加载引导程序的第二阶段 [英] Loading second stage of a bootloader

查看:256
本文介绍了加载引导程序的第二阶段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建用于x86计算机一个小型操作系统,并开始写code的相当小的引导程序。我创建的引导程序相当简单,它直接位于主引导记录后,该部门加载一个小秒引导程序,并跳转到code。在主引导记录的引导程序code似乎运行正常,当它试图跳到第二阶段引导程序出现问题。这第二阶段的bootloader应该输出一个字母表示成功(字母S),所以我可以告诉正在执行code。问题是,从来都没有出现在屏幕上,所以我怀疑是从来没有执行第二阶段引导程序。在code我用了以下内容:

I'm trying to create a small operating system for x86 machines and started writing the code for a fairly minimal bootloader. The bootloader I created is quite simple, it loads a small second bootloader from the sector located directly after the master boot record and jumps to that code. The bootloader code in the master boot record seems to run fine, the problem occurs when it tries to jump to the second stage bootloader. This second stage bootloader is supposed to output a letter indicating success (the letter S) so I can tell the code is being executed. The problem is nothing ever appears on the screen, so I suspect the second stage bootloader was never executed. The code I used was the following:

bootloader的主引导记录:

Bootloader in the master boot record:

[BITS 16] ; 16 bit mode
[ORG 0x7C00] ; Boot loader start address

Boot:
    ; Initial, dl contains drive number
    ; Set data segment to code segment
    mov ax, cs
    mov ds, ax
    mov es, ax
    ; Set the stack segment to 0xA000
    add ax, 0xA000
    mov ss, ax
    mov sp, 0x00
    ; Reset the drive, dl contains drive number
    mov ah, 0x00
    int 0x13
    ; Read from drive, dl contains drive number
    ;     Set up output location to 0x7E00: 0x00
    mov ax, 0x7E00
    mov es, ax ; Load to 0x7E00 : 0x00
    mov bx, 0x00
ReadDrive:
    mov ah, 0x02
    mov al, 0x01 ; Read 1 sector
    mov ch, 0x00 ; Read on cylinder 0
    mov cl, 0x02 ; Read sector 2
    mov dh, 0x00 ; Head number 0
    int 0x13

    jnc Success
    ; Print error (character F)
    mov al, 0x46
    call PrintChar
    jmp ReadDrive ; Retry

PrintChar: ; Prints a single character
    pusha
    mov ah, 0x09
    mov bh, 0x00
    mov bl, 0x0F
    mov cx, 0x01
    int 0x10
    popa
    ret

Success:
    jmp 0x7E00:0x00 ; Jump to 2nd stage bootloader

TIMES 510 - ($ - $$) db 0
DW 0xAA55 ; Boot signature

在code为第二阶段的bootloader:

The code for the second stage bootloader:

[BITS 16]
[ORG 0x7E00]

Boot2:
    ; Prints the character S to the screen
    mov al, 0x53
    mov ah, 0x09
    mov bh, 0x00
    mov bl, 0x0F
    mov cx, 0x01
    int 0x10
    jmp $ ; Loop forever

TIMES 512 - ($ - $$) db 0 ; Fill rest of block

这code编译并使用以下code写入到驱动器:

This code was compiled and written to a drive using the following code:

nasm boot.asm -o boot.bin -f bin
nasm boot2.asm -o boot2.bin -f bin
dd if=boot.bin of=/dev/sd3 bs=512
dd if=boot2.bin of=/dev/sd3 bs=512 seek=1

这code被写入设备是一个16GB的USB驱动器。计算机我来引导这个code支持USB和靴子他们像任何其他硬盘驱动器引导。在code似乎没有执行的原因是什么?

The device this code was written to was a 16GB USB drive. The computer I used to boot this code supports booting from USB and boots them like any other hard drive. What is the reason the code does not seem to execute?

推荐答案

似乎有一些在code问题。我会尽力找出其中的一些。一些有用的参考材料,在一些答案我为Stackoveflow写上找到。

There seem to be a number of issues in your code. I'll try to identify some of them. Some useful reference material can be found in some answers I have written for Stackoveflow.


  • General引导加载程序提示,给你不希望在一个引导程序
  • 来作一般准则和假设
  • 上不设立陷阱信息 DS 的访问时,正确和获取垃圾内存变量。这个有点适用于你的第二个阶段

  • 与相似之处你也可以提供一些有用的信息的问题。

  • General Boot Loader Tips which give general guidelines and assumptions you don't want to make in a bootloader
  • Information on the pitfalls of not setting up DS properly and getting garbage when accessing memory variables. This applies somewhat to your second stage
  • An answer for a question with similarities to yours could also provide some useful information.

