linux 0.11 version 启动代码分析(bootsect.s)
来源:互联网 发布:知乎 chorm无法登陆 编辑:程序博客网 时间:2024/05/01 22:15
综述
启动代码位于/boot/,包含三个文件,均为汇编编写
/boot/bootsect.s
启动扇区的代码,位于启动扇区,即磁盘的0磁道,0磁头,第一扇区,bios运行之后会跳转到0x7c00处执行代码,这一段的代码则是将位于0x7c00处等待执行的代码。
!! SYS_SIZE is the number of clicks (16 bytes) to be loaded.! 0x3000 is 0x30000 bytes = 196kB, more than enough for current! versions of linux!!! SYSSIZE 为要加载的系统大小,对于当前版本linux来说是足够的!SYSSIZE = 0x3000!! bootsect.s (C) 1991 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 8*65536 bytes long. This should be no! problem, even in the future. I want to keep it simple. This 512 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.!! bootsect.s (C) 1991 Linus Torvalds版权所有!! bootsect.s在bios启动过程当中被加载到0x7c00处,然后把它自己移动到0x90000处,再跳转到0x90000处执行! ! 需要注意的是当前system有8×65536字节大小,在没有像minix中包含的缓冲区高速缓存的情况下! 这512KB的内核大小是足够的,即使在之后的版本当中也应该是足够的。!! NOTE! currently system is at most 8*65536 bytes long. This should be no! problem, even in the future. I want to keep it simple. This 512 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 !text,data,bss段放在一起,没有分区SETUPLEN = 4 ! setup占扇区数量 BOOTSEG = 0x07c0 ! bootsect的最初地址INITSEG = 0x9000 ! bootsect将会移动到整个地址SETUPSEG = 0x9020 ! setup的开始位置SYSSEG = 0x1000 !system加载的位置ENDSEG = SYSSEG + SYSSIZE ! system加载位置结束 !ROOT_DEV:0x000 - 作为启动的软驱类型! 0x301 - 第一个驱动器上的第一个分区ROOT_DEV = 0x306 entry start ! 入口地址为startstart: mov ax,#BOOTSEG mov ds,ax mov ax,#INITSEG mov es,ax mov cx,#256 sub si,si sub di,di rep ! 将0x7c00:0x0000位置处256字节复制到0x9000:0x0000处,一次两个字节 movw jmpi go,INITSEG ! 跳转至INITSEG段的go处,即复制之后位于0x90000处的下一条语句位置 go: mov ax,cs mov ds,ax mov es,ax! put stack at 0x9ff00. ! cs, ds, es, ss指向0x90000处 mov ss,ax mov sp,#0xFF00 ! arbitrary value >>512 ! 栈指针sp指向0x9FF00! load the setup-sectors directly after the bootblock.! 在boot块后直接加载setup模块! Note that 'es' is already set up.! 此时es已经设置过了load_setup:! setup 模块加载 mov dx,#0x0000 ! drive 0, head 0 ! dh为磁头号,dl为驱动器号,磁盘则位7置位 mov cx,#0x0002 ! sector 2, track 0 ! ch为磁道号的低8位,cl为开始扇区(位0—5)与磁道号高二位(位6—7) mov bx,#0x0200 ! address = 512, in INITSEG ! es:bx为目的地址,即0x9000:0x0200,0x92000位置 mov ax,#0x0200+SETUPLEN ! service 2, nr of sectors ! ah中为0x13号中断的功能号,即2号,al中为需要执行的扇区数量! 0x13号中断2号功能为将指定扇区的内容加载到内存里 int 0x13 ! read it ! 执行中断0x13 jnc ok_load_setup ! ok - continue ! 执行成功,跳转至ok_load_setup mov dx,#0x0000 ! 中断失败,复位驱动器,此时ah功能号为0x00 mov ax,#0x0000 ! reset the diskette int 0x13 ! 执行0x13号中断,0号功能,复位驱动器 j load_setup ! 回到load_setup重新加载ok_load_setup:! Get disk drive parameters, specifically nr of sectors/track ! 获取磁盘参数,尤其是扇区和磁道的数量 mov dl,#0x00 ! 通过dl指定磁盘 mov ax,#0x0800 ! AH=8 is get drive parameters ! ah(功能号)为0x08,0x13号中断0x08号功能,执行读取磁盘信息,并且返回信息放在cx中 int 0x13 mov ch,#0x00 ! 将ch设置为0,其实是将磁道号清空 seg cs mov sectors,cx ! 之前提到了扇区数不会超过256,所以al的低高两位为0,cx此时为扇区数! 将扇区数赋值给变量sectors mov ax,#INITSEG mov es,ax ! es已改变,重新指向INITSEG! Print some inane message mov ah,#0x03 ! read cursor pos ! 通过中断0x10,功能号0x03,读取光标位置 xor bh,bh int 0x10 mov cx,#24 ! 通过中断0x10打印消息 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) ! 接下来将system加载到0x10000 mov ax,#SYSSEG mov es,ax ! segment of 0x010000 ! es指向 0x010000 call read_it ! 调用子程序read_it,进行加载 call kill_motor ! 调用子程序kill_motor,关闭软驱motor! After that we check which root-device to use. If the device is! defined (!= 0), nothing is done and the given device is used.! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending! on the number of sectors that the BIOS reports currently.! 然后我们检查要使用的root设备,如果设备已经被定义了,那么就直接使用给出的设备! 否则就根据bios目前给出的扇区数量决定使用/dev/PS0 (2, 28)(1.44m软驱)! 或者 ! /dev/at0 (2,8) (1.2m软驱) seg cs mov ax,root_dev ! 是否已经指定了root设备? cmp ax,#0 jne root_defined ! root设备指定了,即不为0,则跳到root_defined子程序 seg cs mov bx,sectors ! 扇区数量放入bx中,准备进行比较 mov ax,#0x0208 ! /dev/ps0 - 1.2Mb ! 1.2Mb软驱的扇区数量 cmp bx,#15 je root_defined ! 如果是1.2Mb软驱,跳转 mov ax,#0x021c ! /dev/PS0 - 1.44Mb ! 判断是否为1.4Mb软驱 cmp bx,#18 je root_defined ! 跳转undef_root: jmp undef_root ! undef_root,死循环(未指定root_device也不为1.2m软驱和1.4m软驱则死循环)root_defined: ! root设备已经指定 seg cs mov root_dev,ax ! 保存root设备号! after that (everyting loaded), we jump to ! the setup-routine loaded directly after! the bootblock:! 所有的都加载完毕之后进入setup jmpi 0,SETUPSEG ! 跳转到setup! 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)!! !! 输入: es - 开始地址的内存段(一般为 0x1000)!sread: .word 1+SETUPLEN ! sectors read of current track !已读扇区head: .word 0 ! current head !当前的磁头track: .word 0 ! current track !当前磁道read_it: mov ax,es ! 检测es是否在0x1000处,此时es,ax为0x1000 test ax,#0x0fffdie: jne die ! es must be at 64kB boundary ! es必须为0x1000,如果不是就死机 xor bx,bx ! bx is starting address within segment !检测通过,清空bx bx = 0rp_read: !循环读取 mov ax,es ! 根据cs位置判断是否已经加载完毕,第一次的时候es和ax为0x1000 cmp ax,#ENDSEG ! have we loaded all yet? jb ok1_read ! 没有加载完毕,跳转至ok1_read ret ok1_read: seg cs mov ax,sectors ! 扇区数量放入ax中,(sectors为15或18) sub ax,sread ! 减去已读扇区数量 sread为5,ax减法后为10 mov cx,ax ! 将未读扇区数量放入cx中 shl cx,#9 ! 计算需要读取的字节数 cx * 512 = 10h * 512 = 8 * 1K = 8K add cx,bx ! 计算段内偏移 jnc ok2_read ! cf位无进位跳转 je ok2_read ! zf位置位则跳转 xor ax,ax ! 清空ax sub ax,bx ! 求补 shr ax,#9 ! 计算最多可读长度ok2_read: ! 读取64k以内数据 call read_track ! 读取磁道 mov cx,ax ! 保存ax add ax,sread ! 当前所读取的扇区数 seg cs cmp ax,sectors ! 对比需要读取扇区数 jne ok3_read ! 如果当前磁道还未读取扇区,则跳转至ok3_read继续读取 mov ax,#1 ! 如果当前磁头面已经读取完毕,则读取下一磁头面 sub ax,head ! 如果是0磁头,则跳转至ok4_read读1磁头面 jne ok4_read ! 如果不是,读下一磁道 inc track ok4_read: mov head,ax ! 保存当前磁头号 xor ax,ax ! 清空ax,准备保存已读扇区ok3_read: mov sread,ax ! 保存已读取扇区数 shl cx,#9 ! 计算读取的长度 add bx,cx ! 调整当前段内数据开始位置 jnc rp_read ! 如果小于64k边界值,跳转至rp_read继续读取 mov ax,es ! 已经读取64k数据,调整es位置 add ax,#0x1000 mov es,ax xor bx,bx ! 清除段内偏移值 jmp rp_read ! 跳转至rp_read继续读取read_track: ! 读取磁道函数 push ax ! ax、bx、cx、dx入栈保存 push bx push cx push dx mov dx,track ! 当前磁道号 mov cx,sread ! 当前已读扇区数 inc cx ! 读取扇区数 mov ch,dl ! ch中为当前磁头号 mov dx,head ! 取磁头号 mov dh,dl ! dh为磁头号 mov dl,#0 ! 当前驱动器号 and dx,#0x0100 ! 确保磁头号不大于1 mov ah,#2 ! int 0x13功能号2读磁盘到内存 int 0x13 ! 执行中断,进行读取 jc bad_rt ! 判断是否出错,出错则跳转至bad_rt处理 pop dx ! 如果读取成功则弹出入栈寄存器,并跳出此函数 pop cx pop bx pop ax retbad_rt: mov ax,#0 ! ah为零 mov dx,#0 ! 指定驱动器 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 ! dx入栈保存 mov dx,#0x3f2 ! 软驱控制器端口 mov al,#0 ! 命令字 outb ! 写入命令 pop dx ! dx出栈 ret ! 返回sectors: !之前用于存储扇区数量的变量 .word 0msg1: !要显示的信息 .byte 13,10 !回车换行的ASII码 .ascii "Loading system ..." .byte 13,10,13,10.org 508 !从地址508处开始root_dev: !定义根设备变量 .word ROOT_DEVboot_flag: !启动扇区的标志 .word 0xAA55.textendtext:.dataenddata:.bssendbss:
0 0
- linux 0.11 version 启动代码分析(bootsect.s)
- bootsect启动代码分析
- linux-0.11中bootsect.s分析
- Linux0.11内核--启动引导代码分析bootsect.s
- Linux0.11内核--启动引导代码分析bootsect.s
- Linux启动分析(2)— bootsect.S、setup.S、head.S分析
- Linux启动分析(2)— bootsect.S、setup.S、head.S分析
- Linux启动分析(2)— bootsect.S、setup.S、head.S分析
- Linux启动分析 bootsect.S、setup.S、head.S分析(学习转)
- Linux启动分析— bootsect.S、setup.S、head.S分析
- Linux启动分析(2)— bootsect.S、setup.S、head.S分析
- linux2.6.11启动代码之bootsect.s
- linux2.6.11启动代码之bootsect.s
- Linux 0.11/boot/bootsect.s
- linux-0.11抠代码-bootsect
- bootsect.s代码注释
- bootsect.S分析
- bootsect.s分析
- Linux java.net.UnknownHostException找不到主机名解决办法
- 第3章 操作符
- javascript代码放在<head></head>和<body></body>的区别
- Linux定时任务 Crontab命令 详解
- Samba文件共享服务搭建
- linux 0.11 version 启动代码分析(bootsect.s)
- 查看Linux是多少位的
- 如何将java web项目上线/部署到公网
- 链表的各类操作详解
- iOS开发 - 用AVPlayer封装一个播放器
- ache.ibatis.binding.BindingException: Type interface dynamicDao.dao.UserDao is not known to the Mapp
- cocos2d 3.10 lua 自定义场景切换方法
- asdasd
- elastic search学习