linux0.11内核源码——boot和setup部分
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部分的更多相关文章
- linux0.11内核源码剖析:第一篇 内存管理、memory.c【转】
转自:http://www.cnblogs.com/v-July-v/archive/2011/01/06/1983695.html linux0.11内核源码剖析第一篇:memory.c July ...
- linux-0.11 内核源码学习笔记一(嵌入式汇编语法及使用)
linux内核源码虽然是用C写的,不过其中有很多用嵌入式汇编直接操作底层硬件的“宏函数”,要想顺利的理解内核理论和具体实现逻辑,学会看嵌入式汇编是必修课,下面内容是学习过程中的笔记:当做回顾时的参考. ...
- linux0.11内核源码——进程各状态切换的跟踪
准备工作 1.进程的状态有五种:新建(N),就绪或等待(J),睡眠或阻塞(W),运行(R),退出(E),其实还有个僵尸进程,这里先忽略 2.编写一个样本程序process.c,里面实现了一个函数 /* ...
- Linux0.11内核源码——内核态进程切换的改进
本来想自己写的,但是发现了一篇十分优秀的博客 https://www.cnblogs.com/tradoff/p/5734582.html system_call的源码解析:https://blog. ...
- Linux0.11内核源码——内核态线程(进程)切换的实现
以fork()函数为例,分析内核态进程切换的实现 首先在用户态的某个进程中执行了fork()函数 fork引发中断,切入内核,内核栈绑定用户栈 首先分析五段论中的第一段: 中断入口:先把相关寄存器压栈 ...
- 自制操作系统小样例——参考部分linux0.11内核源码
详细代码戳这里. 一.启动引导 采用软件grub2进行引导,基于规范multiboot2进行启动引导加载.multiboot2的文档资料戳这里. 二.具体内容 开发环境 系统环境:Ubuntu 14. ...
- linux0.11内核源码——用户级线程及内核级线程
参考资料:哈工大操作系统mooc 用户级线程 1.每个进程执行时会有一套自己的内存映射表,即我们所谓的资源,当执行多进程时切换要切换这套内存映射表,即所谓的资源切换 2.但是如果在这个进程中创建线程, ...
- ubuntu14.04 64位系统下编译3.13.11内核源码
该过程一共分为四步: 1.下载内核:我下载的是3.13.11这个版本的内核! 2.解压内核:我将其解压/home/jello/Downloads/linux-3.13.11目录下!下文将会基于此目录编 ...
- linux0.01内核源码结构
目录 boot 系统引导. fs 文件系统. include 头文件.一些C标准库,系统核心库. init 入口.main.c. kernel 内核. lib 库.C源程序,一些基本核心的程序. mm ...
随机推荐
- Docker 官网文档翻译汇总
官方文档地址 Guide Docker 入门 Docker 入门教程 方向和设置 容器 服务 swarm 集群 stack 部署应用 概述 用 Docker 进行开发 在 Docker 上开发应用 应 ...
- iframe父窗口和子窗口的调用方法
iframe 父窗口和子窗口的调用方法父窗口调用子窗口 iframe_name.iframe_document_object.object_attribute = attribute_value 例子 ...
- 手撸红黑树-Red-Black Tree 入门
一.学习红黑树前的准备: 熟悉基础数据结构 了解二叉树概念 二.红黑树的规则和规则分析: 根节点是黑色的 所有叶子节点(Null)是黑色的,一般会认定节点下空节点全部为黑色 如果节点为红色,那么子节点 ...
- STL之pair及其非成员函数make_pair()
std::pair是一个结构模板,提供了一种将两个异构对象存储为一个单元的方法. 定义于头文件 <utility> template< class T1, class T2 > ...
- Pandas matplotlib 无法显示中文
Pandas 无法显示中文问题 解决方案 Pandas在绘图时,会显示中文为方块,主要原因有二: matplotlib 字体问题seaborn 字体问题 (实际上,matplotlib是支持uni ...
- 【题解】Hankson 的趣味题
题目大意 已知正整数$a_{0}$.$a_{1}$.$b_{0}$.$b_{1}$($1 \leq a_{0}, a_{1}, b_{0}, b_{1} \leq 2 \times 10^{9}$), ...
- Codeforces 208E. Blood Cousins
传送门 题目大意: 小C喜欢研究族谱,这一天小C拿到了一整张族谱. 小C先要定义一下k-祖先. x的1-祖先指的是x的父亲 x的k-祖先指的是x的(k-1)-祖先的父亲 小C接下来要定义k-兄弟 x的 ...
- cgi+lighttpd上传大文件失败解决办法
问题: - 前端页面点击上传按钮,不超过30M的小文件顺利上传到板子指定位置,上传60Md的更新包,出错,http状态码413——请求实体过大 环境: - web服务器——lighttpd1.4.30 ...
- chrome浏览器canvas画图不显示
问题产生在学习cabvas给画布画图像的时候发现使用IE edge浏览器可以正常显示图像,而chrome则不行,经百度后知道是因为chrome浏览器会先加载javascript代码,之后才加载图片,这 ...
- Oracle:同步两张表的相同字段
有一个需求需要同步两张表的相同字段,比如表A和表B,这两张表是不同的用户下的表,表结构是一样的. 一开始我简单写了一个sql语句,如下: update ord_log1 A set (A.pid, A ...