harib16a:
  这一部分,我们在系统中实现读取文件内容的命令type。在windows中,输入“type 文件名”,在Linux中,输入“cat 文件名”都可以显示文件的内容。我们先来看看如何读取文件本身的内容。这一节的前面部分,笔者花了大量篇幅去寻找文件内容在内存中的位置得到了以下规律:
 1、clustno 表示文件从哪个扇区开始放:

  • HARIBOTE.SYS  02 00 -> clustno = 0x0002 :0x004200
  •        IPL10.NAS  39 00 -> clustno = 0x0039 :0x00b000
  •        MAKE.BAT  3F 00 ->  clustno = 0x003F :0x00bc00

 2、磁盘映像中的地址 = clustno * 512 +0x003e00
     好了接下来我们修改CMD任务中的内容

void console_task(struct SHEET *sheet, unsigned int memtotal)
{ //.....
char s[], cmdline[], *p;
//.....
for (;;) {
//.....
} else if (cmdline[] == 't' && cmdline[] == 'y' && cmdline[] == 'p' &&
cmdline[] == 'e' && cmdline[] == ' ') {
/* type命令 */
/* 准备文件名 */
for (y = ; y < ; y++) {
s[y] = ' ';
}
y = ;
for (x = ; y < && cmdline[x] != ; x++) {//从cmdline[30]的第5个字符开始,将文件名写到数组s中
if (cmdline[x] == '.' && y <= ) {
y = ;
} else {
s[y] = cmdline[x];
if ('a' <= s[y] && s[y] <= 'z') {
/* 将小写字母换成大写字母,因为镜像中写的文件信息都是大写字母 */
s[y] -= 0x20;
}
y++;
}
}
/* 寻找文件 */
for (x = ; x < ; ) {         //在224个文件段信息里面找
if (finfo[x].name[] == 0x00) {  //第一字节为0x00,表示这一段不包含文件信息
break;
}
if ((finfo[x].type & 0x18) == ) {//包含信息
for (y = ; y < ; y++) {  //该段的文件名信息和S数组比较
if (finfo[x].name[y] != s[y]) {
goto type_next_file; //不想等,不是这个文件,
}
}
break; /* 找不到文件 */
}
type_next_file: //继续往下找
x++;
}
if (x < && finfo[x].name[] != 0x00) {
/* 找到文件的情况,x为文件的段号 */
y = finfo[x].size; //文件的大小
    //文件内容在内存中的位置
p = (char *) (finfo[x].clustno * + 0x003e00 + ADR_DISKIMG);
cursor_x = ;    //用来记录是否到达行尾,行首初始化为8
for (x = ; x < y; x++) {
/* 逐字输出 */
s[] = p[x];
s[] = ;
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, s, );
cursor_x += ;
if (cursor_x == + ) {     //到达最右端后换行
cursor_x = ;
cursor_y = cons_newline(cursor_y, sheet);//换行
}
}
} else {
/* 没有找到文件的情况,输出提示信息File not found.换行 */
putfonts8_asc_sht(sheet, , cursor_y, COL8_FFFFFF, COL8_000000, "File not found.", );
cursor_y = cons_newline(cursor_y, sheet);
}
cursor_y = cons_newline(cursor_y, sheet);
}
//.....
}
}

harib16b:
  我们发现系统中的type命令无法对制表符、换行、回车进行相应的操作和处理;笔者首先给出了这三个特殊字符的字符编码,接着Windows和Linux中的换行符进行了比较,最后作者决定用以下编码来表示这三个特殊字符:

  • 0x09......制表符:这里设定4个空格的长度为一个制表符
  • 0x0a......换行符:换行
  • 0x0d......回车符:忽略

  按照上述字符编码,修改CMD任务:

