mbr.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. * install new master boot record boot code on PC disk.
  11. */
  12. #include <u.h>
  13. #include <libc.h>
  14. #include <disk.h>
  15. typedef struct {
  16. uint8_t active; /* active flag */
  17. uint8_t starth; /* starting head */
  18. uint8_t starts; /* starting sector */
  19. uint8_t startc; /* starting cylinder */
  20. uint8_t type; /* partition type */
  21. uint8_t endh; /* ending head */
  22. uint8_t ends; /* ending sector */
  23. uint8_t endc; /* ending cylinder */
  24. uint8_t lba[4]; /* starting LBA */
  25. uint8_t size[4]; /* size in sectors */
  26. } Tentry;
  27. enum {
  28. Toffset = 0x1BE, /* offset of partition table */
  29. Type9 = 0x39,
  30. };
  31. /*
  32. * Default boot block prints an error message and reboots.
  33. */
  34. static int ndefmbr = Toffset;
  35. static char defmbr[512] = {
  36. [0x000] = 0xEB, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  37. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  38. [0x03E] = 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
  39. 0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
  40. 0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
  41. 0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
  42. 0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
  43. 0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
  44. 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
  45. 0xC3, 'N', 'o', 't', ' ', 'a', ' ', 'b',
  46. 'o', 'o', 't', 'a', 'b', 'l', 'e', ' ',
  47. 'd', 'i', 's', 'c', ' ', 'o', 'r', ' ',
  48. 'd', 'i', 's', 'c', ' ', 'e', 'r', 'r',
  49. 'o', 'r', '\r', '\n', 'P', 'r', 'e', 's',
  50. 's', ' ', 'a', 'l', 'm', 'o', 's', 't',
  51. ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y',
  52. ' ', 't', 'o', ' ', 'r', 'e', 'b', 'o',
  53. 'o', 't', '.', '.', '.', 0x00, 0x00, 0x00,
  54. };
  55. void
  56. usage(void)
  57. {
  58. fprint(2, "usage: disk/mbr [-m mbrfile] disk\n");
  59. exits("usage");
  60. }
  61. void
  62. fatal(char *fmt, ...)
  63. {
  64. char err[ERRMAX];
  65. va_list arg;
  66. va_start(arg, fmt);
  67. vsnprint(err, ERRMAX, fmt, arg);
  68. va_end(arg);
  69. fprint(2, "mbr: %s\n", err);
  70. exits(err);
  71. }
  72. static void
  73. putle32(void* v, uint32_t i)
  74. {
  75. uint8_t *p;
  76. p = v;
  77. p[0] = i;
  78. p[1] = i>>8;
  79. p[2] = i>>16;
  80. p[3] = i>>24;
  81. }
  82. static void
  83. writechs(Disk *disk, uint8_t *p, int64_t lba)
  84. {
  85. int c, h, s;
  86. s = lba % disk->s;
  87. h = (lba / disk->s) % disk->h;
  88. c = lba / (disk->s * disk->h);
  89. if(c >= 1024) {
  90. c = 1023;
  91. h = disk->h - 1;
  92. s = disk->s - 1;
  93. }
  94. p[0] = h;
  95. p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0);
  96. p[2] = c;
  97. }
  98. static void
  99. wrtentry(Disk *disk, Tentry *tp, int type, uint32_t base, uint32_t lba,
  100. uint32_t end)
  101. {
  102. tp->active = 0x80; /* make this sole partition active */
  103. tp->type = type;
  104. writechs(disk, &tp->starth, lba);
  105. writechs(disk, &tp->endh, end-1);
  106. putle32(tp->lba, lba-base);
  107. putle32(tp->size, end-lba);
  108. }
  109. void
  110. main(int argc, char **argv)
  111. {
  112. Disk *disk;
  113. Tentry *tp;
  114. unsigned char *mbr, *buf;
  115. char *mbrfile;
  116. uint32_t secsize;
  117. int flag9, sysfd, nmbr;
  118. flag9 = 0;
  119. mbrfile = nil;
  120. ARGBEGIN {
  121. case '9':
  122. flag9 = 1;
  123. break;
  124. case 'm':
  125. mbrfile = EARGF(usage());
  126. break;
  127. default:
  128. usage();
  129. } ARGEND
  130. if(argc < 1)
  131. usage();
  132. disk = opendisk(argv[0], 0, 0);
  133. if(disk == nil)
  134. fatal("opendisk %s: %r", argv[0]);
  135. if(disk->type == Tfloppy)
  136. fatal("will not install mbr on floppy");
  137. /*
  138. * we need to cope with 4k-byte sectors on some newer disks.
  139. * we're only interested in 512 bytes of mbr, so
  140. * on 4k disks, rely on /dev/sd to read-modify-write.
  141. */
  142. secsize = 512;
  143. if(disk->secsize != secsize)
  144. fprint(2, "%s: sector size %lld not %ld, should be okay\n",
  145. argv0, disk->secsize, secsize);
  146. buf = malloc(secsize*(disk->s+1));
  147. mbr = malloc(secsize*disk->s);
  148. if(buf == nil || mbr == nil)
  149. fatal("out of memory");
  150. /*
  151. * Start with initial sector from disk.
  152. */
  153. if(seek(disk->fd, 0, 0) < 0)
  154. fatal("seek to boot sector: %r\n");
  155. if(read(disk->fd, mbr, secsize) != secsize)
  156. fatal("reading boot sector: %r");
  157. if(mbrfile == nil){
  158. nmbr = ndefmbr;
  159. memmove(mbr, defmbr, nmbr);
  160. } else {
  161. memset(buf, 0, secsize*disk->s);
  162. if((sysfd = open(mbrfile, OREAD)) < 0)
  163. fatal("open %s: %r", mbrfile);
  164. if((nmbr = read(sysfd, buf, secsize*(disk->s+1))) < 0)
  165. fatal("read %s: %r", mbrfile);
  166. if(nmbr > secsize*disk->s)
  167. fatal("master boot record too large %d > %d", nmbr, secsize*disk->s);
  168. if(nmbr < secsize)
  169. nmbr = secsize;
  170. close(sysfd);
  171. memmove(buf+Toffset, mbr+Toffset, secsize-Toffset);
  172. memmove(mbr, buf, nmbr);
  173. }
  174. if(flag9){
  175. tp = (Tentry*)(mbr+Toffset);
  176. memset(tp, 0, secsize-Toffset);
  177. wrtentry(disk, tp, Type9, 0, disk->s, disk->secs);
  178. }
  179. mbr[secsize-2] = 0x55;
  180. mbr[secsize-1] = 0xAA;
  181. nmbr = (nmbr+secsize-1)&~(secsize-1);
  182. if(seek(disk->wfd, 0, 0) < 0)
  183. fatal("seek to MBR sector: %r\n");
  184. if(write(disk->wfd, mbr, nmbr) != nmbr)
  185. fatal("writing MBR: %r");
  186. exits(0);
  187. }