[自制简单操作系统] 9、命令行与应用程序 整体回顾

 

>_<" 下面是整个操作系统的编译框架,这里bootpack是主程序部分,通过调用其他.c文件里的功能函数及必须用汇编写的功能函数(naskfun.nas)来实现操作系统的各项功能,这里统一把他们编译集成到bootpack.bim中,ipl10.asm是引导部分,asmhead.asm是用汇编写的用来实现汇编和C语言的桥梁及一些初始32位编程的设置。此外为了实现命令行读取文件和运行应用程序的功能,这里把2号蓝色的部分文件也加载到操作系统。此外这里1号红色框内展示的是c文件和字库转换成obj的具体过程。

 

>_<" naskfunc.nas主要是C语言有些函数无法实现必须用汇编实现,这里就是那些汇编实现的功能函数:它们包括让CPU休眠的函数,开中断,关中断,IO读写,获取某个特定寄存器或给某个特定寄存器赋值函数以及far jmp功能函数。

naskfunc.nas

>_<" graphic.c主要是调色板、画矩形、显示字符、画主窗口、画鼠标等绘图的底层函数集,供bootpack.c调用实现绘制窗口等功能~

  1 /* 操作系统函数集合 */
  2 
  3 #include "bootpack.h"
  4 
  5 // -----------------------------------------------------------------------------------
  6 //调色板相关
  7 //-----------------------------------------------------------------------------------
  8 
  9 /////////////////////////////////////////////////////////////////////////////////////
 10 //功能:初始化调色板,建立静态16个颜色映射,然后调用set_palette进行设置
 11 //参数:无
 12 //附件:要调用set_palette函数
 13 void init_palette(void)
 14 {
 15      static unsigned char table_rgb[16 * 3] = {
 16         0x00, 0x00, 0x00,    /*  0:黑 */
 17         0xff, 0x00, 0x00,    /*  1:亮红 */
 18         0x00, 0xff, 0x00,    /*  2:亮绿 */
 19         0xff, 0xff, 0x00,    /*  3:亮黄 */
 20         0x00, 0x00, 0xff,    /*  4:亮蓝 */
 21         0xff, 0x00, 0xff,    /*  5:亮紫 */
 22         0x00, 0xff, 0xff,    /*  6:浅亮蓝 */
 23         0xff, 0xff, 0xff,    /*  7:白 */
 24         0xc6, 0xc6, 0xc6,    /*  8:亮灰 */
 25         0x84, 0x00, 0x00,    /*  9:暗红 */
 26         0x00, 0x84, 0x00,    /* 10:暗绿 */
 27         0x84, 0x84, 0x00,    /* 11:暗黄 */
 28         0x00, 0x00, 0x84,    /* 12:暗青 */
 29         0x84, 0x00, 0x84,    /* 13:暗紫 */
 30         0x00, 0x84, 0x84,    /* 14:浅暗蓝 */
 31         0x84, 0x84, 0x84    /* 15:暗灰 */
 32     };
 33     set_palette(0, 15, table_rgb);
 34     return;
 35     /*C语言中static char只能用于数据,就像汇编中的DB指令 */
 36 }
 37 /////////////////////////////////////////////////////////////////////////////////////
 38 //功能:初始化设置调色板
 39 //参数:开始标号,结束标号,16*3的颜色表
 40 //附加:关闭中断,进行设置(要知道具体设置要求),恢复中断
 41 void set_palette(int start, int end, unsigned char *rgb)
 42 {
 43     int i, eflags;
 44     eflags = io_load_eflags();    /* 记录中断许可标志 */
 45     io_cli();                     /* 将中断许可标志置0,禁止中断 */
 46     io_out8(0x03c8, start);
 47     for (i = start; i <= end; i++) {
 48         io_out8(0x03c9, rgb[0] / 4);
 49         io_out8(0x03c9, rgb[1] / 4);
 50         io_out8(0x03c9, rgb[2] / 4);
 51         rgb += 3;
 52     }
 53     io_store_eflags(eflags);    /* 恢复原中断 */
 54     return;
 55 }
 56 
 57 //-----------------------------------------------------------------------------------
 58 //显示主界面相关
 59 //-----------------------------------------------------------------------------------
 60 
 61 /////////////////////////////////////////////////////////////////////////////////////
 62 //功能:填充VRAM实现画矩形操作
 63 //参数:VRAM初址,x轴像素,颜色标号,后面4个是位置矩形
 64 void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
 65 {
 66     int x, y;
 67     for (y = y0; y <= y1; y++) {
 68         for (x = x0; x <= x1; x++)
 69             vram[y * xsize + x] = c;
 70     }
 71     return;
 72 }
 73 /////////////////////////////////////////////////////////////////////////////////////
 74 //功能:初始化屏幕,画矩形,形成最初的窗口界面
 75 //参数:VRAM初址,屏幕宽和长
 76 //附加:要调用boxfill8函数
 77 void init_screen8(char *vram, int x, int y)
 78 {
 79     boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
 80     boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
 81     boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
 82     boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);
 83 
 84     boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
 85     boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
 86     boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
 87     boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
 88     boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
 89     boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);
 90 
 91     boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
 92     boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
 93     boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
 94     boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
 95     return;
 96 }
 97 
 98 //-----------------------------------------------------------------------------------
 99 //字符显示相关
100 //-----------------------------------------------------------------------------------
101 
102 /////////////////////////////////////////////////////////////////////////////////////
103 //功能:在指定位置显示一个字符
104 //参数:VRAM初址,窗口宽,待显示的位置,颜色,显示文字的初址(这里采用16个char表示一个字符)
105 void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
106 {
107     int i;
108     char *p, d /* data */;
109     for (i = 0; i < 16; i++) {
110         //查询每个char的8个位,如果不为0,就
111         p = vram + (y + i) * xsize + x;
112         d = font[i];
113         if ((d & 0x80) != 0) { p[0] = c; }
114         if ((d & 0x40) != 0) { p[1] = c; }
115         if ((d & 0x20) != 0) { p[2] = c; }
116         if ((d & 0x10) != 0) { p[3] = c; }
117         if ((d & 0x08) != 0) { p[4] = c; }
118         if ((d & 0x04) != 0) { p[5] = c; }
119         if ((d & 0x02) != 0) { p[6] = c; }
120         if ((d & 0x01) != 0) { p[7] = c; }
121     }
122     return;
123 }
124 /////////////////////////////////////////////////////////////////////////////////////
125 //功能:在指定位置显示一个字符串
126 //参数:VRAM初址,窗口宽,待显示的位置,颜色,待显示文字串的初址(这里采用16个char表示一个字符)
127 //附加:这里采用ASCII,字符串以0x00结尾,要调用putfont8()函数,这里可以和printf()函数连用将数据格式化为字符串类型
128 void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
129 {
130     extern char hankaku[4096];
131     for (; *s != 0x00; s++) {
132         putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
133         x += 8;
134     }
135     return;
136 }
137 
138 //-----------------------------------------------------------------------------------
139 //显示鼠标指针
140 //-----------------------------------------------------------------------------------
141 
142 /////////////////////////////////////////////////////////////////////////////////////
143 //功能:准备鼠标指针(16*16)
144 //参数:存放鼠标颜色信息的字符指针,窗口背景颜色
145 //附件:先定义一个cursor鼠标效果数组,然后转换为鼠标颜色数组(即,每一点应该涂什么颜色)
146 void init_mouse_cursor8(char *mouse, char bc)
147 {
148     static char cursor[16][16] = {
149         "**************..",
150         "*OOOOOOOOOOO*...",
151         "*OOOOOOOOOO*....",
152         "*OOOOOOOOO*.....",
153         "*OOOOOOOO*......",
154         "*OOOOOOO*.......",
155         "*OOOOOOO*.......",
156         "*OOOOOOOO*......",
157         "*OOOO**OOO*.....",
158         "*OOO*..*OOO*....",
159         "*OO*....*OOO*...",
160         "*O*......*OOO*..",
161         "**........*OOO*.",
162         "*..........*OOO*",
163         "............*OO*",
164         ".............***"
165     };//16*16的字节的内存
166     int x, y;
167 
168     for (y = 0; y < 16; y++) {//根据上面的鼠标数组建立一个绘制方案保存在mouse里
169         for (x = 0; x < 16; x++) {
170             if (cursor[y][x] == '*') {//边缘涂黑色
171                 mouse[y * 16 + x] = COL8_000000;
172             }
173             if (cursor[y][x] == 'O') {//内部涂白色
174                 mouse[y * 16 + x] = COL8_FFFFFF;
175             }
176             if (cursor[y][x] == '.') {//外部图背景色
177                 mouse[y * 16 + x] = bc;
178             }
179         }
180     }
181     return;
182 }
183 /////////////////////////////////////////////////////////////////////////////////////
184 //功能:绘制鼠标
185 //参数:VRAM初址,x轴像素,鼠标指针大小,位置,鼠标绘制方案,bxsize和pxsize大体相同
186 //附件:鼠标绘制方案即初始化函数得到的mouse,真正用的时候,先初始化,然后就可以用这个函数绘制鼠标啦
187 void putblock8_8(char *vram, int vxsize, int pxsize,
188     int pysize, int px0, int py0, char *buf, int bxsize)
189 {
190     int x, y;
191     for (y = 0; y < pysize; y++) {
192         for (x = 0; x < pxsize; x++) {
193             vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
194         }
195     }
196     return;
197 }
graphic.c

>_<" dsctbl.c主要负责GDT IDT分段相关。这里我们要定义两个结构体:SEGMENT_DESCRIPTOR 和 GATE_DESCRIPTOR,如下:

 1 /* dsctbl.c about GDT IDT that's Global Descriptor Table and Interrupt Descriptor Table*/
 2 struct SEGMENT_DESCRIPTOR {//8 bytes segment infomation,total 8192 parts [here similar to the method of the setting palette] 
 3     short limit_low, base_low;//address of segment base[high:mid:low=1:1:2]=4 bytes =32 bits
 4     char base_mid, access_right;//segment limit[high:low=1:2],only 20 bits = high byte's low 4 bits + low 2bytes' 16bits
 5     char limit_high, base_high;//segment property access[limit_high:right=1:1],only 12 bits = limit_high's high 4 bits + access_right's 8 bits
 6 };
 7 //PS 1):segment limit equals the number of GDT's effective bytes -1 
 8 //PS 2):the segment limit just only has 20 bits, which can represent 1MB, and the segment property has 1 bit flag, 
 9 //if this flag =1,and the limit's unit uses page to replace byte(here 1 page = 4kb) 
10 //PS 3):the segment property has 16 bits liking that:xxxx0000 xxxxxxxx 
11 //the high 4 bits are extended access
12 //the low 8 bits are:
13 //  0x00:unused description table
14 //  0x92:system exclusive,readable and writable,non-executable
15 //  0x9a:system exclusive,readable and non-writable,executable
16 //  0xf2:application useing,readable and writable,non-executable
17 //  0xfa:application useing,readable and non-writable,executable
18 
19 struct GATE_DESCRIPTOR {//
20     short offset_low, selector;
21     char dw_count, access_right;
22     short offset_high;
23 };

 1 /* dsctbl.c GDT IDT分段及中断相关 */
 2 
 3 #include "bootpack.h"
 4 
 5 
 6 /////////////////////////////////////////////////////////////////////////////////////
 7 //功能:
 8 //参数:
 9 //附件:
10 void init_gdtidt(void)
11 {
12     /*在bootpack.h文件里面定义了分段结构体和中断结构体,这里实例化gdt和idt*/
13     struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;//从0x00270000~0x0027ffff共8192个分段
14     struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) ADR_IDT;//从0x0026f800~0x0026ffff共256个分段
15     int i;
16 
17     /* GDT的初始化 */
18     for (i = 0; i <= LIMIT_GDT / 8; i++) {
19         set_segmdesc(gdt + i, 0, 0, 0);
20     }
21     //,上限,地址,属性
22     set_segmdesc(gdt + 1, 0xffffffff,   0x00000000, AR_DATA32_RW);//设定全局段
23     set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);//设定bootpack512字节的段
24     /* ;1) 这个函数用来指定的段上限和地址赋值给GDTR的48位寄存器,这是个很特殊的寄存器,并不能用MOV来直接赋值
25     ;,唯一的方法就是指定一个内存地址,从指定的内存地址读取6字节(也就是48位),然后赋值给GDTR寄存器。完成这一任务的指令就是LGDT
26     ;2) 该寄存器的低16位(即内存的最初的2个字节)是段上限,它等于“GDT的有效的字节数-1”,剩下的32位,代表GDT的开始地址
27     ;3) 这里2个参数是ESP+4和ESP+8里存放,而我们要的是6字节形式的,所以要转换为我们想要的形式~ */
28     load_gdtr(LIMIT_GDT, ADR_GDT);
29 
30     /* IDT的初始化 */
31     for (i = 0; i <= LIMIT_IDT / 8; i++) {
32         set_gatedesc(idt + i, 0, 0, 0);
33     }
34     load_idtr(LIMIT_IDT, ADR_IDT);
35 
36     /* IDT的設定 */
37     set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
38     set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
39     set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
40     set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
41     /*这里asm_inthadler21注册在idt的第0x21号,这样如果发生了中断,CPU就会自动调用asm_inthandler21.
42     这里的2*8表示asm_inthandler21属于哪一个段,即段号2,乘以8是因为低3位有别的意思,这低3位必须为0
43     这里段号为2的段在初始化的地方我们设置为bootpack全局段
44     最后的AR_INTGATE32将IDT的属性,设定为0x008e,表示用于中断处理的有效性
45     */
46     return;
47 }
48 
49 void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
50 {
51     if (limit > 0xfffff) {
52         ar |= 0x8000; /* G_bit = 1 */
53         limit /= 0x1000;
54     }
55     sd->limit_low    = limit & 0xffff;
56     sd->base_low     = base & 0xffff;
57     sd->base_mid     = (base >> 16) & 0xff;
58     sd->access_right = ar & 0xff;
59     sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
60     sd->base_high    = (base >> 24) & 0xff;
61     return;
62 }
63 
64 void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
65 {
66     gd->offset_low   = offset & 0xffff;
67     gd->selector     = selector;
68     gd->dw_count     = (ar >> 8) & 0xff;
69     gd->access_right = ar & 0xff;
70     gd->offset_high  = (offset >> 16) & 0xffff;
71     return;
72 }
dsctbl.c

>_<" int.c文件中是中断初始化函数和int27号中断句柄函数~另外鼠标和键盘的中断句柄放在了他们各自的.c文件中~

 1 /* the part of interrupt */
 2 
 3 #include "bootpack.h"
 4 #include <stdio.h>
 5 
 6 /////////////////////////////////////////////////////////////////////////////////////
 7 //功能:中断初始化函数
 8 //参数:无
 9 void init_pic(void)
10 /* PIC(programmable interrupt controller) initialize */
11 {
12     io_out8(PIC0_IMR,  0xff  ); /* disabled all interrupts */
13     io_out8(PIC1_IMR,  0xff  ); /* disabled all interrupts */
14 
15     io_out8(PIC0_ICW1, 0x11  ); /* edge trigger mode */
16     io_out8(PIC0_ICW2, 0x20  ); /* IRQ0-7 are received by INT20-27 */
17     io_out8(PIC0_ICW3, 1 << 2); /* PIC1 is connected by IRQ2 */
18     io_out8(PIC0_ICW4, 0x01  ); /* unbuffered mode */
19 
20     io_out8(PIC1_ICW1, 0x11  ); /* edge trigger mode */
21     io_out8(PIC1_ICW2, 0x28  ); /* IRQ8-15 are received by INT28-2f */
22     io_out8(PIC1_ICW3, 2     ); /* PIC1 is connnected by IRQ2 */
23     io_out8(PIC1_ICW4, 0x01  ); /* unbuffered mode */
24 
25     io_out8(PIC0_IMR,  0xfb  ); /* 11111011 disable all interrupts except PIC1 */
26     io_out8(PIC1_IMR,  0xff  ); /* 11111111 disable all interrupts */
27 
28     return;
29 }
30 
31 void inthandler27(int *esp)                         
32 {
33     io_out8(PIC0_OCW2, 0x67); /* IRQ-07受付完了をPICに通知 */
34     return;
35 }
int.c

>_<" fifo.c是存放FIFO结构及相关操作的函数集合,这里FIFO结构是用来存放鼠标、键盘等消息,用来在中断和普通函数之间传递消息~下面是FIFO的结构体及其说明。其功能函数包括初始化、放入、取出、读取FIFO状态等函数。

1 struct FIFO32 {//FIFO缓冲区数据结构
2     int *buf;//缓冲区
3     int p, q, size, free, flags;//下一个数据的写入地址,下一个数据的读出地址,缓冲区的大小,free是缓冲区没有数据的字节数,flag是是否溢出
4         struct TASK *task;//当FIFO中写数据的时候将任务唤醒,用于记录要唤醒任务的信息
5 };


fifo.c

>_<" memory.c是内存管理相关函数集,首先要定义两个结构体:FREEINFO(可用信息结构体),MEMMAN(内存管理结构体)。功能函数中包括内存检测、内存初始化、内存分配、内存释放等相关函数,其中以4K倍数分配和释放内存即找到不小于size的最小4k倍数的内存释放。

1 struct FREEINFO {    /* 可用信息 */
2     unsigned int addr, size;
3 };
4 struct MEMMAN {        /* 内存管理 */
5     int frees, maxfrees, lostsize, losts;
6     struct FREEINFO free[MEMMAN_FREES];
7 };

  1 /* 内存相关
  2 策略是先写入再读出看看是否一样,来确定是否正常,但是486以上的有高速缓存,所以要关闭高速缓存才行
  3  */
  4 
  5 #include "bootpack.h"
  6 
  7 #define EFLAGS_AC_BIT        0x00040000
  8 #define CR0_CACHE_DISABLE    0x60000000
  9 
 10 /////////////////////////////////////////////////////////////////////////////////////
 11 //参数:开始位置和结束位置
 12 //附加:(1)最初对EFLAGS处理,是检查CPU是486还是386.如果是486以上,EFLAGS寄存器的第18位应该是AC标志位
 13 //如果不是386就没有这一位,第18位一直为0,这里我们有意识的把1写到这一位,然后再读EFLAGS的值,继而
 14 //检查AC标志位是否为1.最后将AC标志位重置为0。(2)为了禁止缓存,需要对CR0寄存器的某一位置0,这里用的
 15 //是会编写的load_cr0和store_cr0
 16 unsigned int memtest(unsigned int start, unsigned int end)
 17 {
 18     char flg486 = 0;
 19     unsigned int eflg, cr0, i;
 20 
 21     /* 386偐丄486埲崀側偺偐偺妋擣 */
 22     eflg = io_load_eflags();
 23     eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 */
 24     io_store_eflags(eflg);
 25     eflg = io_load_eflags();
 26     if ((eflg & EFLAGS_AC_BIT) != 0) { /* 386偱偼AC=1偵偟偰傕帺摦偱0偵栠偭偰偟傑偆 */
 27         flg486 = 1;
 28     }
 29     eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0 */
 30     io_store_eflags(eflg);
 31 
 32     if (flg486 != 0) {
 33         cr0 = load_cr0();
 34         cr0 |= CR0_CACHE_DISABLE; /* 僉儍僢僔儏嬛巭 */
 35         store_cr0(cr0);
 36     }
 37 
 38     i = memtest_sub(start, end);
 39 
 40     if (flg486 != 0) {
 41         cr0 = load_cr0();
 42         cr0 &= ~CR0_CACHE_DISABLE; /* 僉儍僢僔儏嫋壜 */
 43         store_cr0(cr0);
 44     }
 45 
 46     return i;
 47 }
 48 /*
 49 /////////////////////////////////////////////////////////////////////////////////////
 50 //功能:检查区域内的内存是否有效,因为c编译器会清除掉一些东西,所以就只能用汇编写,见naskfunc.nas
 51 //参数:起始位置
 52 //附加:写入取反看看修改没,再取反看看修改没,如果两次都修改就认为是能够使用的内存
 53 unsigned int memtest_sub(unsigned int start,unsigned int end)
 54 {
 55     unsigned int i,*p,old,pat0=0xaa55aa55,pat1=0x55aa55aa;
 56     for(i=start;i<=end;i+=4){
 57         p=(unsigned int *)i;
 58         old=*p;
 59         *p=pat0;
 60         *p^=0xffffffff;
 61         if(*p!=pat1){
 62         not_memory:
 63             *p=old;
 64             break;            
 65         }
 66         *p^=0xffffffff;
 67         if(*p!=pat0){
 68             goto not_memory;
 69         }
 70         *p=old;
 71     }
 72     return i;
 73 }
 74 */
 75 
 76 
 77 /////////////////////////////////////////////////////////////////////////////////////
 78 //功能:初始化内存管理
 79 //参数:
 80 void memman_init(struct MEMMAN *man)
 81 {
 82     man->frees = 0;            /* 可用信息数目 */
 83     man->maxfrees = 0;        /* 用于观察可用信息状况,frees最大值 */
 84     man->lostsize = 0;        /* 释放失败的内存总和 */
 85     man->losts = 0;            /* 释放失败次数 */
 86     return;
 87 }
 88 
 89 /////////////////////////////////////////////////////////////////////////////////////
 90 //功能:获取空余内存的时际大小
 91 //参数:
 92 unsigned int memman_total(struct MEMMAN *man)
 93 {
 94     unsigned int i, t = 0;
 95     for (i = 0; i < man->frees; i++) {
 96         t += man->free[i].size;
 97     }
 98     return t;
 99 }
