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

自定义OS开发:GRUB配置1024x768x32后无法切换至图形模式

自定义OS GRUB图形模式切换失败问题

开发自定义操作系统,使用GRUB引导加载内核时遇到图形模式切换失败问题:已在GRUB配置中设置启动为1024x768x32图形模式,但系统启动后仍处于文本模式——内核中面向文本模式的print函数可正常运行,图形模式相关操作无效果。已在多台虚拟机和物理机测试,GRUB版本为2.06。

引导加载程序代码(bootloader.asm)

[bits 32]

section .multiboot

align 4
dd 0x1BADB002            ; Multiboot magic number
dd 0x00                  ; Flags
dd -(0x1BADB002 + 0x00)  ; Checksum (must be such that all the dword sums to zero)

section .bootstrap_stack
align 16
stack_bottom: 
times 16384 db 0 ; Declare a stack of 16KB
stack_top:

section .text

extern kmain ; This should be in your kernel code
global start

start:

    mov esp, stack_top ; Set up the stack
    call kmain         ; Call the main function in the kernel
    cli                ; Disable interrupts
.hang:
    hlt                ; Halt the CPU
    jmp .hang          ; Infinite loop just in case

内核代码(kernel.c)

#define VIDEO_MEMORY 0xA0000

void print(char *str, int x, int y) {
    volatile char *video = (volatile char*)(0xB8000 + 2*x + 160*y);
    while (*str != 0) {
        *video = *str;
        video += 2;
        str++;
    }
}

#define VIDEO_MEMORY 0xA0000

void fill_screen(unsigned char color) {
    unsigned char* video_memory = (unsigned char*)VIDEO_MEMORY;
    int i;
    for (i = 0; i < 320 * 200; i++)
        video_memory[i] = color;
}

void draw_pixel(int x, int y, unsigned char color) {
    unsigned char* video_memory = (unsigned char*)VIDEO_MEMORY;
    int offset = y * 320 + x;
    video_memory[offset] = color;
}

void fillRect(int x, int y, int width, int height, unsigned char color) {
    unsigned char* video_memory = (unsigned char*)0xA0000;
    int i, j;
    for (i = y; i < y + height; i++) {
        for (j = x; j < x + width; j++) {
            draw_pixel(x+i,y+j, color);
        }
    }
}

void kmain() {
    print("hello", 0, 0);
    
        fill_screen(0x0F);     // Fill the screen with white color (0x0F)
        draw_pixel(160, 100, 0x0);   // Draw a black pixel at (160, 100)
    fillRect(5,10,20,20,0xFF);
    uint8_t* framebuffer = (uint8_t*)0xA0000; // Replace with your framebuffer address
    unsigned int bytes_per_pixel = 3; // Replace with your bytes per pixel
    unsigned int bytes_per_scanline = 1920; // Replace with your bytes per scanline
    unsigned int x = 10; // The x coordinate of the pixel
    unsigned int y = 10; // The y coordinate of the pixel

    uint8_t* pixel_address = framebuffer + y * bytes_per_scanline + x * bytes_per_pixel;
    pixel_address[0] = 0xFF; // Red
    pixel_address[1] = 0x00; // Green
    pixel_address[2] = 0x00; // Blue

}

GRUB配置(grub.cfg)

set default=0
set timeout=0

menuentry "My OS" {
    multiboot /boot/myos.bin
    set gfxpayload=1024x768x32
    insmod all_video
    boot
}

排查方向与解决建议

  • 修正GRUB配置顺序:set gfxpayload和insmod all_video必须放在multiboot命令之前,GRUB需要在加载内核前就设置好图形模式。修正后的配置如下:
    set default=0
    set timeout=0
    
    menuentry "My OS" {
        insmod all_video
        set gfxpayload=1024x768x32
        multiboot /boot/myos.bin
        boot
    }
    
  • 启用Multiboot图形支持标志:当前引导加载程序的Multiboot flags为0x00,未启用图形模式支持。需要将flags改为0x00000003(同时启用内存信息和图形模式支持),并重新计算校验码:
    dd 0x1BADB002            ; Multiboot magic number
    dd 0x00000003            ; Flags: 0x1=内存信息, 0x2=图形模式支持
    dd -(0x1BADB002 + 0x00000003)  ; 重新计算校验码
    
  • 读取GRUB传递的帧缓冲参数:内核中硬编码的0xA0000是VGA 320x200 8位模式的地址,与GRUB设置的1024x768x32模式不匹配。需要修改kmain接收Multiboot信息指针,解析其中的帧缓冲地址、分辨率、像素格式:
    #include <stdint.h>
    
    typedef struct multiboot_info {
        uint32_t flags;
        uint32_t mem_lower;
        uint32_t mem_upper;
        // 省略其他字段,仅保留图形相关部分
        uint32_t framebuffer_addr;
        uint32_t framebuffer_pitch;
        uint32_t framebuffer_width;
        uint32_t framebuffer_height;
        uint8_t framebuffer_bpp;
    } multiboot_info_t;
    
    void kmain(multiboot_info_t *mbi) {
        // 检查是否支持图形模式
        if (mbi->flags & (1 << 12)) {
            uint8_t* framebuffer = (uint8_t*)mbi->framebuffer_addr;
            uint32_t pitch = mbi->framebuffer_pitch;
            uint32_t width = mbi->framebuffer_width;
            uint32_t height = mbi->framebuffer_height;
            uint8_t bpp = mbi->framebuffer_bpp;
    
            // 绘制测试像素(注意部分格式为BGR)
            uint32_t x = 10, y = 10;
            uint8_t* pixel = framebuffer + y * pitch + x * (bpp / 8);
            pixel[0] = 0xFF; // 蓝
            pixel[1] = 0x00; // 绿
            pixel[2] = 0x00; // 红
        }
    }
    
    同时修改引导加载程序,将Multiboot信息指针传递给kmain:
    start:
        mov esp, stack_top ; 设置栈
        push ebx           ; Multiboot信息指针存于ebx,传递给kmain
        call kmain         ; 调用内核主函数
        cli                ; 禁用中断
    .hang:
        hlt                ; 暂停CPU
        jmp .hang          ; 无限循环
    
  • 验证图形模式支持性:在GRUB菜单按c进入命令行,手动执行insmod all_video、set gfxpayload=1024x768x32、vbeinfo查看支持的模式列表,确认1024x768x32是否在其中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 12:07:13