mbr.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /* Copyright (C) 2013 by John Cronin <jncronin@tysos.org>
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. * The above copyright notice and this permission notice shall be included in
  10. * all copies or substantial portions of the Software.
  11. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. * THE SOFTWARE.
  18. */
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include "block.h"
  24. #include "vfs.h"
  25. #include "util.h"
  26. #define MBR_DEBUG
  27. // Code for interpreting an mbr
  28. struct mbr_block_dev {
  29. struct block_device bd;
  30. struct block_device *parent;
  31. int part_no;
  32. uint32_t start_block;
  33. uint32_t blocks;
  34. uint8_t part_id;
  35. };
  36. static char driver_name[] = "mbr";
  37. static int mbr_read(struct block_device *, uint8_t *buf, size_t buf_size, uint32_t starting_block);
  38. static int mbr_write(struct block_device *, uint8_t *buf, size_t buf_size, uint32_t starting_block);
  39. int read_mbr(struct block_device *parent, struct block_device ***partitions, int *part_count)
  40. {
  41. (void)partitions;
  42. (void)part_count;
  43. (void)driver_name;
  44. /* Check the validity of the parent device */
  45. if(parent == (void*)0)
  46. {
  47. printf("MBR: invalid parent device\r\n");
  48. return -1;
  49. }
  50. /* Read the first 512 bytes */
  51. uint8_t *block_0 = (uint8_t *)malloc(512);
  52. if(block_0 == NULL)
  53. return -1;
  54. #ifdef MBR_DEBUG
  55. printf("MBR: reading block 0 from device %s\r\n", parent->device_name);
  56. #endif
  57. int ret = block_read(parent, block_0, 512, 0);
  58. if(ret < 0)
  59. {
  60. printf("MBR: block_read failed (%i)\r\n", ret);
  61. free(block_0);
  62. return ret;
  63. }
  64. if(ret != 512)
  65. {
  66. printf("MBR: unable to read first 512 bytes of device %s, only %d bytes read\r\n",
  67. parent->device_name, ret);
  68. free(block_0);
  69. return -1;
  70. }
  71. /* Check the MBR signature */
  72. if((block_0[0x1fe] != 0x55) || (block_0[0x1ff] != 0xaa))
  73. {
  74. printf("MBR: no valid mbr signature on device %s (bytes are %x %x)\r\n",
  75. parent->device_name, block_0[0x1fe], block_0[0x1ff]);
  76. free(block_0);
  77. return -1;
  78. }
  79. printf("MBR: found valid MBR on device %s\r\n", parent->device_name);
  80. #ifdef MBR_DEBUG
  81. /* Dump the first sector */
  82. printf("MBR: first sector:");
  83. for(int dump_idx = 0; dump_idx < 512; dump_idx++)
  84. {
  85. if((dump_idx & 0xf) == 0)
  86. printf("\r\n%03x: ", dump_idx);
  87. printf("%02x ", block_0[dump_idx]);
  88. }
  89. printf("\r\n");
  90. #endif
  91. // If parent block size is not 512, we have to coerce start_block
  92. // and blocks to fit
  93. if(parent->block_size < 512)
  94. {
  95. // We do not support parent device block sizes < 512
  96. printf("MBR: parent block device is too small (%i)\r\n", parent->block_size);
  97. free(block_0);
  98. return -1;
  99. }
  100. uint32_t block_size_adjust = parent->block_size / 512;
  101. if(parent->block_size % 512)
  102. {
  103. // We do not support parent device block sizes that are not a
  104. // multiple of 512
  105. printf("MBR: parent block size is not a multiple of 512 (%i)\r\n",
  106. parent->block_size);
  107. free(block_0);
  108. return -1;
  109. }
  110. #ifdef MBR_DEBUG
  111. if(block_size_adjust > 1)
  112. {
  113. printf("MBR: block_size_adjust: %i\r\n", block_size_adjust);
  114. }
  115. #endif
  116. /* Load the partitions */
  117. struct block_device **parts =
  118. (struct block_device **)malloc(4 * sizeof(struct block_device *));
  119. int cur_p = 0;
  120. for(int i = 0; i < 4; i++)
  121. {
  122. int p_offset = 0x1be + (i * 0x10);
  123. if(block_0[p_offset + 4] != 0x00)
  124. {
  125. // Valid partition
  126. struct mbr_block_dev *d =
  127. (struct mbr_block_dev *)malloc(sizeof(struct mbr_block_dev));
  128. memset(d, 0, sizeof(struct mbr_block_dev));
  129. d->bd.driver_name = driver_name;
  130. char *dev_name = (char *)malloc(strlen(parent->device_name) + 3);
  131. strcpy(dev_name, parent->device_name);
  132. dev_name[strlen(parent->device_name)] = '_';
  133. dev_name[strlen(parent->device_name) + 1] = '0' + i;
  134. dev_name[strlen(parent->device_name) + 2] = 0;
  135. d->bd.device_name = dev_name;
  136. d->bd.device_id = (uint8_t *)malloc(1);
  137. d->bd.device_id[0] = i;
  138. d->bd.dev_id_len = 1;
  139. d->bd.read = mbr_read;
  140. if(parent->write)
  141. d->bd.write = mbr_write;
  142. d->bd.block_size = parent->block_size;
  143. d->bd.supports_multiple_block_read = parent->supports_multiple_block_read;
  144. d->bd.supports_multiple_block_write = parent->supports_multiple_block_write;
  145. d->part_no = i;
  146. d->part_id = block_0[p_offset + 4];
  147. d->start_block = read_word(block_0, p_offset + 8);
  148. d->blocks = read_word(block_0, p_offset + 12);
  149. d->parent = parent;
  150. // Adjust start_block and blocks to the parent block size
  151. if(d->start_block % block_size_adjust)
  152. {
  153. printf("MBR: partition number %i does not start on a block "
  154. "boundary (%i).\r\n", d->part_no, d->start_block);
  155. return -1;
  156. }
  157. d->start_block /= block_size_adjust;
  158. if(d->blocks % block_size_adjust)
  159. {
  160. printf("MBR: partition number %i does not have a length "
  161. "that is an exact multiple of the block length (%i).\r\n",
  162. d->part_no, d->start_block);
  163. return -1;
  164. }
  165. d->blocks /= block_size_adjust;
  166. d->bd.num_blocks = d->blocks;
  167. parts[cur_p++] = (struct block_device *)d;
  168. #ifdef MBR_DEBUG
  169. printf("MBR: partition number %i (%s) of type %x, start sector %u, "
  170. "sector count %u, p_offset %03x\r\n",
  171. d->part_no, d->bd.device_name, d->part_id,
  172. d->start_block, d->blocks, p_offset);
  173. #endif
  174. // Register the fs
  175. register_fs((struct block_device *)d, d->part_id);
  176. }
  177. }
  178. if (NULL != partitions)
  179. *partitions = parts;
  180. else
  181. free(parts);
  182. if (NULL != part_count)
  183. *part_count = cur_p;
  184. printf("MBR: found total of %i partition(s)\r\n", cur_p);
  185. free(block_0);
  186. return 0;
  187. }
  188. int mbr_read(struct block_device *dev, uint8_t *buf, size_t buf_size, uint32_t starting_block)
  189. {
  190. struct block_device *parent = ((struct mbr_block_dev *)dev)->parent;
  191. return parent->read(parent, buf, buf_size,
  192. starting_block + ((struct mbr_block_dev *)dev)->start_block);
  193. }
  194. int mbr_write(struct block_device *dev, uint8_t *buf, size_t buf_size, uint32_t starting_block)
  195. {
  196. struct block_device *parent = ((struct mbr_block_dev *)dev)->parent;
  197. return parent->write(parent, buf, buf_size,
  198. starting_block + ((struct mbr_block_dev *)dev)->start_block);
  199. }