#2
chengstone2010-01-31 17:14
|
但即使是从头开始,也绝不会超过5分钟(不计下载一个17.6MB的编译器的时间)。
开始搭建操作系统编程实验环境前的一些废话:
无论是学习一门新的语言或是任何新的技术,搭建编程环境,一直是阻挡我们这些编程菜鸟的第一道难关。
经常可以在网上看到说自己弄一个星期甚至是十天半月还没将编程环境搞定的求助贴。
对于编写操作系统,阻碍着想要编写自己的操作系统的无数编程菜鸟的,主要有两个问题。
一、操作系统理论书籍无数,却缺少从零开始的入门资料。即使是minix的《操作系统设计与实现》或是一些讲解linux内核的外文书籍,对于像我这样的菜鸟来说依然如天书一样难懂。
二、一个简单方便易于修改测试的操作操作系统实验平台。也许对于长期在linux下的程序员来说,这个问题并不是很大。但是在中国,大多数是像我这样被windows盗版毒害而无法脱身的编程菜鸟。想要学习编写操作系统,就意味着要抛弃windows下的傻瓜化的环境,需要重新去学习linux下的shell、make、vi、gcc等等。
对于第一个问题,于源写的《自己动手写操作系统》是中国广大初学者的福音(目前已经有第二版了),终于其他的参考书籍,因为我没有看过,就不再妄言什么了。
对于第二个问题,说真的,我学习《自己动手写操作系统》到第5章后就是扑在这里了。也许是我孤陋寡闻,似乎编写操作系统就很难离开linux的帮助,更不用说纯粹在windows下编写与调试(虚拟机安装linux的不算)。
决定了编程平台,编程语言与编译器的选择也是一个问题。一般而言,需要汇编与C语言结合编写。C语言就不提了,对于汇编,我见过masm、tasm、nasm都有人选。两种语言的混合使用与项目管理,在Linux下有makefile帮助,windows下,只能说是我孤陋寡闻了。
下面介绍我现在使用操作系统开发环境,主要是一款支持汇编与c语言混合编程的编译器yc90,以及必不可少的虚拟机bochs。至于编辑器,虽然yc90自带了一个,但是我用着不习惯,开始我用vs2005,现在主要用notepad++。
废话说完,若是在使用windowsxp的读者,就按照下面步骤快速搭建一个实验环境体验一下吧。
1.下载yc90:请到CSDN上杨晓兵的博客上下载。地址:http://blog.(下载链接在博客的左下角:yc09.rar 17.6MB)
2.解压yc09.rar 中YC09.exe,点击运行安装(主要是二次解压一个文件,解压后的文件大小为68MB,大约需要1分钟左右。)
至此,实验环境算是勉强搭建好了。性急的朋友可以单击桌面产生的YC09快捷方式打开yc90编辑器,然后打开安装目录YC09\example下的tinix.c(例如C:\YC09\example\tinix.c),运行tinix 微型操作系统源代码(tinix.cpp 作者于渊)
但是,这样还不是很方便。所以我是新建一个实验文件夹,将YC09\example下的bochs.exe、BIOS-bochs-latest、VGABIOS-elpin-2.40、x11-pc-us.map四个文件拷贝到实验文件夹内。
然后自己编写一个run.c(功能与tinix.c相同,我称之为宿主程序)与操作系统实验代码。用YC09编译生产run.exe后,运行run.exe就会自动编译编写的实验代码并且生成软盘镜像文件img与调用bochs.exe运行。我写的run.c与原作者写的tinix.c主要区别在于:运行run.exe后,想要修改操作系统实验代码并且再次运行查看效果,只需要在run.exe的控制台上点击回车就行了(也许你需要多点几次)。
至于编程最重要的调试和反汇编,我是安装Bochs-2.4.2,使用bochsdbg.exe。关于调试与反汇编的问题我就不在这里罗嗦了。
以下是搭建实验环境可能需要用到的代码。
code:run.c
程序代码:
//文件:run.c
//功能:编译操作系统的实验代码并创建软盘img,生成bochs配置文件,运行bochs。
//说明:imgBuffer(镜像缓冲区)大小为1.4MB,前512字节为引导扇区,
// 第510、511字节放引导程序结束标记:0x55、0xaa。
// 在主函数里根据需要编译各个16位32位代码,然后根据需要放到合适的地方。
// 在这个版本中,编译16位代码boot.c将其放到处引导扇区起始。
//运行:请使用yc00编译器编译运行run.c。在控制台点击回车会重新编译运行实验代码。
//作者:miao
//时间:2010-1-30
#define FDISK_SIZE 1474560 //镜像大小:1.4MB
//虚拟机设置
char *pmSrc =
"megs: 32 \n"
"romimage: file=BIOS-bochs-latest, address=0xf0000 \n"
"vgaromimage: VGABIOS-elpin-2.40 \n"
"floppya: 1_44=boot.img, status=inserted \n"
"boot: a \n"
"log: boot.log \n"
"mouse: enabled=0 \n"
"keyboard_mapping: enabled=1, map=x11-pc-us.map \n";
//编译指定代码文件并放入镜像指定位置
//filename:要编译的文件名 imgBuffer:保存到的镜像缓冲区
//startIndex:指定起始位置 limitSize:编译后程序限定大小
int CompileFile(char *fileName, byte *imgBuffer, int startIndex, int limitSize)
{
char *tempBuffer; //保存部分引导程序的临时缓冲区
//编译此部分引导程序,结果放到tempBuffer中
int length = YC_CompileCpp(&tempBuffer, fileName, 0, 0);
if(length <= 0 || length > limitSize)
{
printf("文件: %s 中存在一些语法错误或文件过大(超过%d字节):%d字节\n", fileName,limitSize,length);
return 1;
}
printf("文件: %s 编译成功,大小为:%d字节。\n", fileName, length);
//将1此部分引导程序放到镜像引导扇区缓冲区指定起始位置
memcpy(imgBuffer + startIndex, tempBuffer, length);
free(tempBuffer);
return 0;
}
int main(int argc, char **argv)
{
char * filePath = argv[0]; //当前文件夹路径
char fileName[MAX_PATH]; //用于缓存各个文件名
//将可执行文件的完整路径去掉文件名,保留文件夹路径
for( int i = strlen(filePath);filePath[i] != '\\';i--)
filePath[i] = '\0';
byte *imgBuffer = new byte[FDISK_SIZE];//镜像缓冲区
_start:
//编译boot.c引导测试程序并放在引导扇区起始处,编译后的程序必须小于511字节
if(CompileFile("boot.c", imgBuffer, 0, 511))
goto _restart;
//0000H-01FFH 为FAT引导扇区[第0扇区] 以55 AA标志结束 长度为200H(512)字节
imgBuffer[510] = 0x55;
imgBuffer[511] = 0xaa;//标记软盘引导结尾
//创建操作系统镜像boot.img
if(YC_writefile("boot.img", imgBuffer, FDISK_SIZE) != FDISK_SIZE)
{
printf("写: %s 文件过程中出现错误。\r\n", fileName);
goto _restart;
}
printf("\n%s 创建成功。\n", fileName);
//生成操作系统虚拟机配置文件boot.src
YC_writefile("boot.src", pmSrc, strlen(pmSrc));
//运行虚拟机
YC_WinExec(strcat(strcpy(fileName, filePath), "bochs.exe"), "-q -f boot.src");
_restart:
printf("\n点击回车重新编译运行!\n\n");
while(getchar() != '\n');
goto _start;
return 0;
}
code:boot.c//功能:编译操作系统的实验代码并创建软盘img,生成bochs配置文件,运行bochs。
//说明:imgBuffer(镜像缓冲区)大小为1.4MB,前512字节为引导扇区,
// 第510、511字节放引导程序结束标记:0x55、0xaa。
// 在主函数里根据需要编译各个16位32位代码,然后根据需要放到合适的地方。
// 在这个版本中,编译16位代码boot.c将其放到处引导扇区起始。
//运行:请使用yc00编译器编译运行run.c。在控制台点击回车会重新编译运行实验代码。
//作者:miao
//时间:2010-1-30
#define FDISK_SIZE 1474560 //镜像大小:1.4MB
//虚拟机设置
char *pmSrc =
"megs: 32 \n"
"romimage: file=BIOS-bochs-latest, address=0xf0000 \n"
"vgaromimage: VGABIOS-elpin-2.40 \n"
"floppya: 1_44=boot.img, status=inserted \n"
"boot: a \n"
"log: boot.log \n"
"mouse: enabled=0 \n"
"keyboard_mapping: enabled=1, map=x11-pc-us.map \n";
//编译指定代码文件并放入镜像指定位置
//filename:要编译的文件名 imgBuffer:保存到的镜像缓冲区
//startIndex:指定起始位置 limitSize:编译后程序限定大小
int CompileFile(char *fileName, byte *imgBuffer, int startIndex, int limitSize)
{
char *tempBuffer; //保存部分引导程序的临时缓冲区
//编译此部分引导程序,结果放到tempBuffer中
int length = YC_CompileCpp(&tempBuffer, fileName, 0, 0);
if(length <= 0 || length > limitSize)
{
printf("文件: %s 中存在一些语法错误或文件过大(超过%d字节):%d字节\n", fileName,limitSize,length);
return 1;
}
printf("文件: %s 编译成功,大小为:%d字节。\n", fileName, length);
//将1此部分引导程序放到镜像引导扇区缓冲区指定起始位置
memcpy(imgBuffer + startIndex, tempBuffer, length);
free(tempBuffer);
return 0;
}
int main(int argc, char **argv)
{
char * filePath = argv[0]; //当前文件夹路径
char fileName[MAX_PATH]; //用于缓存各个文件名
//将可执行文件的完整路径去掉文件名,保留文件夹路径
for( int i = strlen(filePath);filePath[i] != '\\';i--)
filePath[i] = '\0';
byte *imgBuffer = new byte[FDISK_SIZE];//镜像缓冲区
_start:
//编译boot.c引导测试程序并放在引导扇区起始处,编译后的程序必须小于511字节
if(CompileFile("boot.c", imgBuffer, 0, 511))
goto _restart;
//0000H-01FFH 为FAT引导扇区[第0扇区] 以55 AA标志结束 长度为200H(512)字节
imgBuffer[510] = 0x55;
imgBuffer[511] = 0xaa;//标记软盘引导结尾
//创建操作系统镜像boot.img
if(YC_writefile("boot.img", imgBuffer, FDISK_SIZE) != FDISK_SIZE)
{
printf("写: %s 文件过程中出现错误。\r\n", fileName);
goto _restart;
}
printf("\n%s 创建成功。\n", fileName);
//生成操作系统虚拟机配置文件boot.src
YC_writefile("boot.src", pmSrc, strlen(pmSrc));
//运行虚拟机
YC_WinExec(strcat(strcpy(fileName, filePath), "bochs.exe"), "-q -f boot.src");
_restart:
printf("\n点击回车重新编译运行!\n\n");
while(getchar() != '\n');
goto _start;
return 0;
}
程序代码:
//文件:boot.c
//功能:处于引导扇区的一个显示一个字符串的简单程序。
//运行:run.exe自动会编译boo.c与生成img并调用Bochs运行此程序。
//提示:请先用yc90编译run.c文件,生成run.exe程序。
// 之后修改boot.c代码,可直接运行run.exe查看效果。
// 只要不关闭run.exe操作台程序,修改boot.c代码并保存后,
// 在run.exe控制台点击回车,就会重修自动编译boot.c并运行虚拟机。
//作者:miao
//时间:2010-1-30
#define YCBIT 16 //告诉编译器,以16位格式编译程序
#define YCORG 7c00h //告诉编译器,在7c00处加载程序
#define MsgLngth 12 //串长度
char Msg[] = "Hello, Miao!";
asm void main()
{
mov ax, cs
mov ds, ax
mov es, ax
; 清屏
mov ah, 06h ; 屏幕初始化或上卷
mov aL, 00h ; AH = 6, AL = 0h
mov bx, 01111h ; 设置底色为蓝色
mov cx, 0 ; 左上角开始: (0, 0)
mov dl, 4fh ; 到第x列
mov dh, 1fh ; 到第x行
int 10h ; 显示中断
; 显示字符串
mov ax,&Msg
mov bp,ax ;es:bp=串地址
mov ah, 13h ; AH:13显示字符串
mov al, 1h ; AH = 13, AL = 01h
mov bx, 0014h ; 页号为0(BH = 0) 蓝底红字(BL = 14h)
mov cx, MsgLngth ; CX = 串长度
mov dl, 00h ; 起始列
mov dh, 00h ; 起始行
int 10h ; 显示中断
}
对于菜鸟来说,运行某个大大的代码看看效果,再修改几个参数,试探运行看看,甚至是设置一些断点,查看内存状态什么的,如此重复,是学习的主要方式。我使用的这个操作操作系统编程实验环境完全满足这个要求,甚至比我用FlashDevelop写flash程序还要方便许多。//功能:处于引导扇区的一个显示一个字符串的简单程序。
//运行:run.exe自动会编译boo.c与生成img并调用Bochs运行此程序。
//提示:请先用yc90编译run.c文件,生成run.exe程序。
// 之后修改boot.c代码,可直接运行run.exe查看效果。
// 只要不关闭run.exe操作台程序,修改boot.c代码并保存后,
// 在run.exe控制台点击回车,就会重修自动编译boot.c并运行虚拟机。
//作者:miao
//时间:2010-1-30
#define YCBIT 16 //告诉编译器,以16位格式编译程序
#define YCORG 7c00h //告诉编译器,在7c00处加载程序
#define MsgLngth 12 //串长度
char Msg[] = "Hello, Miao!";
asm void main()
{
mov ax, cs
mov ds, ax
mov es, ax
; 清屏
mov ah, 06h ; 屏幕初始化或上卷
mov aL, 00h ; AH = 6, AL = 0h
mov bx, 01111h ; 设置底色为蓝色
mov cx, 0 ; 左上角开始: (0, 0)
mov dl, 4fh ; 到第x列
mov dh, 1fh ; 到第x行
int 10h ; 显示中断
; 显示字符串
mov ax,&Msg
mov bp,ax ;es:bp=串地址
mov ah, 13h ; AH:13显示字符串
mov al, 1h ; AH = 13, AL = 01h
mov bx, 0014h ; 页号为0(BH = 0) 蓝底红字(BL = 14h)
mov cx, MsgLngth ; CX = 串长度
mov dl, 00h ; 起始列
mov dh, 00h ; 起始行
int 10h ; 显示中断
}
最后提一下一下,YC90中附带附带了大量源代码。
tinix 微型操作系统源代码(tinix.cpp 作者于渊)
lua 5.1.2 源代码
ruby 1.8.6 源代码
basic 源代码
flash4.0 播放器源代码
llinux 0.11 起动部分源代码(其它部分需花不少时间来移植到YC, 有兴趣者可做这个工作)
mpeg 解码器源代码(mpg.cpp 作者不详)
mpeg 编码器源代码(mpge.cpp 作者不详)
三维游戏引擎源代码(OpenGL)(sword.cpp 作者WWBOSS)
赛车游戏源代码raceX.cpp(作者不详)
中国象棋源代码(作者陶善文)
五子棋源代码(作者不详)
俄罗斯方块源代码(作者不详)
三维台球(OpenGL)源代码(作者不详)
射击、爆炸游戏(OpenGL)源代码(作者不详)
UFO游戏源代码(作者不详)
……