启用引导加载器加载一个USB的第二扇形 [英] Enable the boot loader to load the second sector of a USB

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

问题描述

我学习汇编语言。我写了一个简单的引导程序。测试出来后,没有工作。这里是我的code:

  [位16]
[有机0x7c00]JMP启动数据:
wolf_wel_msg DB'欢迎Bootloader的!!!,0X0D,0x0A的,0
wolf_kernel_load DB'加载内核....',0X0D,0x0A的,0
wolf_error_msg DB'Kernel.bin没有找到!,0X0D,0x0A的,0
wolf_error_msg1分贝'preSS任意键重新启动..',0开始:
        MOV SI,wolf_wel_msg
    电话wolf_print    MOV SI,wolf_kernel_load
    电话wolf_print    PUSHF
    STC    MOV啊,00
    MOV DL,00
    INT 13H    read_sector:
            MOV AX,为0x0
        MOV ES,AX
        异或BX,BX
            MOV啊,02
        MOV人,01
        MOV CH,01
        MOV CL,02
        MOV DH,00
        MOV DL,00
        INT 13H    JC wolf_error
    POPF
    JMP为0x0:为0x1000
    CLI
    HLT    wolf_error:
            MOV SI,wolf_error_msg
        电话wolf_print
        MOV SI,wolf_error_msg1
        电话wolf_print
            MOV啊,00
        INT 16H
        异斧,斧
        INT 19H    wolf_print:
            LODSB
        还是人,人
        JZ退出
        MOV啊,为0x0E
        INT 10H
        JMP wolf_print
        出口:
            RET次510 - ($ - $$)0分贝
DW 0xAA55将

这code被放置在使用该命令将USB的第一个扇区:

  DD如果= F:\\的= \\\\ \\ D BOOT.BIN:BS = 512计数= 1

一个简单的程序被加载在使用该命令将USB的第二个扇区:

  DD如果= F:\\的= \\\\ \\ D hello.bin:BS = 512寻求= 1数= 1

这是code加载到第二个扇区程序:

  [位16]
[组织为0x1000]JMP启动
数据:
   MSG DB'你好',0
开始:
   MOV SI,味精
   JMP打印   CLI
   HLT
   打印:
      LODSB
      还是人,人
      JZ退出
      MOV啊,为0x0E
      INT 10H
      JMP打印
  出口:
      RET

为什么不工作我的引导加载程序?难道我做错了什么?有什么建议?


解决方案

您code假设的 DS 的设置为0。你不能假设。如果您使用的是code的第一部分应该明确设置的 DS 的0 组织0x7c00

您应认真考虑通过设置定义你的筹码的 SS:SP 的。你不知道在哪里现有的或是否是足够大,以处理你打算做什么。

被调用之前,为了你的bootloader,BIOS会设置的 DL 的启动设备号进行注册。你不应该让从引导驱动器的驱动器请求时在code设置的 DL 的为0。你应该使用在存在的价值的 DL 的,当你的引导程序被调用。

您应该使用的 CLD 的指令清除方向标志,因为你正在使用的 LODSB 的指令期待在内存中前进。没有担保的方向标志将被正确设置,所以你应该明确地将它设置为你需要的 CLD 的方向(向前)或 STD 的(向后)。

我在我的通用的Bootloader提示 StackOverflow的答案就上述问题的详细信息。

由于您使用的不是 BPB 那么我强烈建议删除 JMP启动作为你的引导程序的第一条指令。相反,移动数据code之后,但在引导扇区签名之前( 0xAA55将)。其原因是某些BIOS将尝试找到的 BPB 的基础上的 JMP 的指令出现作为引导程序的第一个指令,如果发现改写你的引导程序的部件内存造成潜在的未定义的行为。

您引导程序使用此指令,开始从第二扇区加载你的第二个阶段:

  JMP为0x0:为0x1000

问题是,当你读了部门设置的 ES:BX 的是这样的:

  read_sector:
    MOV AX,为0x0
    MOV ES,AX
    异或BX,BX

本套 ES:BX 的为0x0000:为0x0000这显然不是在您的 JMP 的预计,code是。您需要设置的 ES:BX 的到你想要的内存位置 INT 13 / AH = 02H 读取磁盘扇区的进入。

