在终端运行x86 DOS,为mipsel编译tiny386
现在为ARM架构构建的x86虚拟机较多但为一些嵌入式轻量平台如mipsel构建的较少为节约mipsel的运行资源本次编译基于Tiny386进行修改加入了终端显示80*25的VGA文本和从终端读取输入以实现在终端运行DOS不使用SDL等图形库。一拉取修改源码1拉取源码git clone https://gitcode.com/gh_mirrors/ti/tiny386.git删除目录中的kvm.c和kvm.hmipsel不支持2修改main.c将main.c修改为以下内容#include stdio.h #include stdlib.h #include string.h #include errno.h #include unistd.h #include stdint.h #include stdbool.h #include time.h #include sys/socket.h #include netinet/in.h #include fcntl.h #include pc.h #include vga.h #include i8042.h typedef struct PS2KbdState PS2KbdState; void ps2_put_keycode(PS2KbdState *s, int is_down, int keycode); uint32_t get_uticks() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, ts); return ((uint32_t) ts.tv_sec * 1000000 (uint32_t) ts.tv_nsec / 1000); } #ifndef _WIN32 #include sys/mman.h void *bigmalloc(size_t size) { void *p mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p MAP_FAILED) { fprintf(stderr, bigmalloc mmap fail size%zu: %s\n, size, strerror(errno)); abort(); } return p; } #else void *bigmalloc(size_t size) { void *p malloc(size); if (!p) { fprintf(stderr, bigmalloc malloc fail size%zu\n, size); abort(); } return p; } #endif int load_rom(void *phys_mem, const char *file, uword addr, int backward) { FILE *fp fopen(file, rb); if (fp NULL) { fprintf(stderr, load_rom open fail %s: %s\n, file, strerror(errno)); abort(); } fseek(fp, 0, SEEK_END); long len ftell(fp); if (len 0) { fprintf(stderr, load_rom empty file %s\n, file); fclose(fp); abort(); } fprintf(stderr, load_rom: %s, len %ld\n, file, len); rewind(fp); if (backward) fread(phys_mem addr - len, 1, len, fp); else fread(phys_mem addr, 1, len, fp); fclose(fp); return (int)len; } // VGA文本渲染全局常量 #define VGA_COLS 80 #define VGA_ROWS 25 #define TERM_BUF_SZ (VGA_COLS * (VGA_ROWS 2)) #define MIN_REFRESH_US 100000 #define VGA_TEXT_OFFSET 0x18000 // 0xB8000 - 0xA0000 标准文本显存偏移 static char vga_term_buf[TERM_BUF_SZ]; static char vga_term_last[TERM_BUF_SZ]; static uint32_t last_refresh_tick 0; static uint16_t vga_text_read_char(VGAState *vga, int row, int col) { uint32_t offset VGA_TEXT_OFFSET (row * VGA_COLS col) * 2; uint8_t ch vga_mem_read(vga, offset); uint8_t attr vga_mem_read(vga, offset 1); return ((uint16_t)attr 8) | ch; } // 终端刷新回调输出VGA画面到stdout static void redraw_terminal(void *opaque, int x, int y, int w, int h) { PC *pc (PC*)opaque; uint32_t now get_uticks(); // 刷新限流降低串口负载 if ((now - last_refresh_tick) MIN_REFRESH_US) return; memset(vga_term_buf, 0, TERM_BUF_SZ); int buf_off 0; // 遍历标准80x25文本显存 for (int r 0; r VGA_ROWS; r) { for (int c 0; c VGA_COLS; c) { uint16_t charattr vga_text_read_char(pc-vga, r, c); uint8_t ch charattr 0xFF; // 只打印可打印ASCII其余替换空格 if (ch 0x20 ch 0x7F) vga_term_buf[buf_off] ch; else vga_term_buf[buf_off] ; if (buf_off TERM_BUF_SZ - 2) goto buf_end; } vga_term_buf[buf_off] \n; if (buf_off TERM_BUF_SZ - 2) goto buf_end; } buf_end: vga_term_buf[buf_off] \0; // 裁剪尾部多余空行 while (buf_off 0 (vga_term_buf[buf_off-1] \n || vga_term_buf[buf_off-1] )) buf_off--; vga_term_buf[buf_off] \0; // 仅画面变化时输出避免重复刷屏 if (strcmp(vga_term_buf, vga_term_last) ! 0) { fputs(\033[H\033[2J, stdout); fputs(vga_term_buf, stdout); fflush(stdout); strncpy(vga_term_last, vga_term_buf, TERM_BUF_SZ - 1); vga_term_last[TERM_BUF_SZ - 1] \0; last_refresh_tick now; } } // 本地终端stdin键盘输入 static uint8_t ansi_seq[8]; static int seq_len 0; static bool shift_active false; // Tab切换Shift锁定 typedef struct PS2KbdState PS2KbdState; void ps2_put_keycode(PS2KbdState *s, int is_down, int keycode); static void send_key(PS2KbdState *kbd, int sdl_key); static void parse_ansi(PS2KbdState *kbd); static int char_to_sdl(char c); static void term_poll(PC *pc); static int stdin_nonblock_setup(void); static int stdin_nonblock_setup(void) { int flags fcntl(STDIN_FILENO, F_GETFL); if(flags -1) return -1; fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); return 0; } static void send_key(PS2KbdState *kbd, int sdl_key) { ps2_put_keycode(kbd, 1, sdl_key); ps2_put_keycode(kbd, 0, sdl_key); } static void parse_ansi(PS2KbdState *kbd) { if (seq_len 3) { seq_len 0; memset(ansi_seq, 0, sizeof(ansi_seq)); return; } uint8_t cmd ansi_seq[2]; switch(cmd) { case A: send_key(kbd, 0x48); break; /* UP */ case B: send_key(kbd, 0x50); break; /* DOWN */ case C: send_key(kbd, 0x4D); break; /* RIGHT */ case D: send_key(kbd, 0x4B); break; /* LEFT */ } seq_len 0; memset(ansi_seq, 0, sizeof(ansi_seq)); } static int char_to_sdl(char c) { if (!shift_active) { switch(c) { case 0: return 11; case 1: return 2; case 2: return 3; case 3: return 4; case 4: return 5; case 5: return 6; case 6: return 7; case 7: return 8; case 8: return 9; case 9: return 10; case a: return 0x1E; case b: return 0x30; case c: return 0x2E; case d: return 0x20; case e: return 0x12; case f: return 0x21; case g: return 0x22; case h: return 0x23; case i: return 0x17; case j: return 0x24; case k: return 0x25; case l: return 0x26; case m: return 0x32; case n: return 0x31; case o: return 0x18; case p: return 0x19; case q: return 0x10; case r: return 0x13; case s: return 0x1F; case t: return 0x14; case u: return 0x16; case v: return 0x2F; case w: return 0x11; case x: return 0x2D; case y: return 0x15; case z: return 0x2C; case : return 0x39; case \r: return 0x1C; case \n: return 0x1C; case \b: return 0x0E; case .: return 0x34; case /: return 0x35; case \\:return 0x2B; case -: return 0x0C; case : return 0x0D; case [: return 0x1A; case ]: return 0x1B; case ;: return 0x27; case \:return 0x28; case ,: return 0x33; default: return 0; } } else { // Shift开启大写字母 上档符号 switch(c) { case 0: return 11; case 1: return 2; case 2: return 3; case 3: return 4; case 4: return 5; case 5: return 6; case 6: return 7; case 7: return 8; case 8: return 9; case 9: return 10; case a: return 0x1E; case b: return 0x30; case c: return 0x2E; case d: return 0x20; case e: return 0x12; case f: return 0x21; case g: return 0x22; case h: return 0x23; case i: return 0x17; case j: return 0x24; case k: return 0x25; case l: return 0x26; case m: return 0x32; case n: return 0x31; case o: return 0x18; case p: return 0x19; case q: return 0x10; case r: return 0x13; case s: return 0x1F; case t: return 0x14; case u: return 0x16; case v: return 0x2F; case w: return 0x11; case x: return 0x2D; case y: return 0x15; case z: return 0x2C; case \r: return 0x1C; case \n: return 0x1C; case \b: return 0x0E; case -: return 0x0C; case : return 0x0D; case [: return 0x1A; case ]: return 0x1B; case ;: return 0x27; case \:return 0x28; case ,: return 0x33; case .: return 0x34; case /: return 0x35; default: return 0; } } } static void term_poll(PC *pc) { PS2KbdState *kbd pc-kbd; uint8_t ch; ssize_t ret; ret read(STDIN_FILENO, ch, 1); if(ret 0) return; if (ch 0x1B) { ansi_seq[seq_len] ch; return; } if (seq_len 0) { ansi_seq[seq_len] ch; if (seq_len 3) { parse_ansi(kbd); } return; } // Tab 切换 Shift锁定开关 if (ch \t) { shift_active !shift_active; return; } // 空格独立注入修复 if (ch ) { if (shift_active) ps2_put_keycode(kbd,1,0x2A); ps2_put_keycode(kbd,1,0x39); ps2_put_keycode(kbd,0,0x39); if (shift_active) ps2_put_keycode(kbd,0,0x2A); return; } int sdl_sc char_to_sdl(ch); if (sdl_sc ! 0) { if (shift_active) ps2_put_keycode(kbd, 1, 0x2A); send_key(kbd, sdl_sc); if (shift_active) ps2_put_keycode(kbd, 0, 0x2A); } } // 终端键盘模块结束 int main(int argc, char *argv[]) { PCConfig conf; memset(conf, 0, sizeof(conf)); conf.mem_size 4 * 1024 * 1024; conf.vga_mem_size 256 * 1024; conf.width 720; conf.height 480; conf.cpu_gen 4; conf.fpu 0; conf.enable_serial1; const char *ini_path NULL; bool enable_kvm false; // 命令行参数解析MIPS屏蔽KVM if (argc 2) { ini_path argv[1]; } else if (argc 3) { if (strcmp(argv[1], -kvm) 0) { #if defined(__mips__) fprintf(stderr, WARN: MT7621 MIPS 不支持KVM忽略参数\n); #else enable_kvm true; #endif ini_path argv[2]; } } else { fprintf(stderr, Usage: %s config.ini\n, argv[0]); #if !defined(__mips__) fprintf(stderr, x86专用: %s -kvm config.ini\n, argv[0]); #endif return 1; } int parse_err ini_parse(ini_path, parse_conf_ini, conf); if (parse_err) { fprintf(stderr, INI解析错误 code%d\n, parse_err); return parse_err; } #if !defined(__mips__) if (enable_kvm) conf.cpu_gen -1; #endif // 不分配图形帧缓冲 void *fb NULL; PC *pc pc_new(redraw_terminal, NULL, fb, conf); load_bios_and_reset(pc); pc-boot_start_time get_uticks(); // 初始化stdin非阻塞键盘 stdin_nonblock_setup(); fprintf(stdout, tiny386 headless | VGA stdout | stdin terminal keyboard\n); for (; pc-shutdown_state ! 8;) { term_poll(pc); pc_step(pc); pc_vga_step(pc); } printf(\n虚拟机退出\n); return 0; }二编译因为我的目标平台为openwrt我本次使用openwrt的工具链编译make clean mipsel-openwrt-linux-musl-gcc -O3 *.c -o tiny386_net -I. -lm产物为tiny386_net将其上传至运行设备三其他文件准备在tiny386_net的同一目录新建test.ini内容如下[pc] bios bios.bin vga_bios vgabios.bin enable_serial1 mem_size 8M vga_mem_size 256K fda dos.img fill_cmos 1 vga_force_8dm 0 [display] width 1024 height 768 [cpu] gen 4 fpu 0将本文中的资源下载86将里面的vgabios.binbios.bindos.img放入目录四运行./tiny386_net test.ini如果没有问题会进入DOS界面单击Tab 键切换 Shift 锁定模式通过网盘分享的文件tiny386_net.zip链接: https://pan.baidu.com/s/19Fe1D2SLjp0xbEmXviBOMw?pwd1234 提取码: 1234

