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

为何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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 09:09:52