feat(panic): FUCK [panic] mode=strict|fallback + realtest image variant

- UTSM panic_full returns in fallback mode (logs [PANIC:FALLBACK] + code + hit
  count); panic_halt keeps always-halt sites (CPU exception, VMM-E11 LA57,
  VMM-E15 DSK jump, UTSM-E42 test hook). Call sites given safe continuations.
- Mode passed to DSK/FirstInit/login/desktop via DSK_BOOT_FLAG_PANIC_FALLBACK;
  DKM kernel_api.panic / kern.log.panic return to driver; ext4 fatal aborts the
  op via setjmp/longjmp and DSK falls back to FAT32 ESP.
- build.ps1/Makefile: dev=strict, release=fallback, new realtest (release
  options + strict); default -Variant all; serialized iso packing under -j.
- Fix '*/' inside comments (dkm.h, kernel_api.h, bus.c) that broke the build.
- Includes pending work: dkm_bus service bus, mt7920/wlan drivers, desktop
  files/startmenu/prank, pe-tools, diskinfo, docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Linehu
2026-10-12 23:57:19 +08:00
co-authored by Cursor
parent a7e5b2bc7a
commit 8554a82677
84 changed files with 7325 additions and 484 deletions
+25
View File
@@ -0,0 +1,25 @@
CC ?= clang
LD ?= ld.lld
ROOT := ../../..
OUT := $(ROOT)/SYSTEM/bin/diskinfo.elf
CFLAGS := -target x86_64-unknown-none -std=c11 -ffreestanding -fno-builtin -fno-stack-protector -fpie -mno-red-zone -mno-sse -mno-sse2 -mno-mmx -msoft-float -m64 -Wall -Wextra -I../../sdk/include -I../.. -O2
LDFLAGS := -nostdlib -static -pie -z max-page-size=0x1000 -T linker.ld
C_SOURCES := main.c
OBJECTS := $(C_SOURCES:.c=.o)
.PHONY: all clean
all: $(OUT)
$(OUT): $(OBJECTS) linker.ld
@mkdir -p "$(dir $(OUT))"
$(LD) $(LDFLAGS) -o $@ $(OBJECTS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
powershell -NoProfile -Command "Get-ChildItem -Path . -Recurse -Filter *.o | Remove-Item -Force; if (Test-Path '$(OUT)') { Remove-Item '$(OUT)' -Force }"
+26
View File
@@ -0,0 +1,26 @@
ENTRY(dsk_entry)
PHDRS
{
text PT_LOAD FLAGS(5);
rodata PT_LOAD FLAGS(4);
data PT_LOAD FLAGS(6);
dynamic PT_DYNAMIC FLAGS(4);
}
SECTIONS
{
. = 0x1000;
.text : ALIGN(4K) { *(.text*) } :text
.rodata : ALIGN(4K) { *(.rodata*) } :rodata
.data : ALIGN(4K) {
*(.data*)
*(.data.rel.ro*)
*(COMMON)
} :data
.rela.dyn : ALIGN(8) { *(.rela.dyn*) } :data
.dynamic : ALIGN(8) { *(.dynamic*) } :data :dynamic
.bss : ALIGN(4K) {
*(.bss*)
} :data
}
+253
View File
@@ -0,0 +1,253 @@
/* 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");
}
}
+14 -9
View File
@@ -102,6 +102,17 @@ static inline int f32_disk_load(void) {
return 0;
}
/* FAT 项。卷首 256 扇区缓存盖住时直接读;否则按扇区补读。
* 读失败当成链结束,避免把缓存尾部垃圾当成下一簇。 */
static inline u32 f32_fat_entry(u32 fo) {
if (fo + 4u <= 256u * 512u)
return f32_r32(f32_disk + fo) & 0x0FFFFFFFu;
u8 fat_sec[512];
if (f32_read_sectors(fo / 512u, 1, fat_sec) != 0)
return 0x0FFFFFF8u;
return f32_r32(fat_sec + (fo % 512u)) & 0x0FFFFFFFu;
}
/* ---- 8.3 名字转换 ---- */
/* "file.txt" / "NAME" → 11 字符 8.3 名(大写,空格填充)
@@ -688,9 +699,7 @@ static inline int f32_list_root(f32_list_cb emit, void *user_data) {
f32_name_from_83(dir[e].name, disp);
if (emit(disp, dir[e].fsize, dir[e].attr, user_data) != 0) goto done;
}
u32 fo = fat_byte_off + clus * 4;
if (fo + 4 > sizeof(f32_disk)) break;
clus = f32_r32(f32_disk + fo) & 0x0FFFFFFF;
clus = f32_fat_entry(fat_byte_off + clus * 4);
}
done:
return 0;
@@ -755,9 +764,7 @@ static inline int f32_list_dir(u32 dir_clus, f32_list_entry_cb emit, void *user_
/* 短名项处理完毕,重置 LFN 缓冲等待下一条链 */
fat32_lfn_init(&lfn);
}
u32 fo = fat_byte_off + clus * 4;
if (fo + 4 > sizeof(f32_disk)) break;
clus = f32_r32(f32_disk + fo) & 0x0FFFFFFF;
clus = f32_fat_entry(fat_byte_off + clus * 4);
}
done:
return 0;
@@ -879,9 +886,7 @@ static inline int f32_find_in_dir_lfn(u32 dir_clus, const char *long_name,
}
fat32_lfn_init(&lfn);
}
u32 fo = fat_byte_off + clus * 4;
if (fo + 4 > sizeof(f32_disk)) break;
clus = f32_r32(f32_disk + fo) & 0x0FFFFFFF;
clus = f32_fat_entry(fat_byte_off + clus * 4);
}
not_found:
return -1;
+60
View File
@@ -0,0 +1,60 @@
# build.ps1 — 编译 Deshab PE 系统工具(mingw-w64 g++)
#
# GUI 工具 → SYSTEM/program/*.exe(开始菜单 STARTMENU.CNF 启动,窗口嵌入桌面)
# CLI 工具 → SYSTEM/bin/*.exe(CMD 里敲名字运行,输出走串口)
#
# 编译模式与 CODE/tools/pe-samples/hello64.c 相同:
# -nostartfiles -Wl,--entry,main -Wl,--image-base,0x140000000
# (无 CRT 启动;只准调 pe_shim 表内的 Win32 面)
#
# 用法: powershell -File build.ps1 [-Gxx <g++路径>]
param([string]$GxxPath = "")
$ErrorActionPreference = "Stop"
$Root = (Resolve-Path "$PSScriptRoot\..\..\..").Path
$ProgDir = Join-Path $Root "SYSTEM\program"
$BinDir = Join-Path $Root "SYSTEM\bin"
# 定位 g++:参数 > PATH > msys2 默认位置
$gxx = $null
if ($GxxPath -and (Test-Path $GxxPath)) {
$gxx = $GxxPath
} elseif (Get-Command g++ -ErrorAction SilentlyContinue) {
$gxx = (Get-Command g++).Source
} elseif (Test-Path "C:\msys64\mingw64\bin\g++.exe") {
$gxx = "C:\msys64\mingw64\bin\g++.exe"
} else {
throw "g++ not found (install msys2 mingw-w64 or pass -GxxPath)"
}
Write-Host "[pe-tools] g++ = $gxx"
$Flags = @(
"-O2", "-Wall", "-std=c++17",
"-nostartfiles",
"-Wl,--entry,main",
"-Wl,--image-base,0x140000000"
)
# GUI 工具(user32 消息循环 + gdi32 DIB/BitBlt)
$GuiTools = @("sysinfo", "clock", "paint", "notes")
# CLI 工具(putchar/puts/ExitProcess)
$CliTools = @("pciscan", "portio")
foreach ($t in $GuiTools) {
$src = Join-Path $PSScriptRoot "$t.cpp"
$out = Join-Path $ProgDir "$t.exe"
& $gxx @Flags $src -o $out -lgdi32 -luser32
if ($LASTEXITCODE -ne 0) { throw "build failed: $t" }
Write-Host "[pe-tools] GUI $t -> SYSTEM\program\$t.exe"
}
foreach ($t in $CliTools) {
$src = Join-Path $PSScriptRoot "$t.cpp"
$out = Join-Path $BinDir "$t.exe"
& $gxx @Flags $src -o $out
if ($LASTEXITCODE -ne 0) { throw "build failed: $t" }
Write-Host "[pe-tools] CLI $t -> SYSTEM\bin\$t.exe"
}
Write-Host "[pe-tools] done. (imports must stay within pe_shim table; verify with objdump -p)"
+109
View File
@@ -0,0 +1,109 @@
/* clock.cpp — Deshab 时钟(GUI PE64 工具)
*
* 模拟表盘(时/分/秒针)+ 数字时间/日期,RTC 实时刷新。
* 渲染循环每帧自驱(无 WM_TIMER,SetTimer 在 shim 中是 no-op)。
* Esc 关闭。
*/
#include "pe_tool.h"
static void draw_hand(PT_Canvas *cv, int cx, int cy,
double angle, int len, int width, u32 col) {
/* 角度 0 = 12 点方向,顺时针 */
int ex = cx + (int)(len * angle_sin(angle));
int ey = cy - (int)(len * angle_cos(angle));
pt_line(cv, cx, cy, ex, ey, width, col);
}
/* sin/cos:角度单位 = 圈(0..1)。表盘刻度只需粗精度,
* 用 0.1° 查表 + 线性插值避免引入浮点库调用。 */
static const short S_SIN[91] = { /* sin(0..90°)*10000 */
0, 175, 349, 523, 698, 872, 1045, 1219, 1392, 1564,
1736, 1908, 2079, 2250, 2419, 2588, 2756, 2924, 3090, 3256,
3420, 3584, 3746, 3907, 4067, 4226, 4384, 4540, 4695, 4848,
5000, 5150, 5299, 5446, 5592, 5736, 5878, 6018, 6157, 6293,
6428, 6561, 6691, 6820, 6947, 7071, 7193, 7314, 7431, 7547,
7660, 7771, 7880, 7986, 8090, 8192, 8290, 8387, 8480, 8572,
8660, 8746, 8829, 8910, 8988, 9063, 9135, 9205, 9272, 9336,
9397, 9455, 9511, 9563, 9613, 9659, 9703, 9744, 9781, 9816,
9848, 9877, 9903, 9925, 9945, 9962, 9976, 9986, 9994, 9998,
10000,
};
static double sin_deg(double deg) {
/* 折叠到 [0,90] 再查表插值;deg ∈ [0,360) */
int neg = 0;
if (deg >= 180.0) { deg -= 180.0; neg = 1; }
if (deg >= 90.0) deg = 180.0 - deg;
int i = (int)deg;
if (i > 89) i = 89; /* deg==90 → [89]→[90] 插值 1.0 */
double frac = deg - i;
double v = (S_SIN[i] + (S_SIN[i + 1] - S_SIN[i]) * frac) / 10000.0;
return neg ? -v : v;
}
static double angle_sin(double turns) {
double d = turns * 360.0;
d -= (long)(d / 360.0) * 360.0;
if (d < 0) d += 360.0;
return sin_deg(d);
}
static double angle_cos(double turns) {
return angle_sin(turns + 0.25);
}
static void frame(PT_Canvas *cv) {
pt_fill(cv, 0, 0, cv->w, cv->h, PT_BG);
PT_Time t = pt_rtc_now();
/* 表盘卡 */
int cx = cv->w / 2;
int cy = cv->h / 2 - 20;
int r = cv->h / 3;
if (r > cv->w / 3) r = cv->w / 3;
if (r > 200) r = 200;
if (r < 60) r = 60;
pt_disc(cv, cx, cy, r + 14, PT_CARD);
pt_ring(cv, cx, cy, r + 14, 2, PT_STROKE);
pt_ring(cv, cx, cy, r, 2, PT_STROKE);
/* 刻度:12 大格 */
for (int i = 0; i < 12; i++) {
double a = i / 12.0;
int sx = cx + (int)((r - 14) * angle_sin(a));
int sy = cy - (int)((r - 14) * angle_cos(a));
int ex = cx + (int)((r - 4) * angle_sin(a));
int ey = cy - (int)((r - 4) * angle_cos(a));
pt_line(cv, sx, sy, ex, ey, i % 3 == 0 ? 4 : 2, PT_TEXT2);
}
/* 指针 */
double h_turns = (t.hour % 12) / 12.0 + t.min / 720.0;
double m_turns = t.min / 60.0 + t.sec / 3600.0;
double s_turns = t.sec / 60.0;
draw_hand(cv, cx, cy, h_turns, r / 2, 7, PT_TEXT);
draw_hand(cv, cx, cy, m_turns, r * 3 / 4, 5, PT_TEXT);
draw_hand(cv, cx, cy, s_turns, r - 18, 2, PT_ERROR);
pt_disc(cv, cx, cy, 6, PT_TEXT);
pt_disc(cv, cx, cy, 3, PT_CARD);
/* 数字时间/日期 */
char b[16];
pt_fmt_time(t, b);
pt_text_center(cv, b, cx, cy + r + 26, PT_TEXT);
pt_fmt_date(t, b);
pt_text_center(cv, b, cx, cy + r + 50, PT_TEXT_DIM);
pt_text(cv, "Esc = close", 16, cv->h - 26, PT_TEXT_DIM);
}
int main(void) {
PT_Desc d;
d.w = 420; d.h = 560;
d.title = L"Clock";
d.frame = frame;
d.key = 0;
d.mouse = 0;
return pt_run(&d);
}
+117
View File
@@ -0,0 +1,117 @@
/* notes.cpp — Deshab 记事本(GUI PE64 工具)
*
* 单缓冲文本编辑:WM_CHAR 键入、Backspace 删、Enter 换行、
* 自动折行 + 尾部自动滚动;底部状态栏显示字符数。
* 无文件 IO(shim CreateFileA → PE-E05),纯内存便签。
* Esc 关闭。
*/
#include "pe_tool.h"
#define NOTE_CAP 4096
#define LINE_H 20
#define MARGIN 10
static char g_buf[NOTE_CAP + 1];
static int g_len;
static int g_view_line; /* 顶部可见行 */
/* 折行游标走查:返回总行数,*end_line/*end_col 为缓冲末尾(光标)位置 */
static int layout_walk(int cols, int *end_line, int *end_col) {
int line = 0, col = 0;
for (int i = 0; i < g_len; i++) {
if (g_buf[i] == '\n') { line++; col = 0; continue; }
col++;
if (col >= cols) { line++; col = 0; }
}
*end_line = line;
*end_col = col;
return line + 1;
}
/* shim 键盘合成契约:可打印字符(>=0x20)走 WM_CHAR;Backspace/Enter/Esc
* 等控制键只走 WM_KEYDOWN(vk),WM_CHAR 不合成。 */
static void key(unsigned vk, unsigned ch) {
if (ch) {
if (ch >= 32 && ch < 127 && g_len < NOTE_CAP)
g_buf[g_len++] = (char)ch;
return;
}
if (vk == 8) { /* Backspace */
if (g_len > 0) g_len--;
return;
}
if (vk == 13) { /* Enter */
if (g_len < NOTE_CAP) g_buf[g_len++] = '\n';
return;
}
}
static void frame(PT_Canvas *cv) {
pt_fill(cv, 0, 0, cv->w, cv->h, PT_BG);
int cols = (cv->w - MARGIN * 2) / PT_STEP;
if (cols < 8) cols = 8;
int view_h = cv->h - LINE_H; /* 底部状态栏高度 LINE_H */
int rows = view_h / LINE_H;
if (rows < 1) rows = 1;
int cur_line, cur_col;
int total = layout_walk(cols, &cur_line, &cur_col);
(void)total;
/* 自动滚动:光标保持可见 */
if (cur_line >= g_view_line + rows) g_view_line = cur_line - rows + 1;
if (cur_line < g_view_line) g_view_line = cur_line;
if (g_view_line < 0) g_view_line = 0;
/* 文本区卡片 */
pt_round_fill(cv, MARGIN / 2, MARGIN / 2, cv->w - MARGIN, view_h - MARGIN,
PT_CARD, 8);
/* 折行绘制(只画可见行窗口) */
{
int line = 0, col = 0;
for (int i = 0; i < g_len; i++) {
char c = g_buf[i];
if (c == '\n') { line++; col = 0; continue; }
if (line >= g_view_line && line < g_view_line + rows)
pt_char(cv, c, MARGIN + col * PT_STEP,
MARGIN + (line - g_view_line) * LINE_H, PT_TEXT);
col++;
if (col >= cols) { line++; col = 0; }
if (line >= g_view_line + rows && line > cur_line) break;
}
}
/* 光标(RTC 秒闪烁) */
{
PT_Time t = pt_rtc_now();
if ((t.sec & 1) == 0 && cur_line >= g_view_line &&
cur_line < g_view_line + rows) {
pt_fill(cv, MARGIN + cur_col * PT_STEP,
MARGIN + (cur_line - g_view_line) * LINE_H,
2, LINE_H - 4, PT_ACCENT);
}
}
/* 状态栏 */
char b[24];
int n = pt_dec((u32)g_len, b);
b[n++] = '/';
n += pt_dec(NOTE_CAP, b + n);
b[n] = 0;
pt_fill(cv, 0, cv->h - LINE_H, cv->w, LINE_H, PT_BG);
pt_text(cv, b, MARGIN, cv->h - LINE_H + 2, PT_TEXT_DIM);
pt_text(cv, "Esc = close", cv->w - MARGIN - 11 * PT_STEP,
cv->h - LINE_H + 2, PT_TEXT_DIM);
}
int main(void) {
PT_Desc d;
d.w = 560; d.h = 480;
d.title = L"Notes";
d.frame = frame;
d.key = key;
d.mouse = 0;
return pt_run(&d);
}
+136
View File
@@ -0,0 +1,136 @@
/* paint.cpp — Deshab 画板(GUI PE64 工具)
*
* 顶栏:色板(10 色)+ 笔刷(2/6/12px)+ Clear。
* 客户区:左键拖拽画线(独立持久层,UI 每帧叠加)。
* 键盘:C = 清空;Esc 关闭。
* 无文件 IO(shim CreateFileA → PE-E05),本工具为纯画布。
*/
#include "pe_tool.h"
#define TB_H 52
#define SWATCH_N 10
#define SWATCH_S 24
static const u32 g_swatches[SWATCH_N] = {
PTCOL(0x1A, 0x1A, 0x1A), PTCOL(0xFF, 0xFF, 0xFF),
PTCOL(0xC4, 0x2B, 0x1C), PTCOL(0xF7, 0x63, 0x16),
PTCOL(0xFF, 0xB9, 0x00), PTCOL(0x0F, 0x7B, 0x0F),
PTCOL(0x00, 0x67, 0xC0), PTCOL(0x8B, 0x5C, 0xF6),
PTCOL(0xE3, 0x00, 0x8B), PTCOL(0x8A, 0x8A, 0x8A),
};
static u32 *g_layer; /* 持久绘画层(画布区) */
static int g_layer_w, g_layer_h;
static int g_cvw; /* 实际画布宽(窗口可能被 surface 钳位) */
static int g_color = 6; /* 默认 Win11 蓝 */
static int g_brush = 2; /* 笔刷索引:0=2px 1=6px 2=12px */
static const int g_brush_px[3] = { 2, 6, 12 };
static int g_drawing;
static int g_last_x, g_last_y;
static void layer_alloc(int w, int h) {
g_layer_w = w;
g_layer_h = h;
for (long i = 0; i < (long)w * h; i++) g_layer[i] = PTCOL(0xFF, 0xFF, 0xFF);
}
static void stroke_to(int x, int y) {
int px = g_brush_px[g_brush];
/* 持久层画线(构造视图 canvas) */
PT_Canvas cv;
cv.w = g_layer_w; cv.h = g_layer_h; cv.bits = g_layer;
pt_line(&cv, g_last_x, g_last_y, x, y, px, g_swatches[g_color]);
pt_disc(&cv, x, y, px / 2, g_swatches[g_color]);
g_last_x = x; g_last_y = y;
}
static void mouse(int x, int y, int buttons, int edge) {
int cw = g_cvw;
/* 顶栏命中 */
if (edge & 1) { /* 左键按下 */
if (y < TB_H) {
/* 色板 */
for (int i = 0; i < SWATCH_N; i++) {
int sx = 10 + i * (SWATCH_S + 6);
if (x >= sx && x < sx + SWATCH_S &&
y >= (TB_H - SWATCH_S) / 2 && y < (TB_H - SWATCH_S) / 2 + SWATCH_S) {
g_color = i;
return;
}
}
/* 笔刷 */
for (int i = 0; i < 3; i++) {
int bx = 10 + SWATCH_N * (SWATCH_S + 6) + 12 + i * 40;
if (x >= bx && x < bx + 36 && y >= 8 && y < TB_H - 8) {
g_brush = i;
return;
}
}
/* Clear */
int cx = cw - 80;
if (x >= cx && x < cx + 72 && y >= 12 && y < TB_H - 12) {
layer_alloc(g_layer_w, g_layer_h);
return;
}
return;
}
/* 画布起笔 */
g_drawing = 1;
g_last_x = x; g_last_y = y - TB_H;
stroke_to(x, y - TB_H);
return;
}
if (edge & 2) g_drawing = 0;
if (buttons & 1 && g_drawing && y >= TB_H)
stroke_to(x, y - TB_H);
}
static void key(unsigned vk, unsigned ch) {
if (ch == 'c' || ch == 'C') layer_alloc(g_layer_w, g_layer_h);
}
static void frame(PT_Canvas *cv) {
g_cvw = cv->w;
/* 画布层 → DIB */
for (int r = 0; r < g_layer_h && r + TB_H < cv->h; r++)
for (int q = 0; q < g_layer_w && q < cv->w; q++)
cv->bits[(long)(r + TB_H) * cv->w + q] = g_layer[(long)r * g_layer_w + q];
/* 顶栏 */
pt_fill(cv, 0, 0, cv->w, TB_H, PT_BG);
pt_fill(cv, 0, TB_H - 1, cv->w, 1, PT_STROKE);
for (int i = 0; i < SWATCH_N; i++) {
int sx = 10 + i * (SWATCH_S + 6);
int sy = (TB_H - SWATCH_S) / 2;
pt_round_fill(cv, sx, sy, SWATCH_S, SWATCH_S, g_swatches[i], 6);
if (g_color == i)
pt_rect(cv, sx - 2, sy - 2, SWATCH_S + 4, SWATCH_S + 4, PT_ACCENT);
}
for (int i = 0; i < 3; i++) {
int bx = 10 + SWATCH_N * (SWATCH_S + 6) + 12 + i * 40;
int bc = g_brush == i ? PT_ACCENT : PT_TEXT2;
pt_disc(cv, bx + 18, TB_H / 2, g_brush_px[i] / 2 + 1, bc);
if (g_brush == i)
pt_rect(cv, bx, 8, 36, TB_H - 16, PT_ACCENT);
}
pt_round_fill(cv, cv->w - 80, 12, 72, TB_H - 24, PT_CARD, 4);
pt_rect(cv, cv->w - 80, 12, 72, TB_H - 24, PT_STROKE);
pt_text_center(cv, "Clear", cv->w - 44, TB_H / 2 - 9, PT_TEXT);
pt_text(cv, "C = clear Esc = close", 10, cv->h - 24, PT_TEXT_DIM);
}
int main(void) {
static u32 layer_mem[900 * 700]; /* 静态层:msvcrt malloc shim 可用,但静态最稳 */
g_layer = layer_mem;
PT_Desc d;
d.w = 700; d.h = 560;
d.title = L"Paint";
d.frame = frame;
d.key = key;
d.mouse = mouse;
/* 层尺寸按期望值预分配;pt_run 钳位后窗口只会更小(绘制有界) */
layer_alloc(700, 560 - TB_H);
return pt_run(&d);
}
+136
View File
@@ -0,0 +1,136 @@
/* pciscan.cpp — Deshab PCI/CPU 扫描(控制台 PE64 工具)
*
* 在 CMD 里敲 "pciscan" 运行(cmd.elf PATH:FAT32 根 → bin/)。
* 输出走串口(shim putchar/puts → COM1;QEMU -serial stdio 可见)。
* 注意 shim printf 仅支持 3 个格式参数 —— 全部输出用自制助手拼行。
*
* 内容:CPUID 厂商/型号串/核心数/hypervisor 位 + PCI 配置空间枚举
* (bus 0-3,0xCF8/0xCFC 直读,Ring0 原生执行)+ RTC 日期时间。
*/
#include <windows.h>
typedef unsigned int u32;
typedef unsigned char u8;
typedef unsigned short u16;
static inline void outp(u16 port, u32 v) {
__asm__ volatile("outl %0,%1" :: "a"(v), "Nd"(port));
}
static inline u32 inp(u16 port) {
u32 v;
__asm__ volatile("inl %1,%0" : "=a"(v) : "Nd"(port));
return v;
}
static inline u8 inpb(u16 port) {
u8 v;
__asm__ volatile("inb %1,%0" : "=a"(v) : "Nd"(port));
return v;
}
static inline void outpb(u16 port, u8 v) {
__asm__ volatile("outb %0,%1" :: "a"(v), "Nd"(port));
}
/* ---- 输出助手(shim printf 参数受限,逐段 puts/putchar 拼行) ---- */
static void ps(const char *s) { while (*s) putchar(*s++); }
static void pch(char c) { putchar(c); }
static void pd(u32 v) {
char b[12];
int n = 0;
if (v == 0) { pch('0'); return; }
while (v > 0) { b[n++] = (char)('0' + v % 10); v /= 10; }
while (n > 0) pch(b[--n]);
}
static void ph(u32 v) {
static const char hd[] = "0123456789ABCDEF";
ps("0x");
for (int i = 7; i >= 0; i--) pch(hd[(v >> (i * 4)) & 0xF]);
}
static void ph4(u32 v) {
static const char hd[] = "0123456789ABCDEF";
for (int i = 3; i >= 0; i--) pch(hd[(v >> (i * 4)) & 0xF]);
}
static u32 pci_read(u16 bus, u16 dev, u16 fn, u8 off) {
outp(0xCF8, 0x80000000u | ((u32)bus << 16) | ((u32)dev << 11)
| ((u32)fn << 8) | off);
return inp(0xCFC);
}
static void cpuid_(u32 leaf, u32 *a, u32 *b, u32 *c, u32 *d) {
__asm__ volatile("cpuid" : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
: "a"(leaf), "c"(0));
}
static int bcd(u8 v) { return (v >> 4) * 10 + (v & 0xF); }
int main(void) {
/* ---- CPU ---- */
u32 a, b, c, d;
cpuid_(0, &a, &b, &c, &d);
char vendor[13];
((u32 *)vendor)[0] = b; ((u32 *)vendor)[1] = d; ((u32 *)vendor)[2] = c;
vendor[12] = 0;
ps("Deshab pciscan\r\n");
ps("CPU vendor: "); ps(vendor); ps("\r\n");
ps("CPUID max leaf: "); ph(a); ps("\r\n");
char brand[49];
brand[0] = 0;
if (a >= 0x80000004u) {
for (u32 leaf = 0x80000002u; leaf <= 0x80000004u; leaf++) {
cpuid_(leaf, &a, &b, &c, &d);
int off = (int)(leaf - 0x80000002u) * 16;
((u32 *)brand)[off / 4 + 0] = a;
((u32 *)brand)[off / 4 + 1] = b;
((u32 *)brand)[off / 4 + 2] = c;
((u32 *)brand)[off / 4 + 3] = d;
}
brand[48] = 0;
ps("CPU brand: "); ps(brand); ps("\r\n");
}
cpuid_(1, &a, &b, &c, &d);
ps("CPU cores (max APIC id): "); pd((b >> 16) & 0xFF); ps("\r\n");
ps("Hypervisor: "); ps(((c >> 31) & 1) ? "yes" : "no"); ps("\r\n");
/* ---- PCI ---- */
ps("\r\nPCI devices (bus 0-3):\r\n");
int found = 0;
for (u16 bus = 0; bus < 4; bus++) {
for (u16 dev = 0; dev < 32; dev++) {
for (u16 fn = 0; fn < 8; fn++) {
u32 vd = pci_read(bus, dev, fn, 0);
u16 ven = vd & 0xFFFF, dev_id = vd >> 16;
if (ven == 0xFFFF) continue;
u32 cl = pci_read(bus, dev, fn, 8);
u32 ht = pci_read(bus, dev, fn, 12);
ps(" ");
pd(bus); pch(':'); pd(dev); pch('.'); pch((char)('0' + fn));
ps(" ");
ph4(ven); pch(':'); ph4(dev_id);
ps(" class "); ph4((cl >> 16) & 0xFFFF);
ps(" rev "); ph4(cl & 0xFF);
pch('\r'); pch('\n');
found++;
/* 非 multifunction 设备跳过 fn>0 */
if (fn == 0 && !((ht >> 16) & 0x80)) break;
}
}
}
ps("Total PCI functions: "); pd((u32)found); ps("\r\n");
/* ---- RTC ---- */
outpb(0x70, 0x09); int yy = bcd(inpb(0x71));
outpb(0x70, 0x08); int mo = bcd(inpb(0x71));
outpb(0x70, 0x07); int dd = bcd(inpb(0x71));
outpb(0x70, 0x04); int hh = bcd(inpb(0x71));
outpb(0x70, 0x02); int mi = bcd(inpb(0x71));
outpb(0x70, 0x00); int ss = bcd(inpb(0x71));
if (yy < 100) yy += 2000;
ps("RTC: "); pd((u32)yy); pch('-'); pd((u32)mo); pch('-'); pd((u32)dd);
pch(' '); pd((u32)hh); pch(':'); pd((u32)mi); pch(':'); pd((u32)ss);
ps("\r\n");
ps("done.\r\n");
ExitProcess(0);
return 0;
}
+341
View File
@@ -0,0 +1,341 @@
/* pe_tool.h — Deshab PE GUI 工具公共运行时
*
* 目标环境:Deshab UTSM PE 兼容层(pe_shim 窗口模式 run_windowed)。
* 编译:mingw-w64 g++ -nostartfiles -Wl,--entry,main -Wl,--image-base,0x140000000
*
* 可用 Win32 面(pe_shim 表内子集):
* user32: RegisterClassExW/CreateWindowExW/PeekMessageW/TranslateMessage/
* DispatchMessageW/PostQuitMessage/DefWindowProcW/GetSystemMetrics
* gdi32: CreateCompatibleDC/CreateDIBSection/SelectObject/BitBlt
* kernel32: ExitProcess/GetTickCount/QueryPerformanceCounter/Frequency
*
* 不可用(调了即未实现 stub / panic):
* TextOut*/SetPixel 等 GDI 绘制(自带 11x18 位图字体 + DIB 直写像素)
* 文件 IO(CreateFileA → PE-E05 panic)
* WM_TIMER(SetTimer 为 no-op;渲染循环每帧自驱)
*
* PE32+ 在 Ring0 原生执行 → 端口 I/O(CMOS RTC)直接可用。
*/
#ifndef DESHAB_PE_TOOL_H
#define DESHAB_PE_TOOL_H
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
typedef unsigned int u32;
typedef unsigned char u8;
typedef unsigned short u16;
/* ---- 端口 I/O(Ring0 原生) ---- */
static inline void pt_outb(u16 port, u8 v) {
__asm__ volatile("outb %0,%1" :: "a"(v), "Nd"(port));
}
static inline u8 pt_inb(u16 port) {
u8 v;
__asm__ volatile("inb %1,%0" : "=a"(v) : "Nd"(port));
return v;
}
/* ---- 11x18 ASCII 位图字体(与 firstInit/desktop 同表) ---- */
#include "../../firstInit/ascii_bitmaps.c"
/* ---- 画布(32bpp top-down DIB) ---- */
struct PT_Canvas {
int w, h;
u32 *bits;
};
#define PTCOL(r, g, b) (0xFF000000u | ((u32)(r) << 16) | ((u32)(g) << 8) | (u32)(b))
/* Win11 Light 主题令牌(与 fluent_ui.h g_wf_light 对齐) */
#define PT_BG PTCOL(0xF3, 0xF3, 0xF3) /* 页面底 */
#define PT_CARD PTCOL(0xFF, 0xFF, 0xFF) /* 卡片底 */
#define PT_STROKE PTCOL(0xD6, 0xD6, 0xD6) /* 控件描边 */
#define PT_TEXT PTCOL(0x1A, 0x1A, 0x1A) /* 主文本 */
#define PT_TEXT2 PTCOL(0x5D, 0x5D, 0x5D) /* 次文本 */
#define PT_TEXT_DIM PTCOL(0x8A, 0x8A, 0x8A) /* 弱文本 */
#define PT_ACCENT PTCOL(0x00, 0x67, 0xC0) /* Win11 蓝 */
#define PT_ACCENT_LT PTCOL(0x00, 0x78, 0xD4)
#define PT_ERROR PTCOL(0xC4, 0x2B, 0x1C)
#define PT_SUCCESS PTCOL(0x0F, 0x7B, 0x0F)
static inline void pt_px(PT_Canvas *c, int x, int y, u32 col) {
if (x < 0 || x >= c->w || y < 0 || y >= c->h) return;
c->bits[(long)y * c->w + x] = col;
}
static inline void pt_fill(PT_Canvas *c, int x, int y, int w, int h, u32 col) {
for (int r = 0; r < h; r++)
for (int q = 0; q < w; q++)
pt_px(c, x + q, y + r, col);
}
static inline void pt_rect(PT_Canvas *c, int x, int y, int w, int h, u32 col) {
for (int q = 0; q < w; q++) { pt_px(c, x + q, y, col); pt_px(c, x + q, y + h - 1, col); }
for (int r = 0; r < h; r++) { pt_px(c, x, y + r, col); pt_px(c, x + w - 1, y + r, col); }
}
static inline void pt_round_fill(PT_Canvas *c, int x, int y, int w, int h,
u32 col, int rad) {
if (rad > w / 2) rad = w / 2;
if (rad > h / 2) rad = h / 2;
for (int r = 0; r < h; r++)
for (int q = 0; q < w; q++) {
int dx = 0, dy = 0, corner = 0;
if (q < rad && r < rad) { dx = rad - 1 - q; dy = rad - 1 - r; corner = 1; }
else if (q >= w - rad && r < rad) { dx = q - (w - rad); dy = rad - 1 - r; corner = 1; }
else if (q < rad && r >= h - rad) { dx = rad - 1 - q; dy = r - (h - rad); corner = 1; }
else if (q >= w - rad && r >= h - rad){ dx = q - (w - rad); dy = r - (h - rad); corner = 1; }
if (corner && dx * dx + dy * dy > rad * rad) continue;
pt_px(c, x + q, y + r, col);
}
}
/* Bresenham 直线(带厚度) */
static inline void pt_line(PT_Canvas *c, int x0, int y0, int x1, int y1,
int w, u32 col) {
int dx = x1 > x0 ? x1 - x0 : x0 - x1;
int dy = y1 > y0 ? y1 - y0 : y0 - y1;
int sx = x0 < x1 ? 1 : -1, sy = y0 < y1 ? 1 : -1;
int err = dx - dy, half = w / 2;
for (;;) {
pt_fill(c, x0 - half, y0 - half, w, w, col);
if (x0 == x1 && y0 == y1) break;
int e2 = 2 * err;
if (e2 > -dy) { err -= dy; x0 += sx; }
if (e2 < dx) { err += dx; y0 += sy; }
}
}
/* 圆盘 / 圆环 */
static inline void pt_disc(PT_Canvas *c, int cx, int cy, int r, u32 col) {
for (int dy = -r; dy <= r; dy++)
for (int dx = -r; dx <= r; dx++)
if (dx * dx + dy * dy <= r * r)
pt_px(c, cx + dx, cy + dy, col);
}
static inline void pt_ring(PT_Canvas *c, int cx, int cy, int r, int s, u32 col) {
for (int dy = -r; dy <= r; dy++)
for (int dx = -r; dx <= r; dx++) {
int d2 = dx * dx + dy * dy;
if (d2 <= r * r && d2 > (r - s) * (r - s))
pt_px(c, cx + dx, cy + dy, col);
}
}
/* ---- 文本(11x18 位图,透明底) ---- */
#define PT_FONT_W 11
#define PT_FONT_H 18
#define PT_STEP 10 /* 字距(与 DU_ASCII_STEP 一致) */
static inline int pt_strw(const char *s) {
int n = 0;
while (s[n]) n++;
return n * PT_STEP;
}
static inline void pt_char(PT_Canvas *c, char ch, int x, int y, u32 fg) {
u32 idx = (u32)(ch - ' ');
if (idx > 94) idx = 0;
const u8 *glyph = g_ascii[idx];
for (int r = 0; r < PT_FONT_H; r++)
for (int q = 0; q < PT_FONT_W; q++) {
u8 a = glyph[r * PT_FONT_W + q];
if (a) pt_px(c, x + q, y + r, fg);
}
}
static inline void pt_text(PT_Canvas *c, const char *s, int x, int y, u32 fg) {
int cx = x;
while (*s) { pt_char(c, *s, cx, y, fg); cx += PT_STEP; s++; }
}
static inline void pt_text_center(PT_Canvas *c, const char *s, int cx, int y, u32 fg) {
pt_text(c, s, cx - pt_strw(s) / 2, y, fg);
}
/* 十进制格式化(无 CRT) */
static inline int pt_dec(u32 v, char *out) {
char tmp[10];
int n = 0;
if (v == 0) { out[0] = '0'; out[1] = 0; return 1; }
while (v > 0) { tmp[n++] = (char)('0' + v % 10); v /= 10; }
for (int i = 0; i < n; i++) out[i] = tmp[n - 1 - i];
out[n] = 0;
return n;
}
static inline int pt_hex32(u32 v, char *out) {
static const char hd[] = "0123456789ABCDEF";
out[0] = '0'; out[1] = 'x';
for (int i = 0; i < 8; i++)
out[2 + i] = hd[(v >> (28 - i * 4)) & 0xF];
out[10] = 0;
return 10;
}
/* ---- CMOS RTC(Ring0 端口直读,BCD) ---- */
static inline u8 pt_rtc_reg(int reg) {
pt_outb(0x70, (u8)reg);
return pt_inb(0x71);
}
static inline int pt_rtc_bcd(u8 v) { return (v >> 4) * 10 + (v & 0xF); }
struct PT_Time {
int year, month, day, hour, min, sec;
};
static inline PT_Time pt_rtc_now(void) {
PT_Time t;
t.year = pt_rtc_bcd(pt_rtc_reg(0x09)) + (pt_rtc_bcd(pt_rtc_reg(0x32)) * 100);
t.month = pt_rtc_bcd(pt_rtc_reg(0x08));
t.day = pt_rtc_bcd(pt_rtc_reg(0x07));
t.hour = pt_rtc_bcd(pt_rtc_reg(0x04));
t.min = pt_rtc_bcd(pt_rtc_reg(0x02));
t.sec = pt_rtc_bcd(pt_rtc_reg(0x00));
if (t.year < 2000) t.year += 2000; /* 无世纪寄存器的 RTC */
return t;
}
static inline void pt_fmt_time(PT_Time t, char *out) {
out[0] = (char)('0' + t.hour / 10); out[1] = (char)('0' + t.hour % 10);
out[2] = ':';
out[3] = (char)('0' + t.min / 10); out[4] = (char)('0' + t.min % 10);
out[5] = ':';
out[6] = (char)('0' + t.sec / 10); out[7] = (char)('0' + t.sec % 10);
out[8] = 0;
}
static inline void pt_fmt_date(PT_Time t, char *out) {
out[0] = (char)('0' + t.year / 1000 % 10);
out[1] = (char)('0' + t.year / 100 % 10);
out[2] = (char)('0' + t.year / 10 % 10);
out[3] = (char)('0' + t.year % 10);
out[4] = '-';
out[5] = (char)('0' + t.month / 10); out[6] = (char)('0' + t.month % 10);
out[7] = '-';
out[8] = (char)('0' + t.day / 10); out[9] = (char)('0' + t.day % 10);
out[10] = 0;
}
/* ---- CPUID ---- */
static inline void pt_cpuid(u32 leaf, u32 sub,
u32 *a, u32 *b, u32 *c, u32 *d) {
__asm__ volatile("cpuid"
: "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d)
: "a"(leaf), "c"(sub));
}
/* ============================================================
* 事件循环运行时
* ============================================================ */
struct PT_Desc {
int w, h; /* 期望窗口尺寸(自动钳位到 surface) */
const wchar_t *title;
void (*frame)(PT_Canvas *cv); /* 每帧绘制(DIB 直写) */
void (*key)(unsigned vk, unsigned ch); /* ch!=0 → 可打印字符 */
void (*mouse)(int x, int y, int buttons, int edge);
/* edge: bit0=L down bit1=L up bit2=R down bit3=R up */
};
static PT_Desc pt_g_desc;
static PT_Canvas pt_g_cv;
static int pt_g_buttons;
static int pt_g_last_x, pt_g_last_y;
static LRESULT CALLBACK pt_wndproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
switch (msg) {
case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP: {
int x = (int)(short)LOWORD(lp), y = (int)(short)HIWORD(lp);
int btn = 0, edge = 0;
if (msg == WM_MOUSEMOVE) btn = (wp & 1) ? 1 : 0;
else if (msg == WM_LBUTTONDOWN) { btn = 1; edge = 1; }
else if (msg == WM_LBUTTONUP) { btn = 0; edge = 2; }
else if (msg == WM_RBUTTONDOWN) { btn = 2; edge = 4; }
else { btn = 0; edge = 8; }
pt_g_buttons = btn;
if (pt_g_desc.mouse) pt_g_desc.mouse(x, y, btn, edge);
pt_g_last_x = x; pt_g_last_y = y;
return 0;
}
case WM_KEYDOWN:
if (pt_g_desc.key) pt_g_desc.key((unsigned)wp, 0);
return 0;
case WM_CHAR:
if (pt_g_desc.key) pt_g_desc.key(0, (unsigned)wp);
return 0;
case WM_CLOSE:
DestroyWindow(hwnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProcW(hwnd, msg, wp, lp);
}
/* 渲染循环:PeekMessage 泵(空转时 shim 让出给 desktop 宿主帧)+ 每帧绘制 */
int pt_run(const PT_Desc *desc) {
pt_g_desc = *desc;
int sw = GetSystemMetrics(0); /* 窗口模式 = 宿主 surface 尺寸 */
int sh = GetSystemMetrics(1);
if (sw > 0 && desc->w > sw) pt_g_desc.w = sw;
if (sh > 0 && desc->h > sh) pt_g_desc.h = sh;
WNDCLASSEXW wc;
for (unsigned i = 0; i < sizeof(wc); i++) ((u8 *)&wc)[i] = 0;
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = pt_wndproc;
wc.hInstance = 0;
wc.lpszClassName = L"DESHABPT";
RegisterClassExW(&wc);
HWND hwnd = CreateWindowExW(0, L"DESHABPT", pt_g_desc.title, 0,
CW_USEDEFAULT, CW_USEDEFAULT,
pt_g_desc.w, pt_g_desc.h,
0, 0, 0, 0);
if (!hwnd) return 1;
ShowWindow(hwnd, SW_SHOW);
RECT rc;
rc.right = 0; rc.bottom = 0;
GetClientRect(hwnd, &rc);
pt_g_cv.w = rc.right ? rc.right : pt_g_desc.w;
pt_g_cv.h = rc.bottom ? rc.bottom : pt_g_desc.h;
/* DIB backbuffer(top-down 32bpp) */
BITMAPINFO bmi;
for (unsigned i = 0; i < sizeof(bmi); i++) ((u8 *)&bmi)[i] = 0;
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = pt_g_cv.w;
bmi.bmiHeader.biHeight = -pt_g_cv.h; /* top-down */
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
HDC wnd_dc = GetDC(hwnd);
HDC mem_dc = CreateCompatibleDC(wnd_dc);
void *bits = 0;
HBITMAP dib = CreateDIBSection(wnd_dc, &bmi, DIB_RGB_COLORS, &bits, 0, 0);
if (!dib || !bits) return 2;
SelectObject(mem_dc, dib);
pt_g_cv.bits = (u32 *)bits;
MSG msg;
for (;;) {
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
ExitProcess((unsigned)msg.wParam);
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
if (pt_g_desc.frame) pt_g_desc.frame(&pt_g_cv);
BitBlt(wnd_dc, 0, 0, pt_g_cv.w, pt_g_cv.h, mem_dc, 0, 0, SRCCOPY);
}
/* not reached */
}
#endif /* DESHAB_PE_TOOL_H */
+121
View File
@@ -0,0 +1,121 @@
/* portio.cpp — Deshab 端口读写工具(控制台 PE64,diskpart 风格硬件调试)
*
* 用法(在 CMD 里运行,输出走串口):
* portio <port> 读一字节(十六进制端口)
* portio <port> <value> 写一字节
* portio 用法帮助
*
* 例:
* portio 70 → 读 CMOS 地址口
* portio 70 0 → CMOS 寄存器 0(秒)
* portio 71 → 读出秒(BCD)
*
* Ring0 原生执行,IOPL 无限制。危险提示:写错端口可能挂机。
*/
#include <windows.h>
typedef unsigned int u32;
typedef unsigned char u8;
typedef unsigned short u16;
static inline u8 inpb(u16 port) {
u8 v;
__asm__ volatile("inb %1,%0" : "=a"(v) : "Nd"(port));
return v;
}
static inline void outpb(u16 port, u8 v) {
__asm__ volatile("outb %0,%1" :: "a"(v), "Nd"(port));
}
static void ps(const char *s) { while (*s) putchar(*s++); }
static void pch(char c) { putchar(c); }
static void ph(u32 v) {
static const char hd[] = "0123456789ABCDEF";
ps("0x");
for (int i = 3; i >= 0; i--) pch(hd[(v >> (i * 4)) & 0xF]);
}
/* 解析十进制/0x 前缀十六进制;成功返回 0 */
static int parse_num(const char *s, u32 *out) {
u32 v = 0;
if (!s || !s[0]) return -1;
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
s += 2;
if (!s[0]) return -1;
for (;;) {
char c = *s++;
if (!c) break;
int d;
if (c >= '0' && c <= '9') d = c - '0';
else if (c >= 'a' && c <= 'f') d = c - 'a' + 10;
else if (c >= 'A' && c <= 'F') d = c - 'A' + 10;
else return -1;
v = v * 16 + (u32)d;
}
} else {
for (;;) {
char c = *s++;
if (!c) break;
if (c < '0' || c > '9') return -1;
v = v * 10 + (u32)(c - '0');
}
}
*out = v;
return 0;
}
/* 从 cmdline 提取第 n 个空格分隔 token(0 = 程序名) */
static int token(const char *cmd, int n, char *out, int cap) {
int idx = 0, ti = 0;
const char *p = cmd;
while (*p) {
while (*p == ' ') p++;
if (!*p) break;
ti = 0;
while (*p && *p != ' ') {
if (idx == n && ti < cap - 1) out[ti++] = *p;
p++;
}
if (idx == n) {
out[ti] = 0;
return ti > 0 ? 0 : -1;
}
idx++;
}
return -1;
}
int main(void) {
const char *cmd = GetCommandLineA();
char t1[32], t2[32];
u32 port, val;
if (token(cmd, 1, t1, sizeof(t1)) != 0) {
ps("Deshab portio - port read/write tool (serial console)\r\n");
ps("usage: portio <port> [value] (hex with 0x, or decimal)\r\n");
ps(" portio 70 read CMOS address port\r\n");
ps(" portio 70 0 select CMOS reg 0 (seconds)\r\n");
ps(" portio 71 read seconds (BCD)\r\n");
ps("WARNING: wrong port writes can hang the machine.\r\n");
ExitProcess(0);
}
if (parse_num(t1, &port) != 0 || port > 0xFFFF) {
ps("portio: bad port\r\n");
ExitProcess(1);
}
if (token(cmd, 2, t2, sizeof(t2)) == 0) {
/* 写 */
if (parse_num(t2, &val) != 0 || val > 0xFF) {
ps("portio: bad value\r\n");
ExitProcess(1);
}
outpb((u16)port, (u8)val);
ps("portio: wrote "); ph(val); ps(" -> port "); ph(port); ps("\r\n");
} else {
u8 v = inpb((u16)port);
ps("portio: port "); ph(port); ps(" = "); ph(v); ps("\r\n");
}
ExitProcess(0);
return 0;
}
+128
View File
@@ -0,0 +1,128 @@
/* sysinfo.cpp — Deshab 系统信息(GUI PE64 工具)
*
* 显示:CPUID 厂商/型号串/核心数、TSC 频率、RTC 实时时钟、
* 开机时长(TSC)、宿主 surface 分辨率、PE 兼容层标识。
* Esc 关闭(shim 合成 WM_CLOSE)。
*/
#include "pe_tool.h"
static char g_vendor[16];
static char g_brand[52];
static u32 g_cores;
static int g_hv;
static u64 g_tsc_hz;
static void probe(void) {
/* vendor */
u32 a, b, c, d;
pt_cpuid(0, 0, &a, &b, &c, &d);
((u32 *)g_vendor)[0] = b;
((u32 *)g_vendor)[1] = d;
((u32 *)g_vendor)[2] = c;
g_vendor[12] = 0;
/* brand string */
if (a >= 0x80000004u) {
for (u32 leaf = 0x80000002u; leaf <= 0x80000004u; leaf++) {
pt_cpuid(leaf, 0, &a, &b, &c, &d);
int off = (int)(leaf - 0x80000002u) * 16;
((u32 *)g_brand)[off / 4 + 0] = a;
((u32 *)g_brand)[off / 4 + 1] = b;
((u32 *)g_brand)[off / 4 + 2] = c;
((u32 *)g_brand)[off / 4 + 3] = d;
}
g_brand[48] = 0;
} else {
g_brand[0] = 0;
}
pt_cpuid(1, 0, &a, &b, &c, &d);
g_cores = (b >> 16) & 0xFF;
g_hv = (int)((c >> 31) & 1);
LARGE_INTEGER f;
f.QuadPart = 0;
QueryPerformanceFrequency(&f);
g_tsc_hz = (u64)f.QuadPart;
}
/* 画一行 label: value,返回下一行 y */
static int row(PT_Canvas *cv, int y, const char *label, const char *value) {
pt_text(cv, label, 28, y, PT_TEXT2);
pt_text(cv, value, 170, y, PT_TEXT);
return y + 30;
}
static void frame(PT_Canvas *cv) {
pt_fill(cv, 0, 0, cv->w, cv->h, PT_BG);
/* 顶部标题卡 */
pt_round_fill(cv, 16, 16, cv->w - 32, 64, PT_CARD, 8);
pt_text(cv, "Deshab SysInfo", 32, 22, PT_TEXT);
pt_text(cv, "PE compat layer / native Ring0", 32, 44, PT_TEXT_DIM);
/* 信息卡 */
int ch = 0;
int rows = 8;
ch = 16 + rows * 30 + 24;
pt_round_fill(cv, 16, 92, cv->w - 32, ch, PT_CARD, 8);
int y = 108;
y = row(cv, y, "CPU vendor", g_vendor);
y = row(cv, y, "CPU brand", g_brand[0] ? g_brand : "(not supported)");
{
char b[16];
pt_dec(g_cores, b);
row(cv, y, "CPU cores (max APIC)", b);
y += 30;
}
y = row(cv, y, "Hypervisor", g_hv ? "yes" : "no");
{
char b[24];
u32 mhz = g_tsc_hz ? (u32)(g_tsc_hz / 1000000u) : 0;
pt_dec(mhz, b);
int n = 0;
while (b[n]) n++;
b[n] = ' '; b[n+1] = 'M'; b[n+2] = 'H'; b[n+3] = 'z'; b[n+4] = 0;
y = row(cv, y, "TSC frequency", b);
}
{
PT_Time t = pt_rtc_now();
char b[16];
pt_fmt_date(t, b);
int n = 0;
while (b[n]) n++;
b[n] = ' ';
pt_fmt_time(t, b + n + 1);
y = row(cv, y, "RTC now", b);
}
{
char b[16];
pt_dec(GetTickCount() / 1000, b);
int n = 0;
while (b[n]) n++;
b[n] = ' '; b[n+1] = 's'; b[n+2] = 0;
y = row(cv, y, "Uptime (boot)", b);
}
{
char b[16];
int n = pt_dec((u32)cv->w, b);
b[n] = 'x';
pt_dec((u32)cv->h, b + n + 1);
y = row(cv, y, "Surface", b);
}
/* 底部提示 */
pt_text(cv, "Esc = close", 16, cv->h - 26, PT_TEXT_DIM);
}
int main(void) {
probe();
PT_Desc d;
d.w = 560; d.h = 460;
d.title = L"SysInfo";
d.frame = frame;
d.key = 0;
d.mouse = 0;
return pt_run(&d);
}