1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  */
9 
10 #include <sys/cdefs.h>
11 __FBSDID("$FreeBSD: stable/9/lib/libdisk/write_amd64_disk.c 130067 2004-06-04 11:49:11Z brian $");
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/disklabel.h>
21 #include <sys/diskmbr.h>
22 #include <paths.h>
23 #include "libdisk.h"
24 
25 /*
26  * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
27  *	I'm not sure which, so I leave it like it worked before. --schweikh
28  */
29 static int
Write_FreeBSD(int fd,const struct disk * new,const struct chunk * c1)30 Write_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
31 {
32 	struct disklabel *dl;
33 	int i;
34 	void *p;
35 	u_char buf[BBSIZE];
36 
37 	for (i = 0; i < BBSIZE/512; i++) {
38 		if (!(p = read_block(fd, i + c1->offset, 512)))
39 			return (1);
40 		memcpy(buf + 512 * i, p, 512);
41 		free(p);
42 	}
43 	if (new->boot1)
44 		memcpy(buf, new->boot1, 512);
45 
46 	if (new->boot2)
47 		memcpy(buf + 512, new->boot2, BBSIZE - 512);
48 
49 	dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
50 	Fill_Disklabel(dl, new, c1);
51 
52 	for (i = 0; i < BBSIZE / 512; i++)
53 		write_block(fd, i + c1->offset, buf + 512 * i, 512);
54 
55 	return 0;
56 }
57 
58 static void
Write_Int32(u_int32_t * p,u_int32_t v)59 Write_Int32(u_int32_t *p, u_int32_t v)
60 {
61 	u_int8_t *bp = (u_int8_t *)p;
62 
63 	bp[0] = (v >> 0) & 0xff;
64 	bp[1] = (v >> 8) & 0xff;
65 	bp[2] = (v >> 16) & 0xff;
66 	bp[3] = (v >> 24) & 0xff;
67 }
68 
69 /*
70  * Special install-time configuration for the i386 boot0 boot manager.
71  */
72 static void
Cfg_Boot_Mgr(u_char * mbr,int edd)73 Cfg_Boot_Mgr(u_char *mbr, int edd)
74 {
75 
76 	if (mbr[0x1b0] == 0x66 && mbr[0x1b1] == 0xbb) {
77 		if (edd)
78 			mbr[0x1bb] |= 0x80;	/* Packet mode on */
79 		else
80 			mbr[0x1bb] &= 0x7f;	/* Packet mode off */
81 	}
82 }
83 
84 int
Write_Disk(const struct disk * d1)85 Write_Disk(const struct disk *d1)
86 {
87 	int fd, j;
88 	uint i;
89 	struct chunk *c1;
90 	int ret = 0;
91 	char device[64];
92 	u_char *mbr;
93 	struct dos_partition *dp,work[NDOSPART];
94 	int s[4];
95 	int need_edd = 0;	/* Need EDD (packet interface) */
96 
97 	strcpy(device, _PATH_DEV);
98         strcat(device, d1->name);
99 
100         fd = open(device, O_RDWR);
101         if (fd < 0)
102                 return 1;
103 
104 	memset(s, 0, sizeof s);
105 	if (!(mbr = read_block(fd, 0, d1->sector_size))) {
106 		close (fd);
107 		return (1);
108 	}
109 	dp = (struct dos_partition *)(mbr + DOSPARTOFF);
110 	memcpy(work, dp, sizeof work);
111 	dp = work;
112 	free(mbr);
113 	for (c1 = d1->chunks->part; c1; c1 = c1->next) {
114 		if (c1->type == unused)
115 			continue;
116 		if (!strcmp(c1->name, "X"))
117 			continue;
118 		j = c1->name[strlen(d1->name) + 1] - '1';
119 		if (j < 0 || j > 3)
120 			continue;
121 		s[j]++;
122 		if (c1->type == freebsd)
123 			ret += Write_FreeBSD(fd, d1, c1);
124 
125 		Write_Int32(&dp[j].dp_start, c1->offset);
126 		Write_Int32(&dp[j].dp_size, c1->size);
127 
128 		i = c1->offset;
129 		if (i >= 1024 * d1->bios_sect * d1->bios_hd) {
130 			dp[j].dp_ssect = 0xff;
131 			dp[j].dp_shd = 0xff;
132 			dp[j].dp_scyl = 0xff;
133 			need_edd++;
134 		} else {
135 			dp[j].dp_ssect = i % d1->bios_sect;
136 			i -= dp[j].dp_ssect++;
137 			i /= d1->bios_sect;
138 			dp[j].dp_shd =  i % d1->bios_hd;
139 			i -= dp[j].dp_shd;
140 			i /= d1->bios_hd;
141 			dp[j].dp_scyl = i;
142 			i -= dp[j].dp_scyl;
143 			dp[j].dp_ssect |= i >> 2;
144 		}
145 #ifdef DEBUG
146 		printf("S:%lu = (%x/%x/%x)", c1->offset,
147 		       dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
148 #endif
149 
150 		i = c1->end;
151 		dp[j].dp_esect = i % d1->bios_sect;
152 		i -= dp[j].dp_esect++;
153 		i /= d1->bios_sect;
154 		dp[j].dp_ehd =  i % d1->bios_hd;
155 		i -= dp[j].dp_ehd;
156 		i /= d1->bios_hd;
157 		if (i > 1023)
158 			i = 1023;
159 		dp[j].dp_ecyl = i;
160 		i -= dp[j].dp_ecyl;
161 		dp[j].dp_esect |= i >> 2;
162 #ifdef DEBUG
163 		printf("  E:%lu = (%x/%x/%x)\n", c1->end,
164 		       dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
165 #endif
166 
167 		dp[j].dp_typ = c1->subtype;
168 		if (c1->flags & CHUNK_ACTIVE)
169 			dp[j].dp_flag = 0x80;
170 		else
171 			dp[j].dp_flag = 0;
172 	}
173 	j = 0;
174 	for (i = 0; i < NDOSPART; i++) {
175 		if (!s[i])
176 			memset(dp + i, 0, sizeof *dp);
177 		if (dp[i].dp_flag)
178 			j++;
179 	}
180 	if (!j)
181 		for(i = 0; i < NDOSPART; i++)
182 			if (dp[i].dp_typ == 0xa5)
183 				dp[i].dp_flag = 0x80;
184 
185 	if (!(mbr = read_block(fd, 0, d1->sector_size))) {
186 		close (fd);
187 		return (1);
188 	}
189 	if (d1->bootmgr) {
190 		memcpy(mbr, d1->bootmgr, DOSPARTOFF);
191 		Cfg_Boot_Mgr(mbr, need_edd);
192         }
193 	memcpy(mbr + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
194 	mbr[512-2] = 0x55;
195 	mbr[512-1] = 0xaa;
196 	write_block(fd, 0, mbr, d1->sector_size);
197 	if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
198 		for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
199 			write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
200 				    d1->sector_size);
201 
202 	close(fd);
203 	return 0;
204 }
205