11
11
#include "esp_err.h"
12
12
#include "esp_log.h"
13
13
#include "esp_random.h"
14
+
14
15
#include "esp_ext_part_tables.h"
16
+ #include "esp_ext_part_tables_private.h"
15
17
#include "esp_mbr.h"
18
+ #include "esp_mbr_private.h"
16
19
17
20
#if __has_include (< bsd /sys /queue .h > )
18
21
#include <bsd/sys/queue.h>
22
25
23
26
static const char * TAG = "esp_mbr" ;
24
27
25
- #define MBR_CHS_HEADS 255
26
- #define MBR_CHS_SECTORS_PER_TRACK 63
27
- #define MBR_CHS_MAX_CYLINDER 1023
28
- #define MBR_CHS_MAX_HEAD 254
29
- #define MBR_CHS_MAX_SECTOR 63
30
-
31
- void mbr_set_chs (uint8_t chs [3 ], uint32_t val )
28
+ void esp_mbr_chs_arr_val_set (uint8_t chs [3 ], uint32_t val )
32
29
{
33
30
chs [0 ] = val & 0xFF ;
34
31
chs [1 ] = (val >> 8 ) & 0xFF ;
35
32
chs [2 ] = (val >> 16 ) & 0xFF ;
36
33
}
37
34
38
- uint32_t mbr_get_chs (const uint8_t chs [3 ])
35
+ uint32_t esp_mbr_chs_arr_val_get (const uint8_t chs [3 ])
39
36
{
40
37
return chs [0 ] | (chs [1 ] << 8 ) | (chs [2 ] << 16 );
41
38
}
42
39
43
- void lba_to_chs (uint8_t chs [3 ], uint32_t lba )
40
+ void esp_mbr_lba_to_chs_arr (uint8_t chs [3 ], uint32_t lba )
44
41
{
45
42
uint16_t cylinder ;
46
43
uint8_t head ;
@@ -75,7 +72,7 @@ void lba_to_chs(uint8_t chs[3], uint32_t lba)
75
72
}
76
73
}
77
74
78
- uint32_t lba_align (uint32_t lba , esp_ext_part_sector_size_t sector_size , esp_ext_part_align_t alignment )
75
+ uint32_t esp_mbr_lba_align (uint32_t lba , esp_ext_part_sector_size_t sector_size , esp_ext_part_align_t alignment )
79
76
{
80
77
if (sector_size == 0 || alignment == 0 ) {
81
78
return lba ; // No alignment
@@ -93,6 +90,18 @@ static uint8_t ext_part_type_known_to_mbr_type(esp_ext_part_type_known_t type)
93
90
return 0x06 ; // FAT16B with LBA addressing
94
91
case ESP_EXT_PART_TYPE_FAT32 :
95
92
return 0x0C ; // FAT32 with LBA addressing
93
+ /*
94
+ LittleFS is not a standard MBR partition type, but we can use a custom type `0xC3`, which is not usually used nowadays.
95
+ This allows us to identify LittleFS partitions in the MBR.
96
+
97
+ Explanation why `0xC3` was chosen:
98
+ 0xC 3
99
+ 1100 0011
100
+ ↑↑ ↑ ↑↑↑↑
101
+ └│─│─┴┴┴┴── 0x83 => a modern filesystem (e.g. Linux)
102
+ └─│─────── 0x40 => CHS used as LittleFS block size
103
+ └─────── 0x10 => a hidden filesystem
104
+ */
96
105
case ESP_EXT_PART_TYPE_LITTLEFS :
97
106
return 0xC3 ; // Possibly LittleFS (MBR CHS field => LittleFS block size hack)
98
107
case ESP_EXT_PART_TYPE_EXFAT_OR_NTFS : // Not supported, but we can return a type for it
@@ -173,7 +182,7 @@ static void ext_part_list_item_do_extra(esp_ext_part_list_item_t* item, mbr_part
173
182
switch (item -> info .type ) { // Parsed type
174
183
case ESP_EXT_PART_TYPE_LITTLEFS :
175
184
item -> info .flags |= ESP_EXT_PART_FLAG_EXTRA ; // Set the extra flag to indicate that this partition has extra information
176
- item -> info .extra = mbr_get_chs (partition -> chs_start ); // Put LittleFS block size which was stored in `chs_start` to `extra` field
185
+ item -> info .extra = esp_mbr_chs_arr_val_get (partition -> chs_start ); // Put LittleFS block size which was stored in `chs_start` to `extra` field
177
186
break ;
178
187
default :
179
188
break ;
@@ -195,11 +204,13 @@ esp_err_t esp_mbr_parse(void* mbr_buf,
195
204
return ESP_ERR_NOT_FOUND ;
196
205
}
197
206
207
+ // Set defaults
208
+ part_list -> sector_size = ESP_EXT_PART_SECTOR_SIZE_512B ; // Default sector size
209
+
210
+ // Load extra arguments if provided
198
211
if (extra_args ) {
199
212
if (extra_args -> sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN ) {
200
213
part_list -> sector_size = extra_args -> sector_size ; // Use the sector size hint from extra_args
201
- } else {
202
- part_list -> sector_size = ESP_EXT_PART_SECTOR_SIZE_512B ; // Default sector size
203
214
}
204
215
}
205
216
@@ -240,7 +251,7 @@ esp_err_t esp_mbr_parse(void* mbr_buf,
240
251
esp_ext_part_list_item_t item = {
241
252
.info = {
242
253
.address = partition -> lba_start ,
243
- .sector_count = partition -> sector_count ,
254
+ .size = esp_ext_part_sector_count_to_bytes (( uint64_t ) partition -> sector_count , part_list -> sector_size ) ,
244
255
.extra = 0 ,
245
256
.label = NULL , // MBR does not have labels
246
257
.flags = ESP_EXT_PART_FLAG_NONE ,
@@ -275,14 +286,14 @@ static bool mbr_partition_fill(mbr_partition_t* partition, esp_ext_part_list_ite
275
286
case ESP_EXT_PART_TYPE_FAT16 :
276
287
case ESP_EXT_PART_TYPE_FAT32 :
277
288
// Set CHS values based on LBA start and end
278
- lba_to_chs (partition -> chs_start , lba_start );
279
- lba_to_chs (partition -> chs_end , lba_end );
289
+ esp_mbr_lba_to_chs_arr (partition -> chs_start , lba_start );
290
+ esp_mbr_lba_to_chs_arr (partition -> chs_end , lba_end );
280
291
break ;
281
292
case ESP_EXT_PART_TYPE_LITTLEFS :
282
293
// Use `chs_start` to store LittleFS block size (if stored in `extra` field)
283
294
if (item -> info .extra != 0 ) {
284
295
// If the extra flag is set, use the extra field to store the LittleFS block size
285
- mbr_set_chs (partition -> chs_start , item -> info .extra );
296
+ esp_mbr_chs_arr_val_set (partition -> chs_start , item -> info .extra );
286
297
287
298
if (!(item -> info .flags & ESP_EXT_PART_FLAG_EXTRA )) {
288
299
// If the extra flag is not set but the extra field is set, log a warning
@@ -307,12 +318,14 @@ esp_err_t esp_mbr_generate(mbr_t* mbr,
307
318
return ESP_ERR_INVALID_ARG ;
308
319
}
309
320
321
+ // Set default arguments for MBR generation
310
322
esp_mbr_generate_extra_args_t args = {
311
323
.sector_size = part_list -> sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN ? part_list -> sector_size : ESP_EXT_PART_SECTOR_SIZE_512B , // Default sector size
312
324
.alignment = ESP_EXT_PART_ALIGN_1MiB , // Default alignment
313
325
.keep_signature = false, // Default is to generate a new disk signature
314
326
};
315
327
328
+ // Load extra arguments if provided
316
329
if (extra_args ) {
317
330
if (extra_args -> sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN ) {
318
331
args .sector_size = extra_args -> sector_size ;
@@ -342,15 +355,23 @@ esp_err_t esp_mbr_generate(mbr_t* mbr,
342
355
mbr_partition_t * partition = NULL ;
343
356
esp_ext_part_list_item_t * it = NULL ;
344
357
int i = 0 ;
358
+ uint64_t sector_count ;
345
359
SLIST_FOREACH (it , & part_list -> head , next ) {
360
+ // Check if we have enough space in the MBR partition table
361
+ sector_count = esp_ext_part_bytes_to_sector_count (it -> info .size , args .sector_size );
362
+ if (it -> info .address > UINT32_MAX || sector_count > UINT32_MAX ) {
363
+ ESP_LOGE (TAG , "Partition address or size exceeds 32-bit limit of MBR" );
364
+ return ESP_ERR_NOT_SUPPORTED ; // Address or size too large for MBR
365
+ }
366
+
346
367
partition = (mbr_partition_t * ) & mbr -> partition_table [i ];
347
368
i += 1 ;
348
369
349
370
if (it -> info .flags & ESP_EXT_PART_FLAG_ACTIVE ) {
350
371
partition -> status = MBR_PARTITION_STATUS_ACTIVE ;
351
372
}
352
- partition -> lba_start = lba_align ( it -> info .address , args .sector_size , args .alignment );
353
- partition -> sector_count = it -> info . sector_count ;
373
+ partition -> lba_start = esp_mbr_lba_align (( uint32_t ) it -> info .address , args .sector_size , args .alignment );
374
+ partition -> sector_count = ( uint32_t ) sector_count ;
354
375
partition -> type = ext_part_type_known_to_mbr_type (it -> info .type );
355
376
356
377
if (mbr_partition_fill (partition , it ) == false) {
0 commit comments