linux内核分析(转自某位大哥网上的笔记).doc_第1页
linux内核分析(转自某位大哥网上的笔记).doc_第2页
linux内核分析(转自某位大哥网上的笔记).doc_第3页
linux内核分析(转自某位大哥网上的笔记).doc_第4页
linux内核分析(转自某位大哥网上的笔记).doc_第5页
已阅读5页,还剩124页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

启动 当PC启动时,Intel系列的CPU首先进入的是实模式,并开始执行位于地址0xFFFF0处的代码,也就是ROM-BIOS起始位置的代码。BIOS先进行一系列的系统自检,然后初始化位于地址0的中断向量表。最后BIOS将启动盘的第一个扇区装入到0x7C00,并开始执行此处的代码.这就是对内核初始化过程的一个最简单的描述。 最初,Linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自己装入到绝对地址0x90000,再将其后的2k字节装入到地址0x90200处,最后将核心的其余部分装入到0x10000。 当系统装入时,会显示Loading.信息。装入完成后,控制转向另一个实模式下的汇编语言代码boot/Setup.S。Setup部分首先设置一些系统的硬件设备,然后将核心从0x10000处移至0x1000处。这时系统转入保护模式,开始执行位于0x1000处的代码。 接下来是内核的解压缩。0x1000处的代码来自于文件Boot/head.S,它用来初始化寄存器和调用decompress_kernel( )程序。decompress_kernel( )程序由Boot/inflate.c, Boot/unzip.c 和Boot/misc.c组成。解压缩后的数据被装入到了0x100000处,这也是Linux不能在内存小于2M的环境下运行的主要原因。 解压后的代码在0x1010000处开始执行,紧接着所有的32位的设置都将完成: IDT、GDT和LDT将被装入,处理器初始化完毕,设置好内存页面,最终调用start_kernel过程。这大概是整个内核中最为复杂的部分。系统开始运行 Linux kernel 最早的C代码从汇编标记startup_32开始执行|startup_32: |start_kernel |lock_kernel |trap_init |init_IRQ |sched_init |softirq_init |time_init |console_init |#ifdef CONFIG_MODULES |init_modules |#endif |kmem_cache_init |sti |calibrate_delay |mem_init |kmem_cache_sizes_init |pgtable_cache_init |fork_init |proc_caches_init |vfs_caches_init |buffer_init |page_cache_init |signals_init |#ifdef CONFIG_PROC_FS |proc_root_init |#endif |#if defined(CONFIG_SYSVIPC) |ipc_init |#endif |check_bugs |smp_init |rest_init |kernel_thread |unlock_kernel |cpu_idlestartup_32 arch/i386/kernel/head.Sstart_kernel init/main.clock_kernel include/asm/smplock.htrap_init arch/i386/kernel/traps.cinit_IRQ arch/i386/kernel/i8259.csched_init kernel/sched.csoftirq_init kernel/softirq.ctime_init arch/i386/kernel/time.cconsole_init drivers/char/tty_io.cinit_modules kernel/module.ckmem_cache_init mm/slab.csti include/asm/system.hcalibrate_delay init/main.cmem_init arch/i386/mm/init.ckmem_cache_sizes_init mm/slab.cpgtable_cache_init arch/i386/mm/init.cfork_init kernel/fork.cproc_caches_initvfs_caches_init fs/dcache.cbuffer_init fs/buffer.cpage_cache_init mm/filemap.csignals_init kernel/signal.cproc_root_init fs/proc/root.cipc_init ipc/util.ccheck_bugs include/asm/bugs.hsmp_init init/main.crest_initkernel_thread arch/i386/kernel/process.cunlock_kernel include/asm/smplock.hcpu_idle arch/i386/kernel/process.c start_kernel( )程序用于初始化系统内核的各个部分,包括: *设置内存边界,调用paging_init( )初始化内存页面。 *初始化陷阱,中断通道和调度。 *对命令行进行语法分析。 *初始化设备驱动程序和磁盘缓冲区。 *校对延迟循环。最后的functionrest_init 作了以下工作: 开辟内核线程init 调用unlock_kernel 建立内核运行的cpu_idle环, 如果没有调度,就一直死循环实际上start_kernel永远不能终止.它会无穷地循环执行cpu_idle. 最后,系统核心转向move_to_user_mode( ),以便创建初始化进程(init)。此后,进程0开始进入无限循环。 初始化进程开始执行/etc/init、/bin/init 或/sbin /init中的一个之后,系统内核就不再对程序进行直接控制了。之后系统内核的作用主要是给进程提供系统调用,以及提供异步中断事件的处理。多任务机制已经建立起来,并开始处理多个用户的登录和fork( )创建的进程。init init是第一个进程,或者说内核线程|init |lock_kernel |do_basic_setup |mtrr_init |sysctl_init |pci_init |sock_init |start_context_thread |do_init_calls |(*call()-; kswapd_init |prepare_namespace |free_initmem |unlock_kernel |execve 目录-启动步骤系统引导:涉及的文件./arch/$ARCH/boot/bootsect.s./arch/$ARCH/boot/setup.sbootsect.S这个程序是linux kernel的第一个程序,包括了linux自己的bootstrap程序,但是在说明这个程序前,必须先说明一般IBM PC开机时的动作(此处的开机是指打开PC的电源:一般PC在电源一开时,是由内存中地址FFFF:0000开始执行(这个地址一定在ROM BIOS中,ROM BIOS一般是在FEOOOh到FFFFFh中),而此处的内容则是一个jump指令,jump到另一个位於ROM BIOS中的位置,开始执行一系列的动作,包括了检查RAM,keyboard,显示器,软硬磁盘等等,这些动作是由系统测试代码(system test code)来执行的,随着制作BIOS厂商的不同而会有些许差异,但都是大同小异,读者可自行观察自家机器开机时,萤幕上所显示的检查讯息。紧接着系统测试码之后,控制权会转移给ROM中的启动程序(ROM bootstrap routine),这个程序会将磁盘上的第零轨第零扇区读入内存中(这就是一般所谓的boot sector,如果你曾接触过电脑病毒,就大概听过它的大名),至於被读到内存的哪里呢? -绝对位置07C0:0000(即07C00h处),这是IBM系列PC的特性。而位在linux开机磁盘的boot sector上的正是linux的bootsect程序,也就是说,bootsect是第一个被读入内存中并执行的程序。现在,我们可以开始来看看到底bootsect做了什么。第一步首先,bootsect将它自己从被ROM BIOS载入的绝对地址0x7C00处搬到0x90000处,然后利用一个jmpi(jump indirectly)的指令,跳到新位置的jmpi的下一行去执行,第二步接着,将其他segment registers包括DS,ES,SS都指向0x9000这个位置,与CS看齐。另外将SP及DX指向一任意位移地址( offset ),这个地址等一下会用来存放磁盘参数表(disk para- meter table )第三步接着利用BIOS中断服务int 13h的第0号功能,重置磁盘控制器,使得刚才的设定发挥功能。第四步完成重置磁盘控制器之后,bootsect就从磁盘上读入紧邻着bootsect的setup程序,也就是setup.S,此读入动作是利用BIOS中断服务int 13h的第2号功能。setup的image将会读入至程序所指定的内存绝对地址0x90200处,也就是在内存中紧邻着bootsect 所在的位置。待setup的image读入内存后,利用BIOS中断服务int 13h的第8号功能读取目前磁盘的参数。第五步再来,就要读入真正linux的kernel了,也就是你可以在linux的根目录下看到的vmlinuz 。在读入前,将会先呼叫BIOS中断服务int 10h 的第3号功能,读取游标位置,之后再呼叫BIOS 中断服务int 10h的第13h号功能,在萤幕上输出字串Loading,这个字串在boot linux时都会首先被看到,相信大家应该觉得很眼熟吧。第六步接下来做的事是检查root device,之后就仿照一开始的方法,利用indirectjump 跳至刚刚已读入的setup部份第七步 setup.S完成在实模式下版本检查,并将硬盘,鼠标,内存参数写入到 INITSEG中,并负责进入保护模式。第八步 操作系统的初始化。目录-bootsect.S1.将自己移动到0x9000:0x0000处,为内核调入留出地址空间;2.建立运行环境(ss=ds=es=cs=0x9000, sp=0x4000-12),保证起动程序运行;3.BIOS初始化0x1E号中断为软盘参数表,将它取来保存备用;4.将setup读到0x9000:0x0200处;5.测试软盘参数一个磁道有多少个扇区(也没有什么好办法,只能试试36, 18, 15, 9对不对了);6.打印“Loading”;7.读入内核到0x1000:0000(如果是bzImage, 则将每个64K移动到0x100000处,在实模式下,只能调用0x15号中断了,这段代码无法放在bootsect中所以只能放在setup中,幸好此时setup已经读入了);8.到setup去吧发发信人: seis (矛), 信区: Linux标 题: Linux操作系统内核引导程序详细剖析发信站: BBS 水木清华站 (Fri Feb 2 14:12:43 2001)! bootsect.s (c) 1991, 1992 Linus Torvalds 版权所有! Drew Eckhardt修改过! Bruce Evans (bde)修改过! bootsect.s 被bios-启动子程序加载至0x7c00 (31k)处,并将自己! 移到了地址0x90000 (576k)处,并跳转至那里。! bde - 不能盲目地跳转,有些系统可能只有512k的低! 内存。使用中断0x12来获得(系统的)最高内存、等。! 它然后使用BIOS中断将setup直接加载到自己的后面(0x90200)(576.5k),! 并将系统加载到地址0x10000处。! 注意! 目前的内核系统最大长度限制为(8*65536-4096)(508k)字节长,即使是在! 将来这也是没有问题的。我想让它保持简单明了。这样508k的最大内核长度应该! 是足够了,尤其是这里没有象minix中一样包含缓冲区高速缓冲(而且尤其是现在! 内核是压缩的 ! 加载程序已经做的尽量地简单了,所以持续的读出错将导致死循环。只能手工重启。! 只要可能,通过一次取得整个磁道,加载过程可以做的很快的。#include /* 为取得CONFIG_ROOT_RDONLY参数 */! config.h中(即autoconf.h中)没有CONFIG_ROOT_RDONLY定义!?#include.textSETUPSECS = 4 ! 默认的setup程序扇区数(setup-sectors)的默认值;BOOTSEG = 0x7C0 ! bootsect的原始地址;INITSEG = DEF_INITSEG ! 将bootsect程序移到这个段处(0x9000) - 避开;SETUPSEG = DEF_SETUPSEG ! 设置程序(setup)从这里开始(0x9020);SYSSEG = DEF_SYSSEG ! 系统加载至0x1000(65536)(64k)段处;SYSSIZE = DEF_SYSSIZE ! 系统的大小(0x7F00): 要加载的16字节为一节的数;! 以上4个DEF_参数定义在boot.h中:! DEF_INITSEG 0x9000! DEF_SYSSEG 0x1000! DEF_SETUPSEG 0x9020! DEF_SYSSIZE 0x7F00 (=32512=31.75k)*16=508k! ROOT_DEV & SWAP_DEV 现在是由build中编制的;ROOT_DEV = 0SWAP_DEV = 0#ifndef SVGA_MODE#define SVGA_MODE ASK_VGA#endif#ifndef RAMDISK#define RAMDISK 0#endif#ifndef CONFIG_ROOT_RDONLY#define CONFIG_ROOT_RDONLY 1#endif! ld86 需要一个入口标识符,这和通常的一样;.globl _main_main:#if 0 /* 调试程序的异常分支,除非BIOS古怪(比如老的HP机)否则是无害的 */int 3#endifmov ax,#BOOTSEG ! 将ds段寄存器置为0x7C0;mov ds,axmov ax,#INITSEG ! 将es段寄存器置为0x9000;mov es,axmov cx,#256 ! 将cx计数器置为256(要移动256个字, 512字节);sub si,si ! 源地址 ds:si=0x07C0:0x0000;sub di,di ! 目的地址es:di=0x9000:0x0000;cld ! 清方向标志;rep ! 将这段程序从0x7C0:0(31k)移至0x9000:0(576k)处;movsw ! 共256个字(512字节)(0x200长);jmpi go,INITSEG ! 间接跳转至移动后的本程序go处;! ax和es现在已经含有INITSEG的值(0x9000);go: mov di,#0x4000-12 ! 0x4000(16k)是;=bootsect + setup 的长度 +! + 堆栈的长度 的任意的值;! 12 是磁盘参数块的大小 es:di=0x94000-12=592k-12;! bde - 将0xff00改成了0x4000以从0x6400处使用调试程序(bde)。如果! 我们检测过最高内存的话就不用担心这事了,还有,我的BIOS可以被配置为将wini驱动表! 放在内存高端而不是放在向量表中。老式的堆栈区可能会搞乱驱动表;mov ds,ax ! 置ds数据段为0x9000;mov ss,ax ! 置堆栈段为0x9000;mov sp,di ! 置堆栈指针INITSEG:0x4000-12处;/* 许多BIOS的默认磁盘参数表将不能* 进行扇区数大于在表中指定* 的最大扇区数( - 在某些情况下* 这意味着是7个扇区)后面的多扇区的读操作。* 由于单个扇区的读操作是很慢的而且当然是没问题的,* 我们必须在RAM中(为第一个磁盘)创建新的参数表。* 我们将把最大扇区数设置为36 - 我们在一个ED 2.88驱动器上所能* 遇到的最大值。* 此值太高是没有任何害处的,但是低的话就会有问题了。* 段寄存器是这样的: ds=es=ss=cs - INITSEG,(=0X9000)* fs = 0, gs没有用到。*/! 上面执行重复操作(rep)以后,cx为0;mov fs,cx ! 置fs段寄存器=0;mov bx,#0x78 ! fs:bx是磁盘参数表的地址;push dsseg fslds si,(bx) ! ds:si是源地址;! 将fs:bx地址所指的指针值放入ds:si中;mov cl,#6 ! 拷贝12个字节到0x9000:0x4000-12开始处;cldpush di ! 指针0x9000:0x4000-12处;repmovswpop di ! di仍指向0x9000:0x4000-12处(参数表开始处);pop si ! ds =; si=INITSEG(=0X9000);movb 4(di),*36 ! 修正扇区计数值;seg fsmov (bx),di ! 修改fs:bx(0000:0x007处磁盘参数表的地址为0x9000:0x4000-12;seg fsmov 2(bx),es! 将setup程序所在的扇区(setup-sectors)直接加载到boot块的后面。! 0x90200开始处;! 注意,es已经设置好了。! 同样经过rep循环后cx为0load_setup:xor ah,ah ! 复位软驱(FDC);xor dl,dlint 0x13xor dx,dx ! 驱动器0, 磁头0;mov cl,#0x02 ! 从扇区2开始,磁道0;mov bx,#0x0200 ! 置数据缓冲区地址=es:bx=0x9000:0x200;! 在INITSEG段中,即0x90200处;mov ah,#0x02 ! 要调用功能号2(读操作);mov al,setup_sects ! 要读入的扇区数SETUPSECS=4;! (假释所有数据都在磁头0、磁道0);int 0x13 ! 读操作;jnc ok_load_setup ! ok则继续;push ax ! 否则显示出错信息。保存ah的值(功能号2);call print_nl ! 打印换行;mov bp,sp ! bp将作为调用print_hex的参数;call print_hex ! 打印bp所指的数据;pop axjmp load_setup ! 重试!INT 13 - DISK - READ SECTOR(S) INTO MEMORY! AH = 02h! AL = number of sectors to read (must be nonzero)! CH = low eight bits of cylinder number! CL = sector number 1-63 (bits 0-5)! high two bits of cylinder (bits 6-7, hard disk only)! DH = head number! DL = drive number (bit 7 set for hard disk)! ES:BX -; data buffer! Return: CF set on error! if AH = 11h (corrected ECC error), AL = burst length! CF clear if successful! AH = status (see #00234)! AL = number of sectors transferred (only valid if CF set for some! BIOSes)!ok_load_setup:! 取得磁盘驱动器参数,特别是每磁道扇区数(nr of sectors/track);#if 0! bde - Phoenix BIOS手册中提到功能0x08只对硬盘起作用。! 但它对于我的一个BIOS(1987 Award)不起作用。! 不检查错误码是致命的错误。xor dl,dlmov ah,#0x08 ! AH=8用于取得驱动器参数;int 0x13xor ch,ch! INT 13 - DISK - GET DRIVE PARAMETERS (PC,XT286,CONV,PS,ESDI,SCSI)! AH = 08h! DL = drive (bit 7 set for hard disk)!Return: CF set on error! AH = status (07h) (see #00234)! CF clear if successful! AH = 00h! AL = 00h on at least some BIOSes! BL = drive type (AT/PS2 floppies only) (see #00242)! CH = low eight bits of maximum cylinder number! CL = maximum sector number (bits 5-0)! high two bits of maximum cylinder number (bits 7-6)! DH = maximum head number! DL = number of drives! ESI -; drive parameter table (floppies only)!#else! 好象没有BIOS调用可取得扇区数。如果扇区36可以读就推测是36个扇区,! 如果扇区18可读就推测是18个扇区,如果扇区15可读就推测是15个扇区,! 否则推测是9. 36, 18, 15, 9mov si,#disksizes ! ds:si-;要测试扇区数大小的表;probe_loop:lodsb ! ds:si所指的字节 =;al, si=si+1;cbw ! 扩展为字(word);mov sectors, ax ! 第一个值是36,最后一个是9;cmp si,#disksizes+4jae got_sectors ! 如果所有测试都失败了,就试9;xchg ax,cx ! cx = 磁道和扇区(第一次是36=0x0024);xor dx,dx ! 驱动器0,磁头0;xor bl,bl ! 设置缓冲区es:bx = 0x9000:0x0a00(578.5k);mov bh,setup_sects ! setup_sects = 4 (共2k);inc bhshl bh,#1 ! setup后面的地址(es=cs);mov ax,#0x0201 ! 功能2(读),1个扇区;int 0x13jc probe_loop ! 如果不对,就试用下一个值;#endifgot_sectors:! 恢复esmov ax,#INITSEGmov es,ax ! es = 0x9000;! 打印一些无用的信息(换行后,显示Loading)mov ah,#0x03 ! 读光标位置;xor bh,bhint 0x10mov cx,#9mov bx,#0x0007 ! 页0,属性7 (normal);mov bp,#msg1mov ax,#0x1301 ! 写字符串,移动光标;int 0x10! ok, 我们已经显示出了信息,现在! 我们要加载系统了(到0x10000处)(64k处)mov ax,#SYSSEGmov es,ax ! es=0x01000的段;call read_it ! 读system,es为输入参数;call kill_motor ! 关闭驱动器马达;call print_nl ! 打印回车换行;! 这以后,我们来检查要使用哪个根设备(root-device)。如果已指定了设备(!=0)! 则不做任何事而使用给定的设备。否则的话,使用/dev/fd0H2880 (2,32)或/dev/PS0(2,2! 或者是/dev/at0 (2,之一,这取决于我们假设我们知道的扇区数而定。! |_ ps0? (x,y)-表示主、次设备号?seg csmov ax,root_devor ax,axjne root_definedseg csmov bx,sectors ! sectors = 每磁道扇区数;mov ax,#0x0208 ! /dev/ps0 - 1.2Mb;cmp bx,#15je root_definedmov al,#0x1c ! /dev/PS0 - 1.44Mb ! 0x1C = 28;cmp bx,#18je root_definedmov al,0x20 ! /dev/fd0H2880 - 2.88Mb;cmp bx,#36je root_definedmov al,#0 ! /dev/fd0 - autodetect;root_defined:seg csmov root_dev,ax ! 其中保存由设备的主、次设备号;! 这以后(所有程序都加载了),我们就跳转至! 被直接加载到boot块后面的setup程序去:jmpi 0,SETUPSEG ! 跳转到0x9020:0000(setup程序的开始位置);! 这段程序将系统(system)加载到0x10000(64k)处,! 注意不要跨越64kb边界。我们试图以最快的速度! 来加载,只要可能就整个磁道一起读入。! 输入(in): es - 开始地址段(通常是0x1000)!sread: .word 0 ! 当前磁道已读的扇区数;head: .word 0 ! 当前磁头;track: .word 0 ! 当前磁道;read_it:mov al,setup_sectsinc almov sread,al ! 当前sread=5;mov ax,es ! es=0x1000;test ax,#0x0fff ! (ax AND 0x0fff, if ax=0x1000 then zero-flag=1 );die: jne die ! es 必须在64kB的边界;xor bx,bx ! bx 是段内的开始地址;rp_read:#ifdef _BIG_KERNEL_#define CALL_HIGHLOAD_KLUDGE .word 0x1eff, 0x220 ! 调用 far * bootsect_kludge! 注意: as86不能汇编这;CALL_HIGHLOAD_KLUDGE ! 这是在setup.S中的程序;#elsemov ax,essub ax,#SYSSEG ! 当前es段值减system加载时的启始段值(0x1000);#endifcmp ax,syssize ! 我们是否已经都加载了?(ax=0x7f00 ?);jbe ok1_read ! if ax ;缓冲区,al=要读的扇区数,也即当前磁道未读的扇区数;mov cx,ax ! ax仍为调用read_track之前的值,即为读入的扇区数;add ax,sread ! ax = 当前磁道已读的扇区数;cmp ax,sectors ! 已经读完当前磁道上的扇区了吗?jne ok3_read ! 没有,则跳转;mov ax,#1sub ax,head ! 当前是磁头1吗?jne ok4_read ! 不是(是磁头0)则跳转(此时ax=1);inc track ! 当前是磁头1,则读下一磁道(当前磁道加1);ok4_read:mov head,ax ! 保存当前磁头号;xor ax,ax ! 本磁道已读扇区数清零;ok3_read:mov sread,ax ! 存本磁道已读扇区数;shl cx,#9 ! 刚才一次读操作读入的扇区数 * 512;add bx,cx ! 调整数据缓冲区的起始指针;jnc rp_read ! 如果该指针没有超过64K的段内最大偏移量,则跳转继续读操作;mov ax,es ! 如果超过了,则将段地址加0x1000(下一个64K段);add ah,#0x10mov es,axxor bx,bx ! 缓冲区地址段内偏移量置零;jmp rp_read ! 继续读操作;read_track:pusha ! 将寄存器ax,cx,dx,bx,sp,bp,si,di压入堆栈;pushamov ax,#0xe2e ! loading. message 2e = . ! 显示一个.mov bx,#7int 0x10popamov dx,track ! track = 当前磁道;mov cx,sreadinc cx ! cl = 扇区号,要读的起始扇区;mov ch,dl ! ch = 磁道号的低8位;mov dx,head !mov dh,dl ! dh = 当前磁头号;and dx,#0x0100 ! dl = 驱动器号(0);mov ah,#2 ! 功能2(读),es:bx指向读数据缓冲区;push dx ! 为出错转储保存寄存器的值到堆栈上;push cxpush bxpush axint 0x13jc bad_rt ! 如果出错,则跳转;add sp, #8 ! 清(放弃)堆栈上刚推入的4个寄存器值;poparetbad_rt: push ax ! 保存出错码;call print_all ! ah = error, al = read;xor ah,ahxor dl,dlint 0x13add sp,#10popajmp read_track/* print_all是用于调试的。* 它将打印出所有寄存器的值。所作的假设是* 从一个子程序中调用的,并有如下所示的堆栈帧结构* dx* cx* bx* ax* error* ret ; dest := dest + src + c )daaint 0x10loop print_digitret/* 这个过程(子程序)关闭软驱的马达,这样* 我们进入内核后它的状态就是已知的,以后也就* 不用担心它了。*/kill_motor:push dxmov dx,#0x3f2xor al,aloutbpop dxret! 数据区sectors:.word 0 ! 当前每磁道扇区数。(36|18|15|9)disksizes: ! 每磁道扇区数表.byte 36, 18, 15, 9msg1:.byte 13, 10.ascii L 497 ! 从boot程序的二进制文件的497字节开始setup_sects:.byte SETUPSECSroot_flags:.word CONFIG_ROOT_RDONLYsyssize:.word SYSSIZEswap_dev:.word SWAP_DEVram_size:.word RAMDISKvid_mode:.word SVGA_MODEroot_dev:.word ROOT_DEVboot_flag: ! 分区启动标志.word 0xAA55目录-setup.S1、按规定得有个头,所以一开始是惯用的JMP;2、头里边内容很丰富,具体用法走着瞧;3、自我检测,不知道有什么用,防伪造?防篡改?4、如果装载程序不对,只好死掉!以下终于走入正题;5、获取内存容量(使用了三种办法,其中的E820和E801看不明白,int 15倒是老朋友了-应该是上个世纪80年代末认识的了,真佩服十年过去了,情意依旧,不过遇上一些不守规矩的BIOS,不知道还行不行);6、将键盘重复键的重复率设为最大,灵敏一点?7、检测硬盘,不懂,放这里干什么?8、检测MCA总线(不要问我这是什么);9、检测PS/2鼠标,用int 11,只是不知道为何放这里;10、检测电源管理BIOS;唉,书到用时方恨少,不懂的太多了,真不好意思;不过也没有关系, 不懂的就别去动它就行了;以下要进入内核了;11、 在进入保护模式之前,可以调用一个你提供的试模式下的过程,让你最后在看她一眼,当然你要是不提供,那就有个默认的,无非是塞住耳朵闭上眼睛禁止任何中断,包括著名的NMI ;12、设置保护模式起动后的例程地址, 你可以写自己的例程,但不是代替而是把它加在setup提供的例程的前面(显示一个小鸭子?);13、如果内核是zImage, 将它移动到0x10000处;14、如果自己不在0x90000处,则移动到0x90000处;15、建立idt, gdt表;16、启动A20;17、屏住呼吸,屏闭所有中断;18、启动!movw $1, %ax ; lmsw %ax; 好已经进入保护模式下,马上进行局部调整;19、jmpi 0x100000, _KERNEL_CS,终于进入内核;setup.SA summary of the setup.S code 。The slight differences in the operation of setup.S due to a big kernel is documented here. When the switch to 32 bit protected mode begins the code32_start address is defined as 0x100000 (when loaded) here.code32_start:#ifndef _BIG_KERNEL_.long 0x1000#else.long 0x100000#endifAfter setting the keyboard repeat rate to a maximum, calling video.S, storing the video parameters, checking for the hard disks, PS/2 mouse, and APM BIOS the preparation for real mode switch begins.The interrupts are disabled. Since the loader changed the code32_start address, the code32 varable is updated. This would be used for the jmpi instruction when the setup.S finally jumps to compressed/head.S. In case of a big kernel this is loacted at 0x100000.seg csmov eax, code32_start !modified above by the loaderseg csmov code32,eax!code32 contains the correct address to branch to after setup.S finishes After the above code there is a slight difference in the ways the big and small kernels are dealt. In cas

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论