Day2 进入自定义的操作系统代码

本文详细介绍了基于x8632位的引导程序初始化过程,包括引导程序的工作模式、内存扩展策略、内核寄存器的使用以及从汇编到C的加载器跳转技术。作者通过李述铜老师的课程笔记,展示了如何通过BIOS中断加载loader和处理不同模式下的内存寻址方式。
摘要由CSDN通过智能技术生成

**该系列文章为bilibili李述铜老师手写基于x86 32位的操作系统课程笔记,如有疑问欢迎评论沟通**


一、初始化引导程序并读取磁盘

        引导程序主要用于为操作系统运行初始化运行的环境,并加载操作系统运行。

        此处引用李述铜老师课程中的视频截图表示该引导程序的工作模式:

         通过该工作模式可以看出整个引导程序的工作量比较大,但是BIOS只会加载磁盘的第0扇区(512字节)进入内存中,而512字节内存的容量十分的有限不足支撑完成这么大的工作量,因此考虑扩展内存,扩展内存有两种方式

        1.将一部分Boot(引导程序)完成的工作放于内核(Kernel)之中,即内核中包含了原本应有Boot去完成的工作。

        2.二级加载,通过Boot去加载loader,由loader完成更为复杂的初始化工作。

        此处引用李述铜老师的课程截图:      

         x86与编程相关的主要内核寄存器,此处引用课程截图:

        其中:

        1.通用寄存器:因为实模式下只能使用十六位的寄存器,也就是说在Boot程序中只能使用AX,BX,CX,DX寄存器

        2.段寄存器CS、DS、SS、ES、FS、GS为段寄存器,为访问特定内存地址,需要采用段值+偏移量的形式进行寻址。(此课程为了方便,直接将所有的段地址寄存器设置为了0,直接寻址,不通过加上偏移量寻址)

        8086内存映射图引用课程截图:        

        值得注意的是x86的处理器的栈是从高地址往低地址进行的压栈。

        前置知识了解清楚之后,打开工程基本框架的boot文件夹下的start.s汇编文件,并在_start下写入代码进行初始化环境:

_start:

	# 首先将段地址寄存器全部设置为0
	mov $0,%ax
	mov %ax,%ds
	mov %ax,%ss
	mov %ax,%es
	mov %ax,%fs
	mov %ax,%gs

	# 初始化栈空间,设置栈的起始地址
	# 也可以使用  $_start,因为这个start程序汇编出来后就是放在0x7c00
	mov $0x7c00,%esp

         然后通过BIOS提供的软中断接口完成扇区读取加载loader:

	# 利用BIOS软中断开始读取磁盘加载loader
	# INT13为磁盘读取的服务中断
	# 使用方法如下:
	# AH=02H
	# AL=扇区数
	# CH=柱面
	# DH=磁头
	# DL=驱动器,00H-7Fh:软盘;80H-0FFH:硬盘
	# ES:BX=缓冲区的地址
	# 出口参数:CF=0---操作成功,AH=00H,AL=传输的扇区数,否则AH=状态代码
read_loader:
	mov $0x8000, %bx
	mov $0x2, %ah
	# cx=ch:cl各八位
	# 扇区设置为2是因为BIOS认为磁盘的扇区是以1开始编号
	mov $0x2, %cx
	# 64个扇区表示32KB,因为一个扇区512字节
	mov $64, %al
	mov $0x0080, %dx
	# 开始执行软中断
	int $0x13
	jc read_loader 

	# 当使用-exec x /20xb 0x8000指令读取缓冲区数据时会发现数据与0x200位置数据一样,为什么一样呢?
	# 因为我们是从硬盘的第2个扇区开始读,而第一个扇区为512字节,也就是表示16进制的0x200,因为是从0x0开始编号,因此第一扇区的结束位置为0x199
	# 所以读取到的数据是0x200开始往后的64*512个字节

	# 原地跳转指令

二、从汇编到C并跳转到loader

        从汇编到c可以通过JMP指令或者CALL指令进行跳转:        

	# 通过jmp指令直接跳转到函数中
	jmp boot_entry

         即跳转到了boot.c文件中的boot_entry函数中,值得注意的是,boot_entry为函数名并且需要在前声明为外部函数

	# 声明函数为外部声明的函数
	.extern boot_entry

         接着先新建loader工程,loader工程中如图所示:

       加入loader新工程需要在上一层文件中的CMake配置文件中加入该段代码来配置整个工程:

add_subdirectory(./source/loader)

并在新工程下也新建一个CMakeLists.txt的文件便于CMake对工程进行管理(博主跟着课程直接复制boot的配置文件进行相应的更改),然后将script文件夹以及.vscode文件夹下相应操作系统的shell脚本文件中与loader文件有关的语句取消注释即完成新工程的创建。

        其中.c文件有两个是因为一个c文件为16位实模式下执行的loader代码,一个为32位保护模式下的loader代码。

        loader_16.c文件中需要将__asm__(".code16gcc") 代码置于第一行表示该文件代码编译为16位的代码。如:

//__asm__ 是GCC的内联汇编的关键字,用于插入汇编代码
//该代码用于告诉GCC生成16位的代码
__asm__(".code16gcc");

        因为boot和loader在不同的地方,从boot工程跳转到loader工程则可以通过指针函数的方式完成跳转,即在boot.c的中写如:

//宏定义loader起始地址
#define LOADER_START_ADDR 0x8000

/**
 * Boot的C入口函数
 * 只完成一项功能,即从磁盘找到loader文件然后加载到内容中,并跳转过去
 */
void boot_entry(void) {
    //通过函数指针的方式强制转化该地址并调用该地址完成工程之间的跳转
    ((void (*)(void))LOADER_START_ADDR)();
} 

        这样就完成了由boot工程到loader工程的跳转工作。


项目gitee地址:https://gitee.com/jim-jenny/x86-32OS

  • 24
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值