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

📄 1.html

📁 网上一个牛人整理的关于linux内核编译
💻 HTML
📖 第 1 页 / 共 5 页
字号:
! 来加载,只要可能就整个磁道一起读入。<br>
!<br>
! 输入(in): es - 开始地址段(通常是0x1000)<br>
!<br>
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>

⌨️ 快捷键说明

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