100 
101 /////////////////////////////////////////////////////////////////////////////////////
102 //功能:分配内存
103 //参数:大小
104 unsigned int memman_alloc(struct MEMMAN *man, unsigned int size)
105 {
106     unsigned int i, a;
107     for (i = 0; i < man->frees; i++) {
108         if (man->free[i].size >= size) {
109             //找到了足够大的内存
110             a = man->free[i].addr;
111             man->free[i].addr += size;
112             man->free[i].size -= size;
113             if (man->free[i].size == 0) {
114                 /* free[i]变成了0就减掉一条信息 */
115                 man->frees--;
116                 for (; i < man->frees; i++) {
117                     man->free[i] = man->free[i + 1]; /* 带入结构体 */
118                 }
119             }
120             return a;
121         }
122     }
123     return 0; /* 没有可用空间 */
124 }
125 
126 /////////////////////////////////////////////////////////////////////////////////////
127 //功能:内存释放
128 //参数:
129 int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size)
130 {
131     int i, j;
132     /* 为了方便归纳内存,将free[]按照addr的顺序排列 */
133     /* 所以,现决定应该放到哪里 */
134     for (i = 0; i < man->frees; i++) {
135         if (man->free[i].addr > addr) {
136             break;
137         }
138     }
139     /* free[i - 1].addr < addr < free[i].addr */
140     if (i > 0) {
141         /* 前面有可用内存 */
142         if (man->free[i - 1].addr + man->free[i - 1].size == addr) {
143             /* 可以与前面的可用内存归纳到一起 */
144             man->free[i - 1].size += size;
145             if (i < man->frees) {
146                 /* 后面也有 */
147                 if (addr + size == man->free[i].addr) {
148                     /* 也可与后面可用内存归纳到一起 */
149                     man->free[i - 1].size += man->free[i].size;
150                     /* man->free[i]删除 */
151                     /* free[i]变成0后归纳到前面去 */
152                     man->frees--;
153                     for (; i < man->frees; i++) {
154                         man->free[i] = man->free[i + 1]; /* 结构体赋值 */
155                     }
156                 }
157             }
158             return 0; /* 成功完成 */
159         }
160     }
161     /* 不能与前面的可用空间归纳到一起 */
162     if (i < man->frees) {
163         /* 后面有 */
164         if (addr + size == man->free[i].addr) {
165             /* 可以与后面的内容归纳到一起 */
166             man->free[i].addr = addr;
167             man->free[i].size += size;
168             return 0; /* 成功完成 */
169         }
170     }
171     /* 既不能与前面的内容归纳到一起,也不能与后面的内容归纳到一起,没有剩余的空间可以分配了 */
172     if (man->frees < MEMMAN_FREES) {
173         /* free[i]之后的,向后移动,腾出一点可用空间 */
174         for (j = man->frees; j > i; j--) {
175             man->free[j] = man->free[j - 1];
176         }
177         man->frees++;
178         if (man->maxfrees < man->frees) {
179             man->maxfrees = man->frees; /* 更新最大值 */
180         }
181         man->free[i].addr = addr;
182         man->free[i].size = size;
183         return 0; /* 成功完成 */
184     }
185     /* 不能后移 */
186     man->losts++;
187     man->lostsize += size;
188     return -1; /* 失败 */
189 }
190 
191 /////////////////////////////////////////////////////////////////////////////////////
192 //功能:
193 //参数:
194 unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size)
195 {
196     unsigned int a;
197     size = (size + 0xfff) & 0xfffff000;
198     a = memman_alloc(man, size);
199     return a;
200 }
201 
202 /////////////////////////////////////////////////////////////////////////////////////
203 //功能:
204 //参数:
205 int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size)
206 {
207     int i;
208     size = (size + 0xfff) & 0xfffff000;
209     i = memman_free(man, addr, size);
210     return i;
211 }
memory.c

>_<" mouse.c文件存放的是和鼠标消息处理相关,首先还是定义一个MOUSE_DEC的结构体,用来存放鼠标消息,如下。其功能函数包括鼠标事件响应句柄函数、鼠标使能函数、鼠标信息解码函数。其中鼠标信息解码是把鼠标发过来的原信息转换为相应的鼠标信息保存在鼠标结构体中。

1 struct MOUSE_DEC {
2     unsigned char buf[3], phase;
3     int x, y, btn;
4 };

 1 /* 鼠标相关函数 */
 2 
 3 #include "bootpack.h"
 4 
 5 struct FIFO32 *mousefifo;
 6 int mousedata0;
 7 
 8 /////////////////////////////////////////////////////////////////////////////////////
 9 //功能:PS/2的鼠标中断,一会在汇编中调用这个函数实现真正的中断:_asm_inthandler2c
