32位保护模式下VGA输出错乱,疑似内存布局或GDT配置问题求助
32位保护模式下VGA输出错乱,疑似内存布局或GDT配置问题求助
各位大佬好,我正在用x86汇编和C写一个引导加载程序和简单内核,切换到32位保护模式后C代码能正常运行,但VGA输出总是错乱——要么消息互相覆盖,要么部分内容直接消失,实在卡壳了来求助!
我正在实现的功能:
- 从引导加载程序加载并运行简单C内核
- 进入32位保护模式
- 通过
0xB8000地址直接写入VGA文本内存
目前能正常工作的部分:
- 引导加载程序能成功加载内核到内存
- 可以顺利切换进入32位保护模式
- 少量
echo()调用能正常通过VGA显示文本
遇到的问题:
当我给C文件增加更多echo()调用后,输出就开始损坏了:文本会出现在错误的位置,或者部分内容突然消失。感觉像是内存布局出了问题——会不会我看似进入了保护模式,但实际上还受实模式1MB内存限制的影响?
相关代码片段:
引导加载程序及保护模式切换代码(boot.asm):
[org 0x7c00] KERNEL_LOCATION equ 0x1000 mov [BOOT_DISK], dl xor ax, ax mov es, ax mov ds, ax mov bp, 0x8000 mov sp, bp mov bx, KERNEL_LOCATION mov dh, 2 mov ah, 0x02 mov al, dh mov ch, 0x00 mov dh, 0x00 mov cl, 0x02 mov dl, [BOOT_DISK] int 0x13 ; 暂时没加错误处理,之后会补! mov ah, 0x0 mov al, 0x3 int 0x10 ; 切换到文本模式 CODE_SEG equ GDT_code - GDT_start DATA_SEG equ GDT_data - GDT_start cli lgdt [GDT_descriptor] mov eax, cr0 or eax, 1 mov cr0, eax jmp CODE_SEG:start_protected_mode jmp $ BOOT_DISK: db 0 GDT_start: GDT_null: dd 0x0 dd 0x0 GDT_code: dw 0xffff dw 0x0 db 0x0 db 0b10011010 db 0b11001111 db 0x0 GDT_data: dw 0xffff dw 0x0 db 0x0 db 0b10010010 db 0b11001111 db 0x0 GDT_end: GDT_descriptor: dw GDT_end - GDT_start - 1 dd GDT_start [bits 32] start_protected_mode: mov ax, DATA_SEG mov ds, ax mov ss, ax mov es, ax mov fs, ax mov gs, ax mov ebp, 0x90000 ; 32位栈基址 mov esp, ebp jmp KERNEL_LOCATION times 510-($-$$) db 0 dw 0xaa55
C内核代码示例(kernel.c):
#include <stdint.h> volatile uint8_t* video = (uint8_t*)0xB8000; void echo(const char* message, uint8_t color, int row, int col) { // VGA内存基地址 volatile uint8_t* video = (uint8_t*)0xb8000; // 确保列数在有效范围(0-79) if (col < 0 || col >= 80) return; // 计算偏移量 int offset = (row * 80 + col) * 2; // 确保不超出屏幕内存范围 if (offset >= 4000) return; // 写入消息字符 for (int i = 0; message[i] != '\0'; ++i) { // 防止超出80列 if (col + i >= 80) break; // 写入字符和颜色字节 video[offset + i * 2] = message[i]; video[offset + i * 2 + 1] = color; } } int main() { echo("HELLO WORLD!", 0xD0, 0, 0); // 这里加更多echo调用后就出问题了 return 0; }
内核入口代码(entry.asm):
global _start extern main section .text [bits 32] _start: call main jmp $
我已经尝试过的方法:
- 增大栈的大小(把
ebp设到更高的地址) - 限制
echo的输出范围,确保不会越界 - 手动检查内存布局,确认VGA地址
0xB8000未被占用
我的疑问:
是不是我虽然进入了保护模式,但因为没设置分页或者GDT段限配置不对,导致内存不能完全使用?还是内核加载到了错误的内存区域,导致它覆盖了VGA内存或者自身代码?
内容来源于stack exchange
相关产品推荐
相关产品推荐

