1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - tools - showversion
3   File:     main.c
4 
5   Copyright 2003-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-12-03#$
14   $Rev: 9495 $
15   $Author: sasaki_yu $
16  *---------------------------------------------------------------------------*/
17 #include <stdio.h>
18 #include <string.h>
19 
20 extern const unsigned long SDK_DATE_OF_LATEST_FILE;
21 
22 #define  LE(a)   ((((a)<<24)&0xff000000)|(((a)<<8)&0x00ff0000)|\
23                   (((a)>>8)&0x0000ff00)|(((a)>>24)&0x000000ff))
24 
25 #define  MAGIC_CODE     0x2106c0de
26 #define  BUILD_MAGIC_CODE   0x3381c0de
27 
28 #define ERROR_NO_VERSION_INFO 1
29 #define ERROR_BUILDTYPE_MISMATCH 2
30 
31 typedef unsigned char u8;
32 typedef unsigned short int u16;
33 typedef unsigned long int u32;
34 typedef union
35 {
36     u8      byte[4];
37     u32     word;
38 }
39 tFormat;
40 
41 typedef struct
42 {
43     u8      reserve[32];               //
44     u32     rom_offset;                // Transfer source ROM offset
45     u32     entry_address;             // Execution start address
46     u32     ram_address;               // Transfer destination RAM address
47     u32     size;                      // Size of the transmission
48 }
49 tRomHeader;
50 
51 #define ROMOFFSET_MODULE9       0x00000020      // ARM9 resident module information region
52 
53 typedef struct
54 {
55     u8      major;
56     u8      minor;
57     u16     relstep;
58     u8      relclass;
59     u8      relnumber_major;
60     u8      relnumber_minor;
61     char   *relname;
62 }
63 tVersion;
64 
65 
66 #define RELCLASS_TEST          0
67 #define RELCLASS_PR            1
68 #define RELCLASS_RC            2
69 
70 #define RELSTEP_PR6            106
71 #define RELSTEP_FC             200
72 #define RELSTEP_RELEASE        300
73 
74 int findMagicNumber(FILE *fp, u32 magic_code, u32 *buffer, u32 buffer_len);
75 
76 
77 //
78 // Search magic number and store preceding data in an array.
79 // Example: magic_code = 0x12345678, buffer_len = 4
80 //   When the data is lined up as data2, data1, 0x12345678, 0x87654321, the following are the results.
81 // buffer[0] = 0x87654321
82 // buffer[1] = 0x12345678
83 // buffer[2] = data1
84 // buffer[3] = data2
85 //
86 // Return value: If the magic number is found, 1 is returned; if it is not found, 0 is returned.
findMagicNumber(FILE * fp,u32 magic_code,u32 * buffer,u32 buffer_len)87 int findMagicNumber(FILE *fp, u32 magic_code, u32 *buffer, u32 buffer_len)
88 {
89     u32 i = 0;
90     while (1 == fread(buffer, sizeof(u32), 1, fp))
91     {
92         if(buffer[1] == magic_code && buffer[0] == LE(magic_code))
93         {
94             return 1;
95         }
96 
97         for(i = 1; i < buffer_len; ++i)
98         {
99             buffer[buffer_len - i] = buffer[buffer_len - i - 1];
100         }
101     }
102     return 0;
103 }
104 
main(int argc,char * argv[])105 int main(int argc, char *argv[])
106 {
107     u32     buffer[4];
108     FILE   *fp;
109     tRomHeader romHeader;
110     u32     magicCodeBE, magicCodeLE;
111     u32     buildMagicCodeBE, buildMagicCodeLE;
112     u16     one = 0x0001;
113     tFormat f;
114     tVersion v;
115     u16     relnumber;
116     u32     error = 0;
117     magicCodeBE = *(u8 *)&one ? LE(MAGIC_CODE) : MAGIC_CODE;
118     magicCodeLE = LE(magicCodeBE);
119     buildMagicCodeBE = *(u8 *)&one ? LE(BUILD_MAGIC_CODE) : BUILD_MAGIC_CODE;
120     buildMagicCodeLE = LE(buildMagicCodeBE);
121 
122     if (argc != 2)
123     {
124         fprintf(stderr,
125                 "NITRO-SDK Development Tool - showversion - Show version information\n"
126                 "Build %lu\n"
127                 "\n"
128                 "Usage: showversion ROMFILE\n"
129                 "\n"
130                 "  Show NITRO-SDK version information in ROMFILE\n" "\n", SDK_DATE_OF_LATEST_FILE);
131         return 5;
132     }
133 
134     if (NULL == (fp = fopen(argv[1], "rb")))
135     {
136         fprintf(stderr, "Error: Cannot open '%s'\n", argv[1]);
137         return 1;
138     }
139 
140     if (1 != fread(&romHeader, sizeof(romHeader), 1, fp))
141     {
142         fclose(fp);
143         fprintf(stderr, "Error: Cannot open '%s'\n", argv[1]);
144         return 1;
145     }
146 
147     //
148     // Determine whether it is a ROM file
149     //          Here this determines whether execution start address and transfer destination RAM address are within the range 0x02000000 to 0x027fffff.
150     //
151     //
152     if ((romHeader.ram_address & 0xff800000) != 0x02000000 ||
153         (romHeader.entry_address & 0xff800000) != 0x02000000)
154     {
155         //
156         // If not a ROM file, destroy ROM header information (zero clears it) and return file pointer to top.
157         //
158         //
159         (void)memset(&romHeader, 0, sizeof(tRomHeader));
160         rewind(fp);
161     }
162 
163     v.major = 0;
164     buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0;
165 
166     //
167     // Determine that magicCode is lined up in this order in ROM and display versionInfo:
168     //      buffer[2] versionInfo
169     //      buffer[1] magicCodeBE
170     //      buffer[0] magicCodeLE
171     //
172     //
173     while (findMagicNumber(fp, magicCodeBE, buffer, 3))
174     {
175         f.word = buffer[2];
176         v.major = f.byte[3];       // 31..24bit
177         v.minor = f.byte[2];       // 23..16bit
178         v.relstep = ((u16)f.byte[0]) | (((u16)f.byte[1]) << 8);     // 15...0bit
179         v.relclass = v.relstep / 10000;
180         relnumber = v.relstep % 10000;
181         v.relnumber_major = relnumber / 100;
182         v.relnumber_minor = relnumber % 100;
183 
184         switch (v.relstep / 100)   // Determine the last three digits
185         {
186             //
187             // Special number determination
188             //
189         case RELSTEP_PR6:
190             if (v.relnumber_minor == 50)
191             {
192                 v.relname = "IPL";
193                 v.relnumber_major = 0;
194                 v.relnumber_minor = 0;
195             }
196             else
197             {
198                 v.relname = "PR";
199                 if (v.relnumber_minor > 50)
200                 {
201                     v.relnumber_minor -= 50;
202                 }
203             }
204             break;
205 
206         case RELSTEP_FC:
207             v.relname = "FC";
208             break;
209 
210         case RELSTEP_RELEASE:
211             v.relname = "RELEASE";
212             break;
213 
214         default:
215 
216             //
217             // Determine normal numbers (postfix notation)
218             //
219             switch (v.relclass)
220             {
221             case RELCLASS_TEST:
222                 v.relname = "test";
223                 break;
224 
225             case RELCLASS_PR:
226                 v.relname = "PR";
227                 break;
228 
229             case RELCLASS_RC:
230                 v.relname = "RC";
231                 break;
232 
233             default:
234                 v.relname = NULL;
235                 break;
236             }
237             break;
238         }
239 
240         printf("NITRO-SDK VERSION: %d.%02d", v.major, v.minor);
241 
242         //
243         // Displaying release class name (test/PR/RC and the like)
244         //
245         if (v.relname)
246         {
247             printf(" %s", v.relname);
248 
249             if (v.relnumber_major)
250             {
251                 printf("%d", v.relnumber_major);
252             }
253             if (v.relnumber_minor)
254             {
255                 printf(" plus");
256 
257                 if (v.relnumber_minor > 1)
258                 {
259                     printf("%d", v.relnumber_minor);
260                 }
261             }
262         }
263         else
264         {
265             printf("XXX [unknown RelID=%d]", v.relstep);
266         }
267 
268         //
269         // Determine whether within a permanent area
270         //
271         if ((u32)ftell(fp) - romHeader.rom_offset < romHeader.size)
272         {
273             printf(" [STATIC MODULE]");
274         }
275 
276         printf("\n");
277 
278         //
279         // Message for when the value had no setting
280         //
281         if (v.major == 0)
282         {
283             fprintf(stderr, "** Error: No version information in '%s'\n", argv[1]);
284             fprintf(stderr, "(older than 2.0FC?)\n");
285             error |= ERROR_NO_VERSION_INFO;
286         }
287     }
288 
289     //
290     // Determine build type
291     //      Determine ARM9 and ARM7
292     //      Determine FINALROM, RELEASE, DEBUG
293     //
294     // If FINALROM, RELEASE, DEBUG are mixed, display an error
295     //
296     {
297         u32 dBuildType = 0xffffffff, buildType = 0, target = 0;
298         int mismatch = 0;
299         rewind(fp);
300 
301         while(findMagicNumber(fp, buildMagicCodeBE, buffer, 4))
302         {
303             u32 version = buffer[2] & 0x000000ff;
304             char* buildName[] = {"FINALROM", "RELEASE", "DEBUG"};
305             if(version == 1)
306             {
307                 target = (buffer[3] >> 8) & 0x000000ff;
308                 buildType = buffer[3] & 0x000000ff;
309                 printf("BUILD_TYPE:ARM%d %s\n", (int)target,
310                     ((buildType != 0xff) ? buildName[buildType] : "Invalid"));
311 
312                 // Detect whether a different build type is mixed in.
313                 if(dBuildType != 0xffffffff && dBuildType != buildType)
314                 {
315                     mismatch = 1;
316                 }
317                 dBuildType = buildType;
318             }
319         }
320         if(mismatch)
321         {
322             fprintf(stderr, "** Error: Build type mismatch\n");
323             error |= ERROR_BUILDTYPE_MISMATCH;
324         }
325     }
326 
327     fclose(fp);
328 
329     return error;
330 }
331