INT 13H / AH = 02H 的要求柱面/磁头/扇区数被正确设定。部门从1开始编号,但柱面和磁头是从零开始的。磁盘的第二个部门是在柱面0,磁头0,扇区2.您code套缸1而不是0。这code是错误的,因为你真的应该将其设置为0:

  MOV CH,01

在创建打印作为函数的第二个阶段,因为它有一个 RET 指令结束。 JMP打印应改为调用打印

通过上述建议的所有变化,包括我一般引导程序提示你那些code可以修改为:

boot.asm

  [位16]
[有机0x7c00]                   ;使用由BIOS寄存器DL传递给我们引导驱动器号
开始:
    异斧,斧;我们要的0段为DS此问题
    MOV DS,AX;将AX设为您的具体情况适当段值
    MOV ES,AX;在这种情况下,我们将默认为ES = DS
    MOV BX,为0x8000;堆栈段可以是任何可用内存    MOV SS,BX;这与堆栈@ 0x80000的顶部放置它。
    MOV SP,AX;集SP = 0,堆栈底部将是@ 0x8FFFF    CLD;设置的方向标志为正方向    MOV SI,wolf_wel_msg
    电话wolf_print    MOV SI,wolf_kernel_load
    电话wolf_print    PUSHF
    STC    MOV啊,00
    INT 13H    read_sector:
        MOV AX,为0x0
        MOV ES,AX; ES = 0
        MOV BX,为0x1000; BX = 0x1000中。 ES:BX =为0x0:为0x1000
                        ; ES:BX =起始地址读取扇区(S)成
        MOV啊,02; INT 13H / AH = 2 =读取的扇区从驱动器
        MOV人,01;扇区读取= 1
        MOV CH,00; CH =汽缸。磁盘的第二扇形
                        ;在Cylinder的0而不是1
        MOV CL,02;读取扇区= 2
        MOV DH,00;头读取= 0
                        ; DL并没有被破坏我们的bootloader code,仍然
                        ;包含启动驱动器#由BIOS传递给我们的bootloader
        INT 13H    JC wolf_error
    POPF
    JMP为0x0:为0x1000
    CLI
    HLT    wolf_error:
        MOV SI,wolf_error_msg
        电话wolf_print
        MOV SI,wolf_error_msg1
        电话wolf_print
        MOV啊,00
        INT 16H
        异斧,斧
        INT 19H    wolf_print:
        LODSB
        还是人,人
        JZ退出
        MOV啊,为0x0E
        INT 10H
        JMP wolf_print
        出口:
        RET;引导签名之前,但code后的数据移动
wolf_wel_msg DB'欢迎Bootloader的!!!,0X0D,0x0A的,0
wolf_kernel_load DB'加载内核....',0X0D,0x0A的,0
wolf_error_msg DB'Kernel.bin没有找到!,0X0D,0x0A的,0
wolf_error_msg1分贝'preSS任意键重新启动..',0次510 - ($ - $$)0分贝
DW 0xAA55将

hello.asm

  [组织为0x1000]JMP启动
数据:
   MSG DB'你好',0
开始:
   MOV SI,味精
   调用打印;打印是一个函数,利用呼叫,而不是JMP   CLI
   HLT
   打印:
      LODSB
      还是人,人
      JZ退出
      MOV啊,为0x0E
      INT 10H
      JMP打印
  出口:
      RET


由于它似乎使用的是基于您的 DD 的命令给出的信息Windows中,您可能正在运行到另一个问题。我不知道哪个 DD 的你正在使用,但 =的\\\\。\\ D:不写入到磁盘的开始( USB驱动器),它将会写入分区D:驻留在,磁盘本身不是开始

我建议你使用从 Chrysocome 最新的 DD 的。截至今天最新的是 0.6beta3 。我推荐这个版本,因为它可以让你的磁盘(或U盘)相对正常访问到驱动器,而不是相对于特定分区的开始的开始。这可能会导致严重的问题,尝试存储第一和第二扇形正常。借助最新版的我会使用这些命令是管理员权限以写入到USB驱动器:

  DD如果= F:\\ BOOT.BIN OD = D:BS = 512计数= 1
DD如果= F:\\ hello.bin OD = D:BS = 512寻求= 1数= 1

