1105816Sphk/*
2105816Sphk * ----------------------------------------------------------------------------
3105816Sphk * "THE BEER-WARE LICENSE" (Revision 42):
4105816Sphk * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5105816Sphk * can do whatever you want with this stuff. If we meet some day, and you think
6105816Sphk * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7105816Sphk * ----------------------------------------------------------------------------
8105816Sphk */
9105816Sphk
10105816Sphk#include <sys/cdefs.h>
11105816Sphk__FBSDID("$FreeBSD$");
12105816Sphk
13105816Sphk#include <stdio.h>
14105816Sphk#include <stdlib.h>
15105816Sphk#include <unistd.h>
16105816Sphk#include <fcntl.h>
17105816Sphk#include <string.h>
18105816Sphk#include <sys/types.h>
19105816Sphk#include <sys/stat.h>
20105816Sphk#include <sys/disklabel.h>
21105816Sphk#include <sys/diskmbr.h>
22105816Sphk#include <paths.h>
23105816Sphk#include "libdisk.h"
24105816Sphk
25106949Snyan/*
26106949Snyan * XXX: A lot of hardcoded 512s probably should be foo->sector_size;
27106949Snyan *	I'm not sure which, so I leave it like it worked before. --schweikh
28106949Snyan */
29105816Sphkstatic int
30110339SjhbWrite_FreeBSD(int fd, const struct disk *new, const struct chunk *c1)
31105816Sphk{
32105816Sphk	struct disklabel *dl;
33105816Sphk	int i;
34105816Sphk	void *p;
35105816Sphk	u_char buf[BBSIZE];
36105816Sphk
37106949Snyan	for (i = 0; i < BBSIZE/512; i++) {
38130067Sbrian		if (!(p = read_block(fd, i + c1->offset, 512)))
39130067Sbrian			return (1);
40105816Sphk		memcpy(buf + 512 * i, p, 512);
41105816Sphk		free(p);
42105816Sphk	}
43106949Snyan	if (new->boot1)
44105816Sphk		memcpy(buf, new->boot1, 512);
45105816Sphk
46106949Snyan	if (new->boot2)
47106949Snyan		memcpy(buf + 512, new->boot2, BBSIZE - 512);
48105816Sphk
49105816Sphk	dl = (struct disklabel *)(buf + 512 * LABELSECTOR + LABELOFFSET);
50110339Sjhb	Fill_Disklabel(dl, new, c1);
51105816Sphk
52106949Snyan	for (i = 0; i < BBSIZE / 512; i++)
53105816Sphk		write_block(fd, i + c1->offset, buf + 512 * i, 512);
54105816Sphk
55105816Sphk	return 0;
56105816Sphk}
57105816Sphk
58105816Sphkstatic void
59105816SphkWrite_Int32(u_int32_t *p, u_int32_t v)
60105816Sphk{
61106949Snyan	u_int8_t *bp = (u_int8_t *)p;
62106949Snyan
63106949Snyan	bp[0] = (v >> 0) & 0xff;
64106949Snyan	bp[1] = (v >> 8) & 0xff;
65106949Snyan	bp[2] = (v >> 16) & 0xff;
66106949Snyan	bp[3] = (v >> 24) & 0xff;
67105816Sphk}
68105816Sphk
69105816Sphk/*
70105816Sphk * Special install-time configuration for the i386 boot0 boot manager.
71105816Sphk */
72105816Sphkstatic void
73105816SphkCfg_Boot_Mgr(u_char *mbr, int edd)
74105816Sphk{
75106949Snyan
76106949Snyan	if (mbr[0x1b0] == 0x66 && mbr[0x1b1] == 0xbb) {
77106949Snyan		if (edd)
78106949Snyan			mbr[0x1bb] |= 0x80;	/* Packet mode on */
79106949Snyan		else
80106949Snyan			mbr[0x1bb] &= 0x7f;	/* Packet mode off */
81106949Snyan	}
82105816Sphk}
83105816Sphk
84105816Sphkint
85105816SphkWrite_Disk(const struct disk *d1)
86105816Sphk{
87110339Sjhb	int fd, j;
88110339Sjhb	uint i;
89105816Sphk	struct chunk *c1;
90105816Sphk	int ret = 0;
91105816Sphk	char device[64];
92105816Sphk	u_char *mbr;
93105816Sphk	struct dos_partition *dp,work[NDOSPART];
94105816Sphk	int s[4];
95105816Sphk	int need_edd = 0;	/* Need EDD (packet interface) */
96105816Sphk
97106949Snyan	strcpy(device, _PATH_DEV);
98106949Snyan        strcat(device, d1->name);
99105816Sphk
100106949Snyan        fd = open(device, O_RDWR);
101105821Sphk        if (fd < 0)
102105816Sphk                return 1;
103105816Sphk
104106949Snyan	memset(s, 0, sizeof s);
105130067Sbrian	if (!(mbr = read_block(fd, 0, d1->sector_size))) {
106130067Sbrian		close (fd);
107130067Sbrian		return (1);
108130067Sbrian	}
109106949Snyan	dp = (struct dos_partition *)(mbr + DOSPARTOFF);
110105816Sphk	memcpy(work, dp, sizeof work);
111105816Sphk	dp = work;
112105816Sphk	free(mbr);
113105816Sphk	for (c1 = d1->chunks->part; c1; c1 = c1->next) {
114106949Snyan		if (c1->type == unused)
115106949Snyan			continue;
116106949Snyan		if (!strcmp(c1->name, "X"))
117106949Snyan			continue;
118105816Sphk		j = c1->name[strlen(d1->name) + 1] - '1';
119105816Sphk		if (j < 0 || j > 3)
120105816Sphk			continue;
121105816Sphk		s[j]++;
122105816Sphk		if (c1->type == freebsd)
123110339Sjhb			ret += Write_FreeBSD(fd, d1, c1);
124105816Sphk
125105816Sphk		Write_Int32(&dp[j].dp_start, c1->offset);
126105816Sphk		Write_Int32(&dp[j].dp_size, c1->size);
127105816Sphk
128105816Sphk		i = c1->offset;
129106949Snyan		if (i >= 1024 * d1->bios_sect * d1->bios_hd) {
130105816Sphk			dp[j].dp_ssect = 0xff;
131105816Sphk			dp[j].dp_shd = 0xff;
132105816Sphk			dp[j].dp_scyl = 0xff;
133105816Sphk			need_edd++;
134105816Sphk		} else {
135105816Sphk			dp[j].dp_ssect = i % d1->bios_sect;
136105816Sphk			i -= dp[j].dp_ssect++;
137105816Sphk			i /= d1->bios_sect;
138105816Sphk			dp[j].dp_shd =  i % d1->bios_hd;
139105816Sphk			i -= dp[j].dp_shd;
140105816Sphk			i /= d1->bios_hd;
141105816Sphk			dp[j].dp_scyl = i;
142105816Sphk			i -= dp[j].dp_scyl;
143105816Sphk			dp[j].dp_ssect |= i >> 2;
144105816Sphk		}
145105816Sphk#ifdef DEBUG
146106949Snyan		printf("S:%lu = (%x/%x/%x)", c1->offset,
147106949Snyan		       dp[j].dp_scyl, dp[j].dp_shd, dp[j].dp_ssect);
148105816Sphk#endif
149105816Sphk
150105816Sphk		i = c1->end;
151105816Sphk		dp[j].dp_esect = i % d1->bios_sect;
152105816Sphk		i -= dp[j].dp_esect++;
153105816Sphk		i /= d1->bios_sect;
154105816Sphk		dp[j].dp_ehd =  i % d1->bios_hd;
155105816Sphk		i -= dp[j].dp_ehd;
156105816Sphk		i /= d1->bios_hd;
157106949Snyan		if (i > 1023)
158106949Snyan			i = 1023;
159105816Sphk		dp[j].dp_ecyl = i;
160105816Sphk		i -= dp[j].dp_ecyl;
161105816Sphk		dp[j].dp_esect |= i >> 2;
162105816Sphk#ifdef DEBUG
163106949Snyan		printf("  E:%lu = (%x/%x/%x)\n", c1->end,
164106949Snyan		       dp[j].dp_ecyl, dp[j].dp_ehd, dp[j].dp_esect);
165105816Sphk#endif
166105816Sphk
167105816Sphk		dp[j].dp_typ = c1->subtype;
168105816Sphk		if (c1->flags & CHUNK_ACTIVE)
169105816Sphk			dp[j].dp_flag = 0x80;
170105816Sphk		else
171105816Sphk			dp[j].dp_flag = 0;
172105816Sphk	}
173105816Sphk	j = 0;
174106949Snyan	for (i = 0; i < NDOSPART; i++) {
175105816Sphk		if (!s[i])
176105816Sphk			memset(dp + i, 0, sizeof *dp);
177105816Sphk		if (dp[i].dp_flag)
178105816Sphk			j++;
179105816Sphk	}
180105816Sphk	if (!j)
181105816Sphk		for(i = 0; i < NDOSPART; i++)
182105816Sphk			if (dp[i].dp_typ == 0xa5)
183105816Sphk				dp[i].dp_flag = 0x80;
184105816Sphk
185130067Sbrian	if (!(mbr = read_block(fd, 0, d1->sector_size))) {
186130067Sbrian		close (fd);
187130067Sbrian		return (1);
188130067Sbrian	}
189105816Sphk	if (d1->bootmgr) {
190105816Sphk		memcpy(mbr, d1->bootmgr, DOSPARTOFF);
191105816Sphk		Cfg_Boot_Mgr(mbr, need_edd);
192105816Sphk        }
193105816Sphk	memcpy(mbr + DOSPARTOFF, dp, sizeof *dp * NDOSPART);
194105816Sphk	mbr[512-2] = 0x55;
195105816Sphk	mbr[512-1] = 0xaa;
196105816Sphk	write_block(fd, 0, mbr, d1->sector_size);
197105816Sphk	if (d1->bootmgr && d1->bootmgr_size > d1->sector_size)
198106949Snyan		for (i = 1; i * d1->sector_size <= d1->bootmgr_size; i++)
199106949Snyan			write_block(fd, i, &d1->bootmgr[i * d1->sector_size],
200106949Snyan				    d1->sector_size);
201105816Sphk
202105816Sphk	close(fd);
203105816Sphk	return 0;
204105816Sphk}
205