10 void inthandler2c(int *esp)
11 {
12     unsigned char data;
13     io_out8(PIC1_OCW2, 0x64);     /* IRQ-12受付完了をPIC1に通知 */
14     io_out8(PIC0_OCW2, 0x62);     /* IRQ-02受付完了をPIC0に通知 */
15     data = io_in8(PORT_KEYDAT);
16     fifo32_put(mousefifo, data+mousedata0);
17     return;
18 }
19 
20 #define KEYCMD_SENDTO_MOUSE        0xd4
21 #define MOUSECMD_ENABLE            0xf4
22 /////////////////////////////////////////////////////////////////////////////////////
23 //功能:使能鼠标
24 //参数:
25 //附加:这个函数和init_keyboard十分相似,不同的在于输入的数据不同
26 //如果向键盘控制电路发送指令0xd4,下一数据就会自动发送给鼠标,利用这一特性来发送激活鼠标的指令
27 //其中答复消息为0xfa
28 void enable_mouse(struct FIFO32 *fifo,int data0,struct MOUSE_DEC *mdec)
29 {
30     //将FIFO缓冲区信息保存到全局变量
31     mousefifo=fifo;
32     mousedata0=data0;
33     //鼠标有效
34   wait_KBC_sendready();//让键盘控制电路做好准备,等待控制指令的到来
35   io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
36   wait_KBC_sendready();
37   io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
38   //顺利的话,ACK(0xfa)会被发送
39   mdec->phase = 0;//等待鼠标0xfa阶段
40   return;
41 }
42 /////////////////////////////////////////////////////////////////////////////////////
43 //功能:鼠标信息解码程序,把信息保存在鼠标结构体中
44 //参数:鼠标结构体,从缓冲区读取的数据
45 //附加:首先把最初读到的0xfa舍掉,之后从鼠标那里送过来的数据都应该是3个字节一组的,所以每当数据累计3字节时候就作相应处理[这里返回1]
46 //最后将鼠标的点击信息放在btn中,将鼠标的移动信息保存在x,y中
47 int mouse_decode(struct MOUSE_DEC *mdec, unsigned char dat)
48 {
49     if (mdec->phase == 0) {
50          /*等待鼠标的0xfa状态*/
51         if (dat == 0xfa) {
52             mdec->phase = 1;
53         }
54         return 0;
55     }
56     if (mdec->phase == 1) {
57         /*等待鼠标的第一字节*/
58         if ((dat & 0xc8) == 0x08) {
59             mdec->buf[0] = dat;
60             mdec->phase = 2;
61         }
62         return 0;
63     }
64     if (mdec->phase == 2) {
65         /*等待鼠标的第二字节*/
66         mdec->buf[1] = dat;
67         mdec->phase = 3;
68         return 0;
69     }
70     if (mdec->phase == 3) {
71         /*等待鼠标的第三字节,并作处理*/
72         mdec->buf[2] = dat;
73         mdec->phase = 1;//注意这里是恢复到1不是0,见附加说明,刚开始舍去0xfa以后每次3字节
74     /*下面是根据buf的3个数据进行计算鼠标信息
75     这里btn是buf[0]的低3位,最低位表示鼠标左击,中间表示鼠标中间被击,第3位表示鼠标右击
76     鼠标的x,和y坐标基本和buf[1],buf[2]相等,但是要根据buf[0]的前半部分作相应的变化:要么第8位及8位以后的全部设成1,或全部保留为0
77     */
78         mdec->btn = mdec->buf[0] & 0x07;
79         mdec->x = mdec->buf[1];
80         mdec->y = mdec->buf[2];
81         if ((mdec->buf[0] & 0x10) != 0) {
82             mdec->x |= 0xffffff00;
83         }
84         if ((mdec->buf[0] & 0x20) != 0) {
85             mdec->y |= 0xffffff00;
86         }
87         mdec->y = - mdec->y; /* 因为鼠标和屏幕的方向恰好相反,所以这里取反*/
88         return 1;
89     }
90     return -1; 
91 }
nouse.c
>_<" mtask.c是任务管理相关函数集,首先要声明4个结构体,分别是TSS32结构体,即任务状态段,用来保存任务的相关寄存器等信息,当发生中断时,将相关数据保存在此结构体中,当恢复中断时再将此结构体内的信息加载,从而实现中断前的保存现场和中断后的恢复现场的功能;Task结构体,即任务结构体,上面的TSS32仅仅是任务状态段,一个完整的任务还要包含任务的GDT号、优先级、FIFO缓冲区等信息,所以该任务结构体封装了这些信息用来保存一个任务;TASKLEVEL,是为了实现二维的优先级,所谓的二维优先级是当高优先级的层存在任务时低优先级的层的任务被屏蔽,任务只在高优先级层内进行切换;TASKCTL是任务管理结构体,负责记录所有任务的的信息。其功能函数包括初始化任务、分配任务、添加任务、删除任务、获取任务、切换任务、闲置任务、挂起任务等和任务相关的各种函数。
 1 struct TSS32 {//task status segment 任务状态段
 2     int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;//保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下会被写入)
 3     int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;//32位寄存器
 4     int es, cs, ss, ds, fs, gs;//16位寄存器
 5     int ldtr, iomap;//有关任务设置部分
 6 };
 7 struct TASK {
 8     int sel, flags; /* sel用来存放GDT的编号 */
 9     int level, priority;
10     struct FIFO32 fifo;//把FIFO绑定到任务里
11     struct TSS32 tss;
12 };
13 struct TASKLEVEL {
14     int running; /* 正在运行的任务量数 */
15     int now; /* 这个变量用来记录当前正在运行的任务是哪一个 */
16     struct TASK *tasks[MAX_TASKS_LV];
17 };
18 struct TASKCTL {
19     int now_lv; /* 正在运行的level */
20     char lv_change; /* 在下次任务切换时是否需要改变LEVEL */
21     struct TASKLEVEL level[MAX_TASKLEVELS];//最多10个level
22     struct TASK tasks0[MAX_TASKS];
23 };

 

 
  1 /* 任务管理相关程序 */
  2 
  3 #include "bootpack.h"
  4 
  5 struct TASKCTL *taskctl;
  6 struct TIMER *task_timer;
  7 
  8 /////////////////////////////////////////////////////////////////////////////////////
  9 //功能:用来返回现在活动中的struct TASK的内存地址
 10 //参数:
 11 struct TASK *task_now(void)
 12 {
 13     struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];
 14     return tl->tasks[tl->now];
 15 }
 16 /////////////////////////////////////////////////////////////////////////////////////
 17 //功能:向struct TASKLEVEL中添加一个任务
 18 //参数:
 19 void task_add(struct TASK *task)
 20 {
 21     struct TASKLEVEL *tl = &taskctl->level[task->level];//获取task的level
 22     tl->tasks[tl->running] = task;
 23     tl->running++;
 24     task->flags = 2; /* 活动中 */
 25     return;
 26 }
 27 /////////////////////////////////////////////////////////////////////////////////////
 28 //功能:从struct TASKLEVEL中删除一个任务,就是线性数组中删除一个数据类似的数据结构
 29 //参数:
 30 void task_remove(struct TASK *task)
 31 {
 32     int i;
 33     struct TASKLEVEL *tl = &taskctl->level[task->level];//获取task的level
 34 
 35     /* 寻找task所在的位置 */
 36     for (i = 0; i < tl->running; i++) {
 37         if (tl->tasks[i] == task) {
 38             break;
 39         }
 40     }
 41 
 42     tl->running--;
 43     if (i < tl->now) {
 44         tl->now--; /* 需要移动成员,所以要做相应的处理 */
 45     }
 46     if (tl->now >= tl->running) {//超出最大,回到最小
 47         tl->now = 0;
 48     }
 49     task->flags = 1; /* 休眠中 */
 50 
 51     /* 移动 */
 52     for (; i < tl->running; i++) {
 53         tl->tasks[i] = tl->tasks[i + 1];
 54     }
 55 
 56     return;
 57 }
 58 /////////////////////////////////////////////////////////////////////////////////////
 59 //功能:用来在任务时决定接下来切换到哪个LEVEL
 60 //参数:
 61 void task_switchsub(void)
 62 {
 63     int i;
 64     for (i = 0; i < MAX_TASKLEVELS; i++) {//寻找最上层的level
 65         if (taskctl->level[i].running > 0) {//从上层遍历,如果这一层当前运行的任务存在就返回这个level
 66             break; 
 67         }
 68     }
 69     taskctl->now_lv = i;
 70     taskctl->lv_change = 0;
 71     return;
 72 }
 73 /////////////////////////////////////////////////////////////////////////////////////
 74 //功能:闲置,不工作,只执行HLT
 75 //参数:
 76 void task_idle(void)
 77 {
 78     for (;;) {
 79         io_hlt();
 80     }
 81 }
 82 /////////////////////////////////////////////////////////////////////////////////////
 83 //功能:初始化任务控制
 84 //参数:
 85 //返回:返回一个内存地址,意思是现在正在运行这个程序,已经变成一个任务
 86 struct TASK *task_init(struct MEMMAN *memman)
 87 {
 88     int i;
 89     struct TASK *task, *idle;
 90     struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
 91     
 92     taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof (struct TASKCTL));//TASKCTL是个很大的结构体,所以要申请一个内存空间
 93     for (i = 0; i < MAX_TASKS; i++) {
 94         taskctl->tasks0[i].flags = 0;
 95         taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;
 96         set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);//定义在gdt的号,段长限制为103字节
 97     }
 98     for (i = 0; i < MAX_TASKLEVELS; i++) {//把每一层的level全都设置为0
 99         taskctl->level[i].running = 0;
100         taskctl->level[i].now = 0;
101     }
102     
103     task = task_alloc();
104     task->flags = 2; /* 活动中标志 */
105     task->priority = 2; //任务优先级//0.02s定时器
106     task->level = 0;    /* 第0层 */
107     task_add(task);        //加入level中
108     task_switchsub();    /* 用来任务切换时决定接下来切换到哪个LEVEL */
109     load_tr(task->sel);
110     //向TR寄存器写入这个值,因为刚才把当前运行任务的GDT定义为3号,TR寄存器是让CPU记住当前正在运行哪一个任务
111     //每当进行任务切换时,TR寄存器的值也会自动变换,task register
112     //每次给TR赋值的时候,必须把GDT的编号乘以8
113     task_timer = timer_alloc();
114     timer_settime(task_timer, task->priority);
115     
116     idle = task_alloc();
117     idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
118     idle->tss.eip = (int) &task_idle;
119     idle->tss.es = 1 * 8;
120     idle->tss.cs = 2 * 8;
121     idle->tss.ss = 1 * 8;
122     idle->tss.ds = 1 * 8;
123     idle->tss.fs = 1 * 8;
124     idle->tss.gs = 1 * 8;
125     task_run(idle, MAX_TASKLEVELS - 1, 1);//将idle放在最低优先级,当没有其他任务时,就处于这个任务,休眠
126     
127     return task;//这样开始的时候level0里只有一个任务
128 }
129 /////////////////////////////////////////////////////////////////////////////////////
130 //功能:任务分配[遍历所有的任务,发现任务处于空闲状态的进行初始化]
131 //参数:
132 struct TASK *task_alloc(void)
133 {
134     int i;
135     struct TASK *task;
136     for (i = 0; i < MAX_TASKS; i++) {
137         if (taskctl->tasks0[i].flags == 0) {
138             task = &taskctl->tasks0[i];
139             task->flags = 1; /* 正在使用标志 */
140             task->tss.eflags = 0x00000202; /* IF = 1; */
141             task->tss.eax = 0; /* 这里先设置为0 */
142             task->tss.ecx = 0;
143             task->tss.edx = 0;
144             task->tss.ebx = 0;
145             task->tss.ebp = 0;
146             task->tss.esi = 0;
147             task->tss.edi = 0;
148             task->tss.es = 0;
149             task->tss.ds = 0;
150             task->tss.fs = 0;
151             task->tss.gs = 0;
152             task->tss.ldtr = 0;//先这样设置
153             task->tss.iomap = 0x40000000;
154             return task;
155         }
156     }
157     return 0; /* 全部都正在使用 */
158 }
159 /////////////////////////////////////////////////////////////////////////////////////
160 //功能:在没有改变之前,task_run中下一个要切换的任务是固定不变的,不过现在就不同了,
161 //如果本次task_run启动一个比当前活动中的任务LEVEL更高的任务,那么下次任务切换时,就得无条件的切换到更高优先级的LEVEL中
162 //此外,如果当前任务中的LEVEL被下调,那么就得把其他LEVEL的有先任务放在前面
163 //综上所述:我们需要再下次切换时先检查LEVEL,因此将lv_change置为1
164 void task_run(struct TASK *task, int level, int priority)
165 {
166     if (level < 0) {
167         level = task->level; /* 不改变level */
168     }
169     if (priority > 0) {
170         task->priority = priority;
171     }
172 
173     if (task->flags == 2 && task->level != level) { /* 改变活动中的LEVEL */
174         task_remove(task); /* 这里执行之后flag的值会变为1,于是下面的语句也会被执行 */
175     }
176     if (task->flags != 2) {
177         /* 从休眠状态唤醒 */
178         task->level = level;
179         task_add(task);
180     }
181 
182     taskctl->lv_change = 1; /* 下次切换任务时检查LEVEL */
183     return;
184 }
185 /////////////////////////////////////////////////////////////////////////////////////
186 //功能:running为1的时候不用进行任务切换,函数直接结束,当running大于2的时候,先把now加1
187 //再把now代表的任务切换成当前的任务,最后再将末尾的任务移到开头
188 //参数:
189 void task_switch(void)
190 {
191     struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];//当前任务的LEVEL
192     struct TASK *new_task, *now_task = tl->tasks[tl->now];
193     tl->now++;
194     if (tl->now == tl->running) {
195         tl->now = 0;
196     }
197     if (taskctl->lv_change != 0) {//LEVEL之间变换了
198         task_switchsub();//用来在任务时决定接下来切换到哪个LEVEL,直接从头开始找,找到第一个LEVEL中有任务的返回
199         tl = &taskctl->level[taskctl->now_lv];
200     }
201     new_task = tl->tasks[tl->now];
202     timer_settime(task_timer, new_task->priority);
203     if (new_task != now_task) {
204         farjmp(0, new_task->sel);
205     }
206     return;
207 }
208 /////////////////////////////////////////////////////////////////////////////////////
209 //功能:任务休眠,从任务数组中删除该任务,如果处于正在运行的任务,就让其休眠
210 //参数:
211 void task_sleep(struct TASK *task)
212 {
213     struct TASK *now_task;
214     if (task->flags == 2) {
215         /* 如果处于活动状态 */
216         now_task = task_now();
217         task_remove(task); /* 执行此语句的话,flags将被置为1 remove其实就是从数组中删除一个*/
218         if (task == now_task) {
219             /* 如果让自己休眠需要进行任务切换 */
220             task_switchsub();
221             now_task = task_now(); /* 在设定后获取当前任务的值 */
222             farjmp(0, now_task->sel);
223         }
224     }
225     return;
226 }
mtask.c

