L3 操作系统启动

L3 操作系统启动

[1] setup 模块

[1.1] setup.s

此部分的代码用来完成 OS 启动前的设置。

start: mov ax,#INITSEG	mov ds,ax	mov ah,#0x03
	xor bh,bh	int 0x10 // 取光标位置dx
	mov ah,#0x88	int0x15		mov [2],ax //cs:[2]
	cli //不允许中断
	mov ax,#0x0000	cld
do_move: mov es,ax	add ax,#0x1000
	cmp ax,#0x9000	jz end_move
	mov ds,ax	sub di,di
	sub si,si
	mov cx,#0x8000
	rep
	movsw
	jmp do_move

此时的内存分布:

内存地址长度名称
0x900002光标位置
0x900022扩展内存数
0x9000C2显卡参数
0x901FC2根设备号

前面 boot 空出来的位置就是为了这里留给操作系统,操作系统占据从 0 地址开始的位置。

[1.2] 进入保护模式

call empty_8042		mov al,#0xD1		out #0x64,al
call empty_8042		mov al,#0xDF		out #0x60,al
mov ax,#0x0001		mov cr0,ax
jmpi 0,8 //关键作用!

若在实模式下,ip = 0, cs = 8,cs << 4 + ip = 0x80,在 system 模块中,显然不合法。
因此实际上,这里的 寻址方式 发生了改变,也就是说 CPU 的地址解释程序发生了变化。
20 位地址最多只能代表 1M 内存,因此不能使用传统的左移 4 位加 ip,而应该改成 32 位机器模式,能表达 4G内存,即 保护模式
cr0 寄存器就用来实现这种变换, PE=1 代表保护模式。
在这里插入图片描述

[1.3] 将 setup 移动到 0 地址处

end_move: mov ax,#SETUPSEG		mov ds,ax
	lidt idt_48		lgdt gdt 48//设置保护模式下的中断和寻址
idt_48:.word 0		.word 0,0//保护模式中断函数表
gdt_48:.word 0x800		.word 512+gdt,0x9
gdt:	.word 0,0,0,0 //0字节
		.word 0x07FF, 0x0000, 0x9A00, 0x00C0 // 8字节
		.word 0x07FF, 0x0000, 0x9200, 0x00C0 // 16字节

生成 setup 需要的 gdt 表。

[1.4] 保护模式下的地址翻译和中断处理

在 Intel 硬件中实现了 GDT(Global Description Table),此时 cs:ip 中的 cs 代表选择子,ip 代表偏移,通过查表 + 偏移产生 32 位地址。
同时,中断也是通过 IDT 表去查询中断处理函数入口,包含系统接口。

[1.5] jmpi 0,8

在这里插入图片描述
上图是 GDT 表项。
根据 setup 中 gdt 的内容,可得基址为 0x00,因此实际上是跳转到内存 0x0000 处执行,即 操作系统的模块开始处 执行。
setup 的工作到此完成。

[2] 跳到 system 模块执行

[2.1] 第一部分代码 head.s

// linux/Makefile
disk: Image
	dd bs=8192 if=Image of=/dev/PS0
Image: boot/bootsect boot/setup toolssystem tools/build //树依赖结构
	tools/build boot/bootsect boot/setup tools/system > Image
tools/system: boot/head.o init/main.o $(DRIVERS) ...
	$(LD) boot/head.o init/main.o $(DRIVERS) ... -o tools/system

Image:操作系统镜像(boot | setup | OS | …)
head.s(head.o):操作系统的第一个部分


// head.s, 此处为 32 位汇编代码
stratup_32: ......
	call setup_idt // 正式建立 idt 和 gdt 表
	call setup_gdt
	......
l: incl %eax
......
setup_idt: lea ignore_int,%edx
	movl $0x00080000,%eax		movw %dx,%ax
	lea _idt,%edi		movl %eax,(%edi)

setup 进入保护模式,完成少部分硬件的初始化;
而 head 是在进入保护模式后,完成操作系统正式运行之前的初始化。

[2.2] 三种汇编

  • as86 汇编:16位
  • GNU as 汇编:32位
  • 内嵌汇编

[2.3] after_page_tables

after_page_tables:
	pushl $0		pushl $0		pushl $0		pushl $L6
	pushl $_main		jmp set_paging
L6:		jmp L6
setup_paging:	设置页表 ret

从汇编跳转到操作系统的 C 代码入口(main函数)。

[2.4] main 函数

// init/main.c
void main(void)
{	mem_init();
	trap_init();
	blk_dev_init();
	chr_dev_init();
	tty_init();
	time_init();
	sched_init();
	buffer_init();
	hd_init();
	floppy_init():
	sti();
	move_to_user_mode();
	if(!fork()) {init();}
}

包含内存、中断、设备、时钟、CPU 等内容的初始化……

[2.5] mem_init()

// linux/mm/memory.c
void mem_init(long start_mem, long end_mem)
{
	int i;
	for(i=0; i<PAGING_PAGES; i++)
		mem_map[i] = USED; // PAGIN_PAGES 被 OS 自己使用
	i = MAP_NR(start_mem);
	end_mem -= start_mem;
	end_mem >>= 12; // 每个页的大小为 2^12 = 4K
	while(end_mem -- > 0)
		mem_map[i++] = 0; }

end_mem 由前面的步骤得出,代表总扩展内存大小。

[3] 小结

系统启动步骤:
boot -> setup -> head -> main -> mem_init -> …
或者简单概括为两大步骤:
(1)将操作系统读入内存
(2)完成初始化,获取各类硬件信息,生成对应数据结构

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值