|
#2
2010-05-17 11:37
|
在这里的主要工作是整理代码与添加字符串与int型数值的输出函数。
在yc09中,编译后的二进制文件,函数似乎是按照在代码中的先后顺序排列的,然后再在末尾放置所有的变量。
在整个内核中,是以kernel.c文件为核心。在后面添加任何模块,都是在kernel.c文件的开头包含头文件,在kernel.c文件的末尾包含代码文件。如此,就可以保证内核的入口函数(main函数)一直是在最前面。
所有的头文件里,主要包含宏、数据结构定义、全局变量以及函数的声明等。
而对应的代码文件,则是具体的函数体。
下面是此次新添加或有过修改的代码,未作改动的文件将不再贴出。
code:kernel.h(新)

//文件:kernel.h
//功能:kernel头文件,放置需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-14
/* 宏定义区 */
#define ProtecAddr 0x7f00 //进入保护模式后的程序基址
//GDT 选择子
#define SelectorCode32 8*1 //指向32位段处代码段,可执行可读
#define SelectorVideo 8*2 //指向显存首地址
#define SelectorData32 8*3 //指向32位段处,这样,在程序中的变量就可以读写了
/* 数据结构与全局变量定义区 */
//GDT界限,注意,这个与boot.c中的GDT不同,从boot.c跳转过来后会立即载入这个新的GDT
DESCRIPTOR label_gdt[] =
{
// 段基址 段界限 属性
Descriptor(0, 0, 0),
Descriptor(ProtecAddr, 0xfffff, DA_CR | DA_32), //32位代码段,可执行可读
Descriptor(0xb8000, 0xffff, DA_DRW), //显存地址段,可读可写
Descriptor(ProtecAddr, 0xfffff, DA_DRW | DA_32), //令32位代码段的变量可以读写
};
#pragma pack(1)
struct GDT_PTR
{
t_16 size;
void *addr;
}GdtPtr = {sizeof(label_gdt), (char*)&label_gdt + ProtecAddr}; //段界限,基地址
#pragma pack()
int kernel_main();
//功能:kernel头文件,放置需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-14
/* 宏定义区 */
#define ProtecAddr 0x7f00 //进入保护模式后的程序基址
//GDT 选择子
#define SelectorCode32 8*1 //指向32位段处代码段,可执行可读
#define SelectorVideo 8*2 //指向显存首地址
#define SelectorData32 8*3 //指向32位段处,这样,在程序中的变量就可以读写了
/* 数据结构与全局变量定义区 */
//GDT界限,注意,这个与boot.c中的GDT不同,从boot.c跳转过来后会立即载入这个新的GDT
DESCRIPTOR label_gdt[] =
{
// 段基址 段界限 属性
Descriptor(0, 0, 0),
Descriptor(ProtecAddr, 0xfffff, DA_CR | DA_32), //32位代码段,可执行可读
Descriptor(0xb8000, 0xffff, DA_DRW), //显存地址段,可读可写
Descriptor(ProtecAddr, 0xfffff, DA_DRW | DA_32), //令32位代码段的变量可以读写
};
#pragma pack(1)
struct GDT_PTR
{
t_16 size;
void *addr;
}GdtPtr = {sizeof(label_gdt), (char*)&label_gdt + ProtecAddr}; //段界限,基地址
#pragma pack()
int kernel_main();
code:kernel.c(改)

