为何VGA文本模式下字符始终写入0xb8000内存地址?
问题分析与解决方案
你的字符始终写入0xb8000的问题源于两个核心错误:
1. 链接脚本配置错误导致静态变量失效
你的kernel.ld将.data和.bss段分配到了0x80000000地址,但内核实际被bootloader加载到物理地址0x1000。在未开启分页的32位实模式下,0x80000000超出了内核加载的内存范围,导致静态变量x、y、style的存储地址无效——修改初始值时实际操作的是不存在的内存区域,运行时这些变量的值始终为随机垃圾值或固定为0,偏移量计算永远为0,字符只能写入0xb8000。
修正后的kernel.ld:
SECTIONS { . = 0x1000; .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } end = .; _end = .; __end = .; }
2. VGA偏移量计算逻辑错误
VGA文本模式中每个字符占用2字节(字符+属性),正确的偏移量应为行+列的总字符数乘以2。你的代码错误地将行偏移按单字节计算、列偏移按双字节计算:
int offset = y * screen_width + (x * 2); // 错误
修正后的计算方式:
int offset = (y * screen_width + x) * 2; // 正确
例如y=1(第二行)、x=0(第一列)时,正确偏移是(1*80+0)*2=160,原代码会计算为80,导致字符写到第二行中间位置。
额外的空语句bug
代码中存在一个无意义的空语句,会导致控制字符判断分支什么都不做:
else if (c < ' '); // 多余的分号
修正后:
else if (c >= ' ') { // 直接处理可打印字符 // ... 写入逻辑 }
最终修正后的write函数
static void write(const unsigned char c) { if (c == '\n') { ++y; x = 0; } else if (c == '\r') { x = 0; } else if (c >= ' ') { int offset = (y * screen_width + x) * 2; VGA_BASE[offset] = c; VGA_BASE[offset + 1] = style; ++x; } if (x >= screen_width) { ++y; x = 0; } if (y >= screen_height) { scroll(y - screen_height + 1); } set_cursor(); }
内容的提问来源于stack exchange,提问作者IYBBT
相关产品推荐
相关产品推荐

