1 /*	$NetBSD: disksubr_acorn.c,v 1.12 2013/03/09 16:02:25 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  *	from: @(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
62  */
63 
64 /*
65  * Copyright (c) 1995 Mark Brinicombe
66  * All rights reserved.
67  *
68  * Redistribution and use in source and binary forms, with or without
69  * modification, are permitted provided that the following conditions
70  * are met:
71  * 1. Redistributions of source code must retain the above copyright
72  *    notice, this list of conditions and the following disclaimer.
73  * 2. Redistributions in binary form must reproduce the above copyright
74  *    notice, this list of conditions and the following disclaimer in the
75  *    documentation and/or other materials provided with the distribution.
76  * 3. All advertising materials mentioning features or use of this software
77  *    must display the following acknowledgement:
78  *	This product includes software developed by the University of
79  *	California, Berkeley and its contributors.
80  * 4. Neither the name of the University nor the names of its contributors
81  *    may be used to endorse or promote products derived from this software
82  *    without specific prior written permission.
83  *
84  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
85  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
88  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94  * SUCH DAMAGE.
95  *
96  *	from: @(#)ufs_disksubr.c	7.16 (Berkeley) 5/4/91
97  */
98 
99 #include <sys/cdefs.h>
100 __KERNEL_RCSID(0, "$NetBSD: disksubr_acorn.c,v 1.12 2013/03/09 16:02:25 christos Exp $");
101 
102 #include <sys/param.h>
103 #include <sys/systm.h>
104 #include <sys/buf.h>
105 #include <sys/disklabel.h>
106 
107 static int filecore_checksum(u_char *);
108 
109 /*
110  * static int filecore_checksum(u_char *bootblock)
111  *
112  * Calculates the filecore boot block checksum. This is used to validate
113  * a filecore boot block on the disk.  If a boot block is validated then
114  * it is used to locate the partition table. If the boot block is not
115  * validated, it is assumed that the whole disk is NetBSD.
116  *
117  * The basic algorithm is:
118  *
119  *	for (each byte in block, excluding checksum) {
120  *		sum += byte;
121  *		if (sum > 255)
122  *			sum -= 255;
123  *	}
124  *
125  * That's equivalent to summing all of the bytes in the block
126  * (excluding the checksum byte, of course), then calculating the
127  * checksum as "cksum = sum - ((sum - 1) / 255) * 255)".  That
128  * expression may or may not yield a faster checksum function,
129  * but it's easier to reason about.
130  *
131  * Note that if you have a block filled with bytes of a single
132  * value "X" (regardless of that value!) and calculate the cksum
133  * of the block (excluding the checksum byte), you will _always_
134  * end up with a checksum of X.  (Do the math; that can be derived
135  * from the checksum calculation function!)  That means that
136  * blocks which contain bytes which all have the same value will
137  * always checksum properly.  That's a _very_ unlikely occurence
138  * (probably impossible, actually) for a valid filecore boot block,
139  * so we treat such blocks as invalid.
140  */
141 static int
filecore_checksum(u_char * bootblock)142 filecore_checksum(u_char *bootblock)
143 {
144 	u_char byte0, accum_diff;
145 	u_int sum;
146 	int i;
147 
148 	sum = 0;
149 	accum_diff = 0;
150 	byte0 = bootblock[0];
151 
152 	/*
153 	 * Sum the contents of the block, keeping track of whether
154 	 * or not all bytes are the same.  If 'accum_diff' ends up
155 	 * being zero, all of the bytes are, in fact, the same.
156 	 */
157 	for (i = 0; i < 511; ++i) {
158 		sum += bootblock[i];
159 		accum_diff |= bootblock[i] ^ byte0;
160 	}
161 
162 	/*
163 	 * Check to see if the checksum byte is the same as the
164 	 * rest of the bytes, too.  (Note that if all of the bytes
165 	 * are the same except the checksum, a checksum compare
166 	 * won't succeed, but that's not our problem.)
167 	 */
168 	accum_diff |= bootblock[i] ^ byte0;
169 
170 	/* All bytes in block are the same; call it invalid. */
171 	if (accum_diff == 0)
172 		return (-1);
173 
174 	return (sum - ((sum - 1) / 255) * 255);
175 }
176 
177 
178 int
filecore_label_read(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep,const char ** msgp,int * cylp,int * netbsd_label_offp)179 filecore_label_read(dev_t dev, void (*strat)(struct buf *),
180 	struct disklabel *lp, struct cpu_disklabel *osdep,
181 	const char **msgp,
182 	int *cylp, int *netbsd_label_offp)
183 {
184 	struct filecore_bootblock *bb;
185 	int heads;
186 	int sectors;
187 	int rv = 1;
188 	int cyl, netbsdpartoff;
189 	struct buf *bp;
190 
191 #ifdef __GNUC__
192 	netbsdpartoff = 0;		/* XXX -Wuninitialized */
193 #endif
194 
195 	/* get a buffer and initialize it */
196         bp = geteblk((int)lp->d_secsize);
197         bp->b_dev = dev;
198 
199 	/* read the Acorn filecore boot block */
200 
201 	bp->b_blkno = FILECORE_BOOT_SECTOR;
202 	bp->b_bcount = lp->d_secsize;
203 	bp->b_flags |= B_READ;
204 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
205 	(*strat)(bp);
206 
207 	/*
208 	 * if successful, validate boot block and
209 	 * locate partition table
210 	 */
211 
212 	if (biowait(bp)) {
213 		*msgp = "filecore boot block I/O error";
214 		goto out;
215 	}
216 
217 	bb = (struct filecore_bootblock *)bp->b_data;
218 
219 	/* Validate boot block */
220 
221 	if (bb->checksum != filecore_checksum((u_char *)bb)) {
222 		/*
223 		 * Invalid boot block so lets assume the
224 		 *  entire disc is NetBSD
225 		 */
226 		rv = 0;
227 		goto out;
228 	}
229 
230 	/* Get some information from the boot block */
231 
232 	cyl = bb->partition_cyl_low + (bb->partition_cyl_high << 8);
233 
234 	heads = bb->heads;
235 	sectors = bb->secspertrack;
236 
237 	/* Do we have a NETBSD partition table ? */
238 
239 	if (bb->partition_type == PARTITION_FORMAT_RISCBSD) {
240 #ifdef DEBUG_LABEL
241 		printf("%s; heads = %d nsectors = %d\n",
242 		    __func__, heads, sectors);
243 #endif
244 		netbsdpartoff = cyl * heads * sectors;
245 	} else if (bb->partition_type == PARTITION_FORMAT_RISCIX) {
246 		struct riscix_partition_table *rpt;
247 		int loop;
248 
249 		/*
250 		 * We have a RISCiX partition table :-( groan
251 		 *
252 		 * Read the RISCiX partition table and see if
253 		 * there is a NetBSD partition
254 		 */
255 
256 		bp->b_blkno = cyl * heads * sectors;
257 #ifdef DEBUG_LABEL
258 		printf("%s: Found RiscIX partition table @ %08x\n",
259 		    __func__, bp->b_blkno);
260 #endif
261 		bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
262 		bp->b_bcount = lp->d_secsize;
263 		bp->b_oflags &= ~(BO_DONE);
264 		bp->b_flags |= B_READ;
265 		(*strat)(bp);
266 
267 		/*
268 		 * if successful, locate disk label within block
269 		 * and validate
270 		 */
271 
272 		if (biowait(bp)) {
273 			*msgp = "disk label I/O error";
274 			goto out;
275 		}
276 
277 		rpt = (struct riscix_partition_table *)bp->b_data;
278 #ifdef DEBUG_LABEL
279 		for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop)
280 			printf("%s: p%d: %16s %08x %08x %08x\n", loop,
281 			    __func__, rpt->partitions[loop].rp_name,
282 			    rpt->partitions[loop].rp_start,
283 			    rpt->partitions[loop].rp_length,
284 			    rpt->partitions[loop].rp_type);
285 #endif
286 		for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop) {
287 			if (strcmp(rpt->partitions[loop].rp_name,
288 			    "RiscBSD") == 0 ||
289 			    strcmp(rpt->partitions[loop].rp_name,
290 			    "NetBSD") == 0 ||
291 			    strcmp(rpt->partitions[loop].rp_name,
292 			    "Empty:") == 0) {
293 				netbsdpartoff =
294 				    rpt->partitions[loop].rp_start;
295 				break;
296 			}
297 		}
298 		if (loop == NRISCIX_PARTITIONS) {
299 			*msgp = "NetBSD partition identifier string not found.";
300 			goto out;
301 		}
302 	} else {
303 		*msgp = "Invalid partition format";
304 		goto out;
305 	}
306 
307 	*cylp = cyl;
308 	*netbsd_label_offp = netbsdpartoff;
309 	*msgp = NULL;
310 out:
311         brelse(bp, 0);
312 	return (rv);
313 }
314 
315 
316 /*
317  * Return -1 not found, 0 found positive errno
318  */
319 int
filecore_label_locate(dev_t dev,void (* strat)(struct buf *),struct disklabel * lp,struct cpu_disklabel * osdep,int * cylp,int * netbsd_label_offp)320 filecore_label_locate(dev_t dev,
321 	void (*strat)(struct buf *),
322 	struct disklabel *lp,
323 	struct cpu_disklabel *osdep,
324 	int *cylp, int *netbsd_label_offp)
325 {
326 	struct filecore_bootblock *bb;
327 	int heads;
328 	int sectors;
329 	int rv;
330 	int cyl, netbsdpartoff;
331 	struct buf *bp;
332 
333 	/* get a buffer and initialize it */
334         bp = geteblk((int)lp->d_secsize);
335         bp->b_dev = dev;
336 
337 	/* read the filecore boot block */
338 
339 #ifdef DEBUG_LABEL
340 	printf("%s: Reading boot block\n", __func__);
341 #endif
342 
343 	bp->b_blkno = FILECORE_BOOT_SECTOR;
344 	bp->b_bcount = lp->d_secsize;
345 	bp->b_flags |= B_READ;
346 	bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
347 	(*strat)(bp);
348 
349 	/*
350 	 * if successful, validate boot block and locate
351 	 * partition table
352 	 */
353 
354 	if ((rv = biowait(bp)) != 0) {
355 		goto out;
356 	}
357 
358 	bb = (struct filecore_bootblock *)bp->b_data;
359 	rv = 0;
360 
361 	/* Validate boot block */
362 
363 	if (bb->checksum != filecore_checksum((u_char *)bb)) {
364 		/*
365 		 * Invalid boot block so lets assume the
366 		 * entire disc is NetBSD
367 		 */
368 #ifdef DEBUG_LABEL
369 		printf("%s: Bad filecore boot block (incorrect checksum)\n",
370 		    __func__);
371 #endif
372 		rv = -1;
373 		goto out;
374 	}
375 
376 	/* Do we have a NetBSD partition ? */
377 
378 	if (bb->partition_type != PARTITION_FORMAT_RISCBSD) {
379 #ifdef DEBUG_LABEL
380 		printf("%s: Invalid partition format\n", __func__);
381 #endif
382 		rv = EINVAL;
383 		goto out;
384 	}
385 
386 	cyl = bb->partition_cyl_low + (bb->partition_cyl_high << 8);
387 
388 	heads = bb->heads;
389 	sectors = bb->secspertrack;
390 
391 #ifdef DEBUG_LABEL
392 	printf("%s: heads = %d nsectors = %d\n", __func__, heads, sectors);
393 #endif
394 
395 	netbsdpartoff = cyl * heads * sectors;
396 
397 	*cylp = cyl;
398 	*netbsd_label_offp = netbsdpartoff;
399 out:
400         brelse(bp, 0);
401 	return (rv);
402 }
403