//文件:kernel.c
//功能:内核程序,目前功能为测试print.c里的几个输出函数
//运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。
//作者:miao
//时间:2010-5-14
#define YCBIT 32 //告诉编译器,以32位格式编译程序
#define YCORG 0x0 //此值会对在编译时对变量函数等产生地址基址偏移量,简单起便,设置为0
#include "global.h"
#include "kernel.h"
#include "print.h"
//内核入口点
asm void main()
{
lgdt cs:GdtPtr //加载新的GDTR
mov eax, SelectorVideo
mov gs, ax //视频段选择子(目的)
mov eax, SelectorData32 //令32位代码段的变量(printPlace)可以读写
mov ds, ax
jmp kernel_main
}
int kernel_main()
{
int i;
//测试字符串输出函数
disp_str("this is default color string.\n");
for(i=0;i<=0x7f;i++)
{
disp_color_str("c ",i);
}
disp_str("\n");
for(i=0x80;i<=0xff;i++)
{
disp_color_str("c ",i);
}
disp_str("\n");
for(i=0;i<0x2f;i++)
disp_int(i);
disp_str("\n");
for(i=0xffff;i>0xffe0;i--)
disp_int(i);
while(1);
return 0;
}
#include "print.c"
//功能:内核程序,目前功能为测试print.c里的几个输出函数
//运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。
//作者:miao
//时间:2010-5-14
#define YCBIT 32 //告诉编译器,以32位格式编译程序
#define YCORG 0x0 //此值会对在编译时对变量函数等产生地址基址偏移量,简单起便,设置为0
#include "global.h"
#include "kernel.h"
#include "print.h"
//内核入口点
asm void main()
{
lgdt cs:GdtPtr //加载新的GDTR
mov eax, SelectorVideo
mov gs, ax //视频段选择子(目的)
mov eax, SelectorData32 //令32位代码段的变量(printPlace)可以读写
mov ds, ax
jmp kernel_main
}
int kernel_main()
{
int i;
//测试字符串输出函数
disp_str("this is default color string.\n");
for(i=0;i<=0x7f;i++)
{
disp_color_str("c ",i);
}
disp_str("\n");
for(i=0x80;i<=0xff;i++)
{
disp_color_str("c ",i);
}
disp_str("\n");
for(i=0;i<0x2f;i++)
disp_int(i);
disp_str("\n");
for(i=0xffff;i>0xffe0;i--)
disp_int(i);
while(1);
return 0;
}
#include "print.c"
code:print.h(新)

//文件:print.h
//功能:print头文件,放置需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-14
/* 数据结构与全局变量定义区 */
int disp_pos;//记录已经输出到屏幕哪里的坐标("光标")
/* 函数的声明区 */
void disp_str(char * info);//使用蓝底红字输出一个字符串
asm void disp_color_str(char * info, int color);//使用指定颜色输出一个字符串
void disp_int(int input);//以十六进制格式输出一个数
//文件:print.h
//功能:print头文件,放置需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-14
/* 数据结构与全局变量定义区 */
int disp_pos;//记录已经输出到屏幕哪里的坐标("光标")
/* 函数的声明区 */
void disp_str(char * info);//使用蓝底红字输出一个字符串
asm void disp_color_str(char * info, int color);//使用指定颜色输出一个字符串
void disp_int(int input);//以十六进制格式输出一个数
//功能:print头文件,放置需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-14
/* 数据结构与全局变量定义区 */
int disp_pos;//记录已经输出到屏幕哪里的坐标("光标")
/* 函数的声明区 */
void disp_str(char * info);//使用蓝底红字输出一个字符串
asm void disp_color_str(char * info, int color);//使用指定颜色输出一个字符串
void disp_int(int input);//以十六进制格式输出一个数
//文件:print.h
//功能:print头文件,放置需要用到的宏、数据结构定义、全局变量以及函数的声明等
//作者:miao
//时间:2010-5-14
/* 数据结构与全局变量定义区 */
int disp_pos;//记录已经输出到屏幕哪里的坐标("光标")
/* 函数的声明区 */
void disp_str(char * info);//使用蓝底红字输出一个字符串
asm void disp_color_str(char * info, int color);//使用指定颜色输出一个字符串
void disp_int(int input);//以十六进制格式输出一个数
code:print.c(新)

