"skipping"内存块的 ATA 磁盘驱动程序



我正试图编写一个简单的32位x86操作系统,但我的ATA磁盘驱动程序代码有问题。

我已经编写了以下C++类,其函数read_sects_pio28应该读取sect_count磁盘扇区,从偏移量sect_offs开始,到物理地址pa_dest:

template<typename T>
void out(uint16_t port, T data)
{
asm ("out %0,%1"
: : "a" (data), "d" (port));
}
template<typename T>
T in(uint16_t port)
{
T data;
asm volatile("in %1,%0"
: "=a" (data)
: "d" (port));
return data;
}
template<typename T>
void ins(uint16_t port, uint32_t dest, uint32_t count)
{
static_assert(detail::is_uint_le32_t<T>());
asm volatile("rep ins%z2"
: "+D" (dest), "+c" (count), "=m" (dest)
: "d" (port)
: "memory");
}
class Disk_driver_ata
{
enum : uint32_t
{
ATA_PORT_DATA = 0x1F0,
ATA_PORT_SECT_COUNT = 0x1F2,
ATA_PORT_LBA_LO = 0x1F3,
ATA_PORT_LBA_MID = 0x1F4,
ATA_PORT_LBA_HI = 0x1F5,
ATA_PORT_DRIVE_HEAD = 0x1F6,
ATA_PORT_STATUS = 0x1F7,
ATA_PORT_CMD = 0x1F7
};
enum : uint8_t
{
ATA_PIO48_MASTER = 0x40,
ATA_PIO48_CMD_READ = 0x24,
ATA_STATUS_DRQ = 0x08
};
public:
void read_sects(uint32_t pa_dest,
uint64_t sect_offs,
uint16_t sect_count) const override
{ read_sects_pio48(pa_dest, sect_offs, sect_count); }
private:
static void read_sects_pio48(uint32_t pa_dest,
uint64_t sect_offs,
uint16_t sect_count)
{
x86::outb(ATA_PORT_DRIVE_HEAD, ATA_PIO48_MASTER);
x86::outb(ATA_PORT_SECT_COUNT, (sect_count >> 8) & 0xFF);
x86::outb(ATA_PORT_LBA_LO, (sect_offs >> 24) & 0xFF);
x86::outb(ATA_PORT_LBA_MID, (sect_offs >> 32) & 0xFF);
x86::outb(ATA_PORT_LBA_HI, (sect_offs >> 40) & 0xFF);
x86::outb(ATA_PORT_SECT_COUNT, sect_count & 0xFF);
x86::outb(ATA_PORT_LBA_LO, sect_offs & 0xFF);
x86::outb(ATA_PORT_LBA_MID, (sect_offs >> 8) & 0xFF);
x86::outb(ATA_PORT_LBA_HI, (sect_offs >> 16) & 0xFF);
x86::outb(ATA_PORT_CMD, ATA_PIO48_CMD_READ);
for (uint8_t sec = 0u; sec < sect_count; ++sec) {
poll_status(ATA_STATUS_DRQ);
x86::ins<uint32_t>(ATA_PORT_DATA, pa_dest, DISK_SECT_SIZE / 4);
pa_dest += DISK_SECT_SIZE / 4;
}
}
static void poll_status(uint8_t status)
{
while (!(x86::in<uint8_t>(ATA_PORT_STATUS) & status))
;
}
};

