我正在从头开始构建自己的操作系统。我读了VESA教程,写了一个程序切换到VESA模式,然后把屏幕变成白色。(Stage1。Asm是一个加载并执行内核的程序。
Stage2.asm
[BITS 16]
MOV AX, 800
MOV BX, 600
MOV CL, 32
CALL vbe_set_mode
JMP Fill
vbe_set_mode:
mov [.width], ax
mov [.height], bx
mov [.bpp], cl
sti
push es
mov ax, 0x4F00
mov di, vbe_info
int 0x10
pop es
cmp ax, 0x4F
jne .error
mov ax, word[vbe_info.video_modes]
mov [.offset], ax
mov ax, word[vbe_info.video_modes+2]
mov [.segment], ax
mov ax, [.segment]
mov fs, ax
mov si, [.offset]
.find_mode:
mov dx, [fs:si]
add si, 2
mov [.offset], si
mov [.mode], dx
mov ax, 0
mov fs, ax
push dx
mov dx, 0xFFFF
cmp [.mode], dx
pop dx
je .error
push es
mov ax, 0x4F01
mov cx, [.mode]
mov di, vbe_mode_info
int 0x10
pop es
cmp ax, 0x4F
jne .error
mov ax, [.width]
cmp ax, [vbe_mode_info.width]
jne .next_mode
mov ax, [.height]
cmp ax, [vbe_mode_info.height]
jne .next_mode
mov al, [.bpp]
cmp al, [vbe_mode_info.bpp]
jne .next_mode
mov ax, [.width]
mov word[vbe_screen.width], ax
mov ax, [.height]
mov word[vbe_screen.height], ax
mov eax, [vbe_mode_info.framebuffer]
mov dword[vbe_screen.physical_buffer], eax
mov ax, [vbe_mode_info.pitch]
mov word[vbe_screen.bytes_per_line], ax
mov eax, 0
mov al, [.bpp]
mov byte[vbe_screen.bpp], al
shr eax, 3
mov dword[vbe_screen.bytes_per_pixel], eax
mov ax, [.width]
shr ax, 3
dec ax
mov word[vbe_screen.x_cur_max], ax
mov ax, [.height]
shr ax, 4
dec ax
mov word[vbe_screen.y_cur_max], ax
; Set the mode
push es
mov ax, 0x4F02
mov bx, [.mode]
or bx, 0x4000 ; enable LFB
mov di, 0 ; not sure if some BIOSes need this... anyway it doesn't hurt
int 0x10
pop es
cmp ax, 0x4F
jne .error
clc
ret
.next_mode:
mov ax, [.segment]
mov fs, ax
mov si, [.offset]
jmp .find_mode
.error:
LEA SI, MsgNoVESA
CALL Print
jmp $
.width dw 0
.height dw 0
.bpp db 0
.segment dw 0
.offset dw 0
.mode dw 0
vbe_screen:
.width dw 0
.height dw 0
.bpp dw 0
.physical_buffer db 0
.bytes_per_pixel dw 0
.bytes_per_line dw 0
.x_cur_max dw 0
.y_cur_max dw 0
vbe_info:
.signature db "VESA"
.version dw 0
.oem dd 0
.capabilities dd 0
.video_modes dd 0
.video_memory dw 0
.software_rev dw 0
.vendor dd 0
.product_name dd 0
.product_rev dd 0
.reserved db 222 dup 0
.oem_data db 256 dup 0
vbe_mode_info:
.attributes dw 0
.window_a db 0
.window_b db 0
.granularity dw 0
.window_size dw 0
.segment_a dw 0
.segment_b dw 0
.win_func_ptr dd 0
.pitch dw 0
.width dw 0
.height dw 0
.w_char db 0
.y_char db 0
.planes db 0
.bpp db 0
.banks db 0
.memory_model db 0
.bank_size db 0
.image_pages db 0
.reserved0 db 0
.red_mask db 0
.red_position db 0
.green_mask db 0
.green_position db 0
.blue_mask db 0
.blue_position db 0
.reserved_mask db 0
.reserved_position db 0
.direct_color_attributes db 0
.framebuffer dd 0
.off_screen_mem_off dd 0
.off_screen_mem_size dw 0
.reserved1 db 206 dup 0
Fill:
MOV EBX, [vbe_mode_info.framebuffer]
MOV EAX, [vbe_mode_info.framebuffer]
ADD EAX, 800 * 600 * 4
MOV ECX, 0x00FFFFFF
MOV EDX, 0
FillLoop:
MOV [EBX], ECX
ADD EBX, 4
CMP EBX, EAX
JA EndFunc
JMP FillLoop
EndFunc:
CLI
HLT
MsgNoVESA: db "This PC is not support VESA.", 0x00
此程序适用于QEMU,但不适用于vmware或Virtualbox。为什么这个程序只能在QEMU上工作?
我在代码中发现了几个错误:
mov eax, [vbe_mode_info.framebuffer] mov dword[vbe_screen.physical_buffer], eax
写入dword在字节大小的变量中.physical_buffer db 0
.
mov eax, 0 mov al, [.bpp] mov byte[vbe_screen.bpp], al shr eax, 3 mov dword[vbe_screen.bytes_per_pixel], eax
写入dword在字大小的变量中.bytes_per_pixel dw 0
。这会损坏指向线性帧缓冲区的指针,从而在写入内存时产生灾难性的结果!
您从未检查过VESA版本。尽管如此,您应该这样做,因为您需要的framebuffer指针PhysBasePtr仅包含在VESA 2.0或更好版本的ModeInformation块中。