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

32位保护模式下开发贪吃蛇OS无法绘制白色像素问题

32位保护模式下无法绘制像素的问题

我正在开发一款运行贪吃蛇的OS,当前处于32位保护模式,但无法在屏幕上绘制像素。实模式下切换到Mode 0x13(320x200x256色)模式后屏幕变黑,进入保护模式内核运行后,绘制的像素仍不显示。我参考了OSDev上的《Drawing_In_Protected_Mode》文章进行开发。以下是相关代码:

kernel.c

#include "display.h"    // Include Display Drivers
#include "constants.h" // Include constants that C doesn't have included
#include "keyboard.h" // Include the custom keyboard driver

void _start(){} // Remove LD Warning

DisplayDetails globalDisplayDetails; // The display details.

int main(){
    // Init the display details
    DisplayDetails details = display_init();
    globalDisplayDetails = details;
    bool running = true;
    
    while(running){
        // This is the OS loop
        putpixel(100, 100, 0x00FFFFFF);
    }
    
    // return 0;
}

display.h(显示驱动)

#define VRAM 0xA0000

typedef struct DisplayModeDetails {
    int width;            // Width of one line of pixels
    int height;          //  Height of display in pixels
    int colors;         //   How many colors are supported
    int pitch;         //    How many bytes of VRAM to skip when going 1 pixel down
    int pixelWidth;   //     How many bytes of VRAM to skip when going 1 pixel right
} DisplayDetails;

struct DisplayModeDetails display_init(){
    struct DisplayModeDetails details; // Setup display mode details
    details.width      = 640;
    details.height     = 480;
    details.colors     = 16;
    details.pitch      = 1;
    details.pixelWidth = 1;
    return details;
}

void putpixel(int pos_x, int pos_y, unsigned long VGA_COLOR)
{
    unsigned char* location = (unsigned char*)0xA0000 + 320 * pos_y + pos_x;
    *location = VGA_COLOR;
}

boot_sect.asm

[bits 16]
[org 0x7C00]

mov [BOOTDRIVE], dl

; call clear_screen ; Clear screen
call load_kernel

load_kernel:
    mov bx, KERNELOFFSET
    mov dh, 0x05
    mov dl, [BOOTDRIVE]
    ; mov dl, 0x80
    call clear_screen     ; Clear Screen
    call disk_load        ; Load From Disk

    mov ah, 0x00          ; Start setting video mode
    mov al, 0x13          ; 320x200 256 color graphics
    int 0x10

    cli                   ; Disable Interrupts
    lgdt [gdt_descriptor] ; GDT start address
    mov eax, cr0
    or eax, 1
    mov cr0, eax          ; Jump to Protected 32 bit mode
    jmp CODESEG:start_protected_mode

    jmp $

clear_screen:
    pusha

    mov ah, 0x07     ; Scroll al lines; 0 = all
    mov bh, 0x0f     ; white on black
    mov cx, 0x00     ; row=0, col=0
    mov dx, 0x184f   ; row = 24, col = 79
    int 0x10         ; Call interrupt

    mov ah, 0x02
    mov dh, 0x00
    mov dl, 0x00
    mov bh, 0x00
    int 0x10

    popa
    ret

disk_load:
    pusha
    push dx
    mov ah, 0x02 ; read mode
    mov al, dh   ; read dh number of sects
    mov cl, 0x02 ; read from sect 2 (1 = boot)
    mov ch, 0x00 ; cylinder 0
    mov dh, 0x00 ; head 0

    int 0x13
    jc disk_error

    pop dx
    cmp al, dh

    jne sectors_error
    popa
    ret

disk_error:
    mov ah, '1' ; Error Code
    jmp err_loop
sectors_error:
    mov ah, '2' ; Error Code
    jmp err_loop
err_loop:
    call clear_screen
    mov dh, ah ; Print Error Message
    mov ah, 0x0e
    mov al, 'E'
    int 0x10
    mov al, 'r'
    int 0x10
    int 0x10
    mov al, ' '
    int 0x10
    mov al, dh ; Print Error Code
    int 0x10
    
    jmp $ ; create infinite loop

; Constants
KERNELOFFSET equ 0x1000
CODESEG equ gdt_code - gdt_start
DATASEG equ gdt_data - gdt_start

gdt_start:
    dq 0x0

    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
        dd gdt_start

[bits 32]
start_protected_mode:
    ; Load the kernel
    mov ax, DATASEG
    mov dx, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    
    mov ebp, 0x9000
    mov esp, ebp

    call KERNELOFFSET
    jmp $

BOOTDRIVE db 0

; Marking as bootable.
times 510-($-$$) db 0
dw 0xaa55

kernel_entry.asm

[bits 32]
[extern main]
call main
jmp $

构建测试脚本

gcc -m32 -fno-pie -ffreestanding -g -c kernel.c  -o obj/main.o

nasm -f elf kernel_entry.asm -o obj/entry.o
nasm -f bin boot_sect.asm -o obj/boot.bin

ld -m elf_i386 -o obj/kernel.bin -Ttext 0x1000 obj/main.o obj/entry.o  --oformat binary

cat obj/boot.bin obj/kernel.bin > bin/os.bin

qemu-system-x86_64 -drive format=raw,file=bin/os.bin -display sdl

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:10:18