1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - tools - loadrun.TWL
3   File:     loadrun.c
4 
5   Copyright 2007-2008 Nintendo. All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law. They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-07-15#$
14   $Rev: 7370 $
15   $Author: yada $
16  *---------------------------------------------------------------------------*/
17 #include <windows.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/fcntl.h>
23 #include <sys/stat.h>
24 #include <getopt.h>
25 #include <signal.h>
26 #include <time.h>
27 
28 #include "isd_api.h"
29 
30 #define  SDK_BOOL_ALREADY_DEFINED_
31 #include <twl_win32.h>
32 #include <nitro/os/common/system.h>
33 
34 extern const unsigned long SDK_DATE_OF_LATEST_FILE;
35 
36 //---- Application name
37 #define EXEC_NAME          "loadrun.TWL"
38 #define DEBUGGER_NAME      "IS-TWL-DEBUGGER"
39 
40 
41 //---- Version string
42 #define VERSION_STRING     " 1.7  Copyright 2007-2008 Nintendo. All right reserved."
43 // 1.7  Enabled HYBRID to run in NITRO mode (added -N)
44 // 1.6  Enabled display of final error
45 // 1.5  Made reference to debugging prohibit flag
46 // 1.4  Updated for matching only of end with serial specification
47 // 1.3  Official support for ISTD_DownloadGo function
48 // 1.2  Fixed print callback bug
49 // 1.1  Supported IS-TWL-DEBUGGER Ver.0.41
50 // 1.0 Published
51 
52 //---- exit number
53 #define EXIT_NUM_NO_ERROR               207     // Successful exit (however, this will not result next time)
54 #define EXIT_NUM_USER_SIGNAL            206     // Forced exit by user (ctrl-C)
55 #define EXIT_NUM_EXEC_TIME_OUT          205     // Forced exit due to execution timeout
56 #define EXIT_NUM_TIME_OUT               204     // Forced exit due to display timeout
57 #define EXIT_NUM_SHOW_DEVICES           203     // Exit on device list display
58 #define EXIT_NUM_SHOW_USAGE             202     // Exit on help display
59 #define EXIT_NUM_SHOW_VERSION           201     // Exit on version display
60 #define EXIT_NUM_STRING_ABORT           200     // Forced exit by character string
61 
62 #define EXIT_NUM_NO_DEVICE              -1      // There are no available devices
63 #define EXIT_NUM_UNKNOWN_OPTION         -2      // An unknown option was specified
64 #define EXIT_NUM_ILLEGAL_OPTION         -3      // Illegal use of option
65 #define EXIT_NUM_NO_INPUT_FILE          -4      // The specified file does not exist or cannot be opened
66 #define EXIT_NUM_NOT_CONNECT            -5      // Failed to connect to device
67 #define EXIT_NUM_CANNOT_USE_CARTRIDGE   -6      // Failed to lock cartridge
68 #define EXIT_NUM_CANNOT_USE_CARD        -7      // Failed to lock card
69 #define EXIT_NUM_PRINTF_ERROR           -8      // Error while handling printf data
70 #define EXIT_NUM_LOADING_ERROR          -9      // Error during loading
71 #define EXIT_NUM_EXEC_PROHIBITION       -10     // Execution is not allowed
72 #define EXIT_NUM_NO_HYBRID_NITRO        -11     // Cannot execute HYBRID with NITRO
73 
74 //---- Maximum console count
75 #define PRINT_CONSOLE_MAX   4
76 
77 //---- ROM header information
78 #define RH_FLAG_OFFSET					0x1c	// Various information flags in the ROM header
79 #define RH_FLAG_DEBUGGER_PROHIBITION	(1<<3)	// Cannot run debugger with this bit raised
80 
81 //---- For device specification
82 char   *gDeviceName[] = {
83     "TWLEMU", "TWLDEB", NULL
84 };
85 int     gDeviceTypeArray[] = {
86     ISTD_DEVICE_IS_TWL_EMULATOR,
87     ISTD_DEVICE_IS_TWL_DEBUGGER,
88 };
89 
90 //---- Operating mode
91 BOOL    gQuietMode = FALSE;            // Quiet mode
92 BOOL    gVerboseMode = FALSE;          // verbose mode
93 BOOL    gDebugMode = FALSE;            // Debug mode
94 
95 BOOL    gStdinMode = FALSE;            // stdin mode
96 
97 BOOL    gIsForceNitro = FALSE;         // Set hybrid to NITRO mode?
98 
99 BOOL    gIsTypeSpecified = FALSE;      // Is there a device type specification?
100 int     gSpecifiedType;                // Device type if one is specified
101 
102 BOOL    gIsSerialSpecified = FALSE;    // Is there a serial number specification?
103 int     gSpecifiedSerial;              // Serial number if one was specified
104 
105 BOOL    gIsCartridgeLocked = FALSE;    // Should the cartridge slot be locked?
106 BOOL    gIsCardLocked = FALSE;         // Should the card slot be locked?
107 
108 int     gTimeOutTime = 0;              // Timeout interval in sec (0 indicates no timeout)
109 BOOL    gTimeOutOccured = FALSE;       // Has a timeout occurred?
110 
111 int     gExecTimeOutTime = 0;          // Execution timeout interval in sec (0 indicates no timeout)
112 int     gExecTimeOutOccured = FALSE;   // Has an execution timeout occurred?
113 
114 char   *gAbortString = NULL;           // Abort string
115 BOOL    gStringAborted = FALSE;        // Has execution terminated due to the abort string?
116 
117 BOOL    gExitAborted = FALSE;          // Exit from OS_Exit()
118 int     gExitStatusNum = EXIT_NUM_STRING_ABORT; // Return value when terminated by OS_Exit()
119 int     gExitStrLength;                // Length of exit string
120 
121 BOOL    gShowArchitecture = FALSE;      // Show the architecture?
122 BOOL    gShowConsoleNum = FALSE;        // Show the console number?
123 
124 
125 //---- For TWL library
126 HINSTANCE gDllInstance;
127 ISDDEVICEHANDLE gDeviceHandle;
128 ISDDEVICEID gDeviceId;
129 
130 //Connected to the device? (for slot switch)
131 BOOL    gDeviceConnected = FALSE;
132 
133 
134 //---- Device list
135 #define DEVICE_MAX_NUM      256
136 #define DEVICE_SERIAL_NONE  0x7fffffff // means no specified
137 ISTDDevice gDeviceList[DEVICE_MAX_NUM];
138 int     gCurrentDevice = -1;
139 int     gConnectedDeviceNum = 0;
140 
141 int     gDeviceTypeSpecified = ISTD_DEVICE_NONE;
142 int     gDeviceSerialSpecified = DEVICE_SERIAL_NONE;    // means no specified
143 #define DEVICE_SERIAL_STRING_MAX_SIZE 256
144 char	gDeviceSerialString[DEVICE_SERIAL_STRING_MAX_SIZE];
145 int     gDeviceSerialStringLen = 0;
146 
147 //---- Input file
148 #define FILE_NAME_MAX_SIZE  1024
149 FILE   *gInputFile;
150 char    gInputFileNameString[FILE_NAME_MAX_SIZE];
151 BOOL    gIsInputFileOpened = FALSE;
152 
153 //---- Time
154 time_t  gStartTime = 0;                // Start time
155 BOOL    gIsLineHead[PRINT_CONSOLE_MAX] = {TRUE, TRUE, TRUE, TRUE}; // Start of line?
156 BOOL    gShowLapTime = FALSE;
157 
158 //---- Signal
159 BOOL    gStoppedByUser = FALSE;        // Indicates whether execution was stopped by the user.
160 
161 //---- Displayed?
162 volatile BOOL    gIsOutputString = FALSE;
163 
164 
165 #define printfIfNotQuiet(str)    do{if(!gQuietMode){fputs(str,stdout);}}while(0)
166 
167 void    displayErrorAndExit(int exitNum, char *message);
168 BOOL    outputString(TWLArch arch, int console, char *buf, int bufSize);
169 
170 static void printCallback( LPVOID user, ISDCPUARCH arch, DWORD console, const void* recvBuf, DWORD size );
171 void checkFileFlag(void);
172 
173 /*---------------------------------------------------------------------------*
174   Name:         myExit
175 
176   Description:  similar to exit()
177 
178   Arguments:    exitNum: exit() number
179 
180   Returns:      None.
181  *---------------------------------------------------------------------------*/
myExit(int exitNum)182 void myExit(int exitNum)
183 {
184     //---- Turns off the slot for the cartridge and card
185     if (gDeviceConnected)
186     {
187 //        (void)ISNTD_CartridgeSlotPower(gDeviceHandle, FALSE);
188 //        (void)ISNTD_CardSlotPower(gDeviceHandle, FALSE);
189     }
190 
191     //---- Deallocate DLL memory
192 //    ISNTD_FreeDll();
193     ISTD_FreeDll();
194 
195     if (!gQuietMode)
196     {
197         if (exitNum == EXIT_NUM_USER_SIGNAL)
198         {
199             printf("\n*** %s: stopped by user.\n", EXEC_NAME);
200         }
201         else if (exitNum == EXIT_NUM_TIME_OUT)
202         {
203             printf("\n*** %s: stopped by print timeout.\n", EXEC_NAME);
204         }
205         else if (exitNum == EXIT_NUM_EXEC_TIME_OUT)
206         {
207             printf("\n*** %s: stopped by exec timeout.\n", EXEC_NAME);
208         }
209         else if (gStringAborted)
210         {
211             printf("\n*** %s: stopped by aborting string.\n", EXEC_NAME);
212         }
213         else if (gExitAborted)
214         {
215             exitNum = gExitStatusNum;
216         }
217     }
218 
219     exit(exitNum);
220 }
221 
222 /*---------------------------------------------------------------------------*
223   Name:         listDevice
224 
225   Description:  Displays a list of devices and terminates
226 
227   Arguments:    None.
228 
229   Returns:      None.
230  *---------------------------------------------------------------------------*/
listDevice(void)231 void listDevice(void)
232 {
233     int     n;
234 
235     //---- Device read
236     gConnectedDeviceNum = ISTD_GetDeviceList(&gDeviceList[0], DEVICE_MAX_NUM);
237     if (gConnectedDeviceNum < 0)
238     {
239         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "Cannot access devices.");
240     }
241 
242     printf("---- Connected devices:\n");
243 
244     for (n = 0; n < gConnectedDeviceNum; n++)
245     {
246         switch (gDeviceList[n].type)
247         {
248 			case ISTD_DEVICE_IS_TWL_EMULATOR:
249 				printf("%3d: [IS-TWL-DEBUGGER] serial:%8d\n", n, gDeviceList[n].serial);
250 				break;
251 			case ISTD_DEVICE_IS_TWL_DEBUGGER:
252 				printf("%3d: [%s] serial:%8d\n", n, DEBUGGER_NAME, gDeviceList[n].serial);
253 				break;
254 			case ISTD_DEVICE_UNKNOWN:
255 				printf("%3d: unknown device %x:%x\n", n, (int)gDeviceList[n].id.eType, (int)gDeviceList[n].id.nSerial );
256 				break;
257 			default:
258 				printf("Illegal device\n");
259 				break;
260         }
261     }
262 
263     //---- Search result
264     printf("Found %d device%s.\n", gConnectedDeviceNum, (gConnectedDeviceNum<=1)?"":"s" );
265 
266     myExit(EXIT_NUM_SHOW_DEVICES);
267 }
268 
269 /*---------------------------------------------------------------------------*
270   Name:         searchDevice
271 
272   Description:  search device
273 
274   Arguments:    None.
275 
276   Returns:      None.
277  *---------------------------------------------------------------------------*/
searchDevice(void)278 void searchDevice(void)
279 {
280 	int		tmpMatch = -1;
281 	int		tmpMatchCount = 0;
282 
283     //---- If there is no device
284     if (gConnectedDeviceNum <= 0)
285     {
286         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "found no device.");
287     }
288 
289 	//---- First one if no device has been specified
290     if (gDeviceTypeSpecified == ISTD_DEVICE_NONE && gDeviceSerialSpecified == DEVICE_SERIAL_NONE)
291 	{
292         gCurrentDevice = 0;
293 	}
294 	//---- There is a device or serial specification
295 	else
296 	{
297         int     n;
298 		char    tmpStr[DEVICE_SERIAL_STRING_MAX_SIZE];
299 		char    tmpStrLen;
300 
301         gCurrentDevice = -1;
302         for (n = 0; n < gConnectedDeviceNum; n++)
303         {
304             //---- Matching with specified device
305             if (gDeviceTypeSpecified != ISTD_DEVICE_NONE && gDeviceTypeSpecified != gDeviceList[n].type)
306             {
307                 continue;
308             }
309 
310             //---- Matching with specified serial
311             if (gDeviceSerialSpecified != DEVICE_SERIAL_NONE )
312 			{
313 				//---- Equal
314 				if ( gDeviceSerialSpecified == gDeviceList[n].serial )
315 				{
316 					gCurrentDevice = n;
317 					break;
318 				}
319 
320 				//---- Partial matching because not equal
321 				sprintf( tmpStr, "%d", gDeviceList[n].serial );
322 				tmpStrLen = strlen(tmpStr);
323 
324 				if ( ( tmpStrLen > gDeviceSerialStringLen ) &&
325 					 ( ! strcmp( &tmpStr[ tmpStrLen - gDeviceSerialStringLen ], gDeviceSerialString ) ) )
326 				{
327 					tmpMatch = n;
328 					tmpMatchCount ++;
329 				}
330             }
331         }
332     }
333 
334 	//---- If there is one partial match
335 	if ( gCurrentDevice < 0 )
336 	{
337 		if ( tmpMatchCount == 1 )
338 		{
339 			gCurrentDevice = tmpMatch;
340 		}
341 		else if ( tmpMatchCount >= 2 )
342 		{
343 			displayErrorAndExit(EXIT_NUM_NO_DEVICE, "two or more devices matched to sperified serial number." );
344 		}
345 	}
346 
347     //---- The specified device does not exist or is incorrect
348     if (gCurrentDevice < 0
349         || gDeviceList[gCurrentDevice].type == ISTD_DEVICE_NONE
350         || gDeviceList[gCurrentDevice].type == ISTD_DEVICE_UNKNOWN)
351     {
352         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "illegal device.");
353     }
354 }
355 
356 /*---------------------------------------------------------------------------*
357   Name:         displayUsage
358 
359   Description:  Displays the usage
360 
361   Arguments:    None.
362 
363   Returns:      None.
364  *---------------------------------------------------------------------------*/
displayUsage(void)365 void displayUsage(void)
366 {
367     fprintf(stderr,
368             "TWL-SDK Development Tool - %s - Execute TWL ROM image\n"
369             "Build %lu\n\n"
370             "Usage: %s [OPTION] <SrlFile>\n"
371             "\tdownload TWL srl file to %s and execute.\n\n"
372             "Options:\n"
373             "  --version                   : Show %s version.\n"
374             "  --debuggerVersion           : Show debugger version.\n"
375             "  -h, --help                  : Show this help.\n"
376             "  -q, --quiet                 : Quiet mode.\n"
377             "  -v, --verbose               : Verbose mode.\n"
378             "  -L, --list                  : List connecting device.\n"
379             "  -N, --nitro                 : Run hybrid rom as NITRO mode\n"
380             "  -l, --lap                   : Show lap time at each line.\n"
381 //            "  -d, --type=DEVICE          : Specify device type.\n"
382 //            "                                DEVICE=TWLEMU|TWLDEB.\n"
383             "  -A, --architecture          : Show architecture at each line.\n"
384             "  -n, --console               : Show console number at each line.\n"
385             "  -s, --serial=SERIAL         : Specify serial number.\n"
386             "  -t, --timeout=SECOND        : Specify quit time after last print.\n"
387             "  -T, --exec-timeout=SECOND   : Specify quit time after execute program.\n"
388             "  -a, --abort-string=STRING   : Specify aborting string.\n"
389             "  -c, --card-slot=SWITCH      : Card      slot SWITCH=ON|OFF, default OFF.\n"
390             "  -C, --cartridge-slot=SWITCH : Cartridge slot SWITCH=ON|OFF, default OFF.\n",
391 //            "  --stdin, --standard-input   : Read data from stdin instead of <SrlFile>.\n\n",
392 			EXEC_NAME,
393             SDK_DATE_OF_LATEST_FILE,
394 			EXEC_NAME,
395 			DEBUGGER_NAME,
396 			EXEC_NAME );
397 }
398 
399 /*---------------------------------------------------------------------------*
400   Name:         displayVersion
401 
402   Description:  Displays the version
403 
404   Arguments:    None.
405 
406   Returns:      None.
407  *---------------------------------------------------------------------------*/
displayVersion(void)408 void displayVersion(void)
409 {
410     printf("*** %s: %s\n", EXEC_NAME, VERSION_STRING);
411 }
412 
413 /*---------------------------------------------------------------------------*
414   Name:         displayDebuggerVersion
415 
416   Description:  Displays debugger version.
417 
418   Arguments:    None.
419 
420   Returns:      None.
421  *---------------------------------------------------------------------------*/
displayDebuggerVersion(void)422 void displayDebuggerVersion(void)
423 {
424 	BOOL r;
425 	DWORD major;
426 	DWORD minor;
427 	DWORD build;
428 	DWORD revision;
429 	r = ISTD_GetVersion( &major, &minor, &build, &revision);
430 
431 	if (r)
432 	{
433 		printf("*** %s: %s version is %d.%d.%04d.%04d\n",
434 			   EXEC_NAME, DEBUGGER_NAME, (int)major, (int)minor, (int)build, (int)revision);
435 	}
436 	else
437 	{
438 		printf("*** %s: failed to get %s version.\n", EXEC_NAME, DEBUGGER_NAME );
439 	}
440 	myExit(EXIT_NUM_NO_ERROR);
441 }
442 
443 /*---------------------------------------------------------------------------*
444   Name:         displayErrorAndExit
445 
446   Description:  Displays errors.
447 
448   Arguments:    None.
449 
450   Returns:      None.
451  *---------------------------------------------------------------------------*/
displayErrorAndExit(int exitNum,char * message)452 void displayErrorAndExit(int exitNum, char *message)
453 {
454 	if (gDebugMode)
455 	{
456 		printf("last error=%lx\n", ISTD_GetLastError());
457 	}
458 
459     printf("*** %s: Error: %s\n", EXEC_NAME, message);
460 
461     //---- Deallocate DLL memory
462     ISTD_FreeDll();
463 
464     exit(exitNum);
465 }
466 
467 /*---------------------------------------------------------------------------*
468   Name:         parseOption
469 
470   Description:  parses the option line
471 
472   Arguments:    argc : argument count
473                 argv: argument vector
474 
475   Returns:      result. less than 0 if error.
476  *---------------------------------------------------------------------------*/
parseOption(int argc,char * argv[])477 void parseOption(int argc, char *argv[])
478 {
479     int     n;
480     int     c;
481     BOOL    helpFlag = FALSE;
482 
483     struct option optionInfo[] = {
484         {"help", no_argument, NULL, 'h'},
485         {"quiet", no_argument, NULL, 'q'},
486         {"verbose", no_argument, NULL, 'v'},
487         {"list", no_argument, NULL, 'L'},
488         {"nitro", no_argument, NULL, 'N'},
489         {"lap", no_argument, NULL, 'l'},
490         {"debug", no_argument, NULL, 'D'},      //Hidden options
491         {"version", no_argument, NULL, '1'},
492         {"debuggerVersion", no_argument, NULL, '2'},
493 //        {"stdin", no_argument, NULL, 'I'},
494 //        {"standard-input", no_argument, NULL, 'I'},
495         {"type", required_argument, 0, 'd'},    //Hidden options
496         {"serial", required_argument, 0, 's'},
497         {"timeout", required_argument, 0, 't'},
498         {"exec-timeout", required_argument, 0, 'T'},
499         {"abort-string", required_argument, 0, 'a'},
500         {"card-slot", required_argument, 0, 'c'},
501         {"cartridge-slot", required_argument, 0, 'C'},
502         {"architecture", no_argument, NULL, 'A'},
503         {"console", no_argument, NULL, 'n'},
504         {NULL, 0, 0, 0}
505     };
506     int     optionIndex;
507 
508     char   *optionStr = NULL;
509 
510     //---- suppress error string of getopt_long()
511     opterr = 0;
512 
513     while (1)
514     {
515         c = getopt_long(argc, argv, "+hqvLNlDd:s:t:T:a:c:C:An", &optionInfo[0], &optionIndex);
516 
517         //printf("optind=%d optopt=%d  %x(%c) \n", optind, optopt, c,c );
518 
519         if (c == -1)
520         {
521             break;
522         }
523 
524         switch (c)
525         {
526         case 'I':                     //---- Standard input
527             gStdinMode = TRUE;
528             break;
529         case 'h':                     //---- Help display
530             helpFlag = TRUE;
531             break;
532         case 'q':                     //---- Quiet mode
533             gQuietMode = TRUE;
534             break;
535         case 'v':                     //---- Verbose mode
536             gVerboseMode = TRUE;
537             break;
538         case 'D':                     //---- Debug mode
539             gDebugMode = TRUE;
540             break;
541         case '1':                     //---- Program version display
542             displayVersion();
543             myExit(EXIT_NUM_SHOW_VERSION);
544             break;
545         case '2':                     //---- Debugger version display
546 			displayDebuggerVersion();
547             myExit(EXIT_NUM_SHOW_VERSION);
548 			break;
549         case 'L':                     //---- Device list
550             listDevice();
551             break;
552         case 'N':                     //---- Set hybrid to NITRO mode
553             gIsForceNitro = TRUE;
554             break;
555         case 'l':                     //---- Lap time
556             gShowLapTime = TRUE;
557             break;
558 		case 'A':
559 			gShowArchitecture = TRUE; // Display architecture
560 			break;
561 		case 'n':
562 			gShowConsoleNum = TRUE;   // Display console number
563 			break;
564         case 'd':                     //---- Device
565             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
566             {
567                 int     n;
568                 for (n = 0; gDeviceName[n]; n++)
569                 {
570                     if (!strcmp(optionStr, gDeviceName[n]))
571                     {
572                         gDeviceTypeSpecified = gDeviceTypeArray[n];
573                         break;
574                     }
575                 }
576 
577                 if (gDeviceTypeSpecified == ISTD_DEVICE_NONE)
578                 {
579                     displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION, "illegal device type.");
580                 }
581             }
582             break;
583         case 's':                     //---- Serial specification
584             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
585             gDeviceSerialSpecified = atoi(optionStr);
586 			strncpy(gDeviceSerialString, optionStr, DEVICE_SERIAL_STRING_MAX_SIZE);
587 			gDeviceSerialString[DEVICE_SERIAL_STRING_MAX_SIZE-1] = '\0';
588 			gDeviceSerialStringLen = strlen( gDeviceSerialString );
589             break;
590         case 'c':                     //---- Card slot lock
591             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
592             if (!strcmp(optionStr, "ON") || !strcmp(optionStr, "on"))
593             {
594                 gIsCardLocked = TRUE;
595             }
596             else if (!strcmp(optionStr, "OFF") || !strcmp(optionStr, "off"))
597             {
598                 gIsCardLocked = FALSE;
599             }
600             else
601             {
602                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION, "illegal value for card slot option.");
603             }
604             break;
605         case 'C':                     //---- Cartridge slot lock
606             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
607             if (!strcmp(optionStr, "ON") || !strcmp(optionStr, "on"))
608             {
609                 gIsCartridgeLocked = TRUE;
610             }
611             else if (!strcmp(optionStr, "OFF") || !strcmp(optionStr, "off"))
612             {
613                 gIsCartridgeLocked = FALSE;
614             }
615             else
616             {
617                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
618                                     "illegal value for cartridge slot option.");
619             }
620             break;
621         case 't':                     //---- Timeout interval beginning from final display
622             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
623             gTimeOutTime = atoi(optionStr);
624             if (gTimeOutTime <= 0)
625             {
626                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
627                                     "illegal value for abort timeout option.");
628             }
629             break;
630         case 'T':                     //---- Execution timeout interval
631             optionStr = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
632             gExecTimeOutTime = atoi(optionStr);
633             if (gExecTimeOutTime <= 0)
634             {
635                 displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
636                                     "illegal value for abort exec timeout option.");
637             }
638             break;
639         case 'a':                     //---- Abort string
640             gAbortString = (char *)(optarg + ((*optarg == '=') ? 1 : 0));
641             {
642                 int     length = strlen(gAbortString);
643                 if (length <= 0 || length > 256)
644                 {
645                     displayErrorAndExit(EXIT_NUM_ILLEGAL_OPTION,
646                                         "illegal value for abort string option.");
647                 }
648             }
649             break;
650         default:
651             displayErrorAndExit(EXIT_NUM_UNKNOWN_OPTION, "unknown option.");
652         }
653     }
654 
655     //---- Help display
656     {
657         BOOL    isDisplayHelp = FALSE;
658 
659         if (helpFlag)
660         {
661             isDisplayHelp = TRUE;
662         }
663         else if (argc <= optind && !gStdinMode)
664         {
665             isDisplayHelp = TRUE;
666         }
667         else if (argc > optind && gStdinMode)
668         {
669             isDisplayHelp = TRUE;
670         }
671 
672         if (isDisplayHelp)
673         {
674             displayUsage();
675             exit(EXIT_NUM_SHOW_USAGE);
676         }
677     }
678 
679     //---- Input file name
680     if (!gStdinMode)
681     {
682         strncpy(gInputFileNameString, argv[optind], FILE_NAME_MAX_SIZE);
683     }
684 
685     if (gVerboseMode)
686     {
687         if (!gStdinMode)
688         {
689             printf("Input file is [%s]\n", gInputFileNameString);
690         }
691         else
692         {
693             printf("Input file is stdin\n");
694         }
695     }
696 
697     //---- Information display
698     if (gVerboseMode)
699     {
700         printf("Print time out : %d sec.\n", gTimeOutTime);
701         printf("Execute time out : %d sec.\n", gExecTimeOutTime);
702         printf("Card lock : %s.\n", (gIsCardLocked) ? "ON" : "OFF");
703         printf("Cartridge lock : %s.\n", (gIsCartridgeLocked) ? "ON" : "OFF");
704 
705         if (gAbortString)
706         {
707             printf("Abort string : [%s]\n", gAbortString);
708         }
709     }
710 }
711 
712 /*---------------------------------------------------------------------------*
713   Name:         loadFile
714 
715   Description:  loads file
716 
717   Arguments:    None.
718 
719   Returns:      None.
720  *---------------------------------------------------------------------------*/
loadFile(void)721 void loadFile(void)
722 {
723     unsigned int address = 0;
724 
725     //---- File open
726     if (gStdinMode)
727     {
728         gInputFile = stdin;
729         _setmode(_fileno(gInputFile), O_BINARY);
730     }
731     else
732     {
733         if ((gInputFile = fopen(gInputFileNameString, "rb")) == NULL)
734         {
735             displayErrorAndExit(EXIT_NUM_NO_INPUT_FILE, "cannot open input file.");
736         }
737     }
738     gIsInputFileOpened = TRUE;
739 
740 	//---- Check file
741 	checkFileFlag();
742 
743     //---- Connected to device
744     if ((gDeviceHandle = ISTD_OpenEx(gDeviceList[gCurrentDevice].id)) == NULL)
745     {
746         displayErrorAndExit(EXIT_NUM_NOT_CONNECT, "cannot connect device.");
747     }
748     gDeviceConnected = TRUE;
749 
750     //---- Issue reset
751     ISTD_Reset(gDeviceHandle, TRUE);
752     Sleep(1000);
753 
754 	//----- Specify print callback
755 	ISTD_PrintfSetCB( gDeviceHandle, printCallback, (void*)0 );
756 
757 	//---- Set mode for hybrid
758 	if ( ISTD_SetHybridMode )
759 	{
760 		ISTD_SetHybridMode( gDeviceHandle, gIsForceNitro? ISDHYBRID_NTR: ISDHYBRID_TWL );
761 	}
762 	else
763 	{
764 		if ( gIsForceNitro )
765 		{
766 			displayErrorAndExit(EXIT_NUM_LOADING_ERROR, "cannot run as NITRO mode. The required version of IS-TWL-DEBUGGER is v0.64 or later.");
767 		}
768 	}
769 
770 	//---- Download and startup ROM data
771 	if ( ! ISTD_DownloadGo( gDeviceHandle, gInputFileNameString ) )
772 	{
773 		displayErrorAndExit(EXIT_NUM_LOADING_ERROR, "troubled while loading input file.");
774 	}
775 
776 #if 0
777     //---- Transfer every 16KB
778     while (1)
779     {
780         char    buf[16384];
781         size_t  size = fread(buf, 1, sizeof(buf), gInputFile);
782         static int progressCount = 0;
783 
784         if (!size)
785         {
786             break;
787         }
788 
789         //---- Transfer
790         if (!ISTD_WriteROM(gDeviceHandle, buf, address, size))
791         {
792             displayErrorAndExit(EXIT_NUM_LOADING_ERROR, "troubled while loading input file.");
793         }
794 
795         address += size;
796 
797         if (gVerboseMode)
798         {
799             if (!(progressCount++ % 32))
800             {
801                 printf("*");
802             }
803         }
804     }
805 #endif
806 
807     //---- File close
808     if (gStdinMode)
809     {
810         _setmode(_fileno(gInputFile), O_TEXT);
811     }
812     else
813     {
814         fclose(gInputFile);
815     }
816     gIsInputFileOpened = FALSE;
817 
818     if (gVerboseMode)
819     {
820         printf("\nInput file size: %d (0x%x) byte\n", address, address);
821     }
822 }
823 
824 /*---------------------------------------------------------------------------*
825   Name:         checkFileFlag
826 
827   Description:  Checks ROM header execution flag.
828 
829   Arguments:    None.
830 
831   Returns:      None.
832  *---------------------------------------------------------------------------*/
checkFileFlag(void)833 void checkFileFlag(void)
834 {
835 	char buf[0x100];
836 
837 	fseek( gInputFile, 0, SEEK_SET );
838 	fread( buf, 1, sizeof(buf), gInputFile );
839 
840 	//---- Whether debugger can be run
841 	if ( buf[RH_FLAG_OFFSET] & RH_FLAG_DEBUGGER_PROHIBITION )
842 	{
843 		displayErrorAndExit(EXIT_NUM_EXEC_PROHIBITION, "cannot exec this file. (debugger forbidden)");
844 	}
845 
846 	//---- rewind
847 	rewind( gInputFile );
848 }
849 
850 /*---------------------------------------------------------------------------*
851   Name:         setSlopPower
852 
853   Description:  Slot power process
854 
855   Arguments:    None.
856 
857   Returns:      None.
858  *---------------------------------------------------------------------------*/
setSlotPower(void)859 void setSlotPower(void)
860 {
861     //---- Should the cartridge slot be locked?
862     if (gIsCartridgeLocked)
863     {
864 //        if (!ISNTD_CartridgeSlotPower(gDeviceHandle, TRUE))
865         if (0)
866         {
867             displayErrorAndExit(EXIT_NUM_CANNOT_USE_CARTRIDGE, "cannot use cartridge slot.");
868         }
869     }
870 
871     //---- Should the card slot be locked?
872     if (gIsCardLocked)
873     {
874 //        if (!ISNTD_CardSlotPower(gDeviceHandle, TRUE))
875         if (0)
876         {
877             displayErrorAndExit(EXIT_NUM_CANNOT_USE_CARD, "cannot use card slot.");
878         }
879     }
880 
881 #if 0
882     //---- Cancel reset
883     Sleep(1000);
884     ISTD_Reset(gDeviceHandle, FALSE);
885 #endif
886 }
887 
888 
889 /*---------------------------------------------------------------------------*
890   Name:         procPrint
891 
892   Description:  printf process
893 
894   Arguments:    None.
895 
896   Returns:      None.
897  *---------------------------------------------------------------------------*/
898 TWLArch archNum[] = {
899     TWLArchARM9,
900     TWLArchARM7
901 };
902 
903 #define PRINT_ONETIME_SIZE  512
904 #define PRINT_CONSOLE_MAX   4
905 
906 //---- Buffer for joint display
907 static char gConbineBuf[PRINT_CONSOLE_MAX][PRINT_ONETIME_SIZE * 2 + 2] = {"\0", "\0", "\0", "\0" };
908 
909 static char *gConbineBufPtr[PRINT_CONSOLE_MAX] = {&gConbineBuf[0][0],
910 												  &gConbineBuf[1][0],
911 												  &gConbineBuf[2][0],
912 												  &gConbineBuf[3][0] };
913 
914 //---- Buffer for joining and comparing character strings
915 static char gLineBuf[PRINT_ONETIME_SIZE + 1];
916 
917 
procPrintf(void)918 void procPrintf(void)
919 {
920     int     blankTime = 0;
921 
922     //---- Size of exit string
923     gExitStrLength = strlen(OS_EXIT_STRING_1);
924 
925     while (1)
926     {
927         //---- When stopped by the user
928         if (gStoppedByUser)
929         {
930             myExit(EXIT_NUM_USER_SIGNAL);
931         }
932 
933         //---- Exit?
934         if (gStringAborted || gExitAborted)
935         {
936             break;
937         }
938 
939         //---- If text is not being displayed
940         if (!gIsOutputString)
941         {
942             Sleep(100);
943             blankTime += 100;
944 
945             //---- Timeout decision
946             if (gTimeOutTime && blankTime > gTimeOutTime * 1000)
947             {
948                 gTimeOutOccured = TRUE;
949                 break;
950             }
951         }
952         //---- If text has been displayed
953         else
954         {
955 			gIsOutputString = FALSE;
956             blankTime = 0;
957         }
958 
959         //---- Timeout check
960         if (gExecTimeOutTime > 0)
961         {
962             time_t  currentTime;
963             (void)time(&currentTime);
964 
965             if (currentTime - gStartTime >= gExecTimeOutTime)
966             {
967                 gExecTimeOutOccured = TRUE;
968                 break;
969             }
970         }
971     }
972 }
973 
974 /*---------------------------------------------------------------------------*
975   Name:         printCallback
976 
977   Description:  Print callback
978 
979   Arguments:    user    :
980                 arch    :
981                 console :
982                 recvBuf :
983                 size:
984 
985   Returns:      None.
986  *---------------------------------------------------------------------------*/
printCallback(LPVOID user,ISDCPUARCH arch,DWORD console,const void * recvBuf,DWORD size)987 static void printCallback( LPVOID user, ISDCPUARCH arch, DWORD console, const void* recvBuf, DWORD size )
988 {
989 //printf("%d arch:%d console:%d buf:%x size:%d\n", (int)user, (int)arch, (int)console, (int)recvBuf, (int)size );
990 	gIsOutputString = TRUE;
991 	outputString(arch, console, (char*)recvBuf, size);
992 }
993 
994 /*---------------------------------------------------------------------------*
995   Name:         showLapTime
996 
997   Description:  displays lap time at line head
998 
999   Arguments:    None.
1000 
1001   Returns:      None.
1002  *---------------------------------------------------------------------------*/
showLapTime(void)1003 void showLapTime(void)
1004 {
1005     int     lap;
1006     time_t  currentTime;
1007 
1008     (void)time(&currentTime);
1009     lap = currentTime - gStartTime;
1010 
1011     printf("{%d:%02d}", lap / 60, lap % 60);
1012 }
1013 
showAddition(TWLArch arch,int console)1014 void showAddition(TWLArch arch, int console)
1015 {
1016 	static char* archStr[] = {"A9", "A7"};
1017 	int archIndex = -1;
1018 
1019 	if ( gIsLineHead[console] )
1020 	{
1021 		if ( gShowArchitecture )
1022 		{
1023 			//---- Investigate architecture
1024 			if ( arch == TWLArchARM9 )
1025 			{
1026 				archIndex=0;
1027 			}
1028 			else if ( arch == TWLArchARM7 )
1029 			{
1030 				archIndex=1;
1031 			}
1032 		}
1033 		if ( !gShowConsoleNum )
1034 		{
1035 			console = -1;
1036 		}
1037 
1038 		//---- Display architecture and console number
1039 		if ( archIndex<0 && console<0 )
1040 		{
1041 			// do nothing
1042 		}
1043 		else if ( archIndex<0 )
1044 		{
1045 			printf("<%d>", console );
1046 		}
1047 		else if ( console<0 )
1048 		{
1049 			printf("<%s>", archStr[archIndex] );
1050 		}
1051 		else
1052 		{
1053 			printf("<%s:%d>", archStr[archIndex], console );
1054 		}
1055 
1056 		//---- Time display
1057 		if (!gQuietMode && gShowLapTime)
1058 		{
1059 			showLapTime();
1060 		}
1061 	}
1062 }
1063 
1064 /*---------------------------------------------------------------------------*
1065   Name:         outputString
1066 
1067   Description:  outputs string to stdout
1068 
1069   Arguments:    arch    : architecture(TWLArchARM9, TWLArchARM7, None)
1070                 console : console num (0-3, -1)
1071                 buf: buffer
1072                 bufSize: data size in buffer
1073 
1074   Returns:      FALSE if to do quit.
1075  *---------------------------------------------------------------------------*/
outputString(TWLArch arch,int console,char * buf,int bufSize)1076 BOOL outputString(TWLArch arch, int console, char *buf, int bufSize)
1077 {
1078     char   *bufEnd = buf + bufSize;
1079     char   *p = buf;
1080 
1081     int     abortStrLength = gAbortString ? strlen(gAbortString) : 0;
1082 
1083 	static int prevConsole = -1;
1084 
1085 	if ( prevConsole >= 0 && prevConsole != console )
1086 	{
1087         gIsLineHead[prevConsole] = TRUE;
1088 		printf("\n");
1089 	}
1090 	prevConsole = console;
1091 
1092     while (p < bufEnd)
1093     {
1094         char   *crPtr = strchr(p, '\n');
1095 
1096         //---- \n missing
1097         if (!crPtr)
1098         {
1099             //---- Save for comparison
1100             strcat(gConbineBufPtr[console], p);
1101             gConbineBufPtr[console] += strlen(p);
1102 
1103 			//---- Additional information
1104 			showAddition( arch, console );
1105             gIsLineHead[console] = FALSE;
1106 
1107             //---- Display
1108             printfIfNotQuiet(p);
1109 
1110             //---- Destroy if buffer overflows (the responsibility is on the output side to insert \n)
1111             if (gConbineBufPtr[console] - &gConbineBuf[console][0] > PRINT_ONETIME_SIZE)
1112             {
1113                 gConbineBufPtr[console] = &gConbineBuf[console][0];
1114                 *gConbineBufPtr[console] = '\0';
1115             }
1116 
1117             break;
1118         }
1119 
1120         //---- copy up to \n
1121         {
1122             int     n = crPtr - p + 1;
1123 
1124             //---- Combine for comparison
1125             strncpy(gConbineBufPtr[console], p, n);
1126             gConbineBufPtr[console][n] = '\0';
1127 
1128             //---- For display
1129             strncpy(&gLineBuf[0], p, n);
1130             gLineBuf[n] = '\0';
1131         }
1132 
1133 		//---- Additional information
1134 		showAddition( arch, console );
1135         gIsLineHead[console] = TRUE;
1136 
1137         //---- Line display
1138         printfIfNotQuiet(gLineBuf);
1139 
1140         //---- Compare with abort string
1141         if (gAbortString && !strncmp(gConbineBuf[console], gAbortString, abortStrLength))
1142         {
1143             gStringAborted = TRUE;
1144             return FALSE;
1145         }
1146 
1147         //---- Exit using OS_Exit
1148         if (!strncmp(gConbineBuf[console], OS_EXIT_STRING_1, gExitStrLength))
1149         {
1150             gExitAborted = TRUE;
1151             gExitStatusNum = atoi(gConbineBuf[console] + gExitStrLength);
1152             return FALSE;
1153         }
1154 
1155         gConbineBufPtr[console] = &gConbineBuf[console][0];
1156         *gConbineBufPtr[console] = '\0';
1157 
1158         p = crPtr + 1;
1159     }
1160 
1161     return TRUE;
1162 }
1163 
1164 /*---------------------------------------------------------------------------*
1165   Name:         signalHandler
1166 
1167   Description:  signal handler
1168 
1169   Arguments:    sig
1170                 argv: argument vector
1171 
1172   Returns:      ---
1173  *---------------------------------------------------------------------------*/
signalHandler(int sig)1174 void signalHandler(int sig)
1175 {
1176     gStoppedByUser = TRUE;
1177 }
1178 
1179 /*---------------------------------------------------------------------------*
1180   Name:         Main
1181 
1182   Description:  main proc
1183 
1184   Arguments:    argc : argument count
1185                 argv: argument vector
1186 
1187   Returns:      ---
1188  *---------------------------------------------------------------------------*/
main(int argc,char * argv[])1189 int main(int argc, char *argv[])
1190 {
1191     //---- Initialize DLL
1192     ISTD_InitDll();
1193 
1194     //---- Disable buffering of standard output
1195     setvbuf(stdout, NULL, _IONBF, 0);
1196 
1197     //---- Option parsing
1198     parseOption(argc, argv);
1199 
1200     //---- Device read
1201     gConnectedDeviceNum = ISTD_GetDeviceList(&gDeviceList[0], DEVICE_MAX_NUM);
1202     if (gConnectedDeviceNum < 0)
1203     {
1204         displayErrorAndExit(EXIT_NUM_NO_DEVICE, "Cannot access devices.");
1205     }
1206 
1207     //---- Search for device
1208     searchDevice();
1209 
1210     //---- Read
1211     loadFile();
1212 
1213     //---- Signal setting
1214     (void)signal(SIGINT, signalHandler);
1215 
1216     //---- Slot
1217     setSlotPower();
1218 
1219     //---- Get start time
1220     (void)time(&gStartTime);
1221 
1222     //---- printf process
1223     procPrintf();
1224 
1225     //---- End
1226     if (gExitAborted)                  //---- Exit from OS_Exit()
1227     {
1228         myExit(gExitStatusNum);
1229     }
1230     else if (gStringAborted)           //---- Abort string
1231     {
1232         myExit(EXIT_NUM_STRING_ABORT);
1233     }
1234     else if (gTimeOutOccured)          //---- Timeout
1235     {
1236         myExit(EXIT_NUM_TIME_OUT);
1237     }
1238     else if (gExecTimeOutOccured)
1239     {
1240         myExit(EXIT_NUM_EXEC_TIME_OUT);
1241     }
1242     else                               //---- Normal end
1243     {
1244         myExit(EXIT_NUM_NO_ERROR);
1245     }
1246     //---- never reached here
1247 
1248     //---- dummy to avoid warning
1249     return 0;
1250 }
1251