Patrick Sant
Patrick Sant

Reputation: 59

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

why i cant access all the pixels at vesa modes?

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

int 0x10;                       // video interupter

im drawing direct in screen with(in protected mode):

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

in real mode:

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;

in the 13h mode i can draw at all the screen, but in the vesa i can draw only before +/- line(y) 100

Upvotes: 0

Views: 636

Answers (2)

Patrick Sant
Patrick Sant

Reputation: 59

this code configure the VBE mode, and draw a pixel at screen( you can draw at all screen with 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

Upvotes: 1

Brendan
Brendan

Reputation: 37232

why i cant access all the pixels at vesa modes?

Originally (due to limitations of real mode combined with the original video cards not needing more) the video card was given two 64 KiB areas of physical memory (from 0x000A0000 to 0x000AFFFF, and from 0x000B0000 to 0x000BFFFF).

When video cards started supporting better video modes (with more pixels and more bits per pixel) the frame buffer didn't fit in the 64 KiB area; so video cards starting doing an ugly hack called "bank switching" to work around the problem. Basically; you select which 64 KiB piece of the frame buffer gets mapped into a legacy 64 KiB area of the physical address space.

When video cards started supporting even better video modes bank switching started to get messy (especially for 24-bit video modes, where different parts of the same pixel can be in different banks), and as video RAM got faster the bank switching (which used slow IO ports) didn't, and the bank switching became a performance problem. At the same time, CPUs were supporting much larger physical address sizes (e.g. 4 GiB instead of the original 1 MiB) and the whole slow hacky mess seemed even sillier. To fix that different video cards started providing their whole frame buffer at a different physical address (using proprietary non-standard extensions); and not long after that VBE added a standard API that software can use to control the proprietary non-standard extensions. This become known as "Linear Frame Buffer" (LFB).

In practice; what all this means is that:

  • for VBE 1, you have to use bank switching to access more than 64 KiB of the frame buffer. Note: In theory, for some video cards its possible to configure both 64 KiB areas so that it looks like a single 128 KiB area; and this can help to avoid bank switching when the video mode's frame buffer is larger than 64 KiB and less than 128 KiB.

  • for VBE 2 and later, you can choose to use bank switching or LFB. In this case you have to check that the video mode supports LFB, then tell VBE that you want to use LFB by setting a flag when you set the mode, and get the address of LFB (which will NOT be at 0x000A0000) from VBE's mode information structure.

Upvotes: 2

Related Questions