实验内核版本:0.11

  ◆ 从开机到main函数的三步:

   启动BIOS,准备实模式下的中断向量表和中断服务程序;

   从启动盘加载OS程序到内存中,加载OS程序的工作就是利用第一步中的中断服务程序实现的;

   为执行保护模式下32位的main函数做过渡工作。

  

  Intel将所有80x86系列的CPU硬件都设计为加电即进入16位实模式状态运行;

  将CPU硬件逻辑设计为在加电瞬间强行将CS置为0xFFFFIP置为0x0000,即是CS:IP指向了0xFFFF0这个地址;  

  整个过程是一个纯硬件完成给你的,恰好ROM-BIOS的入口地址就是0xFFFF0,即是BIOS程序的第一条指令就设计在这个位置上。

  

  ➤ BIOS加载中断向量和终端服务程序到内存

  BIOS通常被固化在ROM中,它通常会检查显卡、内存等自检操作,当然,在这里最值得一提的是BOIS在内存中建立中断向量表和中断服务程序。书中选择的BIOS的大小为8KB,地址为:0xFE000~0xFFFFF。

   BIOS在内存最开始的位置(0x00000)用1KB的内存空间(0x00000~0x003FFF)构建中断向量表。中断向量表由256个中断向量,每个中断向量占4 Byte,其中两个Byte为CS的值,两个Byte为IP的值。1K = 256 × 4B。

   在紧接着中断向量表的256 Byte的内存空间构建BIOS数据区(0x00400~0x004FF)。

   在大约56KB以后的位置(0xE2CE)加载8KB左右的与中断向量相应的若干中断服务程序。0xE2CE = 14 + 12 × 16 + 2 × 162 + 14 × 163 = 14 + 12 × 24  + 2 × 28 + 14 × 212(14 × 4 × 210 = 56KB) = 56.52734375KB。

  

  ◆ 加载OS内核程序:

  现在将开始执行boot操作了。此时,计算机将分三次将OS逐次加载到内存中。

   由BIOS中断int0x19 把第1扇区bootsect的内容加载到内存中。

   由bootsect将第1个扇区之后的4个扇区加载至内存。

   由bootsect将第5个扇区之后的240个扇区加载至内存。

  

  图1 boot下的三个文件

  ➤ 加载引导程序bootsect(第一个扇区)

  1. 计算机硬件与BIOS联手,通过CPU执行int 0x19中断将引导程序所在的第一个扇区加载至内存。int 0x19中断向量指向的中断服务程序的入口地址是0x0E6F2,该中断服务程序的功能是固定的,它会将软驱的0号磁头对应盘面的0磁道1扇区的内存拷贝至0x07C00处。引导程序代码在boot/bootsect.s文件中。

  2. 当它被执行时,首先会将自己移动到0x90000(代码段最开始的地方就做了这个操作line 46)。

  3. 然后,它设置堆栈,栈顶指定为0x9000:0xFF00。

  4. 读第2~5共4个扇区的代码(setup.s)到内存0x90200处。

  5. 将第5个扇区之后的240个扇区的代码(system模块)读入到以0x10000开始的内存。

  6. 之后,bootsect.s将控制权交给setup.s。

图2 执行过程图

  

bootsect.s代码如下:

 !
