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. Docker 官网文档翻译汇总

    官方文档地址 Guide Docker 入门 Docker 入门教程 方向和设置 容器 服务 swarm 集群 stack 部署应用 概述 用 Docker 进行开发 在 Docker 上开发应用 应 ...

  2. iframe父窗口和子窗口的调用方法

    iframe 父窗口和子窗口的调用方法父窗口调用子窗口 iframe_name.iframe_document_object.object_attribute = attribute_value 例子 ...

  3. 手撸红黑树-Red-Black Tree 入门

    一.学习红黑树前的准备: 熟悉基础数据结构 了解二叉树概念 二.红黑树的规则和规则分析: 根节点是黑色的 所有叶子节点(Null)是黑色的,一般会认定节点下空节点全部为黑色 如果节点为红色,那么子节点 ...

  4. STL之pair及其非成员函数make_pair()

    std::pair是一个结构模板,提供了一种将两个异构对象存储为一个单元的方法. 定义于头文件 <utility> template< class T1, class T2 > ...

  5. Pandas matplotlib 无法显示中文

    Pandas 无法显示中文问题 解决方案 Pandas在绘图时,会显示中文为方块,主要原因有二:   matplotlib 字体问题seaborn 字体问题 (实际上,matplotlib是支持uni ...

  6. 【题解】Hankson 的趣味题

    题目大意 已知正整数$a_{0}$.$a_{1}$.$b_{0}$.$b_{1}$($1 \leq a_{0}, a_{1}, b_{0}, b_{1} \leq 2 \times 10^{9}$), ...

  7. Codeforces 208E. Blood Cousins

    传送门 题目大意: 小C喜欢研究族谱,这一天小C拿到了一整张族谱. 小C先要定义一下k-祖先. x的1-祖先指的是x的父亲 x的k-祖先指的是x的(k-1)-祖先的父亲 小C接下来要定义k-兄弟 x的 ...

  8. cgi+lighttpd上传大文件失败解决办法

    问题: - 前端页面点击上传按钮,不超过30M的小文件顺利上传到板子指定位置,上传60Md的更新包,出错,http状态码413——请求实体过大 环境: - web服务器——lighttpd1.4.30 ...

  9. chrome浏览器canvas画图不显示

    问题产生在学习cabvas给画布画图像的时候发现使用IE edge浏览器可以正常显示图像,而chrome则不行,经百度后知道是因为chrome浏览器会先加载javascript代码,之后才加载图片,这 ...

  10. Oracle:同步两张表的相同字段

    有一个需求需要同步两张表的相同字段,比如表A和表B,这两张表是不同的用户下的表,表结构是一样的. 一开始我简单写了一个sql语句,如下: update ord_log1 A set (A.pid, A ...