>_<" sheet.c主要是窗口管理函数集,主要解决多窗口叠加问题,其中涉及刷屏,窗口叠加等,这里的多窗口的管理的数据结构和上面多任务管理的数据结构很像,都是采用链表的思路,这样插入删除都比较快速,加速了处理速度。其中结构体SHEET,即图层结构体,包括图层的大小、位置、高度、设置信息、描述窗口的缓冲区;结构体SHTCTL,即图层管理结构体,包括所有图层信息和当前最上层的图层的标记等信息。功能函数包括初始化图层控制、获取图层、设定图层、刷新图层、设定图层高度、设定图层位置、释放图层等和图层操作相关的函数。

 1 struct SHEET {//图层结构体
 2     unsigned char *buf;//所描绘内容的地址
 3     int bxsize, bysize, vx0, vy0, col_inv, height, flags;//图层大小,图层坐标,透明色色号,土层高度,存放有关图层的设定信息
 4     struct SHTCTL *ctl;
 5 };
 6 struct SHTCTL {//图层管理结构体
 7     unsigned char *vram, *map;
 8     int xsize, ysize, top;
 9     struct SHEET *sheets[MAX_SHEETS];
10     struct SHEET sheets0[MAX_SHEETS];
11 };//top存放最上面图层的高度,sheet0图层顺序混乱,要按照升序排列,然后将地址写入sheets中,方便使用

  1 /* 儅僂僗傗僂傿儞僪僂偺廳偹崌傢偣張棟 */
  2 
  3 #include "bootpack.h"
  4 
  5 #define SHEET_USE        1
  6 
  7 /////////////////////////////////////////////////////////////////////////////////////
  8 //功能:图层控制初始化
  9 //参数:
 10 struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize)
 11 {
 12     struct SHTCTL *ctl;
 13     int i;
 14     ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL));//分配内存为图层管理结构体
 15     if (ctl == 0) {
 16         goto err;
 17     }
 18     ctl->map = (unsigned char *) memman_alloc_4k(memman, xsize * ysize);
 19     if (ctl->map == 0) {
 20         memman_free_4k(memman, (int) ctl, sizeof (struct SHTCTL));
 21         goto err;
 22     }
 23     ctl->vram = vram;
 24     ctl->xsize = xsize;
 25     ctl->ysize = ysize;
 26     ctl->top = -1; /* 一个SHEET都没有 */
 27     for (i = 0; i < MAX_SHEETS; i++) {
 28         ctl->sheets0[i].flags = 0; /* 标记为未使用 */
 29         ctl->sheets0[i].ctl = ctl; /* 強懏傪婰榐 */
 30     }
 31 err:
 32     return ctl;
 33 }
 34 /////////////////////////////////////////////////////////////////////////////////////
 35 //功能:取得新生成未使用的图层,从最前面的开始找,找到就算
 36 //参数:
 37 struct SHEET *sheet_alloc(struct SHTCTL *ctl)
 38 {
 39     struct SHEET *sht;
 40     int i;
 41     for (i = 0; i < MAX_SHEETS; i++) {
 42         if (ctl->sheets0[i].flags == 0) {
 43             sht = &ctl->sheets0[i];
 44             sht->flags = SHEET_USE; /* 标记为正在使用 */
 45             sht->height = -1; /* 隐藏 */
 46             return sht;
 47         }
 48     }
 49     return 0;    /* 所有SHEET都处在正在使用的状态 */
 50 }
 51 /////////////////////////////////////////////////////////////////////////////////////
 52 //功能:设定涂层缓冲区的大小和透明色的函数
 53 //参数:
 54 void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv)
 55 {
 56     sht->buf = buf;
 57     sht->bxsize = xsize;
 58     sht->bysize = ysize;
 59     sht->col_inv = col_inv;
 60     return;
 61 }
 62 /////////////////////////////////////////////////////////////////////////////////////
 63 //功能:显示缓冲映射,可以有效解决闪烁问题
 64 //参数:
 65 void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0)
 66 {
 67     int h, bx, by, vx, vy, bx0, by0, bx1, by1;
 68     unsigned char *buf, sid, *map = ctl->map;
 69     struct SHEET *sht;
 70     if (vx0 < 0) { vx0 = 0; }
 71     if (vy0 < 0) { vy0 = 0; }
 72     if (vx1 > ctl->xsize) { vx1 = ctl->xsize; }
 73     if (vy1 > ctl->ysize) { vy1 = ctl->ysize; }
 74     for (h = h0; h <= ctl->top; h++) {
 75         sht = ctl->sheets[h];
 76         sid = sht - ctl->sheets0; /* 斣抧傪堷偒嶼偟偰偦傟傪壓偠偒斣崋偲偟偰棙梡 */
 77         buf = sht->buf;
 78         bx0 = vx0 - sht->vx0;
 79         by0 = vy0 - sht->vy0;
 80         bx1 = vx1 - sht->vx0;
 81         by1 = vy1 - sht->vy0;
 82         if (bx0 < 0) { bx0 = 0; }
 83         if (by0 < 0) { by0 = 0; }
 84         if (bx1 > sht->bxsize) { bx1 = sht->bxsize; }
 85         if (by1 > sht->bysize) { by1 = sht->bysize; }
 86         for (by = by0; by < by1; by++) {
 87             vy = sht->vy0 + by;
 88             for (bx = bx0; bx < bx1; bx++) {
 89                 vx = sht->vx0 + bx;
 90                 if (buf[by * sht->bxsize + bx] != sht->col_inv) {
 91                     map[vy * ctl->xsize + vx] = sid;
 92                 }
 93             }
 94         }
 95     }
 96     return;
 97 }
 98 /////////////////////////////////////////////////////////////////////////////////////
 99 //功能:刷新指定的区域(vx0, vy0, vx1, vy1)
100 //参数:
101 void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0, int h1)
102 {
103     int h, bx, by, vx, vy, bx0, by0, bx1, by1;
104     unsigned char *buf, *vram = ctl->vram, *map = ctl->map, sid;
105     struct SHEET *sht;
106     /* refresh超出画面则修正,解决鼠标跑画面外不出现的问题 */
107     if (vx0 < 0) { vx0 = 0; }
108     if (vy0 < 0) { vy0 = 0; }
109     if (vx1 > ctl->xsize) { vx1 = ctl->xsize; }
110     if (vy1 > ctl->ysize) { vy1 = ctl->ysize; }
111     for (h = h0; h <= h1; h++) {
112         sht = ctl->sheets[h];
113         buf = sht->buf;
114         sid = sht - ctl->sheets0;
115         /* 使用vx0~vy1,对bx0~by1进行倒推 */
116         bx0 = vx0 - sht->vx0;
117         by0 = vy0 - sht->vy0;
118         bx1 = vx1 - sht->vx0;
119         by1 = vy1 - sht->vy0;
120         if (bx0 < 0) { bx0 = 0; }
121         if (by0 < 0) { by0 = 0; }
122         if (bx1 > sht->bxsize) { bx1 = sht->bxsize; }
123         if (by1 > sht->bysize) { by1 = sht->bysize; }
124         for (by = by0; by < by1; by++) {
125             vy = sht->vy0 + by;
126             for (bx = bx0; bx < bx1; bx++) {
127                 vx = sht->vx0 + bx;
128                 if (map[vy * ctl->xsize + vx] == sid) {
129                     vram[vy * ctl->xsize + vx] = buf[by * sht->bxsize + bx];
130                 }
131             }
132         }
133     }
134     return;
135 }
136 /////////////////////////////////////////////////////////////////////////////////////
137 //功能:设定底板高度函数
138 //参数:
139 void sheet_updown(struct SHEET *sht, int height)
140 {
141     struct SHTCTL *ctl = sht->ctl;
142     int h, old = sht->height; /* 存储设置前的高度信息 */
143 
144     /* 指定高度过高过低都要修正 */
145     if (height > ctl->top + 1) {
146         height = ctl->top + 1;
147     }
148     if (height < -1) {
149         height = -1;
150     }
151     sht->height = height; /* 设定高度 */
152 
153     /* 主要是进行sheets[]的重新排列 */
154     if (old > height) {    /* 比以前低 */
155         if (height >= 0) {
156             /* 把中间的往上提 */
157             for (h = old; h > height; h--) {
158                 ctl->sheets[h] = ctl->sheets[h - 1];
159                 ctl->sheets[h]->height = h;
160             }
161             ctl->sheets[height] = sht;
162             sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1);
163             sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height + 1, old);
164         } else {    /* 隐藏 */
165             if (ctl->top > old) {
166                 /* 降下来 */
167                 for (h = old; h < ctl->top; h++) {
168                     ctl->sheets[h] = ctl->sheets[h + 1];
169                     ctl->sheets[h]->height = h;
170                 }
171             }
172             ctl->top--; /* 由于显示中图层少了一个,所以最上面的图层的高度下降 */
173             sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0);
174             sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, 0, old - 1);
175         }
176     } else if (old < height) {    /* 比以前高 */
177         if (old >= 0) {
178             /* 把中间的拉下去 */
179             for (h = old; h < height; h++) {
180                 ctl->sheets[h] = ctl->sheets[h + 1];
181                 ctl->sheets[h]->height = h;
182             }
183             ctl->sheets[height] = sht;
184         } else {    /* 由隐藏状态转为显示状态 */
185             /* 将已在上面的提上来 */
186             for (h = ctl->top; h >= height; h--) {
187                 ctl->sheets[h + 1] = ctl->sheets[h];
188                 ctl->sheets[h + 1]->height = h + 1;
189             }
190             ctl->sheets[height] = sht;
191             ctl->top++; /* 由于显示图层增加了一个,所以最上面的图层高度增加 */
192         }
193         sheet_refreshmap(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height);
194         sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize, height, height);
195     }
196     return;
197 }
198 /////////////////////////////////////////////////////////////////////////////////////
199 //功能:刷新屏幕函数
200 //参数:
201 void sheet_refresh(struct SHEET *sht, int bx0, int by0, int bx1, int by1)
202 {
203     if (sht->height >= 0) { /* 如果正在显示,按照新图层的信息刷新画面 */
204         sheet_refreshsub(sht->ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1, sht->height, sht->height);
205     }
206     return;
207 }
208 /////////////////////////////////////////////////////////////////////////////////////
209 //功能:上下左右移动窗口
210 //参数:
211 void sheet_slide(struct SHEET *sht, int vx0, int vy0)
212 {
213     struct SHTCTL *ctl = sht->ctl;
214     int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
215     sht->vx0 = vx0;//更新位置
216     sht->vy0 = vy0;
217     if (sht->height >= 0) { /* 如果正在显示,按照新图层刷新画面 */
218         sheet_refreshmap(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0);
219         sheet_refreshmap(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height);
220         sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize, 0, sht->height - 1);
221         sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize, sht->height, sht->height);
222     }
223     return;
224 }
225 /////////////////////////////////////////////////////////////////////////////////////
226 //功能:释放已使用图层的内存的函数
227 //参数:
228 void sheet_free(struct SHEET *sht)
229 {
230     if (sht->height >= 0) {
231         sheet_updown(sht, -1); /* 如果处于显示状态,则先隐藏 */
232     }
233     sht->flags = 0; /* 标记为未使用 */
234     return;
235 }
sheet.c