void console_task(struct SHEET *sheet, unsigned int memtotal)
{ //.....
for (;;) {
//.....
} else if (strncmp(cmdline, "type ", ) == ) {    //只比较前面的5个字符
//......
if (s[] == 0x09) {            /* 制表符 */
for (;;) {
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, " ", );
cursor_x += ;
if (cursor_x == + ) {
cursor_x = ;
cursor_y = cons_newline(cursor_y, sheet);
}
if (((cursor_x - ) & 0x1f) == ) {//CMD窗口宽度为8个像素笔者规定的一个制表符是4个字符,因此是32个像素的值
break;       /* 被32整除break */
}
}
} else if (s[] == 0x0a) { /* 换行 */
cursor_x = ;
cursor_y = cons_newline(cursor_y, sheet);
} else if (s[] == 0x0d) { /* 回车 */
     /* 这里暂时不进行任何操作 */
} else { /* 按照一般的字符进行显示操作 */
putfonts8_asc_sht(sheet, cursor_x, cursor_y, COL8_FFFFFF, COL8_000000, s, );
cursor_x += ;
if (cursor_x == + ) {
cursor_x = ;
cursor_y = cons_newline(cursor_y, sheet);
}
}
}
}
//.....
}
}

harib16c:
  type命令有时无法正确显示文件的内容。而且如果文件大小超过了512字节,也会出现问题。怎么存储大于512字节的内容呢?我们来看看FAT和clustno.
  FAT(file allocation table):文件分配表,用来记录文件在磁盘中存放位置的表。它位于从0柱面、0磁头、2扇区开始的9个扇区中,在磁盘映像中相当于0x000200-0x0013ff。微软已经对这个FAT进行了压缩,我们将数据以3个字节为一组进行解压缩:规则如下:ab ce ef ->dab efc;微软将FAT看作是很重要的磁盘信息,为此在磁盘中放了两份FAT:0x000200-0x0013ff和0x001400-0x0025ff。

  

  clustno:表示文件从哪个扇区开始放

  • HARIBOTE.SYS   02 00 -> clustno = 0x0002 :0x004200
  • IPL10.NAS      39 00 -> clustno = 0x0039 :0x00b000
  • MAKE.BAT      3F 00 -> clustno = 0x003F :0x00bc00

  以HARIBOTE.SYS为例,读取文件内容顺序如下
    1、clustno = 0x0002;读取从clustno * 512 +0x003e00开始的512字节的内容
    2、clustno = FAT(clustno) = 3;读取从clustno * 512 +0x003e00开始的512字节的内容
    3、clustno = FAT(clustno) = 4;读取从clustno * 512 +0x003e00开始的512字节的内容
    4、依次类推,直到clustno = FAT(clustno) = (FF8-FFF)表示文件尾部
  我们根据上面的原理和信息来写程序

