35
35
import MemoryMap from 'nrf-intel-hex' ;
36
36
37
37
import { DeviceMemInfo , DeviceVersion } from './device-mem-info' ;
38
+ import { areUint8ArraysEqual } from './common' ;
38
39
import * as hexMapUtil from './hex-map-utils' ;
39
40
41
+ /** Indicates the data contain in each of the different regions */
42
+ enum RegionId {
43
+ /** Soft Device is the data blob containing the Nordic Bluetooth stack. */
44
+ softDevice = 1 ,
45
+ /** Contains the MicroPython runtime. */
46
+ microPython = 2 ,
47
+ /** Contains the MicroPython microbit filesystem reserved flash. */
48
+ fs = 3 ,
49
+ }
50
+
51
+ /**
52
+ * The "hash type" field in a region row indicates how to interpret the "hash
53
+ * data" field.
54
+ */
55
+ enum RegionHashType {
56
+ /** The hash data is empty. */
57
+ empty = 0 ,
58
+ /** The full hash data field is used as a hash of the region in flash */
59
+ data = 1 ,
60
+ /** The 4 LSB bytes of the hash data field are used as a pointer */
61
+ pointer = 2 ,
62
+ }
63
+
64
+ /**
65
+ * The data stored in a Region row from the Flash Regions table.
66
+ */
40
67
interface RegionRow {
41
- id : number ;
68
+ /** The Region ID, as described in the RegionId enum. */
69
+ id : RegionId ;
70
+ /** The flash page where this Region starts. */
42
71
startPage : number ;
72
+ /** Length of the region in bytes. */
43
73
lengthBytes : number ;
44
- hashType : number ;
74
+ /** Identifies the type of data contained in the Hash Data field. */
75
+ hashType : RegionHashType ;
76
+ /** Hash Data can be one of the types indicated in the RegionHashType enum. */
45
77
hashData : number ;
78
+ /** When Hash Data is a pointer, this variable holds the pointed string. */
46
79
hashPointerData : string ;
47
80
}
48
81
82
+ /**
83
+ * The Flash Regions Table ends with a Header containing information about the
84
+ * table itsel.
85
+ */
49
86
interface TableHeader {
87
+ /** The flash page size in log2 format. */
50
88
pageSizeLog2 : number ;
89
+ /** The flash page size in bytes. */
51
90
pageSize : number ;
91
+ /** The number of regions described in the table. */
52
92
regionCount : number ;
93
+ /** The length in bytes of the table, excluding this header. */
53
94
tableLength : number ;
95
+ /** The Flash Regions Table format version. */
54
96
version : number ;
97
+ /** The address of this table header (useful for calculation row offsets). */
55
98
startAddress : number ;
99
+ /** The end address of this table header. */
56
100
endAddress : number ;
57
101
}
58
102
@@ -80,7 +124,7 @@ enum RegionHeaderOffset {
80
124
regionCount = pageSizeLog2 + NUM_REG_LEN_BYTES ,
81
125
tableLength = regionCount + TABLE_LEN_LEN_BYTES ,
82
126
version = tableLength + VERSION_LEN_BYTES ,
83
- magic_1 = version + MAGIC_1_LEN_BYTES ,
127
+ magic1 = version + MAGIC_1_LEN_BYTES ,
84
128
}
85
129
86
130
// Magic numbers to identify the Flash Regions Table in flash
@@ -114,44 +158,46 @@ enum RegionRowOffset {
114
158
const REGION_ROW_LEN_BYTES = RegionRowOffset . id ;
115
159
116
160
/**
117
- * The "hash type" field in a region row indicates how to interpret the "hash
118
- * data" field.
119
- */
120
- enum RegionHashType {
121
- /** The hash data is empty. */
122
- empty = 0 ,
123
- /** The full hash data field is used as a hash of the region in flash */
124
- data = 1 ,
125
- /** The 4 LSB bytes of the hash data field are used as a pointer */
126
- pointer = 2 ,
127
- }
128
-
129
- /** Indicates the data contain in each of the different regions */
130
- enum RegionId {
131
- softDevice = 1 ,
132
- microPython = 2 ,
133
- fs = 3 ,
134
- }
135
-
136
- /**
137
- * .
161
+ * Iterates through the provided Intel Hex Memory Map and tries to find the
162
+ * Flash Regions Table header, by looking for the magic values at the end of
163
+ * each flash page.
164
+ *
165
+ * TODO: Indicate here what errors can be thrown.
138
166
*
139
- * @param iHexMap - .
140
- * @returns {TableHeader }
167
+ * @param iHexMap - Intel Hex memory map to scan for the Flash Regions Table.
168
+ * @param pSize - Flash page size to scan at the end of each page.
169
+ * @returns The table header data.
141
170
*/
142
- function getTableHeader ( iHexMap : MemoryMap ) : TableHeader {
171
+ function getTableHeader ( iHexMap : MemoryMap , pSize : number = 1024 ) : TableHeader {
143
172
let endAddress = 0 ;
144
- for ( let i = 4096 ; i <= 0x80000 ; i += 4096 ) {
173
+ const magic1ToFind = new Uint8Array (
174
+ new Uint32Array ( [ REGION_HEADER_MAGIC_1 ] ) . buffer
175
+ ) ;
176
+ const magic2ToFind = new Uint8Array (
177
+ new Uint32Array ( [ REGION_HEADER_MAGIC_2 ] ) . buffer
178
+ ) ;
179
+ const mapEntries = iHexMap . paginate ( pSize , 0xff ) . entries ( ) ;
180
+ for ( let iter = mapEntries . next ( ) ; ! iter . done ; iter = mapEntries . next ( ) ) {
181
+ if ( ! iter . value ) continue ;
182
+ const blockByteArray : Uint8Array = iter . value [ 1 ] ;
183
+ const subArrayMagic2 = blockByteArray . subarray ( - RegionHeaderOffset . magic2 ) ;
145
184
if (
146
- iHexMap . getUint32 ( i - RegionHeaderOffset . magic2 , true ) ===
147
- REGION_HEADER_MAGIC_2 &&
148
- iHexMap . getUint32 ( i - RegionHeaderOffset . magic_1 , true ) ===
149
- REGION_HEADER_MAGIC_1
185
+ areUint8ArraysEqual ( subArrayMagic2 , magic2ToFind ) &&
186
+ areUint8ArraysEqual (
187
+ blockByteArray . subarray (
188
+ - RegionHeaderOffset . magic1 ,
189
+ - ( RegionHeaderOffset . magic1 - MAGIC_1_LEN_BYTES )
190
+ ) ,
191
+ magic1ToFind
192
+ )
150
193
) {
151
- endAddress = i ;
194
+ const pageStartAddress : number = iter . value [ 0 ] ;
195
+ endAddress = pageStartAddress + pSize ;
152
196
break ;
153
197
}
154
198
}
199
+ // TODO: Throw an error if table is not found.
200
+
155
201
const version = hexMapUtil . getUint16 (
156
202
iHexMap ,
157
203
endAddress - RegionHeaderOffset . version
@@ -169,7 +215,7 @@ function getTableHeader(iHexMap: MemoryMap): TableHeader {
169
215
endAddress - RegionHeaderOffset . pageSizeLog2
170
216
) ;
171
217
const pageSize = Math . pow ( 2 , pageSizeLog2 ) ;
172
- const startAddress = endAddress - RegionHeaderOffset . magic_1 ;
218
+ const startAddress = endAddress - RegionHeaderOffset . magic1 ;
173
219
174
220
return {
175
221
pageSizeLog2,
@@ -183,10 +229,15 @@ function getTableHeader(iHexMap: MemoryMap): TableHeader {
183
229
}
184
230
185
231
/**
186
- * .
232
+ * Parses a Region rows from a Flash Regions Table inside the Intel Hex memory
233
+ * map, which ends at the provided rowEndAddress.
234
+ *
235
+ * Since the Flash Regions Table is placed at the end of a page, we iterate
236
+ * from the end to the beginning.
187
237
*
188
- * @param iHexMap - .
189
- * @param rowEndAddress - .
238
+ * @param iHexMap - Intel Hex memory map to scan for the Flash Regions Table.
239
+ * @param rowEndAddress - Address at which the row ends (same as the address
240
+ * where the next row or table header starts).
190
241
* @returns The Region info from the row.
191
242
*/
192
243
function getRegionRow ( iHexMap : MemoryMap , rowEndAddress : number ) : RegionRow {
@@ -224,15 +275,19 @@ function getRegionRow(iHexMap: MemoryMap, rowEndAddress: number): RegionRow {
224
275
}
225
276
226
277
/**
227
- * Reads the UICR data from an Intel Hex map and retrieves the MicroPython data.
278
+ * Reads the Flash Regions Table data from an Intel Hex map and retrieves the
279
+ * MicroPython DeviceMemInfo data.
228
280
*
229
281
* @throws {Error } When the Magic Header is not present.
282
+ * @throws {Error } When the MicroPython or FS regions are not found.
230
283
*
231
- * @param intelHexMap - Memory map of the Intel Hex data .
232
- * @returns Object with the decoded UICR MicroPython data .
284
+ * @param intelHexMap - Memory map of the Intel Hex to scan .
285
+ * @returns Object with the parsed data from the Flash Regions Table .
233
286
*/
234
- function getHexMapUicrData ( iHexMap : MemoryMap ) : DeviceMemInfo {
235
- const tableHeader = getTableHeader ( iHexMap ) ;
287
+ function getHexMapFlashRegionsData ( iHexMap : MemoryMap ) : DeviceMemInfo {
288
+ // TODO: There is currently have some "internal" knowledge here and it's
289
+ // scanning the flash knowing the page size is 4 KBs
290
+ const tableHeader = getTableHeader ( iHexMap , 4096 ) ;
236
291
const regionRows : { [ id : string ] : RegionRow } = { } ;
237
292
for ( let i = 0 ; i < tableHeader . regionCount ; i ++ ) {
238
293
const rowEndAddress = tableHeader . startAddress - i * REGION_ROW_LEN_BYTES ;
@@ -279,16 +334,17 @@ function getHexMapUicrData(iHexMap: MemoryMap): DeviceMemInfo {
279
334
}
280
335
281
336
/**
282
- * Reads the UICR data from an Intel Hex string and retrieves the MicroPython
283
- * data.
337
+ * Reads the Flash Regions Table data from an Intel Hex map and retrieves the
338
+ * MicroPython DeviceMemInfo data.
284
339
*
285
340
* @throws {Error } When the Magic Header is not present.
341
+ * @throws {Error } When the MicroPython or FS regions are not found.
286
342
*
287
343
* @param intelHex - MicroPython Intel Hex string.
288
- * @returns .
344
+ * @returns Object with the parsed data from the Flash Regions Table .
289
345
*/
290
- function getIntelHexUicrData ( intelHex : string ) : DeviceMemInfo {
291
- return getHexMapUicrData ( MemoryMap . fromHex ( intelHex ) ) ;
346
+ function getIntelHexFlashRegionsData ( intelHex : string ) : DeviceMemInfo {
347
+ return getHexMapFlashRegionsData ( MemoryMap . fromHex ( intelHex ) ) ;
292
348
}
293
349
294
- export { getHexMapUicrData , getIntelHexUicrData } ;
350
+ export { getHexMapFlashRegionsData , getIntelHexFlashRegionsData } ;
0 commit comments