int 13h似乎不读取包含我的内核的扇区 [英] int 13h doesn't appear to read sectors containing my kernel

查看:73
本文介绍了int 13h似乎不读取包含我的内核的扇区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用USB上的引导程序加载一些数据,但显然int 13h无法正常工作!

I am trying to load up a little data using my bootloader on a USB, but apparently int 13h won't work!

引导程序:

[bits 16]
[ORG 0x7c00]

jmp 0x0000:start
start:

cli
xor ax, ax
mov ss, ax
mov sp, 0x7c00

mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
sti

mov [driveno], dl

reset:
    ;reset drive
xor ax, ax
mov dl, [driveno]
int 0x13
or ah, ah
jnz reset


mov ah, 0x02
mov al, 0x01
mov bx, 0x0000
mov es, bx
mov bx, 0x7e00

mov dl, [driveno]

xor dh, dh

mov cx, 0x0002

int 0x13
or ah, ah
jnz reset


mov dx, [0x7e00]   ;So i can check and see if it has been loaded
call printhex

cli
hlt
jmp $

print:
loop:
lodsb
or al, al
jz done
mov ah, 0x0e
mov bx, 0x0003 ;page 0 and default color
int 0x10
jmp loop
done:
ret

printhex:
push bx
push si
mov si, hex_template

mov bx, dx
shr bx, 12
mov bx, [bx+hexabet]
mov [hex_template+2], bl

mov bx, dx
shr bx, 8
and bx, 0x000f
mov bx, [bx+hexabet]
mov [hex_template+3], bl

mov bx, dx
shr bx, 4
and bx, 0x000f
mov bx, [bx+hexabet]
mov [hex_template+4], bl

mov bx, dx
and bx, 0x000f
mov bx, [bx+hexabet]
mov [hex_template+5], bl

call print
pop si
pop bx
ret

hex_template db '0x????',0
hexabet db '0123456789abcdef'

driveno db 0      ;Storing dl

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

dw 0x1234  ;This wont load!!!!

times 510 db 0

我希望我的十六进制转储方法将0x1234打印到屏幕上,但是它却打印0x0000!我知道我的十六进制转储方法有效,问题是0x1234从来没有被加载过.有什么想法吗?

I want my hex dump method to print out 0x1234 to the screen, but it prints 0x0000 instead! I know my hex dump method works, the problem is that the 0x1234 never gets loaded in the first place. Any ideas?

我正在Windows上运行.我用以下命令编译并生成图像:

I'm running on Windows. I compile and generate an image with:

nasm -f bin -o boot.bin boot.asm
dd if=boot.bin of=\\.\e: bs=512 count=2

我正在使用 chrysocome 中的 dd .谁能解释这种行为?

I am using dd from chrysocome. Can anyone explain this behavior?

推荐答案

尽管这个问题很久了,但它的确暴露了一个我知道其他人已经遇到过的问题,应该给出正确的答案.

Although this question is old, it does bring to light a problem that I know has been experienced by others that does deserve a proper answer.

弗兰克·科特勒指出,您的代码看起来不错.我有几个未成年的顽皮:

As Frank Kotler points out your code looks fine. A couple minor nitpicks I have:

  • Before using lodsb you don't specify a direction flag with instruction CLD or STD. In your case it should be CLD since you expect LODSB to advance in a positive direction. You can see a more thorough explanation in another StackOverflow answer I wrote.
  • Although you are targeting 16-bit code you are setting up fs and gs segment registers which aren't available one 8086/8088/80286.

问题是您对 DD 程序的使用情况.您可以这样做:

The issue is your usage of the DD program. You do:

dd if=boot.bin of=\.\e: bs=512 count=2

通常,您将使用 of = \\.\ e:和双反斜杠,但这不是问题的根源. \.\ e:实际上并不指向磁盘(或USB驱动器)的开头.它指向 E:指向的分区的开头.因此,您在分区数据的开头而不是 Master Boot Record (MBR)处写入了引导加载程序.较新版本的 DD 支持一个选项,用于指定整个设备的开头(而不仅仅是分区):

Typically you'd use of=\\.\e: with double backslash, however this isn't the cause of the problem. \.\e: doesn't actually point at the beginning of the disk (or USB drive). It points to the beginning of the partition that E: points to. Because of this you wrote your bootloader at the beginning of partition data, and not the Master Boot Record(MBR) . Newer versions of DD support an option to specify the the beginning of the entire device (not just a partition):

0.6beta1版本中的更改

Changes in version 0.6beta1

输入磁盘和输出磁盘的新功能id =/od =.如果是磁盘上的唯一分区,则将选择整个磁盘.例如:如果您插入USB磁盘并将其安装为f :,则'id = f:'将选择USB磁盘(而不仅仅是分区,如if = \.\ f:那样)

new feature id=/od= for input disk and output disk. if is the only partition on a disk, then the entire disk is selected. Eg: if you insert a USB disk and it is mounted as f: then 'id=f:' will select the USB disk (not just the partition like if=\.\f: would do)

要写入分区 E:所在的USB驱动器的开头,可以执行此操作(我假设您以具有Admin特权的用户身份运行命令提示符):

