Lab1:bootloader操作系统的启动
前言
最近接了一个外包项目再加上填一些之前立的flag,发现好像很久没有发博客了。现在编译原理操作系统算法方面都还有大坑没有填,加上离实习越来越近,应用层方面的学习也要加强了,但反倒是压力越大越想摸鱼
之前暑假的时候跟着书上写过一个玩具操作系统,然后之后还翻了一下Linux0.11一起写了一个系列的博客,但是还是觉得认识的太浅薄,然后最近发现清华大学的一个操作系统课程,就跟着了。准备用博客来记录一下,虽然会和之前的那个系列有些重复,但是也算是加强巩固了
BIOS
对于所有寄存器开机时都有各自的初始值,在X86中,CS和EIP寄存器分别是F000H,0000FFF0H,所以X86开机执行的第一条指令就是位于这个位置的指令,一般这条指令都是长跳转指令,从这里跳到BIOS程序的起始位置。
BIOS的工作是硬件自检和初始化,并且读取该设备的第一扇区,并且转交CPU控制权
bootloader
由BIOS加载的第一扇区一般放的都是bootloader,bootloader的工作就是
- 切换到保护模式,启用分段机制
- 读取磁盘中的操作系统内核
- 将CPU控制权转交到操作系统
实模式
实模式的存在主要是为了兼容老的操作系统(16bit),在这种状态下软件可访问的物理内存空间不能超过1MB,主要的区别就是实模式的寻址能力和方式,实模式将整个物理内存看成分段的区域,程序代码和数据位于不同区域,操作系统和用户程序并没有区别对待,而且每一个指针都是指向实际的物理地址。
段基址 << 4 + 段内偏移
所以对于32位的处理器就有了保护模式。bootloader的一个工作就是将实模式切换为保护模式
保护模式
在保护模式下,对内存的管理就采用了分段机制,当然在后面还会有分页机制
分段机制将内存划分成以起始地址和长度限制这两个二维参数表示的内存块,这些内存块就称之为段
段机制里会有四个概念:
- 段选择子
在实模式下,段寄存器原本存放的是段基址,但在保护模式下存放的是段选择子,段选择子的本质其实是一个索引,在全局描述符表的索引,但是它还包含其它信息,比如特权级信息
- 全局描述符表
全局描述符表,其实就是一个保存着段描述符的数组
- 段描述符
至于段描述符就是真正描述物理地址的数据结构了,每个段由如下三个参数进行定义:段基地址(Base Address)、段界限(Limit)和段属性(Attributes)。段属性里包含了一个特权级信息等等
- 特权级
至于保护模式为什么叫做保护模式,可能就是因为它指定了代码都是在一个特定的特权级下运行的,从而决定了代码可以做什么,不可以做什么
- CPL:当前特权级(Current Privilege Level) 保存在CS段寄存器(选择子)的最低两位,CPL就是当前活动代码段的特权级,并且它定义了当前所执行程序的特权级别)
- DPL:描述符特权(Descriptor Privilege Level) 存储在段描述符中的权限位,用于描述对应段所属的特权等级,也就是段本身能被访问的真正特权级。
- 地址转换
在没有进入到保护模式的时候,对应的地址就是相应的物理地址,但是在启动了保护模式下,逻辑地址--> (分段地址转换) -->线性地址 == 物理地址
bootloader主要代码
void
bootmain(void) {
// 读取第一扇区
readseg((uintptr_t)ELFHDR, SECTSIZE * 8, 0);
// 判断操作系统内核编译后的文件是不是有效的ELF文件
if (ELFHDR->e_magic != ELF_MAGIC) {
goto bad;
}
struct proghdr *ph, *eph;
// 加载内核
ph = (struct proghdr *)((uintptr_t)ELFHDR + ELFHDR->e_phoff);
eph = ph + ELFHDR->e_phnum;
for (; ph < eph; ph ++) {
readseg(ph->p_va & 0xFFFFFF, ph->p_memsz, ph->p_offset);
}
// 启动内核
((void (*)(void))(ELFHDR->e_entry & 0xFFFFFF))();
bad:
outw(0x8A00, 0x8A00);
outw(0x8A00, 0x8E00);
/* do nothing */
while (1);
}
中断和异常
操作系统和CPU一起提供了一种能够打断操作系统和应用的正常执行,让操作系统完成相关处理,然后在恢复操作系统和应用的正常执行。在操作系统中,这种机制称为中断机制。
当CPU收到中断(通过8259A完成)或者异常的事件时,它会暂停执行当前的程序或任务,通过一定的机制跳转到负责处理这个信号的相关处理例程中,在完成对这个事件的处理后再跳回到刚才被打断的程序或任务中。
中断向量和中断服务例程的对应关系主要是由IDT(中断描述符表)负责。操作系统在IDT中设置好各种中断向量对应的中断描述符,留待CPU在产生中断后查询对应中断服务例程的起始地址。而IDT本身的起始地址保存在idtr寄存器中。
IDT的代码实现
void
idt_init(void) {
// __vectors中存放的就是所有的中断处理程序
extern uintptr_t __vectors[];
int i;
for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {
// 设置中断门
SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
}
// 加载进寄存器中
lidt(&idt_pd);
}
所有的中断处理程序最后都是进行一些寄存器的保存然后最后交由__alltraps调用trap
.globl vector0
vector0:
pushl $0
pushl $0
jmp __alltraps
.globl vector1
vector1:
pushl $0
pushl $1
jmp __alltraps
__alltraps:
pushl %ds
pushl %es
pushl %fs
pushl %gs
pushal
movl $GD_KDATA, %eax
movw %ax, %ds
movw %ax, %es
pushl %esp
call trap
popl %esp
.globl __trapret
__trapret:
popal
popl %gs
popl %fs
popl %es
popl %ds
addl $0x8, %esp
iret
最后trap调用trap_dispatch根据不同的服务来执行相关代码
void
trap(struct trapframe *tf) {
trap_dispatch(tf);
}
Lab1:bootloader操作系统的启动的更多相关文章
- 我是如何学习写一个操作系统(二):操作系统的启动之Bootloader
前言 今天本来的任务看书和把之前写的FragileOS整理一下,但是到现在还在摸鱼,书也只看一点.后来整理了一下写这个系列的思路,原本的目的是对操作系统原理性的学习和对之前写的一个玩具型操作系统的回顾 ...
- 通过从代码层面分析Linux内核启动来探知操作系统的启动过程
通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...
- ucore lab1 bootloader学习笔记
---恢复内容开始--- 开机流程回忆 以Intel 80386为例,计算机加电后,CPU从物理地址0xFFFFFFF0(由初始化的CS:EIP确定,此时CS和IP的值分别是0xF000和0xFFF0 ...
- 操作系统的启动与引导问题 BIOS、UEFI、MBR、GPT
关于ISO.WIM.GHO三者的正确理解. ISO(Isolation)文件一般以ISO为扩展名,是复制光盘上全部信息而形成的镜像文件. WIM是英文Microsoft Windows Imaging ...
- Linux内核剖析——操作系统的启动
一.总体功能 1.从通电到BIOS跳转 1.1 CPU在通电后,先进入实模式,设置CS=0XFFFF,IP = 0X0000(指向BIOS) 1.2 BIOS进行执行系统监测,并且在地址=0处初始化中 ...
- 通过简单的Linux内核启动程序代码窥探操作系统的启动原理
作者:吴乐 山东师范大学 <Linux内核分析> 孟宁 MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.程序设计与分析 ...
- CC3200模块的内存地址划分和bootloader,启动流程(二)
1. 首先启动内部ROM固化的BOOT,然后这个ROM启动需要使用内存空间0X2000 0000 --- 0X2000 4000共16K的空间.一级BOOT的作用是串口升级和驱动库. 2. 然后是二级 ...
- 制作安装Linux操作系统的启动U盘方法其实就这么简单
安装系统前,我们需要制作系统安装启动U盘(或者DVD,但已经很少使用DVD,所以不再介绍),通过启动U盘来帮助我们安装下载好的Linux系统. 接下来我们来介绍在Windows.Linux和MacOS ...
- Linux基础:操作系统的启动
Centos6: # 1.加电自检(BIOS)# 2.MBR引导(512k)dd </dev/zero >/dev/sda bs=1k count=400 # 3.GRUB菜单(选择系统) ...
随机推荐
- Prometheus监控学习笔记之prometheus 版本1.7 常用启动参数
日志类: -log.level 可选值 [debug, info, warn, error, fatal] 例:-log.level "info" -log.format 可选 ...
- 我得新博客上线了采用Vue+Layui的结合开发,后台采用asp.net mvc
地址:www.zswblog.xyz 写完这个博客项目我真的很开心! 希望博客园的大佬们能去看看,如果可以希望帮我在Layui的年度案例点一个赞,谢谢! 地址:https://fly.layui.co ...
- Redis之缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级
目录 Redis之缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级 1.缓存雪崩 2.缓存穿透 3.缓存预热 4.缓存更新 5.缓存降级 Redis之缓存雪崩.缓存穿透.缓存预热.缓存更新.缓存降级 ...
- python3 + robotframework ride 乱码问题
执行ride时乱码问题 如果被执行的文件所在路径中含有中文,执行时可能会报如下错误 robotframework版本:robotframework-ride 1.7.3.1python 3.7.3 解 ...
- 开发--CentOS-7安装及配置
开发|CentOS-7安装及配置 本文主要进行详细讲解CentOS7.5系统的安装过程,以及CentOS系统初始化技术.我并不想将这篇文章变成一个教程,尽管我将详细的进行每一步的讲解,enjoy! 前 ...
- JDBC注册驱动程序3种方式
以MySQL的驱动为例,介绍注册驱动程序的3种方式 1:Class.forName("com.mysql.cj.jdbc.Driver");// 加载数据库驱动 package c ...
- token安全之任意密码重置
前言 偶然间挖了一个漏洞是密码重置,挖掘过程很有趣,可以参考下. 挖掘过程 在说明之前我们可以先走下正常流程,这样才方便查漏~ 正常流程 第一步骤: 正常填写完,点击下一步发送请求: POST /[U ...
- 『计算机视觉』imgaug图像增强库中部分API简介
https://github.com/aleju/imgaug 介绍一下官方demo中用到的几个变换,工程README.md已经给出了API简介,个人觉得不好理解,特此单独记录一下: import n ...
- 洛谷P2486 [SDOI2011]染色(树链剖分+线段树判断边界)
[题目链接] [思路]: 涉及到树上区间修改操作,所以使用树链剖分,涉及到区间查询,所以使用线段树. update操作时,就正常操作,难点在于query操作的计数. 因为树链剖分的dfs序只能保证一条 ...
- RMP和YUM软件安装
1.卸载RPM包 rpm -e rpm包的名称 2.安装rpm包 rmp -ivh xxx.rpm 3.查询yum服务器是否有需要安装的软件 yum list|grep xxx软件列表 4.yum安装 ...