Files
Deshab-OS/CODE/cmd/main.c
T
2026-07-28 14:35:14 +08:00

962 lines
30 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Deshab CMD — Windows 风格命令行(PE/EXE 兼容层前端)
*
* 黑底白字 cmd.exe 风格,PS/2 键盘输入。
* 内置命令:dir/cd/type/copy/del/ren/mkdir/rmdir/echo/cls/ver/set/help/exit
* PE 执行:输入 foo.exe 或 foo → 从 FAT32 根读取 → 调用 UTSM PE 服务执行
* - PE32+ (64位):UTSM 原生 Ring0 执行
* - PE32 (32位):UTSM 内嵌 x86-32 解释器执行
* Esc 返回桌面。
*/
#include "../UTSM/include/utsm/dsk.h"
#include "../UTSM/include/utsm/pe.h"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef long long i64;
#define COM1 0x3F8
static __inline__ void outb(u16 port, u8 value) { __asm__ volatile("outb %0,%1"::"a"(value),"Nd"(port)); }
static __inline__ u8 inb(u16 port) { u8 v; __asm__ volatile("inb %1,%0":"=a"(v):"Nd"(port)); return v; }
/* ---- TSC 计时 ---- */
static u64 g_tsc_per_ms = 0;
static __inline__ u64 rdtsc_cmd(void) {
u32 lo, hi;
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
return ((u64)hi << 32) | lo;
}
static void tsc_calibrate_cmd(void) {
outb(0x43, 0x30);
outb(0x40, 0x7c);
outb(0x40, 0x2e);
u64 tsc_start = rdtsc_cmd();
u16 prev = 0; u64 loops = 0;
for (;;) {
outb(0x43, 0x00);
u16 cur = (u16)inb(0x40) | ((u16)inb(0x40) << 8);
if (cur > prev && loops > 10) break;
prev = cur; loops++;
}
u64 tsc_end = rdtsc_cmd();
g_tsc_per_ms = (tsc_end - tsc_start) / 10;
}
static void serial_wait_tx(void) {
if (g_tsc_per_ms == 0) tsc_calibrate_cmd();
if (g_tsc_per_ms == 0) {
for (u32 i = 0; i < 100000; i++) { if (inb(COM1 + 5) & 0x20) break; }
return;
}
u64 deadline = rdtsc_cmd() + g_tsc_per_ms / 10;
while (rdtsc_cmd() < deadline) {
if (inb(COM1 + 5) & 0x20) break;
__asm__ volatile("pause");
}
}
static void sputc(char c) { serial_wait_tx(); outb(COM1, (unsigned char)c); }
static void swrite(const char *s) { while (*s) { if (*s == '\n') sputc('\r'); sputc(*s++); } }
static void logl(const char *s) { swrite(s); swrite("\n"); }
/* ASCII 字体 — 必须在 deshab_ui.h 之前包含 */
#include "../firstInit/ascii_bitmaps.c"
#include "../UTSM/include/utsm/deshab_ui.h"
/* FAT32 共享读写库 */
#include "../tools/fat32_io.h"
/* ============================================================
* 颜色定义 — Windows cmd.exe 风格(黑底浅灰字)
* ============================================================ */
#define CMD_BG 0xFF000000u /* 纯黑背景 */
#define CMD_TEXT 0xFFC0C0C0u /* 浅灰文字(cmd.exe 默认) */
#define CMD_PROMPT 0xFFFFFFFFu /* 白色提示符 */
#define CMD_ERROR 0xFFFF6060u /* 浅红错误 */
#define CMD_OK 0xFF60FF60u /* 浅绿成功 */
#define CMD_INFO 0xFF60A0FFu /* 浅蓝信息 */
#define CMD_DIM 0xFF808080u /* 灰色暗淡 */
#define CMD_WARN 0xFFFFFF60u /* 黄色警告 */
/* ============================================================
* 终端缓冲区与渲染
* ============================================================ */
#define TERM_COLS 100
#define TERM_ROWS 40
#define TERM_MAX_CHARS (TERM_COLS * TERM_ROWS)
static du_context g_ctx;
static u64 fb_a, fb_w, fb_h, fb_p;
static u8 term_ch[TERM_MAX_CHARS];
static u32 term_fg[TERM_MAX_CHARS];
static int term_w = TERM_COLS;
static int term_h = TERM_ROWS;
static int cur_col = 0;
static int cur_row = 0;
static int cur_visible = 1;
static int term_start_x, term_start_y;
static const dsk_boot_context *g_boot_ctx = 0;
static u64 g_kernel_api = 0;
static const pe_service *g_pe_svc = 0;
/* dev_mode 串口镜像 */
static int g_serial_mirror = 0;
static void term_init_pos(void) {
int margin = 4;
term_start_x = margin;
term_start_y = margin;
int avail_w = (int)fb_w - margin * 2;
int avail_h = (int)fb_h - margin * 2;
term_w = avail_w / (int)DU_ASCII_STEP;
term_h = avail_h / (int)DU_ASCII_LINE_H;
if (term_w < 10) term_w = 10;
if (term_h < 5) term_h = 5;
if (term_w > TERM_COLS) term_w = TERM_COLS;
if (term_h > TERM_ROWS) term_h = TERM_ROWS;
}
static void term_clear_buf(void) {
for (int i = 0; i < TERM_MAX_CHARS; i++) {
term_ch[i] = ' ';
term_fg[i] = CMD_TEXT;
}
cur_col = 0;
cur_row = 0;
}
static void term_scroll(void) {
for (int r = 1; r < term_h; r++) {
for (int c = 0; c < term_w; c++) {
int src = r * TERM_COLS + c;
int dst = (r - 1) * TERM_COLS + c;
term_ch[dst] = term_ch[src];
term_fg[dst] = term_fg[src];
}
}
for (int c = 0; c < term_w; c++) {
term_ch[(term_h - 1) * TERM_COLS + c] = ' ';
term_fg[(term_h - 1) * TERM_COLS + c] = CMD_TEXT;
}
cur_row = term_h - 1;
cur_col = 0;
}
static void term_newline(void) {
cur_col = 0;
cur_row++;
if (cur_row >= term_h) term_scroll();
}
static void term_putc_color(char c, u32 color) {
if (g_serial_mirror) { if (c == '\n') sputc('\r'); sputc(c); }
if (c == '\n') { term_newline(); return; }
if (c == '\r') { cur_col = 0; return; }
if (c == '\t') {
int spaces = 8 - (cur_col % 8);
for (int i = 0; i < spaces; i++) term_putc_color(' ', color);
return;
}
if (c < ' ' || c > '~') c = '.';
if (cur_col >= term_w) term_newline();
int idx = cur_row * TERM_COLS + cur_col;
term_ch[idx] = (u8)c;
term_fg[idx] = color;
cur_col++;
}
static void term_putc(char c) { term_putc_color(c, CMD_TEXT); }
static void term_puts_color(const char *s, u32 color) { while (*s) term_putc_color(*s++, color); }
static void term_puts(const char *s) { term_puts_color(s, CMD_TEXT); }
/* ---- 数字转字符串 ---- */
static void term_putu(u32 v) {
char buf[12];
int i = 11;
buf[i--] = 0;
if (v == 0) { buf[i--] = '0'; }
while (v > 0 && i >= 0) { buf[i--] = (char)('0' + (v % 10)); v /= 10; }
term_puts(&buf[i + 1]);
}
static void term_putx(u32 v) {
static const char hex[] = "0123456789ABCDEF";
term_putc('0'); term_putc('x');
for (int i = 28; i >= 0; i -= 4) {
u32 nib = (v >> i) & 0xF;
if (nib != 0 || i <= 12) term_putc(hex[nib]);
}
}
/* ---- 终端全屏渲染 ---- */
static void term_redraw_all(void) {
du_fill_rect(&g_ctx, 0, 0, (i64)fb_w, (i64)fb_h, CMD_BG);
for (int r = 0; r < term_h; r++) {
i64 y = term_start_y + (i64)r * (i64)DU_ASCII_LINE_H;
for (int c = 0; c < term_w; c++) {
int idx = r * TERM_COLS + c;
i64 x = term_start_x + (i64)c * (i64)DU_ASCII_STEP;
du_draw_char(&g_ctx, (char)term_ch[idx], x, y, term_fg[idx], CMD_BG);
}
}
}
static void term_redraw_cursor(void) {
if (cur_col >= term_w) return;
i64 x = term_start_x + (i64)cur_col * (i64)DU_ASCII_STEP;
i64 y = term_start_y + (i64)cur_row * (i64)DU_ASCII_LINE_H;
du_fill_rect(&g_ctx, x, y, (i64)DU_ASCII_STEP - 1, (i64)DU_ASCII_CELL_H, CMD_PROMPT);
}
static void term_clear_cursor(void) {
if (cur_col >= term_w) return;
i64 x = term_start_x + (i64)cur_col * (i64)DU_ASCII_STEP;
i64 y = term_start_y + (i64)cur_row * (i64)DU_ASCII_LINE_H;
int idx = cur_row * TERM_COLS + cur_col;
du_fill_rect(&g_ctx, x, y, (i64)DU_ASCII_STEP - 1, (i64)DU_ASCII_CELL_H, CMD_BG);
du_draw_char(&g_ctx, (char)term_ch[idx], x, y, term_fg[idx], CMD_BG);
}
/* ============================================================
* 键盘输入(PS/2 Scan Code Set 1)
* ============================================================ */
static char scan_to_ascii(u8 sc, int shift) {
static const char normal[58] = {
0, 27, '1','2','3','4','5','6','7','8','9','0','-','=', 8, '\t',
'q','w','e','r','t','y','u','i','o','p','[',']','\n',0,
'a','s','d','f','g','h','j','k','l',';','\'', '`',0,'\\',
'z','x','c','v','b','n','m',',','.','/',0,'*',0,' '
};
static const char shifted[58] = {
0, 27, '!','@','#','$','%','^','&','*','(',')','_','+', 8, '\t',
'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',0,
'A','S','D','F','G','H','J','K','L',':','"','~',0,'|',
'Z','X','C','V','B','N','M','<','>','?',0,'*',0,' '
};
if (sc >= 58) return 0;
return shift ? shifted[sc] : normal[sc];
}
/* ============================================================
* 字符串工具
* ============================================================ */
static int str_eq(const char *a, const char *b) {
while (*a && *b) { if (*a != *b) return 0; a++; b++; }
return *a == *b;
}
static int str_len(const char *s) {
int n = 0;
while (s[n]) n++;
return n;
}
static void str_copy(char *dst, const char *src, int max) {
int i = 0;
while (src[i] && i < max - 1) { dst[i] = src[i]; i++; }
dst[i] = 0;
}
static int str_ieq(const char *a, const char *b) {
while (*a && *b) {
char ca = *a, cb = *b;
if (ca >= 'a' && ca <= 'z') ca -= 32;
if (cb >= 'a' && cb <= 'z') cb -= 32;
if (ca != cb) return 0;
a++; b++;
}
return *a == *b;
}
/* ============================================================
* 输入行编辑
* ============================================================ */
static char input_buf[256];
static int input_len = 0;
static int input_cursor = 0;
static const char *PROMPT = "C:\\> ";
static void redraw_input_line(void) {
int prompt_len = str_len(PROMPT);
i64 y = term_start_y + (i64)cur_row * (i64)DU_ASCII_LINE_H;
du_fill_rect(&g_ctx, term_start_x, y,
(i64)term_w * (i64)DU_ASCII_STEP,
(i64)DU_ASCII_CELL_H, CMD_BG);
for (int i = 0; i < prompt_len; i++) {
i64 x = term_start_x + (i64)i * (i64)DU_ASCII_STEP;
du_draw_char(&g_ctx, PROMPT[i], x, y, CMD_PROMPT, CMD_BG);
}
for (int i = 0; i < input_len; i++) {
i64 x = term_start_x + (i64)(prompt_len + i) * (i64)DU_ASCII_STEP;
du_draw_char(&g_ctx, input_buf[i], x, y, CMD_TEXT, CMD_BG);
}
cur_col = prompt_len + input_cursor;
term_redraw_cursor();
}
static void insert_char(char c) {
if (input_len >= 255) return;
for (int i = input_len; i > input_cursor; i--)
input_buf[i] = input_buf[i - 1];
input_buf[input_cursor] = c;
input_len++;
input_cursor++;
redraw_input_line();
}
static void delete_char_back(void) {
if (input_cursor == 0) return;
for (int i = input_cursor - 1; i < input_len - 1; i++)
input_buf[i] = input_buf[i + 1];
input_len--;
input_cursor--;
input_buf[input_len] = 0;
redraw_input_line();
}
static void cursor_left(void) {
if (input_cursor > 0) { input_cursor--; redraw_input_line(); }
}
static void cursor_right(void) {
if (input_cursor < input_len) { input_cursor++; redraw_input_line(); }
}
static void cursor_home(void) {
input_cursor = 0;
redraw_input_line();
}
static void cursor_end(void) {
input_cursor = input_len;
redraw_input_line();
}
static void kill_line(void) {
input_len = 0;
input_cursor = 0;
input_buf[0] = 0;
redraw_input_line();
}
/* ============================================================
* 内置命令
* ============================================================ */
static void cmd_help(void) {
term_puts_color("Deshab CMD — 命令列表:\r\n", CMD_INFO);
term_puts(" dir 列出文件\r\n");
term_puts(" cd 显示当前目录\r\n");
term_puts(" type <file> 显示文件内容\r\n");
term_puts(" copy <a> <b> 复制文件\r\n");
term_puts(" del <file> 删除文件\r\n");
term_puts(" ren <a> <b> 重命名文件\r\n");
term_puts(" echo <text> 显示文本 (echo text > file 写入)\r\n");
term_puts(" cls 清屏\r\n");
term_puts(" ver 显示版本\r\n");
term_puts(" set 显示环境变量\r\n");
term_puts(" help 显示此帮助\r\n");
term_puts(" exit 返回桌面\r\n");
term_puts_color("\nPE 程序执行:\r\n", CMD_WARN);
term_puts(" <name>.exe 运行 PE32+/PE32 程序 (如 hello.exe)\r\n");
term_puts(" <name> 自动查找 name.exe 并运行\r\n");
}
static void cmd_ver(void) {
term_puts_color("Deshab CMD [Version 0.1.0]\r\n", CMD_OK);
term_puts_color("(c) 2026 Deshab Project. PE/EXE 兼容层 by UTSM.\r\n", CMD_DIM);
}
static void cmd_cls(void) {
term_clear_buf();
term_redraw_all();
}
static void cmd_cd(void) {
term_puts("C:\\\r\n");
}
static void cmd_set(void) {
term_puts_color("环境变量:\r\n", CMD_INFO);
term_puts(" PATH=C:\\;C:\\bin\r\n");
term_puts(" PROMPT=$P$G\r\n");
term_puts(" OS=Deshab\r\n");
term_puts(" PE_COMPAT=UTSM_PE32+_PE32\r\n");
}
/* dir — 列出 FAT32 根目录文件 */
typedef struct {
int count;
u32 total_bytes;
} dir_ctx_static;
static int dir_list_cb(const char *name, u32 size, u8 attr, void *ud) {
dir_ctx_static *st = (dir_ctx_static *)ud;
if (attr & 0x10) {
term_puts_color(name, CMD_INFO);
term_puts_color(" <DIR> ", CMD_DIM);
} else {
term_puts(name);
term_puts(" ");
/* 右对齐文件大小 */
u32 sz = size;
char numbuf[12];
int ni = 11;
numbuf[ni--] = 0;
if (sz == 0) numbuf[ni--] = '0';
while (sz > 0 && ni >= 0) { numbuf[ni--] = (char)('0' + sz % 10); sz /= 10; }
while (ni >= 0) numbuf[ni--] = ' ';
term_puts(&numbuf[0]);
st->total_bytes += size;
}
term_puts("\r\n");
st->count++;
return 0;
}
static void cmd_dir(void) {
if (!f32_blk_read) {
term_puts_color("dir: 无块设备\r\n", CMD_ERROR);
return;
}
term_puts_color(" C 盘的卷是 DESHAB\r\n", CMD_DIM);
term_puts_color(" 卷序列号为 DE5A-B002\r\n", CMD_DIM);
term_puts("\r\n C:\\ 的目录\r\n\r\n");
dir_ctx_static st = {0, 0};
f32_list_root(dir_list_cb, &st);
term_puts("\r\n");
term_putu((u32)st.count);
term_puts(" 个文件 ");
term_putu(st.total_bytes);
term_puts(" 字节\r\n");
}
/* type <file> — 显示文件内容 */
static void cmd_type(const char *args) {
if (!*args) { term_puts_color("type: 缺少文件名\r\n", CMD_ERROR); return; }
if (!f32_blk_read) { term_puts_color("type: 无块设备\r\n", CMD_ERROR); return; }
char name11[11];
if (f32_name_to_83(args, name11) != 0) {
term_puts_color("type: 无效文件名\r\n", CMD_ERROR);
return;
}
u8 *data = 0; u32 size = 0;
if (f32_read_root_file(name11, &data, &size) != 0) {
term_puts_color("type: 文件不存在\r\n", CMD_ERROR);
return;
}
/* 输出文件内容(按字符) */
for (u32 i = 0; i < size; i++) {
char c = (char)data[i];
if (c == '\n') term_putc('\r');
term_putc(c);
}
if (size > 0 && data[size - 1] != '\n') term_putc('\r');
term_putc('\n');
}
/* echo <text> — 显示文本或重定向到文件 */
static void cmd_echo(const char *args) {
/* 检查重定向: echo text > file */
char text[256];
str_copy(text, args, sizeof(text));
/* 查找 > */
int redir = -1;
for (int i = 0; text[i]; i++) {
if (text[i] == '>') { redir = i; break; }
}
if (redir >= 0) {
/* 重定向到文件 */
text[redir] = 0;
/* 去尾部空格 */
int tl = str_len(text);
while (tl > 0 && text[tl - 1] == ' ') text[--tl] = 0;
/* 获取文件名 */
char *fn = text + redir + 1;
while (*fn == ' ') fn++;
if (!*fn) { term_puts_color("echo: 重定向缺少文件名\r\n", CMD_ERROR); return; }
char name11[11];
if (f32_name_to_83(fn, name11) != 0) {
term_puts_color("echo: 无效文件名\r\n", CMD_ERROR);
return;
}
if (!f32_blk_write) { term_puts_color("echo: 无块设备写能力\r\n", CMD_ERROR); return; }
/* 构造写入内容 */
char content[256];
int ci = 0;
for (int i = 0; i < tl && ci < 254; i++) content[ci++] = text[i];
content[ci++] = '\r';
content[ci++] = '\n';
if (f32_write_root_file(name11, (const u8 *)content, (u32)ci) != 0) {
term_puts_color("echo: 写入失败\r\n", CMD_ERROR);
return;
}
term_puts_color("echo: 已写入 ", CMD_OK);
term_puts(fn);
term_puts("\r\n");
} else {
/* 直接显示 */
if (*args) {
term_puts(args);
}
term_puts("\r\n");
}
}
/* copy <src> <dst> — 复制文件 */
static void cmd_copy(const char *args) {
char src[64], dst[64];
int si = 0, di = 0;
const char *p = args;
while (*p == ' ') p++;
while (*p && *p != ' ' && si < 63) src[si++] = *p++;
src[si] = 0;
while (*p == ' ') p++;
while (*p && di < 63) dst[di++] = *p++;
dst[di] = 0;
if (!src[0] || !dst[0]) {
term_puts_color("copy: 用法 copy <源文件> <目标文件>\r\n", CMD_ERROR);
return;
}
if (!f32_blk_read || !f32_blk_write) {
term_puts_color("copy: 无块设备\r\n", CMD_ERROR);
return;
}
char s83[11], d83[11];
if (f32_name_to_83(src, s83) != 0 || f32_name_to_83(dst, d83) != 0) {
term_puts_color("copy: 无效文件名\r\n", CMD_ERROR);
return;
}
u8 *data = 0; u32 size = 0;
if (f32_read_root_file(s83, &data, &size) != 0) {
term_puts_color("copy: 源文件不存在\r\n", CMD_ERROR);
return;
}
if (f32_write_root_file(d83, data, size) != 0) {
term_puts_color("copy: 写入失败\r\n", CMD_ERROR);
return;
}
term_puts_color(" 1 个文件已复制。\r\n", CMD_OK);
}
/* del <file> — 删除文件 */
static void cmd_del(const char *args) {
if (!*args) { term_puts_color("del: 缺少文件名\r\n", CMD_ERROR); return; }
if (!f32_blk_write) { term_puts_color("del: 无块设备写能力\r\n", CMD_ERROR); return; }
char name11[11];
if (f32_name_to_83(args, name11) != 0) {
term_puts_color("del: 无效文件名\r\n", CMD_ERROR);
return;
}
if (f32_delete_root_file(name11) != 0) {
term_puts_color("del: 文件不存在或删除失败\r\n", CMD_ERROR);
return;
}
term_puts_color("del: 已删除\r\n", CMD_OK);
}
/* ren <old> <new> — 重命名文件 */
static void cmd_ren(const char *args) {
char old[64], nw[64];
int oi = 0, ni = 0;
const char *p = args;
while (*p == ' ') p++;
while (*p && *p != ' ' && oi < 63) old[oi++] = *p++;
old[oi] = 0;
while (*p == ' ') p++;
while (*p && ni < 63) nw[ni++] = *p++;
nw[ni] = 0;
if (!old[0] || !nw[0]) {
term_puts_color("ren: 用法 ren <旧名> <新名>\r\n", CMD_ERROR);
return;
}
if (!f32_blk_read || !f32_blk_write) {
term_puts_color("ren: 无块设备\r\n", CMD_ERROR);
return;
}
char o83[11], n83[11];
if (f32_name_to_83(old, o83) != 0 || f32_name_to_83(nw, n83) != 0) {
term_puts_color("ren: 无效文件名\r\n", CMD_ERROR);
return;
}
u8 *data = 0; u32 size = 0;
if (f32_read_root_file(o83, &data, &size) != 0) {
term_puts_color("ren: 源文件不存在\r\n", CMD_ERROR);
return;
}
if (f32_write_root_file(n83, data, size) != 0) {
term_puts_color("ren: 写入新文件失败\r\n", CMD_ERROR);
return;
}
if (f32_delete_root_file(o83) != 0) {
term_puts_color("ren: 删除旧文件失败(警告)\r\n", CMD_WARN);
}
term_puts_color("ren: 已重命名\r\n", CMD_OK);
}
static void cmd_mkdir(void) { term_puts_color("mkdir: FAT32 根目录不支持子目录\r\n", CMD_WARN); }
static void cmd_rmdir(void) { term_puts_color("rmdir: FAT32 根目录不支持子目录\r\n", CMD_WARN); }
/* ============================================================
* PE/EXE 程序执行
* ============================================================ */
/* 检查文件名是否以 .exe/.com/.bat 结尾(不区分大小写) */
static int has_exec_ext(const char *name) {
int len = str_len(name);
if (len < 4) return 0;
const char *ext = name + len - 4;
if (ext[0] != '.') return 0;
if (str_ieq(ext, ".exe")) return 1;
if (str_ieq(ext, ".com")) return 1;
if (str_ieq(ext, ".bat")) return 2;
return 0;
}
/* 执行 PE/EXE 程序。
* prog_name = 程序名(可能带或不带 .exe 后缀)
* full_cmdline = 完整命令行(程序名 + 参数,即 GetCommandLineA 返回值)
*/
static void exec_pe(const char *prog_name, const char *full_cmdline) {
if (!g_pe_svc) {
term_puts_color("PE 兼容层不可用(UTSM PE 服务未初始化)\r\n", CMD_ERROR);
return;
}
if (!f32_blk_read) {
term_puts_color("无块设备,无法读取 PE 文件\r\n", CMD_ERROR);
return;
}
/* 构造 8.3 文件名 */
char base[64];
str_copy(base, prog_name, sizeof(base));
/* 如果没有扩展名,自动补 .exe */
int has_dot = 0;
for (int i = 0; base[i]; i++) {
if (base[i] == '.') { has_dot = 1; break; }
}
if (!has_dot) {
int bl = str_len(base);
if (bl > 59) bl = 59;
base[bl] = '.'; base[bl + 1] = 'e'; base[bl + 2] = 'x';
base[bl + 3] = 'e'; base[bl + 4] = 0;
}
char name11[11];
if (f32_name_to_83(base, name11) != 0) {
term_puts_color("无效文件名\r\n", CMD_ERROR);
return;
}
/* 从 FAT32 根目录读取 */
u8 *pe_data = 0; u32 pe_size = 0;
if (f32_read_root_file(name11, &pe_data, &pe_size) != 0) {
term_puts_color("'", CMD_ERROR);
term_puts_color(prog_name, CMD_ERROR);
term_puts_color("' 不是内部或外部命令,也不是可运行的程序。\r\n", CMD_ERROR);
return;
}
/* 验证 PE 头(MZ 签名) */
if (pe_size < 2 || pe_data[0] != 'M' || pe_data[1] != 'Z') {
term_puts_color("不是有效的 PE/EXE 文件(缺少 MZ 签名)\r\n", CMD_ERROR);
return;
}
term_puts_color("正在执行 ", CMD_INFO);
term_puts_color(prog_name, CMD_WARN);
term_puts_color(" ...\r\n", CMD_INFO);
term_redraw_all();
/* 调用 UTSM PE 服务执行 */
logl("[cmd] PE run begin");
swrite("[cmd] cmdline: "); swrite(full_cmdline); swrite("\n");
u64 exit_code = 0;
int rc = g_pe_svc->run(pe_data, (u64)pe_size, full_cmdline, &exit_code);
if (rc != 0) {
term_puts_color("PE 执行失败,错误码: ", CMD_ERROR);
term_putx((u32)rc);
term_puts("\r\n");
} else {
term_puts_color("程序退出,返回码: ", CMD_DIM);
term_putu((u32)exit_code);
term_puts("\r\n");
}
logl("[cmd] PE run end");
}
/* ============================================================
* 命令解析与分发
* ============================================================ */
static int g_should_exit = 0;
static void execute_command(const char *cmd) {
while (*cmd == ' ') cmd++;
if (*cmd == 0) return;
/* 提取命令名 */
const char *args = cmd;
while (*args && *args != ' ') args++;
int cmd_name_len = (int)(args - cmd);
char name[64];
if (cmd_name_len >= 64) cmd_name_len = 63;
for (int i = 0; i < cmd_name_len; i++) name[i] = cmd[i];
name[cmd_name_len] = 0;
while (*args == ' ') args++;
/* 内置命令(不区分大小写) */
if (str_ieq(name, "help") || str_eq(name, "?")) { cmd_help(); return; }
if (str_ieq(name, "ver")) { cmd_ver(); return; }
if (str_ieq(name, "cls") || str_ieq(name, "clear")) { cmd_cls(); return; }
if (str_ieq(name, "dir") || str_ieq(name, "ls")) { cmd_dir(); return; }
if (str_ieq(name, "cd")) { cmd_cd(); return; }
if (str_ieq(name, "type") || str_ieq(name, "cat")) { cmd_type(args); return; }
if (str_ieq(name, "copy") || str_ieq(name, "cp")) { cmd_copy(args); return; }
if (str_ieq(name, "del") || str_ieq(name, "rm")) { cmd_del(args); return; }
if (str_ieq(name, "ren") || str_ieq(name, "mv")) { cmd_ren(args); return; }
if (str_ieq(name, "mkdir") || str_ieq(name, "md")) { cmd_mkdir(); return; }
if (str_ieq(name, "rmdir") || str_ieq(name, "rd")) { cmd_rmdir(); return; }
if (str_ieq(name, "echo")) { cmd_echo(args); return; }
if (str_ieq(name, "set")) { cmd_set(); return; }
if (str_ieq(name, "exit") || str_ieq(name, "quit")) {
term_puts_color("返回桌面...\r\n", CMD_DIM);
g_should_exit = 1;
return;
}
if (str_ieq(name, "reboot")) {
term_puts_color("重启中...\r\n", CMD_WARN);
term_redraw_all();
for (u64 i = 0; i < 100000000ULL; i++) __asm__ volatile("pause");
/* 触发三重故障重启 */
__asm__ volatile("int $0x03");
return;
}
/* PE/EXE 执行:检查是否为可执行文件 */
int ext_type = has_exec_ext(name);
if (ext_type == 1) {
/* .exe/.com → PE 执行 */
exec_pe(name, cmd);
return;
}
if (ext_type == 2) {
/* .bat → 批处理(暂不支持) */
term_puts_color("批处理文件 (.bat) 暂不支持\r\n", CMD_WARN);
return;
}
/* 无扩展名 → 尝试自动补 .exe 执行 */
if (cmd_name_len > 0 && name[0] != '.') {
exec_pe(name, cmd);
return;
}
/* 未知命令 */
term_puts_color("'", CMD_ERROR);
term_puts_color(name, CMD_ERROR);
term_puts_color("' 不是内部或外部命令,也不是可运行的程序。\r\n", CMD_ERROR);
}
/* ============================================================
* 主入口
* ============================================================ */
__attribute__((visibility("default")))
void dsk_entry(const dsk_boot_context *ctx) {
__asm__ volatile("cli");
logl("[cmd] boot");
if (!ctx || ctx->magic != 0x44534B31424F4F54ULL) {
logl("[cmd] bad context");
for (;;) __asm__("hlt");
}
fb_a = ctx->framebuffer_address;
fb_w = ctx->framebuffer_width;
fb_h = ctx->framebuffer_height;
fb_p = ctx->framebuffer_pitch;
g_kernel_api = ctx->dkm_kernel_api;
g_boot_ctx = ctx;
/* 获取 block 设备 read/write */
{
u64 api = ctx->dkm_kernel_api;
u64 blk = *(u64 *)(api + 0xA8);
f32_block_read_fn bread = blk ? (f32_block_read_fn)*(u64 *)(blk + 16) : 0;
f32_block_write_fn bwrite = blk ? (f32_block_write_fn)*(u64 *)(blk + 24) : 0;
f32_init(bread, bwrite);
}
if (f32_blk_read) logl("[cmd] block_read ok");
if (f32_blk_write) logl("[cmd] block_write ok");
/* 获取 PE 服务(reserved[4]) */
{
u64 pe_addr = ctx->reserved[4];
if (pe_addr) {
const pe_service *pe = (const pe_service *)pe_addr;
if (pe->magic == PE_SERVICE_MAGIC) {
g_pe_svc = pe;
logl("[cmd] PE service ok");
} else {
logl("[cmd] PE service magic mismatch");
}
} else {
logl("[cmd] PE service not available");
}
}
/* dev_mode 串口镜像 */
if (ctx->reserved[3] == 1) {
g_serial_mirror = 1;
}
/* 初始化渲染上下文 */
du_context_init(&g_ctx, fb_a, fb_w, fb_h, fb_p);
term_init_pos();
term_clear_buf();
term_redraw_all();
/* 启动 banner */
term_puts_color("Deshab CMD [Version 0.1.0]\r\n", CMD_OK);
term_puts_color("(c) 2026 Deshab Project. PE/EXE 兼容层 by UTSM.\r\n", CMD_DIM);
term_putc('\r');
term_putc('\n');
if (g_pe_svc) {
term_puts_color("PE 兼容层已就绪 (PE32+ 原生 + PE32 解释器)\r\n", CMD_OK);
} else {
term_puts_color("警告: PE 兼容层不可用\r\n", CMD_WARN);
}
term_putc('\r');
term_putc('\n');
term_redraw_all();
/* 主循环 */
int shift = 0;
int e0 = 0;
u64 blink_start = rdtsc_cmd();
g_should_exit = 0;
for (;;) {
/* 绘制提示符 */
term_puts_color(PROMPT, CMD_PROMPT);
input_len = 0;
input_cursor = 0;
input_buf[0] = 0;
int prompt_len = str_len(PROMPT);
cur_col = prompt_len;
cur_visible = 1;
redraw_input_line();
int cmd_done = 0;
while (!cmd_done && !g_should_exit) {
/* 光标闪烁 */
if (g_tsc_per_ms) {
u64 now = rdtsc_cmd();
u64 elapsed = now - blink_start;
int want_vis = (elapsed / (g_tsc_per_ms * 530)) & 1;
if (want_vis != cur_visible) {
if (want_vis) term_redraw_cursor();
else term_clear_cursor();
cur_visible = want_vis;
}
}
u8 st = inb(0x64);
if (!(st & 1)) { __asm__("pause"); continue; }
u8 data = inb(0x60);
if (st & 0x20) continue; /* 忽略鼠标数据 */
u8 sc = data;
blink_start = rdtsc_cmd();
if (!cur_visible) { cur_visible = 1; term_redraw_cursor(); }
if (sc == 0xE0) { e0 = 1; continue; }
if (sc == 0x2A || sc == 0x36) { shift = 1; continue; }
if (sc == 0xAA || sc == 0xB6) { shift = 0; continue; }
if (sc & 0x80) {
/* 按键释放 */
e0 = 0;
continue;
}
if (e0) {
if (sc == 0x4B) cursor_left();
else if (sc == 0x4D) cursor_right();
else if (sc == 0x47) cursor_home();
else if (sc == 0x4F) cursor_end();
else if (sc == 0x53) { /* Delete */ }
e0 = 0;
continue;
}
if (sc == 0x1C) {
/* Enter — 提交命令 */
term_clear_cursor();
input_buf[input_len] = 0;
term_putc('\r');
term_putc('\n');
execute_command(input_buf);
input_len = 0;
input_cursor = 0;
input_buf[0] = 0;
cmd_done = 1;
term_redraw_all();
continue;
}
if (sc == 0x0E) { delete_char_back(); continue; }
if (sc == 0x01) {
/* Esc — 返回桌面 */
logl("[cmd] esc -> return to DSK");
g_should_exit = 1;
cmd_done = 1;
continue;
}
if (sc == 0x15 && !shift) { kill_line(); continue; }
char c = scan_to_ascii(sc, shift);
if (c && c >= 32 && c <= 126) {
insert_char(c);
}
}
if (g_should_exit) break;
}
logl("[cmd] exit");
}