这假定您的 USB 的驱动器是驱动器D:在你的问题提出了建议。 警告:如果不使用正确的驱动器可能会导致其它设备上的数据丢失和破坏!

如果这些命令正常工作,输出应该是这样的:


  DD如果= BOOT.BIN OD = D:BS = 512计数= 1
rawwrite DD的Windows版本0.6beta3。
撰稿约翰Newbigin< jn@it.swin.edu.au>
这个程序是由GPL版本2的条款约束。装置D:?是\\\\一个链接\\设备\\ HarddiskVolume5 \\\\。\\设备\\ HarddiskVolume5是\\设备\\ Harddisk1的一个分区
512 100%
1 + 0记录
1 + 0的记录了DD如果= hello.bin OD = D:BS = 512寻求= 1数= 1
rawwrite DD的Windows版本0.6beta3。
撰稿约翰Newbigin< jn@it.swin.edu.au>
这个程序是由GPL版本2的条款约束。装置D:?是\\\\一个链接\\设备\\ HarddiskVolume5 \\\\。\\设备\\ HarddiskVolume5是\\设备\\ Harddisk1的一个分区
28 5%
0 + 1记录
0 + 1记录了


一旦你发出这些命令时,Windows会自动检测到该驱动器不再格式正确。不要允许Windows格式化驱动器。如果你允许它格式化驱动器,将它重新分区和格式化了。它这样做会破坏​​你写的引导扇区。当系统提示,只需取消的格式的对话可能会出现对话框。

记住要正确卸载/从系统中删除之前弹出您的USB驱动器。未能正确卸载将可能导致数据不能正确/完全写入驱动器。

如果你想创建的Bochs,QEMU磁盘映像,DOSBox中等等,你可以创建在命令提示符720K软盘与以下命令:

  DD如果= /开发/的= disk.img BS = 1024计数= 720为零
DD如果= F:中\\ BOOT.BIN = disk.img BS = 512计数= 1 =单次转​​换notrunc之外
DD如果= F:\\ = disk.img BS = 512 hello.bin寻求= 1数= 1 =单次转​​换notrunc之外

图片文件 disk.img 应的Bochs,QEMU,DOSBox中,等是可用的或将其写入软盘720K一个真正的电脑上使用。

的/ dev / zero的看起来像一个典型的Unix / Linux的设备。在 DD 的用于Windows命令我建议你用理解的/ dev / zero的作为刚刚产生零一个特殊的输入设备。 Windows没有的/ dev / zero的设备,但 DD 的认为这是一个特殊的内部设备,并模拟它。


在与Bochs的2.6.8在MS Windows上运行,这是我所看到的:

在这里输入的形象描述

在我的联想笔记本电脑L520(非EFI BIOS)与16GB USB棒,这是我所看到的:

在这里输入的形象描述

I am learning the assembly language. I wrote a simple bootloader. After testing it out, it didn't work. Here is my code:

[bits 16]
[org 0x7c00]

jmp start

data:
wolf_wel_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0
wolf_kernel_load db 'Loading kernel....',0x0D,0x0A,0
wolf_error_msg db 'Kernel.bin not found!',0x0D,0x0A,0
wolf_error_msg1 db 'Press any key to restart..',0

start:
        mov si, wolf_wel_msg
    call wolf_print

    mov si, wolf_kernel_load
    call wolf_print

    pushf
    stc

    mov ah,00
    mov dl,00
    int 13h

    read_sector:
            mov ax, 0x0
        mov es, ax
        xor bx, bx
            mov ah, 02
        mov al, 01
        mov ch, 01
        mov cl, 02
        mov dh, 00
        mov dl, 00
        int 13h

    jc wolf_error
    popf
    jmp 0x0:0x1000
    cli
    hlt

    wolf_error:
            mov si, wolf_error_msg
        call wolf_print
        mov si, wolf_error_msg1
        call wolf_print
            mov ah,00
        int 16h
        xor ax,ax
        int 19h

    wolf_print:
            lodsb 
        or al,al
        jz exit
        mov ah,0x0e
        int 10h
        jmp wolf_print
        exit:
            ret

times 510-($-$$) db 0
dw 0xAA55

This code is placed in the first sector of the USB using this command:

dd if=f:\boot.bin of=\\.\d: bs=512 count=1

