BIOS INT 13H有问题(从驱动器中读取扇区) [英] Problem with BIOS INT 13H (Read Sectors From Drive)

查看:93
本文介绍了BIOS INT 13H有问题(从驱动器中读取扇区)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在创建一个简单的独立程序的过程中,我在第一个扇区中编写了一个简单的引导加载程序.其目的是将程序加载到内存中.为此,我使用AH = 2的INT 13h.代码是:

In my efforts to create a simple standalone program I have written a simple boot loader in the first sector. Its purpose is to load the program into memory. For this purpose I am using INT 13h with AH=2. The code is:

disk_load:
  push dx           ; Store DX on stack so later we can recall how many sectors were requested to be read,
                    ; even if it is altered in the meantime.
  mov ah, 0x02        ; BIOS read sector.
  mov al, dh          ; Read DH sectors.
  mov ch, 0x00        ; Select cylinder 0.
  mov dh, 0x00        ; Select head 0.
  mov cl, 0x02        ; Start reading from second sector (i.e. after the boot sector).
  int 0x13            ; BIOS interrupt.
                      ;  <!----here
  pop dx
  ret

load_software:
  mov bx, 0x7e0
  mov es, bx
  xor bx, bx
  mov dh, 66
  mov dl, [BOOT_DRIVE]
  call disk_load

我在VirtualBox 5.2.8中锻炼了所有东西,效果很好.将所有内容移动到具有VirtualBox 6.0.14的第二台计算机上均无法通过实验.中断以CF设置结束,表示失败.

I was exercising everything in VirtualBox 5.2.8 and it worked perfectly well. Moving everything to a second machine that has VirtualBox 6.0.14 fails the experiment. The interrupt finishes with CF set, indicating a failure.

Boot loader不会跳转的情况下阅读出色的答案到内核​​代码我已经解决了可能导致问题的未指定DS值的潜在问题.如果在int 0x13调用之前停止并转储CPU状态,则两个VirtualBox上的状态都将保持一致:

Reading the excellent answer in Boot loader doesn't jump to kernel code I have fixed the potential problem of unspecified DS value that could cause problems. If I stop and dump the CPU status just before the int 0x13 call I get a consistent state on both VirtualBoxes:

00:00:05.930849 eax = 00000280 ebx = 00007e00 ecx = 00000002 edx = 00000000 esi = 00000000 edi = 0000fff0

00:00:05.930849 eax=00000280 ebx=00007e00 ecx=00000002 edx=00000000 esi=00000000 edi=0000fff0

00:00:05.930857 eip = 00007cc8 esp = 00007bf9 ebp = 00007bff iopl = 0 nv up ei pl nz na po nc

00:00:05.930857 eip=00007cc8 esp=00007bf9 ebp=00007bff iopl=0 nv up ei pl nz na po nc

00:00:05.930864 cs = {0000 base = 0000000000000000限制= 0000ffff标志= 0000009b} dr0 = 00000000 dr1 = 00000000

00:00:05.930864 cs={0000 base=0000000000000000 limit=0000ffff flags=0000009b} dr0=00000000 dr1=00000000

00:00:05.930877 ds = {0000 base = 0000000000000000限制= 0000ffff标志= 00000093} dr2 = 00000000 dr3 = 00000000

