Day4

Using the C language and screen display

Add a write memory function

1
2
3
4
5
6
7
; add to naskfunc.nas
; void write_mem8(int addr , int data)
_write_mem8:
mov ecx,[esp+4] ; ecx = addr
mov al,[esp+8] ; al = data
mov [ecx],al ; *ecx = al
ret

Draw something via direct VRAM access in C

1
2
3
4
5
6
7
8
9
10
11
void io_hlt(void);
void write_mem8(int addr , int data);
void HariMain(void){
int i ;
//fill the whole VRAM
for (i = 0xa0000 ; i <= 0xaffff ; i++){
write_mem8(i , 14); //the author use 15 which is color white
}

for (;;) io_hlt();
}

direct access to VRAM

Use pointer
1
2
3
4
5
6
7
8
void HariMain(void){
int i ;
//fill the whole VRAM
for (i = 0xa0000 ; i <= 0xaffff ; i++){
*i = i & 0xf ;
}

for (;;) io_hlt();

rainbow

Configuring colors

we can define a mapping between the 8 bit color and 24 bit color

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
//bootpack.c
void io_hlt(void);
void io_cli(void);
void io_out8(int port , int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start , int end , unsigned char * rgb);

void HariMain(void){
int i ;
char * p ;
init_palette();
p = (char *) 0xa0000 ;
for (i = 0 ; i <= 0xffff ; i++){
p[i] = i & 0xf;
}
for(;;) io_hlt();

}

void init_palette(void)
{ static unsigned char table_rgb[16 * 3] = {
0x00, 0x00, 0x00, /* 0:黑 */
0xff, 0x00, 0x00, /* 1:亮红 */
0x00, 0xff, 0x00, /* 2:亮绿 */
0xff, 0xff, 0x00, /* 3:亮黄 */
0x00, 0x00, 0xff, /* 4:亮蓝 */
0xff, 0x00, 0xff, /* 5:亮紫 */
0x00, 0xff, 0xff, /* 6:浅亮蓝 */
0xff, 0xff, 0xff, /* 7:白 */
0xc6, 0xc6, 0xc6, /* 8:亮灰 */
0x84, 0x00, 0x00, /* 9:暗红 */
0x00, 0x84, 0x00, /* 10:暗绿 */
0x84, 0x84, 0x00, /* 11:暗黄 */
0x00, 0x00, 0x84, /* 12:暗青 */
0x84, 0x00, 0x84, /* 13:暗紫 */
0x00, 0x84, 0x84, /* 14:浅暗蓝 */
0x84, 0x84, 0x84 /* 15:暗灰 */
};
set_palette(0, 15, table_rgb);
return;
}

void set_palette(int start , int end , unsigned char * rgb){
int i , eflags;
eflags = io_load_eflags();
io_cli(); // no interrupt allowed
io_out8(0x03c8 , start); //write to port 0x03c8 (video DA converter)
for (i = start ; i <= end ; i++){
io_out8(0x03c9 , rgb[0] / 4);
io_out8(0x03c9, rgb[1] / 4);
io_out8(0x03c9 , rgb[2] / 4);
rgb+=3;
}
io_store_eflags(eflags);
return ;
}

首先在一连串的访问中屏蔽中断(比如CLI)。

将想要设定的调色板号码写入0x03c8,紧接着,按R,G,B的顺序

写入0x03c9。如果还想继续设定下一个调色板,则省略调色板号

码,再按照RGB的顺序写入0x03c9就行了。

如果想要读出当前调色板的状态,首先要将调色板的号码写入

0x03c7,再从0x03c9读取3次。读出的顺序就是R,G,B。如果要继

续读出下一个调色板,同样也是省略调色板号码的设定,按RGB的

顺序读出。

如果最初执行了CLI,那么最后要执行STI。

为什么这里要除4?

VGA显示模式只支持6位的颜色,而我们是采用8位的16进制来表示颜色,为了更好的适配VGA显示,需要将8位的颜色右移2位,也就是除4。

Port 0x3C8

Port 0x3C8, 0x3C9 and 0x3C7 control the DAC. Each register in the DAC consists of 18 bits, 6 bits for each color component. To write a color, write the color index to port 0x3C8, then write 3 bytes to 0x3C9 in the order red, green, blue. If you want to write multiple consecutive DAC entries, you only need to write the first entry’s index to 0x3C8 then write all values to 0x3C9 in the order red, green, blue, red, green, blue, and so on. The accessed DAC entry will automatically increment after every three bytes written. To read the DAC entries, write the index to be read to 0x3C7, then read the bytes from port 0x3C9 in a similar fashion (as with writing, the index will increment after every three bytes read)

osdev

Implement low level functions in assembly

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
[FORMAT "WCOFF"]
[INSTRSET "i486p"] ; use ISA 486
[BITS 32]
[FILE "naskfunc.nas"]

global _io_hlt , _io_cli , _io_sti , _io_stihlt
global _io_in8 , _io_in16 , _io_in32
global _io_out8 , _io_out16 , _io_out32
global _io_load_eflags , _io_store_eflags

[SECTION .text]

_io_hlt:
hlt
ret

_io_cli:
cli
ret

_io_sti:
sti
ret

_io_stihlt:
sti
hlt
ret

_io_in8:
mov edx , [esp + 4]
mov eax, 0
in eax, dx
ret

_io_in16:
mov edx,[esp+4]
mov eax,0
in eax,dx
ret

_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 ax,[esp+8]
out dx,ax
ret

_io_out32:
mov edx,[esp+4]
mov eax,[esp+8]
out dx,eax
ret

_io_load_eflags:
pushfd ; push flags double word
pop eax
ret

_io_store_eflags:
mov eax,[esp+4]
push eax
popfd ; pop flags double word
ret

Draw a rectangle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void boxfill8(unsigned char * vram , int xsize , unsigned char c , int x0 , int y0, int x1 , int y1){
int x, y ;
for ( y = y0 ; y <= y1 ; y++){
for (x = x0 ; x <= x1 ; x++){
vram[y * xsize + x] = c;
}
}
}

#define COL8_FF0000 1
....

//in HariMain
boxfill8(0xa0000 , 320 , COL8_FF0000 , 20 , 20, 120,120)

qemu emulate

vmware

To use VMware, first add a floppy driver in hardware configuration(you can find an “add” button near the bottom of the window), then just boot from floppy, using the file haribote.img