30天自制操作系统(第20天)

20.1 显示单个字符的API1

需要实现:当在命令窗口输入 ‘hlt’ 时,打印一个字符。思考一下,需要在执行hlt.nas文件时打印的字符,所以需要在文件中规定要打印的字符。打印字符需要调用cons_putchar函数,而该函数需要3个输入参数,还需要另外两个参数,怎么传递呢?参考函数farjmp和asm_inthandler20等中断函数,是通过汇编语言实现的,这里采用了类似做法。
; hlt.nasMOV 	AL,'A'CALL 	2*8:0xbe3	        ;_asm_cons_putchar函数地址; naskfunc.nas
;void cons_putchar(struct CONSOLE *cons, int chr, char move);
_asm_cons_putchar:PUSH	1				; move=1,占4字节AND		EAX,0xff		; 将AH和EAX的高位置0,将EAX置为已存入字符编码的状态PUSH	EAX				; chr = [EAX]地址存的元素,占4字节PUSH	DWORD [0x0fec]	; 读取内存并PUSH该值,该地址值就是输入参数cons,占4字节CALL	_cons_putcharADD		ESP,12			; 所以是移动12位将栈中的数据丢弃RETF                    ; 
代码中对AL、AH和EAX高16位进行了设置,先后压入1、‘A’和cons(该值在函数 console_task进行了规定,是该函数中的cons值放到地址0x0fec处),再调用函数cons_putchar时将对栈中元素进行依次读出,形成其输入参数并执行。
应用程序对API执行 CALL的时候,千万不能忘记加上段号应用程序所在的段为“1003 * 8”,而 操作系统所在的段为“2 * 8”,因此我们不能使用普通的CALL,而应该使用far-CALL。 far-CALL实际上和far-JMP一样,只要同时指定段和偏移量即可。既然用了far-CALL,就必须相应地使用far-RET,也就是RETF指令。
注释:CALL  2*8:0xbe3代码行中的0xbe3,是bootpack.map文件中的_asm_cons_putchar的地址,由于每个电脑生成的bootpack.map文件中的地址不相同,所以需要根据自身情况进行调整。

20.2 结束应用程序

实现的功能位:当应用程序执行完成后,返回操作系统。执行完CALL     2*8:0xbe3后执行RETF就可以返回操作系统了。 相应地,操作系统这边也需要用 CALL 来代替 JMP 启动应用程序才对。
/*                console.c                */
void cmd_hlt(struct CONSOLE *cons, int *fat)
{struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;struct FILEINFO *finfo = file_search("HLT.HRB", (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;char *p;if (finfo != 0) {/* 找到了与”HLT.HRB“字符串相同的文件 */p = (char *) memman_alloc_4k(memman, finfo->size);file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);
/*这里*/farcall(0, 1003 * 8);memman_free_4k(memman, (int) p, finfo->size);} else {/* 未找到与”HLT.HRB“字符串相同的文件 */putfonts8_asc_sht(cons->sht, 8, cons->cur_y, COL8_FFFFFF, COL8_000000, "File not found.", 15);cons_newline(cons);}cons_newline(cons);return;
}/*                naskfunc.nas                */
_farcall: 						; void farcall(int eip, int cs);CALL 	FAR [ESP+4] 	; eip, csRET/*                hlt.nas                */
[BITS 32]MOV 	AL,'A'CALL 	2*8:0xbf1	;_asm_cons_putchar函数地址,指定段和偏移量RETF

20.3 不随操作系统版本而改变的API

在20.2节中提到 CALL  2*8:0xbe3代码行中的0xbe3数值是不确定的,如何在不修改的情况下准确得到该地址呢?可以考虑用中断,在 MOV     AL,'A'后执行中断(中断代码中有asm_cons_putchar函数地址)。就像文件dsctbl.c中鼠标和键盘中断一样,进行规定,按照设想0x20~0x2f是存放 IRQ的,所以用0x40号。
/*                dsctbl.c                */
void init_gdtidt(void)
{( 中略)/* IDT的设置*/set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);set_gatedesc(idt + 0x40, (int) asm_cons_putchar, 2 * 8, AR_INTGATE32); /*这里!*/return;
}/*                hlt.nas                */
[BITS 32]MOV  AL,'h'INT  0x40   ;这里MOV  AL,'e'INT  0x40   ;这里MOV  AL,'l'INT  0x40   ;这里MOV  AL,'l'INT  0x40   ;这里MOV  AL,'o'INT  0x40   ;这里RETF/*                naskfunc.nas                */
_asm_cons_putchar:PUSH	1				; move=1,占4字节AND		EAX,0xff		; 将AH和EAX的高位置0,将EAX置为已存入字符编码的状态PUSH	EAX				; chr = [EAX]地址存的元素,占4字节PUSH	DWORD [0x0fec]	; 读取内存并PUSH该值,该地址值就是输入参数cons,占4字节CALL	_cons_putcharADD		ESP,12			; 所以是移动12位将栈中的数据丢弃IRETD       ;这里

