Practice of "30 day self made operating system" 04 C language and screen display

04 C language and screen display practice

In the original text, the author has made great efforts to explain the knowledge of C language, which will not be covered here..

1. Display mode and memory

The content author of the previous day set the display of our operating system to VGA 320*200 8-bit palette mode, 8-bit means that we can use 256 colors, but in essence, VGA is RGB color mode, which requires 3 bytes to represent a complete color. We can only set the color number, which is a mapping of 8-bit to 24-bit color. The setting method will be introduced later.

And set the display resolution to 320 * 200, each pixel needs a byte (8 bits) to represent the color

In this mode, the address range of the video memory is 0xa0000 -0xaffff, but only 320 * 200 bytes are needed for a pixel to store a byte, but the video memory range is 64K larger than that of the stored pixel, and I don't know why..

2. Assembly for memory writing

_write_mem8: ; void write_mem8(int addr, int data);
    MOV ECX,[ESP+4] ; [ESP + 4]The address stored in is read in ECX
    MOV AL,[ESP+8] ; [ESP + 8]Data stored in, read it in AL
    MOV [ECX],AL
RET

Here is the 32-bit mode, so the registers we use are expansion registers. Here, the function parameters of C compiler are pushed from right to left, so we simply write a 32-bit data to the memory of the specified 32-bit address

3. Color number setting

As mentioned earlier, our display mode is VGA 8-bit palette mode, which requires you to specify different colors for different 256 color numbers. The author uses 16 colors to draw his operating system, as follows:

static unsigned char table_rgb[16 * 3] = {
	0x00, 0x00, 0x00,	/*  0:black */
	0xff, 0x00, 0x00,	/*  1:Liang Hong */
	0x00, 0xff, 0x00,	/*  2:Bright green */
	0xff, 0xff, 0x00,	/*  3:Bright yellow */
	0x00, 0x00, 0xff,	/*  4:Brilliant blue */
	0xff, 0x00, 0xff,	/*  5:Bright violet */
	0x00, 0xff, 0xff,	/*  6:Light brilliant blue */
	0xff, 0xff, 0xff,	/*  7:white */
	0xc6, 0xc6, 0xc6,	/*  8:Bright grey */
	0x84, 0x00, 0x00,	/*  9:Dull red */
	0x00, 0x84, 0x00,	/* 10:Dark green */
	0x84, 0x84, 0x00,	/* 11:Dark yellow */
	0x00, 0x00, 0x84,	/* 12:Dark blue */
	0x84, 0x00, 0x84,	/* 13:Dark purple */
	0x00, 0x84, 0x84,	/* 14:Light dark blue */
	0x84, 0x84, 0x84	/* 15:Dark grey */
};

At the same time, the author provides many functions to help write such as port:

void io_hlt(void); // Hover CPU before
void io_cli(void); // Interrupt identification bit reset
void io_out8(int port, int data);	// Output 8-bit data
int io_load_eflags(void);	// Returns the value of the representation register
void io_store_eflags(int eflags); // Using eflags overload to represent register

The assembly is realized as follows:

; naskfunc
; TAB=4

[FORMAT "WCOFF"]				; Mode of making target file	
[INSTRSET "i486p"]				; Use instructions up to 486
[BITS 32]						; 3 Machine language for making 32-bit mode
[FILE "naskfunc.nas"]			; file name

		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

The right IN OUT instructions IN the code are necessary instructions for the interaction between CPU and other input and output devices. IN reads data from the specified port, and OUT writes data. Note that the return values of functions IN assembly (compiled IN C language) are all through EAX registers

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

  1. First, mask interrupts (such as CLI) in a series of accesses.
  2. Write the palette number you want to set to 0x03c8, and then write it in the order of R, G, B
    0x03c9. If you want to continue to set the next palette, omit the palette number, and then follow the RGB
    Write 0x03c9 in sequence.
  3. If you want to read the status of the palette, first you need to write the palette number to 0x03c7, and then from the
    0x03c9 read 3 times. The order of reading is R, G, B. If you want to continue reading the next palette, the same as
    The sample also omits the palette number setting and reads in RGB order.
  4. If CLI is executed initially, STI is executed last

The corresponding C language code is as follows:

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);
/*Even if it is written in the same source file, if you want to use it before definition, you must declare it in advance. */
void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void HariMain(void)
{
	int i; /* Declare variables. Variable i is a 32-bit integer */
	char *p; /* Variable p is the address used by BYTE [...] */
	init_palette(); /* Set palette */
    p = (char *) 0xa0000; /* Designated address */
    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:black */
        0xff, 0x00, 0x00, /* 1:Bright red */
    	0x00, 0xff, 0x00, /* 2:Bright green */
        0xff, 0xff, 0x00, /* 3:Bright yellow */
        0x00, 0x00, 0xff, /* 4:Brilliant blue */
        0xff, 0x00, 0xff, /* 5:Bright violet */
        0x00, 0xff, 0xff, /* 6:Light brilliant blue */
        0xff, 0xff, 0xff, /* 7:white */
        0xc6, 0xc6, 0xc6, /* 8:Bright grey */
        0x84, 0x00, 0x00, /* 9:Dull red */
        0x00, 0x84, 0x00, /* 10:Dark green */
        0x84, 0x84, 0x00, /* 11:Dark yellow */
        0x00, 0x00, 0x84, /* 12:Dark blue */
        0x84, 0x00, 0x84, /* 13:Dark purple */
        0x00, 0x84, 0x84, /* 14:Light dark blue */
        0x84, 0x84, 0x84 /* 15:Dark grey */
	};
	set_palette(0, 15, table_rgb);
	return;
/* C The static char statement in the language can only be used for data, which is equivalent to the DB instruction in assembly */
} 
void set_palette(int start, int end, unsigned char *rgb)
{
    int i, eflags;
    eflags = io_load_eflags(); /* Record the value of the interrupt permission flag*/
    io_cli(); /* Set interrupt permission flag to 0, disable interrupt */
    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); /* Restore interrupt permission flag */
	return;
}

The renderings are as follows:

3. Draw rectangle

The picture coordinate system is the top left coordinate system (the top left corner is the vertex), so for the coordinate (x,y), we only need to use 0xa0000 + x + y * 320 as the corresponding address of the coordinate, so it is much easier to draw the rectangle

Draw the rectangle code as follows:

/*
vram: Corresponding display address 0xa0000
xsize: Corresponding width
c: Color number
 Upper left lower right coordinate
*/
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 renderings are as follows:

In the end, the author draws a simple interface, which is realized by drawing rectangles. That's not enough

39 original articles published, 143 praised, 110000 visitors+
Private letter follow

Keywords: C

Added by ungown_admin on Sun, 26 Jan 2020 18:29:27 +0200