https://blog.csdn.net/KLKFL/article/details/80730131

  https://www.cnblogs.com/joey-hua/p/5528228.html

参考的两篇博客

x86系统在刚开机时CPU处于实模式

计算机在刚打开电源时 :CS=0xFFFF,IP=0x0000

即寻址为0xFFFF0(ROM BIOS映射区)

然后将 0磁道0扇区 的512个字节读入0x7c00处

然后设置   CS=0x07c0,IP=0x0000

此时0x7c00出存放的代码就是从磁盘的引导扇区读入的那512个字节bootsect

此时一些宏的定义:

 BOOTSEG = 0x07c0

 INITSEG = 0x9000

 SETUPSEG = 0x9020

 SYSSEG = 0x1000

表示bootsect先被加载到了0x07c0段,然后bootsect的512个字节会被移动到0x9000段,紧跟着的setup段就从0x9020段开始,system段从0x1000开始

bootsect做的事就是把setup加载到内存上,然后显示logo

 entry _start !程序的入口是_start 

 _start:
!下面是调用0x10中断,显示光标操作
mov ah,#0x03
xor bh,bh
int 0x10 mov cx,# !字符串msg的长度
mov bx,#0x0007 !调用0x10中断时,bx寄存器=0x0007表示显示树形
mov bp,#msg1
mov ax,#0x07c0
mov es,ax !es:bp表示要显示的字符串的地址,当前段(bootsect)就是0x07c0,字符串的地址已经赋值给bp
mov ax,#0x1301
int 0x10 !调用中断显示logo !设置一个死循环保证不退出
inf_loop:
jmp inf_loop !这就是要显示的logo
msg1:
.byte ,
.ascii "Hello OS world, my name is LZJ"
.byte ,,, !boot_flag是设置引导扇区的标记,必须由这个才能进行引导,且必须放在最后两个字节
!bootsect的大小是512个字节,所以boot_flag得放在第510个字节处
.org
boot_flag:
.word 0xAA55

然后用bootsect读取setup

先把setup.s编写好

 entry _start
_start:
mov ah,#0x03
xor bh,bh
int 0x10 mov cx,#
mov bx,#0x0007
mov bp,#msg2
mov ax,cs
mov es,ax !此时已经将setup加载到了0x9020处,所以字符串的断地址直接设置为cs即可
mov ax,#0x1301
int 0x10 !调用中断 inf_loop: !死循环防止退出
jmp inf_loop
msg1:
.byte ,
.ascii "Hello OS world, my name is LZJ"
.byte ,,, .org !这里还是和bootsect一样
boot_flag:
.word 0xAA55

然后对上面的bootsect.s进行修改让bootsect能够读入setup

 SETUPLEN=            !自定义的setup段的长度为2个扇区
SETUPSEG=0x07e0 !因为自定仪的代码没有将bootsect移到0x9000出,所以setup段的开始地址在磁盘的的0x07e0处
entry _start
_start:
mov ah,#0x03
xor bh,bh
int 0x10 mov cx,#
mov bx,#0x0007
mov bp,#msg1
mov ax,#0x07c0
mov es,ax
mov ax,#0x1301
int 0x10 load_setup: !从这里开始进行载入setup !0x13号中断是BIOS读磁盘扇区的中断
mov dx,#0x0000 !dh=磁头号,dl=驱动器号
mov cx,#0x0002 !ch=柱面号,cl=开始扇区
mov bx,#0x0200 !表示将读取的内容放在内存es:bp处,es是0x7c0,bp是0x200(前200字节)
mov ax,#0x0200+SETUPLEN !ah=0x02表示读磁盘,al=扇区数量,本来应该是4,但是自己写的setup只占用了2个扇区(512字节)
int 0x13 !调用中断读取setup jnc ok_load_setup !读入成功则跳转 mov dx,#0x0000 !读入失败则调用0x13中断进行复位重启,再次进行读入
mov ax,#0x0000
int 0x13
jmp load_setup !再次进行读写 ok_load_setup:
jmpi ,SETUPSEG !cs:ip跳转到0x07e0:0x0000处,即跳转到setup执行 msg1:
.byte ,
.ascii "Hello OS world, my name is LZJ"
.byte ,,, !自己写的setup.s只占用了512个字节(两个扇区),实际上linux0.11用了4个扇区
.org
boot_flag:
.word 0xAA55

然后用makefile进行编译,可能要修改下build.c

make BootImage

实际上,bootsect在读完setup后还会读入system,其地址为0x10000-0x8ffff

然后是setup需要完成的工作:

  完成os启动前的设置,使系统进入保护模式:

首先读入的就是硬件信息:光标,扩展内存数,显卡参数,跟设备号

然后将system模块向下移动到0地址

  但是,0地址处本来有重要内容,比如int中断,如何避免冲突?

    此时setup让硬件进入保护模式,即int和cs:ip的寻址电路被改变,igt(中断描述符表:用来查中断)和gdt(全局描述符表:用来查cs值对应的段的地址)就是改变后的寻址方式

    cs在保护模式中也称为选择子,表示段的编号

  具体的实现:

    在system移动结束(end_move)后,新建一张临时的gdt表,其内容设置为

    

    下面是gdt表的格式

    

    有一个寄存器叫做cr0,其末尾PE=1为启动保护模式,

    所以先把cr0的末尾置为1来进入保护模式,然后执行指令

\

jmpi ,8 !cs=0x0008,ip=0x0000

     cs=8,对应的gdt从第8个字节开始后的内容恰好为0,所以要跳转的地址为0x0000:0x0000

    即system的开头head.s文件

到此为止setup也完成了任务,系统开始执行head.s

参考了一张图片,表示的是在每个阶段每个块的位置

模仿linux0.11的代码

 mov    ax,#INITSEG
! 设置 ds = 0x9000
mov ds,ax
mov ah,#0x03
! 读入光标位置
xor bh,bh
! 调用 0x10 中断
int 0x10
! 将光标位置写入 0x90000.
mov [],dx ! 读入内存大小位置
mov ah,#0x88
int 0x15
mov [],ax ! 从 0x41 处拷贝 个字节(磁盘参数表)
mov ax,#0x0000
mov ds,ax
lds si,[*0x41]    !把内存记录磁盘参数的值赋值给si
mov ax,#INITSEG    
mov es,ax        !INITSEG赋值给es
mov di,#0x0004     !
mov cx,#0x10 !
! 重复16次
rep
movsb

最后是setup.s的全代码

 INITSEG  = 0x9000
entry _start
_start:
! Print "NOW we are in SETUP"
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bx,#0x0007
mov bp,#msg2
mov ax,cs
mov es,ax
mov ax,#0x1301
int 0x10 mov ax,cs
mov es,ax
! init ss:sp
mov ax,#INITSEG
mov ss,ax
mov sp,#0xFF00 ! Get Params
mov ax,#INITSEG
mov ds,ax
mov ah,#0x03
xor bh,bh
int 0x10
mov [],dx
mov ah,#0x88
int 0x15
mov [],ax
mov ax,#0x0000
mov ds,ax
lds si,[*0x41]
mov ax,#INITSEG
mov es,ax
mov di,#0x0004
mov cx,#0x10
rep
movsb ! Be Ready to Print
mov ax,cs
mov es,ax
mov ax,#INITSEG
mov ds,ax ! Cursor Position
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bx,#0x0007
mov bp,#msg_cursor
mov ax,#0x1301
int 0x10
mov dx,[]
call print_hex
! Memory Size
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bx,#0x0007
mov bp,#msg_memory
mov ax,#0x1301
int 0x10
mov dx,[]
call print_hex
! Add KB
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bx,#0x0007
mov bp,#msg_kb
mov ax,#0x1301
int 0x10
! Cyles
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bx,#0x0007
mov bp,#msg_cyles
mov ax,#0x1301
int 0x10
mov dx,[]
call print_hex
! Heads
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bx,#0x0007
mov bp,#msg_heads
mov ax,#0x1301
int 0x10
mov dx,[]
call print_hex
! Secotrs
mov ah,#0x03
xor bh,bh
int 0x10
mov cx,#
mov bx,#0x0007
mov bp,#msg_sectors
mov ax,#0x1301
int 0x10
mov dx,[]
call print_hex inf_loop:
jmp inf_loop print_hex:
mov cx,#
print_digit:
rol dx,#
mov ax,#0xe0f
and al,dl
add al,#0x30
cmp al,#0x3a
jl outp
add al,#0x07
outp:
int 0x10
loop print_digit
ret
print_nl:
mov ax,#0xe0d ! CR
int 0x10
mov al,#0xa ! LF
int 0x10
ret msg2:
.byte ,
.ascii "NOW we are in SETUP"
.byte ,,,
msg_cursor:
.byte ,
.ascii "Cursor position:"
msg_memory:
.byte ,
.ascii "Memory Size:"
msg_cyles:
.byte ,
.ascii "Cyls:"
msg_heads:
.byte ,
.ascii "Heads:"
msg_sectors:
.byte ,
.ascii "Sectors:"
msg_kb:
.ascii "KB" .org
boot_flag:
.word 0xAA55

linux0.11内核源码——boot和setup部分的更多相关文章

  1. linux0.11内核源码剖析:第一篇 内存管理、memory.c【转】

    转自:http://www.cnblogs.com/v-July-v/archive/2011/01/06/1983695.html linux0.11内核源码剖析第一篇:memory.c July  ...

  2. linux-0.11 内核源码学习笔记一(嵌入式汇编语法及使用)

    linux内核源码虽然是用C写的,不过其中有很多用嵌入式汇编直接操作底层硬件的“宏函数”,要想顺利的理解内核理论和具体实现逻辑,学会看嵌入式汇编是必修课,下面内容是学习过程中的笔记:当做回顾时的参考. ...

  3. linux0.11内核源码——进程各状态切换的跟踪

    准备工作 1.进程的状态有五种:新建(N),就绪或等待(J),睡眠或阻塞(W),运行(R),退出(E),其实还有个僵尸进程,这里先忽略 2.编写一个样本程序process.c,里面实现了一个函数 /* ...

  4. Linux0.11内核源码——内核态进程切换的改进

    本来想自己写的,但是发现了一篇十分优秀的博客 https://www.cnblogs.com/tradoff/p/5734582.html system_call的源码解析:https://blog. ...

  5. Linux0.11内核源码——内核态线程(进程)切换的实现

    以fork()函数为例,分析内核态进程切换的实现 首先在用户态的某个进程中执行了fork()函数 fork引发中断,切入内核,内核栈绑定用户栈 首先分析五段论中的第一段: 中断入口:先把相关寄存器压栈 ...

  6. 自制操作系统小样例——参考部分linux0.11内核源码

    详细代码戳这里. 一.启动引导 采用软件grub2进行引导,基于规范multiboot2进行启动引导加载.multiboot2的文档资料戳这里. 二.具体内容 开发环境 系统环境:Ubuntu 14. ...

  7. linux0.11内核源码——用户级线程及内核级线程

    参考资料:哈工大操作系统mooc 用户级线程 1.每个进程执行时会有一套自己的内存映射表,即我们所谓的资源,当执行多进程时切换要切换这套内存映射表,即所谓的资源切换 2.但是如果在这个进程中创建线程, ...

  8. ubuntu14.04 64位系统下编译3.13.11内核源码

    该过程一共分为四步: 1.下载内核:我下载的是3.13.11这个版本的内核! 2.解压内核:我将其解压/home/jello/Downloads/linux-3.13.11目录下!下文将会基于此目录编 ...

  9. linux0.01内核源码结构

    目录 boot 系统引导. fs 文件系统. include 头文件.一些C标准库,系统核心库. init 入口.main.c. kernel 内核. lib 库.C源程序,一些基本核心的程序. mm ...

随机推荐

  1. leetcode 215. 数组中的第K个最大元素(python)

    在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2输出: 5示 ...

  2. delphi 按钮 2 行

    http://bbs.csdn.net/topics/390230792 回复于: 2015-06-01 21:11:02 最简单的办法:------------------------以下是转载的, ...

  3. Jmeter接口测试报告模板优化

    优化后在接口报告的接口信息中,直接展示url,method,结果和响应时间,详情中展示请求和响应数据.具体如下: 模板文件 jmeter-results-detail-report_21.xsl: & ...

  4. Jmeter从数据库中读取数据

    Jmeter从数据库中读取数据 1.测试计划中添加Mysql Jar包 2.添加线程组 3.添加 jdbc connection configuration 4.添加JDBC Request,从数据库 ...

  5. 2019年Java Web最流行的开发框架总结

    ORM型框架:对数据进行持久化操作,例如:基于SQL的MyBatis框架和Hibernate框架. MVC型框架:从逻辑上分为视图层,控制层,模型层,各层各司其职,之间是相互调用的关系,而不是相互依赖 ...

  6. 企业SRC整理

    0.SRCs|安全应急响应中心 - 0xsafe 1.腾讯安全应急响应中心(TSRC) 2.360安全应急响应中心 3.京东安全应急响应中心(JSRC) 4.平安集团安全应急响应中心(PSRC) 5. ...

  7. Easyui表格显示日期格式错误

    问题   如下图: 解决办法: 以Sql Server 2008为例,在执行查询时,把“采购日期”字段由datetime转换为string,前端以string类型显示.

  8. JavaScript LoopQueue

    function Queue() { var items = []; this.enqueue = function(element) { items.push(element) } this.deq ...

  9. Spring cloud学习--Zuul01

    Zuul解决的问题 作为系统的统一入口,屏蔽了系统内部各个微服务的细节 可以与微服务治理框架结合,实现自动化的服务实例维护以及负载均衡的路由转发 实现接口权限校验与微服务业务逻辑的解耦 搭建Zuul服 ...

  10. BZOJ 4675(点分治)

    题面 传送门 分析 由于期望的线性性,我们可以分别计算每个点对对答案的贡献 有三个人取数字,分开对每个人考虑 设每个人分别取了k个数,则一共有\(C_n^k\)种组合,选到每种组合的概率为\(\fra ...