20.4 为应用程序自由命名

从小节标题可看出,按照在命令窗口中的输入字符进行查找文件。在之前章节中已经实现了 mem cls dir 、type等命令,按照设想当输入命令时查找文件,如果有则执行该文件,否则显示"Bad command.'',并不仅仅对'hlt'命令有效。
在原函数 cmd_hlt 的基础上稍作修改后得到 cmd_app 函数,其中输入参数增加了个cmdline(命令字符串),并在函数内对命令进行处理(文件名有无后缀)。
int cmd_app(struct CONSOLE *cons, int *fat, char *cmdline){struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;struct FILEINFO *finfo;struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;char name[18], *p;int i;for(i = 0; i < 13; i++){//将cmdline转换成nameif(cmdline[i] <= ' ')break;//空格32 换行回车等操作的ASCII码均小于32name[i] = cmdline[i];}name[i] = 0;finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);//寻找与name相同的文件if(finfo == 0 && name[i-1] != '.'){//没找到,则增加后缀名再次查找name[i  ] = '.';name[i+1] = 'H';name[i+2] = 'R';name[i+3] = 'B';name[i+4] = 0;finfo = file_search(name, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);}if (finfo != 0) {/* 找到了与字符串name相同的文件 */p = (char *) memman_alloc_4k(memman, finfo->size);file_loadfile(finfo->clustno, finfo->size, p, fat, (char *) (ADR_DISKIMG + 0x003e00));set_segmdesc(gdt + 1003, finfo->size - 1, (int) p, AR_CODE32_ER);farcall(0, 1003 * 8);memman_free_4k(memman, (int) p, finfo->size);cons_newline(cons);return 1;}return 0;
}

20.5 当心寄存器

修改hello.nas文件,用一个循环持续向AL赋值。INT 0x40之后ECX寄存器的值可能会发生变化所导致的,因此加上了PUSHAD和POPAD,确保可以将全部寄存器的值还原。
/*                hello.nas                */
[INSTRSET "i486p"]
[BITS 32]MOV 	ECX,msgputloop:MOV		AL,[CS:ECX]CMP 	AL,0		;AL==0则跳转JE 		finINT 	0x40ADD 	ECX,1JMP 	putloop
fin:RETF
msg:DB		"hello",0
/*                naskfunc.nas                */
_asm_cons_putchar:STIPUSHAD	                ;这里				PUSH	1				; move=1,占4字节AND		EAX,0xff		; 将AH和EAX的高位置0,将EAX置为已存入字符编码的状态PUSH	EAX				; chr = [EAX]地址存的元素,占4字节PUSH	DWORD [0x0fec]	; 读取内存并PUSH该值,该地址值就是输入参数cons,占4字节CALL	_cons_putcharADD		ESP,12			; 所以是移动12位将栈中的数据丢弃POPAD                   ;这里IRETD

20.6 用API显示字符串

从其他操作系统的显示字符串的 API来看,一般有两种方式:一种是显示一串字符,遇到字符编码0则结束,如函数cons_putstr0;另一种是先指定好要显示的字符串的长度再显示,如函数cons_putstr1。
//打印字符串
void cons_putstr0(struct CONSOLE *cons, char *s){for(; *s != 0; s++)cons_putchar(cons, *s, 1);return;
}
//打印s中前l个字符
void cons_putstr1(struct CONSOLE *cons, char *s, int l){int i;for(i = 0; i < l; i++)cons_putchar(cons, s[i], 1);return;
}
并对函数 cons_runcmd、cmd_mem、cmd_dir、cmd_type进行修改,调用函数 cons_putstr0或cons_putstr1,这里就不做展示了。
以前调用的是cons_putchar函数只能打印一个字符,有了上述两个函数,并参考BIOS的调用方式,执行INT 0x40时就可以直接调用这些函数实现打印字符串。
功能号 1…… 显示单个字符( AL = 字符编码)
功能号 2…… 显示字符串 0 EBX = 字符串地址)
功能号 3…… 显示字符串 1 EBX = 字符串地址, ECX = 字符串长度)
思路如下:cmd_app函数调整执行IDT中1003 * 8地址,该地址存放的是要执行的文件数据(下面以文件hello为例)。文件hello中对ecx等寄存器进行赋值,并产生中断0x40,该中断调用函数asm_hrb_api中的hrb_api,而hrb_api是根据edx寄存器的值执行相应字符或字符串的打印操作。
/*                hello.nas                */
[INSTRSET "i486p"]
[BITS 32]MOV 	ECX,msgMOV 	EDX,1
putloop:MOV		AL,[CS:ECX]CMP 	AL,0		;AL==0则跳转JE 		finINT 	0x40ADD 	ECX,1JMP 	putloop
fin:RETF
msg:DB		"hello",0/*                dsctbl.c                */
set_gatedesc(idt + 0x40, (int) asm_hrb_api,      2 * 8, AR_INTGATE32);/*                naskfunc.nas                */
_asm_hrb_api:STIPUSHAD					; 用于保存寄存器值的PUSHPUSHAD					; 用于向hrb_api传值的PUSHCALL 	_hrb_apiADD		ESP,32POPADIRETD/*                console.c                */
//根据输入参数打印数据 eax为当前字符 ebx为字符串 ecx长度
void hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax){struct CONSOLE *cons = (struct CONSOLE *) *((int *) 0x0fec);if(edx == 1)cons_putchar(cons, eax&0xff, 1);else if(edx == 2)cons_putstr0(cons, (char*)ebx);else if(edx == 3)cons_putstr1(cons, (char*)ebx, ecx);return;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/709770.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

postcss-px-to-viewport include属性

包含include配置的(github)&#xff1a;npm i https://github.com/evrone/postcss-px-to-viewport -S 包含include配置的(npm)&#xff1a;npm i postcss-px-to-viewport-8-with-include -S 不包含包include配置的(npm)&#xff1a;npm i postcss-px-to-viewport 看了一下这篇文…

Linux 基础之 vmstat 命令详解

文章目录 一、前言二、使用说明2.1 vmstat [delay/count/d/D/t/w]2.2.vm模式的字段 一、前言 vmstat(VirtualMeomoryStatistics&#xff0c;虚拟内存统计)是一个不错的 Linux/Unix 监控工具&#xff0c;在性能测试中除了top外也是比较常用的工具之一&#xff0c;它可以监控操作…

同局域网共享虚拟机(VMware)

一、前言 首先我们先来了解下 VMware 的三种网络模式桥接模式、NAT模式、仅主机模式&#xff0c;网络类型介绍详情可以参考下我之前的文档 Linux系统虚拟机安装&#xff08;上&#xff09;第三章 - 第9步指定网络类型。了解三种网络模式的原理之后&#xff0c;再来剖析下需求&…

Python爬虫——Urllib库-上

这几天都在为了蓝桥杯做准备&#xff0c;一直在刷算法题&#xff0c;确实刷算法题的过程是及其的枯燥且枯燥的。于是我还是决定给自己找点成就感出来&#xff0c;那么Python的爬虫就这样开始学习了。 注&#xff1a;文章源于观看尚硅谷爬虫视频后笔记 目录 Urllib库 基本使…

自定义View中的ListView和ScrollView嵌套的问题

当我们在使用到ScrollView和ListView的时候可能会出现显示不全的问题。那我们可以进行以下分析 ScrollView在测量子布局的时候会用UNSPECIFIED。通过源码观察&#xff0c; 在ScrollView的onMeasure方法中 Overrideprotected void onMeasure(int widthMeasureSpec, int heightMe…

MySQL数据库安装与配置全攻略

MySQL安装配置教程 MySQL是一种流行的开源数据库管理系统&#xff0c;广泛用于网站和服务器应用程序中存储数据。本教程将引导你完成在Windows系统上安装和配置MySQL数据库的步骤。 一、下载MySQL安装包 访问MySQL官方网站&#xff1a;MySQL Downloads选择"MySQL Commu…

MySQL进阶:大厂高频面试——各类SQL语句性能调优经验

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;MySQL进阶&#xff1a;强推&#xff0c;冲大厂必精通&#xff01;MySQL索引底层&#xff08;BTree&#xff09;、性能分析、使用…

HTTP笔记(五)

个人学习笔记&#xff08;整理不易&#xff0c;有帮助点个赞&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 目录 一&#xff1a;HTTP报文首部 &#xff08;1&#xff09;HTTP请求报文 &#xff08;2&#xff09…

WPF MVVM中List<>和ObservableCollection<>的区别与对比分析

在WPF MVVM&#xff08;模型-视图-视图模型&#xff09;架构中&#xff0c;数据绑定是实现UI与后端逻辑分离的关键特性。为了使UI能够响应后端数据的变化&#xff0c;通常需要用到特定的集合类型。在WPF中&#xff0c;最常见的两种集合类型是List< T>和ObservableCollect…

Kaggle 竞赛入门

打比赛不用写算法源码&#xff0c;应用的时候不用自己写。学习的时候可以自己写。 Kaggle 竞赛入门 认识 Kaggle 平台Kaggle竞赛知识前提结构化数据前提图像数据文本数据 Kaggle竞赛套路一个赛题的完整流程 认识 Kaggle 平台 Kaggle 官网 主页&#xff0c;比赛&#xff08;数据…

复现nerfstudio并训练自己制作的数据集

网站&#xff1a;安装 - nerfstudio GitHub - nerfstudio-project/nerfstudio&#xff1a;NeRF 的协作友好工作室 安装之前要确保电脑上已经有CUDA11.8或以上版本&#xff08;更高版本的可以安装11.8的toolkit&#xff09; 创建环境 conda create --name nerfstudio -y pyt…

Vector容器介绍

一、引言 在C标准库中&#xff0c;vector是一个非常重要的容器&#xff0c;它提供了动态数组的功能。与静态数组不同&#xff0c;vector可以在运行时动态地增加或减少其大小。这使得vector在处理不确定数量的数据时变得非常有用。vector容器保证了元素的连续存储&#xff0c;因…

浅谈 Linux 网络编程 - Server 端模型、sockaddr、sockaddr_in 结构体

文章目录 前言前置知识Server 端核心模型 【重点】相关函数 【重点】socket 函数bind 函数listen 函数accept 函数close 函数 sockaddr 数据结构 【重点】 前言 本文主要是对 Linux 网络编程中&#xff0c;Server 端的模型、相关函数 以及 sockaddr、sockaddr_in 结构体做介绍…

图片压缩上传实例

前台图片上传压缩是一种常见的需求&#xff0c;可以通过前端技术实现图片的压缩&#xff0c;减小图片的大小&#xff0c;提高页面加载速度。以下是一个前台图片上传压缩的实例&#xff1a; 首先&#xff0c;在前端页面中添加一个文件上传的input标签&#xff1a; <input ty…

黑马程序员——接口测试——day05——Request库、Cookie、Session、UnitTest框架

目录&#xff1a; Requests库 Requests库安装和简介设置http请求语法应用案例 案例1案例2案例3案例4Cookie Cookie简介CookieSession认证方式案例5-看演示&#xff0c;此代码不需实现Session Session简介Session自动管理Cookie案例6面试题Cookie和Session区别获取指定响应数据…

Codeforces Round 929 (Div. 3)

A. 全部负数处理到前面&#xff0c;全部都能变成正数 // Problem: A. Turtle Puzzle: Rearrange and Negate // Contest: Codeforces - Codeforces Round 929 (Div. 3) // URL: https://codeforces.com/contest/1933/problem/A // Memory Limit: 256 MB // Time Limit: 2000 …

300分钟吃透分布式缓存(拉钩教育总结)

开篇寄语 开篇寄语&#xff1a;缓存&#xff0c;你真的用对了吗&#xff1f; 你好&#xff0c;我是你的缓存老师陈波&#xff0c;可能大家对我的网名 fishermen 会更熟悉。 我是资深老码农一枚&#xff0c;经历了新浪微博从起步到当前月活数亿用户的大型互联网系统的技术演进…

Linux|centos7|yum和编译安装ImageMagick记录

一&#xff0c; yum安装imagemagick imagemagick这个软件是图像文件的处理神器&#xff0c;可以文字转图像以及图像的剪辑等等工作&#xff0c;也是配合人工智能工程的不可或缺的工具&#xff0c;具体的用处和特点就不在这里废话了&#xff0c;有兴趣的百度就行了 本次是在…

SpringBoot底层原理

SpringBoot底层原理 一 配置优先级 1.配置方式 Springboot中支持三种配置方式&#xff0c;分别为&#xff1a; application.propertiesapplication.ymlapplication.yaml 2.配置优先级 当存在多份配置文件时&#xff0c;配置文件会按照它们的优先级生效。 优先级从高到底…

Linux中df和du命令

当涉及到在Linux系统中管理磁盘空间时&#xff0c;df和du命令是非常有用的工具。除了基本用法外&#xff0c;它们还具有一些高级用法&#xff0c;可以提供更详细和定制化的磁盘信息。下面是Linux中df和du命令的十个常用的高级用法&#xff0c;附带相应的代码和输出。 df -i - 显…