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
+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);
}