! SYS_SIZE is the number of clicks ( bytes) to be loaded.
! 0x3000 is 0x30000 bytes = 196kB, more than enough for current
! versions of linux
!
SYSSIZE = 0x3000
!
! bootsect.s (C) Linus Torvalds
!
! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
! iself out of the way to address 0x90000, and jumps there.
!
! It then loads 'setup' directly after itself (0x90200), and the system
! at 0x10000, using BIOS interrupts.
!
! NOTE! currently system is at most * bytes long. This should be no
! problem, even in the future. I want to keep it simple. This kB
! kernel size should be enough, especially as this doesn't contain the
! buffer cache as in minix
!
! The loader has been made as simple as possible, and continuos
! read errors will result in a unbreakable loop. Reboot by hand. It
! loads pretty fast by getting whole sectors at a time whenever possible. .globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text SETUPLEN = 4 ! nr of setup-sectors
BOOTSEG = 0x07c0 ! original address of boot-sector
INITSEG = 0x9000 ! we move boot here - out of the way
SETUPSEG = 0x9020 ! setup starts here
SYSSEG = 0x1000 ! system loaded at 0x10000 (65536).
ENDSEG = SYSSEG + SYSSIZE ! where to stop loading ! ROOT_DEV: 0x000 - same type of floppy as boot.
! 0x301 - first partition on first drive etc
ROOT_DEV = 0x306 entry start
start:
mov ax,#BOOTSEG
mov ds,ax
mov ax,#INITSEG
mov es,ax
mov cx,#256
sub si,si
sub di,di
rep
movw
jmpi go,INITSEG
go: mov ax,cs
mov ds,ax
mov es,ax
! put stack at 0x9ff00.
mov ss,ax
mov sp,#0xFF00 ! arbitrary value >>512 ! load the setup-sectors directly after the bootblock.
! Note that 'es' is already set up. load_setup:
mov dx,#0x0000 ! drive 0, head 0
mov cx,#0x0002 ! sector 2, track 0
mov bx,#0x0200 ! address = 512, in INITSEG
mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors
int 0x13 ! read it
jnc ok_load_setup ! ok - continue
mov dx,#0x0000
mov ax,#0x0000 ! reset the diskette
int 0x13
j load_setup ok_load_setup: ! Get disk drive parameters, specifically nr of sectors/track mov dl,#0x00
mov ax,#0x0800 ! AH=8 is get drive parameters
int 0x13
mov ch,#0x00
seg cs
mov sectors,cx
mov ax,#INITSEG
mov es,ax ! Print some inane message mov ah,#0x03 ! read cursor pos
xor bh,bh
int 0x10 mov cx,#24
mov bx,#0x0007 ! page 0, attribute 7 (normal)
mov bp,#msg1
mov ax,#0x1301 ! write string, move cursor
int 0x10 ! ok, we've written the message, now
! we want to load the system (at 0x10000) mov ax,#SYSSEG
mov es,ax ! segment of 0x010000
call read_it
call kill_motor ! After that we check which root-device to use. If the device is
! defined (!= ), nothing is done and the given device is used.
! Otherwise, either /dev/PS0 (,) or /dev/at0 (,), depending
! on the number of sectors that the BIOS reports currently. seg cs
mov ax,root_dev
cmp ax,#
jne root_defined
seg cs
mov bx,sectors
mov ax,#0x0208 ! /dev/ps0 - .2Mb
cmp bx,#
je root_defined
mov ax,#0x021c ! /dev/PS0 - .44Mb
cmp bx,#
je root_defined
undef_root:
jmp undef_root
root_defined:
seg cs
mov root_dev,ax ! after that (everyting loaded), we jump to
! the setup-routine loaded directly after
! the bootblock: jmpi ,SETUPSEG ! This routine loads the system at address 0x10000, making sure
! no 64kB boundaries are crossed. We try to load it as fast as
! possible, loading whole tracks whenever we can.
!
! in: es - starting address segment (normally 0x1000)
!
sread: .word +SETUPLEN ! sectors read of current track
head: .word ! current head
track: .word ! current track read_it:
mov ax,es
test ax,#0x0fff
die: jne die ! es must be at 64kB boundary
xor bx,bx ! bx is starting address within segment
rp_read:
mov ax,es
cmp ax,#ENDSEG ! have we loaded all yet?
jb ok1_read
ret
ok1_read:
seg cs
mov ax,sectors
sub ax,sread
mov cx,ax
shl cx,#
add cx,bx
jnc ok2_read
je ok2_read
xor ax,ax
sub ax,bx
shr ax,#
ok2_read:
call read_track
mov cx,ax
add ax,sread
seg cs
cmp ax,sectors
jne ok3_read
mov ax,#
sub ax,head
jne ok4_read
inc track
ok4_read:
mov head,ax
xor ax,ax
ok3_read:
mov sread,ax
shl cx,#
add bx,cx
jnc rp_read
mov ax,es
add ax,#0x1000
mov es,ax
xor bx,bx
jmp rp_read read_track:
push ax
push bx
push cx
push dx
mov dx,track
mov cx,sread
inc cx
mov ch,dl
mov dx,head
mov dh,dl
mov dl,#
and dx,#0x0100
mov ah,#
int 0x13
jc bad_rt
pop dx
pop cx
pop bx
pop ax
ret
bad_rt: mov ax,#
mov dx,#
int 0x13
pop dx
pop cx
pop bx
pop ax
jmp read_track /*
* This procedure turns off the floppy drive motor, so
* that we enter the kernel in a known state, and
* don't have to worry about it later.
*/
kill_motor:
push dx
mov dx,#0x3f2
mov al,#0
outb
pop dx
ret sectors:
.word 0 msg1:
.byte 13,10
.ascii "Loading system ..."
.byte 13,10,13,10 .org 508
root_dev:
.word ROOT_DEV
boot_flag:
.word 0xAA55 .text
endtext:
.data
enddata:
.bss
endbss:

  