我想使用这个函数来加载我的内核的可执行ELF段,它目前只有688字节大,以寻址0x100000。在磁盘上,段从0x1800开始,因此使用pa_dest=0x10000sect_offs=12sect_count=2调用read_sects_pio28(我已经使用调试器验证了实际情况(。

但这似乎只是类型的工作。以下是磁盘上的片段:

00001800  e9 00 00 00 00 55 89 e5  83 ec 08 83 ec 0c 6a 68  |.....U........jh|
00001810  e8 31 02 00 00 83 c4 10  83 ec 0c 6a 65 e8 24 02  |.1.........je.$.|
00001820  00 00 83 c4 10 83 ec 0c  6a 6c e8 17 02 00 00 83  |........jl......|
00001830  c4 10 83 ec 0c 6a 6c e8  0a 02 00 00 83 c4 10 83  |.....jl.........|
00001840  ec 0c 6a 6f e8 fd 01 00  00 83 c4 10 83 ec 0c 6a  |..jo...........j|
00001850  0a e8 f0 01 00 00 83 c4  10 90 c9 c3 55 89 e5 83  |............U...|
00001860  ec 18 8b 45 08 66 89 45  f4 0f b7 45 f4 83 ec 0c  |...E.f.E...E....|
00001870  50 e8 fa 01 00 00 83 c4  10 c9 c3 55 89 e5 83 ec  |P..........U....|
00001880  18 8b 45 08 8b 55 0c 66  89 45 f4 89 d0 88 45 f0  |..E..U.f.E....E.|
00001890  0f b6 55 f0 0f b7 45 f4  83 ec 08 52 50 e8 eb 01  |..U...E....RP...|
000018a0  00 00 83 c4 10 90 c9 c3  55 89 e5 83 ec 18 c7 45  |........U......E|
000018b0  f4 00 00 00 00 83 ec 08  6a 0e 68 d4 03 00 00 e8  |........j.h.....|
000018c0  b7 ff ff ff 83 c4 10 83  ec 0c 68 d5 03 00 00 e8  |..........h.....|
000018d0  88 ff ff ff 83 c4 10 0f  b6 c0 c1 e0 08 89 45 f4  |..............E.|
000018e0  83 ec 08 6a 0f 68 d4 03  00 00 e8 8c ff ff ff 83  |...j.h..........|
000018f0  c4 10 83 ec 0c 68 d5 03  00 00 e8 5d ff ff ff 83  |.....h.....]....|
00001900  c4 10 0f b6 c0 09 45 f4  8b 45 08 c7 00 00 80 0b  |......E..E......|
00001910  00 8b 45 f4 89 c2 8b 45  08 66 89 50 04 90 c9 c3  |..E....E.f.P....|
00001920  55 89 e5 53 83 ec 14 8b  45 0c 88 45 f7 c6 45 f6  |U..S....E..E..E.|
00001930  f0 0f b6 45 f6 c1 e0 08  89 c2 0f b6 45 f7 09 d0  |...E........E...|
00001940  66 89 45 f4 0f b6 45 f7  83 f8 0a 75 11 8b 45 08  |f.E...E....u..E.|
00001950  0f b7 40 04 8d 50 50 8b  45 08 66 89 50 04 8b 45  |..@..PP.E.f.P..E|
00001960  08 8b 18 8b 45 08 0f b7  40 04 8d 48 01 8b 55 08  |....E...@..H..U.|
00001970  66 89 4a 04 0f b7 c0 01  c0 8d 14 03 0f b7 45 f4  |f.J...........E.|
00001980  66 89 02 90 8b 45 08 0f  b7 50 04 0f b7 c2 69 c0  |f....E...P....i.|
00001990  cd cc 00 00 c1 e8 10 66  c1 e8 06 66 89 45 f2 0f  |.......f...f.E..|
000019a0  b7 4d f2 89 c8 c1 e0 02  01 c8 c1 e0 04 29 c2 66  |.M...........).f|
000019b0  89 55 f2 8b 45 08 0f b7  40 04 0f b7 c0 69 c0 cd  |.U..E...@....i..|
000019c0  cc 00 00 c1 e8 10 66 c1  e8 06 66 89 45 f0 0f b7  |......f...f.E...|
000019d0  55 f0 89 d0 c1 e0 02 01  d0 c1 e0 04 89 c2 0f b7  |U...............|
000019e0  45 f2 01 d0 66 89 45 ee  83 ec 08 6a 0f 68 d4 03  |E...f.E....j.h..|
000019f0  00 00 e8 84 fe ff ff 83  c4 10 0f b7 45 ee 0f b6  |............E...|
00001a00  c0 83 ec 08 50 68 d4 03  00 00 e8 6c fe ff ff 83  |....Ph.....l....|
00001a10  c4 10 83 ec 08 6a 0e 68  d4 03 00 00 e8 5a fe ff  |.....j.h.....Z..|
00001a20  ff 83 c4 10 0f b7 45 ee  66 c1 e8 08 0f b6 c0 83  |......E.f.......|
00001a30  ec 08 50 68 d4 03 00 00  e8 3e fe ff ff 83 c4 10  |..Ph.....>......|
00001a40  90 8b 5d fc c9 c3 55 89  e5 83 ec 18 83 ec 0c 8d  |..]...U.........|
00001a50  45 f0 50 e8 50 fe ff ff  83 c4 10 83 ec 08 ff 75  |E.P.P..........u|
00001a60  08 8d 45 f0 50 e8 b6 fe  ff ff 83 c4 10 90 c9 c3  |..E.P...........|
00001a70  55 89 e5 83 ec 14 8b 45  08 66 89 45 ec 0f b7 45  |U......E.f.E...E|
00001a80  ec 89 c2 ec 88 45 ff 0f  b6 45 ff c9 c3 55 89 e5  |.....E...E...U..|
00001a90  83 ec 08 8b 45 08 8b 55  0c 66 89 45 fc 89 d0 88  |....E..U.f.E....|
00001aa0  45 f8 0f b6 45 f8 0f b7  55 fc ee 90 c9 c3 3a 00  |E...E...U.....:.|
00001ab0  00 00 03 00 27 00 00 00  01 01 fb 0e 0d 00 01 01  |....'...........|