相关新闻

可解释智能体系统:基于摘要记忆的对话反诈技术解析

可解释智能体系统:基于摘要记忆的对话反诈技术解析

1. 项目缘起:为什么我们需要一个“会解释”的对话反诈系统? 最近几年,无论是工作还是生活,我们与AI对话的频次越来越高。从客服机器人到智能助手,再到各种社交应用里的“虚拟伴侣”,对话式AI已经无处不在。…

2026/8/18 19:56:47 阅读更多 →
HTTP QUERY方法详解:复杂查询的标准化解决方案与Spring Boot实践

HTTP QUERY方法详解:复杂查询的标准化解决方案与Spring Boot实践

在 HTTP 协议的发展历程中,GET、POST、PUT、DELETE 等方法是开发者最熟悉的工具。然而,随着应用场景的复杂化,特别是对复杂查询和搜索需求的增长,传统的 GET 方法在语义和功能上开始显得力不从心。GET 方法虽然用于获取资源&#…

2026/8/18 19:55:47 阅读更多 →
DeepSeek Harness 小白入门 22:strict JSON Schema:结构更稳,但为什么仍要二次校验

DeepSeek Harness 小白入门 22:strict JSON Schema:结构更稳,但为什么仍要二次校验

DeepSeek Harness 小白入门 22:strict JSON Schema:结构更稳,但为什么仍要二次校验 [!NOTE] 这是 第二阶段 协议护栏 的第 22 课。本文面向第一次接触 Agent Harness 的读者,目标是:正确使用 strict 工具 Schema 并保留应用侧验证。真实练习场景是:让工具参数严格满足城…

