Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
54
usage(void)
55
{
56
	fprint(2, "usage: disk/mbr [-m mbrfile] disk\n");
57
	exits("usage");
58
}
59
 
60
void
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
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
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
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
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
}