您做的设置栈,但它有可能重叠显存。虽然这可能是不相关的你的问题,这是一个潜在的问题。有了这个code:

You do set up a stack but it potentially overlaps video memory. Although this likely isn't related to your problems, it is a potential issue. With this code:

add ax, 0xA000
mov ss, ax
mov sp, 0x00

您设置的 SS 的= 0xa000和 SP 的= 0×0000。此设置堆栈,但不幸的是第一个值压入堆栈将在0xa000:(0x0000-2)= 0xa000:0xfffe。 0xa000:0xfffe恰好落在可能显存内。也许你打算做SS = 0×9000的堆栈所以第一个值将处于0×9000:0xfffe。还有一个障碍有太多。该扩展BIOS数据区域(EBDA),可以在该区域。有些BIOS错误地返回了错误的大小此区域。在大多数情况下,它是0K大小刚好低于物理地址0xa0000最大4k。如果你占了大多数最坏的情况,我会去用栈略低于。

You set SS =0xa000, and SP =0x0000 . This sets up the stack, but unfortunately the first value pushed on the stack will be at 0xa000:(0x0000-2)= 0xa000:0xfffe . 0xa000:0xfffe happens to possibly fall within video memory. Maybe you intended to do ss=0x9000 so first value on stack would be at 0x9000:0xfffe . There is a snag there too. The Extended Bios Data Area (EBDA) can be in that region. Some BIOSes incorrectly return the wrong size for this area. In most cases it is 0k to 4k in size just below physical address 0xa0000. If you account for most worst case scenarios I'd go with a stack just below that.

add ax, 0x9000
mov ss, ax
mov sp, 0xF000  ; Bottom of stack at 0x9000:0xF000


内存地址0x7e00

有2这里的问题。在你的问题,你建议你尝试读取第二阶段逼到引导程序之上的区域。这将是在物理地址0x7e00。您code做到这一点:


Memory Address 0x7e00

There are 2 problems here. In your question you suggest you are trying to read the second stage into the area just above the bootloader. That would be at physical address 0x7e00. Your code does this:

; Read from drive, dl contains drive number
;     Set up output location to 0x7E00: 0x00
mov ax, 0x7E00
mov es, ax ; Load to 0x7E00 : 0x00
mov bx, 0x00

16位<一href=\"https://web.archive.org/web/20150908174936/http://thestarman.pcministry.com/asm/debug/Segments.html\"相对=nofollow>段:偏移成对的使用此计算映射到物理存储器地址:(段&下; 4;)+偏移量(小于4;是相同的由16倍)。这意味着,0x7E00:0x00为物理存储器地址(0x7E00&下; 4;)+ 0 = 0x7e000。显然那是错误的。我相信你打算是这样的:

16-bit Segment:Offset pairs use this calculation to map to a physical memory address: (segment<<4)+offset (<<4 is the same as multiplying by 16). That means that 0x7E00:0x00 is physical memory address (0x7E00<<4)+0=0x7e000 . That clearly is wrong. I believe what you intended was this:

mov ax, 0x07E0
mov es, ax ; Load to 0x07E0:0x00
mov bx, 0x00

0x07E0:0x00为物理存储器地址(0x07E0&下; 4;)+ 0 = 0x7e00。这仅仅是物理地址0x7c00加载到内存中的引导程序之上的区域。类似的问题出现时,你的 FAR JMP 的与此code中的第二个阶段:

0x07E0:0x00 is physical memory address (0x07E0<<4)+0=0x7e00 . That is the area just above the bootloader loaded into memory at physical address 0x7c00. A similar issue arises when you the FAR JMP to the second stage with this code:

jmp 0x7E00:0x00 ; Jump to 2nd stage bootloader

应该是:

jmp 0x07E0:0x00 ; Jump to 2nd stage bootloader  


对于第二阶段的

潜在问题

如果您建议的更改( JMP 0x07E0:0×00 )提到的previously那么的 FAR JMP 的会改变的 CS :IP 的到的 CS 的= 0x07E0(段)的 IP 的= 0×0000(偏移)并继续执行那里。你需要你的 ORG 的指令相匹配的偏移量( IP 的),您从第一阶段跳转到。由于偏移量( IP 的)在0x0000您的ORG指令应符合:


Potential Issues for Second Stage

If you make the suggested change (jmp 0x07E0:0x00) mentioned previously then the FAR JMP will change CS:IP to CS =0x07E0(segment), IP= 0x0000(offset) and continue execution there. You need your ORG directive to match the offset (IP) that you jump to from your first stage. Since the offset (IP) is 0x0000 your ORG directive should match:

[ORG 0x0000]

您还需要确保当你的第二个阶段开始加载的 DS 的也设置相匹配。实现这一目标的方法之一是在code段的 CS 的显式复制到数据段的 DS 的。可与code。在第二级的这样的顶部来完成:

You need to also make sure that when your second stage starts loading that DS is also set up to match. One way of achieving this is to explicitly copy the Code Segment CS to the Data Segment DS . That can be done with code at the top of the second stage like this:

mov ax, cs 
mov ds, ax

如果没有正确设置数据段的 DS 的所有变量引用会使用错误的段,有可能不会指向他们真的是在内存中。您code没有在此刻有变数,所以你没有注意到的问题。

Without a properly set up data segment DS all the references to the variables will use the wrong segment and likely won't point to where they really are in memory. Your code doesn't have variables at the moment so you don't notice the issue.

在这个答案的序言中提到了我的Bootloader将军提示,提示#1是非常重要的:

In my General Bootloader Tips mentioned in this answer's prolog, tip #1 is very important:


      
  • 当BIOS跳转到您的code,你不能依赖于CS,DS,ES,SS,SP寄存器具有有效的或预期值。他们应该引导程序启动的时候进行适当的设置。您只能保证你的引导程序被加载并从物理地址0x00007c00和引导驱动器号被装入DL寄存器运行。

  •   

在您的code你的bootloader有这样:

In your code your bootloader has this:

[BITS 16] ; 16 bit mode
[ORG 0x7C00] ; Boot loader start address

Boot:
    ; Initial, dl contains drive number
    ; Set data segment to code segment
    mov ax, cs
    mov ds, ax
    mov es, ax

[ORG 0x7C00] 是好的,但正在取得的 CS 的段设置为0x0000,当它达到了我们的bootloader的假设。然后,我们设置的 DS = CS 的。一个天真的bootloader传统智慧是,BIOS跳转为0x0000:0x7c00( CS:IP 的)。的 ORG 的应该偏移匹配(在本例中的 IP 的)。问题是,在现实中的BIOS跳转到物理地址0x00007c00但它可以与各种 CS的做到这一点:IP 的对。

[ORG 0x7C00] is fine, but there is an assumption being made that the CS segment is set to 0x0000 when it reached our bootloader. We then set DS=CS. Conventional wisdom for a naive bootloader is that the BIOS jumps to 0x0000:0x7c00 (CS:IP). ORG should match the offset (in this case IP). The problem is that in reality the BIOS jumps to physical address 0x00007c00 but it can do it with a variety of CS:IP pairs.

在BIOS可能远远JMP'ed(或同等学历)我们code与 JMP 0x07c0:0×0000 ,以及一些仿真器和真实的硬件做这种方式。 0x07c0:0×0000是一个物理地址(0x07c0&下; 4;)+ 0 = 0x7c00。这是完全正常的,但要注意的 IP 的= 0×0000。我们设置 [ORG 0x7c00] 。这将是一个不匹配!我们如何解决这个问题,如果我们实际上并不知道是什么的 CS:IP 的配对BIOS调用我们?简单 - 不要在引导程序的第一阶段的 CS 的复制到的 DS 的。因为我们需要一个的0x7c00偏移的 DS 的需要是0x0000到工作。我们应该明确地把为0x0000在我们的数据段( DS 的)。在code可能是这样的:

The BIOS could have FAR JMP'ed (or equivalent) to our code with jmp 0x07c0:0x0000, and some emulators and real hardware do it this way. 0x07c0:0x0000 is a physical address of (0x07c0<<4)+0=0x7c00 . This is perfectly fine, but notice that IP = 0x0000. We've set [ORG 0x7c00]. That would be a mismatch! How do we get around this if we don't actually know what CS:IP pair the BIOS calls us with? Simple - don't copy CS to DS in the first stage of a bootloader. Since we need an offset of 0x7c00, DS needs to be 0x0000 to work. We should explicitly place 0x0000 in our Data Segment (DS). The code could look like this:

[BITS 16] ; 16 bit mode
[ORG 0x7C00] ; Boot loader start address

Boot:
    ; Initial, dl contains drive number
    ; Set data segment to code segment
    xor ax, ax   ; AX=0
    mov ds, ax   ; DS=0  
    mov es, ax   ; ES=0

这篇关于加载引导程序的第二阶段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