本文共 6702 字,大约阅读时间需要 22 分钟。
开机过程中干了什么?
注:(5)中读取一个扇区的数据(512B)到内存0x7c00中、0磁道0扇区就是操作系统的引导扇区boot_sect -> set up -> system
先看看代码:可能看不懂,可以直接根据下面解释来看重点!
!! 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 = 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..globl begtext, begdata, begbss, endtext, enddata, endbss.textbegtext:.databegdata:.bssbegbss:.textSETUPLEN = 4 ! nr of setup-sectorsBOOTSEG = 0x07c0 ! original address of boot-sectorINITSEG = 0x9000 ! we move boot here - out of the waySETUPSEG = 0x9020 ! setup starts hereSYSSEG = 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 etcROOT_DEV = 0x306entry _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,INITSEGgo: 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_setupok_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,#21 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, nowinf_loop: jmp inf_loop! 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 (!= 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. seg cs mov ax,root_dev cmp ax,#0 jne root_defined seg cs mov bx,sectors mov ax,#0x0208 ! /dev/ps0 - 1.2Mb cmp bx,#15 je root_defined mov ax,#0x021c ! /dev/PS0 - 1.44Mb cmp bx,#18 je root_definedundef_root: jmp undef_rootroot_defined: seg cs mov root_dev,ax! after that (everyting loaded), we jump to! the setup-routine loaded directly after! the bootblock: jmpi 0,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 1+SETUPLEN ! sectors read of current trackhead: .word 0 ! current headtrack: .word 0 ! current trackread_it: mov ax,es test ax,#0x0fffdie: jne die ! es must be at 64kB boundary xor bx,bx ! bx is starting address within segmentrp_read: mov ax,es cmp ax,#ENDSEG ! have we loaded all yet? jb ok1_read retok1_read: seg cs mov ax,sectors sub ax,sread mov cx,ax shl cx,#9 add cx,bx jnc ok2_read je ok2_read xor ax,ax sub ax,bx shr ax,#9ok2_read: call read_track mov cx,ax add ax,sread seg cs cmp ax,sectors jne ok3_read mov ax,#1 sub ax,head jne ok4_read inc trackok4_read: mov head,ax xor ax,axok3_read: mov sread,ax shl cx,#9 add bx,cx jnc rp_read mov ax,es add ax,#0x1000 mov es,ax xor bx,bx jmp rp_readread_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,#0 and dx,#0x0100 mov ah,#2 int 0x13 jc bad_rt pop dx pop cx pop bx pop ax retbad_rt: mov ax,#0 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 mov dx,#0x3f2 mov al,#0 outb pop dx retsectors: .word 0msg1: .byte 13,10 .ascii "Hello my JYOS !" .byte 13,10,13,10.org 508root_dev: .word ROOT_DEVboot_flag: .word 0xAA55.textendtext:.dataenddata:.bssendbss:
下图是引导扇区的代码,其
先将0x070c:0x0000处的代码,移动到0x9000:0x0000 处 再跳转到go; 之后加载setup模块,如下图中,加载到0x9000后面的 0x9020 读入setup后,在屏幕上打印字符串;使用的是mov bp,msg1 mov ax, #1301 int 0x10 利用0x10中断完成显示(并未运行setup!当前指针并未到9020;当前OK_load_setup最后会先读入system模块,再跳转到执行setup.s如下图所示) 如果想要修改这个字符串:1. 修改msg1 2.修改对应字符串的大小:cx,#24中的24是字符串的长度; 下图为read_it中读入system模块的操作;完成后利用jmpi 给ip和cs赋值,完成跳转到setup,完成bootset;读取物理内存大小,并记录,将 system模块移动到0地址处;
在setup的最后,需要完成2件事: 1. 切换寻址模式、 2.跳转到0x0处开始执行system模块的代码;对于切换寻址模式:16-》32 因为在当前情况下使用的寻址模式是(如下图)cs << 4 + ip:其中cs是一个16位寄存器,其 <<4最多拥有20位地址,也就是1MB的内存大小; 这太小了,如今的计算机至少是4G的,因此需要切换寻址模式,不能使用 cs << 4 + ip;
切换的方法就是:下图中红色代码:使用cr0寄存器改变电路(修改末尾PE从 0—》1),从当前的 实模式 --》》》保护模式
在保护模式下,显然地址翻译不同,增加临时的GDT(global Description Table全局描述表)和IDT(中断描述)表;地址翻译从这个表中完成,得到真正的物理地址;这样上面图中的jmpi, 0 8 才能到0x0处;system模块相比于前面的bootsect 和 setup来说,要大得多!因为这是 真正用来校验的代码;
他是由一堆文件编译出来的;entry _start_start: mov ah,#0x03 xor bh,bh int 0x10 mov cx,#36 mov bx,#0x0007 mov bp,#msg1 mov ax,#0x07c0 mov es,ax mov ax,#0x1301 int 0x10inf_loop: jmp inf_loopmsg1: .byte 13,10 .ascii "Hello OS world, my name is LZJ" .byte 13,10,13,10.org 510boot_flag: .word 0xAA55
转载地址:http://kpzwi.baihongyu.com/