ata.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include <asm/port_io.h>
  2. #include <fs/fat.hpp>
  3. #include <kernel/hw/ata.hpp>
  4. #include <kernel/stdio.h>
  5. #include <kernel/syscall.hpp>
  6. #include <kernel/tty.h>
  7. #include <kernel/vfs.hpp>
  8. #include <types/allocator.hpp>
  9. #include <types/status.h>
  10. #include <types/stdint.h>
  11. hw::ata::ata(port_id_t p)
  12. : data(p)
  13. , error(p + 1)
  14. , feats(p + 1)
  15. , count(p + 2)
  16. , lbalo(p + 3)
  17. , lbami(p + 4)
  18. , lbahi(p + 5)
  19. , drive(p + 6)
  20. , stats(p + 7)
  21. , comms(p + 7)
  22. , slave_flag(0x00)
  23. {
  24. }
  25. hw::ata::stat_t hw::ata::status(void) const
  26. {
  27. return hw::ata::stat_t { *stats };
  28. }
  29. bool hw::ata::identify(void) const
  30. {
  31. char buf[512] {};
  32. drive = 0xa0 | slave_flag;
  33. count = 0;
  34. lbalo = 0;
  35. lbami = 0;
  36. lbahi = 0;
  37. comms = 0xec;
  38. stat_t stat {};
  39. while ((stat = status()).in.bsy)
  40. ;
  41. if (stat.in.err)
  42. return false;
  43. read_data(buf, 512);
  44. if (!status().in.rdy)
  45. return false;
  46. return true;
  47. }
  48. int hw::ata::select(bool master)
  49. {
  50. if (master)
  51. slave_flag = 0x00;
  52. else
  53. slave_flag = 0x10;
  54. drive = 0xe0 | slave_flag;
  55. return GB_OK;
  56. }
  57. size_t hw::ata::read_data(char* buf, size_t n) const
  58. {
  59. size_t orig_n = n;
  60. n /= 2;
  61. while (status().in.drq && n--) {
  62. *(uint16_t*)buf = *data;
  63. buf += sizeof(uint16_t);
  64. }
  65. return orig_n - n * 2;
  66. }
  67. size_t hw::ata::write_data(const char* buf, size_t n) const
  68. {
  69. size_t orig_n = n;
  70. n /= 2;
  71. while (status().in.drq && n--) {
  72. data = *(uint16_t*)buf;
  73. buf += sizeof(uint16_t);
  74. }
  75. return orig_n - n * 2;
  76. }
  77. int hw::ata::read_sector(char* buf, uint32_t lba_low, uint16_t lba_high) const
  78. {
  79. count = 0x00; // HIGH BYTE
  80. lbalo = (lba_low >> 24) & 0xff;
  81. lbami = lba_high & 0xff;
  82. lbahi = (lba_high >> 8) & 0xff;
  83. count = 0x01; // LOW BYTE
  84. lbalo = lba_low & 0xff;
  85. lbami = (lba_low >> 8) & 0xff;
  86. lbahi = (lba_low >> 16) & 0xff;
  87. comms = 0x24; // READ SECTORS EXT
  88. while (status().in.bsy)
  89. ;
  90. if (status().in.drq)
  91. read_data(buf, 512);
  92. return GB_OK;
  93. }
  94. int hw::ata::write_sector(const char* buf, uint32_t lba_low, uint16_t lba_high) const
  95. {
  96. count = 0x00; // HIGH BYTE
  97. lbalo = (lba_low >> 24) & 0xff;
  98. lbami = lba_high & 0xff;
  99. lbahi = (lba_high >> 8) & 0xff;
  100. count = 0x01; // LOW BYTE
  101. lbalo = lba_low & 0xff;
  102. lbami = (lba_low >> 8) & 0xff;
  103. lbahi = (lba_low >> 16) & 0xff;
  104. comms = 0x24; // READ SECTORS EXT
  105. while (status().in.bsy)
  106. ;
  107. if (status().in.drq)
  108. write_data(buf, 512);
  109. return GB_OK;
  110. }
  111. static hw::ata* ata_pri;
  112. static hw::ata* ata_sec;
  113. constexpr hw::ata** p_ata_pri = &ata_pri;
  114. constexpr hw::ata** p_ata_sec = &ata_sec;
  115. // data1: offset sectors
  116. // data2: limit sectors
  117. template <hw::ata** ata_bus>
  118. size_t _ata_read(fs::special_node* sn, char* buf, size_t buf_size, size_t offset, size_t n)
  119. {
  120. // TODO: check buf_size
  121. char b[512] {};
  122. char* orig_buf = buf;
  123. size_t start = sn->data1 + offset / 512;
  124. size_t end = sn->data1 + (offset + n + 511) / 512;
  125. if (end > sn->data1 + sn->data2)
  126. end = sn->data1 + sn->data2;
  127. offset %= 512;
  128. for (size_t i = start; i < end; ++i) {
  129. (void)(*ata_bus)->read_sector(b, i, 0);
  130. size_t to_copy = 0;
  131. if (offset)
  132. to_copy = 512 - offset;
  133. else
  134. to_copy = n > 512 ? 512 : n;
  135. memcpy(buf, b + offset, to_copy);
  136. offset = 0;
  137. buf += to_copy;
  138. n -= to_copy;
  139. }
  140. return buf - orig_buf;
  141. }
  142. struct PACKED mbr_part_entry {
  143. uint8_t attr;
  144. uint8_t chs_start[3];
  145. uint8_t type;
  146. uint8_t chs_end[3];
  147. uint32_t lba_start;
  148. uint32_t cnt;
  149. };
  150. struct PACKED mbr {
  151. uint8_t code[440];
  152. uint32_t signature;
  153. uint16_t reserved;
  154. struct mbr_part_entry parts[4];
  155. uint16_t magic;
  156. };
  157. static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t minor)
  158. {
  159. struct mbr hda_mbr { };
  160. auto* dev = fs::vfs_open("/dev");
  161. fs::vfs_read(drive, (char*)&hda_mbr, 512, 0, 512);
  162. for (const auto& part : hda_mbr.parts) {
  163. if (!part.type)
  164. continue;
  165. fs::register_special_block(major, minor++,
  166. _ata_read<p_ata_pri>,
  167. nullptr,
  168. part.lba_start, part.cnt);
  169. fs::vfs_mknode(dev, "hda1", { .in { .major = 2, .minor = 1 } });
  170. }
  171. }
  172. // data: void (*func_to_call_next)(void)
  173. void NORETURN hw::init_ata(void* data)
  174. {
  175. if (!data)
  176. syscall(0x03);
  177. ata_pri = types::kernel_allocator_new<ata>(ATA_PRIMARY_BUS_BASE);
  178. if (ata_pri->identify())
  179. ata_pri->select(true);
  180. ata_sec = types::kernel_allocator_new<ata>(ATA_SECONDARY_BUS_BASE);
  181. if (ata_pri->identify())
  182. ata_pri->select(true);
  183. // data1: offset sectors
  184. // data2: limit sectors
  185. fs::register_special_block(
  186. 2, 0,
  187. _ata_read<p_ata_pri>,
  188. nullptr,
  189. 0,
  190. 0xffffffff);
  191. // data1: offset sectors
  192. // data2: limit sectors
  193. fs::register_special_block(
  194. 2, 8,
  195. _ata_read<p_ata_sec>,
  196. nullptr,
  197. 0,
  198. 0xffffffff);
  199. auto* hda = fs::vfs_open("/dev/hda");
  200. mbr_part_probe(hda->ind, 2, 1);
  201. // noreturn
  202. ((void (*)(void))data)();
  203. for (;;)
  204. syscall(0x03);
  205. }