《Linux内核设计的艺术》学习笔记(一)从开机加电到加载三个汇编源码的更多相关文章

  1. linux内核设计与实现学习笔记-模块

    模块 1.概念:  如果让LINUX Kernel单独运行在一个保护区域,那么LINUX Kernel就成为了“单内核”.    LINUX Kernel是组件模式的,所谓组件模式是指:LINUX K ...

  2. Linux内核设计与实现 读书笔记 转

    Linux内核设计与实现  读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://bl ...

  3. linux内核设计的艺术--系统启动第一步

    计算机究竟是如何执行起来的呢,在我学习计算机的时候一直不是非常明确,可是近期借了本<linux内核设计的艺术>算是知道了计算机从按开机到启动操作系统之间究竟做了些什么. 这本书刚開始介绍的 ...

  4. linux内核分析第四周学习笔记

    linux内核分析第四周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  5. Linux内核分析第二周学习笔记

    linux内核分析第二周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  6. linux内核分析第一周学习笔记

    linux内核分析第一周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  7. 初探内核之《Linux内核设计与实现》笔记上

    内核简介  本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核   原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单.2. 高效 ...

  8. Linux内核设计第一周学习总结 计算机如何工作

    北京电子科技学院 20135310陈巧然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002 ...

  9. Linux内核设计与实现 读书笔记

    第三章 进程管理 1. fork系统调用从内核返回两次: 一次返回到子进程,一次返回到父进程 2. task_struct结构是用slab分配器分配的,2.6以前的是放在内核栈的栈底的:所有进程的ta ...

随机推荐

  1. html5 canvas 笔记二(添加样式和颜色)

    色彩 Colors fillStyle = color 设置图形的填充颜色. strokeStyle = color 设置图形轮廓的颜色. 透明度 Transparency globalAlpha = ...

  2. (个人)读取A.CSV修改它的某列,写入B.CSV

    #!/usr/bin/perl -wuse strict;use warnings;use Tie::File; open(IN_FILE,"<E:/Hzj_works/test1.c ...

  3. href="#"会导致location.replace(location.href);脚本不工作

    我们经常这样:<a onclick="xxx" href="#" 其实这不是一个好习惯,当点下这个连接后,主页面的URL后面会加个#号,这样就会导致很多J ...

  4. 9、Http回顾/Servlet

    1 Http回顾 Http协议: 1)http协议: 对浏览器客户端和服务器端之间数据传输的格式规范. 2)http请求:浏览器->服务器端 格式: 请求行(请求方式(GET/POST) 请求资 ...

  5. iOS开发必备HUD(透明指示层)

    iOS开发必备HUD(透明指示层) 字数421 阅读2123 评论1 喜欢51 1.MBProgressHUD GitHub地址:https://github.com/jdg/MBProgressHU ...

  6. 用ThreadLocal为线程生成唯一标识及实现原理

    1.在多线程编程中,有时候需要自动为每个启动的线程生成一个唯一标识,这个时候,通过一个ThreadLocal变量来保存每个线程的标识是最有效.最方便的方式了. 2.ThreadLocal 实例通常是类 ...

  7. js判断radio,checkbox是否选中

    从数据库循环数据,多选按钮数组 function type_1(){ //多选 var b= document.getElementsByName('service_zj_ids[]');  var ...

  8. drivers/mfd/Mfd-core.c

    mfd: multifunction device drivers---多功能设备驱动开发:A product or device that has multiple functions. An ex ...

  9. Radar之字节流加载图片

    获取GUITexture GameObject _obj = GameObject.Find("Tex1"); GUITexture _tex = _obj.GetComponen ...

  10. Android Studio教程,Android Studio安装教程

    http://jingyan.baidu.com/article/67662997393cf654d51b8435.html