Ucore|kernel-内核编程

基于 intel 80386

Posted by Elli0t on 2020-08-12

技术文档 ucore_os_docs

准备知识

虚拟地址经过分段化为线性地址,线性地址经过分页转为物理地址。

intel 80386 寄存器(它们的宽度都是32位),参考链接

1
2
3
4
5
6
7
8
EAX:累加器 
EBX:基址寄存器
ECX:计数器
EDX:数据寄存器
ESI:源地址指针寄存器
EDI:目的地址指针寄存器
EBP:基址指针寄存器
ESP:堆栈指针寄存器

Segment Register(段寄存器16位,也称 Segment Selector,段选择符,段选择子):除了8086的4 个段外(CS,DS,ES,SS),80386还增加了两个段FS,GS,这些段寄存器都是16位的,用于不同 属性内存段的寻址,它们的含义如下:

1
2
3
4
5
6
CS:代码段(Code Segment) 
DS:数据段(Data Segment)
ES:附加数据段(Extra Segment)
SS:堆栈段(Stack Segment)
FS:附加段
GS 附加段

Flag Register(标志寄存器):EFLAGS,和8086的16位标志寄存器相比,增加了4个控制位,这 20位控制/标志位的位置如下图所示:

4578753446153412643

相关的控制/标识位含义是:

1
2
3
4
5
6
7
8
9
10
CF(Carry Flag):进位标志位; 
PF(Parity Flag):奇偶标志位;
AF(Assistant Flag):辅助进位标志位;
ZF(Zero Flag):零标志位;
SF(Singal Flag):符号标志位;
IF(Interrupt Flag):中断允许标志位,由CLI,STI两条指令来控制;设置IF位使CPU可识别外部(可屏蔽 )中断请求,复位IF位则禁止中断,IF位对不可屏蔽外部中断和故障中断的识别没有任何作用;
DF(Direction Flag):向量标志位,由CLD,STD两条指令来控制;
OF(Overflow Flag):溢出标志位;
IOPL(I/O Privilege Level):I/O特权级字段,它的宽度为2位,它指定了I/O指令的特权级。如果当前的特权级别在数值上小于或等于IOPL,那么I/O指令可执行。否则,将发生一个保护性故障中断;
NT(Nested Task):控制中断返回指令IRET,它宽度为1位。若NT=0,则用堆栈中保存的值恢复EFLAGS,CS和EIP从而实现中断返回;若NT=1,则通过任务切换实现中断返回。在ucore中,设置NT为0

Lab-1

练习1

理解通过make生成执行文件的过程。

\1. 操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每 一条相关命令和命令参数的含义,以及说明命令导致的结果)

1
2
3
4
5
6
7
8
9
10
11
# create ucore.img
UCOREIMG := $(call totarget,ucore.img)

$(UCOREIMG): $(kernel) $(bootblock)
$(V)dd if=/dev/zero of=$@ count=10000
$(V)dd if=$(bootblock) of=$@ conv=notrunc
$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc

$(call create_target,ucore.img)

# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
build 512 bytes boot sector: 'bin/bootblock' success!
dd if=/dev/zero of=bin/ucore.img count=10000
10000+0 records in
10000+0 records out
5120000 bytes (5.1 MB, 4.9 MiB) copied, 0.0167135 s, 306 MB/s
dd if=bin/bootblock of=bin/ucore.img conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 8.5709e-05 s, 6.0 MB/s
dd if=bin/kernel of=bin/ucore.img seek=1 conv=notrunc
146+1 records in
146+1 records out
74828 bytes (75 kB, 73 KiB) copied, 0.000251427 s, 298 MB/s

count = blocks: 仅拷贝 blocks 这个块,块大小等于 ibs 制定的字节数;cone = notrunc;不截断输出文件

先创建一个大小为 10000 字节的块,然后再将 bootblack、kernel 拷贝过去

1
2
3
4
5
6
7
8
$(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign)
@echo + ld $@
$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock)
@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)
@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
@$(call totarget,sign) $(call outfile,bootblock) $(bootblock)

$(call create_target,bootblock)

生成bootasm.o、bootmain.o、sign的相关代码

1
2
gcc -Itools/ -g -Wall -O2 -c tools/sign.c -o obj/sign/tools/sign.o
gcc -g -Wall -O2 obj/sign/tools/sign.o -o bin/sign

ggdb 生成可供 gdb 使用的调试信息

-m32 生成适用于32位环境的代码

-gstabs 生成 stabs 格式的调试信息

-nostdinc 不使用标准库

-fno-stack-protector 不生成用于检测缓冲区溢出的代码

-0s 为减小代码长度进行优化

\2. 一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?

sign.c

1
2
3
4
5
6
7
8
buf[510] = 0x55;
buf[511] = 0xAA;
FILE *ofp = fopen(argv[2], "wb+");
size = fwrite(buf, 1, 512, ofp);
if (size != 512) {
fprintf(stderr, "write '%s' error, size is %d.\n", argv[2], size);
return -1;
}

要求硬盘主引导扇区大小是512字节,还需要510、511个字节处分别是0x55 0xAA

练习2

使用qemu执行并调试lab1中的软件。