>_<" timer.c是定时器相关函数集,还是和图层和任务的管理方法很类似,首先定义一个计时器个体数据结构TIMER,用来保存一个定时器所需的信息,然后定义一个计时器管理数据结构TIMERCTL,用来整体管理计时器。功能函数包括初始化、分配、释放、设置以及中断处理函数。

 1 struct TIMER{
 2     struct TIMER *next;//用来指下一个即将超时的定时器地址
 3     unsigned int flags;//flags记录各个寄存器状态
 4     unsigned int timeout;//用来记录离超时还有多长时间,一旦这个剩余时间为0,程序就往FIFO缓冲区里发送数据,定时器就是用这种方法通知HariMain时间到了
 5     struct FIFO32 *fifo;//消息队列
 6     int data;//该定时器标志,用来向消息队列写的标志信息
 7 };
 8 struct TIMERCTL {
 9     unsigned int count, next;//next是下一个设定时间点,count是累加时间轴
10     struct TIMER *t0;//记录按照某种顺序存好的定时器地址,头指针
11     struct TIMER timers0[MAX_TIMER];
12 };

  1 /* PIT 定时器 */
  2 
  3 #include "bootpack.h"
  4 
  5 #define PIT_CTRL    0x0043
  6 #define PIT_CNT0    0x0040
  7 
  8 struct TIMERCTL timerctl;
  9 //struct TIMERCTL timerctl;//计数器结构体实例化
 10 #define TIMER_FLAGS_ALLOC                1        //已配置状态
 11 #define TIMER_FLAGS_USING                2        //定时器运行中
 12 
 13 /////////////////////////////////////////////////////////////////////////////////////
 14 //功能:定时器初始化,要3次OUT指令,(0x34->0x34)(中断周期低8位->0x40)(高8位->0x40)
 15 //参数:
 16 //附加:设置结果为主频/设置数,这里中断周期设置为0x2e9c,大约为100hz,具体搜:IRQ0中断周期变更PIT
 17 void init_pit(void)
 18 {
 19     int i;
 20     struct TIMER *t;
 21     io_out8(PIT_CTRL, 0x34);
 22     io_out8(PIT_CNT0, 0x9c);
 23     io_out8(PIT_CNT0, 0x2e);
 24     timerctl.count=0;//初始化计数为0
 25     for(i=0;i<MAX_TIMER;i++){//初始化所有定时器未使用
 26         timerctl.timers0[i].flags=0;//未使用
 27     }
 28     t=timer_alloc();//取得一个
 29     t->timeout=0xffffffff;
 30     t->flags=TIMER_FLAGS_USING;
 31     t->next=0;//末尾
 32     timerctl.t0=t;//现在就一个
 33     timerctl.next=0xffffffff;//下一个计时器为哨兵,所以下一个为无穷大
 34     return;
 35 }
 36 /////////////////////////////////////////////////////////////////////////////////////
 37 //功能:分配定时器
 38 //参数:
 39 struct TIMER *timer_alloc(void)
 40 {
 41     int i;
 42     for (i = 0; i < MAX_TIMER; i++) {//从开始开始找没有使用的定时器,找到后设置为分配状态,反回
 43         if (timerctl.timers0[i].flags == 0) {
 44             timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC;
 45             return &timerctl.timers0[i];
 46         }
 47     }
 48     return 0; /* 没有找到 */
 49 }
 50 /////////////////////////////////////////////////////////////////////////////////////
 51 //功能:释放定时器,直接把标志位设为0即可
 52 //参数:
 53 void timer_free(struct TIMER *timer)
 54 {
 55     timer->flags = 0; /* 未使用 */
 56     return;
 57 }
 58 /////////////////////////////////////////////////////////////////////////////////////
 59 //功能:初始化定时器,赋值fifo,设置标志位
 60 //参数:
 61 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data)
 62 {
 63     timer->fifo = fifo;
 64     timer->data = data;
 65     return;
 66 }
 67 /////////////////////////////////////////////////////////////////////////////////////
 68 //功能:设置timer
 69 //参数:输入定时时间
 70 void timer_settime(struct TIMER *timer, unsigned int timeout)
 71 {
 72     int e;
 73     struct TIMER *t,*s;
 74     timer->timeout = timeout + timerctl.count;//当前时间+定时器定时时间
 75     timer->flags = TIMER_FLAGS_USING;//设置成正在使用
 76     e = io_load_eflags();//保存寄存器,关中断
 77     io_cli();
 78 
 79     t=timerctl.t0;
 80     if (timer->timeout <= t->timeout) {
 81         /* 插入最前面的情况 */
 82         timerctl.t0 = timer;
 83         timer->next = t; /* 下面是设定t */
 84         timerctl.next = timer->timeout;
 85         io_store_eflags(e);
 86         return;
 87     }
 88     /* 搜寻插入位置 */
 89     for (;;) {
 90         s = t;
 91         t = t->next;
 92         if (timer->timeout <= t->timeout) {
 93             /* 插入s和t之间 */
 94             s->next = timer; /* s下一个是timer */
 95             timer->next = t; /* timer下一个是t */
 96             io_store_eflags(e);
 97             return;
 98         }
 99     }
100     return;
101 }
102 
103 /////////////////////////////////////////////////////////////////////////////////////
104 //功能:定时器中断处理程序,和键盘鼠标中断类似
105 //参数:
106 void inthandler20(int *esp)
107 {
108     char ts=0;//标记mt_timer任务切换计时器是否超时,如果直接在else语句直接调用任务切换会出现错误,因为这个中断处理还没完成
109     struct TIMER *timer;
110     io_out8(PIC0_OCW2, 0x60);    /* 把IRQ-00信号接受完了的信息通知给PIC */
111     timerctl.count++;
112     if (timerctl.next > timerctl.count) {//如果下一个还没计数完毕就直接返回
113         return;
114     }
115     timer = timerctl.t0; //把最前面的地址赋址给timer
116     for (;;) {
117         if (timer->timeout > timerctl.count) {
118             break;
119         }//从前往后遍历,一旦发现有计时未完成的计时器就跳出循环
120         /*除了上面的情况,都是定时已达的定时器*/
121         timer->flags = TIMER_FLAGS_ALLOC;
122         if(timer != task_timer){
123             fifo32_put(timer->fifo, timer->data);
124         }else{
125             ts=1;/* mt_timer超时 */
126         }
127         timer = timer->next;//下一个定时器的地址赋址给timer
128     }
129     timerctl.t0 = timer;//新移位
130     timerctl.next = timer->timeout;//timectl.next设定
131     if(ts!=0){
132         task_switch();
133     }
134     return;
135 }
timer.c

>_<" window.c从名字就能看出来主要负责绘制窗口的函数集。他们分别包括绘制窗口、绘制标题、显示字符串、绘制文本编辑框等函数~

 1 #include "bootpack.h"
 2 
 3 /////////////////////////////////////////////////////////////////////////////////////
 4 //功能:就像制作背景和鼠标一样,先准备一张图,然后在图层内描绘一个貌似窗口的图就可以了
 5 //参数:
 6 //附加:ACT为0时窗口标题栏是灰色,是1时是蓝色
 7 void make_window8(unsigned char *buf, int xsize, int ysize, char *title, char act)
 8 {
 9     boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         xsize - 1, 0        );
10     boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         xsize - 2, 1        );
11     boxfill8(buf, xsize, COL8_C6C6C6, 0,         0,         0,         ysize - 1);
12     boxfill8(buf, xsize, COL8_FFFFFF, 1,         1,         1,         ysize - 2);
13     boxfill8(buf, xsize, COL8_848484, xsize - 2, 1,         xsize - 2, ysize - 2);
14     boxfill8(buf, xsize, COL8_000000, xsize - 1, 0,         xsize - 1, ysize - 1);
15     boxfill8(buf, xsize, COL8_C6C6C6, 2,         2,         xsize - 3, ysize - 3);
16     boxfill8(buf, xsize, COL8_848484, 1,         ysize - 2, xsize - 2, ysize - 2);
17     boxfill8(buf, xsize, COL8_000000, 0,         ysize - 1, xsize - 1, ysize - 1);
18     make_wtitle8(buf,xsize,title,act);
19     return;
20 }
21 /////////////////////////////////////////////////////////////////////////////////////
22 //功能:画标题(供make_window8调用)
23 //参数:
24 void make_wtitle8(unsigned char *buf, int xsize, char *title, char act)
25 {
26     static char closebtn[14][16] = {//关闭标志
27         "OOOOOOOOOOOOOOO@",
28         "OQQQQQQQQQQQQQ$@",
29         "OQQQQQQQQQQQQQ$@",
30         "OQQQ@@QQQQ@@QQ$@",
31         "OQQQQ@@QQ@@QQQ$@",
32         "OQQQQQ@@@@QQQQ$@",
33         "OQQQQQQ@@QQQQQ$@",
34         "OQQQQQ@@@@QQQQ$@",
35         "OQQQQ@@QQ@@QQQ$@",
36         "OQQQ@@QQQQ@@QQ$@",
37         "OQQQQQQQQQQQQQ$@",
38         "OQQQQQQQQQQQQQ$@",
39         "O$$$$$$$$$$$$$$@",
40         "@@@@@@@@@@@@@@@@"
41     };
42     int x, y;
43     char c, tc, tbc;
44     if (act != 0) {//通过act标志选择2种不同的显示方式
45         tc = COL8_FFFFFF;//标题颜色
46         tbc = COL8_000084;//标题背景颜色
47     } else {
48         tc = COL8_C6C6C6;
49         tbc = COL8_848484;
50     }
51     boxfill8(buf, xsize, tbc,         3,         3,         xsize - 4, 20       );
52     putfonts8_asc(buf, xsize, 24, 4, tc, title);
53     for (y = 0; y < 14; y++) {
54         for (x = 0; x < 16; x++) {
55             c = closebtn[y][x];
56             if (c == '@') {
57                 c = COL8_000000;
58             } else if (c == '$') {
59                 c = COL8_848484;
60             } else if (c == 'Q') {
61                 c = COL8_C6C6C6;
62             } else {
63                 c = COL8_FFFFFF;
64             }
65             buf[(5 + y) * xsize + (xsize - 21 + x)] = c;
66         }
67     }
68     return;
69 }
70 /////////////////////////////////////////////////////////////////////////////////////
71 //功能:先图上背景颜色,再显示字符,最后完成刷新
72 //参数:图层,位置,字体颜色,背景颜色,字符串,字符串长度
73 void putfonts8_asc_sht(struct SHEET *sht, int x, int y, int c, int b, char *s, int l)
74 {
75     boxfill8(sht->buf, sht->bxsize, b, x, y, x + l * 8 - 1, y + 15);
76     putfonts8_asc(sht->buf, sht->bxsize, x, y, c, s);
77     sheet_refresh(sht, x, y, x + l * 8, y + 16);
78     return;
79 }
80 /////////////////////////////////////////////////////////////////////////////////////
81 //功能:描绘文字输入背景的
82 //参数:
83 void make_textbox8(struct SHEET *sht, int x0, int y0, int sx, int sy, int c)
84 {
85     int x1 = x0 + sx, y1 = y0 + sy;
86     boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 2, y0 - 3, x1 + 1, y0 - 3);
87     boxfill8(sht->buf, sht->bxsize, COL8_848484, x0 - 3, y0 - 3, x0 - 3, y1 + 1);
88     boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x0 - 3, y1 + 2, x1 + 1, y1 + 2);
89     boxfill8(sht->buf, sht->bxsize, COL8_FFFFFF, x1 + 2, y0 - 3, x1 + 2, y1 + 2);
90     boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 1, y0 - 2, x1 + 0, y0 - 2);
91     boxfill8(sht->buf, sht->bxsize, COL8_000000, x0 - 2, y0 - 2, x0 - 2, y1 + 0);
92     boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x0 - 2, y1 + 1, x1 + 0, y1 + 1);
93     boxfill8(sht->buf, sht->bxsize, COL8_C6C6C6, x1 + 1, y0 - 2, x1 + 1, y1 + 1);
94     boxfill8(sht->buf, sht->bxsize, c,           x0 - 1, y0 - 1, x1 + 0, y1 + 0);
95     return;
96 }
window.c

