cpu reset ->bios(检查,初始化硬件) ->mbr ->bootloader(GDT ,保护模式开始)->kernel程序(从硬盘加载到内存的虚拟地址)
download:https://sourceforge.net/projects/bochs/files/bochs/
installation reference:https://blog.csdn.net/qq_45923646/article/details/120156421
1.脚本安装相关依赖
2.configure程序根据环境和配置,生成Makefile
添加很多选项 --enable-gdb
3.make & make install
根据makefile进行编译
将编译生成的文件安装到系统中,可能安装到/usr/local/bin or /usr/local/lib
4.可以运行,但需要配置硬盘
使用bximage来配置磁盘 (将mbr写入虚拟硬盘)
bochsrc.disk是bochs运行的配置文件
./bochs -f bochsrc.disk 依照src文件配置,启动bochs
可以写成脚本加入到移动到PATH的目录中,可以直接运行
现在启动系统提示 no bootable device (因为启动盘上什么都没有)
工程PATH= /home/jerry/Downloads/bochs
程序从硬盘,软盘,usb载入内存某区域
cpu的cs:ip的寄存器指向这个程序的起始位置
实模式下 (内存分段访问机制)
物理地址 = 段地址*16 +偏移地址
因为,cpu的寄存器为16位,而地址总线为20位(为了充足的内存1M)
乘16,对于二进制等价于左移4位。
这1M并不是全部对应DRAM(物理内存),而是分配一部分给显存,ROM等
一个计算机能使用多大的内存由地址总线位数决定,而不是随意的堆硬件.32位对应4G内存,插入4G内存条,但实际使用物理内存不到4G
magic number 魔数:计算机中固定写死的东西
伪指令:对于cpu可识别的指令之外,由编译器规定的指令(及时cpu无法理解,但编译器会把它翻译成指定的机器指令)
ex:mov ax, 0
bin:二进制文件,cpu可以直接运行
elf:有于cpu指令无关的东西,程序布局等,需要运行在程序加载器上
流程
- 上电,cpu寄存器被初始化为指定地址,处于实模式(bios入口)
ex:0XFFFF0 此处为指令
- 检测硬件,初始化硬件,建立数据结构,建立中断向量表,secure boot(if)
- bios效验硬盘中(启动盘)0盘0道1扇区的内容,如果扇区末尾的magic number为0x55,0xaa,bios确认此扇区为可执行程序。
- bios将扇区程序MBR加载到内存的物理地址0X7c00,bios再跳转到0x7c00
一个扇区默认512字节,MBR也是512字节
(把程序加载到内存的硬件电路实现:向磁盘控制器发送一个读取命令,指定要读取的扇区号和读取的扇区数量。磁盘控制器将根据这些信息将磁盘上的数据读取到一个称为缓冲区的内存区域中。在数据被读取到缓冲区之后,引导程序将读取到的数据从缓冲区复制到内存中的正确位置
- run MBR,全称为主引导记录(Master Boot Record)
bootloader+分区表(partition table)
执行:
汇编MBR代码:https://github.com/yifengyou/os-elephant/blob/master/code/c02/a/boot/mbr.S
汇编编译器:nasm
dd:磁盘读写工具
nasm -o mbr.bin mbr.S
dd if=xx of=xx ...
将MBR 字节码刷写到磁盘中
效果:bios之后启动了磁盘中的简单MBR程序,屏幕显示 1 MBR
编译器和链接器在编译和链接过程中,会为程序中的各个变量、函数等符号分配一个符号表中的地址(即逻辑地址),这些地址是相对于可执行程序本身的。而在程序运行时,操作系统会将程序加载到内存中,并将逻辑地址转换成物理地址,然后再让 CPU 访问这些地址中的指令和数据。
1.计算机中有指令(不同格式),数据(不同数据类型,不同长度)
2.编译器把数据组织成不同的section(data section,code section)
3.每个Section都被分配了一段连续的地址空间,可执行文件中的指令和数据都存储在对应的Section中
cpu工作逻辑:
可见 VS 不可见 (programmer能否控制与否)
通过指令寄存器来获取指令,指令译码器运行,将相应的操作数放入寄存器(获取操作数先缓存,再内存)
1.cs:ip寄存器 访问内存
ip代码段地址(不可见) + cs偏移地址(可见)
instruction pointer code section
**2.flag寄存器 **
3.通用寄存器
实模式VS保护模式
1.实模式:运用于早期电脑,用户程序和操作系统处于统一特权级别,随意访问任何物理内存地址,没有内存保护机制和虚拟化技术。实模式是早期x86架构的工作模式,它是一种简单的模式,可以使用20位地址总线和16位寄存器来访问内存
cpu寻址方式:
- 直接寻址:直接给出要访问的内存单元地址,例如MOV AX, [0x1234],将0x1234处的内容存入AX寄存器。
- 寄存器间接寻址:使用寄存器存储要访问的内存地址,例如MOV AX, [BX],将BX寄存器中的地址对应的内存内容存入AX寄存器。
- 寄存器相对寻址:使用一个基址寄存器和一个偏移量,计算出要访问的内存地址,例如MOV AX, [BX+SI+0x1234],将(BX+SI+0x1234)处的内存内容存入AX寄存器。
- 基址加变址寻址:使用一个基址寄存器和一个变址寄存器,加上一个可选的偏移量,计算出要访问的内存地址,例如MOV AX, [BX+DI+0x1234],将(BX+DI+0x1234)处的内存内容存入AX寄存器。
栈(堆栈):后进先出,栈顶地址小于栈底地址
1.外设硬件种类繁多(模拟,数字,串行,并行,同步异步),且相对cpu来说运行速度慢。
2.cpu通过IO接口与各种硬件打交道(硬件+软件),硬件:具体实现 软件:驱动程序和各种协议 (驱动硬件工作)
3.数据缓冲,数据格式转换,时序电路同步
4.cpu 》总线 》南桥芯片 (各总线被设计通过寄存器与cpu通信)
5.IO接口可
能加入内存映射,通过地址来访问,也可能独立编址,使用专门的指令来操作(操作寄存器)
目的:整个系统内各部件之间的信息进行传输、交换、共享和逻辑控制
系统总线:数据总线(USB总线,PCI总线等),地址总线(16位,32位,64位),控制总线(中断等),电源总线
内存:内存通常是通过内存总线(Memory Bus)与CPU相连的,内存总线通常是双向数据传输的。显卡:显卡通常是通过PCI Express(PCIe)总线与CPU相连的,PCIe总线是一种高速串行总线,可以提供高带宽和低延迟的数据传输。
硬盘:硬盘通常是通过SATA(Serial Advanced Technology Attachment)总线或者SAS(Serial Attached SCSI)总线与CPU相连的,这些总线都是串行总线,可以提供高速的数据传输。
网卡:网卡通常是通过PCIe总线或者PCI(Peripheral Component Interconnect)总线与CPU相连的,PCIe总线可以提供更高的带宽和更低的延迟。
USB设备:USB设备通常是通过USB(Universal Serial Bus)总线与CPU相连的,USB总线是一种串行总线,可以连接多个外设,并且可以热插拔。
1显卡》显示器 : 显卡提供显存和IO端口两个可编程接口
2输入二进制 》对应对照关系 (ex ASCII)显示器上显示 (文字模式)
彩色图片模式更复杂
3显卡也有bios,显存也被地址总线分配了地址
4两字节显示文字 (高位:颜色信息,低位ASCII)
5主板bios中mbr,把输出改为显存地址
该边MBR内代码,使用显存输出到显示屏,刷写到硬盘中运行。
pending
机械硬盘,固态硬盘
硬盘控制器和硬盘集成-》IDE 集成设备电路
全球标准:PATA,SATA接口
控制硬盘,就是控制硬盘控制器的端口,而端口就是控制器的寄存器
MBR受限于512字节,需要从硬盘中读取loader加载到内存中
如何从实模式切换到保护模式?
实模式:内存分段(GDT)
1.实模式产生于16位的cpu。32/64位cpu兼容实模式和保护模式。
等价于cpu要兼容不同长度的指令(16/32),不同长度的操作数(8/16/32)
需要指名该代码的运行模式,编译器才能编译成为合适的机器码 (反转前缀,编译器操心)
32位cpu为了兼容16位的机制,产生了保护模式和实模式,可以理解为一个会做中西餐的厨师,是可以做中餐的
2.地址总线,数据总线,寄存器发展到32位,寻址空间达到4GB
除了段寄存器依然为16位,原因pending, 成为全局描述符表的选择子
3.引入缓存(缓冲寄存器)
4.实模式下段基地址+偏移量。在保护模式中,需要为内存段添加一些安全属性描述该内存段:段描述符(数据结构:8 bytes):描述一个内存段,所有的描述符统一存放在全局描述符表中(GDT global descriptor table, cpu有专门的指令和寄存器进行访问和初始化)。
最终在段寄存器中存放的是段的选择子。索引值在段描述符表中索引,最终得到内存断的起始地址等相关信息
目的:
确保了每个进程只能访问自己的地址空间,从而达到隔离进程的作用
内核态,用户态代码都需要载入内存,系统调用其实是内存中内核态代码的重复调用,而用户态程序在需要时从硬盘加载到内存中
方法:内存分段(segmentation),内存分页(paging)
1.逻辑上连续,物理上不连续。
2.线性空间,虚拟空间,物理空间。物理空间所有进程+os共享,但每个进程都有4G的虚拟空间。
3.最终送到地址总线的是转换后的物理地址。

4kb为一页,4G/4kb =4 * 1024 * 1024 * kb /4kb = 1024 * 1024
需要用20位地址来表示(像数组标号1,2,3,4)。
一级页表: 虚拟地址的高20位用来索引页表的表项+ 12位页内偏移地址 -》物理地址
二级页表: 一级页表太过于占用空间,引入二级页表:1M个表项分成1K个页表,每个页表有1K个表项的形式
- 高10位作为页目录表的索引,获取页表的物理地址
- 中间10位作为物理页表项的索引,从页表中获取物理页地址
- 将获取到的物理页地址加上后12位页内偏移,获取真实的物理地址
1.每个进程都有自己的页表,每个进程都有自己的独立地址空间,每个进程只能访问自己的地址空间
2.实现一个功能是用户态进程+系统调用才能完整实现的,且用户态是没有权限访问用户态的。ex:4G虚拟内存空间,内核态分配1G,用户态3G
pending......
1.调用库 》 封装系统调用 》中断描述符表(interrupt descripter)
(向就此拿起输入系统调用号,中断指令引发中断,开启中断处理程序 linux中:/usr/include/asm/unistd.h)
-
c语言开发操作系统,就像已经使用了封装好的一套汇编程序,最终都会翻译成机器指令。(抽象化)
-
头文件:程序信息与程序绑定(入口地址,大小,分配内存)ex:高铁站的列车时刻表,去找列车 不需要放在cpu上执行
-
loader将kernel从硬盘中读出,并加载到内存
处理器面对不同的任务,切换特权等级,不同的特权等级使用不同的栈
- 编写操作系统程序的逻辑:
编译为目标文件(未编址) -》 ld命令链接指定文件的虚拟地址
- 函数调用:主调与被调,参数存在什么地方:每个进程有自己的内存空间,存放在栈中
1.参数如何存放,发生中断如何保存现场 (栈)
2.压栈顺序
3.栈空间的清理 (主调与被调函数之间的约定:cdecl:从右向左入栈,调用者清理栈空间)
subtract(int a, int b){
return a-b;
}
int c = subtract(3,2)控制显卡显示文字
区别:
内存地址(MMU管理的虚拟地址)
端口(cpu外部的寄存器 ,由硬件直接处理)
note:有些寄存器也可以看作是内存的一部分,被分配内存地址
1.type的值是多少 SEC的实现怎么看
2.内核挂载点如何查询
3.遇到陌生的东西,如何查询
bg
1.任务优先级,保证整体运行的效率(有文件下载时,鼠标可以工作),且os是中断驱动的
2.单核cpu谈并发,多核cpu谈并行
一个进程,可以创建多个线程,多线程可以同时运行在不同的cpu上实现并行
3.cpu(中断描述符表) -》中断代理芯片(中断向量号):(统一管理可屏蔽中断的优先级判决,再向cpu提供需要执行的中断号)-》主板接口-》外部设备
分类:(中断上半部分:必须马上做,中断下半部分:可以推迟一下)
收到到中断信号,根据中断号,索引并运行中断描述符表中的中断处理程序
1.外部中断(硬件中断):
硬件触发,通过公用中断信号线传递给cpu(INTR and NMI)
1)INTR:可屏蔽中断:外部设备触发,但不影响系统运行(硬盘,鼠标)
2)NMI:不可屏蔽中断:灾难性 ,会宕机(电源掉电,内存读写)
(一般不是软件问题,需要硬件工程师)
2.内部中断
1)软中断:软件主动发生的中断(系统调用)
2)异常:主动发出,cpu运行时错误,但存在异常结果(中断溢出,数组越界,未定义指令)
首先,中断分为软件中断和硬件中断:
- 软件中断通过指令向系统发送中断向量号
- 硬件中断通过中断控制器判断当前中断的优先级后向 CPU 的 INTR 引脚发送中断中断向量号
得到中断向量号之后,CPU 通过向 IDTR 寄存器查询中断描述符表 IDT 的地址
通过中断向量号索引当前中断在 IDT 中的位置,也就是门描述符,从中获取该中断响应的中断处理程序的地址
跳转到中断处理程序去执行,通过 iret 返回
bg:内存分页 32位,虚拟地址,对于内核/用户的任务都有4G虚拟地址
1.内存池:内核内存池,内核物理内存池
- 对于
内核进程,申请内存地址时,从内核的虚拟内存地址池中分配虚拟地址,再从内核物理内存池中分配物理内存,然后在自己的页表中将两个地址建立好映射关系 - 对于
用户进程,申请内存地址时,从内核的虚拟内存地址池中分配虚拟地址,再从用户物理内存池中分配物理内存,然后在自己的页表中将两个地址建立好映射关系
进程,线程
1.对于单核处理器(并发,多任务切换),对于多核处理器(并行)
2.进程与线程(一个部门完成一个项目,但划分为共享资源的多个小组)进程拥有整个地址空间,线程没有
进程 = 线程+资源。(每个进程都有自己的虚拟地址空间,线程没有,但才是调度器中的基本单元
3.单线程进程,多线程进程
4.进程PCB(进程状态,id,优先级,寄存器印象,页表)
5.内存中内核与用户态已经存放在不同的区域,所以线程这一技术分为内核实现和用户态实现。
内核中线程实现:机制由内核原生实现,提供系统调用,但运行逻辑可以运行用户态代码 (更好)
用户态线程实现:既实现线程机制,又实现运行逻辑,线程自己维护线程调度器和线程表 (调线程包) (优点:自定的线程调度算法,不用陷入到内核中减少入栈和出栈 缺点:时间片机制决定每次分配时间并不是很多) 操作系统不知道线程的存在
任务调度器(内核实现)-》进程表(所有进程PCB信息)-》线程表(线程调度)-》将寄存器信息(保存现场)加载到处理器中


