1、8086汇编和c语言混合实现操作系统实验三一、实验目的1. 掌握TASM汇编语言与TURBO C语言汇合编程的方法。2. 实现内核与引导程序分离,掌握软盘上引导操作系统方法。3. 设计并实现一种简单的作业控制语言,建立具有较友好的控制命令的批处理原型操作系统,掌握操作系统提供用户界面和内部功能的实现方法。二、实验内容在实验二的基础上,进化你的原型操作系统,增加下列操作系统功能:(1)将原型操作系统分离为引导程序和MYOS内核,由引导程序加载内核;(2)内核由汇编语言kernal.asm和c语言kernal.c二个模块生成;(3)利用C语言实现作业控制语言mJCB,原型操作系统在当前行显示一个指
2、示符(可以是简单的一个字符或你的学号之类),允许用户输入一行命令(回车结束,语法由你设计),操作系统解释命令并完成相应的功能(3个以上的内置功能,如time、date、asc等,而且能执行软盘上的某个用户程序),并在你的实验报告中详细介绍你的mJCB语言的语法格式和功能。三、实验报告1、涉及的基础知识和实验环境工具综述、你的解决方案包括程序算法原理或流程图、程序模块说明、变量定义与作用说明、数据结构组织等A实验环境工具综述:本次试验环境为VMware9平台上搭建的8086虚拟机,编译器为tasm,tcc,链接器为tlink,通过Winhex剪辑2进制文件,并用DiskWriter工具将主程序写
3、入虚拟软盘,通过虚拟机加载软盘实现裸机运行。B算法原理:a)计算机启动后,通过引导扇区加载软盘上余下的有效扇区。b)引导扇区安装必要的中断,如8号中断用以动态显示时间,21号中断用以用户程序的返回,设置栈指针,数据段指针,建立c语言运行环境,设置计数器,用以动态显示时间。配置完成后,转入基于c语言的控制程序的运行。c)基于c语言的控制程序无限重复向输入端请求命令,解析命令,跳转调用对应程序,但接收到重启命令时重启,接到关机命令时进行关机。d)系统总的实现为引导程序(osa.asm),汇编实现的c语言函数库(clib.asm),汇编实现的中断程序库(oslib.asm),c语言实现的控制台程序(
4、osc.c)。e)由于系统已搭建c语言运行环境,并提供了相应的库,再提供一个供用户用于链接c语言程序的启动程序,用户程序即可完全由c语言实现。启动程序指定用户程序的偏移(如c9000.asm指定了用户的c程序偏移为9000h,可更改启动程序中的org来更改目标程序的偏移),并能够返回控制台(通过调用自己安装的int 21H返回)。C程序模块说明:a)clib.asm中汇编实现的c函数库extern char cls(); 功能:清屏,清空第0页的显存 输入:无 返回:无extern int puts(const char * str); 功能:向当前光标位置输出字符串 输入:字符串首地址 返回
5、:输出字符个数extern char* gets(char* str); 功能:读取字符串 输入:字符串首地址 返回:字符串首地址extern int strlen(const char *str); 功能:求以0结束的字符串的长度 输入:字符串首地址 返回:字符从长度extern int getchar(void); 功能:读取字符 输入:无 返回:字符的ascii码extern int putchar(int c); 功能:输出字符 输入:字符c 返回:字符cextern unsigned int port_in8(unsigned int port); 功能:从port端口读入8位数据
6、输入:端口号 返回:读取的数据extern unsigned int port_in16(unsigned int port); 功能:从port端口读入16位数据 输入:端口号 返回:读取的数据extern void port_out8(unsigned int port, unsigned int value); 功能:向port端口输出8位数据value 输入:端口号和数据 返回:无 extern void port_out16(unsigned int port, unsigned int value); 功能:从port端口输出16位数据value 输入:端口号和数据 返回:无ext
7、ern void setp_cursor(unsigned int bh, unsigned int dh, unsigned int dl); 功能:将第bh页的指针置于dh行dl列 输入:页号bh,行号dh,列号dl 返回:无extern void run_pro(int ord); 功能:运行程序地址表中第ord号程序 输入:程序序号 返回:无b)主控制程序:osc.cextern char cls(); extern int puts(const char * str);extern char* gets(char* str);extern int strlen(const char
8、*str);extern int getchar(void);extern int putchar(int c);extern unsigned int port_in8(unsigned int port);extern unsigned int port_in16(unsigned int port);extern void port_out8(unsigned int port, unsigned int value);extern void port_out16(unsigned int port, unsigned int value);extern void setp_cursor
9、(unsigned int bh, unsigned int dh, unsigned int dl);extern void run_pro(int ord);void inttostr(int x, char *str);int strtoint(char *str);unsigned int bcdtodex(unsigned int x);void get_date(char* buf);/*yy-mm-dd*/void set_date(char *buf);void get_time(char* buf);/*hh:mm:ss*/void set_time(char *buf);v
10、oid pre_time();void interface();int strcmp(char str1, char str2);void atoA(char *buf);int deal(char *buf);int inside(int min, int max, int x);int change_time(int paras);int islegal(int y, int m, int d);int change_date(int paras);int shutdown(int paras);int reboot(int paras);int jc(int paras, char *b
11、uf);char buffer80;int control = 1;char Exit_Message30 = nPress any key to exit.;unsigned int add_Table30 = 0x9000, 0, 0xa000, 0, 0xb000, 0;cmain() int paras; control = 0; while (1) cls(); interface(); gets(buffer); setp_cursor(0, 6, 0); paras = deal(buffer); if (paras != 0) jc(paras, buffer); puts(E
12、xit_Message); getchar(); c)用户程序:cx0.c cx1.c2、实验步骤、操作的主要过程、运行结果、屏幕画面截图等A实验步骤a)编写代码b)在dosbox上执行批处理文件0.bat,得到,执行9000.bat得到用户程序1,执行a000.bat得到用户程序2c)使用WinHex将中7e00h到结束的所有数据写到虚拟软盘文件Tinix.img偏移为0的位置处,将用户程序1和用户程序2对应的代码写到1400h和2400h处。d)从软盘启动虚拟机B屏幕截图a)开机界面b)时间设置c)日期设置 d)运行程序地址表中的用户程序e)指令参数错误检查f)执行重启命令,由于重启时无法
13、截图,只提供命令输入界面g)关机指令C指令总结a)Time 修改cmos时间,不需要参数b)Date 修改cmos日期,不需要参数c)Run x执行第x号用户程序,1=x=2,安装新程序x需扩展。d)Reboot 重启,不需要参数e)Shutdown 关机,不需要参数四、实验心得体会A.程序c语言环境的配置和实现,应基于编译器tcc默认的调用规范cdecl。a)cdecl在8086上对c语言参数的入栈顺序为从右向左入栈,对栈的恢复由程序调用者caller实现,汇编实现c语言函数库时,不需要在函数中对栈进行恢复。在汇编程序中调用c实现的函数,对参数压栈和对函数返回后要注意恢复。b)cdecl对函
14、数的返回值,8位,16位和32位分别存放于al、ax、dx和ax中,汇编中调用c实现的函数时返回值的获取为以上寄存器。c)cdecl只对ds,ss,bp,si,di等寄存器进行保护。当在汇编中调用c实现的函数时,若通用寄存器ax,bx,cx,dx中存在有意义的值,要自行进行压栈保护。B.实现tcc的过程中,发现tcc在栈的处理上存在bug。tcc编译tcc_bug文件得到的二进制文件,通过debug反汇编解析,发现,tcc对函数中的临时字符串buf的取值从bx + offset中取(产生错误的位置在tcc_bug.c文件中有标注),而bx默认的段地址为ds而不是ss。当ds不等于ss时,会取出
15、错误的值,产生乱码。解决方法:通过在引导程序中配置c语言环境时ds和ss设置相同的值,成功解决产生乱码的问题。C.由于8086程序在dos上运行是使用int 21h的4ch号功能返回控制台,本次实验对安装了仅有单个iret指令的21h中断,来实现初步对dos程序的小的兼容,用于与用户的c语言链接的启动程序使用int 21h调用安装的iret进行返回控制台。Osc.cextern char cls(); extern int puts(const char * str);extern char* gets(char* str);extern int strlen(const char *str)
16、;extern int getchar(void);extern int putchar(int c);extern unsigned int port_in8(unsigned int port);extern unsigned int port_in16(unsigned int port);extern void port_out8(unsigned int port, unsigned int value);extern void port_out16(unsigned int port, unsigned int value);extern void setp_cursor(unsi
17、gned int bh, unsigned int dh, unsigned int dl);extern void run_pro(int ord);void inttostr(int x, char *str);int strtoint(char *str);unsigned int bcdtodex(unsigned int x);void get_date(char* buf);/*yy-mm-dd*/void set_date(char *buf);void get_time(char* buf);/*hh:mm:ss*/void set_time(char *buf);void p
18、re_time();void interface();int strcmp(char str1, char str2);void atoA(char *buf);int deal(char *buf);int inside(int min, int max, int x);int change_time(int paras);int islegal(int y, int m, int d);int change_date(int paras);int shutdown(int paras);int reboot(int paras);int jc(int paras, char *buf);c
19、har buffer80;int control = 1;char Exit_Message30 = nPress any key to exit.;unsigned int add_Table30 = 0x9000, 0, 0xa000, 0, 0xb000, 0;cmain() int paras; control = 0; while (1) cls(); interface(); gets(buffer); setp_cursor(0, 6, 0); paras = deal(buffer); if (paras != 0) jc(paras, buffer); puts(Exit_M
20、essage); getchar(); /*control = 1;*/void inttostr(int x, char *str) int l = 0; int i, offset; char buf10; if (x = 0) str0 = 0; str1 = 0; return; if (x 0) bufl = x % 10 + 0; x = x / 10; l+; for (i = 0; i l; +i) strl - i - 1 + offset = bufi; strl + offset = 0;int strtoint(char *str) int len = strlen(s
21、tr); int i; int sou; int p; int ans; if (str0 = -) sou = 1; p = -1; else sou = 0; p = 1; ans = 0; for (i = sou; i 4) * 10 + (x & 0xf);void get_date(char* buf)/*yy-mm-dd*/ unsigned int y, m, d; port_out8(0x70, 9); /*获取年*/ y = port_in8(0x71) & 0xff; buf0 = (y 4) + 0; buf1 = (y & 0xf) + 0; buf2 = -; po
22、rt_out8(0x70, 8);/*获取月*/ m = port_in8(0x71) & 0xff; buf3 = (m 4) + 0; buf4 = (m & 0xf) + 0; buf5 = -; port_out8(0x70, 7);/*获取日*/ d = port_in8(0x71) & 0xff; buf6 = (d 4) + 0; buf7 = (d & 0xf) + 0; buf8 = 0;void set_date(char *buf) unsigned int y, m, d; y = (buf0 - 0) 4) + buf1 - 0; port_out8(0x70, 9)
23、; port_out8(0x71, y); m = (buf3 - 0) 4) + buf4 - 0; port_out8(0x70, 8); port_out8(0x71, m); d = (buf6 - 0) 4) + 0; buf1 = (h & 0xf) + 0; buf2 = :; port_out8(0x70, 2);/*获取分*/ m = port_in8(0x71) & 0xff; buf3 = (m 4) + 0; buf4 = (m & 0xf) + 0; buf5 = :; port_out8(0x70, 0);/*获取秒*/ s = port_in8(0x71) & 0
24、xff; buf6 = (s 4) + 0; buf7 = (s & 0xf) + 0; buf8 = 0;void set_time(char *buf) unsigned int h, m, s; h = (buf0 - 0) 4) + buf1 - 0; port_out8(0x70, 4); port_out8(0x71, h); m = (buf3 - 0) 4) + buf4 - 0; port_out8(0x70, 2); port_out8(0x71, m); s = (buf6 - 0) 4) + buf7 - 0; port_out8(0x70, 0); port_out8
25、(0x71, s);void pre_time() char buf20; /*setp_cursor(0, 1, 62);*/ /*puts(Time:);*/ setp_cursor(0, 1, 70); get_time(buf); puts(buf); /*setp_cursor(0, 2, 62);*/ /*puts(Date:);*/ setp_cursor(0, 2, 70); get_date(buf); puts(buf); void interface() int i; int pos4; pos0 = 0; pos1 = 8; pos2 = 60; pos3 = 79;
26、cls(); setp_cursor(0, 0, 0); for (i = 0; i 80; +i) putchar(=); for (i = 0; i 4; +i) setp_cursor(0, 1, posi); putchar(|); for (i = 0; i 4; +i) setp_cursor(0, 2, posi); putchar(|); setp_cursor(0, 3, 0); for (i = 0; i 80; +i) putchar(=); setp_cursor(0, 1, 2); puts(Lab03); setp_cursor(0, 1, 62); /*把以下部分
27、放到pre_time,乱码,寻址问题?*/ puts(Time:); setp_cursor(0, 2, 62); puts(Date:); pre_time(); setp_cursor(0, 2, 30); puts(MYOS 3.0); setp_cursor(0, 4, 0); puts(Input command:); setp_cursor(0, 5, 0); for (i = 0; i 80; +i) putchar(-); setp_cursor(0, 4, 14);int strcmp(char str1, char str2) int len1 = strlen(str1); int len2 = strlen(str2); int i = 0, j = 0; while (i len1 & j len2 & str1i = str2j) i+; j+; return (str2j - str1i);void atoA(char *buf) int len = strlen(buf); int i; for (i = 0; i len; +i) if (a = bufi & bufi = z) buf
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1