>_<" keyboard.c是键盘处理函数集,类似鼠标但是比鼠标的简单些,因为键盘在硬件设计上原来就考虑到了且其信息编码也不像鼠标的那么麻烦。所以,对于键盘处理的相关函数只有初始化、中断处理及附属的一些函数,没了鼠标的复杂的解码函数。同时也不用一个键盘结构体来存放消息,这里只用一个int类型的keydata0保存键盘消息。

 1 /* 键盘处理函数文件 */
 2 
 3 #include "bootpack.h"
 4 
 5 struct FIFO32 *keyfifo;
 6 int keydata0;
 7 
 8 /////////////////////////////////////////////////////////////////////////////////////
 9 //功能:PS/2的键盘中断,一会在汇编中调用这个函数实现真正的中断:_asm_inthandler21 
10 void inthandler21(int *esp)
11 {
12     int data;
13     io_out8(PIC0_OCW2, 0x61);    /* IRQ-01庴晅姰椆傪PIC偵捠抦 */
14     data = io_in8(PORT_KEYDAT);
15     fifo32_put(keyfifo, keydata0+data);
16     return;
17 }
18 
19 #define PORT_KEYSTA                0x0064
20 #define KEYSTA_SEND_NOTREADY    0x02
21 #define KEYCMD_WRITE_MODE        0x60
22 #define KBC_MODE                0x47
23 /////////////////////////////////////////////////////////////////////////////////////
24 //功能:等待键盘控制电路准备完毕
25 //参数:无
26 //附加:如果键盘控制电路可以接受CPU指令,CPU从设备号码0x0064处所读取的数据的倒数第二位应该是0,否则就一种循环等待
27 void wait_KBC_sendready(void)
28 {
29     for (;;) {
30         if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
31             break;
32         }
33     }
34     return;
35 }
36 
37 void init_keyboard(struct FIFO32 *fifo,int data0)//初始化键盘控制电路
38 {
39     /*将FIFO缓冲区里的信息保存到全局变量里*/
40     keyfifo=fifo;
41     keydata0=data0;
42     //键盘控制器初始化
43   wait_KBC_sendready();//让键盘控制电路做好准备,等待控制指令的到来
44   io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);//键盘模式设置指令
45   wait_KBC_sendready();
46   io_out8(PORT_KEYDAT, KBC_MODE);//鼠标模式设置指令
47   return;
48 }
keyboard.c

>_<" file.c是负责读取磁盘映像中的文件读出,如最上面的那副图蓝色2的部分,把3个文件读到操作系统磁盘映像,当操作系统运行时,想把这些内容读出,就要把FAT解压,同时根据文件保存格式解析文件信息,因此这里要定义一个FILEINFO,即文件信息结构体。

1 struct FILEINFO {
2     unsigned char name[8], ext[3], type;
3     char reserve[10];
4     unsigned short time, date, clustno;
5     unsigned int size;
6 };//修改MakeFile中的语句,将haribote.sys、ipl10.nas、make.bat这3个文件制成操作系统镜像
7 //这样磁盘映像中0x002600字节以后的部分8(文件名)+3(文件格式)+1(文件属性)+10(留待)+2(时间)+2(日期)+2(簇号)+4(大小)字节

 1 #include "bootpack.h"
 2 
 3 /////////////////////////////////////////////////////////////////////////////////////
 4 //功能:将磁盘映像中的FAT解压缩
 5 //参数:展开到fat[],img为磁盘地址
 6 //附加:如果按照16b的方法type肯定可以正确显示文件开头的512字节的内容,如果遇到大于512字节的文件,可能就会显示出其他文件的内容
 7 //按照windows管理磁盘的方法,保存大于512字节的文件时,有时并不是存入连续的扇区中,虽然这种情况不多~
 8 //其实对于文件下一段存放在哪里,在磁盘里是有记录的,我们只要分析这个记录就能正确读取文件内容了,这个记录称为FAT"file allocation table"
 9 //文件分配表,补充一下,在磁盘中没有存放在连续的扇区,就称为磁盘碎片
10 //但是FAT中的是直接不可看懂的,要解压:F0 FF FF -> FF0 FFF
11 //其实这种记录方法如果一旦坏了,就会混乱,为此磁盘中放了2个FAT,第一个位于0x000200~0x0013ff;第二个位于0x001400~0x0025ff
12 void file_readfat(int *fat, unsigned char *img)
13 {
14     int i, j = 0;
15     for (i = 0; i < 2880; i += 2) {
16         fat[i + 0] = (img[j + 0]      | img[j + 1] << 8) & 0xfff;
17         fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff;
18         j += 3;
19     }
20     return;
21 }
22 /////////////////////////////////////////////////////////////////////////////////////
23 //功能:将文件的内容读入内存,这样文件的内容已经排列为正确的顺序
24 //参数:
25 void file_loadfile(int clustno, int size, char *buf, int *fat, char *img)
26 {
27     int i;
28     for (;;) {
29         if (size <= 512) {//读取内存直接读好退出
30             for (i = 0; i < size; i++) {
31                 buf[i] = img[clustno * 512 + i];
32             }
33             break;
34         }
35         for (i = 0; i < 512; i++) {//当大于512时就分别读
36             buf[i] = img[clustno * 512 + i];
37         }
38         size -= 512;
39         buf += 512;
40         clustno = fat[clustno];
41     }
42     return;
43 }
44 /////////////////////////////////////////////////////////////////////////////////////
45 //功能:寻找文件
46 //参数:
47 struct FILEINFO *file_search(char *name, struct FILEINFO *finfo, int max)
48 {
49     int i, j;
50     char s[12];
51     for (j = 0; j < 11; j++) {
52         s[j] = ' ';
53     }//初始化s[]让其为空格
54     j = 0;
55     for (i = 0; name[i] != 0; i++) {
56         if (j >= 11) { return 0; /* 没有找到 */ }
57         if (name[i] == '.' && j <= 8) {
58             j = 8;
59         } else {
60             s[j] = name[i];
61             if ('a' <= s[j] && s[j] <= 'z') {
62                 /* 转换为小写 */
63                 s[j] -= 0x20;
64             } 
65             j++;
66         }
67     }//将名字转换为12字节的8+3名字+扩展名的存储模式,便于比较
68     for (i = 0; i < max; ) {
69         if (finfo[i].name[0] == 0x00) {
70             break;
71         }//不存在文件直接退出
72         if ((finfo[i].type & 0x18) == 0) {
73             for (j = 0; j < 11; j++) {
74                 if (finfo[i].name[j] != s[j]) {
75                     goto next;
76                 }
77             }
78             return finfo + i; /* 找到返回 */
79         }
80 next:
81         i++;
82     }
83     return 0; /* 没有找到 */
84 }
file.c

>_<" console.c是命令行及命令行的黑框相关的函数集合。因为有命令行窗口所以就需要定义一个CONSOLE结构体来保存窗口SHEET和当前的位置及背景颜色。这里命令行窗口是一个新的任务,所以存在console_task用来作为该任务的入口,也就相当于bootpack.c里的main函数,这里的新任务就像一个独立的部分做独立的运行与处理,这一点可以在多任务那部分找到的。而其他的几个函数是负责被该主函数调用实现命令行功能的功能函数。对于命令行命令这里封装成cons_runcmd函数,然后通过调用下面的CMD命令函数,实现cmd命令的功能。这里只有mem、hit、type、dir、cls命令,如果今后想扩展只要在这里写心得cmd命令函数然后在con_runcmd里加入相应的处理即可以了。其中hlt命令是运行独立的程序,如最上面的图中把hlt.asm程序编译并载入磁盘映像,在此处调用读磁盘函数,加载该应用程序并执行,实现了操作系统上运行应用程序的功能。