A simple program is loaded in the second sector of the USB using this command:

dd if=f:\hello.bin of=\\.\d: bs=512 seek=1 count=1

This is the code for the program loaded into the second sector:

[bits 16]
[org 0x1000]

jmp start
data:
   msg db 'Hello',0
start:
   mov si, msg
   jmp print

   cli
   hlt
   print:
      lodsb
      or al, al
      jz exit
      mov ah,0x0e
      int 10h
      jmp print
  exit:
      ret

Why is my boot loader not working? Have I done something wrong? Any suggestions?

解决方案

Your code assumes that DS is set to 0. You can't assume that. First part of your code should explicitly set DS to 0 if you are using org 0x7c00.

You should seriously considering defining your stack by setting SS:SP. You don't know where the existing one is or whether it is large enough to handle what you intend to do.

Just prior to your bootloader being called, the BIOS will set the DL register with the boot device number. You should not be setting DL to 0 in your code when making drive requests from the boot drive. You should be using the value that existed in DL when your bootloader was called.

You should use the CLD instruction to clear the direction flag since you are using the LODSB instruction expecting to be moving forward in memory. There isn't a guarantee the direction flag will be properly set so you should explicitly set it to the direction you need with CLD(forward) or STD(backward).

I have more information on the issues above in my StackOverflow answer with General Bootloader Tips.

Since you are not using a BPB then I highly recommend removing the jmp start as the first instruction of your bootloader. Instead move the data after the code but before the boot sector signature (0xAA55). The reason for that is some BIOSes will attempt to find a BPB based on a JMP instruction appearing as the first instruction of the bootloader, and if found overwrites parts of your bootloader in memory causing potentially undefined behavior.

Your bootloader uses this instruction to start your second stage loaded from the second sector:

jmp 0x0:0x1000

The problem is that when you read the sector setting up ES:BX this way:

read_sector:
    mov ax, 0x0
    mov es, ax
    xor bx, bx

This sets ES:BX to 0x0000:0x0000 which is clearly not where your JMP expects the code to be. You need to set ES:BX to the memory location you want INT 13/AH=02h to read the disk sector(s) into.

INT 13h/AH=02h requires Cylinder/Head/Sector number to be set properly. Sectors start numbering at 1, but Cylinders and Heads are zero based. The second sector of the disk is at Cylinder 0, Head 0, Sector 2. Your code sets Cylinder to 1 instead of 0. This code is wrong since you really should be setting it to 0:

mov ch, 01

In your second stage you created print as a function since it ends with a RET instruction. jmp print should be changed to call print.

With all the changes recommended above, including ones from my general bootloader tips your code could be modified to be:

boot.asm

[bits 16]
[org 0x7c00]

                   ; Use the boot drive number passed to us by BIOS in register DL
start:
    xor ax,ax      ; We want a segment of 0 for DS for this question
    mov ds,ax      ;     Set AX to appropriate segment value for your situation
    mov es,ax      ; In this case we'll default to ES=DS
    mov bx,0x8000  ; Stack segment can be any usable memory

    mov ss,bx      ; This places it with the top of the stack @ 0x80000.
    mov sp,ax      ; Set SP=0 so the bottom of stack will be @ 0x8FFFF

    cld            ; Set the direction flag to be positive direction

    mov si, wolf_wel_msg
    call wolf_print

    mov si, wolf_kernel_load
    call wolf_print

    pushf
    stc

    mov ah,00
    int 13h

    read_sector:
        mov ax, 0x0
        mov es, ax      ; ES = 0
        mov bx, 0x1000  ; BX = 0x1000. ES:BX=0x0:0x1000 
                        ; ES:BX = starting address to read sector(s) into
        mov ah, 02      ; Int 13h/AH=2 = Read Sectors From Drive
        mov al, 01      ; Sectors to read = 1
        mov ch, 00      ; CH=Cylinder. Second sector of disk
                        ; is at Cylinder 0 not 1
        mov cl, 02      ; Sector to read = 2
        mov dh, 00      ; Head to read = 0
                        ; DL hasn't been destroyed by our bootloader code and still
                        ;     contains boot drive # passed to our bootloader by the BIOS
        int 13h

    jc wolf_error
    popf
    jmp 0x0:0x1000
    cli
    hlt

    wolf_error:
        mov si, wolf_error_msg
        call wolf_print
        mov si, wolf_error_msg1
        call wolf_print
        mov ah,00
        int 16h
        xor ax,ax
        int 19h

    wolf_print:
        lodsb
        or al,al
        jz exit
        mov ah,0x0e
        int 10h
        jmp wolf_print
        exit:
        ret