以下是实际加载到内存中的内容:

00000000  e9 00 00 00 00 55 89 e5  83 ec 08 83 ec 0c 6a 68  |.....U........jh|
00000010  e8 31 02 00 00 83 c4 10  83 ec 0c 6a 65 e8 24 02  |.1.........je.$.|
00000020  00 00 83 c4 10 83 ec 0c  6a 6c e8 17 02 00 00 83  |........jl......|
00000030  c4 10 83 ec 0c 6a 6c e8  0a 02 00 00 83 c4 10 83  |.....jl.........|
00000040  ec 0c 6a 6f e8 fd 01 00  00 83 c4 10 83 ec 0c 6a  |..jo...........j|
00000050  0a e8 f0 01 00 00 83 c4  10 90 c9 c3 55 89 e5 83  |............U...|
00000060  ec 18 8b 45 08 66 89 45  f4 0f b7 45 f4 83 ec 0c  |...E.f.E...E....|
00000070  50 e8 fa 01 00 00 83 c4  10 c9 c3 55 89 e5 83 ec  |P..........U....|
00000080  c0 83 ec 08 50 68 d4 03  00 00 e8 6c fe ff ff 83  |....Ph.....l....|
00000090  c4 10 83 ec 08 6a 0e 68  d4 03 00 00 e8 5a fe ff  |.....j.h.....Z..|
000000a0  ff 83 c4 10 0f b7 45 ee  66 c1 e8 08 0f b6 c0 83  |......E.f.......|
000000b0  ec 08 50 68 d4 03 00 00  e8 3e fe ff ff 83 c4 10  |..Ph.....>......|
000000c0  90 8b 5d fc c9 c3 55 89  e5 83 ec 18 83 ec 0c 8d  |..]...U.........|
000000d0  45 f0 50 e8 50 fe ff ff  83 c4 10 83 ec 08 ff 75  |E.P.P..........u|
000000e0  08 8d 45 f0 50 e8 b6 fe  ff ff 83 c4 10 90 c9 c3  |..E.P...........|
000000f0  55 89 e5 83 ec 14 8b 45  08 66 89 45 ec 0f b7 45  |U......E.f.E...E|
00000100  ec 89 c2 ec 88 45 ff 0f  b6 45 ff c9 c3 55 89 e5  |.....E...E...U..|
00000110  83 ec 08 8b 45 08 8b 55  0c 66 89 45 fc 89 d0 88  |....E..U.f.E....|
00000120  45 f8 0f b6 45 f8 0f b7  55 fc ee 90 c9 c3 3a 00  |E...E...U.....:.|
00000130  00 00 03 00 27 00 00 00  01 01 fb 0e 0d 00 01 01  |....'...........| 

似乎中间的一个连续的区块丢失了。这可能是什么原因?

编辑:根据一些建议,我在in中添加了一个缺失的volatile,并切换到48位PIO,但问题仍然存在。

我发现了,我犯了两个非常微不足道的错误:首先,ins的代码不正确,正如Michael Petch指出的那样,它缺少一个volatile。此外,dest应具有类型T*:

template<typename T>
void ins(uint16_t port, uint32_t dest, uint32_t count)
{
static_assert(detail::is_uint_le32_t<T>());
T *dest_ptr = reinterpret_cast<T *>(dest);
asm volatile("rep ins%z2"
: "+D" (dest_ptr), "+c" (count), "=m" (*dest_ptr)
: "d" (port)
: "memory");
}

那么,关键的是,线路pa_dest += DISK_SECT_SIZE / 4是错误的。这应该是pa_dest += DISK_SECT_SIZE,因为ins读取整个扇区(128个双字(,而不仅仅是其中的四分之一

最新更新