⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1.html

📁 介绍linux下文件和设备编程
💻 HTML
📖 第 1 页 / 共 5 页
字号:
sread: .word 0 ! 当前磁道已读的扇区数;<br>head: .word 0 ! 当前磁头;<br>track: .word 0 ! 当前磁道;<p>read_it:<br>mov al,setup_sects<br>inc al<br>mov sread,al !! 当前sread=5;<br>mov ax,es !! es=0x1000;<br>test ax,#0x0fff !! (ax AND 0x0fff, if ax=0x1000 then zero-flag=1 );<br>die: jne die ! es 必须在64kB的边界;<br>xor bx,bx ! bx 是段内的开始地址;<br>rp_read:<br>#ifdef __BIG_KERNEL__<br>#define CALL_HIGHLOAD_KLUDGE .word 0x1eff, 0x220 ! 调用 far * bootsect_kludge<br>! 注意: as86不能汇编这;<br>CALL_HIGHLOAD_KLUDGE ! 这是在setup.S中的程序;<br>#else<br>mov ax,es<br>sub ax,#SYSSEG ! 当前es段值减system加载时的启始段值(0x1000);<br>#endif<br>cmp ax,syssize ! 我们是否已经都加载了?(ax=0x7f00 ?);<br>jbe ok1_read !! if ax &lt;= syssize then 继续读;<br>ret !! 全都加载完了,返回!<br>ok1_read:<br>mov ax,sectors !! sectors=每磁道扇区数;<br>sub ax,sread !! 减去当前磁道已读扇区数,al=当前磁道未读的扇区数(ah=0);<br>mov cx,ax<br>shl cx,#9 !! 乘512,cx = 当前磁道未读的字节数;<br>add cx,bx !! 加上段内偏移值,es:bx为当前读入的数据缓冲区地址;<br>jnc ok2_read !! 如果没有超过64K则继续读;<br>je ok2_read !! 如果正好64K也继续读;<br>xor ax,ax<br>sub ax,bx<br>shr ax,#9<br>ok2_read:<br>call read_track !! es:bx -&gt;缓冲区,al=要读的扇区数,也即当前磁道未读的扇区数;<p>mov cx,ax !! ax仍为调用read_track之前的值,即为读入的扇区数;<br>add ax,sread !! ax = 当前磁道已读的扇区数;<br>cmp ax,sectors !! 已经读完当前磁道上的扇区了吗?<br>jne ok3_read !! 没有,则跳转;<br>mov ax,#1<br>sub ax,head !! 当前是磁头1吗?<br>jne ok4_read !! 不是(是磁头0)则跳转(此时ax=1);<br>inc track !! 当前是磁头1,则读下一磁道(当前磁道加1);<br>ok4_read:<br>mov head,ax !! 保存当前磁头号;<br>xor ax,ax !! 本磁道已读扇区数清零;<br>ok3_read:<br>mov sread,ax !! 存本磁道已读扇区数;<br>shl cx,#9 !! 刚才一次读操作读入的扇区数 * 512;<br>add bx,cx !! 调整数据缓冲区的起始指针;<br>jnc rp_read !! 如果该指针没有超过64K的段内最大偏移量,则跳转继续读操作;<br>mov ax,es !! 如果超过了,则将段地址加0x1000(下一个64K段);<br>add ah,#0x10<br>mov es,ax<br>xor bx,bx !! 缓冲区地址段内偏移量置零;<br>jmp rp_read !! 继续读操作;<p><p>read_track:<br>pusha !! 将寄存器ax,cx,dx,bx,sp,bp,si,di压入堆栈;<br>pusha<br>mov ax,#0xe2e ! loading... message 2e = . !! 显示一个.<br>mov bx,#7<br>int 0x10<br>popa<p>mov dx,track !! track = 当前磁道;<br>mov cx,sread<br>inc cx !! cl = 扇区号,要读的起始扇区;<br>mov ch,dl !! ch = 磁道号的低8位;<br>mov dx,head !!<br>mov dh,dl !! dh = 当前磁头号;<br>and dx,#0x0100 !! dl = 驱动器号(0);<br>mov ah,#2 !! 功能2(读),es:bx指向读数据缓冲区;<p>push dx ! 为出错转储保存寄存器的值到堆栈上;<br>push cx<br>push bx<br>push ax<p>int 0x13<br>jc bad_rt !! 如果出错,则跳转;<br>add sp, #8 !! 清(放弃)堆栈上刚推入的4个寄存器值;<br>popa<br>ret<p>bad_rt: push ax ! 保存出错码;<br>call print_all ! ah = error, al = read;<p><br>xor ah,ah<br>xor dl,dl<br>int 0x13<p><br>add sp,#10<br>popa<br>jmp read_track<p>/*<br>* print_all是用于调试的。<br>* 它将打印出所有寄存器的值。所作的假设是<br>* 从一个子程序中调用的,并有如下所示的堆栈帧结构<br>* dx<br>* cx<br>* bx<br>* ax<br>* error<br>* ret &lt;- sp<br>*<br>*/<p>print_all:<br>mov cx,#5 ! 出错码 + 4个寄存器<br>mov bp,sp<p>print_loop:<br>push cx ! 保存剩余的计数值<br>call print_nl ! 为了增强阅读性,打印换行<p>cmp cl, #5<br>jae no_reg ! 看看是否需要寄存器的名称<p>mov ax,#0xe05 + A - l<br>sub al,cl<br>int 0x10<p>mov al,#X<br>int 0x10<p>mov al,#:<br>int 0x10<p>no_reg:<br>add bp,#2 ! 下一个寄存器<br>call print_hex ! 打印值<br>pop cx<br>loop print_loop<br>ret<p>print_nl: !! 打印回车换行。<br>mov ax,#0xe0d ! CR<br>int 0x10<br>mov al,#0xa ! LF<br>int 0x10<br>ret<p>/*<br>* print_hex是用于调试目的的,打印出<br>* ss:bp所指向的十六进制数。<br>* !! 例如,十六进制数是0x4321时,则al分别等于4,3,2,1调用中断打印出来 4321<br>*/<p>print_hex:<br>mov cx, #4 ! 4个十六进制数字<br>mov dx, (bp) ! 将(bp)所指的值放入dx中<br>print_digit:<br>rol dx, #4 ! 循环以使低4比特用上 !! 取dx的高4比特移到低4比特处。<br>mov ax, #0xe0f ! ah = 请求的功能值,al = 半字节(4个比特)掩码。<br>and al, dl !! 取dl的低4比特值。<br>add al, #0x90 ! 将al转换为ASCII十六进制码(4个指令)<br>daa !! 十进制调整<br>adc al, #0x40 !! (adc dest, src ==&gt; dest := dest + src + c )<br>daa<br>int 0x10<br>loop print_digit<br>ret<p><br>/*<br>* 这个过程(子程序)关闭软驱的马达,这样<br>* 我们进入内核后它的状态就是已知的,以后也就<br>* 不用担心它了。<br>*/<br>kill_motor:<br>push dx<br>mov dx,#0x3f2<br>xor al,al<br>outb<br>pop dx<br>ret<p>!! 数据区<br>sectors:<br>.word 0 !! 当前每磁道扇区数。(36||18||15||9)<p>disksizes: !! 每磁道扇区数表<br>.byte 36, 18, 15, 9<p>msg1:<br>.byte 13, 10<br>.ascii &quot;Loading&quot;<p>.org 497 !! 从boot程序的二进制文件的497字节开始<br>setup_sects:<br>.byte SETUPSECS<br>root_flags:<br>.word CONFIG_ROOT_RDONLY<br>syssize:<br>.word SYSSIZE<br>swap_dev:<br>.word SWAP_DEV<br>ram_size:<br>.word RAMDISK<br>vid_mode:<br>.word SVGA_MODE<br>root_dev:<br>.word ROOT_DEV<br>boot_flag: !! 分区启动标志<br>.word 0xAA55<p><p><br><center><A HREF="#Content">[目录]</A></center><hr><br><A NAME="I357" ID="I357"></A><center><b><font size=+2>setup.S</font></b></center><br>1、按规定得有个头,所以一开始是惯用的JMP;<br>2、头里边内容很丰富,具体用法走着瞧;<br>3、自我检测,不知道有什么用,防伪造?防篡改?<br>4、如果装载程序不对,只好死掉!以下终于走入正题;<br>5、获取内存容量(使用了三种办法,其中的E820和E801看不明白,int 15倒是老朋友了--应该是上个世纪80年代末认识的了,真佩服十年过去了,情意依旧,不过遇上一些不守规矩的BIOS,不知道还行不行);<br>6、将键盘重复键的重复率设为最大,灵敏一点?<br>7、检测硬盘,不懂,放这里干什么?<br>8、检测MCA总线(不要问我这是什么);<br>9、检测PS/2鼠标,用int 11,只是不知道为何放这里;<br>10、检测电源管理BIOS;唉,书到用时方恨少,不懂的太多了,真不好意思;不过也没有关系, 不懂的就别去动它就行了;以下要进入内核了;<br>11、 在进入保护模式之前,可以调用一个你提供的试模式下的过程,让你最后在看她一眼,当然你要是不提供,那就有个默认的,无非是塞住耳朵闭上眼睛禁止任何中断,包括著名的NMI ;<br>12、设置保护模式起动后的例程地址, 你可以写自己的例程,但不是代替而是把它加在setup提供的例程的前面(显示一个小鸭子?);<br>13、如果内核是zImage, 将它移动到0x10000处;<br>14、如果自己不在0x90000处,则移动到0x90000处;<br>15、建立idt, gdt表;<br>16、启动A20;<br>17、屏住呼吸,屏闭所有中断;<br>18、启动!movw $1, %ax ; lmsw %ax; 好已经进入保护模式下,马上进行局部调整;<br>19、jmpi 0x100000, __KERNEL_CS,终于进入内核;<p>setup.S<br>A 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.<br>code32_start:<p>#ifndef __BIG_KERNEL__<br>.long 0x1000<br>#else<br>.long 0x100000<br>#endif<p>After 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.<p>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.<p>seg cs<br>mov eax, code32_start !modified above by the loader<br>seg cs<br>mov code32,eax<p>!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 case of a small kernel the kernel is moved down to segment address 0x100, but a big kernel is not moved. Before decompression, the big kernel stays at 0x100000. The following is the code that does thischeck.test byte ptr loadflags,<p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -