天衣有缝

冠盖满京华,斯人独憔悴~
posts - 35, comments - 115, trackbacks - 0, articles - 0
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

1课:引导程序

声明:转载请保留

译者http://www.cppblog.com/jinglexy

原作者:xiaoming.mo at skelix dot org

MSN & Email: jinglexy at yahoo dot com dot cn


目标:使"system"从软盘启动,并打印"Hello World!" 下载源程序

内存寻址

处理器以字节管理和访问内存,每个字节都有独立的地址,即物理地址。有两种地址映射方式:分段和分页,skelix内核中都用到了。


段对于我们来说再熟悉不过了,先回顾一下dos时期的段吧。它是一个16位的寄存器,所以最多可以直接访问2^16字节的内存,即64K。这对应用程序来说太少了,于是Intel使用Segment:Offset结合方式来表示一个虚拟地址。段寄存器左移4位加上偏移就得到实际的物理地址了。例如,0x7c00:0x0189表示物理地址0x7c189,而不是0x7c000189。计算过程如下:

 

 7C000
+ 0189
-------
 7C189

现在我们来计算最大可以访问的地址:FFFF:FFFF

 FFFF0
+ FFFF
-------
10FFEF

这个范围是1M + 65519 bytes, 因为在80386中使用了20位地址线,所以可以额外多访问65519个字节虚拟地址,例如地址0x100010被映射到地址0x10,访问这两个地址是等价的。

表示同一个物理地址有多种方式,例如07C0:00000000:7C00 就是一样的。

 

另一个概念是线性地址,这个是32位地址,只有当分页机制开启时才有效,文章后面会提到它。

 

引导过程

 

当系统上电或RESET时,处理器将执行一些列的初始化,寄存器被设置成非预知状态,并且cpu处于实模式。也许你想知道cpu是怎样设置segment:offset为物理地址FFFF0的(0xf000:0xfff0就是bios入口地址),这是因为cs寄存器有一个非可见部分,它保存了ffff:0000地址,并且cs在初始化时会被装入f000值。此后以正常方式使用它。当bois取得控制权后,根据用户配置(从软驱,硬盘,或cdrom)中读取第一个sector00007C00,并跳转到该地址执行(就是引导程序bootstrap)。在bootstrap中我们可以使用bios中断,但是进入kernel后就不能再使用了。

 


程序一:使用asld的范例

 

你可以在下载源程序的01/first.cry/bootsect.s

 

        .text              .text表示代码段
        .globl             start
表示start可以用作外部符号
        .code16            GCC
默认使用32位地址和操作数,这里告诉它使用16
start:
        jmp      start    
死循环

.org    0x1fe,   0x90      .org NEW-LC, FILL说明:这里填充0x90,是nop指令的机器码
.word   0xaa55

 

讲解:.org指令指示下一个数据地址,为了编译这个程序,我们写了一个Makefile,总不能老是敲命令吧,呵呵。

网络上可以找到很多写Makefile的资料,编译选项才是我们关注的焦点。


01/first.cry/Makefile

AS=as                     gcc汇编工具
LD=ld                     gcc
连接器

.s.o:
    ${AS} -a $< -o $*.o >$*.map

all: final.img

final.img: bootsect
    mv bootsect final.img

bootsect: bootsect.o
    ${LD} --oformat binary -N -e start -Ttext 0x7c00 -o bootsect $<

 

讲解:ld可以被配置为支持多于一种的目标文件. binary表示没有程序头和其他信息,仅仅是一些裸数据。如果没有这个选项,将被默认链接为elf格式。-Ntextdata节设置为可读写。-Ttexttext节起始地址设置为0x7c00(在jmp和数据引用等重定位链接时会用到这个参考值),所有的引用地址都是在7c00这个地址上加出来的。-e选项指定程序入口点

现在我们运行make指令编译一下:

[root@root~/source/os/skelix/01/first.cry]$ ls
bootsect.s  COPYING  Makefile
[root@root~/source/os/skelix/01/first.cry]$ make
as -a bootsect.s -o bootsect.o >bootsect.map
ld --oformat binary -N -e start -Ttext 0x7c00 -o bootsect bootsect.o
mv bootsect final.img
[root@root~/source/os/skelix/01/first.cry]$ ls
bootsect.map  bootsect.o  bootsect.s  COPYING  final.img  Makefile
[root@root~/source/os/skelix/01/first.cry]$

 

现在,我们启动vmware,运行,载入软驱映象文件"final.img",我们得到一个黑屏,这是正确的,因为我们什么也没有做。

 

程序一:显示 Hello World!

好了,上面的黑屏程序并不是太好玩,现在我们尝试在上面打印"Hello World!"

01/hello.world/bootsect.s

        .text
        .globl  start
        .code16
start:
        jmp     code
msg:                                  
使用jmp指令跳过该变量,这是我们为什么在Makefile使用-N链接选项了
        .string "Hello World!\x0"
code:
        movw    $0xb800,%ax
        movw    %ax,    %es            es
段设置成B800,如前所述,segment:offset地址映射方式,它指向B8000

                                       这意味着第一个字节地址是0(映射到B8000),属性字节是1(映射到B8001

                                       B8001值设置为0x07可以将这个byte颜色设置为黑底白字。
        xorw    %ax,    %ax
        movw    %ax,    %ds

        movw    $msg,   %si            movsb指令设置正确的sidi
        xorw    %di,    %di
        cld
        movb    $0x07,  %al            
字的颜色

1:
        cmp     $0,    (%si)
        je      1f   
        movsb
        stosb
        jmp     1b
1:      jmp     1b

.org    0x1fe,  0x90
.word   0xaa55

 

 

Feedback

# re: 自己动手写内核(第1课:引导程序)(原创)  回复  更多评论   

2007-06-19 02:15 by 路西菲尔
问个弱智问题我怎么不能加载引导程序.
我用vm版本是5.5.3,找不到你文中说的"启动vmware,运行,载入软驱映象文件".我只能在虚拟机的属性设置中找到cd-rom -> 使用ISO镜像.不过设置以后没有效果.

# re: 自己动手写内核(第1课:引导程序)(原创)  回复  更多评论   

2007-06-19 17:00 by 天衣有缝
“编辑虚拟机设置” --> 选项卡:“硬件” --> “添加” --> “软盘驱动器” ,然后选择设备设置,“使用软磁盘映象”

# re: 自己动手写内核(第1课:引导程序)(原创)  回复  更多评论   

2007-06-19 17:37 by 路西菲尔
感谢你的回复解决了我学习道路上的第一个问题

# re: 自己动手写内核(第1课:引导程序)(原创)  回复  更多评论   

2007-06-19 17:52 by 天衣有缝
不客气,如果有什么心得可以邮件联系,这样回复可能会快些:)

# re: 自己动手写内核(第1课:引导程序)(原创)  回复  更多评论   

2007-12-19 10:35 by 上海大众搬场
我也学习了.谢谢

# re: 自己动手写内核(第1课:引导程序)(原创)[未登录]  回复  更多评论   

2009-02-06 07:42 by a
我make没通过!
错误信息:(环境:cygwin(您老人家的那个版本,MinGW的as和ld+MinGW的Make))
zjs@ccb-zz /cygdrive/f/sys
$ make
ld --oformat binary -N -e start -Ttext 0x7c00 -o bootsect bootsect.o
ld: PE operations on non PE file.
f:\mingw\bin\make.exe: *** [bootsect] Error 1
/cygdrive/f/代表F盘(/dev/hda4)
我使用网上一个AS+LD(CYG编译版)错误更多!
错误:(make还是MinGWmake)
zjs@ccb-zz /cygdrive/f/sys
$ /usr/bin/make
ld --oformat binary -N -e start -Ttext 0x7c00 -o bootsect bootsect.o
usage: ld [-03Mimrstz[-]] [-llib_extension] [-o outfile] [-Ccrtfile]
[-Llibdir] [-Olibfile] [-T textaddr] infile...
F:\cygwin\bin\make.exe: *** [bootsect] Error 2

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理