Commit 77a5fe3c authored by Russell King's avatar Russell King Committed by Russell King

[PATCH] Update Acorn partition parsing

This patch:
- re-enables cumana partition parsing
- adds eesox partition parsing
- makes the powertec partition parsing fail if sector 0 looks like
  a PC bios partition table

Rather than having a single "acorn_partition" parser for all these
types, we list them explicitly in check.c instead, along with some
explaination about why they're where they are.
parent 72e31e5c
...@@ -20,7 +20,17 @@ config ACORN_PARTITION ...@@ -20,7 +20,17 @@ config ACORN_PARTITION
help help
Support hard disks partitioned under Acorn operating systems. Support hard disks partitioned under Acorn operating systems.
# bool ' Cumana partition support' CONFIG_ACORN_PARTITION_CUMANA config ACORN_PARTITION_CUMANA
bool "Cumana partition support" if PARTITION_ADVANCED && ACORN_PARTITION
default y if !PARTITION_ADVANCED && ARCH_ACORN
help
Say Y here if you would like to use hard disks under Linux which
were partitioned using the Cumana interface on Acorn machines.
config ACORN_PARTITION_EESOX
bool "EESOX partition support" if PARTITION_ADVANCED && ACORN_PARTITION
default y if !PARTITION_ADVANCED && ARCH_ACORN
config ACORN_PARTITION_ICS config ACORN_PARTITION_ICS
bool "ICS partition support" if PARTITION_ADVANCED && ACORN_PARTITION bool "ICS partition support" if PARTITION_ADVANCED && ACORN_PARTITION
default y if !PARTITION_ADVANCED && ARCH_ACORN default y if !PARTITION_ADVANCED && ARCH_ACORN
......
...@@ -7,14 +7,25 @@ ...@@ -7,14 +7,25 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
* *
* Scan ADFS partitions on hard disk drives. * Scan ADFS partitions on hard disk drives. Unfortunately, there
* isn't a standard for partitioning drives on Acorn machines, so
* every single manufacturer of SCSI and IDE cards created their own
* method.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/adfs_fs.h>
#include "check.h" #include "check.h"
#include "acorn.h" #include "acorn.h"
/*
* Partition types. (Oh for reusability)
*/
#define PARTITION_RISCIX_MFM 1
#define PARTITION_RISCIX_SCSI 2
#define PARTITION_LINUX 9
static struct adfs_discrecord * static struct adfs_discrecord *
adfs_partition(struct parsed_partitions *state, char *name, char *data, adfs_partition(struct parsed_partitions *state, char *name, char *data,
unsigned long first_sector, int slot) unsigned long first_sector, int slot)
...@@ -40,6 +51,21 @@ adfs_partition(struct parsed_partitions *state, char *name, char *data, ...@@ -40,6 +51,21 @@ adfs_partition(struct parsed_partitions *state, char *name, char *data,
} }
#ifdef CONFIG_ACORN_PARTITION_RISCIX #ifdef CONFIG_ACORN_PARTITION_RISCIX
struct riscix_part {
__u32 start;
__u32 length;
__u32 one;
char name[16];
};
struct riscix_record {
__u32 magic;
#define RISCIX_MAGIC (0x4a657320)
__u32 date;
struct riscix_part part[8];
};
static int static int
riscix_partition(struct parsed_partitions *state, struct block_device *bdev, riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
unsigned long first_sect, int slot, unsigned long nr_sects) unsigned long first_sect, int slot, unsigned long nr_sects)
...@@ -81,6 +107,15 @@ riscix_partition(struct parsed_partitions *state, struct block_device *bdev, ...@@ -81,6 +107,15 @@ riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
} }
#endif #endif
#define LINUX_NATIVE_MAGIC 0xdeafa1de
#define LINUX_SWAP_MAGIC 0xdeafab1e
struct linux_part {
__u32 magic;
__u32 start_sect;
__u32 nr_sects;
};
static int static int
linux_partition(struct parsed_partitions *state, struct block_device *bdev, linux_partition(struct parsed_partitions *state, struct block_device *bdev,
unsigned long first_sect, int slot, unsigned long nr_sects) unsigned long first_sect, int slot, unsigned long nr_sects)
...@@ -114,7 +149,7 @@ linux_partition(struct parsed_partitions *state, struct block_device *bdev, ...@@ -114,7 +149,7 @@ linux_partition(struct parsed_partitions *state, struct block_device *bdev,
} }
#ifdef CONFIG_ACORN_PARTITION_CUMANA #ifdef CONFIG_ACORN_PARTITION_CUMANA
static int int
adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev) adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev)
{ {
unsigned long first_sector = 0; unsigned long first_sector = 0;
...@@ -126,7 +161,7 @@ adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev ...@@ -126,7 +161,7 @@ adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev
int slot = 1; int slot = 1;
/* /*
* Try Cumana style partitions - sector 3 contains ADFS boot block * Try Cumana style partitions - sector 6 contains ADFS boot block
* with pointer to next 'drive'. * with pointer to next 'drive'.
* *
* There are unknowns in this code - is the 'cylinder number' of the * There are unknowns in this code - is the 'cylinder number' of the
...@@ -206,7 +241,7 @@ adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev ...@@ -206,7 +241,7 @@ adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev
* hda1 = ADFS partition on first drive. * hda1 = ADFS partition on first drive.
* hda2 = non-ADFS partition. * hda2 = non-ADFS partition.
*/ */
static int int
adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev) adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev)
{ {
unsigned long start_sect, nr_sects, sectscyl, heads; unsigned long start_sect, nr_sects, sectscyl, heads;
...@@ -263,11 +298,18 @@ adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev) ...@@ -263,11 +298,18 @@ adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev)
break; break;
} }
} }
printk("\n");
return 1; return 1;
} }
#endif #endif
#ifdef CONFIG_ACORN_PARTITION_ICS #ifdef CONFIG_ACORN_PARTITION_ICS
struct ics_part {
__u32 start;
__s32 size;
};
static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block) static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block)
{ {
Sector sect; Sector sect;
...@@ -283,6 +325,22 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc ...@@ -283,6 +325,22 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc
return result; return result;
} }
/*
* Check for a valid ICS partition using the checksum.
*/
static inline int valid_ics_sector(const unsigned char *data)
{
unsigned long sum;
int i;
for (i = 0, sum = 0x50617274; i < 508; i++)
sum += data[i];
sum -= le32_to_cpu(*(__u32 *)(&data[508]));
return sum == 0;
}
/* /*
* Purpose: allocate ICS partitions. * Purpose: allocate ICS partitions.
* Params : hd - pointer to gendisk structure to store partition info. * Params : hd - pointer to gendisk structure to store partition info.
...@@ -293,15 +351,13 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc ...@@ -293,15 +351,13 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc
* hda2 = ADFS partition 1 on first drive. * hda2 = ADFS partition 1 on first drive.
* ..etc.. * ..etc..
*/ */
static int int
adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev)
{ {
Sector sect; const unsigned char *data;
unsigned char *data; const struct ics_part *p;
unsigned long sum;
unsigned int i;
int slot; int slot;
struct ics_part *p; Sector sect;
/* /*
* Try ICS style partitions - sector 0 contains partition info. * Try ICS style partitions - sector 0 contains partition info.
...@@ -310,33 +366,33 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) ...@@ -310,33 +366,33 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev)
if (!data) if (!data)
return -1; return -1;
/* if (!valid_ics_sector(data)) {
* check for a valid checksum
*/
for (i = 0, sum = 0x50617274; i < 508; i++)
sum += data[i];
sum -= le32_to_cpu(*(__u32 *)(&data[508]));
if (sum) {
put_dev_sector(sect); put_dev_sector(sect);
return 0; /* not ICS partition table */ return 0;
} }
printk(" [ICS]"); printk(" [ICS]");
for (slot = 1, p = (struct ics_part *)data; p->size; p++) { for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
u32 start = le32_to_cpu(p->start); u32 start = le32_to_cpu(p->start);
u32 size = le32_to_cpu(p->size); s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
if (slot == state->limit) if (slot == state->limit)
break; break;
/*
* Negative sizes tell the RISC OS ICS driver to ignore
* this partition - in effect it says that this does not
* contain an ADFS filesystem.
*/
if (size < 0) { if (size < 0) {
size = -size; size = -size;
/* /*
* We use the first sector to identify what type * Our own extension - We use the first sector
* this partition is... * of the partition to identify what type this
* partition is. We must not make this visible
* to the filesystem.
*/ */
if (size > 1 && adfspart_check_ICSLinux(bdev, start)) { if (size > 1 && adfspart_check_ICSLinux(bdev, start)) {
start += 1; start += 1;
...@@ -349,10 +405,39 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) ...@@ -349,10 +405,39 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev)
} }
put_dev_sector(sect); put_dev_sector(sect);
printk("\n");
return 1; return 1;
} }
#endif #endif
#ifdef CONFIG_ACORN_PARTITION_POWERTEC
struct ptec_part {
__u32 unused1;
__u32 unused2;
__u32 start;
__u32 size;
__u32 unused5;
char type[8];
};
static inline int valid_ptec_sector(const unsigned char *data)
{
unsigned char checksum = 0x2a;
int i;
/*
* If it looks like a PC/BIOS partition, then it
* probably isn't PowerTec.
*/
if (data[510] == 0x55 && data[511] == 0xaa)
return 0;
for (i = 0; i < 511; i++)
checksum += data[i];
return checksum == data[511];
}
/* /*
* Purpose: allocate ICS partitions. * Purpose: allocate ICS partitions.
* Params : hd - pointer to gendisk structure to store partition info. * Params : hd - pointer to gendisk structure to store partition info.
...@@ -363,14 +448,12 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) ...@@ -363,14 +448,12 @@ adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev)
* hda2 = ADFS partition 1 on first drive. * hda2 = ADFS partition 1 on first drive.
* ..etc.. * ..etc..
*/ */
#ifdef CONFIG_ACORN_PARTITION_POWERTEC int
static int
adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev) adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev)
{ {
Sector sect; Sector sect;
unsigned char *data; const unsigned char *data;
struct ptec_partition *p; const struct ptec_part *p;
unsigned char checksum;
int slot = 1; int slot = 1;
int i; int i;
...@@ -378,17 +461,14 @@ adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bd ...@@ -378,17 +461,14 @@ adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bd
if (!data) if (!data)
return -1; return -1;
for (checksum = 0x2a, i = 0; i < 511; i++) if (!valid_ptec_sector(data)) {
checksum += data[i];
if (checksum != data[511]) {
put_dev_sector(sect); put_dev_sector(sect);
return 0; return 0;
} }
printk(" [POWERTEC]"); printk(" [POWERTEC]");
for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) { for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
u32 start = le32_to_cpu(p->start); u32 start = le32_to_cpu(p->start);
u32 size = le32_to_cpu(p->size); u32 size = le32_to_cpu(p->size);
...@@ -397,46 +477,81 @@ adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bd ...@@ -397,46 +477,81 @@ adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bd
} }
put_dev_sector(sect); put_dev_sector(sect);
printk("\n");
return 1; return 1;
} }
#endif #endif
static int (*partfn[])(struct parsed_partitions *, struct block_device *) = { #ifdef CONFIG_ACORN_PARTITION_EESOX
#ifdef CONFIG_ACORN_PARTITION_ICS struct eesox_part {
adfspart_check_ICS, char magic[6];
#endif char name[10];
#ifdef CONFIG_ACORN_PARTITION_POWERTEC u32 start;
adfspart_check_POWERTEC, u32 unused6;
#endif u32 unused7;
#ifdef CONFIG_ACORN_PARTITION_CUMANA u32 unused8;
adfspart_check_CUMANA,
#endif
#ifdef CONFIG_ACORN_PARTITION_ADFS
adfspart_check_ADFS,
#endif
NULL
}; };
/* /*
* Purpose: initialise all the partitions on an ADFS drive. * Guess who created this format?
* These may be other ADFS partitions or a Linux/RiscBSD/RISCiX */
* partition. static const char eesox_name[] = {
'N', 'e', 'i', 'l', ' ',
'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
};
/*
* EESOX SCSI partition format.
* *
* Params : hd - pointer to gendisk structure * This is a goddamned awful partition format. We don't seem to store
* dev - device number to access * the size of the partition in this table, only the start addresses.
* *
* Returns: -1 on error, 0 if not ADFS format, 1 if ok. * There are two possibilities where the size comes from:
* 1. The individual ADFS boot block entries that are placed on the disk.
* 2. The start address of the next entry.
*/ */
int acorn_partition(struct parsed_partitions *state, struct block_device *bdev) int
adfspart_check_EESOX(struct parsed_partitions *state, struct block_device *bdev)
{ {
int i; Sector sect;
const unsigned char *data;
unsigned char buffer[256];
struct eesox_part *p;
u32 start = 0;
int i, slot = 1;
for (i = 0; partfn[i]; i++) { data = read_dev_sector(bdev, 7, &sect);
int r = partfn[i](state, bdev); if (!data)
if (r) { return -1;
if (r > 0)
printk("\n"); /*
return r; * "Decrypt" the partition table. God knows why...
*/
for (i = 0; i < 256; i++)
buffer[i] = data[i] ^ eesox_name[i & 15];
put_dev_sector(sect);
for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
u32 next;
if (memcmp(p->magic, "Eesox", 6))
break;
next = le32_to_cpu(p->start) + first_sector;
if (i)
put_partition(state, slot++, start, next - start);
start = next;
} }
if (i != 0) {
unsigned long size;
size = hd->part[minor(to_kdev_t(bdev->bd_dev))].nr_sects;
add_gd_partition(hd, minor++, start, size - start);
printk("\n");
} }
return 0;
return i ? 1 : 0;
} }
#endif
/* /*
* fs/partitions/acorn.h * linux/fs/partitions/acorn.h
* *
* Copyright (C) 1996-1998 Russell King * Copyright (C) 1996-2001 Russell King.
*/ *
#include <linux/adfs_fs.h> * I _hate_ this partitioning mess - why can't we have one defined
* format, and everyone stick to it?
/*
* Partition types. (Oh for reusability)
*/ */
#define PARTITION_RISCIX_MFM 1
#define PARTITION_RISCIX_SCSI 2
#define PARTITION_LINUX 9
struct riscix_part {
__u32 start;
__u32 length;
__u32 one;
char name[16];
};
struct riscix_record {
__u32 magic;
#define RISCIX_MAGIC (0x4a657320)
__u32 date;
struct riscix_part part[8];
};
#define LINUX_NATIVE_MAGIC 0xdeafa1de
#define LINUX_SWAP_MAGIC 0xdeafab1e
struct linux_part {
__u32 magic;
__u32 start_sect;
__u32 nr_sects;
};
struct ics_part {
__u32 start;
__s32 size;
};
struct ptec_partition {
__u32 unused1;
__u32 unused2;
__u32 start;
__u32 size;
__u32 unused5;
char type[8];
};
int acorn_partition(struct parsed_partitions *state, struct block_device *bdev); int adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev);
int adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev);
int adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev);
int adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev);
int adfspart_check_EESOX(struct parsed_partitions *state, struct block_device *bdev);
...@@ -45,9 +45,33 @@ extern void md_autodetect_dev(dev_t dev); ...@@ -45,9 +45,33 @@ extern void md_autodetect_dev(dev_t dev);
int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
static int (*check_part[])(struct parsed_partitions *, struct block_device *) = { static int (*check_part[])(struct parsed_partitions *, struct block_device *) = {
#ifdef CONFIG_ACORN_PARTITION /*
acorn_partition, * Probe partition formats with tables at disk address 0
* that also have an ADFS boot block at 0xdc0.
*/
#ifdef CONFIG_ACORN_PARTITION_ICS
adfspart_check_ICS,
#endif
#ifdef CONFIG_ACORN_PARTITION_POWERTEC
adfspart_check_POWERTEC,
#endif
#ifdef CONFIG_ACORN_PARTITION_EESOX
adfspart_check_EESOX,
#endif
/*
* Now move on to formats that only have partition info at
* disk address 0xdc0. Since these may also have stale
* PC/BIOS partition tables, they need to come before
* the msdos entry.
*/
#ifdef CONFIG_ACORN_PARTITION_CUMANA
adfspart_check_CUMANA,
#endif #endif
#ifdef CONFIG_ACORN_PARTITION_ADFS
adfspart_check_ADFS,
#endif
#ifdef CONFIG_EFI_PARTITION #ifdef CONFIG_EFI_PARTITION
efi_partition, /* this must come before msdos */ efi_partition, /* this must come before msdos */
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment