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

28.1 alloca

__alloca 会在下述情况下被 C 语言的程序调用(采用 near-CALL 的方式)。
1、要执行的操作从栈中分配 EAX 个字节的内存空间( ESP -= EAX; )
2、要遵守的规则不能改变 ECX 、 EDX 、 EBX 、 EBP 、 ESI 、 EDI的值(可以临时改变它们的值,但要使用 PUSH/POP 来复原)
RET 返回的地址保存在了ESP("RET"指令实际上相当于"POP EIP","POP EIP"实际上又相当于下面两条指令:MOV EIP,[ESP] ADD ESP,4)。为实现类似RET功能指令,所以编写了如下 __alloca函数指令。
__alloca:
SUB ESP,EAX
ADD ESP,4
JMP DWORD [ESP+EAX-4] ; 代替 RET
注:C语言中,在函数外部声明的变量和带static的变量一样,都会被解释为DB和RESB;在函数内部不带static声明的变量则会从栈中分配空间。

28.2 文件操作API

**需要实现的功能:打开、定位、读取、写入和关闭文件。**思路:打开文件时需要指定文件名,如果打开成功,操作系统将返回文件句柄。在随后的操作中,只要提供这个文件句柄就可以进行读写操作了,操作结束后将文件关闭。读取和写入API基本上需要指定需要读取(写入)的数据长度以及内存地址,文件的内容会被传送至内存(写入操作时是由内存传送至文件)。

|-----------------------------------------------------------------|--------------------------|----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
| 打开文件 | 关闭文件 | 文件定位 | 获取文件大小 | 文件读取 |
| EDX=21 EBX= 文件名 EAX= 文件句柄(为 0 时表示打开失败)(由操作系统返回) | EDX=22 EAX= 文件句柄 | EDX=23 EAX= 文件句柄 ECX= 定位模式 =0:定位的起点为文件开头 =1:定位的起点为当前的访问位置 =2:定位的起点为文件末尾 EBX= 定位偏移量 | EDX=24 EAX= 文件句柄 ECX= 文件大小获取模式 =0:普通文件大小 =1:当前读取位置从文件开头起算的偏移量 =2:当前读取位置从文件末尾起算的偏移量 EAX= 文件大小(由操作系统返回) | EDX=25 EAX= 文件句柄 EBX= 缓冲区地址 ECX= 最大读取字节数 EAX= 本次读取到的字节数(由操作系统返回) |

复制代码
/*                    bootpack.h                    */
struct TASK {
    (中略)
    int ds_base, cons_stack;
    struct FILEHANDLE *fhandle; /*从此开始*/
    int *fat; /*到此结束*/
};
struct FILEHANDLE { /*从此开始*/
    char *buf;
    int size;
    int pos;
}; /*到此结束*/

/*                    console.c                    */
void console_task(struct SHEET *sheet, int memtotal)
{
    (中略)
    struct FILEHANDLE fhandle[8];
    (中略)
    for (i = 0; i < 8; i++) 
        fhandle[i].buf = 0; /*未使用标记*/
    task->fhandle = fhandle;
    task->fat = fat;
    (中略)
}

if (finfo->size >= 36 && strncmp(p + 4, "Hari", 4) == 0 && *p == 0x00) {//cmd_app代码片段
    (中略)
    start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0));
    (中略)
    for (i = 0; i < 8; i++) { /*将未关闭的文件关闭*/ /*从此开始*/
        if (task->fhandle[i].buf != 0) {
            memman_free_4k(memman, (int) task->fhandle[i].buf, task->fhandle[i].size);
            task->fhandle[i].buf = 0;
        }
    } /*到此结束*/
    (中略)
}

