《操作系统》的实验代码。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
3.8 KiB

12 years ago
  1. #include <defs.h>
  2. #include <mmu.h>
  3. #include <sem.h>
  4. #include <ide.h>
  5. #include <inode.h>
  6. #include <kmalloc.h>
  7. #include <dev.h>
  8. #include <vfs.h>
  9. #include <iobuf.h>
  10. #include <error.h>
  11. #include <assert.h>
  12. #define DISK0_BLKSIZE PGSIZE
  13. #define DISK0_BUFSIZE (4 * DISK0_BLKSIZE)
  14. #define DISK0_BLK_NSECT (DISK0_BLKSIZE / SECTSIZE)
  15. static char *disk0_buffer;
  16. static semaphore_t disk0_sem;
  17. static void
  18. lock_disk0(void) {
  19. down(&(disk0_sem));
  20. }
  21. static void
  22. unlock_disk0(void) {
  23. up(&(disk0_sem));
  24. }
  25. static int
  26. disk0_open(struct device *dev, uint32_t open_flags) {
  27. return 0;
  28. }
  29. static int
  30. disk0_close(struct device *dev) {
  31. return 0;
  32. }
  33. static void
  34. disk0_read_blks_nolock(uint32_t blkno, uint32_t nblks) {
  35. int ret;
  36. uint32_t sectno = blkno * DISK0_BLK_NSECT, nsecs = nblks * DISK0_BLK_NSECT;
  37. if ((ret = ide_read_secs(DISK0_DEV_NO, sectno, disk0_buffer, nsecs)) != 0) {
  38. panic("disk0: read blkno = %d (sectno = %d), nblks = %d (nsecs = %d): 0x%08x.\n",
  39. blkno, sectno, nblks, nsecs, ret);
  40. }
  41. }
  42. static void
  43. disk0_write_blks_nolock(uint32_t blkno, uint32_t nblks) {
  44. int ret;
  45. uint32_t sectno = blkno * DISK0_BLK_NSECT, nsecs = nblks * DISK0_BLK_NSECT;
  46. if ((ret = ide_write_secs(DISK0_DEV_NO, sectno, disk0_buffer, nsecs)) != 0) {
  47. panic("disk0: write blkno = %d (sectno = %d), nblks = %d (nsecs = %d): 0x%08x.\n",
  48. blkno, sectno, nblks, nsecs, ret);
  49. }
  50. }
  51. static int
  52. disk0_io(struct device *dev, struct iobuf *iob, bool write) {
  53. off_t offset = iob->io_offset;
  54. size_t resid = iob->io_resid;
  55. uint32_t blkno = offset / DISK0_BLKSIZE;
  56. uint32_t nblks = resid / DISK0_BLKSIZE;
  57. /* don't allow I/O that isn't block-aligned */
  58. if ((offset % DISK0_BLKSIZE) != 0 || (resid % DISK0_BLKSIZE) != 0) {
  59. return -E_INVAL;
  60. }
  61. /* don't allow I/O past the end of disk0 */
  62. if (blkno + nblks > dev->d_blocks) {
  63. return -E_INVAL;
  64. }
  65. /* read/write nothing ? */
  66. if (nblks == 0) {
  67. return 0;
  68. }
  69. lock_disk0();
  70. while (resid != 0) {
  71. size_t copied, alen = DISK0_BUFSIZE;
  72. if (write) {
  73. iobuf_move(iob, disk0_buffer, alen, 0, &copied);
  74. assert(copied != 0 && copied <= resid && copied % DISK0_BLKSIZE == 0);
  75. nblks = copied / DISK0_BLKSIZE;
  76. disk0_write_blks_nolock(blkno, nblks);
  77. }
  78. else {
  79. if (alen > resid) {
  80. alen = resid;
  81. }
  82. nblks = alen / DISK0_BLKSIZE;
  83. disk0_read_blks_nolock(blkno, nblks);
  84. iobuf_move(iob, disk0_buffer, alen, 1, &copied);
  85. assert(copied == alen && copied % DISK0_BLKSIZE == 0);
  86. }
  87. resid -= copied, blkno += nblks;
  88. }
  89. unlock_disk0();
  90. return 0;
  91. }
  92. static int
  93. disk0_ioctl(struct device *dev, int op, void *data) {
  94. return -E_UNIMP;
  95. }
  96. static void
  97. disk0_device_init(struct device *dev) {
  98. static_assert(DISK0_BLKSIZE % SECTSIZE == 0);
  99. if (!ide_device_valid(DISK0_DEV_NO)) {
  100. panic("disk0 device isn't available.\n");
  101. }
  102. dev->d_blocks = ide_device_size(DISK0_DEV_NO) / DISK0_BLK_NSECT;
  103. dev->d_blocksize = DISK0_BLKSIZE;
  104. dev->d_open = disk0_open;
  105. dev->d_close = disk0_close;
  106. dev->d_io = disk0_io;
  107. dev->d_ioctl = disk0_ioctl;
  108. sem_init(&(disk0_sem), 1);
  109. static_assert(DISK0_BUFSIZE % DISK0_BLKSIZE == 0);
  110. if ((disk0_buffer = kmalloc(DISK0_BUFSIZE)) == NULL) {
  111. panic("disk0 alloc buffer failed.\n");
  112. }
  113. }
  114. void
  115. dev_init_disk0(void) {
  116. struct inode *node;
  117. if ((node = dev_create_inode()) == NULL) {
  118. panic("disk0: dev_create_node.\n");
  119. }
  120. disk0_device_init(vop_info(node, device));
  121. int ret;
  122. if ((ret = vfs_add_dev("disk0", node, 1)) != 0) {
  123. panic("disk0: vfs_add_dev: %e.\n", ret);
  124. }
  125. }