Advertisement

《30天自制操作系统总结》

阅读量:

文章目录

核心变量
系统功能模块
GDT, IDT, LDT
键盘和鼠标设备
存储管理
* 空闲分区优化
* 内存分配策略

  • 多任务

    • TSS
    • 任务管理数据结构
    • 任务切换
    • 生命周期
    • 调度策略
  • 文件管理

    • 文件控制块
    • FAT
  • 命令行窗口

    • 数据结构
    • 打开窗口
    • 命令执行
    • 系统命令
  • 应用程序

    • 文件头
    • 应用程序启动
    • API
    • 应用程序示例
    • 保护
  • 图层管理

  • 定时器

  • 缓冲区

  • 配置

    • 显示模式
    • 窗口显示

重要变量

name file
mdec 每次鼠标中断产生的数据 bootpack.c
mx,my 鼠标位置 bootpack.c
mmx, mmy 鼠标移动前位置 bootpack.c
fifo 缓冲区,存放鼠标、键盘、定时器缓冲数据 bootpack.c
task_timer 用于任务切换的定时器 mtask.c
key_win 获得焦点的窗口 bootpack.c

系统功能

id 功能 所在文件 说明
1 显卡模式设置 haribote.nas INT 0x10
2 调色板的设置 graphic.c set_palette
3 绘制矩形 graphic.c boxfill8
4 屏幕初始化 graphic.c init_screen8
5 显示字符串 graphic.c putfonts8_asc
6 鼠标显示 graphic.c init_mouse_cursor8,putblock8_8
7 GDT、IDT段设置 dsctbl.c load_gdtr, load_idtr
8 PIC初始化 int.c -
9 键盘中断处理 keyboard.c inthandler21
9.1 Shift+F1 bootpack.c
10 鼠标中断处理 mouse.c inthandler2c
10.1 鼠标数据解析 mouse.c mouse_decode
11 内存分配 memory.c memman_alloc_4k
11.1 内存释放 memory.c memman_free_4k
12 刷新图层,并避免刷新画面外 sheet.c sheet_refreshsub,sheet_refreshsub
12.1 上下移动图层 sheet.c sheet_updown
12.2 左右移动图层 sheet.c sheet_slide
13 窗口制作 windows.c make_window8
14 定时器分配 timer.c timer_alloc
15 任务切换 timer.c inthandler20

GDT, IDT,LDT

在这里插入图片描述
在这里插入图片描述
  • gdt
段号 说明 基址 限长 G C/D -
1 说明CPU可以管理全部4GB内存 0x00000000 0xffffffff 1 D 系统
2 存放haribote.hrb 0x00280000 0x0007ffff 1 C 系统
3-1002 任务的TSS
1003-2002 任务的LDT描述符
  • IDT
    需要将中断处理程序注册到 IDT 中。
中断号 说明 - 中断处理
0x0c 栈异常 如数组越界
0x0d 访问权限异常 主要是访问异常 强制结束任务并返回
0x20 PIT 定时器 IRQ0 产生定时中断
0X21 键盘中断 IRQ1 数据输出到keyfifo
0X2c 鼠标中断 IRQ12 数据输出到mousefifo
  • 0x00~0x1f都是异常所使用的中断,因此IRQ的中断号都是从0x20之后开始的。

LDT

  • GDT的内存地址通过gdtr寄存器传递给CPU;LDT的内存地址则以段描述符的形式存储于GDT中(如同TSS模型),随后LDTR中的选择位将用于定位相应的段描述符。
    • LDTR在TSS框架内运行

键盘与鼠标

键盘

在bootpack 中处理的键盘数据有即时捕获来自1号中断的数据,并不包括以下这些数据之外的其他内容,则直接发送给终端处理。

按键 键码 作用
Tab 0x0f 切换窗口
LShift 0x2a(on),0xaa(off)
RShift 0x36(on),0xb6(off)
CapsLock 0x3a
Shift+F1 - 关闭当前窗口
Shift+F2 - 打开新的console
F11 - -
  • 在console 中处理的键盘数据有
按键 键码 作用
字母,数字,符号 - -

鼠标

事件 动作 case
左键按下 找到点击图层 1:点击区域最上层且不为透明色
左键按下 切换窗口 2:1+点击窗口不是key_win
更新mmx,mmy
关闭应用窗口 4:1+点击x+(sht->flags & 0x10) != 0
关闭命令行窗口 5:1+点击x+(sht->flags & 0x10) == 0
鼠标移动 移动图层 fifo为空

存储器管理

空闲分区管理

  • 数据结构:
复制代码
    struct FREEINFO {	/* information */
    	unsigned int addr, size;
    };
    struct MEMMAN {		/* Memory management */
    	int frees, maxfrees, lostsize, losts;
    	struct FREEINFO free[MEMMAN_FREES];  	//MEMMAN_FREE=4090
    };
  • 基于段式存储管理
  • 在分配过程中,使用首次适应算法,并未进行碎片整理
  • 在释放内存时使用拼接技术

内存分配

BIOS,VRAM等 0x0000_0000 - 0x000f_ffff
软盘内容 0x0010_0000 - 0x0026_7fff (1440KB)
FAT 0x0100_0200 ~ 0x0100_13ff
文件控制块 0x0100_2600 ~ 0x0100_4200 32*224
0x0026_8000-0x0026_f799
IDT x0026_f800 ~ 0x0026_ffff 28*8 bytes
GDT 0x0027_0000~0x0027_ffff 213*8 bytes
bootpack.hrb 0x0028_0000 ~ 0x002f_ffff
栈及其它 0x0030_0000 ~ 0x003f_ffff
空闲块列表 0x003c_0000 ~ 约32KB
malloc 0x0000_1000~ 0x0009_e000
malloc 0x00400000 ~ memtotal - 0x00400000

总共32MB=225B=0x0200_0000

多任务

TSS

复制代码
    struct TSS32 {
    	int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
    	// eip-程序计数器,指向当前执行代码位置,设置为任务代码的起始地址
    	// esp - 指向栈顶
    	int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
    	// cs-代码所在的段号
    	int es, cs, ss, ds, fs, gs;
    	//ldtr ldt的选择符(指向GDT中的LDT描述符)
    	int ldtr, iomap;
    };

任务管理数据结构

复制代码
    struct TASK {
    	// sel-指向GDT中的TSS 
    	// flags: 0-未使用  1-sleep   2-running
    	int sel, flags; /* Sel is the number of GDT. */
    	// level-任务级别   priority*0.01s=分配的时间
    	int level, priority;
    	struct FIFO32 fifo;
    	struct TSS32 tss;
    	struct SEGMENT_DESCRIPTOR ldt[2];
    	struct CONSOLE *cons;
    	int ds_base, cons_stack;
    	struct FILEHANDLE *fhandle;
    	int *fat;
    	char *cmdline;
    };
    struct TASKLEVEL {
    	// 每个level 最多100个任务
    	int running; /* The number of tasks in operation */
    	int now; /* Variables that will let us know which task we're working on */
    	struct TASK *tasks[MAX_TASKS_LV];
    };
    struct TASKCTL {
    	// level0 优先级最高,最多10个level
    	int now_lv; /* At the operating level */
    	char lv_change; /*Do you want me to change levels next time with the taskup switch? */
    	struct TASKLEVEL level[MAX_TASKLEVELS];
    	struct TASK tasks0[MAX_TASKS];
    };

任务切换

  • 只需注册任务,inthandler20 自动进行切换
  • 切换规则:

生命周期

task_alloc

task_run

task_sleep, 时间片用完

close_contask

初始状态0

就绪状态1

运行状态2

销毁状态3

task_run 还可以进行调整以影响任务的优先级(即level)和重要性(即priority)。函数定义如下:void task_run(struct TASK *task, int level, int priority); 当设置为0时会保持该任务的优先级不变;而当设置为1时会保持该任务的重要性不变。

调度策略

  • 多级反馈队列

文件管理

  • 应用程序也是将 name.hrb 以文件的形式存储到内存中

文件控制块

  • 32 字节
复制代码
    struct FILEINFO {
    	// name[0]: 0xe5-此文件被删除  0x00-该段不包含文件信息
    	unsigned char name[8], ext[3], type;
    	char reserve[10];
    	// clusto-表示此文件从哪一个扇区开始存放
    	unsigned short time, date, clustno;
    	unsigned int size;
    };
  • 其中的 type(属性)
类型
0x01 只读文件
0x02 隐藏文件
0x04 系统文件
0x08 非文件信息(比如磁盘名称)
0x10 目录
当同时具有多个属性,只需相加即可

FAT

  • 文件存储位置: clustno乘以512加上十六进制数3E乘以千分之一兆字节加上ADR_DISKIMG在十六进制十六千十千零一十六位的位置。
  • FAT存储位置: 计算结果是将十六进制数值零到二零零零加上十六进制零到一千三百FF的结果再加上ADR-DiskImg。
  • 备份FAT的位置是通过从十六进制一四千到二五千的位置开始并加上ADR-DiskImg来确定的。
  • 每个FAT表项占用一又二分之一字节的空间用于存储下一个簇号信息,在遇到特定的FF8到FFF序列时则表示文件已结束。
  • 操作之前必须先解压缩文件内容。

命令行窗口

数据结构

复制代码
    struct CONSOLE {
    	// sht: 对应图层  0-没有图层(ncst 命令用到)
    	struct SHEET *sht;
    	// x, y, c: 光标的位置、颜色
    	int cur_x, cur_y, cur_c;
    	// timer 用于光标闪烁的定时
    	struct TIMER *timer;
    };
    struct FILEHANDLE {
    	char *buf;
    	int size;
    	int pos;
    };

打开窗口

  • 快捷键组合:Shift + F2
  • 将变量key_win赋值为open_console函数返回的结果;
  • 设置对象sht的任务属性为open_constask函数返回的结果;

命令执行

  • 将字符串保存至 cmdline 变量中
    • 按下 Enter 键后调用 cons_runcmd 函数以执行前述操作
    • 如果该指令是由命令行提供的,则会触发相应的处理流程
    • 否则可能由应用程序 cmd_app 处理该指令
    • 若上一步操作返回成功(即返回值为零),则表示输入正确

系统命令

名称 说明 名称 说明
mem - cls -
dir - type [filename] 显示文件内容
exit 关闭命令行 start [app] 运行应用(阻塞式)
ncst [app] 运行应用(非阻塞)

应用程序

文件头

地址 说明
0x0000 请求操作系统为应用程序准备的数据段的大小 segsize
0x0004 “Hari”
0x0008 -
0x000c ESP初始值&数据部分传送目的地址 esp
0x0010 hrb文件内数据部分的大小 datasize
0x0014 需要传送的数据在.hrb文件中的起始地址
0x0018 0xe9000000(JMP), 当跳转到0x1b,马上执行JMP指令,跳转到应用程序入口地址
0x001c 应用程序入口地址-0x20
0x0020 malloc空间在数据段的起始地址

应用程序启动

  • 在命令行界面中键入应用程序名称,并按回车键执行。
  • 识别当前目录下的文件控制块,并解析.hrb文件记录。
  • 为栈区域分配内存空间,并初始化LDT的代码段与数据段配置。
复制代码
    q = (char *) memman_alloc_4k(memman, segsiz);
    task->ds_base = (int) q;
    set_segmdesc(task->ldt + 0, finfo->size - 1, (int) p, AR_CODE32_ER + 0x60); // p为代码起始地址
    set_segmdesc(task->ldt + 1, segsiz - 1,      (int) q, AR_DATA32_RW + 0x60);
  • 启动:start_app(0x1b, 0 * 8 + 4, esp, 1 * 8 + 4, &(task->tss.esp0));

API

API制作流程

  1. 将 asm_hrb_api 注册到 IDT(0x40),应用程序将通过中断号调用asm_hrb_api。同时asm_hrb_api使用EDX作为功能号寄存器,因此在调用时可指定功能号以调用不同功能。
  2. asm_hrb_api 调用 _hrb_api
  3. hrb_api 根据 EDX 调用不同API
    注: 中断返回:IRETD
功能号 功能
1 显示单个字符(AL=字符编码)
2 显示字符串(EBX=字符串地址)
3 显示字符串(EBX=字符串地址,ECX=字符串长度)
4 程序结束
5 显示窗口
6 向窗口中输入字符
7 在窗口中绘制矩形
8 memman初始化
9 malloc
10 free
11 窗口中画点
12 刷新窗口
13 窗口中画直线
14 关闭窗口
15 响应键盘输入(从和应用绑定的缓冲区中取字符)
16 获取定时器
17 设置定时器发送数据
18 定时器事件设定
19 释放定时器
20 蜂鸣器发声
21 打开文件
22 关闭文件
23 文件定位
24 获取文件大小
25 文件读取
26 获取命令行输入
  • 显示窗口、窗口中输入字符、图形API
寄存器 显示窗口 输入字符 输入矩形
EDX 5 6 7
EBX 窗口缓冲区 窗口句柄 窗口句柄
ESI x轴方向大小 显示位置x坐标 x1
EDI y轴方向大小 显示位置y坐标 y1
EAX 透明色 色号 x0
ECX 窗口名称 字符串长度 y0
EBP - 字符串 色号
返回值
EAX 用于操作窗口的句柄
  • 内存管理ap i
初始化 malloc free
EDX 8 9 10
EBX menman 的地址 menman 的地址 menman 的地址
EAX menman所管理内存起始地址 分配的内存空间地址 释放的内存空间地址
ECX 管理的字节数 分配的字节数 释放的字节数
  • 绘图类api
直线 -
EDX 11 13 -
EBX 窗口句柄 窗口句柄 -
ESI x坐标 x1 x1
EDI y坐标 y1 y1
EAX 色号 x0 x0
ECX 窗口名称 y0 y0
EBP - 色号 色号
返回值
EAX 用于操作窗口的句柄
  • 窗口和键盘api
刷新窗口 关闭窗口 键盘输入
EDX 12 14 15
EBX 窗口句柄 窗口句柄 -
ESI x1 - -
EDI y1 - -
EAX x0 - 0 1 (1-休眠,0-不休眠)
ECX y0 - -
返回值
EAX 按键的字符编码
  • 定时器API
alloc 获取定时器 init 设置发送标志值 set 时间设定 free 释放
EDX 16 17 18 19
EAX 定时器句柄(返回) 数据 时间 -
EBX - 定时器句柄 定时器句柄 定时器句柄
  • 文件操作API
open close seek size read
EDX 21 22 23 24 25
EAX(I) - 文件句柄 文件句柄 文件句柄 文件句柄
EBX 文件名 - 偏移量 - 缓冲区地址
ECX - - 定位模式[1] 文件大小获取模式[2] 最大读取字节数
EAX(O) 文件句柄 - - 文件大小 读取字节数

注:[1]: 0:定位起点为开头, 1:起点为当前访问位置 2:起点为文件末尾
[2]:0:普通文件大小, 1: 当前读取位置从文件开头起算的偏移量
2:当前读取位置从文件末尾起算的偏移量

应用程序示例

作用 程序
显示字符串 hello3,hello4,hello5
显示窗口,并在窗口中输入字符串,绘制矩形 winhelo2,winhelo3
窗口中画点 star1,stars
窗口中画直线 lines
响应键盘输入 walk
定时器 noodle
色彩显示 color, color2

保护

  • 通过区分系统段与应用段
AR_DATA32_RW AR_CODE32_ER 中断门属性
系统段 0x4092 0x409a 0x008e
应用段 0x4092+0x60 0x409a+0x60 0x008e+0x60

图层管理

  • 数据结构
复制代码
    struct SHEET {
    	unsigned char *buf;
    	// flags: 0-未使用    1-使用中   (flags&0x10)!=0-该图层属于应用程序
    	// height:  -1-invisibility   max-top
    	// col_inv: 透明色色号
    	int bxsize, bysize, vx0, vy0, col_inv, height, flags; 
    	struct SHTCTL *ctl;
    	struct TASK *task;
    };
    struct SHTCTL {
    	unsigned char *vram, *map;
    	int xsize, ysize, top;
    	struct SHEET *sheets[MAX_SHEETS];
    	struct SHEET sheets0[MAX_SHEETS];
    };
  • 刷新map sheet_refreshmap
    得到区域内的map

  • 层级局部更新 sheet_refreshsub 基于给定的刷新区域和刷新层级,按照map执行更新。

  • 图层垂直方向上进行调整 sheet_updown

    • 图层平行方向上进行调整 sheet_slide
      通过比较调整前后的布局情况来判断是否完成操作

定时器

  • 数据结构
复制代码
    struct TIMER {
    	struct TIMER *next;
    	unsigned int timeout;
    	// flags: 0-未使用  1-已配置  2-使用中
    	// flags2: 0-一般定时器   1-应用程序申请定时器
    	char flags, flags2;
    	struct FIFO32 *fifo;
    	// 此定时器的标志数据
    	int data;
    };
    struct TIMERCTL {
    	// count 当前时间
    	// next 下一个timeout时间
    	// t0 当前计时器
    	unsigned int count, next;
    	struct TIMER *t0;
    	struct TIMER timers0[MAX_TIMER];
    };
  • 计时器初始化频率设置为100Hz
    • 定时采用列表组织结构,并在列表末尾设置了超时标志位(timeout=0xffff_ffff)
    • timer_alloc函数负责将定时器从无用态转为配置态
    • timer_settime函数用于设定超时值,并将该值赋给当前时间段
    • inthandler20函数执行cout++操作;当触发超时事件时,则会将输出结果发送至缓冲区
    • 调用timer_free函数后会将该定时器重置回无用态
    • timer_cancel函数的作用是将指定的定时器从使用态转回配置态,在此过程中超时值并未被触发

缓冲区

数据结构

复制代码
    struct FIFO32 {
    	int *buf;
    	int p, q, size, free, flags;
    	struct TASK *task;  // 当有数据时需要被唤醒的任务
    };
  • 每个任务有自己单独的缓冲区

公共缓冲区

记号 作用 说明
0,1 光标闪烁用定时器
2, 3 2-显示光标,3-不显示光标 只要是用于console
10 10秒定时器
256 ~ 511 键盘输入 =读入值+256
512~767 鼠标输入 =读入值+512
768 ~ 1023 关闭命令行窗口及任务 sht -= 768
1024 ~ 2023 关闭命令行任务 task_id -= 1024
2024 ~ 2279 仅关闭命令行窗口 在运行应用时关闭窗口

配置

显示模式

功能 说明
显示 对显卡的内存进行修改 显卡模式决定了整个画面分辨率、画面的变化也就是显卡内容的变化

非VBE

复制代码
      MOV         AL,0x13                 ; 3x200x8bit color VGA graphics

      MOV		AH,0x00
      INT		0x10
      MOV		BYTE [VMODE],8	; Note screen mode (see C language)
      MOV		WORD [SCRNX],320
      MOV		WORD [SCRNY],200
      MOV		DWORD [VRAM],0x000a0000

VBE
AX: 0x4f02, VRAM: 0xe0000000

画面模式号码 BX XSIZE YSIZE
0x101 0x4101 640 480
0x103 0x4103 800 600
0x105 0x4105 1024 768
0x107 0x4107 1280 1024

窗口显示

  • 色彩
    标题栏颜色:COL8_000084(深蓝)
    标题栏背景:COL8_C6C6C6(灰)
    透明色号——99
    “桌面背景”:COL8_008484

全部评论 (0)

还没有任何评论哟~