next68k.c revision 1.2 1 /* $NetBSD: next68k.c,v 1.2 2003/10/27 22:38:39 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by David Laight and Christian Limpach.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #if HAVE_NBTOOL_CONFIG_H
40 #include "nbtool_config.h"
41 #endif
42
43 #include <sys/cdefs.h>
44 #if !defined(__lint)
45 __RCSID("$NetBSD: next68k.c,v 1.2 2003/10/27 22:38:39 lukem Exp $");
46 #endif /* !__lint */
47
48 #include <sys/param.h>
49
50 #include <assert.h>
51 #include <err.h>
52 #include <md5.h>
53 #include <stddef.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59 #include "installboot.h"
60
61 #define SECTOR_SIZE DEV_BSIZE
62
63 static uint16_t nextstep_checksum(const void *, const void *);
64
65 static uint16_t
66 nextstep_checksum(const void *vbuf, const void *vlimit)
67 {
68 const uint16_t *buf = vbuf;
69 const uint16_t *limit = vlimit;
70 uint sum = 0;
71
72 while (buf < limit) {
73 sum += be16toh(*buf++);
74 }
75 sum += (sum >> 16);
76 return (sum & 0xffff);
77 }
78
79 int
80 next68k_setboot(ib_params *params)
81 {
82 int retval, labelupdated;
83 uint8_t *bootbuf;
84 uint bootsize;
85 ssize_t rv;
86 uint32_t cd_secsize;
87 int sec_netonb_mult;
88 struct next68k_disklabel *next68klabel;
89 uint16_t *checksum;
90 uint32_t fp, b0, b1;
91
92 assert(params != NULL);
93 assert(params->fsfd != -1);
94 assert(params->filesystem != NULL);
95 assert(params->s1fd != -1);
96 assert(params->stage1 != NULL);
97
98 retval = 0;
99 labelupdated = 0;
100 bootbuf = NULL;
101
102 next68klabel = malloc(NEXT68K_LABEL_SIZE);
103 if (next68klabel == NULL) {
104 warn("Allocating %lu bytes", (unsigned long)NEXT68K_LABEL_SIZE);
105 goto done;
106 }
107
108 /*
109 * Read in the next68k disklabel
110 */
111 rv = pread(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE,
112 NEXT68K_LABEL_SECTOR * SECTOR_SIZE + NEXT68K_LABEL_OFFSET);
113 if (rv == -1) {
114 warn("Reading `%s'", params->filesystem);
115 goto done;
116 }
117 if (rv != NEXT68K_LABEL_SIZE) {
118 warnx("Reading `%s': short read", params->filesystem);
119 goto done;
120 }
121 if (be32toh(next68klabel->cd_version) == NEXT68K_LABEL_CD_V3) {
122 checksum = &next68klabel->NEXT68K_LABEL_cd_v3_checksum;
123 } else {
124 checksum = &next68klabel->cd_checksum;
125 }
126 if (nextstep_checksum (next68klabel, checksum) !=
127 be16toh(*checksum)) {
128 warn("Disklabel checksum invalid on `%s'",
129 params->filesystem);
130 goto done;
131 }
132
133 cd_secsize = be32toh(next68klabel->cd_secsize);
134 sec_netonb_mult = (cd_secsize / SECTOR_SIZE);
135
136 /*
137 * Allocate a buffer, with space to round up the input file
138 * to the next block size boundary, and with space for the boot
139 * block.
140 */
141 bootsize = roundup(params->s1stat.st_size, cd_secsize);
142
143 bootbuf = malloc(bootsize);
144 if (bootbuf == NULL) {
145 warn("Allocating %lu bytes", (unsigned long)bootsize);
146 goto done;
147 }
148 memset(bootbuf, 0, bootsize);
149
150 /*
151 * Read the file into the buffer.
152 */
153 rv = pread(params->s1fd, bootbuf, params->s1stat.st_size, 0);
154 if (rv == -1) {
155 warn("Reading `%s'", params->stage1);
156 goto done;
157 } else if (rv != params->s1stat.st_size) {
158 warnx("Reading `%s': short read", params->stage1);
159 goto done;
160 }
161
162 if (bootsize > be16toh(next68klabel->cd_front) * cd_secsize -
163 NEXT68K_LABEL_SIZE) {
164 warnx("Boot program is larger than front porch space");
165 goto done;
166 }
167
168 fp = be16toh(next68klabel->cd_front);
169 b0 = be32toh(next68klabel->cd_boot_blkno[0]);
170 b1 = be32toh(next68klabel->cd_boot_blkno[1]);
171
172 if (b0 > fp)
173 b0 = fp;
174 if (b1 > fp)
175 b1 = fp;
176 if (((bootsize / cd_secsize) > b1 - b0) ||
177 ((bootsize / cd_secsize) > fp - b1)) {
178 if (2 * bootsize > (fp * cd_secsize - NEXT68K_LABEL_SIZE))
179 /* can only fit one copy */
180 b0 = b1 = NEXT68K_LABEL_SIZE / cd_secsize;
181 else {
182 if (2 * bootsize > (fp * cd_secsize -
183 NEXT68K_LABEL_DEFAULTBOOT0_1 * SECTOR_SIZE))
184 /* can fit two copies starting after label */
185 b0 = NEXT68K_LABEL_SIZE / cd_secsize;
186 else
187 /* can fit two copies starting at default 1 */
188 b0 = NEXT68K_LABEL_DEFAULTBOOT0_1 /
189 sec_netonb_mult;
190 /* try to fit 2nd copy at default 2 */
191 b1 = NEXT68K_LABEL_DEFAULTBOOT0_2 / sec_netonb_mult;
192 if (fp < b1)
193 b1 = fp;
194 if (bootsize / cd_secsize > (fp - b1))
195 /* fit 2nd copy before front porch */
196 b1 = fp - bootsize / cd_secsize;
197 }
198 }
199 if (next68klabel->cd_boot_blkno[0] != htobe32(b0)) {
200 next68klabel->cd_boot_blkno[0] = htobe32(b0);
201 labelupdated = 1;
202 }
203 if (next68klabel->cd_boot_blkno[1] != htobe32(b1)) {
204 next68klabel->cd_boot_blkno[1] = htobe32(b1);
205 labelupdated = 1;
206 }
207 if (params->flags & IB_VERBOSE)
208 printf("Boot programm locations%s: %d %d\n",
209 labelupdated ? " updated" : "", b0 * sec_netonb_mult,
210 b1 * sec_netonb_mult);
211
212 if (params->flags & IB_NOWRITE) {
213 retval = 1;
214 goto done;
215 }
216
217 /*
218 * Write the updated next68k disklabel
219 */
220 if (labelupdated) {
221 if (params->flags & IB_VERBOSE)
222 printf ("Writing updated label\n");
223 *checksum = htobe16(nextstep_checksum (next68klabel,
224 checksum));
225 rv = pwrite(params->fsfd, next68klabel, NEXT68K_LABEL_SIZE,
226 NEXT68K_LABEL_SECTOR * SECTOR_SIZE + NEXT68K_LABEL_OFFSET);
227 if (rv == -1) {
228 warn("Writing `%s'", params->filesystem);
229 goto done;
230 }
231 if (rv != NEXT68K_LABEL_SIZE) {
232 warnx("Writing `%s': short write", params->filesystem);
233 goto done;
234 }
235 }
236
237 b0 *= sec_netonb_mult;
238 b1 *= sec_netonb_mult;
239
240 /*
241 * Write boot program to locations b0 and b1 (if different).
242 */
243 for (;;) {
244 if (params->flags & IB_VERBOSE)
245 printf ("Writing boot program at %d\n", b0);
246 rv = pwrite(params->fsfd, bootbuf, bootsize, b0 * SECTOR_SIZE);
247 if (rv == -1) {
248 warn("Writing `%s' at %d", params->filesystem, b0);
249 goto done;
250 }
251 if (rv != bootsize) {
252 warnx("Writing `%s' at %d: short write",
253 params->filesystem, b0);
254 goto done;
255 }
256 if (b0 == b1)
257 break;
258 b0 = b1;
259 }
260
261 retval = 1;
262
263 done:
264 if (bootbuf)
265 free(bootbuf);
266 if (next68klabel)
267 free(next68klabel);
268 return retval;
269 }
270