1 struct CONSOLE {
2     struct SHEET *sht;//console窗口图层
3     int cur_x, cur_y, cur_c;//当前位置和颜色
4 };

 

  1 #include "bootpack.h"
  2 #include <string.h>
  3 #include <stdio.h>
  4 
  5 /////////////////////////////////////////////////////////////////////////////////////
  6 //功能:consloe窗口任务
  7 //参数:
  8 void console_task(struct SHEET *sheet, unsigned int memtotal)
  9 {
 10     struct TIMER *timer;
 11     struct TASK *task = task_now();//需要自己休眠,就要获取自己的任务地址
 12     struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;//内存
 13     int i, fifobuf[128], *fat = (int *) memman_alloc_4k(memman, 4 * 2880);//先分配一个内存用来存解压后的FAT
 14     struct CONSOLE cons;//consloe类
 15     char cmdline[30];//命令行
 16     cons.sht = sheet;
 17     cons.cur_x =  8;
 18     cons.cur_y = 28;
 19     cons.cur_c = -1;
 20     
 21     fifo32_init(&task->fifo, 128, fifobuf, task);
 22     timer = timer_alloc();//分配时钟
 23     timer_init(timer, &task->fifo, 1);
 24     timer_settime(timer, 50);
 25     file_readfat(fat, (unsigned char *) (ADR_DISKIMG + 0x000200));//读取第一个FAT解压为fat中,第一个位于0x000200~0x0013ff
 26     
 27     cons_putchar(&cons, '>', 1);//显示提示符
 28     
 29     for (;;) {
 30         io_cli();
 31         if (fifo32_status(&task->fifo) == 0) {//没有数据就休眠
 32             task_sleep(task);
 33             io_sti();
 34         } else {//有数据就处理
 35             i = fifo32_get(&task->fifo);
 36             io_sti();
 37             if (i <= 1) {//光标定时器 
 38                 if (i != 0) {
 39                     timer_init(timer, &task->fifo, 0); 
 40                     if (cons.cur_c >= 0) {
 41                         cons.cur_c = COL8_FFFFFF;
 42                     }
 43                 } else {
 44                     timer_init(timer, &task->fifo, 1); 
 45                     if (cons.cur_c >= 0) {
 46                         cons.cur_c = COL8_000000;
 47                     }
 48                 }
 49                 timer_settime(timer, 50);
 50             }
 51             if(i==2){//光标ON
 52                 cons.cur_c = COL8_FFFFFF;
 53             }
 54             if(i==3){//光标OFF
 55                 boxfill8(sheet->buf, sheet->bxsize, COL8_000000, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15);
 56                 cons.cur_c = -1;
 57             }
 58             if(256 <= i && i <= 511) { /* 键盘数据,通过任务A */
 59                 if (i == 8 + 256) {
 60                     if (cons.cur_x > 16) {//退格键
 61                         /* 用空白擦除光标后将光标前移一位 */
 62                         cons_putchar(&cons, ' ', 0);
 63                         cons.cur_x -= 8;
 64                     }
 65                 } else if(i == 10+256){//回车键
 66                     //用空格将光标擦除
 67                     cons_putchar(&cons, ' ', 0);
 68                     cmdline[cons.cur_x / 8 - 2] = 0;
 69                     cons_newline(&cons);
 70                     cons_runcmd(cmdline, &cons, fat, memtotal);    /* 运行命令行 */
 71                     /* 显示提示符 */
 72                     cons_putchar(&cons, '>', 1);
 73                 }else{
 74                     /* 一般字符 */
 75                     if (cons.cur_x < 240) {
 76                         /* 显示一个字符后将光标后移一位 */
 77                         cmdline[cons.cur_x / 8 - 2] = i - 256;
 78                         cons_putchar(&cons, i - 256, 1);
 79                     }
 80                 }
 81             }
 82             //重新显示光标
 83             if (cons.cur_c >= 0) {
 84                 boxfill8(sheet->buf, sheet->bxsize, cons.cur_c, cons.cur_x, cons.cur_y, cons.cur_x + 7, cons.cur_y + 15);
 85             }
 86             sheet_refresh(sheet, cons.cur_x, cons.cur_y, cons.cur_x + 8, cons.cur_y + 16);
 87         }
 88     }
 89 }
 90 /////////////////////////////////////////////////////////////////////////////////////
 91 //功能:在console里输入字符
 92 //参数:move为0时光标不后移
 93 void cons_putchar(struct CONSOLE *cons, int chr, char move)
 94 {
 95     char s[2];
 96     s[0] = chr;
 97     s[1] = 0;
 98     //制表符是用来对其字符的显示位置,遇到制表符就显示4个空格是不正确的,而是在当前位置和下一个制表符之间填充空格~
 99     if (s[0] == 0x09) {    /* 制表符 */
100         for (;;) {
101             putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, " ", 1);
102             cons->cur_x += 8;
103             if (cons->cur_x == 8 + 240) {//超出就换行
104                 cons_newline(cons);
105             }
106             if (((cons->cur_x - 8) & 0x1f) == 0) {//减8就是减去边界,&0x1f是求其%32的余数,每隔制表符为4字符
107                 break;
108             }
109         }
110     } else if (s[0] == 0x0a) {    /* 换行 */
111         cons_newline(cons);
112     } else if (s[0] == 0x0d) {    /* 回车 */
113         /* 暂时不做任何事 */
114     } else {    /* 一般字符 */
115         putfonts8_asc_sht(cons->sht, cons->cur_x, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 1);
116         if (move != 0) {
117             /* move为0时光标不后移 */
118             cons->cur_x += 8;
119             if (cons->cur_x == 8 + 240) {
120                 cons_newline(cons);
121             }
122         }
123     }
124     return;
125 }
126 /////////////////////////////////////////////////////////////////////////////////////
127 //功能:换行与滚动,独立出来~
128 //参数:
129 void cons_newline(struct CONSOLE *cons)
130 {
131     int x, y;
132     struct SHEET *sheet = cons->sht;
133     //换行与滚动屏幕
134     if (cons->cur_y < 28 + 112) {
135         cons->cur_y += 16; /* 换行 */
136     } else {
137         /* 滚动 */
138         for (y = 28; y < 28 + 112; y++) {//向上移动一行
139             for (x = 8; x < 8 + 240; x++) {
140                 sheet->buf[x + y * sheet->bxsize] = sheet->buf[x + (y + 16) * sheet->bxsize];
141             }
142         }
143         for (y = 28 + 112; y < 28 + 128; y++) {//将最后一行覆盖(这里的行是6个)
144             for (x = 8; x < 8 + 240; x++) {
145                 sheet->buf[x + y * sheet->bxsize] = COL8_000000;
146             }
147         }
148         sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
149     }
150     cons->cur_x = 8;
151     return;
152 }
153 /////////////////////////////////////////////////////////////////////////////////////
154 //功能:运行窗口命令
155 //参数:
156 void cons_runcmd(char *cmdline, struct CONSOLE *cons, int *fat, unsigned int memtotal)
157 {
158     if (strcmp(cmdline, "mem") == 0) {
159         cmd_mem(cons, memtotal);
160     } else if (strcmp(cmdline, "cls") == 0) {
161         cmd_cls(cons);
162     } else if (strcmp(cmdline, "dir") == 0) {
163         cmd_dir(cons);
164     } else if (strncmp(cmdline, "type ", 5) == 0) {
165         cmd_type(cons, fat, cmdline);
166     } else if (strcmp(cmdline, "hlt") == 0) {
167         cmd_hlt(cons, fat);
168     } else if (cmdline[0] != 0) {
169         /* 不是命令也不是空行 */
170         putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, "Bad command.", 12);
171         cons_newline(cons);
172         cons_newline(cons);
173     }
174     return;
175 }
176 /////////////////////////////////////////////////////////////////////////////////////
177 //功能:mem命令,获取系统内存信息并显示
178 //参数:
179 void cmd_mem(struct CONSOLE *cons, unsigned int memtotal)
180 {
181     struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
182     char s[30];
183     sprintf(s, "total   %dMB", memtotal / (1024 * 1024));
184     putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 30);
185     cons_newline(cons);
186     sprintf(s, "free %dKB", memman_total(memman) / 1024);
187     putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 30);
188     cons_newline(cons);
189     cons_newline(cons);
190     return;
191 }
192 /////////////////////////////////////////////////////////////////////////////////////
193 //功能:cls命令,清屏
194 //参数:
195 void cmd_cls(struct CONSOLE *cons)
196 {
197     int x, y;
198     struct SHEET *sheet = cons->sht;
199     for (y = 28; y < 28 + 128; y++) {
200         for (x = 8; x < 8 + 240; x++) {
201             sheet->buf[x + y * sheet->bxsize] = COL8_000000;
202         }
203     }
204     sheet_refresh(sheet, 8, 28, 8 + 240, 28 + 128);
205     cons->cur_y = 28;
206     return;
207 }
208 /////////////////////////////////////////////////////////////////////////////////////
209 //功能:dir命令,查看文件
210 //参数:
211 void cmd_dir(struct CONSOLE *cons)
212 {
213     struct FILEINFO *finfo = (struct FILEINFO *) (ADR_DISKIMG + 0x002600);
214     int i, j;
215     char s[30];
216     for (i = 0; i < 224; i++) {
217         if (finfo[i].name[0] == 0x00) {//没有任何文件信息
218             break;
219         }
220         if (finfo[i].name[0] != 0xe5) {//表明该文件已经被删除0xe5
221             if ((finfo[i].type & 0x18) == 0) {//一般文件不是0x20就是0x00
222                 sprintf(s, "filename.ext   %7d", finfo[i].size);
223                 for (j = 0; j < 8; j++) {
224                     s[j] = finfo[i].name[j];
225                 }
226                 s[ 9] = finfo[i].ext[0];
227                 s[10] = finfo[i].ext[1];
228                 s[11] = finfo[i].ext[2];
229                 putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, s, 30);
230                 cons_newline(cons);
231             }
232         }
233     }
234     cons_newline(cons);
235     return;
236 }
237 /////////////////////////////////////////////////////////////////////////////////////
238 //功能:type命令,查看文件内容
239 //参数:
240 void cmd_type(struct CONSOLE *cons, int *fat, char *cmdline)
241 {
242     struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
243     struct FILEINFO *finfo = file_search(cmdline + 5, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
244     char *p;
245     int i;
246     if (finfo != 0) {
247         /* 找到文件的情况 */
248         p = (char *) memman_alloc_4k(memman, finfo->size);//分配一个和文件大小一样的内存
249         file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));//将文件的内容读入内存,这样文件的内容已经排列为正确的顺序
250         for (i = 0; i < finfo->size; i++) {//输出内容,掉用cons_putchar函数
251             cons_putchar(cons, p[i], 1);
252         }
253         memman_free_4k(memman, (int) p, finfo->size);//释放内存
254     } else {
255         /* 没有找到文件的情况 */
256         putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, "File not found.", 15);
257         cons_newline(cons);
258     }
259     cons_newline(cons);//新行
260     return;
261 }
262 /////////////////////////////////////////////////////////////////////////////////////
263 //功能:hlt命令,运行hlt程序
264 //参数:
265 void cmd_hlt(struct CONSOLE *cons, int *fat)
266 {
267     struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
268     struct FILEINFO *finfo = file_search("HLT.HRB", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);
269     struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
270     char *p;
271     if (finfo != 0) {
272         /* 有文件 */
273         p = (char *) memman_alloc_4k(memman, finfo->size);//申请一个内存地址大小一样的p
274         file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));//读取FAT到p
275         set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);//将hlt.hrb读入内存后将其注册为GDT1003号,因为1~2号右dsctbl.c用,而3~1002号由mtask.c
276         farjmp(0, 1003 * 8);//然后调用跳转运行
277         memman_free_4k(memman, (int) p, finfo->size);//释放内存
278     } else {
279         /* 无文件 */
280         putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, "File not found.", 15);
281         cons_newline(cons);
282     }
283     cons_newline(cons);
284     return;
285 }
console.c

>_<" 相关链接~

上述工程代码链接:http://pan.baidu.com/s/1pJkGdwn

[自制简单操作系统] 1、从0-1到汇编再到c语言的奥秘:http://www.cnblogs.com/zjutlitao/p/3945852.html

[自制简单操作系统] 2、鼠标及键盘中断处理事件[PIC\GDT\IDT\FIFO]:http://www.cnblogs.com/zjutlitao/p/3961048.html

[自制简单操作系统] 3、内存管理和窗口叠加:http://www.cnblogs.com/zjutlitao/p/3979306.html

[自制简单操作系统] 4、计时器(线性表实现优化中断):http://www.cnblogs.com/zjutlitao/p/3983279.html

[自制简单操作系统] 5、杂七杂八(高分辨率和键盘输入):http://www.cnblogs.com/zjutlitao/p/3991839.html

[自制简单操作系统] 6、多任务(一):http://www.cnblogs.com/zjutlitao/p/3993403.html

[自制简单操作系统] 7、多任务(二)——任务管理自动化&任务休眠:http://www.cnblogs.com/zjutlitao/p/3994405.html

[自制简单操作系统] 8、多任务(三)——多窗口与优先级http://www.cnblogs.com/zjutlitao/p/3995814.html

 

 

 

posted @ 2014-10-12 20:23  beautifulzzzz  阅读(1702)  评论(0编辑  收藏  举报