//文件:print.c
//功能:向屏幕输出字符的相关函数
//运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。
//作者:miao
//时间:2010-5-14
/* 屏幕颜色与字符的显示(两字节大小)
高字节 低字节
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
闪烁 R G B 高亮 R G B ASCII
背景颜色 字符颜色 字符
*/
void disp_str(char * info)
{
disp_color_str(info,0x14);//默认蓝底红字
}
asm void disp_color_str(char * info, int color)
{
push ebp
mov ebp, esp
mov esi, [ebp + 8] //info
mov edi, disp_pos //取上次输入完后的“光标”位置
mov ah, [ebp + 0xc] //color
dpc_1:
lodsb //从esi指向的源地址中逐一读取一个字符送入al中
test al, al //al是否为空
jz dpc_2 //为空(无字符串要输出),结束函数
cmp al, 0Ah //是回车吗?
jnz dpc_3 //不是换行符,跳到dpc_3直接输出字符
push eax //保存ah里的字符颜色信息
mov eax, edi //求出出下一行起始位置坐标
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop eax
jmp dpc_1
dpc_3:
mov gs:[edi], ax //将ax的信息放到显存显示出来
add edi, 2
jmp dpc_1
dpc_2:
mov disp_pos, edi //保存“光标”位置
pop ebp
ret
}
char *itoa(char *str, int num)//数字前面的 0 不被显示出来, 比如 0000B800 被显示成 0xB800
{
char *p = str;
char ch;
int i;
t_bool flag = FALSE;//标记是否将零输出,从高位起,若当前位不为0,标记为true,其后遇到0,都会输出
*p++ = '0';
*p++ = 'x';
if(num == 0) //为零,以0x0形式输出
*p++ = '0';
else
{
for(i=28;i>=0;i-=4)//从十六进制高位起,逐个转换为字符形式
{
ch = (num >> i) & 0xF;
if(flag || (ch > 0))
{
flag = TRUE;
ch += '0';
if(ch > '9') //为a,b,c,d,e,f
ch += 7;
*p++ = ch;
}
}
}
*p = 0;
return str;
}
//将数字转换为十六进制字符串显示出来
void disp_int(int num)
{
char output[16];
itoa(output, num);
disp_str(output);
}
//功能:向屏幕输出字符的相关函数
//运行:run.exe自动会编译boot.c与生成img并调用Bochs运行此程序。
//作者:miao
//时间:2010-5-14
/* 屏幕颜色与字符的显示(两字节大小)
高字节 低字节
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
闪烁 R G B 高亮 R G B ASCII
背景颜色 字符颜色 字符
*/
void disp_str(char * info)
{
disp_color_str(info,0x14);//默认蓝底红字
}
asm void disp_color_str(char * info, int color)
{
push ebp
mov ebp, esp
mov esi, [ebp + 8] //info
mov edi, disp_pos //取上次输入完后的“光标”位置
mov ah, [ebp + 0xc] //color
dpc_1:
lodsb //从esi指向的源地址中逐一读取一个字符送入al中
test al, al //al是否为空
jz dpc_2 //为空(无字符串要输出),结束函数
cmp al, 0Ah //是回车吗?
jnz dpc_3 //不是换行符,跳到dpc_3直接输出字符
push eax //保存ah里的字符颜色信息
mov eax, edi //求出出下一行起始位置坐标
mov bl, 160
div bl
and eax, 0FFh
inc eax
mov bl, 160
mul bl
mov edi, eax
pop eax
jmp dpc_1
dpc_3:
mov gs:[edi], ax //将ax的信息放到显存显示出来
add edi, 2
jmp dpc_1
dpc_2:
mov disp_pos, edi //保存“光标”位置
pop ebp
ret
}
char *itoa(char *str, int num)//数字前面的 0 不被显示出来, 比如 0000B800 被显示成 0xB800
{
char *p = str;
char ch;
int i;
t_bool flag = FALSE;//标记是否将零输出,从高位起,若当前位不为0,标记为true,其后遇到0,都会输出
*p++ = '0';
*p++ = 'x';
if(num == 0) //为零,以0x0形式输出
*p++ = '0';
else
{
for(i=28;i>=0;i-=4)//从十六进制高位起,逐个转换为字符形式
{
ch = (num >> i) & 0xF;
if(flag || (ch > 0))
{
flag = TRUE;
ch += '0';
if(ch > '9') //为a,b,c,d,e,f
ch += 7;
*p++ = ch;
}
}
}
*p = 0;
return str;
}
//将数字转换为十六进制字符串显示出来
void disp_int(int num)
{
char output[16];
itoa(output, num);
disp_str(output);
}