1 /* Copyright (c) 2010-2017 Benjamin Dobell, Glass Echidna
2 
3  Permission is hereby granted, free of charge, to any person obtaining a copy
4  of this software and associated documentation files (the "Software"), to deal
5  in the Software without restriction, including without limitation the rights
6  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  copies of the Software, and to permit persons to whom the Software is
8  furnished to do so, subject to the following conditions:
9 
10  The above copyright notice and this permission notice shall be included in
11  all copies or substantial portions of the Software.
12 
13  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  THE SOFTWARE.*/
20 
21 #ifndef LIBPIT_H
22 #define LIBPIT_H
23 
24 #ifdef WIN32
25 #pragma warning(disable : 4996)
26 #endif
27 
28 // C/C++ Standard Library
29 #include <cstring>
30 #include <string>
31 #include <vector>
32 
33 namespace libpit
34 {
35 	class PitEntry
36 	{
37 		public:
38 
39 			enum
40 			{
41 				kDataSize = 132,
42 				kPartitionNameMaxLength = 32,
43 				kFlashFilenameMaxLength = 32,
44 				kFotaFilenameMaxLength = 32
45 			};
46 
47 			enum
48 			{
49 				kBinaryTypeApplicationProcessor = 0,
50 				kBinaryTypeCommunicationProcessor = 1
51 			};
52 
53 			enum
54 			{
55 				kDeviceTypeOneNand = 0,
56 				kDeviceTypeFile, // FAT
57 				kDeviceTypeMMC,
58 				kDeviceTypeAll // ?
59 			};
60 
61 			enum
62 			{
63 				kAttributeWrite = 1,
64 				kAttributeSTL = 1 << 1/*,
65 				kAttributeBML = 1 << 2*/ // ???
66 			};
67 
68 			enum
69 			{
70 				kUpdateAttributeFota = 1,
71 				kUpdateAttributeSecure = 1 << 1
72 			};
73 
74 		private:
75 
76 			unsigned int binaryType;
77 			unsigned int deviceType;
78 			unsigned int identifier;
79 			unsigned int attributes;
80 			unsigned int updateAttributes;
81 
82 			unsigned int blockSizeOrOffset;
83 			unsigned int blockCount;
84 
85 			unsigned int fileOffset; // Obsolete
86 			unsigned int fileSize; // Obsolete
87 
88 			char partitionName[kPartitionNameMaxLength];
89 			char flashFilename[kFlashFilenameMaxLength]; // USB flash filename
90 			char fotaFilename[kFotaFilenameMaxLength]; // Firmware over the air
91 
92 		public:
93 
94 			PitEntry();
95 			~PitEntry();
96 
97 			bool Matches(const PitEntry *otherPitEntry) const;
98 
IsFlashable(void)99 			bool IsFlashable(void) const
100 			{
101 				return strlen(partitionName) != 0;
102 			}
103 
GetBinaryType(void)104 			unsigned int GetBinaryType(void) const
105 			{
106 				return binaryType;
107 			}
108 
SetBinaryType(unsigned int binaryType)109 			void SetBinaryType(unsigned int binaryType)
110 			{
111 				this->binaryType = binaryType;
112 			}
113 
GetDeviceType(void)114 			unsigned int GetDeviceType(void) const
115 			{
116 				return deviceType;
117 			}
118 
SetDeviceType(unsigned int deviceType)119 			void SetDeviceType(unsigned int deviceType)
120 			{
121 				this->deviceType = deviceType;
122 			}
123 
GetIdentifier(void)124 			unsigned int GetIdentifier(void) const
125 			{
126 				return identifier;
127 			}
128 
SetIdentifier(unsigned int identifier)129 			void SetIdentifier(unsigned int identifier)
130 			{
131 				this->identifier = identifier;
132 			}
133 
GetAttributes(void)134 			unsigned int GetAttributes(void) const
135 			{
136 				return attributes;
137 			}
138 
SetAttributes(unsigned int attributes)139 			void SetAttributes(unsigned int attributes)
140 			{
141 				this->attributes = attributes;
142 			}
143 
GetUpdateAttributes(void)144 			unsigned int GetUpdateAttributes(void) const
145 			{
146 				return updateAttributes;
147 			}
148 
SetUpdateAttributes(unsigned int updateAttributes)149 			void SetUpdateAttributes(unsigned int updateAttributes)
150 			{
151 				this->updateAttributes = updateAttributes;
152 			}
153 
154 			// Different versions of Loke (secondary bootloaders) on different devices intepret this differently.
GetBlockSizeOrOffset(void)155 			unsigned int GetBlockSizeOrOffset(void) const
156 			{
157 				return blockSizeOrOffset;
158 			}
159 
SetBlockSizeOrOffset(unsigned int blockSizeOrOffset)160 			void SetBlockSizeOrOffset(unsigned int blockSizeOrOffset)
161 			{
162 				this->blockSizeOrOffset = blockSizeOrOffset;
163 			}
164 
GetBlockCount(void)165 			unsigned int GetBlockCount(void) const
166 			{
167 				return blockCount;
168 			}
169 
SetBlockCount(unsigned int blockCount)170 			void SetBlockCount(unsigned int blockCount)
171 			{
172 				this->blockCount = blockCount;
173 			}
174 
GetFileOffset(void)175 			unsigned int GetFileOffset(void) const
176 			{
177 				return fileOffset;
178 			}
179 
SetFileOffset(unsigned int fileOffset)180 			void SetFileOffset(unsigned int fileOffset)
181 			{
182 				this->fileOffset = fileOffset;
183 			}
184 
GetFileSize(void)185 			unsigned int GetFileSize(void) const
186 			{
187 				return fileSize;
188 			}
189 
SetFileSize(unsigned int fileSize)190 			void SetFileSize(unsigned int fileSize)
191 			{
192 				this->fileSize = fileSize;
193 			}
194 
GetPartitionName(void)195 			const char *GetPartitionName(void) const
196 			{
197 				return partitionName;
198 			}
199 
SetPartitionName(const char * partitionName)200 			void SetPartitionName(const char *partitionName)
201 			{
202 				// This isn't strictly necessary but ensures no junk is left in our PIT file.
203 				memset(this->partitionName, 0, kPartitionNameMaxLength);
204 
205 				if (strlen(partitionName) < kPartitionNameMaxLength)
206 					strcpy(this->partitionName, partitionName);
207 				else
208 					memcpy(this->partitionName, partitionName, kPartitionNameMaxLength - 1);
209 			}
210 
GetFlashFilename(void)211 			const char *GetFlashFilename(void) const
212 			{
213 				return flashFilename;
214 			}
215 
SetFlashFilename(const char * flashFilename)216 			void SetFlashFilename(const char *flashFilename)
217 			{
218 				// This isn't strictly necessary but ensures no junk is left in our PIT file.
219 				memset(this->flashFilename, 0, kFlashFilenameMaxLength);
220 
221 				if (strlen(partitionName) < kFlashFilenameMaxLength)
222 					strcpy(this->flashFilename, flashFilename);
223 				else
224 					memcpy(this->flashFilename, flashFilename, kFlashFilenameMaxLength - 1);
225 			}
226 
GetFotaFilename(void)227 			const char *GetFotaFilename(void) const
228 			{
229 				return fotaFilename;
230 			}
231 
SetFotaFilename(const char * fotaFilename)232 			void SetFotaFilename(const char *fotaFilename)
233 			{
234 				// This isn't strictly necessary but ensures no junk is left in our PIT file.
235 				memset(this->fotaFilename, 0, kFotaFilenameMaxLength);
236 
237 				if (strlen(partitionName) < kFotaFilenameMaxLength)
238 					strcpy(this->fotaFilename, fotaFilename);
239 				else
240 					memcpy(this->fotaFilename, fotaFilename, kFotaFilenameMaxLength - 1);
241 			}
242 	};
243 
244 	class PitData
245 	{
246 		public:
247 
248 			enum
249 			{
250 				kFileIdentifier = 0x12349876,
251 				kHeaderDataSize = 28,
252 				kPaddedSizeMultiplicand = 4096
253 			};
254 
255 		private:
256 
257 			unsigned int entryCount; // 0x04
258 			unsigned int unknown1;   // 0x08
259 			unsigned int unknown2;   // 0x0C
260 
261 			unsigned short unknown3; // 0x10
262 			unsigned short unknown4; // 0x12
263 
264 			unsigned short unknown5; // 0x14
265 			unsigned short unknown6; // 0x16
266 
267 			unsigned short unknown7; // 0x18
268 			unsigned short unknown8; // 0x1A
269 
270 			// Entries start at 0x1C
271 			std::vector<PitEntry *> entries;
272 
UnpackInteger(const unsigned char * data,unsigned int offset)273 			static int UnpackInteger(const unsigned char *data, unsigned int offset)
274 			{
275 #ifdef WORDS_BIGENDIAN
276 				int value = (data[offset] << 24) | (data[offset + 1] << 16) |
277 					(data[offset + 2] << 8) | data[offset + 3];
278 #else
279 				// Flip endianness
280 				int value = data[offset] | (data[offset + 1] << 8) |
281 					(data[offset + 2] << 16) | (data[offset + 3] << 24);
282 #endif
283 				return (value);
284 			}
285 
UnpackShort(const unsigned char * data,unsigned int offset)286 			static int UnpackShort(const unsigned char *data, unsigned int offset)
287 			{
288 #ifdef WORDS_BIGENDIAN
289 				short value = (data[offset] << 8) | data[offset + 1];
290 #else
291 				// Flip endianness
292 				short value = data[offset] | (data[offset + 1] << 8);
293 #endif
294 				return (value);
295 			}
296 
PackInteger(unsigned char * data,unsigned int offset,unsigned int value)297 			static void PackInteger(unsigned char *data, unsigned int offset, unsigned int value)
298 			{
299 #ifdef WORDS_BIGENDIAN
300 				data[offset] = (value & 0xFF000000) >> 24;
301 				data[offset + 1] = (value & 0x00FF0000) >> 16;
302 				data[offset + 2] = (value & 0x0000FF00) >> 8;
303 				data[offset + 3] = value & 0x000000FF;
304 #else
305 				// Flip endianness
306 				data[offset] = value & 0x000000FF;
307 				data[offset + 1] = (value & 0x0000FF00) >> 8;
308 				data[offset + 2] = (value & 0x00FF0000) >> 16;
309 				data[offset + 3] = (value & 0xFF000000) >> 24;
310 #endif
311 			}
312 
PackShort(unsigned char * data,unsigned int offset,unsigned short value)313 			static void PackShort(unsigned char *data, unsigned int offset, unsigned short value)
314 			{
315 #ifdef WORDS_BIGENDIAN
316 				data[offset] = (value & 0xFF00) >> 8;
317 				data[offset + 1] = value & 0x00FF;
318 #else
319 				// Flip endianness
320 				data[offset] = value & 0x00FF;
321 				data[offset + 1] = (value & 0xFF00) >> 8;
322 #endif
323 			}
324 
325 		public:
326 
327 			PitData();
328 			~PitData();
329 
330 			bool Unpack(const unsigned char *data);
331 			void Pack(unsigned char *data) const;
332 
333 			bool Matches(const PitData *otherPitData) const;
334 
335 			void Clear(void);
336 
337 			PitEntry *GetEntry(unsigned int index);
338 			const PitEntry *GetEntry(unsigned int index) const;
339 
340 			PitEntry *FindEntry(const char *partitionName);
341 			const PitEntry *FindEntry(const char *partitionName) const;
342 
343 			PitEntry *FindEntry(unsigned int partitionIdentifier);
344 			const PitEntry *FindEntry(unsigned int partitionIdentifier) const;
345 
GetEntryCount(void)346 			unsigned int GetEntryCount(void) const
347 			{
348 				return entryCount;
349 			}
350 
GetDataSize(void)351 			unsigned int GetDataSize(void) const
352 			{
353 				return PitData::kHeaderDataSize + entryCount * PitEntry::kDataSize;
354 			}
355 
GetPaddedSize(void)356 			unsigned int GetPaddedSize(void) const
357 			{
358 				unsigned int dataSize = GetDataSize();
359 				unsigned int paddedSize = (dataSize / kPaddedSizeMultiplicand) * kPaddedSizeMultiplicand;
360 
361 				if (dataSize % kPaddedSizeMultiplicand != 0)
362 					paddedSize += kPaddedSizeMultiplicand;
363 
364 				return paddedSize;
365 			}
366 
GetUnknown1(void)367 			unsigned int GetUnknown1(void) const
368 			{
369 				return unknown1;
370 			}
371 
GetUnknown2(void)372 			unsigned int GetUnknown2(void) const
373 			{
374 				return unknown2;
375 			}
376 
GetUnknown3(void)377 			unsigned short GetUnknown3(void) const
378 			{
379 				return unknown3;
380 			}
381 
GetUnknown4(void)382 			unsigned short GetUnknown4(void) const
383 			{
384 				return unknown4;
385 			}
386 
GetUnknown5(void)387 			unsigned short GetUnknown5(void) const
388 			{
389 				return unknown5;
390 			}
391 
GetUnknown6(void)392 			unsigned short GetUnknown6(void) const
393 			{
394 				return unknown6;
395 			}
396 
GetUnknown7(void)397 			unsigned short GetUnknown7(void) const
398 			{
399 				return unknown7;
400 			}
401 
GetUnknown8(void)402 			unsigned short GetUnknown8(void) const
403 			{
404 				return unknown8;
405 			}
406 	};
407 }
408 
409 #endif
410