ata.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #include <asm/port_io.h>
  2. #include <kernel/hw/ata.hpp>
  3. #include <kernel/stdio.h>
  4. #include <kernel/syscall.hpp>
  5. #include <kernel/tty.h>
  6. #include <kernel/vfs.h>
  7. #include <types/allocator.hpp>
  8. #include <types/status.h>
  9. #include <types/stdint.h>
  10. hw::ata::ata(port_id_t p)
  11. : data(p)
  12. , error(p + 1)
  13. , feats(p + 1)
  14. , count(p + 2)
  15. , lbalo(p + 3)
  16. , lbami(p + 4)
  17. , lbahi(p + 5)
  18. , drive(p + 6)
  19. , stats(p + 7)
  20. , comms(p + 7)
  21. , slave_flag(0x00)
  22. {
  23. }
  24. hw::ata::stat_t hw::ata::status(void) const
  25. {
  26. return hw::ata::stat_t { *stats };
  27. }
  28. bool hw::ata::identify(void) const
  29. {
  30. char buf[512] {};
  31. drive = 0xa0 | slave_flag;
  32. count = 0;
  33. lbalo = 0;
  34. lbami = 0;
  35. lbahi = 0;
  36. comms = 0xec;
  37. stat_t stat {};
  38. while ((stat = status()).in.bsy)
  39. ;
  40. if (stat.in.err)
  41. return false;
  42. read_data(buf, 512);
  43. if (!status().in.rdy)
  44. return false;
  45. return true;
  46. }
  47. int hw::ata::select(bool master)
  48. {
  49. if (master)
  50. slave_flag = 0x00;
  51. else
  52. slave_flag = 0x10;
  53. drive = 0xe0 | slave_flag;
  54. return GB_OK;
  55. }
  56. size_t hw::ata::read_data(char* buf, size_t n) const
  57. {
  58. size_t orig_n = n;
  59. n /= 2;
  60. while (status().in.drq && n--) {
  61. *(uint16_t*)buf = *data;
  62. buf += sizeof(uint16_t);
  63. }
  64. return orig_n - n * 2;
  65. }
  66. size_t hw::ata::write_data(const char* buf, size_t n) const
  67. {
  68. size_t orig_n = n;
  69. n /= 2;
  70. while (status().in.drq && n--) {
  71. data = *(uint16_t*)buf;
  72. buf += sizeof(uint16_t);
  73. }
  74. return orig_n - n * 2;
  75. }
  76. int hw::ata::read_sector(char* buf, uint32_t lba_low, uint16_t lba_high) const
  77. {
  78. count = 0x00; // HIGH BYTE
  79. lbalo = (lba_low >> 24) & 0xff;
  80. lbami = lba_high & 0xff;
  81. lbahi = (lba_high >> 8) & 0xff;
  82. count = 0x01; // LOW BYTE
  83. lbalo = lba_low & 0xff;
  84. lbami = (lba_low >> 8) & 0xff;
  85. lbahi = (lba_low >> 16) & 0xff;
  86. comms = 0x24; // READ SECTORS EXT
  87. while (status().in.bsy)
  88. ;
  89. if (status().in.drq)
  90. read_data(buf, 512);
  91. return GB_OK;
  92. }
  93. int hw::ata::write_sector(const char* buf, uint32_t lba_low, uint16_t lba_high) const
  94. {
  95. count = 0x00; // HIGH BYTE
  96. lbalo = (lba_low >> 24) & 0xff;
  97. lbami = lba_high & 0xff;
  98. lbahi = (lba_high >> 8) & 0xff;
  99. count = 0x01; // LOW BYTE
  100. lbalo = lba_low & 0xff;
  101. lbami = (lba_low >> 8) & 0xff;
  102. lbahi = (lba_low >> 16) & 0xff;
  103. comms = 0x24; // READ SECTORS EXT
  104. while (status().in.bsy)
  105. ;
  106. if (status().in.drq)
  107. write_data(buf, 512);
  108. return GB_OK;
  109. }
  110. static hw::ata* ata_pri;
  111. void hw::init_ata(void* data)
  112. {
  113. if (data != nullptr)
  114. syscall(0x03);
  115. ata_pri = types::kernel_allocator_new<ata>(ATA_PRIMARY_BUS_BASE);
  116. ata_pri->identify();
  117. ata_pri->select(true);
  118. register_special_block(
  119. 2, 0,
  120. [](char* buf, size_t buf_size, size_t offset, size_t n) -> size_t {
  121. // TODO: check buf_size
  122. char b[512] {};
  123. char* orig_buf = buf;
  124. size_t start = offset / 512;
  125. size_t end = (offset + n + 511) / 512;
  126. for (size_t i = start; i < end; ++i) {
  127. ata_pri->read_sector(b, i, 0);
  128. size_t to_copy = 0;
  129. if (offset)
  130. to_copy = 512 - offset;
  131. else
  132. to_copy = n > 512 ? 512 : n;
  133. memcpy(buf, b + offset, to_copy);
  134. offset = 0;
  135. buf += to_copy;
  136. n -= to_copy;
  137. }
  138. return buf - orig_buf;
  139. },
  140. [](const char* buf, size_t offset, size_t n) -> size_t {
  141. syscall(0x03);
  142. return n;
  143. });
  144. auto* hda = vfs_open("/dev/hda");
  145. char buf[512] {};
  146. vfs_read(hda, buf, 512, 1, 512);
  147. vfs_write(hda, buf, 1, 512);
  148. }