2026/8/18 19:55:47 阅读更多 →

最新新闻

QUICK:GPU 加速的 ab initio / DFT 开源量子化学包—原理、安装实测与横向对比

QUICK:GPU 加速的 ab initio / DFT 开源量子化学包—原理、安装实测与横向对比

QUICK 是 UCSD Gtz Lab 与 Michigan State Merz Lab 联合开发的开源量子化学包,主打 GPU-native HF / DFT 计算、MPI 多卡扩展、内置 QM/MM 接口(与 AmberTools 26 直接集成)。专注于 HF/DFT 计算、几何优化、RESP 电荷和 QM/MM 模拟。最新版本 QUICK-26.03(2026-07-25)已…

2026/8/18 20:39:10 阅读更多 →
九种天气下的蓝调通勤:亚洲成年女性高清提示词实验

九种天气下的蓝调通勤:亚洲成年女性高清提示词实验

封面只负责建立系列节奏;正文保留九张独立高清竖图。 摘要| 同样是蓝色,春雨、干雷雨、海雾、轻雪、太阳雨、季风、秋风、霜冻和雨后蓝调会给面料完全不同的亮度与情绪。本组用九位约 22 岁亚洲成年女性、九种面孔与焦段,完成 5 套…

2026/8/18 20:39:10 阅读更多 →
AI 查库为什么要先做权限交集,再让模型看 Schema?

