406 lines
17 KiB
C
406 lines
17 KiB
C
/* gpt_write.h — Deshab 共享 GPT 写库(static inline,无库)
|
||||
|
|
*
|
|||
|
|
* 前置条件:包含者已定义 u8/u16/u32/u64/i64 基础类型。
|
|||
|
|
* 通过 gpt_init() 注入 block_read/block_write 函数指针(签名与 f32 库一致)。
|
|||
|
|
*
|
|||
|
|
* 能力:
|
|||
|
|
* gpt_probe() — 读 LBA1 校验 "EFI PART" 签名 + header CRC(轻量探测)
|
|||
|
|
* gpt_load() — 加载 GPT 头 + 分区表到内部缓冲,并做 CRC 校验
|
|||
|
|
* gpt_find_esp() — 查找 ESP 分区(type GUID c12a7328-...),输出起始/结束 LBA
|
|||
|
|
* gpt_find_part() — 按任意 type GUID 查找分区
|
|||
|
|
* gpt_update_esp() — 新增/更新 ESP 分区项(改起始/结束 LBA)
|
|||
|
|
* gpt_commit() — 重算 entries CRC + 双 header CRC,写主表/备份表/主头/备份头
|
|||
|
|
* gpt_blank_disk() — 全新初始化:protective MBR + 空 GPT(主+备份,无分区)
|
|||
|
|
*
|
|||
|
|
* 与 build.ps1(New-GptHeader / New-GptFat32Image)字节兼容:
|
|||
|
|
* LBA0 protective MBR(type 0xEE),LBA1 主头,LBA2 主表(128×128B = 32 扇区),
|
|||
|
|
* 备份表 lastLba-32,备份头 lastLba。GUID 按 .NET Guid.ToByteArray()
|
|||
|
|
* little-endian 编码(前三组小端、后两组原序)。
|
|||
|
|
* CRC32 为 IEEE 802.3(init 0xFFFFFFFF / poly 0xEDB88320 / xorout 0xFFFFFFFF),
|
|||
|
|
* 与 build.ps1 Get-Crc32 逐位实现等价。
|
|||
|
|
*
|
|||
|
|
* 缓冲:包含者需提供 ~16.5KB BSS(1 扇区头缓冲 + 32 扇区分区表缓冲)。
|
|||
|
|
*
|
|||
|
|
* 典型流程(FirstInit 写盘 / 系统格式化):
|
|||
|
|
* gpt_init(block_read, block_write);
|
|||
|
|
* if (gpt_probe() != 0) gpt_blank_disk(total_sectors, NULL); // 空盘初始化
|
|||
|
|
* gpt_load();
|
|||
|
|
* gpt_update_esp(2048, total_sectors - 34); // 或扩容
|
|||
|
|
* gpt_commit();
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#ifndef DESHAB_GPT_WRITE_H
|
|||
|
|
#define DESHAB_GPT_WRITE_H
|
|||
|
|
|
|||
|
|
/* ---- block 设备函数类型(与 fat32_io.h 签名一致,index 固定 0) ---- */
|
|||
|
|
typedef int (*gpt_block_read_fn)(u32 index, u64 lba, u32 count, void *buf);
|
|||
|
|
typedef int (*gpt_block_write_fn)(u32 index, u64 lba, u32 count, const void *buf);
|
|||
|
|
|
|||
|
|
static gpt_block_read_fn gpt_blk_read = 0;
|
|||
|
|
static gpt_block_write_fn gpt_blk_write = 0;
|
|||
|
|
|
|||
|
|
/* ---- GPT 常量(与 build.ps1 一致) ---- */
|
|||
|
|
#define GPT_SIG_BYTES 8
|
|||
|
|
#define GPT_ENTRIES 128u
|
|||
|
|
#define GPT_ENTRY_SIZE 128u
|
|||
|
|
#define GPT_ENTRY_SECTORS 32u /* 128×128 / 512 */
|
|||
|
|
#define GPT_FIRST_USABLE 34u /* 2 + 32 */
|
|||
|
|
#define GPT_HEADER_SIZE 92u
|
|||
|
|
#define GPT_REVISION 0x00010000u
|
|||
|
|
#define GPT_MBR_PART_OFF 446 /* protective MBR 分区项偏移 */
|
|||
|
|
|
|||
|
|
/* ---- GPT 头(512B,build.ps1 Set-Le* 布局) ---- */
|
|||
|
|
typedef struct __attribute__((packed)) {
|
|||
|
|
u8 sig[8]; /* "EFI PART" */
|
|||
|
|
u32 revision; /* 0x00010000 */
|
|||
|
|
u32 header_size; /* 92 */
|
|||
|
|
u32 header_crc;
|
|||
|
|
u32 reserved0;
|
|||
|
|
u64 current_lba; /* 主头=1,备份头=lastLba */
|
|||
|
|
u64 backup_lba;
|
|||
|
|
u64 first_usable; /* 34 */
|
|||
|
|
u64 last_usable; /* lastLba - 33 */
|
|||
|
|
u8 disk_guid[16];
|
|||
|
|
u64 entries_lba; /* 主表=2,备份表=lastLba-32 */
|
|||
|
|
u32 entries_count; /* 128 */
|
|||
|
|
u32 entries_size; /* 128 */
|
|||
|
|
u32 entries_crc;
|
|||
|
|
u8 reserved[420];
|
|||
|
|
} gpt_header; /* 512B */
|
|||
|
|
|
|||
|
|
/* ---- 分区项(128B) ---- */
|
|||
|
|
typedef struct __attribute__((packed)) {
|
|||
|
|
u8 type_guid[16]; /* 全 0 = 空槽 */
|
|||
|
|
u8 uniq_guid[16];
|
|||
|
|
u64 first_lba;
|
|||
|
|
u64 last_lba;
|
|||
|
|
u64 attrs;
|
|||
|
|
u16 name[36]; /* UTF-16LE,未用部分为 0 */
|
|||
|
|
} gpt_part_entry;
|
|||
|
|
|
|||
|
|
/* ESP 类型 GUID:c12a7328-f81f-11d2-ba4b-00a0c93ec93b
|
|||
|
|
* (.NET Guid.ToByteArray() 编码:前三组小端、后两组原序) */
|
|||
|
|
static const u8 gpt_guid_esp[16] = {
|
|||
|
|
0x28, 0x73, 0x2a, 0xc1, /* c12a7328 */
|
|||
|
|
0x1f, 0xf8, /* f81f */
|
|||
|
|
0xd2, 0x11, /* 11d2 */
|
|||
|
|
0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/* ---- 内部缓冲(每包含者独立) ---- */
|
|||
|
|
static u8 gpt_sec[512]; /* 单扇区(头/MBR)缓冲 */
|
|||
|
|
static u8 gpt_tbl[GPT_ENTRY_SECTORS * 512]; /* 分区表缓冲(32 扇区) */
|
|||
|
|
static u64 gpt_disk_sectors = 0; /* 磁盘总扇区数(探测后已知) */
|
|||
|
|
|
|||
|
|
/* ---- 初始化:注入 block_read/block_write 函数指针 ---- */
|
|||
|
|
static inline void gpt_init(gpt_block_read_fn rd, gpt_block_write_fn wr) {
|
|||
|
|
gpt_blk_read = rd;
|
|||
|
|
gpt_blk_write = wr;
|
|||
|
|
gpt_disk_sectors = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static inline int gpt_read_sectors(u64 lba, u32 count, u8 *out) {
|
|||
|
|
return gpt_blk_read ? gpt_blk_read(0, lba, count, out) : -1;
|
|||
|
|
}
|
|||
|
|
static inline int gpt_write_sectors(u64 lba, u32 count, const u8 *buf) {
|
|||
|
|
return gpt_blk_write ? gpt_blk_write(0, lba, count, buf) : -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 小工具(无库约束:手写循环替代 mem*) ---- */
|
|||
|
|
static inline void gpt_mem_set(u8 *p, u8 v, u32 n) { for (u32 i = 0; i < n; i++) p[i] = v; }
|
|||
|
|
static inline void gpt_mem_cpy(u8 *d, const u8 *s, u32 n) { for (u32 i = 0; i < n; i++) d[i] = s[i]; }
|
|||
|
|
static inline int gpt_mem_eq(const u8 *a, const u8 *b, u32 n) {
|
|||
|
|
for (u32 i = 0; i < n; i++) if (a[i] != b[i]) return 0;
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
static inline u32 gpt_r32(const u8 *p) {
|
|||
|
|
return (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
|
|||
|
|
}
|
|||
|
|
static inline void gpt_w16(u8 *p, u16 v) { p[0] = (u8)v; p[1] = (u8)(v >> 8); }
|
|||
|
|
static inline void gpt_w32(u8 *p, u32 v) {
|
|||
|
|
p[0] = (u8)v; p[1] = (u8)(v >> 8); p[2] = (u8)(v >> 16); p[3] = (u8)(v >> 24);
|
|||
|
|
}
|
|||
|
|
static inline void gpt_w64(u8 *p, u64 v) {
|
|||
|
|
gpt_w32(p, (u32)v); gpt_w32(p + 4, (u32)(v >> 32));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- CRC32(IEEE 802.3,与 build.ps1 Get-Crc32 逐位实现等价;表驱动) ---- */
|
|||
|
|
static u32 gpt_crc_tab[256];
|
|||
|
|
static int gpt_crc_ready = 0;
|
|||
|
|
|
|||
|
|
static inline void gpt_crc_init(void) {
|
|||
|
|
if (gpt_crc_ready) return;
|
|||
|
|
for (u32 i = 0; i < 256; i++) {
|
|||
|
|
u32 c = i;
|
|||
|
|
for (int k = 0; k < 8; k++)
|
|||
|
|
c = (c & 1) ? (c >> 1) ^ 0xEDB88320u : (c >> 1);
|
|||
|
|
gpt_crc_tab[i] = c;
|
|||
|
|
}
|
|||
|
|
gpt_crc_ready = 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static inline u32 gpt_crc32(const u8 *p, u32 n) {
|
|||
|
|
u32 crc = 0xFFFFFFFFu;
|
|||
|
|
for (u32 i = 0; i < n; i++)
|
|||
|
|
crc = (crc >> 8) ^ gpt_crc_tab[(crc ^ p[i]) & 0xFFu];
|
|||
|
|
return crc ^ 0xFFFFFFFFu;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- GUID 工具 ---- */
|
|||
|
|
|
|||
|
|
/* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" → 16B(.NET ToByteArray 编码)
|
|||
|
|
* 返回 0 成功,-1 格式错误 */
|
|||
|
|
static inline int gpt_guid_from_str(const char *s, u8 out[16]) {
|
|||
|
|
static const int hex[256] = { ['0'] = 0, ['1'] = 1, ['2'] = 2, ['3'] = 3,
|
|||
|
|
['4'] = 4, ['5'] = 5, ['6'] = 6, ['7'] = 7, ['8'] = 8, ['9'] = 9,
|
|||
|
|
['a'] = 10, ['b'] = 11, ['c'] = 12, ['d'] = 13, ['e'] = 14, ['f'] = 15,
|
|||
|
|
['A'] = 10, ['B'] = 11, ['C'] = 12, ['D'] = 13, ['E'] = 14, ['F'] = 15 };
|
|||
|
|
/* 位置表:字符串下标 → 字节下标(1=前四组反序,0=后两组原序) */
|
|||
|
|
static const struct { int str; int byte; int rev; } map[16] = {
|
|||
|
|
{ 0, 3, 1 }, { 2, 2, 1 }, { 4, 1, 1 }, { 6, 0, 1 },
|
|||
|
|
{ 9, 5, 1 }, { 11, 4, 1 },
|
|||
|
|
{ 14, 7, 1 }, { 16, 6, 1 },
|
|||
|
|
{ 19, 8, 0 }, { 21, 9, 0 }, { 23, 10, 0 }, { 25, 11, 0 },
|
|||
|
|
{ 28, 12, 0 }, { 30, 13, 0 }, { 32, 14, 0 }, { 34, 15, 0 },
|
|||
|
|
};
|
|||
|
|
if (s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-') return -1;
|
|||
|
|
for (int i = 0; i < 16; i++) {
|
|||
|
|
int hi = hex[(u8)s[map[i].str]];
|
|||
|
|
int lo = hex[(u8)s[map[i].str + 1]];
|
|||
|
|
if (hi < 0 || lo < 0) return -1;
|
|||
|
|
(void)0;
|
|||
|
|
}
|
|||
|
|
for (int i = 0; i < 16; i++)
|
|||
|
|
out[map[i].byte] = (u8)((hex[(u8)s[map[i].str]] << 4) | hex[(u8)s[map[i].str + 1]]);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 16B → "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"(与 .NET Guid.ToString() 同序) */
|
|||
|
|
static inline void gpt_guid_to_str(const u8 g[16], char out[37]) {
|
|||
|
|
static const char *hd = "0123456789abcdef";
|
|||
|
|
static const struct { int byte; int rev; } om[16] = {
|
|||
|
|
{ 3, 1 }, { 2, 1 }, { 1, 1 }, { 0, 1 },
|
|||
|
|
{ 5, 1 }, { 4, 1 },
|
|||
|
|
{ 7, 1 }, { 6, 1 },
|
|||
|
|
{ 8, 0 }, { 9, 0 }, { 10, 0 }, { 11, 0 },
|
|||
|
|
{ 12, 0 }, { 13, 0 }, { 14, 0 }, { 15, 0 },
|
|||
|
|
};
|
|||
|
|
for (int i = 0; i < 16; i++) {
|
|||
|
|
int b = om[i].byte;
|
|||
|
|
out[i * 2] = hd[g[b] >> 4];
|
|||
|
|
out[i * 2 + 1] = hd[g[b] & 0xF];
|
|||
|
|
if (i == 3 || i == 5 || i == 7 || i == 9) { out[i * 2 + 2] = '-'; }
|
|||
|
|
}
|
|||
|
|
out[36] = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- GPT 头构建 / 校验 ---- */
|
|||
|
|
|
|||
|
|
/* 计算头 CRC:前 92 字节、header_crc 字段按 0 参与 */
|
|||
|
|
static inline u32 gpt_header_crc(const gpt_header *h) {
|
|||
|
|
u8 tmp[92];
|
|||
|
|
gpt_mem_cpy(tmp, (const u8 *)h, 92);
|
|||
|
|
gpt_w32(tmp + 16, 0);
|
|||
|
|
return gpt_crc32(tmp, 92);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 构建头(不落盘):entries_crc 由调用者预先算好 */
|
|||
|
|
static inline void gpt_header_build(gpt_header *h, u64 current_lba, u64 backup_lba,
|
|||
|
|
u64 first_usable, u64 last_usable,
|
|||
|
|
const u8 disk_guid[16],
|
|||
|
|
u64 entries_lba, u32 entries_crc) {
|
|||
|
|
static const u8 sig[8] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
|
|||
|
|
gpt_mem_set((u8 *)h, 0, sizeof(*h));
|
|||
|
|
gpt_mem_cpy(h->sig, sig, 8);
|
|||
|
|
h->revision = GPT_REVISION;
|
|||
|
|
h->header_size = GPT_HEADER_SIZE;
|
|||
|
|
h->current_lba = current_lba;
|
|||
|
|
h->backup_lba = backup_lba;
|
|||
|
|
h->first_usable = first_usable;
|
|||
|
|
h->last_usable = last_usable;
|
|||
|
|
if (disk_guid) gpt_mem_cpy(h->disk_guid, disk_guid, 16);
|
|||
|
|
h->entries_lba = entries_lba;
|
|||
|
|
h->entries_count = GPT_ENTRIES;
|
|||
|
|
h->entries_size = GPT_ENTRY_SIZE;
|
|||
|
|
h->entries_crc = entries_crc;
|
|||
|
|
h->header_crc = gpt_header_crc(h);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 校验 LBA 处的 GPT 头(签名/大小/current_lba/CRC),返回 0 有效 */
|
|||
|
|
static inline int gpt_header_validate(const gpt_header *h, u64 expect_lba) {
|
|||
|
|
static const u8 sig[8] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
|
|||
|
|
if (!gpt_mem_eq(h->sig, sig, 8)) return -1;
|
|||
|
|
if (h->revision != GPT_REVISION || h->header_size < GPT_HEADER_SIZE) return -2;
|
|||
|
|
if (h->current_lba != expect_lba) return -3;
|
|||
|
|
if (gpt_header_crc(h) != h->header_crc) return -4;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 分区表操作(内存缓冲) ---- */
|
|||
|
|
static inline gpt_part_entry *gpt_part(u32 idx) {
|
|||
|
|
return (gpt_part_entry *)(gpt_tbl + idx * GPT_ENTRY_SIZE);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 分区表 CRC(覆盖全部 32 扇区) */
|
|||
|
|
static inline u32 gpt_entries_crc(void) {
|
|||
|
|
return gpt_crc32(gpt_tbl, sizeof(gpt_tbl));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static inline int gpt_part_empty(const gpt_part_entry *e) {
|
|||
|
|
return gpt_mem_eq(e->type_guid, (const u8 *)gpt_guid_esp /* 任意非 0 引用 */, 0) &&
|
|||
|
|
gpt_mem_eq(e->type_guid, e->type_guid, 0); /* 恒真占位,防 -Wunused */
|
|||
|
|
}
|
|||
|
|
static inline int gpt_part_is_free(const gpt_part_entry *e) {
|
|||
|
|
/* type_guid 全 0 = 空槽 */
|
|||
|
|
static const u8 zero16[16] = { 0 };
|
|||
|
|
return gpt_mem_eq(e->type_guid, zero16, 16);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 查找第一个 type_guid 匹配的分区(含全 0 停止),返回索引或 -1 */
|
|||
|
|
static inline int gpt_find_part_type(const u8 type_guid[16], u64 *out_first, u64 *out_last) {
|
|||
|
|
for (u32 i = 0; i < GPT_ENTRIES; i++) {
|
|||
|
|
const gpt_part_entry *e = gpt_part(i);
|
|||
|
|
if (gpt_part_is_free(e)) break;
|
|||
|
|
if (gpt_mem_eq(e->type_guid, type_guid, 16)) {
|
|||
|
|
if (out_first) *out_first = e->first_lba;
|
|||
|
|
if (out_last) *out_last = e->last_lba;
|
|||
|
|
return (int)i;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 查找 ESP 分区,返回索引或 -1 */
|
|||
|
|
static inline int gpt_find_esp(u64 *out_first, u64 *out_last) {
|
|||
|
|
return gpt_find_part_type(gpt_guid_esp, out_first, out_last);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 分区名写入(ASCII → UTF-16LE,最多 36 字符) */
|
|||
|
|
static inline void gpt_part_set_name(gpt_part_entry *e, const char *ascii) {
|
|||
|
|
u32 i = 0;
|
|||
|
|
for (; i < 36 && ascii[i]; i++) gpt_w16((u8 *)&e->name[i], (u16)ascii[i]);
|
|||
|
|
for (; i < 36; i++) gpt_w16((u8 *)&e->name[i], 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 填充分区项到指定槽位(返回 0 成功,-1 槽位越界/非空) */
|
|||
|
|
static inline int gpt_part_fill(u32 idx, const u8 type_guid[16], const u8 uniq_guid[16],
|
|||
|
|
u64 first_lba, u64 last_lba, u64 attrs, const char *name) {
|
|||
|
|
if (idx >= GPT_ENTRIES) return -1;
|
|||
|
|
gpt_part_entry *e = gpt_part(idx);
|
|||
|
|
if (!gpt_part_is_free(e)) return -2;
|
|||
|
|
gpt_mem_cpy(e->type_guid, type_guid, 16);
|
|||
|
|
if (uniq_guid) gpt_mem_cpy(e->uniq_guid, uniq_guid, 16);
|
|||
|
|
else gpt_mem_set(e->uniq_guid, 0, 16);
|
|||
|
|
e->first_lba = first_lba;
|
|||
|
|
e->last_lba = last_lba;
|
|||
|
|
e->attrs = attrs;
|
|||
|
|
gpt_part_set_name(e, name);
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 落盘 / 探测 ---- */
|
|||
|
|
|
|||
|
|
/* 探测 LBA1 是否为有效 GPT(轻量,不加载分区表) */
|
|||
|
|
static inline int gpt_probe(void) {
|
|||
|
|
if (gpt_read_sectors(1, 1, gpt_sec) != 0) return -1;
|
|||
|
|
return gpt_header_validate((const gpt_header *)gpt_sec, 1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 加载主头 + 主分区表到缓冲;校验头/表 CRC。total_sectors 为 0 时跳过盘尾推导 */
|
|||
|
|
static inline int gpt_load(u64 total_sectors) {
|
|||
|
|
if (gpt_read_sectors(1, 1, gpt_sec) != 0) return -1;
|
|||
|
|
const gpt_header *h = (const gpt_header *)gpt_sec;
|
|||
|
|
if (gpt_header_validate(h, 1) != 0) return -2;
|
|||
|
|
if (h->entries_lba != 2 || h->entries_count != GPT_ENTRIES) return -3;
|
|||
|
|
if (gpt_read_sectors(2, GPT_ENTRY_SECTORS, gpt_tbl) != 0) return -4;
|
|||
|
|
if (gpt_entries_crc() != h->entries_crc) return -5;
|
|||
|
|
gpt_disk_sectors = total_sectors;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 全新初始化:protective MBR + 空 GPT(主+备份)。disk_guid 可 NULL(全 0)。
|
|||
|
|
* total_sectors 必须 >= 70(34 + 32 表 + 2 头)。 */
|
|||
|
|
static inline int gpt_blank_disk(u64 total_sectors, const u8 disk_guid[16]) {
|
|||
|
|
if (total_sectors < GPT_FIRST_USABLE + GPT_ENTRY_SECTORS + 2) return -1;
|
|||
|
|
|
|||
|
|
/* LBA0 protective MBR(build.ps1 布局) */
|
|||
|
|
gpt_mem_set(gpt_sec, 0, 512);
|
|||
|
|
gpt_sec[GPT_MBR_PART_OFF + 4] = 0xEE; /* type */
|
|||
|
|
gpt_w32(gpt_sec + GPT_MBR_PART_OFF + 8, 1); /* start LBA */
|
|||
|
|
u64 prot = total_sectors - 1;
|
|||
|
|
if (prot > 0xFFFFFFFFu) prot = 0xFFFFFFFFu;
|
|||
|
|
gpt_w32(gpt_sec + GPT_MBR_PART_OFF + 12, (u32)prot); /* sectors */
|
|||
|
|
gpt_sec[510] = 0x55; gpt_sec[511] = 0xAA;
|
|||
|
|
if (gpt_write_sectors(0, 1, gpt_sec) != 0) return -2;
|
|||
|
|
|
|||
|
|
/* 空分区表 */
|
|||
|
|
gpt_mem_set(gpt_tbl, 0, sizeof(gpt_tbl));
|
|||
|
|
u32 entries_crc = gpt_crc32(gpt_tbl, sizeof(gpt_tbl));
|
|||
|
|
|
|||
|
|
/* 主头(LBA1)+ 备份头(lastLba) */
|
|||
|
|
u64 last_lba = total_sectors - 1;
|
|||
|
|
u64 last_usable = last_lba - GPT_ENTRY_SECTORS - 1;
|
|||
|
|
gpt_header ph, bh;
|
|||
|
|
gpt_header_build(&ph, 1, last_lba, GPT_FIRST_USABLE, last_usable,
|
|||
|
|
disk_guid, 2, entries_crc);
|
|||
|
|
gpt_header_build(&bh, last_lba, 1, GPT_FIRST_USABLE, last_usable,
|
|||
|
|
disk_guid, last_lba - GPT_ENTRY_SECTORS, entries_crc);
|
|||
|
|
|
|||
|
|
if (gpt_write_sectors(1, 1, (const u8 *)&ph) != 0) return -3;
|
|||
|
|
if (gpt_write_sectors(2, GPT_ENTRY_SECTORS, gpt_tbl) != 0) return -4;
|
|||
|
|
if (gpt_write_sectors(last_lba - GPT_ENTRY_SECTORS, GPT_ENTRY_SECTORS, gpt_tbl) != 0) return -5;
|
|||
|
|
if (gpt_write_sectors(last_lba, 1, (const u8 *)&bh) != 0) return -6;
|
|||
|
|
|
|||
|
|
gpt_disk_sectors = total_sectors;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 新增/更新 ESP 分区项(内存缓冲,需 gpt_commit 落盘):
|
|||
|
|
* 已有 ESP 则更新范围,否则填第一个空槽。返回槽位索引或负错误码 */
|
|||
|
|
static inline int gpt_update_esp(u64 first_lba, u64 last_lba,
|
|||
|
|
const u8 uniq_guid[16], const char *name) {
|
|||
|
|
static const u8 zero16[16] = { 0 };
|
|||
|
|
int idx = gpt_find_part_type(gpt_guid_esp, 0, 0);
|
|||
|
|
if (idx >= 0) {
|
|||
|
|
gpt_part_entry *e = gpt_part((u32)idx);
|
|||
|
|
e->first_lba = first_lba;
|
|||
|
|
e->last_lba = last_lba;
|
|||
|
|
if (uniq_guid) gpt_mem_cpy(e->uniq_guid, uniq_guid, 16);
|
|||
|
|
if (name) gpt_part_set_name(e, name);
|
|||
|
|
return idx;
|
|||
|
|
}
|
|||
|
|
/* 找第一个空槽(类型全 0) */
|
|||
|
|
for (u32 i = 0; i < GPT_ENTRIES; i++) {
|
|||
|
|
if (gpt_part_is_free(gpt_part(i)))
|
|||
|
|
return gpt_part_fill(i, gpt_guid_esp, uniq_guid ? uniq_guid : zero16,
|
|||
|
|
first_lba, last_lba, 0, name ? name : "Deshab ESP");
|
|||
|
|
}
|
|||
|
|
return -3; /* 表满 */
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* 提交:重算 entries CRC + 双头 CRC,写主表/备份表/主头/备份头(幂等) */
|
|||
|
|
static inline int gpt_commit(void) {
|
|||
|
|
u64 last_lba = 0;
|
|||
|
|
gpt_header h;
|
|||
|
|
/* 读当前主头,取 last_usable / disk_guid / backup 布局 */
|
|||
|
|
if (gpt_read_sectors(1, 1, gpt_sec) != 0) return -1;
|
|||
|
|
gpt_mem_cpy((u8 *)&h, gpt_sec, sizeof(h));
|
|||
|
|
if (gpt_header_validate(&h, 1) != 0) return -2;
|
|||
|
|
last_lba = h.backup_lba;
|
|||
|
|
|
|||
|
|
u32 entries_crc = gpt_entries_crc();
|
|||
|
|
|
|||
|
|
gpt_header_build(&h, 1, last_lba, h.first_usable, h.last_usable,
|
|||
|
|
h.disk_guid, 2, entries_crc);
|
|||
|
|
gpt_header bh;
|
|||
|
|
gpt_header_build(&bh, last_lba, 1, h.first_usable, h.last_usable,
|
|||
|
|
h.disk_guid, last_lba - GPT_ENTRY_SECTORS, entries_crc);
|
|||
|
|
|
|||
|
|
if (gpt_write_sectors(2, GPT_ENTRY_SECTORS, gpt_tbl) != 0) return -3;
|
|||
|
|
if (gpt_write_sectors(1, 1, (const u8 *)&h) != 0) return -4;
|
|||
|
|
if (gpt_write_sectors(last_lba - GPT_ENTRY_SECTORS, GPT_ENTRY_SECTORS, gpt_tbl) != 0) return -5;
|
|||
|
|
if (gpt_write_sectors(last_lba, 1, (const u8 *)&bh) != 0) return -6;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif /* DESHAB_GPT_WRITE_H */
|