To write to the beginning of the USB drive that partition E: is a part of, you can do this (I'm assuming you are running the command prompt as a user with Admin privileges):

dd if=boot.bin od=e: bs=512 count=2

注意我现在如何指定( od = e:). od = (输出设备)仅表示我们要使用 E:所属的整个物理设备分区.

Notice how I have now specified (od=e:). od=(output device) just means that we want to use the entire physical device partition E: belongs to.

可能感兴趣的是为什么引导加载程序似乎可以工作但打印出 0x0000 的原因.我将基于Windows的知识提出我的最佳猜测.

What may be of interest is to why your bootloader seemed to work but printed out 0x0000. I'll offer up my best guess based on knowledge of Windows.

由于 DD 写入分区起始位置(而不是驱动器起始位置)的问题#2(从1开始)实际上并不包含我们的小内核.第一个扇区甚至不包含我们编写的引导程序!

Because of the issue with DD writing to the beginning of the partition (and not the beginning of the drive) sector #2 (1-based) doesn't actually contain our small kernel. Sector #1 doesn't even contain the bootloader we wrote!

现在,如果我们的代码是写在分区中的,为什么引导程序甚至运行,为什么打印错误的值(0x0000)?

Now if our code was written in the partition, why did our bootloader even run and why did it print the wrong value (0x0000)?

如果您使用Windows格式化USB驱动器,则会发生这种情况.您可能没有意识到,默认情况下,USB驱动器的格式类似于具有单个分区的硬盘驱动器,并且一个分区被标记为可引导.Microsoft在MBR(磁盘的第一个扇区)中安装了引导加载程序.此Microsoft引导加载程序是一个链加载程序,通常具有以下功能(某些细节可能有所不同):

This would occur if you formatted the USB drive with Windows. What you may not realize is that the USB drive by default is formatted like a hard drive with a single partition, and that one partition is marked as bootable. Microsoft installs a bootloader in the MBR (first sector of the disk). This Microsoft bootloader is a chainloader, and it typically functions like this (some of the details may vary):

  • 设置细分并正确堆叠
  • 保存 DL [我们启动的驱动器]
  • 将自己从物理地址0x00007C00移到其他地方.
  • 跳到我们应该继续的新内存位置中的偏移量
  • 在分区表中查看标记为可引导的分区
  • 可引导分区(不是磁盘)的第一个扇区(512字节)读入内存中的0x00007C00
  • 使用第一步中保存的值恢复 DL
  • 将FAR JMP转换为0x0000:0x7C00
  • 开始执行分区引导程序,就好像BIOS已加载并直接跳转到它一样.
  • Set up segment and stack appropriately
  • Save DL [drive we booted on]
  • Move ourselves from physical address 0x00007C00 somewhere else.
  • Jump to the offset in the new memory location where we should continue
  • Look at the partition table for the partition marked bootable
  • Read first sector (512 bytes) of the bootable partition (not disk) into memory at 0x00007C00
  • Restore DL with the value saved in first step
  • FAR JMP to 0x0000:0x7C00
  • Execution of the partition bootloader begins as if the BIOS had loaded and jumped to it directly.

我们现在所拥有的是Microsoft MBR引导加载程序,它读取USB驱动器上可引导分区的第一个扇区并执行它.分区的第一个扇区恰好是我们的引导程序,因为我们使用了 dd if = boot.bin of = \.\ e:bs = 512 count = 2 .我们实际上写了两个部分.分区的第二个扇区(不是磁盘)包含我们的内核.因此,我们的引导程序有效运行了!

What we have now is the Microsoft MBR bootloader reading the first sector of the bootable partition on the USB drive and executing it. The first sector of the partition happens to be our bootloader because we used dd if=boot.bin of=\.\e: bs=512 count=2 . We actually wrote two sectors. The second sector of the partition (not disk) contains our kernel. So effectively our bootloader runs!

所以现在我们知道了为什么引导加载程序运行了,为什么它输出了错误的值?现在可能更清楚了,磁盘的第二个扇区没有我们的内核,分区包含了它.磁盘读取( int 13h )代码执行以下操作:

So now we know why our bootloader ran, why did it print out the wrong value? It might be clearer now that the second sector of the disk doesn't have our kernel, the partition contains it. The disk read (int 13h) code does this:

mov ah, 0x02            ; Disk Read
mov al, 0x01            ; Number of Sectors to read
mov bx, 0x0000
mov es, bx
mov bx, 0x7e00          ; ES:BX location to read to 0x0000:0x7E00
mov dl, [driveno]
xor dh, dh
mov cx, 0x0002          ; Read sector #2 (1-based, not 0-based)
int 0x13

我们只读取磁盘的第二个扇区,而不是分区.第二个扇区很可能被清零,这就是我们的引导加载程序读取值0x0000的原因.

We just read the second sector of the disk, not the partition. Most likely the second sector is zeroed out and thus the reason why our bootloader read a value of 0x0000 .

如果我们已正确写入磁盘的前两个扇区(1024个字节)(带有 DD ),则我们的引导加载程序和内核将正常工作..

If we had properly written over the first 2 sectors (1024 bytes) of the disk (with DD) then our bootloader and kernel would have worked properly..

感谢Microsoft及其chainloader-我们的引导程序运行了,但是内核在磁盘上的位置不正确,因此我们打印了一个可能填充零的扇区.这一系列事件恰巧使我们的引导程序运行,并导致 int 13h 出现故障.它可能根本没有失败,只是读取了一个不包含我们内核的扇区.

Thanks to Microsoft and its chainloader - our bootloader ran but the kernel was in the wrong place on the disk and we printed out a sector that is likely filled with zeroes. This chain of events happened to make our bootloader run and made it appear that int 13h failed. It likely didn't fail at all, it just read a sector that didn't contain our kernel.

注意:我使用的是 kernel 这个词,但是在这个问题的上下文中,它是指存储在第二个扇区中的数据( 0x1234 ).

Note: I use the word kernel, but in the context of this question it refers to the data (0x1234) being stored in the second sector.

这篇关于int 13h似乎不读取包含我的内核的扇区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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