前言

最近接了一个外包项目再加上填一些之前立的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)。段属性里包含了一个特权级信息等等

  • 特权级

至于保护模式为什么叫做保护模式,可能就是因为它指定了代码都是在一个特定的特权级下运行的,从而决定了代码可以做什么,不可以做什么

  1. CPL:当前特权级(Current Privilege Level) 保存在CS段寄存器(选择子)的最低两位,CPL就是当前活动代码段的特权级,并且它定义了当前所执行程序的特权级别)
  2. 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操作系统的启动的更多相关文章

  1. 我是如何学习写一个操作系统(二):操作系统的启动之Bootloader

    前言 今天本来的任务看书和把之前写的FragileOS整理一下,但是到现在还在摸鱼,书也只看一点.后来整理了一下写这个系列的思路,原本的目的是对操作系统原理性的学习和对之前写的一个玩具型操作系统的回顾 ...

  2. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程

    通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...

  3. ucore lab1 bootloader学习笔记

    ---恢复内容开始--- 开机流程回忆 以Intel 80386为例,计算机加电后,CPU从物理地址0xFFFFFFF0(由初始化的CS:EIP确定,此时CS和IP的值分别是0xF000和0xFFF0 ...

  4. 操作系统的启动与引导问题 BIOS、UEFI、MBR、GPT

    关于ISO.WIM.GHO三者的正确理解. ISO(Isolation)文件一般以ISO为扩展名,是复制光盘上全部信息而形成的镜像文件. WIM是英文Microsoft Windows Imaging ...

  5. Linux内核剖析——操作系统的启动

    一.总体功能 1.从通电到BIOS跳转 1.1 CPU在通电后,先进入实模式,设置CS=0XFFFF,IP = 0X0000(指向BIOS) 1.2 BIOS进行执行系统监测,并且在地址=0处初始化中 ...

  6. 通过简单的Linux内核启动程序代码窥探操作系统的启动原理

    作者:吴乐  山东师范大学 <Linux内核分析> 孟宁 MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.程序设计与分析 ...

  7. CC3200模块的内存地址划分和bootloader,启动流程(二)

    1. 首先启动内部ROM固化的BOOT,然后这个ROM启动需要使用内存空间0X2000 0000 --- 0X2000 4000共16K的空间.一级BOOT的作用是串口升级和驱动库. 2. 然后是二级 ...

  8. 制作安装Linux操作系统的启动U盘方法其实就这么简单

    安装系统前,我们需要制作系统安装启动U盘(或者DVD,但已经很少使用DVD,所以不再介绍),通过启动U盘来帮助我们安装下载好的Linux系统. 接下来我们来介绍在Windows.Linux和MacOS ...

  9. Linux基础:操作系统的启动

    Centos6: # 1.加电自检(BIOS)# 2.MBR引导(512k)dd </dev/zero >/dev/sda bs=1k count=400 # 3.GRUB菜单(选择系统) ...

随机推荐

  1. 浅聊几种主流Docker网络的实现原理

    原文:https://mp.weixin.qq.com/s/Jdxct8qHrBUtkUq-hnxSRw 参考:https://blog.csdn.net/yarntime/article/detai ...

  2. wsl中的git问题

    当使用wsl打开Windows下的仓库时可能会出现所有文件都被标记为modified,这时一般有两种情况. 文件权限问题 由于wsl申请对文件的读写权限导致文件的权限发生改变.这时只需修改git的设置 ...

  3. msgTips 顶部弹窗

    最近发现好多网站都采用顶部弹窗,并且不用用户手动去点击确定.感觉这样很方便用户,所以也找了好多大神的代码,整理一下方便以后查找 前端: @{ Layout = null; } <!DOCTYPE ...

  4. javascript实现上传图片并展示

    我们也都知道上传图片的样子是这样的(选择前)是这样的(选择后). 先在HTML设置图片上传 <form action="" method=""> & ...

  5. ajax+vue简单使用

    <script type="text/javascript" src="http://cdn.bootcss.com/vue/2.2.2/vue.min.js&qu ...

  6. Django框架(十一)-- 补充:inclusion_tag、defer、only、choice、事务、创建多对多的第三张表、mvc和mtv模式

    一.inclusion_tag 1.作用 用于生成HTML片段,是数据由参数传入而变成动态 2.使用 # 1.app下新建一个模块,templatetags # 2.创建一个py文件(mytag.py ...

  7. spring mybatis错误问题该怎么解决

    1.org.apache.ibatis.exceptions.PersistenceExc org.apache.ibatis.exceptions.PersistenceException: ### ...

  8. 彻底理解webgl

    javascript很简单,核心点就一个: 一切皆对象. 简单又熟悉.呵呵 这么简单的一句话,理解后,你就掌握了js. 一切皆对象,函数也是对象,创建静态方法 fun.action, 创建实例:new ...

  9. Codeforces J. Soldier and Number Game(素数筛)

    题目描述: Soldier and Number Game time limit per test 3 seconds memory limit per test 256 megabytes inpu ...

  10. 孪生网络(Siamese Network)在句子语义相似度计算中的应用

    1,概述 在NLP中孪生网络基本是用来计算句子间的语义相似度的.其结构如下 在计算句子语义相似度的时候,都是以句子对的形式输入到网络中,孪生网络就是定义两个网络结构分别来表征句子对中的句子,然后通过曼 ...