Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
85 views
in Technique[技术] by (71.8m points)

c++ - ATA disk driver "skipping" chunk of memory

I'm trying to write a simple 32 bit x86 operating system and I have an issue with my ATA disk driver code.

I have written the following C++ class whose function read_sects_pio28 should read sect_count disc sectors, starting at offset sect_offs, to physical address 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))
      ;
  }
};

I want to use this this function to load the executable ELF segment of my kernel, which is currently only 688 bytes large, to address 0x100000. On disk, the segment starts at 0x1800 and so read_sects_pio28 is called with pa_dest=0x10000, sect_offs=12, sect_count=2 (I have verified that this is actually the case using a debugger).

But this seems to only sort of work. Here is what the segment looks like on disk:

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  |[email protected]|
00001960  08 8b 18 8b 45 08 0f b7  40 04 8d 48 01 8b 55 08  |[email protected].|
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  |[email protected]..|
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  |....'...........|

And here is what is actually loaded into memory:

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  |....'...........| 

It seems like a contiguous chunk in the middle is missing. What could be the reason for this?

EDIT: following some suggestions I have added a missing volatile in in an switched to 48 bit PIO, but the issue persists.

question from:https://stackoverflow.com/questions/65601995/ata-disk-driver-skipping-chunk-of-memory

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I figured it out, I have made two pretty trivial errors: first the code for ins is incorrect, as Michael Petch pointed out it was missing a volatile. Also, dest should have type 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");
}

Then, critically, the line pa_dest += DISK_SECT_SIZE / 4 is wrong. This should be pa_dest += DISK_SECT_SIZE since ins reads a whole sector (128 double words) and not just a quarter of it.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...