"30 days self-made operating system" Exercise 04 C language and screen display

Exercise 04 C language and screen display

In the original author spent a lot of knowledge about the effort to explain the C language here is not to go into details. .

1. display mode and memory

The content of the previous day will be displayed to set the operating system for our VGA 320*200 8 位调色板model, 8 means that we can use 256 colors, but essentially Condition VGA or RGB mode, you need three bytes represent a full color, we only color can be provided, it is an 8-bit to 24-bit color map setting process described later.

And the resolution is set to be displayed 320*200, each pixel requires one byte (8 bits) to represent the color

Memory address range in this mode is 0xa0000 -0xaffff, but a pixel is stored only need one byte 320*200bytes, but the memory range is larger than 64K pixels stored, I do not know why. .

2. The compilation includes memory write

_write_mem8: ; void write_mem8(int addr, int data);
    MOV ECX,[ESP+4] ; [ESP + 4]中存放的是地址, 将其读入ECX
    MOV AL,[ESP+8] ; [ESP + 8]中存放的是数据, 将其读入AL
    MOV [ECX],AL
RET

Here is the 32-bit mode, so we are expanding the use of registers register, where C language compiler function parameters are pushed onto the stack from right to left, so here is simply put a 32-bit data is written to the specified 32-bit address memory to

3. Color settings

We mentioned earlier the display mode is VGA 8-bit palette mode, you need to specify their own different for different color number of 256 colors. The authors used 16 colors to draw his operating system, as follows:

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:暗灰 */
};

The author also provides a number of functions such as help write ports:

void io_hlt(void); // 之前出现过的悬停CPU
void io_cli(void); // 中断标识位清零
void io_out8(int port, int data);	// 输出8位数据
int io_load_eflags(void);	// 返回表示寄存器值
void io_store_eflags(int eflags); // 使用eflags重载表示寄存器

Its compilation to achieve the following:

; naskfunc
; TAB=4

[FORMAT "WCOFF"]				; 制作目标文件的模式	
[INSTRSET "i486p"]				; 使用到486为止的指令
[BITS 32]						; 3制作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:	; void io_hlt(void);
		HLT
		RET

_io_cli:	; void io_cli(void);
		CLI
		RET

_io_sti:	; void io_sti(void);
		STI
		RET

_io_stihlt:	; void io_stihlt(void);
		STI
		HLT
		RET

_io_in8:	; int io_in8(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AL,DX
		RET

_io_in16:	; int io_in16(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AX,DX
		RET

_io_in32:	; int io_in32(int port);
		MOV		EDX,[ESP+4]		; port
		IN		EAX,DX
		RET

_io_out8:	; void io_out8(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		AL,[ESP+8]		; data
		OUT		DX,AL
		RET

_io_out16:	; void io_out16(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,AX
		RET

_io_out32:	; void io_out32(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,EAX
		RET

_io_load_eflags:	; int io_load_eflags(void);
		PUSHFD		; PUSH EFLAGS 
		POP		EAX
		RET

_io_store_eflags:	; void io_store_eflags(int eflags);
		MOV		EAX,[ESP+4]
		PUSH	EAX
		POPFD		; POP EFLAGS 
		RET

Right code IN OUTinstructions, two instructions by the CPU and other necessary input and output devices to interact instruction INdesignated port read data from OUTthe write data, note compilation (the C compiler) is returned by the function value EAX register

Next step is to start to really set the color number, VGA palette mode setting process is as follows:

  1. First in a series of visits maskable interrupts (such as CLI).
  2. Setting the desired number of palette write 0x03c8, followed, in order R, G, B writes
    0x03c9. If you want to continue to set the next palette, the palette number is omitted, then in accordance with the RGB
    written on the line 0x03c9 sequence.
  3. If you want to read the current palette of the state, first of all to the palette numbers written 0x03c7, and from
    reading three times 0x03c9. Is sequentially read out the R, G, B. To continue the read a palette, the same
    sample is set to the palette number is omitted is read out in the order of RGB.
  4. If the initial implementation of the CLI, then the last to be executed STI

C language code corresponding to the following:

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; /* 声明变量。 变量i是32位整数型 */
	char *p; /* 变量p是BYTE [...]用的地址 */
	init_palette(); /* 设定调色板 */
    p = (char *) 0xa0000; /* 指定地址 */
    for (i = 0; i <= 0xffff; i++) {
    	p[i] = i & 0x0f;
	} 
    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;
/* C语言中的static char语句只能用于数据, 相当于汇编中的DB指令 */
} 
void set_palette(int start, int end, unsigned char *rgb)
{
    int i, eflags;
    eflags = io_load_eflags(); /* 记录中断许可标志的值*/
    io_cli(); /* 将中断许可标志置为0, 禁止中断 */
    io_out8(0x03c8, start);
    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;
}

The effect is as follows:

3. Draw a rectangle

Display screen coordinate system is the upper left coordinates (upper left corner point), so the coordinate (x,y)we just need to 0xa0000 + x + y * 320set coordinates for the corresponding address, that way is much easier to draw a rectangle

Drawing a rectangle code is as follows:

/*
vram: 对应显存地址 0xa0000
xsize: 对应宽
c: 颜色编号
左上-右下坐标
*/
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;
	}
	return;
}

The effect is as follows:

Finally, the authors draw a simple interface is achieved by drawing a rectangle here is not to say

Published 39 original articles · won praise 144 · views 110 000 +

Guess you like

Origin blog.csdn.net/qq_40953281/article/details/104089788