; Moved the data before the boot signature but after the code
wolf_wel_msg db 'Welcome to Bootloader!!!',0x0D,0x0A,0
wolf_kernel_load db 'Loading kernel....',0x0D,0x0A,0
wolf_error_msg db 'Kernel.bin not found!',0x0D,0x0A,0
wolf_error_msg1 db 'Press any key to restart..',0

times 510-($-$$) db 0
dw 0xAA55

hello.asm

[org 0x1000]

jmp start
data:
   msg db 'Hello',0
start:
   mov si, msg
   call print      ; print is a function, use CALL instead of JMP

   cli
   hlt
   print:
      lodsb
      or al, al
      jz exit
      mov ah,0x0e
      int 10h
      jmp print
  exit:
      ret


Since it appears you are using Windows based upon the information given in your DD command, you may be running into another problem. I don't know which DD you are using but of=\\.\d: doesn't write to the beginning of the disk (USB drive), it will write to the partition that D: resides in, not the beginning of the disk itself.

I recommend you use the latest DD from Chrysocome. As of today the latest is 0.6beta3. I recommend this version because it allows you to properly access the disk(or USB stick) relative to the beginning of the drive, not relative to the beginning of a particular partition. This could cause serious problems trying to store the 1st and 2nd sector properly. With the latest version I'd use these commands with Administrator Privileges to write to the USB drive:

dd if=f:\boot.bin od=d: bs=512 count=1
dd if=f:\hello.bin od=d: bs=512 seek=1 count=1

This assumes your USB drive is on Drive D: as is suggested in your question. WARNING: Failure to use the correct drive may result in data loss and corruption on another device!!

If these commands work properly the output should look something like:

dd if=boot.bin od=d: bs=512 count=1
rawwrite dd for windows version 0.6beta3.
Written by John Newbigin <jn@it.swin.edu.au>
This program is covered by terms of the GPL Version 2.

Device d: is a link to \\?\Device\HarddiskVolume5 \\?\Device\HarddiskVolume5 is a partition on \Device\Harddisk1
512 100%
1+0 records in
1+0 records out

dd if=hello.bin od=d: bs=512 seek=1 count=1
rawwrite dd for windows version 0.6beta3.
Written by John Newbigin <jn@it.swin.edu.au>
This program is covered by terms of the GPL Version 2.

Device d: is a link to \\?\Device\HarddiskVolume5 \\?\Device\HarddiskVolume5 is a partition on \Device\Harddisk1
28 5%
0+1 records in
0+1 records out

Once you have issued these commands, Windows may automatically detect that the drive is no longer properly formatted. Do not allow Windows to format the drive. If you do allow it to format the drive, it will repartition it, and format it. In doing so it will destroy the boot sector you wrote. When prompted, just cancel the format dialog box that may appear.

Remember to properly dismount/eject your USB drive before removing it from your system. Failure to properly unmount will likely cause the data to not be properly/completely written to the drive.

If you wish create a disk image for Bochs, QEMU, Dosbox etc you could create a 720k floppy with these commands at a Command Prompt:

dd if=/dev/zero of=disk.img bs=1024 count=720    
dd if=f:\boot.bin of=disk.img bs=512 count=1 conv=notrunc
dd if=f:\hello.bin of=disk.img bs=512 seek=1 count=1 conv=notrunc

The image file disk.img should be usable by Bochs, QEMU, Dosbox, etc. or written to a 720k diskette for use on a real computer.

/dev/zero looks like a typical Unix/Linux device. The DD command for Windows I suggested you use understands /dev/zero as a special input device that just generates zeros. Windows doesn't have /dev/zero device, but DD sees it as a special internal device and simulates it.


When run with Bochs 2.6.8 on MS Windows this is what I saw:

On my Lenovo L520 Laptop (non-EFI BIOS) with a 16GB USB Stick this is what I saw:

这篇关于启用引导加载器加载一个USB的第二扇形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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