一个可运行操作系统内核的平台搭建例子
这里提供一个可以运行的操作系统内核的平台搭建例子,方便初学者学习,高手们就可以无视了。这个是我刚学内核编程时写的,先后看了谢煜波的文章,《自己动手做操作系统》,赵炯博士的《linux 0.12 内核代码分析》,还有《系统实验教程:核心技术与编程实例》这几本书。到现在家里还摆放了《莱昂式》、《Linux内核2.4版源代码分析大全》、《操作系统设计与实现(第一版)》、《LINUX情景分析》、《Linux2.6内核源代码分析》等书,学习操作系统任重而道远,发表这个不成熟的内核例子,希望广大的内核开发初学者们能够获得一些经验吧。
现在简单介绍一下这个实例,我主要是学习了赵炯博士的内核解释并且参照了LINUX 0.12内核来完成的内核编程,所以理论上这是一个字符型界面的可以理解成DOS的内核。不过在实现上,我并非采用了LINUX 0.12的使用SHELL的模式,而是通过一个叫做COMMAND的进程来实现的,感觉上有点像DOS内核的方式,具体的代码在main.c当中。
要生成并运行本内核程序,需要做一些小小的准备,本人未按照赵炯博士的方式进行实现,如果有人在学习《linux 0.12 内核代码分析》而不能够搭建出开发平台的话,不妨试试这个方法。
本方法并不是唯一的选择,只要能搭建出开发、编译平台就可以。
为了模拟运行操作系统的硬件,首先需要安装虚拟机软件,VM、VPC或者BOCHS任选,在这里我使用的是BOCHS。然后我们还需要创建一个磁盘映像文件,相当于在机箱中安装的硬盘一样用来存放OS内核,以启动操作系统。在安装BOCHS软件后,BOCHS系统会自带一个Image生成工具bximage.exe,利用它可以制作软盘和硬盘的空Image文件。这里我制作的是一个256M的磁盘映像文件,具体创建方法很简单,运行之后输入hd表示创建的是硬盘映像,然后选择默认值flat。然后输入磁盘容量256,程序会显示对应的硬盘参数信息,磁道数、磁头数和每磁道扇区数,这些信息一定要保存下来,以后会用到,最后要求输入一个该映像文件的名称。这样一个硬盘的映像文件就创建好了。
第二步呢,当然是给这个“硬盘”格式化了,通常我们会将格式化程序和OS安装程序组合在一起,在这里我分开来做了。现在利用BOCHS将我们创建的硬盘映像文件设置为第二硬盘,编辑bochsrc.bxrc文件,在ata0-master下一行加入我们的硬盘Image文件的配置参数行, ata0-slave:type=disk,path=硬盘映像文件的路径,cylinders=,heads=,spt=
这里最后三项填写我们创建映像文件时我们记下的硬盘参数信息,spt就是sectors per track。我们可以用其他任意的系统来引导,然后通过命令格式化第二硬盘。这里我们使用的是SLS Linux,下载地址如下:http://www.
SLS Linux启动之后,利用fdisk /dev/hdb命令将第二硬盘分成两个区,每个都是128M。第一分区格式化为Old minix格式。第二分区可以格式化成Old Minix格式,也可以是Linux Swap格式,其实都无所谓,因为以后我们会利用程序修改第二分区的分区表信息。
哦了,现在虚拟机有了,虚拟硬盘也有了,我们只需要把内核程序有规律的放入磁盘镜像当中就可以了。至于怎么才算有规律,这里需要一些方法了。第一件事情,要把引导程序写进磁盘的第一个扇区中。我们知道操作系统总是从磁盘0柱0道1扇区开始运行的,也就是只有512字节的引导程序,当然,实际上并没有那么多字节,里面还有4个分区的分区表信息。所以这个程序要求用尽量少的代码完成引导的工作。至于引导程序怎么写,这里先不做说明,大家可以在文章后面提供的下载地址中下载到源程序。
现在假设我们的引导程序写完了,然后编译出了可执行程序。这步很简单,只要把引导程序读出,然后覆盖磁盘镜像文件的前512字节就可以了。记住,是覆盖,明白什么意思了吧。这需要我们编写一个应用程序来辅助完成这个工作。这个代码应该不用我来帮您写吧:-)
当然,这里面还有一个保护磁盘分区表信息的步骤,以免破坏了我们设置好的磁盘分区的信息。
这里有件事情需要事先就要规划好,就是内核文件的存放安排以及内存的安排。不同的内核可能有不同的设计,我选择的是BOOT引导LOADER,然后加载OS内核的方式。所以现在就应该设计LOADER程序在磁盘中的存放以及在内存中的存放。首先我给出内存的大致安排:
|------------------|
| |
| 。 |
| 。 |
| 。 |
| |
|------------------|
| 显示器信息 |
| 内存大小 |
| 硬盘参数 | 9000:7C00H
|------------------|
| 。 |
| 。 |
|------------------|
| LOADER | 9000:0000H
|------------------|
| OS | 1000:0000H 这个位置如果内核太大的话,可能就不适合了,可以另外选择。
|------------------|
| 。 |
| 。 |
|------------------|
| BOOT | 0000:7C00H
|------------------|
| 中断向量 |
| BIOS数据 |
|------------------| 0000:0000H
剩下来就是第二件事了,安排LOADER程序在磁盘镜像中的位置。我的选择是将它放在磁盘的第1K开始的位置上,所以仍然需要写一个应用程序辅助完成。
代码如下:
#include<stdio.h>
#include<stdlib.h>
void main(int argc,char *argv[])
{
FILE *fp,*fp2;
unsigned long pos;
unsigned char tmp;
if(argc>1)
{
fp=fopen(argv[1],"rb+");
fp2=fopen(argv[2],"rb+");
pos=atol(argv[3]);
fseek(fp2,pos,SEEK_SET);
while(!feof(fp))
{
fread(&tmp,sizeof(char),1,fp);
fwrite(&tmp,sizeof(char),1,fp2);
}
fclose(fp);
fclose(fp2);
}
else
{
printf("CMD:write_pos read_filename write_filename write_position");
} /*程序名 待读文件名 待写文件名 待写入的位置*/
}
这样设计以后可以将任何程序覆盖任意的位置了。所以在使用时,待写入的位置就是1024。
现在我们要做的就是最重要的一件事了,就是开始编写内核程序。这是一个很庞大的过程,需要很多部分的设计与各部分的分步实现。这里我不讨论如何编写内核,只说如何将编写好的内核通过我们的平台运行起来。
首先我先提供一下我的磁盘映像里面的分区表信息和两个超级块信息,这两部分信息仅供参考。在这个地方我写了两个应用程序帮助理解每个字节的含义。下面是我以前保存的信息:
分区表:
00 01 01 00 80 0F 7F 02 3F 00 00 00 91 FB 03 00
00 00 41 03 80 0F 7F 7F D0 FB 03 00 30 EC 01 00
引导标志:0
分区起始磁头号:1
当前柱面中扇区号:1
分区起始柱面号:0
分区类型字节:80
分区结束处磁头号:15
分区结束当前柱面中扇区号:63
分区结束柱面号:258
分区起始物理扇区号:63
分区占用的扇区数:261009
引导标志:0
分区起始磁头号:0
当前柱面中扇区号:1
分区起始柱面号:259
分区类型字节:80
分区结束处磁头号:15
分区结束当前柱面中扇区号:63
分区结束柱面号:383
分区起始物理扇区号:261072
分区占用的扇区数:126000
分区表信息决定了每个分区的起始扇区号和占用总扇区数,可以确定内核能够控制的磁盘准确位置。第一个分区自然就是主分区,第二个用作虚拟内存,当然你也可以用作不同的安排。
下面提供获取上述字节信息的源程序:
#include<stdio.h>
struct dir
{
unsigned short inode;
char name[14];
};
struct partition
{
int boot_ind,head,sector,cyl,sys_ind,end_head,end_sector,end_cyl;
long start_sect,nr_sects;
};
void do_put(partition *p)
{
printf("\n\n\n 引导标志:%x\n",p->boot_ind);
printf(" 分区起始磁头号:%d\n",p->head);
printf(" 当前柱面中扇区号:%d\n",p->sector&0x3f);
printf(" 分区起始柱面号:%d\n",(p->sector&0xc0)<<2|p->cyl);
printf(" 分区类型字节:%x\n",p->sys_ind);
printf(" 分区结束处磁头号:%d\n",p->end_head);
printf("分区结束当前柱面中扇区号:%d\n",p->end_sector&0x3f);
printf(" 分区结束柱面号:%d\n",(p->end_sector&0xc0)<<2|p->end_cyl);
printf(" 分区起始物理扇区号:%ld\n",p->start_sect);
printf(" 分区占用的扇区数:%ld\n",p->nr_sects);
}
void do_write(partition *p,FILE *fp)
{
fprintf(fp,"\n\n\n 引导标志:%x\n",p->boot_ind);
fprintf(fp," 分区起始磁头号:%d\n",p->head);
fprintf(fp," 当前柱面中扇区号:%d\n",p->sector&0x3f);
fprintf(fp," 分区起始柱面号:%d\n",(p->sector&0xc0)<<2|p->cyl);
fprintf(fp," 分区类型字节:%x\n",p->sys_ind);
fprintf(fp," 分区结束处磁头号:%d\n",p->end_head);
fprintf(fp,"分区结束当前柱面中扇区号:%d\n",p->end_sector&0x3f);
fprintf(fp," 分区结束柱面号:%d\n",(p->end_sector&0xc0)<<2|p->end_cyl);
fprintf(fp," 分区起始物理扇区号:%ld\n",p->start_sect);
fprintf(fp," 分区占用的扇区数:%ld\n",p->nr_sects);
}
void do_read(char *argv[],partition *p)
{
FILE *fp,*fp2;
int i,j,a,k;
int n[4];
fp2=fopen("c:\\partition.txt","w");
fp=fopen(argv[1],"r");
fscanf(fp,"%d",&k);
for(j=0;j<k;j++)
{
fscanf(fp,"%x",&p->boot_ind);
fscanf(fp,"%x",&p->head);
fscanf(fp,"%x",&p->sector);
fscanf(fp,"%x",&p->cyl);
fscanf(fp,"%x",&p->sys_ind);
fscanf(fp,"%x",&p->end_head);
fscanf(fp,"%x",&p->end_sector);
fscanf(fp,"%x",&p->end_cyl);
for(i=0;i<4;i++)
fscanf(fp,"%x",&n[i]);
p->start_sect=0;
p->start_sect=p->start_sect|n[0]|(n[1]<<8)|(n[2]<<16)|(n[3]<<24);
for(i=0;i<4;i++)
fscanf(fp,"%x",&n[i]);
p->nr_sects=0;
p->nr_sects=p->nr_sects|n[0]|(n[1]<<8)|(n[2]<<16)|(n[3]<<24);
do_put(p);
do_write(p,fp2);
}
fclose(fp);
fclose(fp2);
}
void main(int argc,char *argv[])
{
partition p;
if(argc>1)
{
do_read(argv,&p);
getchar();
}
}
使用方法为:建立一个文本文件,内容为16字节的分区表信息,每字节(两位16进制)一组,排成一行作为一个分区信息,若有多个分区信息则每分区另起一行,如00 01 01 00 80 0F 7F 02 3F 00 00 00 91 FB 03 00
这样就可以保存了,然后将这个文件的路径作为参数传递给上面的可执行文件即可,该程序会在C盘根目录下建立一个叫做partition.txt的文件保存分析后的结果。
超级块:
55 53 00 FA 03 00 08 00 A8 02 00 00 00 1C 08 10 7F 13
00 00 18 f6 04 00 00 80 03 00 00 00 00 1c 08 10 13 14
i节点数:21333
逻辑块数:64000
i节点位图所占块数:3
逻辑块位图所占块数:8
数据区中第一个逻辑块块号:680
LOG:0
最大文件长度:268966912
文件系统魔数:0x137f
i节点数:0
逻辑块数:63000
i节点位图所占块数:4
逻辑块位图所占块数:32768
数据区中第一个逻辑块块号:6
LOG:0
最大文件长度:268966912
文件系统魔数:0x1413
第二个超级块我只改了一点,因为超级块在内核中起到很重要的作用,它确定了每个分区数据区的起始块号以及各位图所占的块数等信息。这里面我主要说第二个,第二个看起来可能有些奇怪。我们看最后两个字节,也就是魔数为0x1413,这个没有任何意义,我瞎写的,你也可以默认它为0x137f,或者改成你想要的。第二个超级块中的数据对于虚拟内存部分起作用,可以根据你的需求任意设置。
下面提供获取上述字节信息的源程序:
#include<stdio.h>
#define NR_PART1 0x1be
#define NR_PART2 0x1ce
#define NR_PART3 0x1de
#define NR_PART4 0x1ee
#define KB 1024
#define SECTOR_POS(X) ((X)*512)
struct dir
{
unsigned short inode;
char name[14];
};
struct superblock
{
unsigned short inodes;
unsigned short blocks;
unsigned short imap_blocks;
unsigned short zmap_blocks;
unsigned short firstdatablock;
unsigned short zero;
unsigned long file_maxsize;
unsigned short magic;
};
struct partition_mem
{
int boot_ind,head,sector,cyl,sys_ind,end_head,end_sector,end_cyl;
long start_sect,nr_sects;
};
struct partition
{
char boot_ind,head,sector,cyl,sys_ind,end_head,end_sector,end_cyl;
long start_sect,nr_sects;
};
void do_write(superblock *p,FILE *fp)
{
fprintf(fp," i节点数:%d\n",p->inodes);
fprintf(fp," 逻辑块数:%d\n",p->blocks);
fprintf(fp," i节点位图所占块数:%d\n",p->imap_blocks);
fprintf(fp," 逻辑块位图所占块数:%d\n",p->zmap_blocks);
fprintf(fp,"数据区中第一个逻辑块块号:%ld\n",p->firstdatablock);
fprintf(fp," LOG:%d\n",p->zero);
fprintf(fp," 最大文件长度:%ld\n",p->file_maxsize);
fprintf(fp," 文件系统魔数:%#x\n",p->magic);
}
void disp_superblock(superblock *s,FILE *fp)
{
fprintf(fp," 节点数:%x\n",s->inodes);
fprintf(fp," 逻辑块数:%x\n",s->blocks);
fprintf(fp," i节点位图占用块数:%x\n",s->imap_blocks);
fprintf(fp,"逻辑块位图占用块数:%x\n",s->zmap_blocks);
fprintf(fp,"第一个数据逻辑块号:%x\n",s->firstdatablock);
fprintf(fp," LOG:%x\n",s->zero);
fprintf(fp," 文件最大长度:%lx\n",s->file_maxsize);
fprintf(fp," 文件系统魔数:%x\n",s->magic);
}
void do_read(char *argv[],superblock *p)
{
FILE *fp,*fp2;
int i,j,k;
int n[4];
fp2=fopen("c:\\superblock.txt","w");
fp=fopen(argv[1],"r");
fscanf(fp,"%d",&k);
for(j=0;j<k;j++)
{
//unsigned short inodes;
//unsigned short blocks;
//unsigned short imap_blocks;
//unsigned short zmap_blocks;
// unsigned short firstdatablock;
//unsigned short zero;
//unsigned long file_maxsize;
//unsigned short magic;
fscanf(fp,"%x",&n[0]);
fscanf(fp,"%x",&n[1]);
p->inodes=0;
p->inodes=p->inodes|n[0]|(n[1]<<8);
fscanf(fp,"%x",&n[0]);
fscanf(fp,"%x",&n[1]);
p->blocks=0;
p->blocks=p->blocks|n[0]|(n[1]<<8);
fscanf(fp,"%x",&n[0]);
fscanf(fp,"%x",&n[1]);
p->imap_blocks=0;
p->imap_blocks=p->imap_blocks|n[0]|(n[1]<<8);
fscanf(fp,"%x",&n[0]);
fscanf(fp,"%x",&n[1]);
p->zmap_blocks=0;
p->zmap_blocks=p->zmap_blocks|n[0]|(n[1]<<8);
fscanf(fp,"%x",&n[0]);
fscanf(fp,"%x",&n[1]);
p->firstdatablock=0;
p->firstdatablock=p->firstdatablock|n[0]|(n[1]<<8);
fscanf(fp,"%x",&n[0]);
fscanf(fp,"%x",&n[1]);
p->zero=0;
p->zero=p->zero|n[0]|(n[1]<<8);
for(i=0;i<4;i++)
fscanf(fp,"%x",&n[i]);
p->file_maxsize=0;
p->file_maxsize=p->file_maxsize|n[0]|(n[1]<<8)|(n[2]<<16)|(n[3]<<24);
fscanf(fp,"%x",&n[0]);
fscanf(fp,"%x",&n[1]);
p->magic=0;
p->magic=p->magic|n[0]|(n[1]<<8);
do_write(p,fp2);
// do_put(p);
//disp_superblock(p,fp2);
}
fclose(fp);
fclose(fp2);
}
void read_superblock(FILE *fp,superblock *s)
{
fread(s,18,1,fp);
}
void main(int argc,char *argv[])
{
superblock s;
// FILE *fp2;
// fp2=fopen("c:\\superblock.txt","w");
if(argc>1)
{
do_read(argv,&s);
getchar();
}
// fclose(fp2);
}
使用方法为:建立一个文本文件,内容为18字节的超级块信息,每字节(两位16进制)一组,排成一行作为一个超级块信息,若有多个超级块信息则每个信息另起一行,如55 53 00 FA 03 00 08 00 A8 02 00 00 00 1C 08 10 7F 13
这样就可以保存了,然后将这个文件的路径作为参数传递给上面的可执行文件即可,该程序会在C盘根目录下建立一个叫做superblock.txt的文件保存分析后的结果。
现在我们假设内核源程序已经编写完毕,并且成功编译出了内核(至于内核各部分如何编写我们会在其他帖子中讨论)。我是在Linux下编写并编译的,MAKE以后,键入如下指令生成内核:objcopy -O binary -R .note -R .comment -S /Stone/system kernel.bin
其中/Stone/system是MAKE后生成的文件,我们将System生成了kernel.bin。
接下来我们需要把编译好的内核程序放入磁盘文件中了,这个时候我们就会发现在第一个分区建立文件系统的好处了,只要把内核程序按照MINIX文件系统能够识别的方式存入就可以了。在操作系统运行时,只要LOADER程序按照MINIX文件系统的格式在第一分区中寻找叫做kernel.bin的文件读入内存就完成了内核的加载操作。当然我们也可以采用其他的文件系统格式。这里暂不讨论MINIX文件系统的理论知识,下面提供将内核程序写入磁盘镜像主分区文件系统的源程序(如果你的内核很大的话,这个代码可能要做一些修改,因为我写代码时偷了个懒:-)):
#include<stdio.h>
#include<string.h>
#define NR_PART1 0x1be
#define NR_PART2 0x1ce
#define NR_PART3 0x1de
#define NR_PART4 0x1ee
#define KB 1024
#define SECTOR_POS(X) ((X)*512)
struct d_inode
{
unsigned short i_mode;
unsigned short i_uid;
unsigned long i_size;
unsigned long i_time;
unsigned char i_gid;
unsigned char i_nlinks;
unsigned short i_zone[9];
};
struct dir
{
unsigned short inode; //i节点号
char name[14]; //文件名
};
struct superblock
{
unsigned short inodes; //节点数
unsigned short blocks; //逻辑块总数(块总数)
unsigned short imap_blocks; //imap所占块数
unsigned short zmap_blocks; //zmap所占块数
unsigned short firstdatablock; //第一个数据块号
unsigned short zero;
unsigned long file_maxsize;
unsigned short magic;
};
struct partition_mem
{
int boot_ind, //引导标志0x80表示是可引导的
head, //分区起始磁头号
sector, //分区起始扇区号(bit0-5)
cyl, //分区起始柱面号
sys_ind, //分区类型字节0x80-OLD MINIX 0x82-SWAP
end_head, //分区结束处磁头号
end_sector, //分区结束扇区号(bit0-5)
end_cyl; //分区结束柱面号
unsigned long start_sect,//分区起始物理扇区号
nr_sects; //分区占用的扇区数
};
struct partition
{
char boot_ind,head,sector,cyl,sys_ind,end_head,end_sector,end_cyl;
long start_sect,nr_sects;
};
void ShowHex(unsigned long a)
{
int n;
printf("a=%ld\n",a);
n=(a>>28)&0xf;
printf("%#x ",n);
n=(a>>24)&0xf;
printf("%#x ",n);
n=(a>>20)&0xf;
printf("%#x ",n);
n=(a>>16)&0xf;
printf("%#x ",n);
n=(a>>12)&0xf;
printf("%#x ",n);
n=(a>>8)&0xf;
printf("%#x ",n);
n=(a>>4)&0xf;
printf("%#x ",n);
n=(a)&0xf;
printf("%#x ",n);
}
void do_put(partition *p)
{
printf("\n\n\n 引导标志:%x\n",p->boot_ind);
printf(" 分区起始磁头号:%d\n",p->head);
printf(" 当前柱面中扇区号:%d\n",p->sector&0x3f);
printf(" 分区起始柱面号:%d\n",(p->sector&0xc0)<<2|p->cyl);
printf(" 分区类型字节:%x\n",p->sys_ind);
printf(" 分区结束处磁头号:%d\n",p->end_head);
printf("分区结束当前柱面中扇区号:%d\n",p->end_sector&0x3f);
printf(" 分区结束柱面号:%d\n",(p->end_sector&0xc0)<<2|p->end_cyl);
printf(" 分区起始物理扇区号:%ld\n",p->start_sect);
printf(" 分区占用的扇区数:%ld\n",p->nr_sects);
}
void disp_partition(partition *p,FILE *fp)
{
fprintf(fp,"\n\n\n 引导标志:%x\n",p->boot_ind);
fprintf(fp," 分区起始磁头号:%d\n",p->head);
fprintf(fp," 当前柱面中扇区号:%d\n",p->sector&0x3f);
fprintf(fp," 分区起始柱面号:%d\n",(p->sector&0xc0)<<2|p->cyl);
fprintf(fp," 分区类型字节:%x\n",p->sys_ind&0xff);
fprintf(fp," 分区结束处磁头号:%d\n",p->end_head);
fprintf(fp,"分区结束当前柱面中扇区号:%d\n",p->end_sector&0x3f);
fprintf(fp," 分区结束柱面号:%d\n",(p->end_sector&0xc0)<<2|p->end_cyl);
fprintf(fp," 分区起始物理扇区号:%ld\n",p->start_sect);
fprintf(fp," 分区占用的扇区数:%ld\n",p->nr_sects);
}
void do_read(char *argv[],partition *p)
{
FILE *fp,*fp2;
int i,j,k;
int n[4];
fp2=fopen("c:\\partition.txt","w");
fp=fopen(argv[1],"r");
fscanf(fp,"%d",&k);
for(j=0;j<k;j++)
{
fscanf(fp,"%x",&p->boot_ind);
fscanf(fp,"%x",&p->head);
fscanf(fp,"%x",&p->sector);
fscanf(fp,"%x",&p->cyl);
fscanf(fp,"%x",&p->sys_ind);
fscanf(fp,"%x",&p->end_head);
fscanf(fp,"%x",&p->end_sector);
fscanf(fp,"%x",&p->end_cyl);
for(i=0;i<4;i++)
fscanf(fp,"%x",&n[i]);
p->start_sect=0;
p->start_sect=p->start_sect|n[0]|(n[1]<<8)|(n[2]<<16)|(n[3]<<24);
for(i=0;i<4;i++)
fscanf(fp,"%x",&n[i]);
p->nr_sects=0;
p->nr_sects=p->nr_sects|n[0]|(n[1]<<8)|(n[2]<<16)|(n[3]<<24);
do_put(p);
disp_partition(p,fp2);
}
fclose(fp);
fclose(fp2);
}
void read_partition(FILE *fp,partition *p)
{
fread(p,16,1,fp);
}
void read_superblock(FILE *fp,superblock *s)
{
fread(s,18,1,fp);
}
void disp_superblock(superblock *s,FILE *fp)
{
fprintf(fp," 节点数:%x\n",s->inodes);
fprintf(fp," 逻辑块数:%x\n",s->blocks);
fprintf(fp," i节点位图占用块数:%x\n",s->imap_blocks);
fprintf(fp,"逻辑块位图占用块数:%x\n",s->zmap_blocks);
fprintf(fp,"第一个数据逻辑块号:%x\n",s->firstdatablock);
fprintf(fp," LOG:%x\n",s->zero);
fprintf(fp," 文件最大长度:%lx\n",s->file_maxsize);
fprintf(fp," 文件系统魔数:%x\n",s->magic);
}
void write_superblock(FILE *fp,superblock *s)
{
fwrite(s,18,1,fp);
}
void write_partition(FILE *fp,partition *p)
{
fwrite(p,16,1,fp);
}
unsigned short find_zblock(FILE *fp,partition *p,superblock *s,int do_it)
{
unsigned long zmap_pos=SECTOR_POS(p->start_sect)+2*KB+s->imap_blocks*KB;
unsigned long count=s->zmap_blocks*KB*8;
unsigned short pos=0;
unsigned char ch,tmp;
//int i;
fseek(fp,zmap_pos,SEEK_SET);
while(pos<count)
{
fread(&ch,1,1,fp);
tmp=0x01;
while(tmp)
{
if(ch&tmp)
{
tmp=tmp<<1;
pos++;
}
else
{
if(pos==0)
{
tmp=tmp<<1;
pos++;
continue;
}
if(pos<count)
{
if(do_it)
{
ch=ch|tmp;
fseek(fp,-1L,SEEK_CUR);
fwrite(&ch,1,1,fp);
}
return pos;
}
}
}
}
return 0;
}
unsigned short find_inode(FILE *fp,partition *p,superblock *s,int do_it)
{
unsigned long imap_pos=SECTOR_POS(p->start_sect)+2*KB;
unsigned long count=s->imap_blocks*KB*8;
unsigned short pos=0;
unsigned char ch,tmp;
//int i;
fseek(fp,imap_pos,SEEK_SET);
while(pos<count)
{
fread(&ch,1,1,fp);
tmp=0x01;
while(tmp)
{
if(ch&tmp)
{
tmp=tmp<<1;
pos++;
}
else
{
if(pos==0)
{
tmp=tmp<<1;
pos++;
continue;
}
if(pos<count)
{
if(do_it)
{
ch=ch|tmp;
fseek(fp,-1L,SEEK_CUR);
fwrite(&ch,1,1,fp);
}
return pos;
}
}
}
}
return 0;
}
long do_directory(FILE *fp,partition *p,superblock *s,unsigned short I_Node,char *filename)
{
dir _dir;
int _kb=1024;
unsigned long data_pos=SECTOR_POS(p->start_sect)+s->firstdatablock*KB;
fseek(fp,data_pos,SEEK_SET);
while(_kb)
{
fread(&_dir,sizeof(struct dir),1,fp);
if(_dir.inode==0&&_kb)
{
_dir.inode=I_Node;
strcpy(_dir.name,filename);
fseek(fp,-16L,SEEK_CUR);
fwrite(&_dir,sizeof(struct dir),1,fp);
return 1L;
}
_kb-=16;
}
return 0L;
}
//unsigned long apply_zblock(FILE *fp,partition *p,superblock *s)
//{
//}
void clear_block(FILE *fp,unsigned short block,partition *p,superblock *s,int fill,unsigned short zblock)
{
char buf[KB]={0,};
unsigned long pos=SECTOR_POS(p->start_sect)+block*KB;
fseek(fp,pos,SEEK_SET);
fwrite(buf,1024,1,fp);
if(fill)
{
fseek(fp,pos,SEEK_SET);
fwrite(&zblock,sizeof(unsigned short),1,fp);
}
}
long do_inodeArea_2(FILE *fp,partition *p,superblock *s,unsigned short i_node,unsigned short zblock,FILE *fp2,d_inode *__nod)
{
unsigned long inode_area=SECTOR_POS(p->start_sect)+(2+s->imap_blocks+s->zmap_blocks)*KB;
unsigned long pos=inode_area+32*(i_node-1);
unsigned long end=SECTOR_POS(p->start_sect)+s->firstdatablock*KB;
unsigned long file_size;
unsigned short state;
int i,j=0;
char buffer[KB],buff[KB];
d_inode nod={0,};
if(pos>=end)return 0L;
fseek(fp2,0,SEEK_END);
file_size=ftell(fp2);
fseek(fp2,0,SEEK_SET);
nod.i_size=file_size;
nod.i_nlinks=1;
nod.i_mode=0100755;
for(i=0;i<7;i++)
if(nod.i_zone[i]==0)
{
nod.i_zone[i]=zblock-1+s->firstdatablock;
goto op;
}
if(nod.i_zone[i]==0)
{
if((state=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L;
}
nod.i_zone[i]=state-1+s->firstdatablock;
clear_block(fp,nod.i_zone[i],p,s,1,zblock-1+s->firstdatablock);
goto op;
}
else
{
fseek(fp,nod.i_zone[i]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fread(buffer,KB,1,fp);
while(j<512)
{
if(((unsigned short *)buffer)[j]==0)
{
((unsigned short *)buffer)[j]=zblock-1+s->firstdatablock;
fseek(fp,nod.i_zone[i]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
goto op;
}
j++;
}
}
if(j>=512)
{
if(nod.i_zone[8]==0)
{
if((state=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L;
}
nod.i_zone[8]=state-1+s->firstdatablock;
clear_block(fp,nod.i_zone[8],p,s,0,zblock-1+s->firstdatablock);
if((state=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L;
}
//nod.i_zone[i]=state-1+s->firstdatablock;
clear_block(fp,state-1+s->firstdatablock,p,s,1,zblock-1+s->firstdatablock);
fseek(fp,nod.i_zone[8]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fread(buffer,KB,1,fp);
((unsigned short *)buffer)[0]=state-1+s->firstdatablock;
fseek(fp,nod.i_zone[8]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
goto op;
}
else
{
fseek(fp,nod.i_zone[8]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fread(buffer,KB,1,fp);
j=0;
while(j<512)
{
if(((unsigned short *)buffer)[j]==0)
{
if((state=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L;
}
//nod.i_zone[8]=state-1+s->firstdatablock;
clear_block(fp,state-1+s->firstdatablock,p,s,1,zblock-1+s->firstdatablock);
((unsigned short *)buffer)[j]=state-1+s->firstdatablock;
fseek(fp,nod.i_zone[8]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
goto op;
}
else
{
i=0;
fseek(fp,((unsigned short *)buffer)[j]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fread(buff,KB,1,fp);
while(i<512)
{
if(((unsigned short *)buff)[i]==0)
{
((unsigned short *)buff)[i]=zblock-1+s->firstdatablock;
fseek(fp,((unsigned short *)buffer)[j]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buff,KB,1,fp);
goto op;
}
i++;
}
}
j++;
}
printf("File is full.Can't fill in any data!\n");
return 0L;
}
}
op:
fseek(fp,pos,SEEK_SET);
fwrite(&nod,sizeof(struct d_inode),1,fp);
*__nod=nod;
return 1L;
}
long do_writeFile(FILE *fp,partition *p,superblock *s,unsigned short i_node,unsigned short zblock,FILE *fp2,d_inode *nod)
{
char buffer[KB],buff[KB];
unsigned short state;
int i=0,j;
//fseek(fp2,0L,SEEK_SET);
rewind(fp2);
{
nod->i_zone[i]=zblock-1+s->firstdatablock;
fread(buffer,KB,1,fp2);
//ShowHex(nod->i_zone[i]*KB+SECTOR_POS(p->start_sect));
fseek(fp,nod->i_zone[i]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
}
if(!feof(fp2))
// if(feof(fp2))
{
i++;
while(!feof(fp2))
{
if((zblock=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L; //需要调用函数删掉申请的逻辑块位及i节点位等
}
printf("Appling ZBlock Is %ld\n",zblock);
if(i<7)
{
nod->i_zone[i]=zblock-1+s->firstdatablock;
fread(buffer,KB,1,fp2);
fseek(fp,nod->i_zone[i]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
i++;
}
else
{
if(i==7)
{
if(nod->i_zone[7]==0)
{
nod->i_zone[7]=zblock-1+s->firstdatablock;
if((zblock=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L; //需要调用函数删掉申请的逻辑块位及i节点位等
}
printf("Appling ZBlock Is %ld\n",zblock);
clear_block(fp,nod->i_zone[7],p,s,0,zblock-1+s->firstdatablock);
}
j=0;
fseek(fp,nod->i_zone[7]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fread(buff,KB,1,fp);
while(j<512)
{
if(((unsigned short *)buff)[j]==0)
{
((unsigned short *)buff)[j]=zblock-1+s->firstdatablock;
fseek(fp,nod->i_zone[7]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buff,KB,1,fp);
goto do_do;
}
j++;
}
if(j>=512)
{
i++;
goto times2;
}
do_do:
fread(buffer,KB,1,fp2);
fseek(fp,(zblock-1+s->firstdatablock)*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
}
else
{
times2:
if(nod->i_zone[8]==0)
{
nod->i_zone[8]=zblock-1+s->firstdatablock;
if((zblock=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L; //需要调用函数删掉申请的逻辑块位及i节点位等
}
printf("Appling ZBlock Is %ld\n",zblock);
clear_block(fp,nod->i_zone[8],p,s,0,zblock-1+s->firstdatablock);
}
//---------------------------------------------------------------------------------------------------
fseek(fp,nod->i_zone[8]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fread(buffer,KB,1,fp);
j=0;
while(j<512)
{
if(((unsigned short *)buffer)[j]==0)
{
if((state=find_zblock(fp,p,s,1))==0)
{
printf("No More Available ZBlock!\n");
return 0L; //需要调用函数删掉申请的逻辑块位及i节点位等
}
clear_block(fp,state-1+s->firstdatablock,p,s,1,zblock-1+s->firstdatablock);
((unsigned short *)buffer)[j]=state-1+s->firstdatablock;
fseek(fp,nod->i_zone[8]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
goto do_do2;
}
else
{
i=0;
fseek(fp,((unsigned short *)buffer)[j]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fread(buff,KB,1,fp);
while(i<512)
{
if(((unsigned short *)buff)[i]==0)
{
((unsigned short *)buff)[i]=zblock-1+s->firstdatablock;
fseek(fp,((unsigned short *)buffer)[j]*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buff,KB,1,fp);
goto do_do2;
}
i++;
}
}
j++;
}
printf("File is full.Can't fill in any data!\n");
return 0L; //需要调用函数删掉申请的逻辑块位及i节点位等
//---------------------------------------------------------------------------------------------------
do_do2:
fread(buffer,KB,1,fp2);
fseek(fp,(zblock-1+s->firstdatablock)*KB+SECTOR_POS(p->start_sect),SEEK_SET);
fwrite(buffer,KB,1,fp);
}
}
}
}
return 1L;
}
long do_inodeArea(FILE *fp,partition *p,superblock *s,unsigned short i_node,unsigned short zblock,FILE *fp2,d_inode *__nod)
{
unsigned long inode_area=SECTOR_POS(p->start_sect)+(2+s->imap_blocks+s->zmap_blocks)*KB;
unsigned long pos=inode_area+32*(i_node-1);
unsigned long end=SECTOR_POS(p->start_sect)+s->firstdatablock*KB;
unsigned long file_size;
//int i,j=0;
// char buffer[KB],buff[KB];
//d_inode nod={0,};
if(pos>=end)return 0L;
fseek(fp2,0,SEEK_END);
file_size=ftell(fp2);
fseek(fp2,0,SEEK_SET);
__nod->i_size=file_size;
__nod->i_nlinks=1;
__nod->i_mode=0100755;
__nod->i_gid=0;
__nod->i_time=0;
__nod->i_uid=0;
fseek(fp,pos,SEEK_SET);
fwrite(__nod,sizeof(struct d_inode),1,fp);
// *__nod=nod;
return 1L;
}
long del_file(FILE *fp,partition *p,superblock *s,char *filename)
{
return 0L;
}
long _Clr(FILE *fp,partition *p,superblock *s)
{
unsigned long imap_pos=SECTOR_POS(p->start_sect)+2*KB;
unsigned long zmap_pos=SECTOR_POS(p->start_sect)+2*KB+s->imap_blocks*KB;
unsigned long position=0xb1e20;
//unsigned char word=3,nul=0,_Nul[160]={0,};
unsigned char word=3,nul=0,_Nul[320]={0,};
fseek(fp,imap_pos,SEEK_SET);
fwrite(&word,1,1,fp);
fwrite(&nul,1,1,fp);
fseek(fp,zmap_pos,SEEK_SET);
fwrite(&word,1,1,fp);
fwrite(_Nul,1,320,fp);
fseek(fp,position,SEEK_SET);
fwrite(_Nul,1,320,fp);
return 1L;
}
void main(int argc,char *argv[])
{
partition p;
superblock s;
// FILE *fp2;
// fp2=fopen("c:\\superblock.txt","w");
if(argc==3)
{
FILE *fp,*fp2;
unsigned char erase=0;
// unsigned long start,end,o_start,o_end;
unsigned short zblock,i_node;
// long state;
char buff[KB];
d_inode nod={0,};
if((fp=fopen(argv[1],"rb+"))==NULL)
{
printf("PANIC:Can't Open Stone.img\n");
goto here;
}
if((fp2=fopen(argv[2],"rb+"))==NULL)
{
printf("PANIC:Can't Open kernel.bin\n");
goto here;
}
fseek(fp,NR_PART1,SEEK_SET);
read_partition(fp,&p);
fseek(fp,(SECTOR_POS(p.start_sect)+KB),SEEK_SET);
read_superblock(fp,&s);
_Clr(fp,&p,&s);
if((zblock=find_zblock(fp,&p,&s,1))==0)
{
printf("No More Available ZBlock!\n");
goto here;
}
printf("Available ZBlock Is %ld\n",zblock);
if((i_node=find_inode(fp,&p,&s,1))==0)
{
printf("No More Available I-Node!\n");
goto here;
}
printf("Available I-Node Is %ld\n",i_node);
if(do_directory(fp,&p,&s,i_node,"kernel.bin"))
printf("Write To Directory Successfully!\n");
else
{
printf("Write To Directory Failed!\n");
goto here;
}
if(do_writeFile(fp,&p,&s,i_node,zblock,fp2,&nod))
printf("Write File To MINIX Successfully!\n");
else
{
printf("Write File To MINIX Failed!\n");
goto here;
}
if(do_inodeArea(fp,&p,&s,i_node,zblock,fp2,&nod))
{
printf("Write Inode-Area Successfully!\n");
printf("文件类型及属性:%#o\n",nod.i_mode);
printf("文件大小:%ld Bytes / %#lx KBs\n",nod.i_size,nod.i_size>>10);
printf("文件块号1:%#x\n",nod.i_zone[0]);
printf("文件块号2:%#x\n",nod.i_zone[1]);
printf("文件块号3:%#x\n",nod.i_zone[2]);
printf("文件块号4:%#x\n",nod.i_zone[3]);
printf("文件块号5:%#x\n",nod.i_zone[4]);
printf("文件块号6:%#x\n",nod.i_zone[5]);
printf("文件块号7:%#x\n",nod.i_zone[6]);
if((nod.i_size>>10)>7&&nod.i_zone[7])
{
int _i=8,_j=0;
fseek(fp,nod.i_zone[7]*KB+SECTOR_POS(p.start_sect),SEEK_SET);
fread(buff,KB,1,fp);
while(_j<512)
{
if(((unsigned short *)buff)[_j]==0)break;
else
{
printf("文件块号%d:%#x\n",_i++,((unsigned short *)buff)[_j]);
}
_j++;
}
}
/* else
{
printf("File Data Written Error!\n");
goto here;
}*/
}
else
printf("Write Inode-Area Failed!\n");
here:
fclose(fp);
fclose(fp2);
//getchar();
}
else
printf("writeTominix stone.img kernel.bin\n");
/*命令格式:程序名 磁盘映像 内核程序*/
}
至此,内核程序所有需要的部分都已经准备好了,剩下来的任务就应该是调试并运行了。这个帖子就暂告一段落了,当然,程序并不是唯一的,我们可以用自己的方式来完成。同时欢迎批评、指教。
大家可以加入群:40524959,里面有相关资料下载地址。
[ 本帖最后由 chengstone 于 2009-11-25 14:50 编辑 ]