void console_task(struct SHEET *sheet, unsigned int memtotal)
{ //......
int *fat = (int *) memman_alloc_4k(memman, * );
//将FAT信息解压缩到fat数组中。。。
file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200));
for (;;) {
//.......
else if (strncmp(cmdline, "type ", ) == ) { //type命令
//......
if (x < && finfo[x].name[] != 0x00) { //第x段有文件信息
p = (char *) memman_alloc_4k(memman, finfo[x].size);//分配一块和文件大小相同的内存p
//file_loadfile将文件中的内容都入到上面分配的内存中
file_loadfile(finfo[x].clustno, finfo[x].size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
cursor_x = ;               //接下来和以前的一样,只不过这里要显示的文件内容都在数组P中
for (y = ; y < finfo[x].size; y++) { //遍历文件(大小为finfo[x].size)
s[] = p[y];
s[] = ;
//.....
//这里处理特殊字符,制表符,换行,回车(看一部分)!
}
memman_free_4k(memman, (int) p, finfo[x].size);//用完了之后把分配的内存p释放掉
}
//......
}
} void file_readfat(int *fat, unsigned char *img){ //将FAT信息解压缩到fat中|规则如下:ab ce ef ->dab efc
int i, j = ;
for (i = ; i < ; i += ) {
fat[i + ] = (img[j + ] | img[j + ] << ) & 0xfff;
fat[i + ] = (img[j + ] >> | img[j + ] << ) & 0xfff;
j += ;
}
return;
} void file_loadfile(int clustno, int size, char *buf, int *fat, char *img)
{ //将文件的内容都写到分配的内存中buf
int i;
for (;;) {
if (size <= ) {
for (i = ; i < size; i++) {
buf[i] = img[clustno * + i];
}
break;
}
for (i = ; i < ; i++) {
buf[i] = img[clustno * + i];
}
size -= ;
buf += ;
clustno = fat[clustno];
}
return;
}

harib16d:
  我们到这里发现代码量已经比较大了,读起来比较吃力,下面我们来对代码进行一下整理:

    • 窗口相关函数->winsows.c
    • 命令行窗口相关函数->console.c
    • 文件相关的函数->

  整理后,工程代码变得清晰了很多,虽然内容没有什么变化。

harib16e:
  前面我们已经能够读取文件的内容了,下面我们要尝试着运行应用程序。我们从下面最简单的开始,将下面四行汇编代码保存为hlt.nas,接着用nask进行汇编,生成hlt.hrb(就是haribote的缩写,这里我们用了自己定义的扩展名.hrb)。之后将hlt.hrb写到镜像中,再用前面编写的file_loadfile将hlt.hrb的内容放到一个大小相等的临时变量中p中(相当于一个缓冲区),接着把这个临时变量p加载到GDT的某个段中,最后调用farjmp()执行GDT中这个段中的程序hlt.hrb。怎么样,原理是不是很容易,下面我们看看代码具体怎么做的。

;hlt.nas 4行的汇编代码,我们将要汇编的源程序
[BITS ]
fin:
HLT
JMP fin
void console_task(struct SHEET *sheet, unsigned int memtotal)
{ //.....
for(;;)
{ //....
else if (strcmp(cmdline, "hlt") == ) {
/* 接收到了hlt字符串 */
for (y = ; y < ; y++) {
s[y] = ' ';//s初始化
}
s[] = 'H';
s[] = 'L';
s[] = 'T';
s[] = 'H';
s[] = 'R';
s[] = 'B';
for (x = ; x < ; ) {
if (finfo[x].name[] == 0x00) {
break;   //找到第一个没有文件信息的片段(片段号退出时为X)
}
if ((finfo[x].type & 0x18) == ) {   //有文件信息的片段
for (y = ; y < ; y++) {
if (finfo[x].name[y] != s[y]) {//文件不是hlt.hrb文件
goto hlt_next_file;     //跳转
}
}
break;   /* 文件是hlt.hrb文件,BREAK */
}
hlt_next_file://这里继续循环,找下一个文件是不是hlt.hrb
x++;
}
if (x < && finfo[x].name[] != 0x00) {
/* 找到了hlt.hrb */
p = (char *) memman_alloc_4k(memman, finfo[x].size);//分配一块和文件hlt.hrb大小相同的内存p
//把这块内存写到GDT的1003号中(这里一般是空闲的,可以写东西
file_loadfile(finfo[x].clustno, finfo[x].size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));
set_segmdesc(gdt + , finfo[x].size - , (int) p, AR_CODE32_ER);
farjmp(, * );                  //任务切换,这里会加载TR寄存器到GDT的1003号,执行
memman_free_4k(memman, (int) p, finfo[x].size);   //执行完成后,释放掉内存p
} else {
/* 没有找打文件hlt.hrb,输出提升信息 "File not found."*/
putfonts8_asc_sht(sheet, , cursor_y, COL8_FFFFFF, COL8_000000, "File not found.", );
cursor_y = cons_newline(cursor_y, sheet);
}
cursor_y = cons_newline(cursor_y, sheet);
}
//.....
}
}

