无法在 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
为什么我无法在 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