254 lines
9.8 KiB
C
254 lines
9.8 KiB
C
/* diskinfo — Deshab 磁盘工具(diskpart 风格,ELF 全屏工具)
|
||||
|
|
*
|
|||
|
|
* 展示:block 设备清单、GPT 分区表(类型/起始/大小)、ESP FAT32
|
|||
|
|
* 容量统计(总簇/空闲簇/已用%)。只读,不写盘。
|
|||
|
|
*
|
|||
|
|
* 构建: cd CODE/tools/diskinfo ; make
|
|||
|
|
* 输出: SYSTEM/bin/diskinfo.elf(开始菜单 bin/xxx.elf 条目启动)
|
|||
|
|
*/
|
|||
|
|
#include "../../firstInit/ascii_bitmaps.c"
|
|||
|
|
#include "../../sdk/include/deshab/deshab.h"
|
|||
|
|
#include "../../sdk/include/deshab/font.h"
|
|||
|
|
#include "../../tools/fat32_part.h"
|
|||
|
|
|
|||
|
|
static dsb_app_context g_ac;
|
|||
|
|
|
|||
|
|
/* ---- 简易格式化 ---- */
|
|||
|
|
static char *fmt_hex(u64 v, char *buf) {
|
|||
|
|
static const char hx[] = "0123456789ABCDEF";
|
|||
|
|
int n = 0;
|
|||
|
|
char tmp[18];
|
|||
|
|
if (!v) { buf[0] = '0'; buf[1] = 0; return buf; }
|
|||
|
|
while (v && n < 16) { tmp[n++] = hx[v & 0xF]; v >>= 4; }
|
|||
|
|
buf[0] = '0'; buf[1] = 'x';
|
|||
|
|
for (int i = 0; i < n; i++) buf[2 + i] = tmp[n - 1 - i];
|
|||
|
|
buf[2 + n] = 0;
|
|||
|
|
return buf;
|
|||
|
|
}
|
|||
|
|
static char *fmt_dec(u64 v, char *buf) {
|
|||
|
|
char tmp[24]; int n = 0;
|
|||
|
|
if (!v) { buf[0] = '0'; buf[1] = 0; return buf; }
|
|||
|
|
while (v && n < 23) { tmp[n++] = (char)('0' + v % 10); v /= 10; }
|
|||
|
|
for (int i = 0; i < n; i++) buf[i] = tmp[n - 1 - i];
|
|||
|
|
buf[n] = 0;
|
|||
|
|
return buf;
|
|||
|
|
}
|
|||
|
|
/* 拼接:a " / " b */
|
|||
|
|
static char *fmt_pair(u64 a, u64 b, char *buf) {
|
|||
|
|
char t1[24], t2[24];
|
|||
|
|
int i = 0;
|
|||
|
|
const char *s = fmt_dec(a, t1);
|
|||
|
|
while (s[i] && i < 40) { buf[i] = s[i]; i++; }
|
|||
|
|
buf[i++] = ' '; buf[i++] = '/'; buf[i++] = ' ';
|
|||
|
|
const char *s2 = fmt_dec(b, t2);
|
|||
|
|
int j = 0;
|
|||
|
|
while (s2[j] && i < 44) buf[i++] = s2[j++];
|
|||
|
|
buf[i] = 0;
|
|||
|
|
return buf;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#define INFO_X 12
|
|||
|
|
#define INFO_Y_START (DSB_TITLEBAR_H + 8)
|
|||
|
|
#define LINE_H 20
|
|||
|
|
#define COL_LABEL_W 190
|
|||
|
|
|
|||
|
|
static int g_line = 0;
|
|||
|
|
|
|||
|
|
static void info_line(const char *label, const char *value, u32 val_color) {
|
|||
|
|
i64 y = INFO_Y_START + (i64)g_line * LINE_H;
|
|||
|
|
dsb_draw_string(&g_ac, label, INFO_X, y, DSB_TEXT_DIM, DSB_BG_PRIMARY, 12);
|
|||
|
|
dsb_draw_string(&g_ac, value, INFO_X + COL_LABEL_W, y, val_color, DSB_BG_PRIMARY, 12);
|
|||
|
|
g_line++;
|
|||
|
|
}
|
|||
|
|
static void info_section(const char *title) {
|
|||
|
|
i64 y = INFO_Y_START + (i64)g_line * LINE_H;
|
|||
|
|
dsb_draw_string(&g_ac, title, INFO_X, y, DSB_ACCENT_LIGHT, DSB_BG_PRIMARY, 12);
|
|||
|
|
dsb_fill_rect(&g_ac, INFO_X, y + 16, (i64)g_ac.fb_w - INFO_X * 2, 1, DSB_BORDER);
|
|||
|
|
g_line += 2;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- 静态读缓冲 ---- */
|
|||
|
|
static u8 g_sec[512]; /* MBR / GPT 头 / BPB */
|
|||
|
|
static u8 g_ptes[16384]; /* GPT 分区项(128 项 × 128B = 16KB) */
|
|||
|
|
static u8 g_fat[65536]; /* FAT 扫描块(128 扇区) */
|
|||
|
|
|
|||
|
|
static u64 rd64(const u8 *p) {
|
|||
|
|
return (u64)p[0] | ((u64)p[1] << 8) | ((u64)p[2] << 16) | ((u64)p[3] << 24)
|
|||
|
|
| ((u64)p[4] << 32) | ((u64)p[5] << 40) | ((u64)p[6] << 48)
|
|||
|
|
| ((u64)p[7] << 56);
|
|||
|
|
}
|
|||
|
|
static u32 rd32(const u8 *p) {
|
|||
|
|
return (u32)p[0] | ((u32)p[1] << 8) | ((u32)p[2] << 16) | ((u32)p[3] << 24);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* block read 直通(fat32_part_probe 回调签名) */
|
|||
|
|
static int blk_read(u32 index, u64 lba, u32 count, void *buf) {
|
|||
|
|
return g_ac.block.read ? g_ac.block.read(index, lba, count, buf) : -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void dsk_entry(const dsk_boot_context *ctx) {
|
|||
|
|
if (ctx->magic != DSK_BOOT_MAGIC) return;
|
|||
|
|
dsb_app_init(&g_ac, ctx);
|
|||
|
|
char buf[64];
|
|||
|
|
|
|||
|
|
dsb_fill_bg(&g_ac, DSB_BG_PRIMARY);
|
|||
|
|
dsb_draw_titlebar(&g_ac, "DiskInfo - diskpart style", (i64)g_ac.fb_w);
|
|||
|
|
dsb_draw_statusbar(&g_ac, "read-only tool, Esc to exit",
|
|||
|
|
(i64)g_ac.fb_w, (i64)g_ac.fb_h);
|
|||
|
|
|
|||
|
|
/* ---- Block 设备 ---- */
|
|||
|
|
const dkm_kernel_api *api = g_ac.api;
|
|||
|
|
if (!api || !api->block || !api->block->device_count) {
|
|||
|
|
info_section("== Block Devices ==");
|
|||
|
|
info_line("block api", "unavailable", DSB_ERROR);
|
|||
|
|
goto wait_esc;
|
|||
|
|
}
|
|||
|
|
{
|
|||
|
|
u32 ndev = api->block->device_count();
|
|||
|
|
info_section("== Block Devices ==");
|
|||
|
|
info_line("device_count", fmt_dec(ndev, buf), DSB_TEXT_PRIMARY);
|
|||
|
|
for (u32 i = 0; i < ndev && i < 4; i++) {
|
|||
|
|
char label[16];
|
|||
|
|
label[0] = 'd'; label[1] = 'e'; label[2] = 'v'; label[3] = '[';
|
|||
|
|
label[4] = (char)('0' + i); label[5] = ']'; label[6] = 0;
|
|||
|
|
const char *name = api->block->device_name
|
|||
|
|
? api->block->device_name(i) : "?";
|
|||
|
|
info_line(label, name ? name : "?", DSB_ACCENT_LIGHT);
|
|||
|
|
if (api->block->sector_size)
|
|||
|
|
info_line(" sector_size", fmt_dec(api->block->sector_size(i), buf),
|
|||
|
|
DSB_TEXT_PRIMARY);
|
|||
|
|
if (api->block->sector_count)
|
|||
|
|
info_line(" sector_count", fmt_dec(api->block->sector_count(i), buf),
|
|||
|
|
DSB_TEXT_PRIMARY);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- GPT 分区表 ---- */
|
|||
|
|
info_section("== GPT Partitions (disk 0) ==");
|
|||
|
|
if (blk_read(0, 1, 1, g_sec) != 0) {
|
|||
|
|
info_line("read LBA1", "failed", DSB_ERROR);
|
|||
|
|
goto wait_esc;
|
|||
|
|
}
|
|||
|
|
if (!(g_sec[0]=='E' && g_sec[1]=='F' && g_sec[2]=='I' && g_sec[3]==' ' &&
|
|||
|
|
g_sec[4]=='P' && g_sec[5]=='A' && g_sec[6]=='R' && g_sec[7]=='T')) {
|
|||
|
|
info_line("signature", "not GPT (MBR raw?)", DSB_WARNING);
|
|||
|
|
goto wait_esc;
|
|||
|
|
}
|
|||
|
|
{
|
|||
|
|
u64 pte_lba = rd64(g_sec + 72);
|
|||
|
|
u32 nent = rd32(g_sec + 80);
|
|||
|
|
u32 esz = rd32(g_sec + 84);
|
|||
|
|
if (esz == 0 || esz > 512) esz = 128;
|
|||
|
|
if (nent > 128) nent = 128;
|
|||
|
|
info_line("entry_lba", fmt_dec(pte_lba, buf), DSB_TEXT_PRIMARY);
|
|||
|
|
info_line("entries", fmt_dec(nent, buf), DSB_TEXT_PRIMARY);
|
|||
|
|
/* 读 128 项 × 128B = 32 扇区 */
|
|||
|
|
if (blk_read(0, pte_lba, 32, g_ptes) != 0) {
|
|||
|
|
info_line("read PTEs", "failed", DSB_ERROR);
|
|||
|
|
goto wait_esc;
|
|||
|
|
}
|
|||
|
|
int shown = 0;
|
|||
|
|
for (u32 i = 0; i < nent; i++) {
|
|||
|
|
const u8 *e = g_ptes + (u64)i * esz;
|
|||
|
|
int used = 0;
|
|||
|
|
for (int k = 0; k < 16; k++) if (e[k]) { used = 1; break; }
|
|||
|
|
if (!used) continue;
|
|||
|
|
u64 first = rd64(e + 32), last = rd64(e + 40);
|
|||
|
|
int is_esp = 1;
|
|||
|
|
for (int k = 0; k < 16; k++)
|
|||
|
|
if (e[k] != fat32_part_esp_guid[k]) { is_esp = 0; break; }
|
|||
|
|
char lb[24];
|
|||
|
|
lb[0] = 'p'; lb[1] = (char)('1' + i);
|
|||
|
|
lb[2] = is_esp ? '*' : ' ';
|
|||
|
|
lb[3] = 0;
|
|||
|
|
/* 类型 GUID 前 4 字节 + 起始 LBA */
|
|||
|
|
char tv[20];
|
|||
|
|
static const char hx[] = "0123456789ABCDEF";
|
|||
|
|
tv[0] = 't'; tv[1] = 'y'; tv[2] = 'p'; tv[3] = 'e'; tv[4] = '=';
|
|||
|
|
for (int k = 0; k < 4; k++) {
|
|||
|
|
tv[5 + k * 2] = hx[e[k] >> 4];
|
|||
|
|
tv[6 + k * 2] = hx[e[k] & 0xF];
|
|||
|
|
}
|
|||
|
|
tv[13] = 0;
|
|||
|
|
info_line(lb, tv, is_esp ? DSB_ACCENT_LIGHT : DSB_TEXT_PRIMARY);
|
|||
|
|
info_line(" first_lba", fmt_dec(first, buf), DSB_TEXT_DIM);
|
|||
|
|
info_line(" sectors", fmt_dec(last - first + 1, buf), DSB_TEXT_DIM);
|
|||
|
|
shown++;
|
|||
|
|
if (shown >= 8) break;
|
|||
|
|
}
|
|||
|
|
if (!shown) info_line("(no partitions)", "", DSB_TEXT_DIM);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* ---- ESP FAT32 容量 ---- */
|
|||
|
|
info_section("== FAT32 Volume (ESP) ==");
|
|||
|
|
{
|
|||
|
|
u64 base = fat32_part_probe(blk_read, 0);
|
|||
|
|
/* probe 语义:0 = superfloppy(BPB 在 LBA0)或失败;>0 = ESP LBA */
|
|||
|
|
if (blk_read(0, base, 1, g_sec) != 0) {
|
|||
|
|
info_line("read BPB", "failed", DSB_ERROR);
|
|||
|
|
goto wait_esc;
|
|||
|
|
}
|
|||
|
|
if (!fat32_part_bpb_ok(g_sec)) {
|
|||
|
|
info_line("BPB", "invalid", DSB_ERROR);
|
|||
|
|
goto wait_esc;
|
|||
|
|
}
|
|||
|
|
u32 spc = g_sec[13];
|
|||
|
|
u32 rsv = (u32)g_sec[14] | ((u32)g_sec[15] << 8);
|
|||
|
|
u32 nfat = g_sec[16];
|
|||
|
|
u32 spf = rd32(g_sec + 36); /* BPB_FATSz32 */
|
|||
|
|
u32 rootc = rd32(g_sec + 44); /* BPB_RootClus */
|
|||
|
|
u64 tot = rd32(g_sec + 32); /* BPB_TotSec32 */
|
|||
|
|
u64 data_sec = rsv + (u64)nfat * spf;
|
|||
|
|
u64 nclus = (tot > data_sec) ? (tot - data_sec) / spc : 0;
|
|||
|
|
|
|||
|
|
{
|
|||
|
|
char lb[16];
|
|||
|
|
for (int i = 0; i < 11; i++) lb[i] = (char)g_sec[71 + i];
|
|||
|
|
lb[11] = 0;
|
|||
|
|
info_line("label", lb, DSB_ACCENT_LIGHT);
|
|||
|
|
}
|
|||
|
|
info_line("bytes/sector", "512", DSB_TEXT_PRIMARY);
|
|||
|
|
info_line("sectors/cluster", fmt_dec(spc, buf), DSB_TEXT_PRIMARY);
|
|||
|
|
info_line("FAT size(sec x n)", fmt_pair(spf, nfat, buf), DSB_TEXT_PRIMARY);
|
|||
|
|
info_line("root_cluster", fmt_dec(rootc, buf), DSB_TEXT_PRIMARY);
|
|||
|
|
info_line("total clusters", fmt_dec(nclus, buf), DSB_TEXT_PRIMARY);
|
|||
|
|
|
|||
|
|
/* 空闲簇扫描:FAT 区按 64KB 块读,统计 (i>=2 && entry==0) */
|
|||
|
|
if (spf) {
|
|||
|
|
u64 fat_lba = base + rsv;
|
|||
|
|
u64 fat_ent = (u64)spf * 512 / 4;
|
|||
|
|
if (fat_ent > nclus + 2) fat_ent = nclus + 2;
|
|||
|
|
u64 free_c = 0;
|
|||
|
|
u32 chunk_sec = sizeof(g_fat) / 512; /* 128 扇区/块 */
|
|||
|
|
u32 ents_per_chunk = chunk_sec * 128; /* FAT 项/块 */
|
|||
|
|
u64 chunks = (fat_ent + ents_per_chunk - 1) / ents_per_chunk;
|
|||
|
|
for (u64 ch = 0; ch < chunks; ch++) {
|
|||
|
|
if (blk_read(0, fat_lba + ch * chunk_sec, chunk_sec, g_fat) != 0)
|
|||
|
|
break;
|
|||
|
|
for (u32 k = 0; k < ents_per_chunk; k++) {
|
|||
|
|
u64 idx = ch * ents_per_chunk + k;
|
|||
|
|
if (idx < 2 || idx >= fat_ent) continue;
|
|||
|
|
u32 v = rd32(g_fat + k * 4) & 0x0FFFFFFFu;
|
|||
|
|
if (v == 0) free_c++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
info_line("free clusters", fmt_dec(free_c, buf), DSB_SUCCESS);
|
|||
|
|
if (nclus) {
|
|||
|
|
u64 used_pct = (nclus - free_c) * 100 / nclus;
|
|||
|
|
info_line("used", fmt_pair(used_pct, 100, buf), DSB_WARNING);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
wait_esc:
|
|||
|
|
/* 等待 Esc 退出 */
|
|||
|
|
for (;;) {
|
|||
|
|
u8 st = dsb_inb(0x64);
|
|||
|
|
if (st & 1) {
|
|||
|
|
u8 sc = dsb_inb(0x60);
|
|||
|
|
if (sc == 1) break; /* Esc make code */
|
|||
|
|
}
|
|||
|
|
__asm__ volatile("pause");
|
|||
|
|
}
|
|||
|
|
}
|