Files

254 lines
9.8 KiB
C
Raw Permalink Normal View History

/* 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");
}
}