17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * install new master boot record boot code on PC disk.
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #include <u.h>
67dd7cddfSDavid du Colombier #include <libc.h>
77dd7cddfSDavid du Colombier #include <disk.h>
87dd7cddfSDavid du Colombier
939734e7eSDavid du Colombier typedef struct {
1039734e7eSDavid du Colombier uchar active; /* active flag */
1139734e7eSDavid du Colombier uchar starth; /* starting head */
1239734e7eSDavid du Colombier uchar starts; /* starting sector */
1339734e7eSDavid du Colombier uchar startc; /* starting cylinder */
1439734e7eSDavid du Colombier uchar type; /* partition type */
1539734e7eSDavid du Colombier uchar endh; /* ending head */
1639734e7eSDavid du Colombier uchar ends; /* ending sector */
1739734e7eSDavid du Colombier uchar endc; /* ending cylinder */
1839734e7eSDavid du Colombier uchar lba[4]; /* starting LBA */
1939734e7eSDavid du Colombier uchar size[4]; /* size in sectors */
2039734e7eSDavid du Colombier } Tentry;
2139734e7eSDavid du Colombier
227dd7cddfSDavid du Colombier enum {
2339734e7eSDavid du Colombier Toffset = 0x1BE, /* offset of partition table */
2439734e7eSDavid du Colombier
2539734e7eSDavid du Colombier Type9 = 0x39,
267dd7cddfSDavid du Colombier };
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier /*
297dd7cddfSDavid du Colombier * Default boot block prints an error message and reboots.
307dd7cddfSDavid du Colombier */
317dd7cddfSDavid du Colombier static int ndefmbr = Toffset;
327dd7cddfSDavid du Colombier static char defmbr[512] = {
337dd7cddfSDavid du Colombier [0x000] 0xEB, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
347dd7cddfSDavid du Colombier 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357dd7cddfSDavid du Colombier [0x03E] 0xFA, 0xFC, 0x8C, 0xC8, 0x8E, 0xD8, 0x8E, 0xD0,
367dd7cddfSDavid du Colombier 0xBC, 0x00, 0x7C, 0xBE, 0x77, 0x7C, 0xE8, 0x19,
377dd7cddfSDavid du Colombier 0x00, 0x33, 0xC0, 0xCD, 0x16, 0xBB, 0x40, 0x00,
387dd7cddfSDavid du Colombier 0x8E, 0xC3, 0xBB, 0x72, 0x00, 0xB8, 0x34, 0x12,
397dd7cddfSDavid du Colombier 0x26, 0x89, 0x07, 0xEA, 0x00, 0x00, 0xFF, 0xFF,
407dd7cddfSDavid du Colombier 0xEB, 0xD6, 0xAC, 0x0A, 0xC0, 0x74, 0x09, 0xB4,
417dd7cddfSDavid du Colombier 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2,
427dd7cddfSDavid du Colombier 0xC3, 'N', 'o', 't', ' ', 'a', ' ', 'b',
437dd7cddfSDavid du Colombier 'o', 'o', 't', 'a', 'b', 'l', 'e', ' ',
447dd7cddfSDavid du Colombier 'd', 'i', 's', 'c', ' ', 'o', 'r', ' ',
457dd7cddfSDavid du Colombier 'd', 'i', 's', 'c', ' ', 'e', 'r', 'r',
467dd7cddfSDavid du Colombier 'o', 'r', '\r', '\n', 'P', 'r', 'e', 's',
477dd7cddfSDavid du Colombier 's', ' ', 'a', 'l', 'm', 'o', 's', 't',
487dd7cddfSDavid du Colombier ' ', 'a', 'n', 'y', ' ', 'k', 'e', 'y',
497dd7cddfSDavid du Colombier ' ', 't', 'o', ' ', 'r', 'e', 'b', 'o',
507dd7cddfSDavid du Colombier 'o', 't', '.', '.', '.', 0x00, 0x00, 0x00,
517dd7cddfSDavid du Colombier };
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier void
usage(void)547dd7cddfSDavid du Colombier usage(void)
557dd7cddfSDavid du Colombier {
567dd7cddfSDavid du Colombier fprint(2, "usage: disk/mbr [-m mbrfile] disk\n");
577dd7cddfSDavid du Colombier exits("usage");
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier
607dd7cddfSDavid du Colombier void
fatal(char * fmt,...)617dd7cddfSDavid du Colombier fatal(char *fmt, ...)
627dd7cddfSDavid du Colombier {
639a747e4fSDavid du Colombier char err[ERRMAX];
647dd7cddfSDavid du Colombier va_list arg;
657dd7cddfSDavid du Colombier
667dd7cddfSDavid du Colombier va_start(arg, fmt);
679a747e4fSDavid du Colombier vsnprint(err, ERRMAX, fmt, arg);
687dd7cddfSDavid du Colombier va_end(arg);
697dd7cddfSDavid du Colombier fprint(2, "mbr: %s\n", err);
707dd7cddfSDavid du Colombier exits(err);
717dd7cddfSDavid du Colombier }
727dd7cddfSDavid du Colombier
7339734e7eSDavid du Colombier static void
putle32(void * v,u32int i)7439734e7eSDavid du Colombier putle32(void* v, u32int i)
7539734e7eSDavid du Colombier {
7639734e7eSDavid du Colombier uchar *p;
7739734e7eSDavid du Colombier
7839734e7eSDavid du Colombier p = v;
7939734e7eSDavid du Colombier p[0] = i;
8039734e7eSDavid du Colombier p[1] = i>>8;
8139734e7eSDavid du Colombier p[2] = i>>16;
8239734e7eSDavid du Colombier p[3] = i>>24;
8339734e7eSDavid du Colombier }
8439734e7eSDavid du Colombier
8539734e7eSDavid du Colombier static void
writechs(Disk * disk,uchar * p,vlong lba)8639734e7eSDavid du Colombier writechs(Disk *disk, uchar *p, vlong lba)
8739734e7eSDavid du Colombier {
8839734e7eSDavid du Colombier int c, h, s;
8939734e7eSDavid du Colombier
9039734e7eSDavid du Colombier s = lba % disk->s;
9139734e7eSDavid du Colombier h = (lba / disk->s) % disk->h;
9239734e7eSDavid du Colombier c = lba / (disk->s * disk->h);
9339734e7eSDavid du Colombier
9439734e7eSDavid du Colombier if(c >= 1024) {
9539734e7eSDavid du Colombier c = 1023;
9639734e7eSDavid du Colombier h = disk->h - 1;
9739734e7eSDavid du Colombier s = disk->s - 1;
9839734e7eSDavid du Colombier }
9939734e7eSDavid du Colombier
10039734e7eSDavid du Colombier p[0] = h;
10139734e7eSDavid du Colombier p[1] = ((s+1) & 0x3F) | ((c>>2) & 0xC0);
10239734e7eSDavid du Colombier p[2] = c;
10339734e7eSDavid du Colombier }
10439734e7eSDavid du Colombier
10539734e7eSDavid du Colombier static void
wrtentry(Disk * disk,Tentry * tp,int type,u32int base,u32int lba,u32int end)10639734e7eSDavid du Colombier wrtentry(Disk *disk, Tentry *tp, int type, u32int base, u32int lba, u32int end)
10739734e7eSDavid du Colombier {
108390ad7e1SDavid du Colombier tp->active = 0x80; /* make this sole partition active */
10939734e7eSDavid du Colombier tp->type = type;
11039734e7eSDavid du Colombier writechs(disk, &tp->starth, lba);
11139734e7eSDavid du Colombier writechs(disk, &tp->endh, end-1);
11239734e7eSDavid du Colombier putle32(tp->lba, lba-base);
11339734e7eSDavid du Colombier putle32(tp->size, end-lba);
11439734e7eSDavid du Colombier }
11539734e7eSDavid du Colombier
1167dd7cddfSDavid du Colombier void
main(int argc,char ** argv)1177dd7cddfSDavid du Colombier main(int argc, char **argv)
1187dd7cddfSDavid du Colombier {
1197dd7cddfSDavid du Colombier Disk *disk;
12039734e7eSDavid du Colombier Tentry *tp;
1217dd7cddfSDavid du Colombier uchar *mbr, *buf;
1227dd7cddfSDavid du Colombier char *mbrfile;
1237dd7cddfSDavid du Colombier ulong secsize;
12439734e7eSDavid du Colombier int flag9, sysfd, nmbr;
1257dd7cddfSDavid du Colombier
12639734e7eSDavid du Colombier flag9 = 0;
1277dd7cddfSDavid du Colombier mbrfile = nil;
1287dd7cddfSDavid du Colombier ARGBEGIN {
12939734e7eSDavid du Colombier case '9':
13039734e7eSDavid du Colombier flag9 = 1;
13139734e7eSDavid du Colombier break;
1327dd7cddfSDavid du Colombier case 'm':
133390ad7e1SDavid du Colombier mbrfile = EARGF(usage());
1347dd7cddfSDavid du Colombier break;
1357dd7cddfSDavid du Colombier default:
1367dd7cddfSDavid du Colombier usage();
1377dd7cddfSDavid du Colombier } ARGEND
1387dd7cddfSDavid du Colombier
1397dd7cddfSDavid du Colombier if(argc < 1)
1407dd7cddfSDavid du Colombier usage();
1417dd7cddfSDavid du Colombier
1427dd7cddfSDavid du Colombier disk = opendisk(argv[0], 0, 0);
1437dd7cddfSDavid du Colombier if(disk == nil)
1447dd7cddfSDavid du Colombier fatal("opendisk %s: %r", argv[0]);
1457dd7cddfSDavid du Colombier
1467dd7cddfSDavid du Colombier if(disk->type == Tfloppy)
1477dd7cddfSDavid du Colombier fatal("will not install mbr on floppy");
148*71369a22SDavid du Colombier /*
149*71369a22SDavid du Colombier * we need to cope with 4k-byte sectors on some newer disks.
150*71369a22SDavid du Colombier * we're only interested in 512 bytes of mbr, so
151*71369a22SDavid du Colombier * on 4k disks, rely on /dev/sd to read-modify-write.
152*71369a22SDavid du Colombier */
153*71369a22SDavid du Colombier secsize = 512;
154*71369a22SDavid du Colombier if(disk->secsize != secsize)
155*71369a22SDavid du Colombier fprint(2, "%s: sector size %lld not %ld, should be okay\n",
156*71369a22SDavid du Colombier argv0, disk->secsize, secsize);
1577dd7cddfSDavid du Colombier
1583ff48bf5SDavid du Colombier buf = malloc(secsize*(disk->s+1));
1593ff48bf5SDavid du Colombier mbr = malloc(secsize*disk->s);
1607dd7cddfSDavid du Colombier if(buf == nil || mbr == nil)
1617dd7cddfSDavid du Colombier fatal("out of memory");
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier /*
1647dd7cddfSDavid du Colombier * Start with initial sector from disk.
1657dd7cddfSDavid du Colombier */
1667dd7cddfSDavid du Colombier if(seek(disk->fd, 0, 0) < 0)
1677dd7cddfSDavid du Colombier fatal("seek to boot sector: %r\n");
1687dd7cddfSDavid du Colombier if(read(disk->fd, mbr, secsize) != secsize)
1697dd7cddfSDavid du Colombier fatal("reading boot sector: %r");
1707dd7cddfSDavid du Colombier
1717dd7cddfSDavid du Colombier if(mbrfile == nil){
1727dd7cddfSDavid du Colombier nmbr = ndefmbr;
1737dd7cddfSDavid du Colombier memmove(mbr, defmbr, nmbr);
1747dd7cddfSDavid du Colombier } else {
1753ff48bf5SDavid du Colombier memset(buf, 0, secsize*disk->s);
1767dd7cddfSDavid du Colombier if((sysfd = open(mbrfile, OREAD)) < 0)
1777dd7cddfSDavid du Colombier fatal("open %s: %r", mbrfile);
1783ff48bf5SDavid du Colombier if((nmbr = read(sysfd, buf, secsize*(disk->s+1))) < 0)
1797dd7cddfSDavid du Colombier fatal("read %s: %r", mbrfile);
1803ff48bf5SDavid du Colombier if(nmbr > secsize*disk->s)
1813ff48bf5SDavid du Colombier fatal("master boot record too large %d > %d", nmbr, secsize*disk->s);
1823ff48bf5SDavid du Colombier if(nmbr < secsize)
1833ff48bf5SDavid du Colombier nmbr = secsize;
1847dd7cddfSDavid du Colombier close(sysfd);
1853ff48bf5SDavid du Colombier memmove(buf+Toffset, mbr+Toffset, secsize-Toffset);
1867dd7cddfSDavid du Colombier memmove(mbr, buf, nmbr);
1877dd7cddfSDavid du Colombier }
18839734e7eSDavid du Colombier
18939734e7eSDavid du Colombier if(flag9){
19039734e7eSDavid du Colombier tp = (Tentry*)(mbr+Toffset);
19139734e7eSDavid du Colombier memset(tp, 0, secsize-Toffset);
19239734e7eSDavid du Colombier wrtentry(disk, tp, Type9, 0, disk->s, disk->secs);
19339734e7eSDavid du Colombier }
1947dd7cddfSDavid du Colombier mbr[secsize-2] = 0x55;
1957dd7cddfSDavid du Colombier mbr[secsize-1] = 0xAA;
1963ff48bf5SDavid du Colombier nmbr = (nmbr+secsize-1)&~(secsize-1);
1977dd7cddfSDavid du Colombier if(seek(disk->wfd, 0, 0) < 0)
1987dd7cddfSDavid du Colombier fatal("seek to MBR sector: %r\n");
1993ff48bf5SDavid du Colombier if(write(disk->wfd, mbr, nmbr) != nmbr)
2007dd7cddfSDavid du Colombier fatal("writing MBR: %r");
2017dd7cddfSDavid du Colombier
2027dd7cddfSDavid du Colombier exits(0);
2037dd7cddfSDavid du Colombier }
204