一切只是开始
来源: BlogBus 原始链接: http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=177475 存档链接: https://web.archive.org/web/20040607204858id_/http://www.blogbus.com:80/blogbus/blog/diary.php?diaryid=177475
一切只是开始 Linux, 嵌入式系统, 串口通信, PALM OS, Bluetooth ... 是工作中正用到的
Java, software engineering, 以及其他的很多技术,是我感兴趣的 <<<kernel study (1) beta version by ardio | 首页 | How to Write Secure Code>>> kernel study (2) bootsect.S read 时间: 04/05/15 author 原创: ardio2001 editor 修改: carol 转载请注明出处: www.loveunix.net 爱 U 家园 Beta version 1.0 last modified 15 th , May, 2004
//@ is commented by ardio /* 请参看“系统初启” * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds *
- BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
- addresses must be multiplied by 16 to obtain their respective linear
- addresses. To avoid confusion, linear addresses are written using leading
- hex while segment addresses are written as segment:offset.
- bde - should not jump blindly, there may be systems with only 512K low
- memory. Use int 0x12 to get the top of memory, etc.
- It then loads 'setup' directly after itself (0x90200), and the system
- at 0x10000, using BIOS interrupts.
/ #include <asm/boot.h> SETUPSECTS = 4 / default nr of setup-sectors / BOOTSEG = 0x07C0 / original address of boot-sector / //@ 启动时系统自动将 bootsect 的二进制代码从磁盘的 0 区 0 道读到内存的 07C0:0000 //@ 确切的说是有 ROM BIOS 的指令来进行这一操作 INITSEG = DEF_INITSEG / we move boot here - out of the way / //@bootsect.S 里的指令将 bootsect 自己移动到内存的这个地址 (0x7C00 处搬到 0x90000) // 这里的常量在 boot.h 里 , 或者在本代码文件末尾有定义 SETUPSEG = DEF_SETUPSEG / setup starts here / //@setup.S 里面的指令待的地方 (0x90200) SYSSEG = DEF_SYSSEG / system loaded at 0x10000 (65536) / SYSSIZE = DEF_SYSSIZE / system size: # of 16-byte clicks / / to be loaded / ROOT_DEV = 0 / ROOT_DEV is now written by "build" / SWAP_DEV = 0 / SWAP_DEV is now written by "build" */ #ifndef SVGA_MODE #define SVGA_MODE ASK_VGA #endif #ifndef RAMDISK #define RAMDISK 0 #endif #ifndef ROOT_RDONLY #define ROOT_RDONLY 1 #endif .code16 .text .global _start _start:
First things first. Move ourself from 0x7C00 -> 0x90000 and jump there.
//@ 这里使用的是 at&t 的汇编 , 与 IBM pc x86 win32 汇编不同, 但指令名称和意义大多相同 //@ 此段的作用是 bootsect 将自身从 07cx:0000 搬迁到内存的 9000:0000 去 movw $BOOTSEG, %ax //@ 与 ibm 汇编 mov ax,BOOTSEG movw %ax, %ds
%ds = BOOTSEG
//@ 设定源 //@ 这里不直接 movw $BOOTSEG,%ds, 可能是 ds 只能从寄存器 //@ 装入数据的原因 . 不确定 , 请高手指点 movw $INITSEG, %ax movw %ax, %es
%ax = %es = INITSEG
//@ 设定目标 movw $256, %cx //@ bootsect 的长度为 256 字节 subw %si, %si //@ 置 0 subw %di, %di //@ 置 0 cld //@ 设定 df 标记为 0 ,地址指针自动增长 rep movsw //@ 进行 256 次从源到目的双字拷贝 ljmp $INITSEG, $go //@ 循环跳转到移动后的新位置继续执行 INITSEG 为新内存位置, go 是 // 偏移量(跳转到 go 标记处) //@ 这个循环就实现了将一段指令 (bootsect) 拷贝到另一个地址 9000:0000 //--------- 到此为止是前文介绍的前 1 步
//------------- 下面的 2-6 步做的是将 setup 的镜像 ( 指令断 ) 搬到内存的 0x90200 //@ 这一段为设置磁盘参数准备栈空间 go: movw $0x4000-12, %di
0x4000 is an arbitrary value >=
//@ 为 bootsect 和 setup 和存磁盘参数的栈留足了空间 , //@0x4000 是估计中足够容纳 bootsect+setup+ 栈的空间大小 //12 是磁盘参数的长度 ,
length of bootsect + length of
setup + room for stack;
12 is disk parm size.
movw %ax, %ds
%ax and %es already contain INITSEG
//@ 设定段地址为 INITSEG 即 9000:0000 //@ %ax 和 %ex 已经包含了地址 INITSEG movw %ax, %ss movw %di, %sp
put stack at INITSEG:0x4000-12.
//@ 栈指针指向底 //--------- 到此为止是前文介绍的前 2 步
//--------- 第 3 步和第 4 步的目的是准备好磁盘驱动器 , 以便从中读入包括 setup.S 在内的其他内核引导部分 . 从 2.6.0 版本开始 , linux 将不支持从软盘启动 , 所以新的 bootsect.S 代码中 , 你将看不到下面的检测设置软盘驱动器 (FDC) 的部分 .----------------------------------------//
Segments are as follows: %cs = %ds = %es = %ss = INITSEG, %fs = 0,
and %gs is unused.
//@ 将位于 0000:0078 的磁盘参数表拷到 9000:4000-12 处以便修改 movw %cx, %fs
%fs = 0
//@ fs 是 32 位 x86 的寄存器,大家可能会不熟悉,查查书吧 movw $0x78, %bx
%fs:%bx is parameter table address
//@ 0000:0078 是系统方磁盘参数表的地方 pushw %ds //@ 保存 %ds ldsw %fs:(%bx), %si
%ds:%si is source
//@ 源 movb $6, %cl
copy 12 bytes
// 循环次数为 6, 每次移动 1 个字 (2 字节 ) pushw %di
%di = 0x4000-12.
// 保存 %di rep
don't worry about cld
//cld 与上面相同 , 所以不需要改动 movsw
already done above
//@ copy 12 字节, 磁盘参数表的实际长度为 11 bytes popw %di popw %ds // 恢复 %di,%ds movb $36, 0x4(%di)
patch sector count
// 设定第一次假设的磁盘簇数量 movw %di, %fs:(%bx) movw %es, %fs:2(%bx) //@ 接着就要获得磁盘的参数 , 但是 , bios 没有直接提供获取簇数量的功能调用 // 所以只能从 36,18,15,9