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.

disk.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #include "etherboot.h"
  2. #include "disk.h"
  3. #undef disk_disable
  4. static int dummy(void *unused __unused)
  5. {
  6. return (0);
  7. }
  8. static unsigned char disk_buffer[DISK_BUFFER_SIZE];
  9. struct disk disk =
  10. {
  11. {
  12. 0, /* dev.disable */
  13. {
  14. 0,
  15. 0,
  16. PCI_BUS_TYPE,
  17. }, /* dev.devid */
  18. 0, /* index */
  19. 0, /* type */
  20. PROBE_FIRST, /* how_probe */
  21. PROBE_NONE, /* to_probe */
  22. 0, /* failsafe */
  23. 0, /* type_index */
  24. {}, /* state */
  25. },
  26. (int (*)(struct disk *, sector_t ))dummy, /* read */
  27. 0 - 1, /* drive */
  28. 0, /* hw_sector_size */
  29. 0, /* sectors_per_read */
  30. 0, /* bytes */
  31. 0, /* sectors */
  32. 0, /* sector */
  33. disk_buffer, /* buffer */
  34. 0, /* priv */
  35. 0, /* disk_offset */
  36. 0, /* direction */
  37. };
  38. static int disk_read(
  39. struct disk *disk, unsigned char *buffer, sector_t sector)
  40. {
  41. int result;
  42. sector_t base_sector;
  43. /* Note: I do not handle disk wrap around here! */
  44. /* Compute the start of the track cache */
  45. base_sector = sector;
  46. /* Support sectors_per_read > 1 only on small disks */
  47. if ((sizeof(sector_t) > sizeof(unsigned long)) &&
  48. (disk->sectors_per_read > 1)) {
  49. unsigned long offset;
  50. offset = ((unsigned long)sector) % disk->sectors_per_read;
  51. base_sector -= offset;
  52. }
  53. /* See if I need to update the track cache */
  54. if ((sector < disk->sector) ||
  55. sector >= disk->sector + (disk->bytes >> 9)) {
  56. twiddle();
  57. result = disk->read(disk, base_sector);
  58. if (result < 0)
  59. return result;
  60. }
  61. /* Service the request from the track cache */
  62. memcpy(buffer, disk->buffer + ((sector - base_sector)<<9), SECTOR_SIZE);
  63. return 0;
  64. }
  65. static int disk_read_sectors(
  66. struct disk *disk,
  67. unsigned char *buffer,
  68. sector_t base_sector, unsigned int sectors)
  69. {
  70. sector_t sector = 0;
  71. unsigned long offset;
  72. int result = 0;
  73. for(offset = 0; offset < sectors; offset++) {
  74. sector = base_sector + offset;
  75. if (sector >= disk->sectors) {
  76. sector -= disk->sectors;
  77. }
  78. result = disk_read(disk, buffer + (offset << 9), sector);
  79. if (result < 0)
  80. break;
  81. }
  82. if (result < 0) {
  83. printf("disk read error at 0x%lx\n", sector);
  84. }
  85. return result;
  86. }
  87. static os_download_t probe_buffer(unsigned char *buffer, unsigned int len,
  88. int increment, unsigned int offset, unsigned int *roffset)
  89. {
  90. os_download_t os_download;
  91. unsigned int end;
  92. end = 0;
  93. os_download = 0;
  94. if (increment > 0) {
  95. end = len - SECTOR_SIZE;
  96. }
  97. do {
  98. offset += increment;
  99. os_download = probe_image(buffer + offset, len - offset);
  100. } while(!os_download && (offset != end));
  101. *roffset = offset;
  102. return os_download;
  103. }
  104. static int load_image(
  105. struct disk *disk,
  106. unsigned char *buffer, unsigned int buf_sectors,
  107. sector_t block, unsigned int offset,
  108. os_download_t os_download)
  109. {
  110. sector_t skip_sectors;
  111. skip_sectors = 0;
  112. while(1) {
  113. skip_sectors = os_download(buffer + offset,
  114. (buf_sectors << 9) - offset, 0);
  115. block += skip_sectors + buf_sectors;
  116. if (block >= disk->sectors) {
  117. block -= disk->sectors;
  118. }
  119. offset = 0;
  120. buf_sectors = 1;
  121. if (disk_read_sectors(disk, buffer, block, 1) < 0) {
  122. return 0;
  123. }
  124. }
  125. return -1;
  126. }
  127. int disk_probe(struct dev *dev)
  128. {
  129. struct disk *disk = (struct disk *)dev;
  130. if (dev->how_probe == PROBE_NEXT) {
  131. disk->drive += 1;
  132. }
  133. return probe(dev);
  134. }
  135. int disk_load_configuration(struct dev *dev)
  136. {
  137. /* Start with the very simplest possible disk configuration */
  138. struct disk *disk = (struct disk *)dev;
  139. disk->direction = (dev->failsafe)?-1:1;
  140. disk->disk_offset = 0;
  141. return 0;
  142. }
  143. int disk_load(struct dev *dev)
  144. {
  145. struct disk *disk = (struct disk *)dev;
  146. /* 16K == 8K in either direction from the start of the disk */
  147. static unsigned char buffer[32*SECTOR_SIZE];
  148. os_download_t os_download;
  149. unsigned int offset;
  150. unsigned int len;
  151. unsigned int buf_sectors;
  152. volatile sector_t block;
  153. volatile int inc, increment;
  154. int i;
  155. int result;
  156. jmp_buf real_restart;
  157. printf("Searching for image...\n");
  158. result = 0;
  159. /* Only check for 16byte aligned images */
  160. increment = (disk->direction < 0)?-16:16;
  161. /* Load a buffer, and see if it contains the start of an image
  162. * we can boot from disk.
  163. */
  164. len = sizeof(buffer);
  165. buf_sectors = sizeof(buffer) / SECTOR_SIZE;
  166. inc = increment;
  167. block = (disk->disk_offset) >> 9;
  168. if (buf_sectors/2 > block) {
  169. block = (disk->sectors - (buf_sectors/2)) + block;
  170. }
  171. /* let probe buffer assume offset always needs to be incremented */
  172. offset = (len/2 + ((disk->disk_offset) & 0x1ff)) - inc;
  173. /* Catch longjmp so if this image fails to load, I start looking
  174. * for the next image where I left off looking for this image.
  175. */
  176. memcpy(&real_restart, &restart_etherboot, sizeof(jmp_buf));
  177. i = setjmp(restart_etherboot);
  178. if ((i != 0) && (i != -2)) {
  179. memcpy(&restart_etherboot, &real_restart, sizeof(jmp_buf));
  180. longjmp(restart_etherboot, i);
  181. }
  182. /* Read the canidate sectors into the buffer */
  183. if (disk_read_sectors(disk, buffer, block, buf_sectors) < 0) {
  184. result = -1;
  185. goto out;
  186. }
  187. if (inc == increment) {
  188. os_download = probe_buffer(buffer, len, inc, offset, &offset);
  189. if (os_download)
  190. goto load_image;
  191. inc = -inc;
  192. }
  193. os_download = probe_buffer(buffer, len, inc, offset, &offset);
  194. if (!os_download) {
  195. result = -1;
  196. goto out;
  197. }
  198. load_image:
  199. printf("Loading image...\n");
  200. result = load_image(disk, buffer, buf_sectors, block, offset, os_download);
  201. out:
  202. memcpy(&restart_etherboot, &real_restart, sizeof(jmp_buf));
  203. return result;
  204. }
  205. int url_file(const char *name,
  206. int (*fnc)(unsigned char *, unsigned int, unsigned int, int) __unused)
  207. {
  208. unsigned int drive;
  209. unsigned long disk_offset;
  210. int direction;
  211. int type;
  212. disk_offset = 0;
  213. direction = 1;
  214. if (memcmp(name, "disk", 4) == 0) {
  215. type = DISK_DRIVER;
  216. name += 4;
  217. }
  218. else if (memcmp(name, "floppy", 6) == 0) {
  219. type = FLOPPY_DRIVER;
  220. name += 6;
  221. }
  222. else {
  223. printf("Unknown device type\n");
  224. return 0;
  225. }
  226. drive = strtoul(name, &name, 10);
  227. if ((name[0] == '+') || (name[0] == '-')) {
  228. direction = (name[0] == '-')? -1 : 1;
  229. name++;
  230. disk_offset = strtoul(name, &name, 10);
  231. }
  232. if (name[0]) {
  233. printf("Junk '%s' at end of disk url\n", name);
  234. return 0;
  235. }
  236. memset(&disk, 0, sizeof(disk));
  237. disk.buffer = disk_buffer;
  238. disk.drive = 0;
  239. disk.dev.how_probe = PROBE_FIRST;
  240. disk.dev.type = type;
  241. do {
  242. disk_disable();
  243. disk.dev.how_probe = disk_probe(&disk.dev);
  244. if (disk.dev.how_probe == PROBE_FAILED) {
  245. printf("Not that many drives\n");
  246. return 0;
  247. }
  248. } while(disk.drive < drive);
  249. disk.direction = direction;
  250. disk.disk_offset = disk_offset;
  251. return disk_load(&disk.dev);
  252. }
  253. void disk_disable(void)
  254. {
  255. disable(&disk.dev);
  256. }