IDEDiskDevice.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #include "IDEDiskDevice.h"
  2. #include "types.h"
  3. #include "Process.h"
  4. #include "StdLib.h"
  5. #include "IO.h"
  6. #include "Scheduler.h"
  7. #include "PIC.h"
  8. #include <Kernel/Lock.h>
  9. //#define DISK_DEBUG
  10. #define IRQ_FIXED_DISK 14
  11. #define IDE0_DATA 0x1F0
  12. #define IDE0_STATUS 0x1F7
  13. #define IDE0_COMMAND 0x1F7
  14. enum IDECommand : byte {
  15. IDENTIFY_DRIVE = 0xEC,
  16. READ_SECTORS = 0x21,
  17. WRITE_SECTORS = 0x30,
  18. };
  19. enum IDEStatus : byte {
  20. BUSY = (1 << 7),
  21. DRDY = (1 << 6),
  22. DF = (1 << 5),
  23. SRV = (1 << 4),
  24. DRQ = (1 << 3),
  25. CORR = (1 << 2),
  26. IDX = (1 << 1),
  27. ERR = (1 << 0),
  28. };
  29. Retained<IDEDiskDevice> IDEDiskDevice::create()
  30. {
  31. return adopt(*new IDEDiskDevice);
  32. }
  33. IDEDiskDevice::IDEDiskDevice()
  34. : IRQHandler(IRQ_FIXED_DISK)
  35. , m_lock("IDEDiskDevice")
  36. {
  37. initialize();
  38. }
  39. IDEDiskDevice::~IDEDiskDevice()
  40. {
  41. }
  42. const char* IDEDiskDevice::class_name() const
  43. {
  44. return "IDEDiskDevice";
  45. }
  46. unsigned IDEDiskDevice::block_size() const
  47. {
  48. return 512;
  49. }
  50. bool IDEDiskDevice::read_block(unsigned index, byte* out) const
  51. {
  52. return const_cast<IDEDiskDevice&>(*this).read_sectors(index, 1, out);
  53. }
  54. bool IDEDiskDevice::write_block(unsigned index, const byte* data)
  55. {
  56. return write_sectors(index, 1, data);
  57. }
  58. static void print_ide_status(byte status)
  59. {
  60. kprintf("DRQ=%u BUSY=%u DRDY=%u SRV=%u DF=%u CORR=%u IDX=%u ERR=%u\n",
  61. (status & DRQ) != 0,
  62. (status & BUSY) != 0,
  63. (status & DRDY) != 0,
  64. (status & SRV) != 0,
  65. (status & DF) != 0,
  66. (status & CORR) != 0,
  67. (status & IDX) != 0,
  68. (status & ERR) != 0);
  69. }
  70. bool IDEDiskDevice::wait_for_irq()
  71. {
  72. #ifdef DISK_DEBUG
  73. kprintf("disk: waiting for interrupt...\n");
  74. #endif
  75. // FIXME: Add timeout.
  76. while (!m_interrupted) {
  77. // FIXME: Put this process into a Blocked state instead, it's stupid to wake up just to check a flag.
  78. Scheduler::yield();
  79. }
  80. #ifdef DISK_DEBUG
  81. kprintf("disk: got interrupt!\n");
  82. #endif
  83. memory_barrier();
  84. return true;
  85. }
  86. void IDEDiskDevice::handle_irq()
  87. {
  88. byte status = IO::in8(0x1f7);
  89. if (status & ERR) {
  90. print_ide_status(status);
  91. m_device_error = IO::in8(0x1f1);
  92. kprintf("IDEDiskDevice: Error %b!\n", m_device_error);
  93. } else {
  94. m_device_error = 0;
  95. }
  96. #ifdef DISK_DEBUG
  97. kprintf("disk:interrupt: DRQ=%u BUSY=%u DRDY=%u\n", (status & DRQ) != 0, (status & BUSY) != 0, (status & DRDY) != 0);
  98. #endif
  99. m_interrupted = true;
  100. }
  101. void IDEDiskDevice::initialize()
  102. {
  103. #ifdef DISK_DEBUG
  104. byte status = IO::in8(IDE0_STATUS);
  105. kprintf("initial status: ");
  106. print_ide_status(status);
  107. #endif
  108. m_interrupted = false;
  109. while (IO::in8(IDE0_STATUS) & BUSY);
  110. enable_irq();
  111. IO::out8(0x1F6, 0xA0); // 0xB0 for 2nd device
  112. IO::out8(0x3F6, 0xA0); // 0xB0 for 2nd device
  113. IO::out8(IDE0_COMMAND, IDENTIFY_DRIVE);
  114. enable_irq();
  115. wait_for_irq();
  116. ByteBuffer wbuf = ByteBuffer::create_uninitialized(512);
  117. ByteBuffer bbuf = ByteBuffer::create_uninitialized(512);
  118. byte* b = bbuf.pointer();
  119. word* w = (word*)wbuf.pointer();
  120. const word* wbufbase = (word*)wbuf.pointer();
  121. for (dword i = 0; i < 256; ++i) {
  122. word data = IO::in16(IDE0_DATA);
  123. *(w++) = data;
  124. *(b++) = MSB(data);
  125. *(b++) = LSB(data);
  126. }
  127. // "Unpad" the device name string.
  128. for (dword i = 93; i > 54 && bbuf[i] == ' '; --i)
  129. bbuf[i] = 0;
  130. m_cylinders = wbufbase[1];
  131. m_heads = wbufbase[3];
  132. m_sectors_per_track = wbufbase[6];
  133. kprintf(
  134. "IDEDiskDevice: Master=\"%s\", C/H/Spt=%u/%u/%u\n",
  135. bbuf.pointer() + 54,
  136. m_cylinders,
  137. m_heads,
  138. m_sectors_per_track
  139. );
  140. }
  141. IDEDiskDevice::CHS IDEDiskDevice::lba_to_chs(dword lba) const
  142. {
  143. CHS chs;
  144. chs.cylinder = lba / (m_sectors_per_track * m_heads);
  145. chs.head = (lba / m_sectors_per_track) % m_heads;
  146. chs.sector = (lba % m_sectors_per_track) + 1;
  147. return chs;
  148. }
  149. bool IDEDiskDevice::read_sectors(dword start_sector, word count, byte* outbuf)
  150. {
  151. LOCKER(m_lock);
  152. #ifdef DISK_DEBUG
  153. dbgprintf("%s: Disk::read_sectors request (%u sector(s) @ %u)\n",
  154. current->process().name().characters(),
  155. count,
  156. start_sector);
  157. #endif
  158. disable_irq();
  159. auto chs = lba_to_chs(start_sector);
  160. while (IO::in8(IDE0_STATUS) & BUSY);
  161. #ifdef DISK_DEBUG
  162. kprintf("IDEDiskDevice: Reading %u sector(s) @ LBA %u (%u/%u/%u)\n", count, start_sector, chs.cylinder, chs.head, chs.sector);
  163. #endif
  164. IO::out8(0x1F2, count == 256 ? 0 : LSB(count));
  165. IO::out8(0x1F3, chs.sector);
  166. IO::out8(0x1F4, LSB(chs.cylinder));
  167. IO::out8(0x1F5, MSB(chs.cylinder));
  168. IO::out8(0x1F6, 0xA0 | chs.head); /* 0xB0 for 2nd device */
  169. IO::out8(0x3F6, 0x08);
  170. while (!(IO::in8(IDE0_STATUS) & DRDY));
  171. IO::out8(IDE0_COMMAND, READ_SECTORS);
  172. m_interrupted = false;
  173. enable_irq();
  174. wait_for_irq();
  175. if (m_device_error)
  176. return false;
  177. byte status = IO::in8(0x1f7);
  178. if (status & DRQ) {
  179. #ifdef DISK_DEBUG
  180. kprintf("Retrieving %u bytes (status=%b), outbuf=%p...\n", count * 512, status, outbuf);
  181. #endif
  182. for (dword i = 0; i < (count * 512); i += 2) {
  183. word w = IO::in16(IDE0_DATA);
  184. outbuf[i] = LSB(w);
  185. outbuf[i+1] = MSB(w);
  186. }
  187. }
  188. return true;
  189. }
  190. bool IDEDiskDevice::write_sectors(dword start_sector, word count, const byte* data)
  191. {
  192. LOCKER(m_lock);
  193. #ifdef DISK_DEBUG
  194. dbgprintf("%s(%u): IDEDiskDevice::write_sectors request (%u sector(s) @ %u)\n",
  195. current->process().name().characters(),
  196. current->pid(),
  197. count,
  198. start_sector);
  199. #endif
  200. disable_irq();
  201. auto chs = lba_to_chs(start_sector);
  202. while (IO::in8(IDE0_STATUS) & BUSY);
  203. //dbgprintf("IDEDiskDevice: Writing %u sector(s) @ LBA %u (%u/%u/%u)\n", count, start_sector, chs.cylinder, chs.head, chs.sector);
  204. IO::out8(0x1F2, count == 256 ? 0 : LSB(count));
  205. IO::out8(0x1F3, chs.sector);
  206. IO::out8(0x1F4, LSB(chs.cylinder));
  207. IO::out8(0x1F5, MSB(chs.cylinder));
  208. IO::out8(0x1F6, 0xA0 | chs.head); /* 0xB0 for 2nd device */
  209. IO::out8(0x3F6, 0x08);
  210. IO::out8(IDE0_COMMAND, WRITE_SECTORS);
  211. while (!(IO::in8(IDE0_STATUS) & DRQ));
  212. byte status = IO::in8(0x1f7);
  213. if (status & DRQ) {
  214. //dbgprintf("Sending %u bytes (status=%b), data=%p...\n", count * 512, status, data);
  215. auto* data_as_words = (const word*)data;
  216. for (dword i = 0; i < (count * 512) / 2; ++i) {
  217. IO::out16(IDE0_DATA, data_as_words[i]);
  218. }
  219. }
  220. m_interrupted = false;
  221. enable_irq();
  222. wait_for_irq();
  223. return !m_device_error;
  224. }