You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写简易内核VGA驱动时的光标位置异常问题求助

问题分析与解决思路

1. 直接导致光标卡死的语法错误

看__CursorSet函数里的这行代码:

__OutByte(VGA_DATA_REGISTER , (uint8_t)(offset && 0xff)) ;

这里误用了逻辑与运算符&&,正确应该用按位与运算符&。逻辑与的特性是:只要offset不为0,offset && 0xff的结果就是1(布尔真),转换成uint8_t后就是0x01。这就导致:

  • 初始化__SetCursor(0)时,0 && 0xff是0,光标正常设在偏移0处;
  • 第一次调用__CursorSet(++offset)时,offset变成1,低字节被设为1;
  • 后续不管offset增加到多少,低字节始终被设为1,光标就一直卡在偏移量1的位置(对应你看到的'e'字符位置)。

修复方法:把&&改成&:

__OutByte(VGA_DATA_REGISTER , (uint8_t)(offset & 0xff)) ;

2. 光标位置计算的逻辑冗余与潜在问题

你的terminal_putentryat函数里,每次都通过__GetCursor()读取硬件光标位置,再++offset来设置新光标,这种做法有两个明显问题:

  • 硬件端口读写是相对耗时的操作,频繁读取会降低内核执行效率;
  • 依赖硬件光标状态来计算下一个位置,容易出现同步问题(比如其他操作修改光标后,这里读取的就是错误值)。

更可靠的做法是直接用terminal_column和terminal_row计算光标偏移:

static void terminal_putentryat(uint8_t c, uint8_t color , uint8_t x, uint8_t y){
    if (check_special_char(c)){
        // 补充换行处理逻辑:重置列、增加行,可选添加屏幕滚动逻辑
        terminal_column = 0;
        terminal_row++;
        __CursorSet(terminal_row * MAX_COLS + terminal_column);
        return ;
    }
    size_t index = y*MAX_COLS +x ;
    videomem[index] = vga_entry(c , color);
    terminal_column++;
    // 直接用当前行列计算光标偏移,无需读取硬件光标
    __CursorSet(terminal_row * MAX_COLS + terminal_column);
}

3. 换行符处理缺失

当前check_special_char判断到换行符直接return,没有更新光标位置,这会导致输入换行后光标停在原地,后续字符会覆盖当前位置的内容。上面的代码已经补充了基础的换行处理,你可以根据需求完善屏幕滚动逻辑(比如当行号超过最大行数时,将所有行上移一行)。

调试建议

如果修复后仍有问题,可以尝试:

  • 在__CursorSet里添加串口调试输出(如果你的内核支持),打印每次设置的offset值,确认是否符合预期;
  • 用GDB查看__CursorSet函数里的offset参数值,检查低字节和高字节的计算是否正确;
  • 验证VGA_CONTROL_REGISTER和VGA_DATA_REGISTER的宏定义是否正确(标准VGA控制端口是0x3D4,数据端口是0x3D5)。

内容的提问来源于stack exchange,提问作者Grouchous

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:52:44