AI 查库为什么要先做权限交集,再让模型看 Schema?

先确定谁能看什么,再让模型生成 SQL;顺序本身就是安全边界。 摘要| 把数据库结构整包交给模型,再对生成 SQL 做一次关键词过滤,看起来省事,实际上把越权风险提前送进了提示词。本文结合 Microi吾码AI 当前 …

2026/8/18 20:39:10 阅读更多 →
干货:18 张思维导图,后端技术学习路线长这样!

干货:18 张思维导图,后端技术学习路线长这样!

1946年, 世界上第一台名叫「ENIAC」的通用计算机被发明出来, 它正如其名字那般仅仅是用来计算的。后来, 计算机数量变得越来越多起来, 当没有网络的时候, 每一台计算机都将会变成一个孤岛, 如此也就不会有如今互联网的那种繁荣景象了。「计算机网络」这门课程的学习路线是极为清…

2026/8/18 20:39:10 阅读更多 →
利用多台老旧笔记本搭建分布式集群,低成本本地部署800亿参数大模型

利用多台老旧笔记本搭建分布式集群,低成本本地部署800亿参数大模型

这次我们来看一个非常硬核的本地AI部署方案:用多台老旧笔记本搭建一个分布式计算集群,来运行参数量高达800亿(80B)的大语言模型。这个项目的核心思路不是追求单卡的极致性能,而是通过资源整合,让那些被淘汰…

2026/8/18 20:39:10 阅读更多 →
重构复杂条件逻辑:状态模式与策略模式实战

重构复杂条件逻辑:状态模式与策略模式实战

1. 为什么我们需要重构if/switch语句在代码维护过程中,我们经常会遇到这样的场景:一个方法里嵌套着七八层if判断,或者一个switch语句横跨上百行代码。这种代码结构不仅难以阅读和维护,还会带来一系列实际问题。我最近接手的一个电…

2026/8/18 20:38:09 阅读更多 →

日新闻

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF

告别逐帧截图:用 extract-video-ppt 快速提取视频中的 PPT 并一键导出 PDF 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 如果你还停留在"看网课 不停暂停 截图 …

2026/8/18 0:00:57 阅读更多 →
思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查

思源宋体TTF一站式上手:7个字重免费商用,从下载到上线的完整走查 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 你是不是也经历过这种时刻:设计稿里…

2026/8/18 0:00:58 阅读更多 →
华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate

华硕笔记本控制权回收指南:GHelper 如何用一个 10MB 文件替代 Armoury Crate 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, …

2026/8/18 0:00:59 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/18 9:15:35 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/18 9:06:28 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/18 9:04:56 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/17 18:54:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/17 18:55:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/17 18:55:55 阅读更多 →