Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

disk: Support GUID Partition Tables (GPT)

Notes:

* Currently limited to 32-bit sector addresses due to internal Rockbox
APIs. So this means a practical limit of 2TiB per drive.
* Only 'General Data' GPT partition type is recognised, as that's
what SD cards seem to use for exFAT/FAT32.

Note that _booting_ off GPT-partitioned drive will require rebuilding
the various rockbox bootloaders, and even then there may be platform
limitations that preclude this.

Change-Id: Ibfaae1960adcb1e81976d4b60dd596c6d16318e4

+132 -10
+129 -10
firmware/common/disk.c
··· 44 44 #define disk_writer_lock() file_internal_lock_WRITER() 45 45 #define disk_writer_unlock() file_internal_unlock_WRITER() 46 46 47 - /* Partition table entry layout: 47 + /* "MBR" Partition table entry layout: 48 48 ----------------------- 49 49 0: 0x80 - active 50 50 1: starting head ··· 58 58 12-15: nr of sectors in partition 59 59 */ 60 60 61 + #define BYTES2INT64(array, pos) \ 62 + (((uint64_t)array[pos+0] << 0) | \ 63 + ((uint64_t)array[pos+1] << 8) | \ 64 + ((uint64_t)array[pos+2] << 16) | \ 65 + ((uint64_t)array[pos+3] << 24) | \ 66 + ((uint64_t)array[pos+4] << 32) | \ 67 + ((uint64_t)array[pos+5] << 40) | \ 68 + ((uint64_t)array[pos+6] << 48) | \ 69 + ((uint64_t)array[pos+7] << 56) ) 70 + 61 71 #define BYTES2INT32(array, pos) \ 62 72 (((uint32_t)array[pos+0] << 0) | \ 63 73 ((uint32_t)array[pos+1] << 8) | \ ··· 65 75 ((uint32_t)array[pos+3] << 24)) 66 76 67 77 #define BYTES2INT16(array, pos) \ 68 - (((uint32_t)array[pos+0] << 0) | \ 69 - ((uint32_t)array[pos+1] << 8)) 78 + (((uint16_t)array[pos+0] << 0) | \ 79 + ((uint16_t)array[pos+1] << 8)) 70 80 71 81 /* space for 4 partitions on 2 drives */ 72 - static struct partinfo part[NUM_DRIVES*4]; 82 + static struct partinfo part[NUM_DRIVES*MAX_PARTITIONS_PER_DRIVE]; 73 83 /* mounted to which drive (-1 if none) */ 74 84 static int vol_drive[NUM_VOLUMES]; 75 85 ··· 120 130 /* For each drive, start at a different position, in order not to 121 131 destroy the first entry of drive 0. That one is needed to calculate 122 132 config sector position. */ 123 - struct partinfo *pinfo = &part[IF_MD_DRV(drive)*4]; 133 + struct partinfo *pinfo = &part[IF_MD_DRV(drive)*MAX_PARTITIONS_PER_DRIVE]; 134 + uint8_t is_gpt = 0; 124 135 125 136 disk_writer_lock(); 126 137 127 138 /* parse partitions */ 128 - for (int i = 0; i < 4; i++) 139 + for (int i = 0; i < MAX_PARTITIONS_PER_DRIVE && i < 4; i++) 129 140 { 130 141 unsigned char* ptr = sector + 0x1be + 16*i; 131 142 pinfo[i].type = ptr[4]; ··· 140 151 { 141 152 /* not handled yet */ 142 153 } 143 - } 154 + 155 + if (pinfo[i].type == PARTITION_TYPE_GPT_GUARD) { 156 + is_gpt = 1; 157 + } 158 + } 159 + 160 + while (is_gpt) { 161 + /* Re-start partition parsing using GPT */ 162 + uint64_t part_lba; 163 + uint32_t part_entries; 164 + uint32_t part_entry_size; 165 + unsigned char* ptr = sector; 166 + 167 + storage_read_sectors(IF_MD(drive,) 1, 1, sector); 168 + 169 + part_lba = BYTES2INT64(ptr, 0); 170 + if (part_lba != 0x5452415020494645ULL) { 171 + DEBUGF("GPT: Invalid signature\n"); 172 + break; 173 + } 174 + part_entry_size = BYTES2INT32(ptr, 8); 175 + if (part_entry_size != 0x00010000) { 176 + DEBUGF("GPT: Invalid version\n"); 177 + break; 178 + } 179 + part_entry_size = BYTES2INT32(ptr, 12); 180 + if (part_entry_size != 0x5c) { 181 + DEBUGF("GPT: Invalid header size\n"); 182 + break; 183 + } 184 + // XXX checksum header -- u32 @ offset 16 185 + part_entry_size = BYTES2INT32(ptr, 24); 186 + if (part_entry_size != 1) { 187 + DEBUGF("GPT: Invalid header LBA\n"); 188 + break; 189 + } 190 + 191 + part_lba = BYTES2INT64(ptr, 72); 192 + part_entries = BYTES2INT32(ptr, 80); 193 + part_entry_size = BYTES2INT32(ptr, 84); 194 + 195 + int part = 0; 196 + reload: 197 + storage_read_sectors(IF_MD(drive,) part_lba, 1, sector); 198 + uint8_t *pptr = ptr; 199 + while (part < MAX_PARTITIONS_PER_DRIVE && part_entries) { 200 + if (pptr - ptr >= SECTOR_SIZE) { 201 + part_lba++; 202 + goto reload; 203 + } 204 + 205 + /* Parse GPT entry. We only care about the "General Data" type, ie: 206 + EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 207 + LE32 LE16 LE16 BE16 BE16 208 + */ 209 + uint64_t tmp; 210 + tmp = BYTES2INT32(pptr, 0); 211 + if (tmp != 0xEBD0A0A2) 212 + goto skip; 213 + tmp = BYTES2INT16(pptr, 4); 214 + if (tmp != 0xB9E5) 215 + goto skip; 216 + tmp = BYTES2INT16(pptr, 6); 217 + if (tmp != 0x4433) 218 + goto skip; 219 + if (pptr[8] != 0x87 || pptr[9] != 0xc0) 220 + goto skip; 221 + if (pptr[10] != 0x68 || pptr[11] != 0xb6 || pptr[12] != 0xb7 || 222 + pptr[13] != 0x26 || pptr[14] != 0x99 || pptr[15] != 0xc7) 223 + goto skip; 224 + 225 + tmp = BYTES2INT64(pptr, 48); /* Flags */ 226 + if (tmp) { 227 + DEBUGF("GPT: Skip parition with flags\n"); 228 + goto skip; /* Any flag makes us ignore this */ 229 + } 230 + tmp = BYTES2INT64(pptr, 32); /* FIRST LBA */ 231 + if (tmp > UINT32_MAX) { // XXX revisit when we resize struct partinfo! 232 + DEBUGF("GPT: partition starts after 2GiB mark\n"); 233 + goto skip; 234 + } 235 + if (tmp < 34) { 236 + DEBUGF("GPT: Invalid start LBA\n"); 237 + goto skip; 238 + } 239 + pinfo[part].start = tmp; 240 + tmp = BYTES2INT64(pptr, 40); /* LAST LBA */ 241 + if (tmp > UINT32_MAX) { // XXX revisit when we resize struct partinfo! 242 + DEBUGF("GPT: partition ends after 2GiB mark\n"); 243 + goto skip; 244 + } 245 + if (tmp <= pinfo[part].start) { 246 + DEBUGF("GPT: Invalid end LBA\n"); 247 + goto skip; 248 + } 249 + pinfo[part].size = tmp - pinfo[part].start + 1; 250 + pinfo[part].type = PARTITION_TYPE_FAT32_LBA; 144 251 252 + DEBUGF("GPart%d: start: %08lx size: %08lx\n", 253 + part,pinfo[part].start,pinfo[part].size); 254 + part++; 255 + 256 + skip: 257 + pptr += part_entry_size; 258 + part_entries--; 259 + } 260 + 261 + is_gpt = 0; /* To break out of the loop */ 262 + } 145 263 disk_writer_unlock(); 146 264 147 265 init = true; ··· 192 310 disk_sector_multiplier[IF_MD_DRV(drive)] = 1; 193 311 #endif 194 312 195 - 196 - /* try "superfloppy" mode */ 313 + /* try "superfloppy" mode */ 197 314 DEBUGF("Trying to mount sector 0.\n"); 198 315 199 316 if (!fat_mount(IF_MV(volume,) IF_MD(drive,) 0)) ··· 210 327 if (mounted == 0 && volume != -1) /* not a "superfloppy"? */ 211 328 { 212 329 for (int i = CONFIG_DEFAULT_PARTNUM; 213 - volume != -1 && i < 4 && mounted < NUM_VOLUMES_PER_DRIVE; 330 + volume != -1 && i < MAX_PARTITIONS_PER_DRIVE && mounted < NUM_VOLUMES_PER_DRIVE; 214 331 i++) 215 332 { 216 333 if (pinfo[i].type == 0 || pinfo[i].type == 5) 217 334 continue; /* skip free/extended partitions */ 335 + 336 + DEBUGF("Trying to mount partition %d.\n", i); 218 337 219 338 #ifdef MAX_LOG_SECTOR_SIZE 220 339 for (int j = 1; j <= (MAX_LOG_SECTOR_SIZE/SECTOR_SIZE); j <<= 1)
+3
firmware/export/disk.h
··· 35 35 #define PARTITION_TYPE_FAT32_LBA 0x0c 36 36 #define PARTITION_TYPE_FAT16 0x06 37 37 #define PARTITION_TYPE_OS2_HIDDEN_C_DRIVE 0x84 38 + #define PARTITION_TYPE_GPT_GUARD 0xee 39 + 40 + #define MAX_PARTITIONS_PER_DRIVE 4 /* Needs to be at least 4 */ 38 41 39 42 bool disk_init(IF_MD_NONVOID(int drive)); 40 43 bool disk_partinfo(int partition, struct partinfo *info);