《操作系统》的实验代码。

214 lines
6.3 KiB

12 years ago
  1. #include <defs.h>
  2. #include <stdio.h>
  3. #include <trap.h>
  4. #include <picirq.h>
  5. #include <fs.h>
  6. #include <ide.h>
  7. #include <x86.h>
  8. #include <assert.h>
  9. #define ISA_DATA 0x00
  10. #define ISA_ERROR 0x01
  11. #define ISA_PRECOMP 0x01
  12. #define ISA_CTRL 0x02
  13. #define ISA_SECCNT 0x02
  14. #define ISA_SECTOR 0x03
  15. #define ISA_CYL_LO 0x04
  16. #define ISA_CYL_HI 0x05
  17. #define ISA_SDH 0x06
  18. #define ISA_COMMAND 0x07
  19. #define ISA_STATUS 0x07
  20. #define IDE_BSY 0x80
  21. #define IDE_DRDY 0x40
  22. #define IDE_DF 0x20
  23. #define IDE_DRQ 0x08
  24. #define IDE_ERR 0x01
  25. #define IDE_CMD_READ 0x20
  26. #define IDE_CMD_WRITE 0x30
  27. #define IDE_CMD_IDENTIFY 0xEC
  28. #define IDE_IDENT_SECTORS 20
  29. #define IDE_IDENT_MODEL 54
  30. #define IDE_IDENT_CAPABILITIES 98
  31. #define IDE_IDENT_CMDSETS 164
  32. #define IDE_IDENT_MAX_LBA 120
  33. #define IDE_IDENT_MAX_LBA_EXT 200
  34. #define IO_BASE0 0x1F0
  35. #define IO_BASE1 0x170
  36. #define IO_CTRL0 0x3F4
  37. #define IO_CTRL1 0x374
  38. #define MAX_IDE 4
  39. #define MAX_NSECS 128
  40. #define MAX_DISK_NSECS 0x10000000U
  41. #define VALID_IDE(ideno) (((ideno) >= 0) && ((ideno) < MAX_IDE) && (ide_devices[ideno].valid))
  42. static const struct {
  43. unsigned short base; // I/O Base
  44. unsigned short ctrl; // Control Base
  45. } channels[2] = {
  46. {IO_BASE0, IO_CTRL0},
  47. {IO_BASE1, IO_CTRL1},
  48. };
  49. #define IO_BASE(ideno) (channels[(ideno) >> 1].base)
  50. #define IO_CTRL(ideno) (channels[(ideno) >> 1].ctrl)
  51. static struct ide_device {
  52. unsigned char valid; // 0 or 1 (If Device Really Exists)
  53. unsigned int sets; // Commend Sets Supported
  54. unsigned int size; // Size in Sectors
  55. unsigned char model[41]; // Model in String
  56. } ide_devices[MAX_IDE];
  57. static int
  58. ide_wait_ready(unsigned short iobase, bool check_error) {
  59. int r;
  60. while ((r = inb(iobase + ISA_STATUS)) & IDE_BSY)
  61. /* nothing */;
  62. if (check_error && (r & (IDE_DF | IDE_ERR)) != 0) {
  63. return -1;
  64. }
  65. return 0;
  66. }
  67. void
  68. ide_init(void) {
  69. static_assert((SECTSIZE % 4) == 0);
  70. unsigned short ideno, iobase;
  71. for (ideno = 0; ideno < MAX_IDE; ideno ++) {
  72. /* assume that no device here */
  73. ide_devices[ideno].valid = 0;
  74. iobase = IO_BASE(ideno);
  75. /* wait device ready */
  76. ide_wait_ready(iobase, 0);
  77. /* step1: select drive */
  78. outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4));
  79. ide_wait_ready(iobase, 0);
  80. /* step2: send ATA identify command */
  81. outb(iobase + ISA_COMMAND, IDE_CMD_IDENTIFY);
  82. ide_wait_ready(iobase, 0);
  83. /* step3: polling */
  84. if (inb(iobase + ISA_STATUS) == 0 || ide_wait_ready(iobase, 1) != 0) {
  85. continue ;
  86. }
  87. /* device is ok */
  88. ide_devices[ideno].valid = 1;
  89. /* read identification space of the device */
  90. unsigned int buffer[128];
  91. insl(iobase + ISA_DATA, buffer, sizeof(buffer) / sizeof(unsigned int));
  92. unsigned char *ident = (unsigned char *)buffer;
  93. unsigned int sectors;
  94. unsigned int cmdsets = *(unsigned int *)(ident + IDE_IDENT_CMDSETS);
  95. /* device use 48-bits or 28-bits addressing */
  96. if (cmdsets & (1 << 26)) {
  97. sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA_EXT);
  98. }
  99. else {
  100. sectors = *(unsigned int *)(ident + IDE_IDENT_MAX_LBA);
  101. }
  102. ide_devices[ideno].sets = cmdsets;
  103. ide_devices[ideno].size = sectors;
  104. /* check if supports LBA */
  105. assert((*(unsigned short *)(ident + IDE_IDENT_CAPABILITIES) & 0x200) != 0);
  106. unsigned char *model = ide_devices[ideno].model, *data = ident + IDE_IDENT_MODEL;
  107. unsigned int i, length = 40;
  108. for (i = 0; i < length; i += 2) {
  109. model[i] = data[i + 1], model[i + 1] = data[i];
  110. }
  111. do {
  112. model[i] = '\0';
  113. } while (i -- > 0 && model[i] == ' ');
  114. cprintf("ide %d: %10u(sectors), '%s'.\n", ideno, ide_devices[ideno].size, ide_devices[ideno].model);
  115. }
  116. // enable ide interrupt
  117. pic_enable(IRQ_IDE1);
  118. pic_enable(IRQ_IDE2);
  119. }
  120. bool
  121. ide_device_valid(unsigned short ideno) {
  122. return VALID_IDE(ideno);
  123. }
  124. size_t
  125. ide_device_size(unsigned short ideno) {
  126. if (ide_device_valid(ideno)) {
  127. return ide_devices[ideno].size;
  128. }
  129. return 0;
  130. }
  131. int
  132. ide_read_secs(unsigned short ideno, uint32_t secno, void *dst, size_t nsecs) {
  133. assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
  134. assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
  135. unsigned short iobase = IO_BASE(ideno), ioctrl = IO_CTRL(ideno);
  136. ide_wait_ready(iobase, 0);
  137. // generate interrupt
  138. outb(ioctrl + ISA_CTRL, 0);
  139. outb(iobase + ISA_SECCNT, nsecs);
  140. outb(iobase + ISA_SECTOR, secno & 0xFF);
  141. outb(iobase + ISA_CYL_LO, (secno >> 8) & 0xFF);
  142. outb(iobase + ISA_CYL_HI, (secno >> 16) & 0xFF);
  143. outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | ((secno >> 24) & 0xF));
  144. outb(iobase + ISA_COMMAND, IDE_CMD_READ);
  145. int ret = 0;
  146. for (; nsecs > 0; nsecs --, dst += SECTSIZE) {
  147. if ((ret = ide_wait_ready(iobase, 1)) != 0) {
  148. goto out;
  149. }
  150. insl(iobase, dst, SECTSIZE / sizeof(uint32_t));
  151. }
  152. out:
  153. return ret;
  154. }
  155. int
  156. ide_write_secs(unsigned short ideno, uint32_t secno, const void *src, size_t nsecs) {
  157. assert(nsecs <= MAX_NSECS && VALID_IDE(ideno));
  158. assert(secno < MAX_DISK_NSECS && secno + nsecs <= MAX_DISK_NSECS);
  159. unsigned short iobase = IO_BASE(ideno), ioctrl = IO_CTRL(ideno);
  160. ide_wait_ready(iobase, 0);
  161. // generate interrupt
  162. outb(ioctrl + ISA_CTRL, 0);
  163. outb(iobase + ISA_SECCNT, nsecs);
  164. outb(iobase + ISA_SECTOR, secno & 0xFF);
  165. outb(iobase + ISA_CYL_LO, (secno >> 8) & 0xFF);
  166. outb(iobase + ISA_CYL_HI, (secno >> 16) & 0xFF);
  167. outb(iobase + ISA_SDH, 0xE0 | ((ideno & 1) << 4) | ((secno >> 24) & 0xF));
  168. outb(iobase + ISA_COMMAND, IDE_CMD_WRITE);
  169. int ret = 0;
  170. for (; nsecs > 0; nsecs --, src += SECTSIZE) {
  171. if ((ret = ide_wait_ready(iobase, 1)) != 0) {
  172. goto out;
  173. }
  174. outsl(iobase, src, SECTSIZE / sizeof(uint32_t));
  175. }
  176. out:
  177. return ret;
  178. }