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