int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax){
	(中略)
	struct FILEINFO *finfo;
	struct FILEHANDLE *fh;
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	(中略)
/*开始*/}else if(edx == 21){//打开文件
		for(i = 0; i < 8; i++){
			if(task->fhandle[i].buf == 0)
				break;
		}
		fh = &task->fhandle[i];
		reg[7] = 0;
		if(i < 8){
			finfo = file_search((char*)ebx+ds_base, (struct FILEINFO*)(ADR_DISKIMG+0x002600), 224);
			if(finfo != 0){
				reg[7] = (int)fh;
				fh->buf = (char *) memman_alloc_4k(memman, finfo->size);
				fh->size = finfo->size;
				fh->pos = 0;
				file_loadfile(finfo->clustno, finfo->size, fh->buf, task->fat, (char *)
					(ADR_DISKIMG+0x003e00));
			}
		}
	}else if(edx == 22){//关闭文件
		fh = (struct FILEHANDLE*)eax;
		memman_free_4k(memman, (int)fh->buf, fh->size);//与打开文件操作中的memman_alloc_4k对应
		fh->buf = 0;
	}else if(edx == 23){//文件定位
		fh = (struct FILEHANDLE*)eax;
		if(ecx == 0){//定位的起点为文件开头
			fh->pos = ebx;
		}else if(ecx == 1){//定位的起点为当前的访问位置
			fh->pos += ebx;
		}else if(ecx == 2){//定位的起点为文件末尾
			fh->pos = fh->size + ebx;
		}
		if(fh->pos < 0)fh->pos = 0;
		if(fh->pos > fh->size)fh->pos = fh->size;
	}else if(edx == 24){//获取文件大小
		fh = (struct FILEHANDLE*)eax;
		if(ecx == 0){//普通文件大小
			reg[7] = fh->size;
		}else if(ecx == 1){//当前读取位置从文件开头起算的偏移量
			reg[7] = fh->pos;
		}else if(ecx == 2){//当前读取位置从文件末尾起算的偏移量
			reg[7] = fh->pos - fh->size;
		}
	}else if(edx == 25){//文件读取,写入到ebx缓存区中
		fh = (struct FILEHANDLE*)eax;
		for(i = 0; i < ecx; i++){
			if(fh->pos == fh->size)break;
			*((char *) ebx + ds_base + i) = fh->buf[fh->pos];
			fh->pos++;
		}
		reg[7] = i;
/*结束*/}
	return 0;
}

28.3 命令行API

需要实现的功能:在用户输入"type ***.nas"这样的命令时获取后面的文件名。
获取命令行
EDX=26
EBX= 存放命令行内容的地址
ECX= 最多可存放多少字节
EAX= 实际存放了多少字节(由操作系统返回)

复制代码
/*                    a_nask.nas                    */
_api_cmdline: ; int api_cmdline(char *buf, int maxsize);
    PUSH EBX
    MOV EDX,26
    MOV ECX,[ESP+12] ; maxsize
    MOV EBX,[ESP+8] ; buf
    INT 0x40
    POP EBX
    RET
/*                    bootpack.h                    */
struct TASK {
    (中略)
    char *cmdline;
};

/*                    console.c                    */
void console_task(struct SHEET *sheet, int memtotal)
{
    (中略)
    task->cons = &cons;
    task->cmdline = cmdline; /*这里!*/
    (中略)
}

int *hrb_api(int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax)
{
    (中略)
    } else if (edx == 26) {
        i = 0;
        for (;;) {
            *((char *) ebx + ds_base + i) = task->cmdline[i];
            if (task->cmdline[i] == 0) {
                break;
            }
            if (i >= ecx) {
                break;
            }
            i++;
        }
        reg[7] = i;
    }
    return 0;
}
相关推荐
互联网运营知识库1 天前
2026年寒假旅游攻略生成二维码怎么做?
经验分享·科技·其他·生活·旅游·节日
t057772 天前
致同提示:财政部等九部委联合发布《企业可持续披露准则第1号——气候(试行)》
其他
pingcode2 天前
子女资助缴费
其他
孙严Pay2 天前
快捷支付:高效安全的在线支付新选择
笔记·科技·计算机网络·其他·微信
老陈头聊SEO3 天前
生成引擎优化(GEO)在内容创作与用户体验提升方面的综合应用与效益分析
其他·搜索引擎·seo优化
羑悻的小杀马特3 天前
【Linux篇章】穿越网络迷雾:揭开 HTTP 应用层协议的终极奥秘!从请求响应到实战编程,从静态网页到动态交互,一文带你全面吃透并征服 HTTP 协议,打造属于你的 Web 通信利刃!
linux·运维·网络·http·操作系统·网络通信
chuangrong1233 天前
道旗制作的精湛工艺:场景中的完美呈现
其他
m0_467031364 天前
番茄矮砧密植水肥一体化系统铺设指南:高效省力的精准灌溉方案
其他
彩妙不是菜喵4 天前
操作系统中的Linux:进程详解--->(深入浅出)从入门到精通
linux·操作系统
农民真快落4 天前
【操作系统】手撸xv6操作系统——types.h/param.h/memlayout.h/riscv.h/defs.h头文件解析
操作系统·risc-v·嵌入式软件·xv6