1111#include "esp_err.h"
1212#include "esp_log.h"
1313#include "esp_random.h"
14+
1415#include "esp_ext_part_tables.h"
16+ #include "esp_ext_part_tables_private.h"
1517#include "esp_mbr.h"
18+ #include "esp_mbr_private.h"
1619
1720#if __has_include (< bsd /sys /queue .h > )
1821#include <bsd/sys/queue.h>
2225
2326static const char * TAG = "esp_mbr" ;
2427
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 )
3229{
3330 chs [0 ] = val & 0xFF ;
3431 chs [1 ] = (val >> 8 ) & 0xFF ;
3532 chs [2 ] = (val >> 16 ) & 0xFF ;
3633}
3734
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 ])
3936{
4037 return chs [0 ] | (chs [1 ] << 8 ) | (chs [2 ] << 16 );
4138}
4239
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 )
4441{
4542 uint16_t cylinder ;
4643 uint8_t head ;
@@ -75,7 +72,7 @@ void lba_to_chs(uint8_t chs[3], uint32_t lba)
7572 }
7673}
7774
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 )
7976{
8077 if (sector_size == 0 || alignment == 0 ) {
8178 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)
9390 return 0x06 ; // FAT16B with LBA addressing
9491 case ESP_EXT_PART_TYPE_FAT32 :
9592 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+ */
96105 case ESP_EXT_PART_TYPE_LITTLEFS :
97106 return 0xC3 ; // Possibly LittleFS (MBR CHS field => LittleFS block size hack)
98107 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
173182 switch (item -> info .type ) { // Parsed type
174183 case ESP_EXT_PART_TYPE_LITTLEFS :
175184 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
177186 break ;
178187 default :
179188 break ;
@@ -195,11 +204,13 @@ esp_err_t esp_mbr_parse(void* mbr_buf,
195204 return ESP_ERR_NOT_FOUND ;
196205 }
197206
207+ // Set defaults
208+ part_list -> sector_size = ESP_EXT_PART_SECTOR_SIZE_512B ; // Default sector size
209+
210+ // Load extra arguments if provided
198211 if (extra_args ) {
199212 if (extra_args -> sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN ) {
200213 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
203214 }
204215 }
205216
@@ -239,8 +250,8 @@ esp_err_t esp_mbr_parse(void* mbr_buf,
239250 // Create a new partition item and populate it with the partition info
240251 esp_ext_part_list_item_t item = {
241252 .info = {
242- .address = partition -> lba_start ,
243- .sector_count = partition -> sector_count ,
253+ .address = esp_ext_part_sector_count_to_bytes (( uint64_t ) partition -> lba_start , part_list -> sector_size ) ,
254+ .size = esp_ext_part_sector_count_to_bytes (( uint64_t ) partition -> sector_count , part_list -> sector_size ) ,
244255 .extra = 0 ,
245256 .label = NULL , // MBR does not have labels
246257 .flags = ESP_EXT_PART_FLAG_NONE ,
@@ -275,14 +286,14 @@ static bool mbr_partition_fill(mbr_partition_t* partition, esp_ext_part_list_ite
275286 case ESP_EXT_PART_TYPE_FAT16 :
276287 case ESP_EXT_PART_TYPE_FAT32 :
277288 // 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 );
280291 break ;
281292 case ESP_EXT_PART_TYPE_LITTLEFS :
282293 // Use `chs_start` to store LittleFS block size (if stored in `extra` field)
283294 if (item -> info .extra != 0 ) {
284295 // 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 );
286297
287298 if (!(item -> info .flags & ESP_EXT_PART_FLAG_EXTRA )) {
288299 // 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,
307318 return ESP_ERR_INVALID_ARG ;
308319 }
309320
321+ // Set default arguments for MBR generation
310322 esp_mbr_generate_extra_args_t args = {
311323 .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
312324 .alignment = ESP_EXT_PART_ALIGN_1MiB , // Default alignment
313325 .keep_signature = false, // Default is to generate a new disk signature
314326 };
315327
328+ // Load extra arguments if provided
316329 if (extra_args ) {
317330 if (extra_args -> sector_size != ESP_EXT_PART_SECTOR_SIZE_UNKNOWN ) {
318331 args .sector_size = extra_args -> sector_size ;
@@ -342,15 +355,24 @@ esp_err_t esp_mbr_generate(mbr_t* mbr,
342355 mbr_partition_t * partition = NULL ;
343356 esp_ext_part_list_item_t * it = NULL ;
344357 int i = 0 ;
358+ uint64_t first_sector_address , sector_count ;
345359 SLIST_FOREACH (it , & part_list -> head , next ) {
360+ // Check if we have enough space in the MBR partition table
361+ first_sector_address = esp_ext_part_bytes_to_sector_count (it -> info .address , args .sector_size );
362+ sector_count = esp_ext_part_bytes_to_sector_count (it -> info .size , args .sector_size );
363+ if (first_sector_address > UINT32_MAX || sector_count > UINT32_MAX ) {
364+ ESP_LOGE (TAG , "Partition address or size exceeds 32-bit limit of MBR" );
365+ return ESP_ERR_NOT_SUPPORTED ; // Address or size too large for MBR
366+ }
367+
346368 partition = (mbr_partition_t * ) & mbr -> partition_table [i ];
347369 i += 1 ;
348370
349371 if (it -> info .flags & ESP_EXT_PART_FLAG_ACTIVE ) {
350372 partition -> status = MBR_PARTITION_STATUS_ACTIVE ;
351373 }
352- partition -> lba_start = lba_align ( it -> info . address , args .sector_size , args .alignment );
353- partition -> sector_count = it -> info . sector_count ;
374+ partition -> lba_start = esp_mbr_lba_align (( uint32_t ) first_sector_address , args .sector_size , args .alignment );
375+ partition -> sector_count = ( uint32_t ) sector_count ;
354376 partition -> type = ext_part_type_known_to_mbr_type (it -> info .type );
355377
356378 if (mbr_partition_fill (partition , it ) == false) {
0 commit comments