终于可以开始用 C 来写代码了。

内核启动代码

#include "src/main.h"

const   char *VGA_BUFFER = (const char*)0x000b8000;// vga 显存开始地址

int kernel_entry()
{
	while (1)
	{
		main();
	}
	return 0;
}
//main.c

#include "stdio.h"
#include "def.h"

void print_logo()
{
	printf("LiteOS 1.0 (c) 2013-2017 dreamyouxi.com\n\n");
	printf("*     *  *****  *****  \n");
	printf("*          *    *         \n");
	printf("*     *    *    *****  \n");
	printf("*     *    *    *         \n");
	printf("****  *    *    *****   OS 1.0 \n");
}

int main()
{
	print_logo();


	flush();


	while (1)
	{

	}
	return 0;
}

由于没有标准库,printf 等标准库函数都需要自己实现。

VGA 显示模式

VGA 13h 显示模式下的显存首地址为 0x0b8000,向这块内存写数据即可输出到屏幕。

该模式下屏幕分辨率为 80(宽 x)× 25(高 y),每个字符占 2 字节:1 字节为字符本身,1 字节为颜色(16 色)。

颜色代码如下(格式:color 背景色 前景色,例如 fc 表示亮白背景 + 亮红前景):

  • 0 = 黑色     8 = 灰色
  • 1 = 蓝色     9 = 淡蓝色
  • 2 = 绿色     A = 淡绿色
  • 3 = 湖蓝色   B = 淡浅绿色
  • 4 = 红色     C = 淡红色
  • 5 = 紫色     D = 淡紫色
  • 6 = 黄色     E = 淡黄色
  • 7 = 白色     F = 亮白色

0x0f 表示黑背景 + 亮白字。VGA 还有其他显示模式,此处不展开。

实现 printf(stdio.c)

void printf(const char*str)
{
	current_std_out_offset += strcpy((void*)(STD_OUT + current_std_out_offset), (void*)str);
}

void flush()
{
	cmd_cls();//clear
	unsigned int i = 0, ii = 0;
	char* out = VGA_BUFFER;
	out = VGA_BUFFER;
	char* out_buffer = (char*)STD_OUT;
	for (i = 0, ii = 0; '\0' != out_buffer[ii] && ii < VGA_BUFFER_MAX_OFFSET; ii++)
	{// left-up is (0,0);
		if (out_buffer[ii] == '\n')
		{
			i = (i / (VGA_X_BUFFER_SIZE)+1) * VGA_X_BUFFER_SIZE;
			continue;
		}
		out[i++] = out_buffer[ii];
		out[i++] = 0x0f;

	}
	current_std_out_offset = 0;
}

基本思路是通过标准函数接口来输出,然后自行实现这些标准函数。这些函数以后也可以提供给可执行代码使用。

运行效果

生成后在 VM 中运行:

实模式下的内存地址范围: