习题
空白表示任务之间的交互消耗的时间;分时可以使得整体的利用效率更高,某些操作可能需要I/O高耗时,轮转会提高效能;
MBR应该在0柱面、0磁头、0扇区,占一个扇区
(1)应该放在每个操作系统的第一个扇区;
(2)引导用户选择操作系统的代码,不同操作系统的位置
(3)从BIOS找到MBR记录,然后从MBR记录以及用户的选择情况,跳转到指定的操作系统启动代码;
磁道 1 的上盘面;
这样设计的原因遵循了
CHS(柱面-磁头-扇区)的寻址方式,而且通过上下两个分区能够尽可能减少磁头的移动,节省时间;节点关系:
1
2
3
4
5
6
7
8
9
10
11Image
-- boot/bootsect
--boot/bootsect.s
-- boot/setup
--boot/setup.s
-- tools/system
-- boot/head.s
-- boot/main.s
-- $ (ARCHIVES) $(DRIVERS)
-- tools/build
-- tools/build.c命令序列:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//编译bootsect
$(AS86) -o boot/bootsect.o boot/bootsect.s
$(LD86) -s -o boot/bootsect boot/bootsect.o
//编译setup
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
//编译system中的模块
$(AS) -c -o boot/head.o boot/head.s
$(AS) -c -o init/main.o boot/main.s
...
//链接system
$(LD) $(LDFLAGS) boot/head.o init/main.o
$(ARCHIVES) $(DRIVERS)
//编译tools
$(CC) $(CFLAGS) -o tools/build tools/build.c读入
system模块的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14id = open(argv[3], O_RDONLY | O_BINARY, 0); //读取system模块
for (i = 0; (c = read(id, buf, sizeof(buf))) > 0; i += c) {
write(1, buf, c);
} //写入system模块
memset(buf, 0, sizeof(buf));//缓冲区至0
// 用0填充到SYSSIZE的大小
while (i < SYSSIZE) {
c = SYSSIZE - i;
if (c > sizeof(buf)) {
c = sizeof(buf);
}
write(1, buf, c);
i += c;
}
实践项目
(1)把Loading system…改为Loading system edited by Leo…
此时字符串的长度变为31个字符,再加上原有的换行符等,总长度为37,对应的CX的的值也要更改为#37;编译后界面显示更改后的字符串,如图所示:
(2) 背景知识:
BIOS的int 0x10中断有很多的功能号,表格如下:
| 寄存器 | 值 | 解释 |
|---|---|---|
| AH | 0x13 | 写入字符串 |
| AL | 0x01 | 写入字符串并移动光标 |
| BH | / | 显示页码 |
| BL | / | 字符属性 |
| CX | / | 字符长度 |
| ES:BP | / | 指向写入字符串的地址 |
由于函数调用依赖于栈进行参数传递和返回地址保存,所以在进行函数调用之前,必须先设置好栈,即设置合理的堆栈段寄存器ss和堆栈指针寄存器sp。
bootsect.s已经将ss:sp设置为0x9000:0xff00,保证大于启动过程中bootsect.s+setup.s+SYSTEM的所占扇区的和;调用函数需要把当前寄存器的值push进去,然后pop出来再返回,值不会改变;调用
BIOS的int 0x10获取当前光标号:寄存器 值 解释 AH 0x03 功能号 BH 0 指定要查询的显示页码 CH / 返回光标的起始扫描线 CL / 返回光标的结束扫描线 DH / 返回光标所在的行号 DL / 返回光标所在的列号 换行包含两个操作:回车(CR)和换行(LF),起源于电传打字机,而现代操作系统做了简化;
操作步骤:
a. 设置好ss/sp堆栈,将某些操作设置为函数,方便调用;
1 | ! repeat set stack, although it is done in bootsect.s |
b . 在进入setup模块时,打印Now we are in SETUP
1 | mov ax, #SETUPSEG |
其中两个函数read_cursor和print_nl分别为:
1 | print_nl: |
(3) 接(2)的背景知识
- 获取扩展内存容量将调用
BIOS的int 0x15中断,功能号为0x88,表格如下:
| 寄存器 | 值 | 解释 |
|---|---|---|
| AH | 0x88 | 获取扩展内存容量,返回参数是AX,以KB为单位 |
在确认disk信息之后,补充:
1 | mov ax, #INITSEG |
其中[2]是一个二进制数,需要进行转化为十六进制的字符打印出来;调用print_hex函数:
1 | !以16进制方式打印栈顶的16位数 |
(4)在跳转到SYSTEM模块之前 (jmpi 0,8) ,加入一个死循环:
1 | dead_loop: |