00:00:05.930877 ds={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr2=00000000 dr3=00000000

00:00:05.930884 es = {0000 base = 0000000000000000限制= 0000ffff标志= 00000093} dr4 = 00000000 dr5 = 00000000

00:00:05.930884 es={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr4=00000000 dr5=00000000

00:00:05.930891 fs = {0000 base = 0000000000000000限制= 0000ffff标志= 00000093} dr6 = ffff0ff0 dr7 = 00000400

00:00:05.930891 fs={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr6=ffff0ff0 dr7=00000400

00:00:05.930898 gs = {0000 base = 0000000000000000限制= 0000ffff标志= 00000093} cr0 = 00000010 cr2 = 00000000

00:00:05.930898 gs={0000 base=0000000000000000 limit=0000ffff flags=00000093} cr0=00000010 cr2=00000000

00:00:05.930904 SS = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} cr3 = 00000000 cr4 = 00000000

00:00:05.930904 ss={0000 base=0000000000000000 limit=0000ffff flags=00000093} cr3=00000000 cr4=00000000

00:00:05.930910 gdtr = 00000000000fe89f:0047 idtr = 0000000000000000:ffff eflags = 00200246

00:00:05.930910 gdtr=00000000000fe89f:0047 idtr=0000000000000000:ffff eflags=00200246

解析所有值,我只能得出结论,该中断的所有输入参数均已正确设置.转储后的状态已设置CF和错误代码:

Parsing all the values I can only conclude that all the input parameters to the interrupt are set up properly. The state after the dump has CF set and an error code:

00:00:08.984877 eax = 00000900 ebx = 00000000 ecx = 00000002 edx = 00000000 esi = 00000000 edi = 0000fff0

00:00:08.984877 eax=00000900 ebx=00000000 ecx=00000002 edx=00000000 esi=00000000 edi=0000fff0

00:00:08.984887 eip = 00007cca esp = 00007bf9 ebp = 00007bff iopl = 0 nv up ei pl nz na po cy

00:00:08.984887 eip=00007cca esp=00007bf9 ebp=00007bff iopl=0 nv up ei pl nz na po cy

00:00:08.984896 cs = {0000 base = 0000000000000000限制= 0000ffff标志= 0000009b} dr0 = 00000000 dr1 = 00000000

00:00:08.984896 cs={0000 base=0000000000000000 limit=0000ffff flags=0000009b} dr0=00000000 dr1=00000000

00:00:08.984909 ds = {0000 base = 0000000000000000限制= 0000ffff标志= 00000093} dr2 = 00000000 dr3 = 00000000

00:00:08.984909 ds={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr2=00000000 dr3=00000000

00:00:08.984917 es = {07e0 base = 0000000000007e00限制= 0000ffff标志= 00000093} dr4 = 00000000 dr5 = 00000000

00:00:08.984917 es={07e0 base=0000000000007e00 limit=0000ffff flags=00000093} dr4=00000000 dr5=00000000

00:00:08.984925 fs = {0000 base = 0000000000000000限制= 0000ffff标志= 00000093} dr6 = ffff0ff0 dr7 = 00000400

00:00:08.984925 fs={0000 base=0000000000000000 limit=0000ffff flags=00000093} dr6=ffff0ff0 dr7=00000400

00:00:08.984934 gs = {0000 base = 0000000000000000限制= 0000ffff标志= 00000093} cr0 = 00000010 cr2 = 00000000

00:00:08.984934 gs={0000 base=0000000000000000 limit=0000ffff flags=00000093} cr0=00000010 cr2=00000000

00:00:08.984941 ss = {0000 base = 0000000000000000 limit = 0000ffff flags = 00000093} cr3 = 00000000 cr4 = 00000000

00:00:08.984941 ss={0000 base=0000000000000000 limit=0000ffff flags=00000093} cr3=00000000 cr4=00000000

00:00:08.984948 gdtr = 00000000000fe89f:0047 idtr = 0000000000000000:ffff eflags = 00200247

00:00:08.984948 gdtr=00000000000fe89f:0047 idtr=0000000000000000:ffff eflags=00200247

注意到错误代码AH=9 数据边界错误(尝试通过DMA跨越64K边界或> 80h扇区)导致我进入

Noting the error code AH=9 data boundary error (attempted DMA across 64K boundary or >80h sectors) lead me to https://en.wikipedia.org/wiki/INT_13H where this statement is made:

缓冲区的寻址应确保完整的缓冲区在给定的段内,即(BX + size_of_buffer)<= 10000h.

Addressing of Buffer should guarantee that the complete buffer is inside the given segment, i.e. ( BX + size_of_buffer ) <= 10000h.

这可以解释我最初的问题,因此我进行了另一项修复以设置es=0x7e0bx=0.这是上面显示的代码的状态.但是,即使这段代码在上述状态下也会失败.

This would explain my initial problems so I made another fix to set the es=0x7e0 and bx=0. This is the state of the code that is displayed above. However even this code fails with the state described above.

进一步的测试表明,我最多可以成功读取65个扇区,但有66个或更多失败.由于它是一个怪异的数字,我计算出第65个扇区的结尾:0xffff.因此问题变得更加混乱.

Further testing shows that I can successfully read up to 65 sectors but 66 or more fails. Being it a weird number I calculated the end of the 65th sector: 0xffff. So the problem becomes a little bit more confusing.

我的es=0x7e0bx=0解决方案应该避免段交叉(据我所知)吗?

Should my es=0x7e0 and bx=0 solution avoid the segment crossing (as I understand it should)?

如果是这样,为什么跨线性地址似乎是个问题?

If it does, why does it seem to be the problem in crossing the linear address?

或者可以跨过该段,但不能跨越线性地址中的0xffff标记吗?

Or can one cross the segment, but not the 0xffff marker in linear address?

谢谢您的帮助.

推荐答案

问题是您尝试在64K边界上尝试DMA".这是事实,您的目标缓冲区的范围从物理地址0x07E00到0x17E00,跨越了0x10000处的64K边界. (这与段边界无关,因此,使用哪个段和偏移值到达0x07E00物理地址都没有关系.)

The problem is that you've "attempted DMA across a 64K boundary". It's the fact that your destination buffer spans from physical address 0x07E00 to 0x17E00, which crosses the 64K boundary at 0x10000. (This has nothing to do with segment boundaries, so it doesn't matter what segment and offset values you use to arrive at a 0x07E00 physical address.)

这样做的原因必须与廉价设计原始IBM PC的方式有关.他们没有使用带有16位总线和16位支持芯片的16位8086,而是使用了便宜的带有8位总线的16位8088 CPU,该CPU可以与便宜的8位支持芯片一起使用.特别是他们选择的DMA控制器只能寻址64K内存,这是典型的寻址限制DMA控制器是为8位CPU设计的.他们通过使用单独的芯片来提供DMA地址的高四位来使其工作,从而允许对8088的完整1024K地址空间进行寻址. (在IBM PC AT上,它被扩展为提供高8位,以便可以访问整个80286 16M地址空间.)

The reason for this has to do how the original IBM PC was designed on the cheap. Instead of using a 16-bit 8086 with a 16-bit bus and 16-bit support chips, they used a cheaper 16-bit 8088 CPU with an 8-bit bus that could be used with cheaper 8-bit support chips. In particular the DMA controller they chose is only capable of addressing 64K of memory, the typical addressing limit for 8-bit CPUs the DMA controller was designed for. They made it work by having a separate chip which provides the upper four bits of DMA addresses, allowing 8088's full 1024K address space to be addressed. (On the IBM PC AT this was extended to provide the upper eight bits, so that the entire 80286 16M address space could be accessed.)

不幸的是,这意味着在DMA操作期间DMA地址的高四位是固定的,这实际上将1024K地址空间划分为16个64K页.任何尝试执行跨64K边界从一页到另一页的DMA操作的尝试都将环绕到页面的开头.尽管BIOS可以通过将读取分为两个单独的读取(每个64K页面一个读取)来解决此问题,但它只会返回错误.

Unfortunately this means the upper four bits the DMA address are fixed during a DMA operation, which effectively divides the 1024K address space into sixteen 64K pages. Any attempt to perform a DMA operation that crosses from one page to the next, across a 64K boundary, will wrap around to the beginning of the page instead. While the BIOS could work around this problem by dividing the read into two separate reads, one for each 64K page, it simply returns an error.

请注意,这通常只是软盘访问中的一个问题,因为硬盘接口通常不使用IBM PC DMA控制器.

Note this is generally only a problem with floppy disk accesses as hard disk interfaces generally don't use the IBM PC DMA controller.

由于跨越轨道和圆柱边界时也存在类似的潜在边界问题,因此解决此问题的最佳方法是一次只读取一个扇区,如Jester和Michael Petch在评论中所说.作为一个简单的解决方法,您可以移动缓冲区,使其从物理地址0x10000开始,但是您可能会发现在现实世界的系统上,您只能读取轨道上的其余扇区.

Since potential boundary problems like this also exist when crossing track and cylinder boundaries, the best way to work around this issue is to just read one sector in a time, like Jester and Michael Petch said in comments. As a simple work around you can just move your buffer so that it starts at physical address 0x10000 but you may find on real world systems you're limited to reading to just the remaining sectors on the track.

这篇关于BIOS INT 13H有问题(从驱动器中读取扇区)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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