做一个有基本printf和clearscreen函数的简单c内核

该教程演示了如何制作一个简单的内核。让我们从例子文件kernel_start.asm的开始进入内核。
[BITS 32]
[global start]
[extern _k_main] ; _k_main c 程序里
start:
call _k_main
cli ; 禁止中断
hlt ; 暂停 cpu
 
这些是32位的代码([BITS 32]表示)调用k_main函数,这个函数的定义在一个C的文件kernel.c里。令人疑惑的是为什么在c文件里它是k_main而在汇编文件里它是_k_main。这是因为c/c++的编译器在c/c++的函数前面加上了一个下划线(_),除非把它连接到一个ELF文件。ELF不需要这个下划线。一旦k_main被调用,指令cli就被执行。Cli关闭中断(虽然在本例中没有中断)。然后,hlt被执行停止cpu的继续运行。可以使用jmp $来代替这个指令,但是它会占用大量的cpu时间而导致cpu过热。注意,hlt指令可以使cpu能被中断唤醒。这就是为什么要在hlt之前禁止中断,为的是让cpu完全的停止。
 
现在来到kernel.c的开始位置看一看定义和函数的原型。
 
#define WHITE_TXT 0x07 // 黑底白字
void k_clear_screen();
unsigned int k_printf(char *message, unsigned int line);
void update_cursor(int row, int col);
 
除了#define WHITE_TXT 0X07之外没有什么特别的。稍后在回来,记住这个里。
 
现在看到k_main函数。
 
k_main() // 象在一般 c 程序里的 main 一样
{
k_clear_screen();
k_printf("Hi!/nHow's this for a starter OS?", 0);
};
 
k_main是一个指向内核的入口。我们在kernel_start.asm文件里调用这个函数。
k_clear_screen 清除屏幕。 k_printf(“Hi!/nHow’s this for a starter OS?”,0); 显示该字符:
Hi!
How’s this for a starter OS?
 
在视频内存的第一行开始(0是第一行,1是第二,2是第三,如此类推)。符号/n象c/c++里的printf函数一个指定一新行。
 
在保护模式下,不能调用bios中断来清屏,我们不得不直接写视频内存。
 
void k_clear_screen() // 清除全部的文本屏幕
{
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
while(i < (80*25*2))
{
vidmem[i]=' ';
i++;
vidmem[i]=WHITE_TXT;
i++;
};
};
 
在上面的函数中,指针vidmem指向0xb8000是保护模式下视频内存的起始地址。定义该指针为char为的是一次可以向视频内存写一个字节。X86的文本模式是80x25个字符。每一个字符需要两个字节。第一个字节是字符内容,第二个是属性控制颜色和闪烁。所以在访问整个视频内存的时候要用80*25*2。Vidmem[I]=’ ‘;是写入一个空格到视频内存(I代表位置)。把I加一, i++;取得下一个视频位置(属性位),把0x07写入。0x07表示一个黑底白字,无闪烁的文本。
 
现在看看k_printf函数!
 
unsigned int k_printf(char *message, unsigned int line) // the message and then the line #
{
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
i=(line*80*2);
while(*message!=0)
{
if(*message=='/n') // check for a new line
{
line++;
i=(line*80*2);
*message++;
} else {
vidmem[i]=*message;
*message++;
i++;
vidmem[i]=WHITE_TXT;
i++;
};
};
return(1);
};
 
k_printf函数和k_clear_screen函数类似。While(*message!=0)循环搜索传入函数字符串的结尾。If(*message == ‘/n’)检查字符串的下一个字符是不是一个新行。如果是,则在line加一,在/n后面的字符将会下一行。如果不是新行(/n),那么就把它放入视频内存并设置属性位0x07。
 
编译内核
 
首先,要下在一个内核源代码。还需要一个汇编编译器(nasm),c语言编译器(DJGPP或者gcc),和一个连接器(LD)。
 
现在,到最靠近连接器文件的顶端,看到这样一行:
.text 0x100000
16进制数表示内核要被载入内存的位置。这里是1MB。
 
首先编译我们的”平底锅”汇编代码文件:
 
nasm -f aout kernel_start.asm -o ks.o
 
把kernel_start.asm文件编译成aout格式的ks.o文件,现在是我们的c文件:
 
gcc -c kernel.c -o kernel.o
 
下一步也就是最后一步是连接ks.o和kernel.o文件到一起。在此,我们要把它用link.ld脚本文件连接到二进制文件里。用下面的命令:
 
ld -T link.ld -o kernel.bin ks.o kernel.o
 
ks.o首先要被连接,否则内核不会正常工作。内核是kernel.bin,并且将要被bootsector/loader运行,设置成保护模式允许A20的使用。
 
结论
一个基本的内核就完成了。你可能想要一个更好的k_printf函数,我们的示例非常简单而且不能处理%s,%d,%c的一些字符。但是已经可以使我们遵循这样的方法继续作下去了。
 
This tutorial was written by Joachim Nock and K.J.
Updated September 13, 2002 by K.J.
 
翻译:flyback 2004/10/2,http://blog.csdn.net/flyback
fly-back@163.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值