编写简易内核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
相关产品推荐
相关产品推荐

