netbsd/sys/arch/arm/arm/disksubr_acorn.c
2014-01-15 10:53:42 +01:00

403 lines
12 KiB
C

/* $NetBSD: disksubr_acorn.c,v 1.12 2013/03/09 16:02:25 christos Exp $ */
/*
* Copyright (c) 1998 Christopher G. Demetriou. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christopher G. Demetriou
* for the NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
*/
/*
* Copyright (c) 1995 Mark Brinicombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: disksubr_acorn.c,v 1.12 2013/03/09 16:02:25 christos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/buf.h>
#include <sys/disklabel.h>
static int filecore_checksum(u_char *);
/*
* static int filecore_checksum(u_char *bootblock)
*
* Calculates the filecore boot block checksum. This is used to validate
* a filecore boot block on the disk. If a boot block is validated then
* it is used to locate the partition table. If the boot block is not
* validated, it is assumed that the whole disk is NetBSD.
*
* The basic algorithm is:
*
* for (each byte in block, excluding checksum) {
* sum += byte;
* if (sum > 255)
* sum -= 255;
* }
*
* That's equivalent to summing all of the bytes in the block
* (excluding the checksum byte, of course), then calculating the
* checksum as "cksum = sum - ((sum - 1) / 255) * 255)". That
* expression may or may not yield a faster checksum function,
* but it's easier to reason about.
*
* Note that if you have a block filled with bytes of a single
* value "X" (regardless of that value!) and calculate the cksum
* of the block (excluding the checksum byte), you will _always_
* end up with a checksum of X. (Do the math; that can be derived
* from the checksum calculation function!) That means that
* blocks which contain bytes which all have the same value will
* always checksum properly. That's a _very_ unlikely occurence
* (probably impossible, actually) for a valid filecore boot block,
* so we treat such blocks as invalid.
*/
static int
filecore_checksum(u_char *bootblock)
{
u_char byte0, accum_diff;
u_int sum;
int i;
sum = 0;
accum_diff = 0;
byte0 = bootblock[0];
/*
* Sum the contents of the block, keeping track of whether
* or not all bytes are the same. If 'accum_diff' ends up
* being zero, all of the bytes are, in fact, the same.
*/
for (i = 0; i < 511; ++i) {
sum += bootblock[i];
accum_diff |= bootblock[i] ^ byte0;
}
/*
* Check to see if the checksum byte is the same as the
* rest of the bytes, too. (Note that if all of the bytes
* are the same except the checksum, a checksum compare
* won't succeed, but that's not our problem.)
*/
accum_diff |= bootblock[i] ^ byte0;
/* All bytes in block are the same; call it invalid. */
if (accum_diff == 0)
return (-1);
return (sum - ((sum - 1) / 255) * 255);
}
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)
{
struct filecore_bootblock *bb;
int heads;
int sectors;
int rv = 1;
int cyl, netbsdpartoff;
struct buf *bp;
#ifdef __GNUC__
netbsdpartoff = 0; /* XXX -Wuninitialized */
#endif
/* get a buffer and initialize it */
bp = geteblk((int)lp->d_secsize);
bp->b_dev = dev;
/* read the Acorn filecore boot block */
bp->b_blkno = FILECORE_BOOT_SECTOR;
bp->b_bcount = lp->d_secsize;
bp->b_flags |= B_READ;
bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
(*strat)(bp);
/*
* if successful, validate boot block and
* locate partition table
*/
if (biowait(bp)) {
*msgp = "filecore boot block I/O error";
goto out;
}
bb = (struct filecore_bootblock *)bp->b_data;
/* Validate boot block */
if (bb->checksum != filecore_checksum((u_char *)bb)) {
/*
* Invalid boot block so lets assume the
* entire disc is NetBSD
*/
rv = 0;
goto out;
}
/* Get some information from the boot block */
cyl = bb->partition_cyl_low + (bb->partition_cyl_high << 8);
heads = bb->heads;
sectors = bb->secspertrack;
/* Do we have a NETBSD partition table ? */
if (bb->partition_type == PARTITION_FORMAT_RISCBSD) {
#ifdef DEBUG_LABEL
printf("%s; heads = %d nsectors = %d\n",
__func__, heads, sectors);
#endif
netbsdpartoff = cyl * heads * sectors;
} else if (bb->partition_type == PARTITION_FORMAT_RISCIX) {
struct riscix_partition_table *rpt;
int loop;
/*
* We have a RISCiX partition table :-( groan
*
* Read the RISCiX partition table and see if
* there is a NetBSD partition
*/
bp->b_blkno = cyl * heads * sectors;
#ifdef DEBUG_LABEL
printf("%s: Found RiscIX partition table @ %08x\n",
__func__, bp->b_blkno);
#endif
bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
bp->b_bcount = lp->d_secsize;
bp->b_oflags &= ~(BO_DONE);
bp->b_flags |= B_READ;
(*strat)(bp);
/*
* if successful, locate disk label within block
* and validate
*/
if (biowait(bp)) {
*msgp = "disk label I/O error";
goto out;
}
rpt = (struct riscix_partition_table *)bp->b_data;
#ifdef DEBUG_LABEL
for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop)
printf("%s: p%d: %16s %08x %08x %08x\n", loop,
__func__, rpt->partitions[loop].rp_name,
rpt->partitions[loop].rp_start,
rpt->partitions[loop].rp_length,
rpt->partitions[loop].rp_type);
#endif
for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop) {
if (strcmp(rpt->partitions[loop].rp_name,
"RiscBSD") == 0 ||
strcmp(rpt->partitions[loop].rp_name,
"NetBSD") == 0 ||
strcmp(rpt->partitions[loop].rp_name,
"Empty:") == 0) {
netbsdpartoff =
rpt->partitions[loop].rp_start;
break;
}
}
if (loop == NRISCIX_PARTITIONS) {
*msgp = "NetBSD partition identifier string not found.";
goto out;
}
} else {
*msgp = "Invalid partition format";
goto out;
}
*cylp = cyl;
*netbsd_label_offp = netbsdpartoff;
*msgp = NULL;
out:
brelse(bp, 0);
return (rv);
}
/*
* Return -1 not found, 0 found positive errno
*/
int
filecore_label_locate(dev_t dev,
void (*strat)(struct buf *),
struct disklabel *lp,
struct cpu_disklabel *osdep,
int *cylp, int *netbsd_label_offp)
{
struct filecore_bootblock *bb;
int heads;
int sectors;
int rv;
int cyl, netbsdpartoff;
struct buf *bp;
/* get a buffer and initialize it */
bp = geteblk((int)lp->d_secsize);
bp->b_dev = dev;
/* read the filecore boot block */
#ifdef DEBUG_LABEL
printf("%s: Reading boot block\n", __func__);
#endif
bp->b_blkno = FILECORE_BOOT_SECTOR;
bp->b_bcount = lp->d_secsize;
bp->b_flags |= B_READ;
bp->b_cylinder = bp->b_blkno / lp->d_secpercyl;
(*strat)(bp);
/*
* if successful, validate boot block and locate
* partition table
*/
if ((rv = biowait(bp)) != 0) {
goto out;
}
bb = (struct filecore_bootblock *)bp->b_data;
rv = 0;
/* Validate boot block */
if (bb->checksum != filecore_checksum((u_char *)bb)) {
/*
* Invalid boot block so lets assume the
* entire disc is NetBSD
*/
#ifdef DEBUG_LABEL
printf("%s: Bad filecore boot block (incorrect checksum)\n",
__func__);
#endif
rv = -1;
goto out;
}
/* Do we have a NetBSD partition ? */
if (bb->partition_type != PARTITION_FORMAT_RISCBSD) {
#ifdef DEBUG_LABEL
printf("%s: Invalid partition format\n", __func__);
#endif
rv = EINVAL;
goto out;
}
cyl = bb->partition_cyl_low + (bb->partition_cyl_high << 8);
heads = bb->heads;
sectors = bb->secspertrack;
#ifdef DEBUG_LABEL
printf("%s: heads = %d nsectors = %d\n", __func__, heads, sectors);
#endif
netbsdpartoff = cyl * heads * sectors;
*cylp = cyl;
*netbsd_label_offp = netbsdpartoff;
out:
brelse(bp, 0);
return (rv);
}