:: limine / common / drivers / disk.s2.c 25.2 KB raw

1
#include <stdint.h>
2
#include <stddef.h>
3
#include <stdalign.h>
4
#include <drivers/disk.h>
5
#include <lib/libc.h>
6
#if defined (BIOS)
7
#  include <lib/real.h>
8
#elif defined (UEFI)
9
#  include <efi.h>
10
#  include <crypt/blake2b.h>
11
#endif
12
#include <lib/misc.h>
13
#include <lib/print.h>
14
#include <lib/rand.h>
15
#include <mm/pmm.h>
16
#include <sys/cpu.h>
17
#include <pxe/pxe.h>
18
19
#define DEFAULT_FASTEST_XFER_SIZE 64
20
#define MAX_FASTEST_XFER_SIZE 512
21
22
#if defined (BIOS)
23
24
struct dpte {
25
    uint16_t io_port;
26
    uint16_t control_port;
27
    uint8_t head_reg_upper;
28
    uint8_t bios_vendor_specific;
29
    uint8_t irq_info;
30
    uint8_t block_count_multiple;
31
    uint8_t dma_info;
32
    uint8_t pio_info;
33
    uint16_t flags;
34
    uint16_t reserved;
35
    uint8_t revision;
36
    uint8_t checksum;
37
} __attribute__((packed));
38
39
struct bios_drive_params {
40
    uint16_t buf_size;
41
    uint16_t info_flags;
42
    uint32_t cyl;
43
    uint32_t heads;
44
    uint32_t sects;
45
    uint64_t lba_count;
46
    uint16_t bytes_per_sect;
47
    uint16_t dpte_off;
48
    uint16_t dpte_seg;
49
} __attribute__((packed));
50
51
struct dap {
52
    uint16_t size;
53
    uint16_t count;
54
    uint16_t offset;
55
    uint16_t segment;
56
    uint64_t lba;
57
};
58
59
#define XFER_BUF_SIZE (xfer_sizes[SIZEOF_ARRAY(xfer_sizes) - 1] * 512)
60
static const size_t xfer_sizes[] = { 1, 2, 4, 8, 16, 24, 32, 48, 64 };
61
static uint8_t *xfer_buf = NULL;
62
63
static size_t fastest_xfer_size(struct volume *volume) {
64
    struct dap dap = {0};
65
66
    if (xfer_buf == NULL)
67
        xfer_buf = conv_mem_alloc(XFER_BUF_SIZE);
68
69
    size_t fastest_size = 1;
70
    uint64_t last_speed = (uint64_t)-1;
71
72
    for (size_t i = 0; i < SIZEOF_ARRAY(xfer_sizes); i++) {
73
        if (xfer_sizes[i] * volume->sector_size > XFER_BUF_SIZE) {
74
            break;
75
        }
76
77
        dap.size    = 16;
78
        dap.count   = xfer_sizes[i];
79
        dap.segment = rm_seg(xfer_buf);
80
        dap.offset  = rm_off(xfer_buf);
81
        dap.lba     = 0;
82
83
        uint64_t start_timestamp = rdtsc();
84
        for (size_t j = 0; j < XFER_BUF_SIZE / 512; j += xfer_sizes[i]) {
85
            struct rm_regs r = {0};
86
            r.eax = 0x4200;
87
            r.edx = volume->drive;
88
            r.esi = (uint32_t)rm_off(&dap);
89
            r.ds  = rm_seg(&dap);
90
            rm_int(0x13, &r, &r);
91
            if (r.eflags & EFLAGS_CF) {
92
                int ah = (r.eax >> 8) & 0xff;
93
                print("Disk error %x. Drive %x", ah, volume->drive);
94
                return 8;
95
            }
96
            dap.lba += xfer_sizes[i];
97
        }
98
        uint64_t end_timestamp = rdtsc();
99
100
        uint64_t speed = end_timestamp - start_timestamp;
101
102
        if (speed < last_speed) {
103
            last_speed = speed;
104
            fastest_size = xfer_sizes[i];
105
        }
106
    }
107
108
    return fastest_size;
109
}
110
111
int disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t count) {
112
    struct dap dap = {0};
113
114
    if (count * volume->sector_size > XFER_BUF_SIZE)
115
        panic(false, "XFER");
116
117
    if (xfer_buf == NULL)
118
        xfer_buf = conv_mem_alloc(XFER_BUF_SIZE);
119
120
    dap.size    = 16;
121
    dap.count   = count;
122
    dap.segment = rm_seg(xfer_buf);
123
    dap.offset  = rm_off(xfer_buf);
124
    dap.lba     = block;
125
126
    struct rm_regs r = {0};
127
    r.eax = 0x4200;
128
    r.edx = volume->drive;
129
    r.esi = (uint32_t)rm_off(&dap);
130
    r.ds  = rm_seg(&dap);
131
132
    rm_int(0x13, &r, &r);
133
134
    if (r.eflags & EFLAGS_CF) {
135
        return DISK_FAILURE;
136
    }
137
138
    if (buf != NULL)
139
        memcpy(buf, xfer_buf, count * volume->sector_size);
140
141
    return DISK_SUCCESS;
142
}
143
144
static bool detect_sector_size(struct volume *volume) {
145
    struct dap dap = {0};
146
147
    if (xfer_buf == NULL)
148
        xfer_buf = conv_mem_alloc(XFER_BUF_SIZE);
149
150
    dap.size    = 16;
151
    dap.count   = 1;
152
    dap.segment = rm_seg(xfer_buf);
153
    dap.offset  = rm_off(xfer_buf);
154
    dap.lba     = 0;
155
156
    struct rm_regs r = {0};
157
    r.eax = 0x4200;
158
    r.edx = volume->drive;
159
    r.esi = (uint32_t)rm_off(&dap);
160
    r.ds  = rm_seg(&dap);
161
162
    struct rm_regs r_copy = r;
163
    struct dap dap_copy = dap;
164
165
    memset(xfer_buf, 0, XFER_BUF_SIZE);
166
167
    rm_int(0x13, &r, &r);
168
169
    if (r.eflags & EFLAGS_CF) {
170
        return false;
171
    }
172
173
    size_t sector_size_a = 0;
174
    for (long i = XFER_BUF_SIZE - 1; i >= 0; i--) {
175
        if (xfer_buf[i] != 0) {
176
            sector_size_a = i + 1;
177
            break;
178
        }
179
    }
180
181
    r = r_copy;
182
    dap = dap_copy;
183
184
    memset(xfer_buf, 0xff, XFER_BUF_SIZE);
185
186
    rm_int(0x13, &r, &r);
187
188
    if (r.eflags & EFLAGS_CF) {
189
        return false;
190
    }
191
192
    size_t sector_size_b = 0;
193
    for (long i = XFER_BUF_SIZE - 1; i >= 0; i--) {
194
        if (xfer_buf[i] != 0xff) {
195
            sector_size_b = i + 1;
196
            break;
197
        }
198
    }
199
200
    volume->sector_size = sector_size_a > sector_size_b ? sector_size_a : sector_size_b;
201
202
    if (volume->sector_size == 0) {
203
        return false;
204
    }
205
206
    return true;
207
}
208
209
void disk_create_index(void) {
210
    // Disk count (only non-removable) at 0040:0075
211
    uint8_t bda_disk_count = mminb(rm_desegment(0x0040, 0x0075));
212
213
    int optical_indices = 1, hdd_indices = 1, consumed_bda_disks = 0;
214
215
    for (uint8_t drive = 0x80; drive < 0xf0; drive++) {
216
        struct rm_regs r = {0};
217
        struct bios_drive_params drive_params;
218
219
        r.eax = 0x4800;
220
        r.edx = drive;
221
        r.ds  = rm_seg(&drive_params);
222
        r.esi = rm_off(&drive_params);
223
224
        drive_params.buf_size = sizeof(struct bios_drive_params);
225
226
        rm_int(0x13, &r, &r);
227
228
        if (r.eflags & EFLAGS_CF) {
229
            continue;
230
        }
231
232
        bool is_removable = drive_params.info_flags & (1 << 2);
233
234
        struct dpte *dpte = NULL;
235
        if (drive_params.buf_size >= 0x1e
236
         && (drive_params.dpte_seg != 0x0000 || drive_params.dpte_off != 0x0000)
237
         && (drive_params.dpte_seg != 0xffff || drive_params.dpte_off != 0xffff)) {
238
            dpte = (void *)rm_desegment(drive_params.dpte_seg, drive_params.dpte_off);
239
            if ((dpte->control_port & 0xff00) != 0xa000) {
240
                // Check for removable (5) or ATAPI (6)
241
                is_removable = is_removable || ((dpte->flags & (1 << 5)) || (dpte->flags & (1 << 6)));
242
            }
243
        }
244
245
        struct volume *block = ext_mem_alloc(sizeof(struct volume));
246
247
        block->drive = drive;
248
        block->partition = 0;
249
        block->first_sect = 0;
250
        block->max_partition = -1;
251
252
        if (!detect_sector_size(block)) {
253
            pmm_free(block, sizeof(struct volume));
254
            continue;
255
        }
256
257
        // Normalize sect_count to 512-byte sectors for consistency with partitions
258
        // Preserve (uint64_t)-1 sentinel value (means "unknown size")
259
        if (drive_params.lba_count == (uint64_t)-1 || drive_params.lba_count == 0) {
260
            block->sect_count = (uint64_t)-1;
261
        } else {
262
            block->sect_count = drive_params.lba_count * (block->sector_size / 512);
263
        }
264
265
        // Detect optical drives via DPTE ATAPI bit (bit 6) or sector size heuristic
266
        bool is_atapi = (dpte != NULL && (dpte->flags & (1 << 6)));
267
        block->is_optical = is_atapi || (block->sector_size == 2048 && is_removable);
268
269
        // Ugly workaround for VMware, because it puts the optical drive at 0x9f but does
270
        // not expose DPTE.
271
        if (drive == 0x9f && block->sector_size == 2048) {
272
            is_removable = true;
273
            block->is_optical = true;
274
        }
275
276
        if (!is_removable && !block->is_optical) {
277
            if (consumed_bda_disks == bda_disk_count) {
278
                pmm_free(block, sizeof(struct volume));
279
                continue;
280
            }
281
            consumed_bda_disks++;
282
        }
283
284
        if (block->is_optical) {
285
            block->index = optical_indices++;
286
        } else {
287
            block->index = hdd_indices++;
288
        }
289
290
        block->fastest_xfer_size = fastest_xfer_size(block);
291
292
        if (gpt_get_guid(&block->guid, block)) {
293
            block->guid_valid = true;
294
        }
295
296
        volume_index = pmm_realloc(
297
            volume_index,
298
            volume_index_i * sizeof(void *),
299
            (volume_index_i + 1) * sizeof(void *)
300
        );
301
        volume_index[volume_index_i++] = block;
302
303
        for (int part = 0; ; part++) {
304
            struct volume *p = ext_mem_alloc(sizeof(struct volume));
305
            int ret = part_get(p, block, part);
306
307
            if (ret == END_OF_TABLE || ret == INVALID_TABLE) {
308
                pmm_free(p, sizeof(struct volume));
309
                break;
310
            }
311
            if (ret == NO_PARTITION) {
312
                pmm_free(p, sizeof(struct volume));
313
                continue;
314
            }
315
316
            volume_index = pmm_realloc(
317
                volume_index,
318
                volume_index_i * sizeof(void *),
319
                (volume_index_i + 1) * sizeof(void *)
320
            );
321
            volume_index[volume_index_i++] = p;
322
323
            block->max_partition++;
324
        }
325
    }
326
}
327
328
#endif
329
330
#if defined (UEFI)
331
332
int disk_read_sectors(struct volume *volume, void *buf, uint64_t block, size_t count) {
333
    EFI_STATUS status;
334
335
    status = volume->block_io->ReadBlocks(volume->block_io,
336
                               volume->block_io->Media->MediaId,
337
                               block, count * volume->sector_size, buf);
338
339
    switch (status) {
340
        case EFI_SUCCESS: return DISK_SUCCESS;
341
        case EFI_NO_MEDIA: return DISK_NO_MEDIA;
342
        default: return DISK_FAILURE;
343
    }
344
}
345
346
static struct volume *pxe_from_efi_handle(EFI_HANDLE efi_handle) {
347
    static struct volume *vol = NULL;
348
349
    // There's only one PXE volume
350
    if (vol) {
351
        return vol;
352
    }
353
354
    EFI_STATUS status;
355
356
    EFI_GUID pxe_base_code_guid = EFI_PXE_BASE_CODE_PROTOCOL_GUID;
357
    EFI_PXE_BASE_CODE *pxe_base_code = NULL;
358
359
    status = gBS->HandleProtocol(efi_handle, &pxe_base_code_guid, (void **)&pxe_base_code);
360
    if (status) {
361
        return NULL;
362
    }
363
364
    if (!pxe_base_code->Mode->DhcpDiscoverValid) {
365
        print("PXE somehow didn't use DHCP?\n");
366
        return NULL;
367
    }
368
369
    if (pxe_base_code->Mode->UsingIpv6) {
370
        print("Sorry, unsupported: PXE IPv6\n");
371
        return NULL;
372
    }
373
374
    vol = pxe_bind_volume(efi_handle, pxe_base_code);
375
    return vol;
376
}
377
378
#define UNIQUE_SECTOR_POOL_SIZE 65536
379
static uint8_t *unique_sector_pool;
380
static bool unique_sectors_calculated = false;
381
382
static void find_unique_sectors(void);
383
384
static struct volume *volume_by_unique_sector(void *b2b) {
385
    for (size_t i = 0; i < volume_index_i; i++) {
386
        if (volume_index[i]->unique_sector_valid == false) {
387
            continue;
388
        }
389
390
        if (memcmp(volume_index[i]->unique_sector_b2b, b2b, BLAKE2B_OUT_BYTES) == 0) {
391
            return volume_index[i];
392
        }
393
    }
394
395
    return NULL;
396
}
397
398
// Search for matching hash including invalidated volumes (for collision detection)
399
static struct volume *volume_by_sector_hash(void *b2b) {
400
    for (size_t i = 0; i < volume_index_i; i++) {
401
        if (volume_index[i]->unique_sector_valid == false
402
         && memcmp(volume_index[i]->unique_sector_b2b, (uint8_t[BLAKE2B_OUT_BYTES]){0}, BLAKE2B_OUT_BYTES) == 0) {
403
            // Hash was never set, skip
404
            continue;
405
        }
406
407
        if (memcmp(volume_index[i]->unique_sector_b2b, b2b, BLAKE2B_OUT_BYTES) == 0) {
408
            return volume_index[i];
409
        }
410
    }
411
412
    return NULL;
413
}
414
415
static bool is_efi_handle_to_skip(EFI_HANDLE efi_handle) {
416
    EFI_STATUS status;
417
418
    EFI_GUID dp_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
419
    EFI_DEVICE_PATH_PROTOCOL *dp = NULL;
420
421
    EFI_GUID guids_to_skip[] = {
422
        // skip 7CCE9C94-983F-4D0A-8143-B6C05545B223 since it is apparently used by exposed
423
        // ROM devices that we do not want to touch
424
        // (see https://github.com/limine-bootloader/limine/issues/521#issuecomment-3160168795)
425
        {0x7CCE9C94, 0x983F, 0x4D0A, {0x81, 0x43, 0xB6, 0xC0, 0x55, 0x45, 0xB2, 0x23}},
426
    };
427
428
    status = gBS->HandleProtocol(efi_handle, &dp_guid, (void **)&dp);
429
    if (status) {
430
        return false;
431
    }
432
433
    for (;;) {
434
        if (dp->Type == END_DEVICE_PATH_TYPE && dp->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
435
            break;
436
        }
437
438
        uint16_t len = *(uint16_t *)dp->Length;
439
440
        // Validate minimum device path node size before accessing type-specific data
441
        if (len < sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
442
            break;  // Malformed device path node
443
        }
444
445
        if (dp->Type == HARDWARE_DEVICE_PATH && dp->SubType == HW_VENDOR_DP) {
446
            // Vendor device path must be large enough to contain a GUID
447
            if (len >= sizeof(EFI_DEVICE_PATH_PROTOCOL) + sizeof(EFI_GUID)) {
448
                EFI_GUID *vendor_guid = (void *)dp + sizeof(EFI_DEVICE_PATH_PROTOCOL);
449
450
                for (size_t i = 0; i < SIZEOF_ARRAY(guids_to_skip); i++) {
451
                    if (memcmp(vendor_guid, &guids_to_skip[i], sizeof(EFI_GUID)) == 0) {
452
                        return true;
453
                    }
454
                }
455
            }
456
        }
457
        dp = (void *)dp + len;
458
    }
459
460
    return false;
461
}
462
463
static bool is_efi_handle_optical(EFI_HANDLE efi_handle) {
464
    EFI_STATUS status;
465
466
    EFI_GUID dp_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
467
    EFI_DEVICE_PATH_PROTOCOL *dp = NULL;
468
469
    status = gBS->HandleProtocol(efi_handle, &dp_guid, (void **)&dp);
470
    if (status) {
471
        return false;
472
    }
473
474
    for (;;) {
475
        if (dp->Type == END_DEVICE_PATH_TYPE && dp->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
476
            break;
477
        }
478
479
        if (dp->Type == MEDIA_DEVICE_PATH && dp->SubType == MEDIA_CDROM_DP) {
480
            return true;
481
        }
482
483
        uint16_t len = *(uint16_t *)dp->Length;
484
        if (len < sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
485
            break;  // Malformed device path node
486
        }
487
        dp = (void *)dp + len;
488
    }
489
490
    return false;
491
}
492
493
static EFI_DEVICE_PATH_PROTOCOL *get_device_path(EFI_HANDLE efi_handle) {
494
    EFI_STATUS status;
495
    EFI_GUID dp_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
496
    EFI_DEVICE_PATH_PROTOCOL *dp = NULL;
497
498
    status = gBS->HandleProtocol(efi_handle, &dp_guid, (void **)&dp);
499
    if (status) {
500
        return NULL;
501
    }
502
    return dp;
503
}
504
505
// Compare device paths up to (but not including) partition nodes
506
static bool device_paths_match_disk(EFI_DEVICE_PATH_PROTOCOL *dp1,
507
                                    EFI_DEVICE_PATH_PROTOCOL *dp2) {
508
    if (dp1 == NULL || dp2 == NULL) {
509
        return false;
510
    }
511
512
    while (!IsDevicePathEnd(dp1) && !IsDevicePathEnd(dp2)) {
513
        // Stop at partition nodes
514
        if (dp1->Type == MEDIA_DEVICE_PATH &&
515
            (dp1->SubType == MEDIA_HARDDRIVE_DP || dp1->SubType == MEDIA_CDROM_DP)) {
516
            break;
517
        }
518
        if (dp2->Type == MEDIA_DEVICE_PATH &&
519
            (dp2->SubType == MEDIA_HARDDRIVE_DP || dp2->SubType == MEDIA_CDROM_DP)) {
520
            break;
521
        }
522
523
        uint16_t len1 = DevicePathNodeLength(dp1);
524
        uint16_t len2 = DevicePathNodeLength(dp2);
525
526
        if (len1 != len2) {
527
            return false;
528
        }
529
530
        if (len1 < sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
531
            return false;
532
        }
533
534
        if (memcmp(dp1, dp2, len1) != 0) {
535
            return false;
536
        }
537
538
        dp1 = (void *)dp1 + len1;
539
        dp2 = (void *)dp2 + len2;
540
    }
541
542
    return true;
543
}
544
545
static struct volume *volume_by_device_path(EFI_HANDLE query_handle) {
546
    EFI_DEVICE_PATH_PROTOCOL *query_dp = get_device_path(query_handle);
547
    if (query_dp == NULL) {
548
        return NULL;
549
    }
550
551
    for (size_t i = 0; i < volume_index_i; i++) {
552
        EFI_DEVICE_PATH_PROTOCOL *vol_dp = get_device_path(volume_index[i]->efi_handle);
553
        if (vol_dp == NULL) {
554
            continue;
555
        }
556
557
        if (device_paths_match_disk(query_dp, vol_dp)) {
558
            // Convert first_sect from 512-byte sectors to device LBAs
559
            int sector_size = volume_index[i]->sector_size;
560
            if ((volume_index[i]->first_sect * 512) % sector_size) {
561
                continue;  // Misaligned, skip this volume
562
            }
563
            uint64_t first_sect_lba = (volume_index[i]->first_sect * 512) / sector_size;
564
565
            EFI_DEVICE_PATH_PROTOCOL *qp = query_dp;
566
            while (!IsDevicePathEnd(qp)) {
567
                if (qp->Type == MEDIA_DEVICE_PATH && qp->SubType == MEDIA_HARDDRIVE_DP) {
568
                    uint16_t len = DevicePathNodeLength(qp);
569
                    // UEFI spec size is 42 bytes, but sizeof() may be larger due to padding
570
                    if (len < 42) {
571
                        break;
572
                    }
573
                    HARDDRIVE_DEVICE_PATH *query_hd = (HARDDRIVE_DEVICE_PATH *)qp;
574
                    if (first_sect_lba == query_hd->PartitionStart) {
575
                        return volume_index[i];
576
                    }
577
                    break;
578
                }
579
                if (qp->Type == MEDIA_DEVICE_PATH && qp->SubType == MEDIA_CDROM_DP) {
580
                    uint16_t len = DevicePathNodeLength(qp);
581
                    if (len < sizeof(CDROM_DEVICE_PATH)) {
582
                        break;
583
                    }
584
                    CDROM_DEVICE_PATH *query_cd = (CDROM_DEVICE_PATH *)qp;
585
                    if (first_sect_lba == query_cd->PartitionStart) {
586
                        return volume_index[i];
587
                    }
588
                    break;
589
                }
590
                uint16_t len = DevicePathNodeLength(qp);
591
                if (len < sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
592
                    break;
593
                }
594
                qp = (void *)qp + len;
595
            }
596
597
            if (IsDevicePathEnd(qp) && volume_index[i]->partition == 0) {
598
                return volume_index[i];
599
            }
600
        }
601
    }
602
603
    return NULL;
604
}
605
606
struct volume *disk_volume_from_efi_handle(EFI_HANDLE efi_handle) {
607
    EFI_STATUS status;
608
609
    EFI_GUID block_io_guid = BLOCK_IO_PROTOCOL;
610
    EFI_BLOCK_IO *block_io = NULL;
611
612
    if (is_efi_handle_to_skip(efi_handle)) {
613
        return NULL;
614
    }
615
616
    status = gBS->HandleProtocol(efi_handle, &block_io_guid, (void **)&block_io);
617
    if (status) {
618
        return pxe_from_efi_handle(efi_handle);
619
    }
620
621
    // Try device path matching first (primary method)
622
    struct volume *ret = volume_by_device_path(efi_handle);
623
    if (ret != NULL) {
624
        return ret;
625
    }
626
627
    // Fallback to unique sector matching
628
    uint64_t bdev_size = ((uint64_t)block_io->Media->LastBlock + 1) * (uint64_t)block_io->Media->BlockSize;
629
    if (bdev_size >= UNIQUE_SECTOR_POOL_SIZE) {
630
        // Pre-calculate unique sectors before reading query data into
631
        // the pool, since find_unique_sectors() uses the same buffer.
632
        find_unique_sectors();
633
634
        status = block_io->ReadBlocks(block_io, block_io->Media->MediaId,
635
                                      0,
636
                                      UNIQUE_SECTOR_POOL_SIZE,
637
                                      unique_sector_pool);
638
        if (status == 0) {
639
640
            uint8_t b2b[BLAKE2B_OUT_BYTES];
641
            blake2b(b2b, unique_sector_pool, UNIQUE_SECTOR_POOL_SIZE);
642
643
            ret = volume_by_unique_sector(b2b);
644
            if (ret != NULL) {
645
                // Verify size, block size, and partition status match
646
                if (block_io->Media->BlockSize == (uint32_t)ret->sector_size
647
                 && bdev_size == ret->sect_count * 512
648
                 && block_io->Media->LogicalPartition == (ret->partition != 0)) {
649
                    return ret;
650
                }
651
            }
652
        }
653
    }
654
655
    return NULL;
656
}
657
658
static void find_unique_sectors(void) {
659
    if (unique_sectors_calculated) {
660
        return;
661
    }
662
    unique_sectors_calculated = true;
663
664
    EFI_STATUS status;
665
666
    for (size_t i = 0; i < volume_index_i; i++) {
667
        if ((volume_index[i]->first_sect * 512) % volume_index[i]->sector_size) {
668
            continue;
669
        }
670
671
        size_t first_sect = (volume_index[i]->first_sect * 512) / volume_index[i]->sector_size;
672
673
        // sect_count is always in 512-byte sectors
674
        if (volume_index[i]->sect_count * 512 < UNIQUE_SECTOR_POOL_SIZE) {
675
            continue;
676
        }
677
678
        status = volume_index[i]->block_io->ReadBlocks(
679
                            volume_index[i]->block_io,
680
                            volume_index[i]->block_io->Media->MediaId,
681
                            first_sect,
682
                            UNIQUE_SECTOR_POOL_SIZE,
683
                            unique_sector_pool);
684
        if (status != 0) {
685
            continue;
686
        }
687
688
        uint8_t b2b[BLAKE2B_OUT_BYTES];
689
        blake2b(b2b, unique_sector_pool, UNIQUE_SECTOR_POOL_SIZE);
690
691
        // Check for collision BEFORE storing hash (so we don't find ourselves)
692
        // This searches all volumes including previously invalidated ones
693
        struct volume *collision = volume_by_sector_hash(b2b);
694
695
        // Always store the hash so future volumes can detect collisions
696
        memcpy(volume_index[i]->unique_sector_b2b, b2b, BLAKE2B_OUT_BYTES);
697
698
        if (collision == NULL) {
699
            volume_index[i]->unique_sector_valid = true;
700
            continue;
701
        }
702
703
        // Collision found - invalidate both volumes
704
        collision->unique_sector_valid = false;
705
        volume_index[i]->unique_sector_valid = false;
706
    }
707
}
708
709
static void find_part_handles(EFI_HANDLE *handles, size_t handle_count) {
710
    for (size_t i = 0; i < handle_count; i++) {
711
        struct volume *vol = disk_volume_from_efi_handle(handles[i]);
712
        if (vol == NULL) {
713
            continue;
714
        }
715
        vol->efi_part_handle = handles[i];
716
    }
717
}
718
719
void disk_create_index(void) {
720
    EFI_STATUS status;
721
722
    unique_sector_pool = ext_mem_alloc(UNIQUE_SECTOR_POOL_SIZE);
723
724
    EFI_HANDLE tmp_handles[1];
725
726
    EFI_GUID block_io_guid = BLOCK_IO_PROTOCOL;
727
    EFI_HANDLE *handles = tmp_handles;
728
    UINTN handles_size = sizeof(tmp_handles);
729
730
    status = gBS->LocateHandle(ByProtocol, &block_io_guid, NULL, &handles_size, handles);
731
732
    // we only care about the first handle, so ignore if we get EFI_BUFFER_TOO_SMALL
733
    if (status != EFI_BUFFER_TOO_SMALL && status != EFI_SUCCESS) {
734
        EFI_GUID pxe_guid = EFI_PXE_BASE_CODE_PROTOCOL_GUID;
735
        status = gBS->LocateHandle(ByProtocol, &pxe_guid, NULL, &handles_size, handles);
736
        // likewise, all that matters is that the protocol is present
737
        if (status == EFI_BUFFER_TOO_SMALL || status == EFI_SUCCESS) {
738
            return;
739
        }
740
741
        goto fail;
742
    }
743
744
    handles = ext_mem_alloc(handles_size);
745
746
    status = gBS->LocateHandle(ByProtocol, &block_io_guid, NULL, &handles_size, handles);
747
748
    if (status != EFI_SUCCESS) {
749
fail:
750
        panic(false, "LocateHandle for BLOCK_IO_PROTOCOL failed. Machine not supported by Limine UEFI.");
751
    }
752
753
    int optical_indices = 1, hdd_indices = 1;
754
755
    size_t handle_count = handles_size / sizeof(EFI_HANDLE);
756
757
    for (size_t i = 0; i < handle_count; i++) {
758
        EFI_BLOCK_IO *drive = NULL;
759
760
        if (is_efi_handle_to_skip(handles[i])) {
761
            continue;
762
        }
763
764
        status = gBS->HandleProtocol(handles[i], &block_io_guid, (void **)&drive);
765
766
        if (status != 0 || drive == NULL || drive->Media->LastBlock == 0)
767
            continue;
768
769
        if (drive->Media->LogicalPartition)
770
            continue;
771
772
        // Read test to ensure device is responsive (skipping this causes hangs on some systems)
773
        status = drive->ReadBlocks(drive, drive->Media->MediaId, 0, 4096, unique_sector_pool);
774
        if (status) {
775
            continue;
776
        }
777
778
        if (drive->Media->BlockSize == 0) {
779
            continue;
780
        }
781
        if (drive->Media->LastBlock == UINT64_MAX) {
782
            continue;
783
        }
784
785
        struct volume *block = ext_mem_alloc(sizeof(struct volume));
786
787
        bool is_optical = is_efi_handle_optical(handles[i]) ||
788
                          (drive->Media->ReadOnly && drive->Media->BlockSize == 2048);
789
790
        if (is_optical) {
791
            block->index = optical_indices++;
792
            block->is_optical = true;
793
        } else {
794
            block->index = hdd_indices++;
795
        }
796
797
        block->efi_handle = handles[i];
798
        block->block_io = drive;
799
        block->partition = 0;
800
        block->sector_size = drive->Media->BlockSize;
801
        block->first_sect = 0;
802
        // Normalize sect_count to 512-byte sectors for consistency with partitions
803
        block->sect_count = (drive->Media->LastBlock + 1) * (drive->Media->BlockSize / 512);
804
        block->max_partition = -1;
805
806
        if (drive->Revision >= EFI_BLOCK_IO_PROTOCOL_REVISION3) {
807
            block->fastest_xfer_size = drive->Media->OptimalTransferLengthGranularity;
808
        }
809
810
        if (block->fastest_xfer_size == 0) {
811
            block->fastest_xfer_size = DEFAULT_FASTEST_XFER_SIZE;
812
        } else if (block->fastest_xfer_size >= MAX_FASTEST_XFER_SIZE) {
813
            block->fastest_xfer_size = MAX_FASTEST_XFER_SIZE;
814
        }
815
816
        if (gpt_get_guid(&block->guid, block)) {
817
            block->guid_valid = true;
818
        }
819
820
        volume_index = pmm_realloc(
821
            volume_index,
822
            volume_index_i * sizeof(void *),
823
            (volume_index_i + 1) * sizeof(void *)
824
        );
825
        volume_index[volume_index_i++] = block;
826
827
        for (int part = 0; ; part++) {
828
            struct volume _p = {0};
829
830
            int ret = part_get(&_p, block, part);
831
832
            if (ret == END_OF_TABLE || ret == INVALID_TABLE)
833
                break;
834
            if (ret == NO_PARTITION)
835
                continue;
836
837
            struct volume *p = ext_mem_alloc(sizeof(struct volume));
838
            memcpy(p, &_p, sizeof(struct volume));
839
840
            volume_index = pmm_realloc(
841
                volume_index,
842
                volume_index_i * sizeof(void *),
843
                (volume_index_i + 1) * sizeof(void *)
844
            );
845
            volume_index[volume_index_i++] = p;
846
847
            block->max_partition++;
848
        }
849
    }
850
851
    find_part_handles(handles, handle_count);
852
853
    pmm_free(handles, handles_size);
854
}
855
856
#endif
tab: 248 wrap: offon