linux-0.00完全注释(一)
时间:2007-04-23 来源:mishuang
! PC机上电后,BIOS会将磁盘的前512字节(MBR)加载到内存0x7c00,并从该处开始执行。
! MBR分为三部分:
! 1)0-445 (446字节)
! 2)446-509(64字节)
! 3)510-511(2字节)
! MBR的前446字节代码会加载OS内核
! 446-509字节是磁盘的四个分区表。详细结构请参考C程序
! http://blog.chinaunix.net/u/23177/showart.php?id=206942
! linux-0.00的这个文件只构成了MBR第一部分。没有磁盘分区表。第三部分是由tools/build.c程序写进去的。
! buf[510]=0x55;
! buf[511]=0xAA;
! boot.s直接将第二扇区(1扇区等于512字节)开始的17个扇区调入内存0x10000,并跳转到那里以保护模式开始执行。
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
! BIOS将这段代码载入到内存的位置
BOOTSEG = 0x07c0
! 实模式下的寻址方式是段寄存器左移四位再加上偏移
SYSSEG = 0x1000
! 这个值是硬编码进去的,编译好的Image文件是8.5k,正好17个扇区
! 其实去掉MBR这一个扇区,应该载入16个扇区就够了
! 我也试了SYSLEN=16确实可以
SYSLEN = 17
entry start
start:
! 跳转到标号go。我试图注释掉下面的语句或者通过ax给cs赋值BOOTSEG
! 但是系统就起不来了,还没有想明白为什么
! 在linux-0.11中,MBR中的代码将自身移到段INITSEG,也就是0x9000:0x0000
! 然后,执行jmpi go,#INITSEG
jmpi go,#BOOTSEG
go:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,#0x400 ! arbitrary value >>512
! BIOS 0x13中断用法
! ah=0x02 读磁盘扇区到内存
! al=需读出扇区数
! ch=磁盘柱面号低8位
! cl=开始扇区(0-5);磁盘柱面号高2位(7-8)
! dh=磁头号(若是硬盘最高位置为1)
! ex:bx=数据缓冲区
! 下面的代码利用0x13号BIOS中断调用将从第二扇区开始的17个扇区调入内存0x1000:0x0000
load_system:
mov dx,#0x0000
mov cx,#0x0002
mov ax,#SYSSEG
mov es,ax
mov bx,#0x0000
mov ax,#0x200+SYSLEN
int 0x13
jnc ok_load
mov dx,#0x0000
mov ax,#0x0000
int 0x13
jmp load_system
ok_load:
! 关中断
cli
! 装入段描述符
mov ax,cs ! right, forgot this at first. didn't work :-)
mov ds,ax
lidt idt_48 ! load idt with 0,0
lgdt gdt_48 ! load gdt with whatever appropriate
! 对8259芯片进行编程,这部分内容可以参考接口方面的书
mov al,#0x11 ! initialization sequence
out #0x20,al ! send it to 8259A-1
out #0xA0,al ! and to 8259A-2
mov al,#0x20 ! start of hardware int's (0x20)
out #0x21,al
mov al,#0x28 ! start of hardware int's 2 (0x28)
out #0xA1,al
mov al,#0x04 ! 8259-1 is master
out #0x21,al
mov al,#0x02 ! 8259-2 is slave
out #0xA1,al
mov al,#0x01 ! 8086 mode for both
out #0x21,al
out #0xA1,al
mov al,#0xFF ! mask off all interrupts for now
out #0x21,al
out #0xA1,al
! 设置状态寄存器,进入保护模式
! 在实模式下,内存地址等于段寄存器左移四位加上偏移
! 进入保护模式后,段寄存器的作用变成了gdt表的索引
! 段寄存器低2位为11代表用户态,00代表内核态
! 段寄存器第3位为1代表局部描述符,0代表全局描述符
! 段寄存器高13位表示该段在gdt表中的索引号,因此系统最多有8192个段
! 在文件head.s的tss结构体中cs=0x0f,其他段寄存器都是0x17
! 也就是说所有段都是用户态的局部段,只不过cs使用gdt表的第一项
! 其他段寄存器使用gdt表的第二项
mov bx,#SYSSEG ! loaded place.
mov ax,#0x0001 ! protected mode (PE) bit
lmsw ax ! This is it!
jmpi 0,8 ! jmp offset 0 of segment 8 (cs)
gdt:
.word 0,0,0,0 ! dummy
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0x10000
.word 0x9A01 ! code read/exec
.word 0x00C0 ! granularity=4096, 386
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0x10000
.word 0x9201 ! data read/write
.word 0x00C0 ! granularity=4096, 386
idt_48:
.word 0 ! idt limit=0
.word 0,0 ! idt base=0L
gdt_48:
.word 0x7ff ! gdt limit=2048, 256 GDT entries
.word 0x7c00+gdt,0 ! gdt base = 07xxx
.text
endtext:
.data
enddata:
.bss
endbss:
! MBR分为三部分:
! 1)0-445 (446字节)
! 2)446-509(64字节)
! 3)510-511(2字节)
! MBR的前446字节代码会加载OS内核
! 446-509字节是磁盘的四个分区表。详细结构请参考C程序
! http://blog.chinaunix.net/u/23177/showart.php?id=206942
! linux-0.00的这个文件只构成了MBR第一部分。没有磁盘分区表。第三部分是由tools/build.c程序写进去的。
! buf[510]=0x55;
! buf[511]=0xAA;
! boot.s直接将第二扇区(1扇区等于512字节)开始的17个扇区调入内存0x10000,并跳转到那里以保护模式开始执行。
.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.text
! BIOS将这段代码载入到内存的位置
BOOTSEG = 0x07c0
! 实模式下的寻址方式是段寄存器左移四位再加上偏移
SYSSEG = 0x1000
! 这个值是硬编码进去的,编译好的Image文件是8.5k,正好17个扇区
! 其实去掉MBR这一个扇区,应该载入16个扇区就够了
! 我也试了SYSLEN=16确实可以
SYSLEN = 17
entry start
start:
! 跳转到标号go。我试图注释掉下面的语句或者通过ax给cs赋值BOOTSEG
! 但是系统就起不来了,还没有想明白为什么
! 在linux-0.11中,MBR中的代码将自身移到段INITSEG,也就是0x9000:0x0000
! 然后,执行jmpi go,#INITSEG
jmpi go,#BOOTSEG
go:
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov sp,#0x400 ! arbitrary value >>512
! BIOS 0x13中断用法
! ah=0x02 读磁盘扇区到内存
! al=需读出扇区数
! ch=磁盘柱面号低8位
! cl=开始扇区(0-5);磁盘柱面号高2位(7-8)
! dh=磁头号(若是硬盘最高位置为1)
! ex:bx=数据缓冲区
! 下面的代码利用0x13号BIOS中断调用将从第二扇区开始的17个扇区调入内存0x1000:0x0000
load_system:
mov dx,#0x0000
mov cx,#0x0002
mov ax,#SYSSEG
mov es,ax
mov bx,#0x0000
mov ax,#0x200+SYSLEN
int 0x13
jnc ok_load
mov dx,#0x0000
mov ax,#0x0000
int 0x13
jmp load_system
ok_load:
! 关中断
cli
! 装入段描述符
mov ax,cs ! right, forgot this at first. didn't work :-)
mov ds,ax
lidt idt_48 ! load idt with 0,0
lgdt gdt_48 ! load gdt with whatever appropriate
! 对8259芯片进行编程,这部分内容可以参考接口方面的书
mov al,#0x11 ! initialization sequence
out #0x20,al ! send it to 8259A-1
out #0xA0,al ! and to 8259A-2
mov al,#0x20 ! start of hardware int's (0x20)
out #0x21,al
mov al,#0x28 ! start of hardware int's 2 (0x28)
out #0xA1,al
mov al,#0x04 ! 8259-1 is master
out #0x21,al
mov al,#0x02 ! 8259-2 is slave
out #0xA1,al
mov al,#0x01 ! 8086 mode for both
out #0x21,al
out #0xA1,al
mov al,#0xFF ! mask off all interrupts for now
out #0x21,al
out #0xA1,al
! 设置状态寄存器,进入保护模式
! 在实模式下,内存地址等于段寄存器左移四位加上偏移
! 进入保护模式后,段寄存器的作用变成了gdt表的索引
! 段寄存器低2位为11代表用户态,00代表内核态
! 段寄存器第3位为1代表局部描述符,0代表全局描述符
! 段寄存器高13位表示该段在gdt表中的索引号,因此系统最多有8192个段
! 在文件head.s的tss结构体中cs=0x0f,其他段寄存器都是0x17
! 也就是说所有段都是用户态的局部段,只不过cs使用gdt表的第一项
! 其他段寄存器使用gdt表的第二项
mov bx,#SYSSEG ! loaded place.
mov ax,#0x0001 ! protected mode (PE) bit
lmsw ax ! This is it!
jmpi 0,8 ! jmp offset 0 of segment 8 (cs)
gdt:
.word 0,0,0,0 ! dummy
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0x10000
.word 0x9A01 ! code read/exec
.word 0x00C0 ! granularity=4096, 386
.word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0x10000
.word 0x9201 ! data read/write
.word 0x00C0 ! granularity=4096, 386
idt_48:
.word 0 ! idt limit=0
.word 0,0 ! idt base=0L
gdt_48:
.word 0x7ff ! gdt limit=2048, 256 GDT entries
.word 0x7c00+gdt,0 ! gdt base = 07xxx
.text
endtext:
.data
enddata:
.bss
endbss:
相关阅读 更多 +