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