Linux操作系统, 构建自己的内核——6.使用调色板绘制系统界面
学习课程:
使用调色板绘制系统界面
在上一课程中,通过往0xA0000-0xAFFFF共64KB的的显存空间写入0-255的字符,来绘制界面。
0-255表示的颜色非常有限,画出来的效果很单调。利用调色板功能,能够绘制出更丰富的图案。
使用调色板功能时,显存空间的每个字符不再表示颜色,而是表示颜色的下标。
真正的颜色存储在一个数组中。因为一个字节最大只能表示到255,所以,表示颜色的数组最大也只能255。
在表示颜色的数组中,使用RGB方法表示颜色,每种颜色用3个字节表示,分别对应red,green,blue。
要打开调色板功能,和写入表示颜色的数组,都需要与硬件的端口打交道。
1. 使用调色板
kernel.asm
%include "pm.inc"
org 0x9000
VRAM_ADDRESS equ 0x000a0000
jmp LABEL_BEGIN
[SECTION .gdt]
; 段基址 段界限 属性
LABEL_GDT: Descriptor 0, 0, 0
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32
LABEL_DESC_VRAM: Descriptor 0, 0ffffffffh, DA_DRW
LABEL_DESC_STACK: Descriptor 0, TopOfStack, DA_DRWA+DA_32
GdtLen equ $ - LABEL_GDT
GdtPtr dw GdtLen - 1
dd 0
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorStack equ LABEL_DESC_STACK - LABEL_GDT
SelectorVram equ LABEL_DESC_VRAM - LABEL_GDT
[SECTION .s16]
[BITS 16]
LABEL_BEGIN:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0100h
mov al, 0x13
mov ah, 0
int 0x10
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_STACK
mov word [LABEL_DESC_STACK + 2], ax
shr eax, 16
mov byte [LABEL_DESC_STACK + 4], al
mov byte [LABEL_DESC_STACK + 7], ah
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT
mov dword [GdtPtr + 2], eax
lgdt [GdtPtr]
cli ;关中断
in al, 92h
or al, 00000010b
out 92h, al
mov eax, cr0
or eax , 1
mov cr0, eax
jmp dword SelectorCode32: 0
[SECTION .s32]
[BITS 32]
LABEL_SEG_CODE32:
;initialize stack for c code
mov ax, SelectorStack
mov ss, ax
mov esp, TopOfStack
mov ax, SelectorVram
mov ds, ax
C_CODE_ENTRY:
%include "palette1.asm"
io_hlt: ;void io_hlt(void);
HLT
RET
io_in8:
mov edx, [esp + 4]
mov eax, 0
in al, dx
io_in16:
mov edx, [esp + 4]
mov eax, 0
in ax, dx
io_in32:
mov edx, [esp + 4]
in eax, dx
ret
io_out8:
mov edx, [esp + 4]
mov al, [esp + 8]
out dx, al
ret
io_out16:
mov edx, [esp + 4]
mov eax, [esp + 8]
out dx, ax
ret
io_out32:
mov edx, [esp + 4]
mov eax, [esp + 8]
out dx, eax
ret
io_cli:
CLI
RET
io_load_eflags:
pushfd
pop eax
ret
io_store_eflags:
mov eax, [esp + 4]
push eax
popfd
ret
SegCode32Len equ $ - LABEL_SEG_CODE32
[SECTION .gs]
ALIGN 32
[BITS 32]
LABEL_STACK:
times 512 db 0
TopOfStack equ $ - LABEL_STACK
操作端口的这几个汇编函数,是很不错的封装,简化了在c语言中的使用。
可以看出来,
[esp+4]表示函数的第一个参数
[esp+8]表示函数的第二个参数
那便有一个疑问,[esp]表示的是什么呢?
esp表示的是上一个函数的返回地址。也就是这个函数执行完成之后,要执行的下一条指令。
而参数是按照从右向左的方式入栈的,所以取的时候,esp+4的位置便取到的是第一个参数。
write_vga.asm
; Disassembly of file: write_vga.o
; Sun Sep 8 06:05:48 2019
; Mode: 32 bits
; Syntax: YASM/NASM
; Instruction set: 80386
CMain: ; Function begin
push ebp ; 0000 _ 55
mov ebp, esp ; 0001 _ 89. E5
sub esp, 24 ; 0003 _ 83. EC, 18
mov dword [ebp-0CH], 0 ; 0006 _ C7. 45, F4, 00000000
call init_palette ; 000D _ E8, FFFFFFFC(rel)
mov dword [ebp-10H], 655360 ; 0012 _ C7. 45, F0, 000A0000
jmp ?_002 ; 0019 _ EB, 17
?_001: mov eax, dword [ebp-10H] ; 001B _ 8B. 45, F0
mov dword [ebp-0CH], eax ; 001E _ 89. 45, F4
mov eax, dword [ebp-10H] ; 0021 _ 8B. 45, F0
and eax, 0FH ; 0024 _ 83. E0, 0F
mov edx, eax ; 0027 _ 89. C2
mov eax, dword [ebp-0CH] ; 0029 _ 8B. 45, F4
mov byte [eax], dl ; 002C _ 88. 10
add dword [ebp-10H], 1 ; 002E _ 83. 45, F0, 01
?_002: cmp dword [ebp-10H], 720895 ; 0032 _ 81. 7D, F0, 000AFFFF
jle ?_001 ; 0039 _ 7E, E0
?_003: call io_hlt ; 003B _ E8, FFFFFFFC(rel)
jmp ?_003 ; 0040 _ EB, F9
; CMain End of function
init_palette:; Function begin
push ebp ; 0042 _ 55
mov ebp, esp ; 0043 _ 89. E5
sub esp, 24 ; 0045 _ 83. EC, 18
mov dword [esp+8H], table_rgb.1397 ; 0048 _ C7. 44 24, 08, 00000000(d)
mov dword [esp+4H], 15 ; 0050 _ C7. 44 24, 04, 0000000F
mov dword [esp], 0 ; 0058 _ C7. 04 24, 00000000
call set_palette ; 005F _ E8, FFFFFFFC(rel)
nop ; 0064 _ 90
leave ; 0065 _ C9
ret ; 0066 _ C3
; init_palette End of function
set_palette:; Function begin
push ebp ; 0067 _ 55
mov ebp, esp ; 0068 _ 89. E5
sub esp, 40 ; 006A _ 83. EC, 28
call io_load_eflags ; 006D _ E8, FFFFFFFC(rel)
mov dword [ebp-0CH], eax ; 0072 _ 89. 45, F4
call io_cli ; 0075 _ E8, FFFFFFFC(rel)
mov eax, dword [ebp+8H] ; 007A _ 8B. 45, 08
mov dword [esp+4H], eax ; 007D _ 89. 44 24, 04
mov dword [esp], 968 ; 0081 _ C7. 04 24, 000003C8
call io_out8 ; 0088 _ E8, FFFFFFFC(rel)
mov eax, dword [ebp+8H] ; 008D _ 8B. 45, 08
mov dword [ebp-10H], eax ; 0090 _ 89. 45, F0
jmp ?_005 ; 0093 _ EB, 59
?_004: mov eax, dword [ebp+10H] ; 0095 _ 8B. 45, 10
movzx eax, byte [eax] ; 0098 _ 0F B6. 00
movzx eax, al ; 009B _ 0F B6. C0
mov dword [esp+4H], eax ; 009E _ 89. 44 24, 04
mov dword [esp], 969 ; 00A2 _ C7. 04 24, 000003C9
call io_out8 ; 00A9 _ E8, FFFFFFFC(rel)
mov eax, dword [ebp+10H] ; 00AE _ 8B. 45, 10
add eax, 1 ; 00B1 _ 83. C0, 01
movzx eax, byte [eax] ; 00B4 _ 0F B6. 00
movzx eax, al ; 00B7 _ 0F B6. C0
mov dword [esp+4H], eax ; 00BA _ 89. 44 24, 04
mov dword [esp], 969 ; 00BE _ C7. 04 24, 000003C9
call io_out8 ; 00C5 _ E8, FFFFFFFC(rel)
mov eax, dword [ebp+10H] ; 00CA _ 8B. 45, 10
add eax, 2 ; 00CD _ 83. C0, 02
movzx eax, byte [eax] ; 00D0 _ 0F B6. 00
movzx eax, al ; 00D3 _ 0F B6. C0
mov dword [esp+4H], eax ; 00D6 _ 89. 44 24, 04
mov dword [esp], 969 ; 00DA _ C7. 04 24, 000003C9
call io_out8 ; 00E1 _ E8, FFFFFFFC(rel)
add dword [ebp+10H], 3 ; 00E6 _ 83. 45, 10, 03
add dword [ebp-10H], 1 ; 00EA _ 83. 45, F0, 01
?_005: mov eax, dword [ebp-10H] ; 00EE _ 8B. 45, F0
cmp eax, dword [ebp+0CH] ; 00F1 _ 3B. 45, 0C
jle ?_004 ; 00F4 _ 7E, 9F
mov eax, dword [ebp-0CH] ; 00F6 _ 8B. 45, F4
mov dword [esp], eax ; 00F9 _ 89. 04 24
call io_store_eflags ; 00FC _ E8, FFFFFFFC(rel)
nop ; 0101 _ 90
leave ; 0102 _ C9
ret ; 0103 _ C3
; set_palette End of function
table_rgb.1397: ; byte
db 00H, 00H, 00H, 0FFH, 00H, 00H, 00H, 0FFH ; 0000 _ ........
db 00H, 0FFH, 0FFH, 00H, 00H, 00H, 0FFH, 0FFH ; 0008 _ ........
db 00H, 0FFH, 00H, 0FFH, 0FFH, 0FFH, 0FFH, 0FFH ; 0010 _ ........
db 0C6H, 0C6H, 0C6H, 84H, 00H, 00H, 00H, 84H ; 0018 _ ........
db 00H, 84H, 84H, 00H, 00H, 00H, 84H, 84H ; 0020 _ ........
db 00H, 84H, 00H, 84H, 84H, 84H, 84H, 84H ; 0028 _ ........
效果:
2. 绘制矩形&绘制桌面
都是调色板的具体应用而已,没有新的知识点。
还没有评论,来说两句吧...