无法在 ASM x86 保护模式下访问所有屏幕字节

Can't access all the screen bytes in ASM x86 protected mode

为什么我无法在 vesa 模式下访问所有像素?

mov ax, 0x4F02;                 // vesa video mode
mov bx, 0x0101;                 // mode 640x480 256 colors

int 0x10;                       // video interupter

我直接在屏幕上绘图(在保护模式下):

mov edi, 0x0A0000
add edi, 80000
mov al,0x0F      ; the color of the pixel
mov [edi], al

在实模式下:

mov ax, 0xA000; video adress
mov es, ax; segment address to es

mov di, 1200; pixel adress x + ( y * width )
mov al, 0x25; pixel colour
mov [es:di], al;

在 13h 模式下,我可以在所有屏幕上绘制,但在 vesa 中,我只能在 +/- line(y) 100 之前绘制

why i cant access all the pixels at vesa modes?

最初(由于实模式的限制加上原始视频卡不需要更多)视频卡被分配了两个 64 KiB 的物理内存区域(从 0x000A0000 到 0x000AFFFF,从 0x000B0000 到 0x000BFFFF)。

当视频卡开始支持更好的视频模式(像素更多,每像素位数更多)时,帧缓冲区不适合 64 KiB 区域;所以视频卡开始做一个名为 "bank switching" 的丑陋黑客来解决这个问题。基本上;您 select 帧缓冲区的哪 64 KiB 块被映射到物理地址的遗留 64 KiB 区域 space。

当视频卡开始支持更好的视频模式时,bank 切换开始变得混乱(特别是对于 24 位视频模式,同一像素的不同部分可以在不同的 bank 中),并且随着视频 RAM 变得更快银行切换(使用慢速 IO 端口)没有,银行切换成为一个性能问题。与此同时,CPU 支持更大的物理地址大小(例如 4 GiB 而不是原来的 1 MiB),整个缓慢的 hacky 混乱似乎更加愚蠢。修复不同的视频卡开始在不同的物理地址提供它们的整个帧缓冲区(使用专有的非标准扩展);不久之后,VBE 添加了一个标准 API,软件可以使用该标准来控制专有的非标准扩展。这被称为 "Linear Frame Buffer" (LFB)。

实践中;这意味着:

  • 对于 VBE 1,您必须使用库切换来访问超过 64 KiB 的帧缓冲区。 注意:理论上,对于某些视频卡,可以配置两个 64 KiB 区域,使其看起来像一个 128 KiB 区域;当视频模式的帧缓冲区大于 64 KiB 且小于 128 KiB 时,这有助于避免库切换。

  • 对于 VBE 2 及更高版本,您可以选择使用库切换或 LFB。在这种情况下,您必须检查视频模式是否支持 LFB,然后通过在设置模式时设置标志来告诉 VBE 您想要使用 LFB,并从 VBE 的模式中获取 LFB 的地址(不会在 0x000A0000)信息结构.

此代码配置VBE模式,并在屏幕上绘制一个像素(您可以使用LFB在所有屏幕上绘制):

vbe_info:

    .signature db "VBE2";   // must be "VESA" to indicate valid VBE support
    .version resw 1;            // VBE version; high byte is major version, low byte is minor version
    .oem resd 1;            // segment:offset pointer to OEM
    .capabilities resd 1;       // bitfield that describes card capabilities
    .video_modes resd 1;        // segment:offset pointer to list of supported video modes
    .video_memory resw 1;       // amount of video memory in 64KB blocks
    .software_rev resw 1;       // software revision
    .vendor resd 1;         // segment:offset to card vendor string
    .product_name resd 1;       // segment:offset to card model name
    .product_rev resd 1;        // segment:offset pointer to product revision
    .reserved resb 222;     // reserved for future expansion
    .oem_data resb 256;     // OEM BIOSes store their strings in this area

mode_info:

    .attributes resw 1;     // deprecated, only bit 7 should be of interest to you, and it indicates the mode supports a linear frame buffer.
    .window_a resb 1;           // deprecated
    .window_b resb 1;           // deprecated
    .granularity resw 1;        // deprecated; used while calculating bank numbers
    .window_size resw 1;
    .segment_a resw 1;
    .segment_b resw 1;
    .win_func_ptr resd 1;       // deprecated; used to switch banks from protected mode without returning to real mode
    .pitch resw 1;          // number of bytes per horizontal line
    .width resw 1;          // width in pixels
    .height resw 1;         // height in pixels
    .w_char resb 1;         // unused...
    .y_char resb 1;         // ...
    .planes resb 1;
    .bpp resb 1;            // bits per pixel in this mode
    .banks resb 1;          // deprecated; total number of banks in this mode
    .memory_model resb 1;
    .bank_size resb 1;      // deprecated; size of a bank, almost always 64 KB but may be 16 KB...
    .image_pages resb 1;
    .reserved0 resb 1;

    .red_mask resb 1;
    .red_position resb 1;
    .green_mask resb 1;
    .green_position resb 1;
    .blue_mask resb 1;
    .blue_position resb 1;
    .reserved_mask resb 1;
    .reserved_position resb 1;
    .direct_color_attributes resb 1;

    .framebuffer resd 1;        // physical address of the linear frame buffer; write here to draw to the screen
    .off_screen_mem_off resd 1;
    .off_screen_mem_size resw 1;    // size of memory in the framebuffer but not being displayed on the screen
    .reserved1 resb 206;

enable_vesa:

vbe_get_info:

    mov ah, 4Fh;        Super VGA support
    mov al, 00h;        Return Super VGA information
    mov di, vbe_info;   Pointer to buffer

    int 0x10;

    cmp ax, 0x4F                ; BIOS doesn't support VBE?
    jne error

get_mode_info:

    mov ax, 4F01h;        Return mode information
    mov cx, 0x101;[vbe_info.video_modes]; first mode
    mov di, mode_info;  Pointer to buffer

    int 0x10;

    cmp ax, 0x4F                ; BIOS doesn't support VBE?
    jne error

set_mode:

    mov ah, 0
    mov ax, 0x4F02
    mov ebx, [vbe_info.video_modes]; estore de modes pointer at ebx to can access as a adress
    mov bx, [ebx+8]; 8/2 = 4th mode in the mode array!!!!!!!

    int 0x10

draw:

    ;Assume first window is valid 
    mov ax, WORD [es:mode_info + 08h]
    mov es, ax

    ;Example of how to change the window 
    mov ax, 4f05h
    xor bx, bx
    mov dx, 5       ;This is granularity units
    int 10h

    ;fist atempt
    mov edi, [mode_info.framebuffer];   framebuffer
    add edi, 180050;                        pixel_offset = y * pitch + ( x * ( bpp/8 )) + framebuffer;
    mov al,0x0F;                        the color of the pixel
    mov [edi], al

    mov si, msg;
    call print

    jmp $

msg db "finish", 0