Skip to main content

cu_sdlogger/
gpt.rs

1use crate::sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
2
3/// Scan the GPT on the SD/eMMC card and return the block range of the Cu29 partition.
4pub fn find_copper_partition<D: BlockDevice>(
5    sd: &D,
6) -> Result<Option<(BlockIdx, BlockCount)>, D::Error> {
7    fn le32(x: &[u8]) -> u32 {
8        u32::from_le_bytes([x[0], x[1], x[2], x[3]])
9    }
10    fn le64(x: &[u8]) -> u64 {
11        u64::from_le_bytes([x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]])
12    }
13
14    // Cu29 TYPE GUID = 29A2E0C9-0000-4C75-9229-000000000029
15    const CU29_TYPE_GUID_ONDISK: [u8; 16] = [
16        0xC9, 0xE0, 0xA2, 0x29, 0x00, 0x00, 0x75, 0x4C, 0x92, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00,
17        0x29,
18    ];
19
20    let mut hdr = [Block::new(); 1];
21    read_blocks(sd, &mut hdr, BlockIdx(1), "gpt-lba1")?;
22    let h: &[u8] = &hdr[0].contents;
23    if &h[0..8] != b"EFI PART" {
24        return Ok(None);
25    }
26
27    let ent_lba = le64(&h[72..80]);
28    let num_ents = le32(&h[80..84]) as usize;
29    let ent_sz = le32(&h[84..88]) as usize;
30    if ent_sz == 0 {
31        return Ok(None);
32    }
33
34    let mut remain = num_ents.checked_mul(ent_sz).unwrap_or(0);
35    let mut lba = ent_lba as u32;
36    let mut buf = [Block::new(); 1];
37
38    while remain > 0 {
39        read_blocks(sd, &mut buf, BlockIdx(lba), "gpt-entry")?;
40        let b = &buf[0].contents;
41        let usable = core::cmp::min(remain, Block::LEN);
42
43        let mut off = 0usize;
44        while off + ent_sz <= usable {
45            let e = &b[off..off + ent_sz];
46            if e[0..16] == CU29_TYPE_GUID_ONDISK {
47                let first = le64(&e[32..40]) as u32;
48                let last = le64(&e[40..48]) as u32;
49                if last >= first {
50                    return Ok(Some((BlockIdx(first), BlockCount(last - first + 1))));
51                }
52            }
53            off += ent_sz;
54        }
55
56        remain -= usable;
57        lba = lba.saturating_add(1);
58    }
59
60    Ok(None)
61}
62
63#[cfg(all(feature = "eh02", not(feature = "eh1")))]
64fn read_blocks<D: BlockDevice>(
65    dev: &D,
66    blocks: &mut [Block],
67    start_block_idx: BlockIdx,
68    reason: &str,
69) -> Result<(), D::Error> {
70    dev.read(blocks, start_block_idx, reason)
71}
72
73#[cfg(feature = "eh1")]
74fn read_blocks<D: BlockDevice>(
75    dev: &D,
76    blocks: &mut [Block],
77    start_block_idx: BlockIdx,
78    _reason: &str,
79) -> Result<(), D::Error> {
80    dev.read(blocks, start_block_idx)
81}