《30天自制操作系统》19_day_学习笔记的更多相关文章

  1. 《30天自制操作系统》学习笔记--Mac下工具的使用

    现在来介绍官网上下的工具怎么用首先是官网地址,书上有个注释上有:hrb.osask.jp 翻译成中文大概是这个样子滴. 上面有两个文件可以下载,一个是工具,一个是工具的源代码,很好的学习资料 下面把工 ...

  2. 《30天自制操作系统》学习笔记--Mac环境搭建

    弄了三天了,终于弄好了,先说结果,就是作者在网站上放了os x的工具(hrb.osask.jp,也有linux下的工具,可以自己去下载),也就是说我白忙活了三天... 再说一下这几天都干啥了,主要是想 ...

  3. 《30天自制操作系统》学习笔记--番外篇之Mac环境下的工具介绍

    这几天又有点不务正业了,书也没看,一直在搞这个破环境,尝试各种做法,网上各种垃圾信息,浪费了很多时间,说的基本都是废话,不过还是找到了一些,赶紧写下来,不然这个过几天又忘了 首先是环境,我用的是Max ...

  4. 《30天自制操作系统》读书笔记(5) GDT&IDT

    梳理项目结构 项目做到现在, 前头的好多东西都忘了, 还是通过Makefile重新理解一下整个项目是如何编译的: 现在我们拥有这么9个文件: ipl10.nas    InitialProgramLo ...

  5. 《30天自制操作系统》读书笔记(3) 引入C语言

    这一次的学习相当曲折, 主要是因为粗心, Makefile里面的错误导致了文件生成出现各种奇奇怪怪的问题, 弄得心力交瘁, 因此制作过程还是尽量按着作者的路子来吧. 作者提供的源码的注释在中文系统下是 ...

  6. 《30天自制操作系统》读书笔记(2)hello, world

    让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实 ...

  7. 30天自制操作系统第九天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第九天的课程已学完,确实有点不想写 ...

  8. 从你的u盘启动:30天自制操作系统第四天u盘启动学习笔记

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 developing environment:ubuntu 关于u盘启动自己做的操 ...

  9. 30天自制操作系统第八天学习笔记(u盘软盘双启动版本)

    暑假学习小日本的那本书:30天自制操作系统 qq交流群:122358078    ,更多学习中的问题.资料,群里分享 environment:开发环境:ubuntu 第八天的学习思考: 关于鼠标是怎么 ...

  10. 《30天自制操作系统》笔记(03)——使用Vmware

    <30天自制操作系统>笔记(03)——使用Vmware 进度回顾 在上一篇,实现了用IPL加载OS程序到内存,然后JMP到OS程序这一功能:并且总结出下一步的OS开发结构.但是遇到了真机测 ...

随机推荐

  1. /var/run/yum.pid 已被锁定,PID 为 XXXX 的另一个程序正在运行。

    安装st-load时, 终端提示 “/var/run/yum.pid 已被锁定,PID 为 13908 的另一个程序正在运行.” 解决方法:直接在终端运行 rm -f /var/run/yum.pid ...

  2. 【算法杂谈】LJX的迪杰斯特拉算法报告

    迪杰斯特拉(di jie qi)算法 这里有一张图: 假设要求从1号节点到5号节点的最短路.那么根据迪杰斯特拉算法的思想,我们先看: 节点1,从节点1出发的一共有3条路,分别是1-6.1-3.1-2. ...

  3. Oracle 取随机数

    1.从表中随机取记录 select * from (select * from staff order by dbms_random.random)      where rownum < 4 ...

  4. ZeroMQ接口函数之 :zmq_msg_size - 以字节为单位返回消息内容的大小

    ZeroMQ 官方地址 :http://api.zeromq.org/4-2:zmq_msg_size zmq_msg_size(3)  ØMQ Manual - ØMQ/3.2.5 Name zmq ...

  5. osg 示例程序解析之osgdelaunay

    osg 示例程序解析之osgdelaunay 转自:http://lzchenheng.blog.163.com/blog/static/838335362010821103038928/ 本示例程序 ...

  6. Memcache及telnent命令详解

    1.启动Memcache 常用参数 memcached 1.4.3 -p <num>      设置端口号(默认不设置为: 11211) -U <num>      UDP监听 ...

  7. 然当装入Ubuntu双系统时,会出现无线硬件开关关闭的问题,当然也就无法连网

    rfkill list all 会出现如下提示 0:ideapad_wlan: Wireless LAN      Soft blocked: no      Hard blocked:yes     ...

  8. 一个人java深入理解java logback配置

    http://blog.csdn.net/initphp/article/category/1230072/2

  9. php上传大文件时,服务器端php.ini文件中需要额外修改的选项

    几个修改点: 1.upload_max_filesize 上传的最大文件 2.post_max_size 上传的最大文件 3.max_execution_time 修改为0表示无超时,一直等待 4.m ...

  10. Windows 7 IE主页被篡改,如何修复?

    有时我们的电脑会因为病毒的入侵,使得IE主页被篡改,然后就会被没底线的广告包围,有时用杀毒软件也不修复,那么此时应该怎么修复呢?其实很简单,只需几步,就可以让您的电脑重新清净下来. 第一步 点击“开始 ...