[自制简单操作系统] 9、命令行与应用程序 整体回顾
>_<" 下面是整个操作系统的编译框架,这里bootpack是主程序部分,通过调用其他.c文件里的功能函数及必须用汇编写的功能函数(naskfun.nas)来实现操作系统的各项功能,这里统一把他们编译集成到bootpack.bim中,ipl10.asm是引导部分,asmhead.asm是用汇编写的用来实现汇编和C语言的桥梁及一些初始32位编程的设置。此外为了实现命令行读取文件和运行应用程序的功能,这里把2号蓝色的部分文件也加载到操作系统。此外这里1号红色框内展示的是c文件和字库转换成obj的具体过程。
>_<" naskfunc.nas主要是C语言有些函数无法实现必须用汇编实现,这里就是那些汇编实现的功能函数:它们包括让CPU休眠的函数,开中断,关中断,IO读写,获取某个特定寄存器或给某个特定寄存器赋值函数以及far jmp功能函数。
>_<" 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 }
>_<" 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 }
>_<" 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 }
>_<" 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 };
>_<" 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 }
>_<" 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 }
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 }
>_<" 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 }
>_<" 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 }
>_<" 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 }
>_<" 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 }
>_<" 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 }
>_<" 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 }
>_<" 相关链接~
上述工程代码链接: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