cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

acorn.c (12321B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  Copyright (c) 1996-2000 Russell King.
      4 *
      5 *  Scan ADFS partitions on hard disk drives.  Unfortunately, there
      6 *  isn't a standard for partitioning drives on Acorn machines, so
      7 *  every single manufacturer of SCSI and IDE cards created their own
      8 *  method.
      9 */
     10#include <linux/buffer_head.h>
     11#include <linux/adfs_fs.h>
     12
     13#include "check.h"
     14
     15/*
     16 * Partition types. (Oh for reusability)
     17 */
     18#define PARTITION_RISCIX_MFM	1
     19#define PARTITION_RISCIX_SCSI	2
     20#define PARTITION_LINUX		9
     21
     22#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
     23	defined(CONFIG_ACORN_PARTITION_ADFS)
     24static struct adfs_discrecord *
     25adfs_partition(struct parsed_partitions *state, char *name, char *data,
     26	       unsigned long first_sector, int slot)
     27{
     28	struct adfs_discrecord *dr;
     29	unsigned int nr_sects;
     30
     31	if (adfs_checkbblk(data))
     32		return NULL;
     33
     34	dr = (struct adfs_discrecord *)(data + 0x1c0);
     35
     36	if (dr->disc_size == 0 && dr->disc_size_high == 0)
     37		return NULL;
     38
     39	nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
     40		   (le32_to_cpu(dr->disc_size) >> 9);
     41
     42	if (name) {
     43		strlcat(state->pp_buf, " [", PAGE_SIZE);
     44		strlcat(state->pp_buf, name, PAGE_SIZE);
     45		strlcat(state->pp_buf, "]", PAGE_SIZE);
     46	}
     47	put_partition(state, slot, first_sector, nr_sects);
     48	return dr;
     49}
     50#endif
     51
     52#ifdef CONFIG_ACORN_PARTITION_RISCIX
     53
     54struct riscix_part {
     55	__le32	start;
     56	__le32	length;
     57	__le32	one;
     58	char	name[16];
     59};
     60
     61struct riscix_record {
     62	__le32	magic;
     63#define RISCIX_MAGIC	cpu_to_le32(0x4a657320)
     64	__le32	date;
     65	struct riscix_part part[8];
     66};
     67
     68#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
     69	defined(CONFIG_ACORN_PARTITION_ADFS)
     70static int riscix_partition(struct parsed_partitions *state,
     71			    unsigned long first_sect, int slot,
     72			    unsigned long nr_sects)
     73{
     74	Sector sect;
     75	struct riscix_record *rr;
     76	
     77	rr = read_part_sector(state, first_sect, &sect);
     78	if (!rr)
     79		return -1;
     80
     81	strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);
     82
     83
     84	if (rr->magic == RISCIX_MAGIC) {
     85		unsigned long size = nr_sects > 2 ? 2 : nr_sects;
     86		int part;
     87
     88		strlcat(state->pp_buf, " <", PAGE_SIZE);
     89
     90		put_partition(state, slot++, first_sect, size);
     91		for (part = 0; part < 8; part++) {
     92			if (rr->part[part].one &&
     93			    memcmp(rr->part[part].name, "All\0", 4)) {
     94				put_partition(state, slot++,
     95					le32_to_cpu(rr->part[part].start),
     96					le32_to_cpu(rr->part[part].length));
     97				strlcat(state->pp_buf, "(", PAGE_SIZE);
     98				strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);
     99				strlcat(state->pp_buf, ")", PAGE_SIZE);
    100			}
    101		}
    102
    103		strlcat(state->pp_buf, " >\n", PAGE_SIZE);
    104	} else {
    105		put_partition(state, slot++, first_sect, nr_sects);
    106	}
    107
    108	put_dev_sector(sect);
    109	return slot;
    110}
    111#endif
    112#endif
    113
    114#define LINUX_NATIVE_MAGIC 0xdeafa1de
    115#define LINUX_SWAP_MAGIC   0xdeafab1e
    116
    117struct linux_part {
    118	__le32 magic;
    119	__le32 start_sect;
    120	__le32 nr_sects;
    121};
    122
    123#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
    124	defined(CONFIG_ACORN_PARTITION_ADFS)
    125static int linux_partition(struct parsed_partitions *state,
    126			   unsigned long first_sect, int slot,
    127			   unsigned long nr_sects)
    128{
    129	Sector sect;
    130	struct linux_part *linuxp;
    131	unsigned long size = nr_sects > 2 ? 2 : nr_sects;
    132
    133	strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);
    134
    135	put_partition(state, slot++, first_sect, size);
    136
    137	linuxp = read_part_sector(state, first_sect, &sect);
    138	if (!linuxp)
    139		return -1;
    140
    141	strlcat(state->pp_buf, " <", PAGE_SIZE);
    142	while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
    143	       linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
    144		if (slot == state->limit)
    145			break;
    146		put_partition(state, slot++, first_sect +
    147				 le32_to_cpu(linuxp->start_sect),
    148				 le32_to_cpu(linuxp->nr_sects));
    149		linuxp ++;
    150	}
    151	strlcat(state->pp_buf, " >", PAGE_SIZE);
    152
    153	put_dev_sector(sect);
    154	return slot;
    155}
    156#endif
    157
    158#ifdef CONFIG_ACORN_PARTITION_CUMANA
    159int adfspart_check_CUMANA(struct parsed_partitions *state)
    160{
    161	unsigned long first_sector = 0;
    162	unsigned int start_blk = 0;
    163	Sector sect;
    164	unsigned char *data;
    165	char *name = "CUMANA/ADFS";
    166	int first = 1;
    167	int slot = 1;
    168
    169	/*
    170	 * Try Cumana style partitions - sector 6 contains ADFS boot block
    171	 * with pointer to next 'drive'.
    172	 *
    173	 * There are unknowns in this code - is the 'cylinder number' of the
    174	 * next partition relative to the start of this one - I'm assuming
    175	 * it is.
    176	 *
    177	 * Also, which ID did Cumana use?
    178	 *
    179	 * This is totally unfinished, and will require more work to get it
    180	 * going. Hence it is totally untested.
    181	 */
    182	do {
    183		struct adfs_discrecord *dr;
    184		unsigned int nr_sects;
    185
    186		data = read_part_sector(state, start_blk * 2 + 6, &sect);
    187		if (!data)
    188			return -1;
    189
    190		if (slot == state->limit)
    191			break;
    192
    193		dr = adfs_partition(state, name, data, first_sector, slot++);
    194		if (!dr)
    195			break;
    196
    197		name = NULL;
    198
    199		nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
    200			   (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
    201			   dr->secspertrack;
    202
    203		if (!nr_sects)
    204			break;
    205
    206		first = 0;
    207		first_sector += nr_sects;
    208		start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
    209		nr_sects = 0; /* hmm - should be partition size */
    210
    211		switch (data[0x1fc] & 15) {
    212		case 0: /* No partition / ADFS? */
    213			break;
    214
    215#ifdef CONFIG_ACORN_PARTITION_RISCIX
    216		case PARTITION_RISCIX_SCSI:
    217			/* RISCiX - we don't know how to find the next one. */
    218			slot = riscix_partition(state, first_sector, slot,
    219						nr_sects);
    220			break;
    221#endif
    222
    223		case PARTITION_LINUX:
    224			slot = linux_partition(state, first_sector, slot,
    225					       nr_sects);
    226			break;
    227		}
    228		put_dev_sector(sect);
    229		if (slot == -1)
    230			return -1;
    231	} while (1);
    232	put_dev_sector(sect);
    233	return first ? 0 : 1;
    234}
    235#endif
    236
    237#ifdef CONFIG_ACORN_PARTITION_ADFS
    238/*
    239 * Purpose: allocate ADFS partitions.
    240 *
    241 * Params : hd		- pointer to gendisk structure to store partition info.
    242 *	    dev		- device number to access.
    243 *
    244 * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok.
    245 *
    246 * Alloc  : hda  = whole drive
    247 *	    hda1 = ADFS partition on first drive.
    248 *	    hda2 = non-ADFS partition.
    249 */
    250int adfspart_check_ADFS(struct parsed_partitions *state)
    251{
    252	unsigned long start_sect, nr_sects, sectscyl, heads;
    253	Sector sect;
    254	unsigned char *data;
    255	struct adfs_discrecord *dr;
    256	unsigned char id;
    257	int slot = 1;
    258
    259	data = read_part_sector(state, 6, &sect);
    260	if (!data)
    261		return -1;
    262
    263	dr = adfs_partition(state, "ADFS", data, 0, slot++);
    264	if (!dr) {
    265		put_dev_sector(sect);
    266    		return 0;
    267	}
    268
    269	heads = dr->heads + ((dr->lowsector >> 6) & 1);
    270	sectscyl = dr->secspertrack * heads;
    271	start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
    272	id = data[0x1fc] & 15;
    273	put_dev_sector(sect);
    274
    275	/*
    276	 * Work out start of non-adfs partition.
    277	 */
    278	nr_sects = get_capacity(state->disk) - start_sect;
    279
    280	if (start_sect) {
    281		switch (id) {
    282#ifdef CONFIG_ACORN_PARTITION_RISCIX
    283		case PARTITION_RISCIX_SCSI:
    284		case PARTITION_RISCIX_MFM:
    285			riscix_partition(state, start_sect, slot,
    286						nr_sects);
    287			break;
    288#endif
    289
    290		case PARTITION_LINUX:
    291			linux_partition(state, start_sect, slot,
    292					       nr_sects);
    293			break;
    294		}
    295	}
    296	strlcat(state->pp_buf, "\n", PAGE_SIZE);
    297	return 1;
    298}
    299#endif
    300
    301#ifdef CONFIG_ACORN_PARTITION_ICS
    302
    303struct ics_part {
    304	__le32 start;
    305	__le32 size;
    306};
    307
    308static int adfspart_check_ICSLinux(struct parsed_partitions *state,
    309				   unsigned long block)
    310{
    311	Sector sect;
    312	unsigned char *data = read_part_sector(state, block, &sect);
    313	int result = 0;
    314
    315	if (data) {
    316		if (memcmp(data, "LinuxPart", 9) == 0)
    317			result = 1;
    318		put_dev_sector(sect);
    319	}
    320
    321	return result;
    322}
    323
    324/*
    325 * Check for a valid ICS partition using the checksum.
    326 */
    327static inline int valid_ics_sector(const unsigned char *data)
    328{
    329	unsigned long sum;
    330	int i;
    331
    332	for (i = 0, sum = 0x50617274; i < 508; i++)
    333		sum += data[i];
    334
    335	sum -= le32_to_cpu(*(__le32 *)(&data[508]));
    336
    337	return sum == 0;
    338}
    339
    340/*
    341 * Purpose: allocate ICS partitions.
    342 * Params : hd		- pointer to gendisk structure to store partition info.
    343 *	    dev		- device number to access.
    344 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
    345 * Alloc  : hda  = whole drive
    346 *	    hda1 = ADFS partition 0 on first drive.
    347 *	    hda2 = ADFS partition 1 on first drive.
    348 *		..etc..
    349 */
    350int adfspart_check_ICS(struct parsed_partitions *state)
    351{
    352	const unsigned char *data;
    353	const struct ics_part *p;
    354	int slot;
    355	Sector sect;
    356
    357	/*
    358	 * Try ICS style partitions - sector 0 contains partition info.
    359	 */
    360	data = read_part_sector(state, 0, &sect);
    361	if (!data)
    362	    	return -1;
    363
    364	if (!valid_ics_sector(data)) {
    365	    	put_dev_sector(sect);
    366		return 0;
    367	}
    368
    369	strlcat(state->pp_buf, " [ICS]", PAGE_SIZE);
    370
    371	for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
    372		u32 start = le32_to_cpu(p->start);
    373		s32 size = le32_to_cpu(p->size); /* yes, it's signed. */
    374
    375		if (slot == state->limit)
    376			break;
    377
    378		/*
    379		 * Negative sizes tell the RISC OS ICS driver to ignore
    380		 * this partition - in effect it says that this does not
    381		 * contain an ADFS filesystem.
    382		 */
    383		if (size < 0) {
    384			size = -size;
    385
    386			/*
    387			 * Our own extension - We use the first sector
    388			 * of the partition to identify what type this
    389			 * partition is.  We must not make this visible
    390			 * to the filesystem.
    391			 */
    392			if (size > 1 && adfspart_check_ICSLinux(state, start)) {
    393				start += 1;
    394				size -= 1;
    395			}
    396		}
    397
    398		if (size)
    399			put_partition(state, slot++, start, size);
    400	}
    401
    402	put_dev_sector(sect);
    403	strlcat(state->pp_buf, "\n", PAGE_SIZE);
    404	return 1;
    405}
    406#endif
    407
    408#ifdef CONFIG_ACORN_PARTITION_POWERTEC
    409struct ptec_part {
    410	__le32 unused1;
    411	__le32 unused2;
    412	__le32 start;
    413	__le32 size;
    414	__le32 unused5;
    415	char type[8];
    416};
    417
    418static inline int valid_ptec_sector(const unsigned char *data)
    419{
    420	unsigned char checksum = 0x2a;
    421	int i;
    422
    423	/*
    424	 * If it looks like a PC/BIOS partition, then it
    425	 * probably isn't PowerTec.
    426	 */
    427	if (data[510] == 0x55 && data[511] == 0xaa)
    428		return 0;
    429
    430	for (i = 0; i < 511; i++)
    431		checksum += data[i];
    432
    433	return checksum == data[511];
    434}
    435
    436/*
    437 * Purpose: allocate ICS partitions.
    438 * Params : hd		- pointer to gendisk structure to store partition info.
    439 *	    dev		- device number to access.
    440 * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok.
    441 * Alloc  : hda  = whole drive
    442 *	    hda1 = ADFS partition 0 on first drive.
    443 *	    hda2 = ADFS partition 1 on first drive.
    444 *		..etc..
    445 */
    446int adfspart_check_POWERTEC(struct parsed_partitions *state)
    447{
    448	Sector sect;
    449	const unsigned char *data;
    450	const struct ptec_part *p;
    451	int slot = 1;
    452	int i;
    453
    454	data = read_part_sector(state, 0, &sect);
    455	if (!data)
    456		return -1;
    457
    458	if (!valid_ptec_sector(data)) {
    459		put_dev_sector(sect);
    460		return 0;
    461	}
    462
    463	strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE);
    464
    465	for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
    466		u32 start = le32_to_cpu(p->start);
    467		u32 size = le32_to_cpu(p->size);
    468
    469		if (size)
    470			put_partition(state, slot++, start, size);
    471	}
    472
    473	put_dev_sector(sect);
    474	strlcat(state->pp_buf, "\n", PAGE_SIZE);
    475	return 1;
    476}
    477#endif
    478
    479#ifdef CONFIG_ACORN_PARTITION_EESOX
    480struct eesox_part {
    481	char	magic[6];
    482	char	name[10];
    483	__le32	start;
    484	__le32	unused6;
    485	__le32	unused7;
    486	__le32	unused8;
    487};
    488
    489/*
    490 * Guess who created this format?
    491 */
    492static const char eesox_name[] = {
    493	'N', 'e', 'i', 'l', ' ',
    494	'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
    495};
    496
    497/*
    498 * EESOX SCSI partition format.
    499 *
    500 * This is a goddamned awful partition format.  We don't seem to store
    501 * the size of the partition in this table, only the start addresses.
    502 *
    503 * There are two possibilities where the size comes from:
    504 *  1. The individual ADFS boot block entries that are placed on the disk.
    505 *  2. The start address of the next entry.
    506 */
    507int adfspart_check_EESOX(struct parsed_partitions *state)
    508{
    509	Sector sect;
    510	const unsigned char *data;
    511	unsigned char buffer[256];
    512	struct eesox_part *p;
    513	sector_t start = 0;
    514	int i, slot = 1;
    515
    516	data = read_part_sector(state, 7, &sect);
    517	if (!data)
    518		return -1;
    519
    520	/*
    521	 * "Decrypt" the partition table.  God knows why...
    522	 */
    523	for (i = 0; i < 256; i++)
    524		buffer[i] = data[i] ^ eesox_name[i & 15];
    525
    526	put_dev_sector(sect);
    527
    528	for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
    529		sector_t next;
    530
    531		if (memcmp(p->magic, "Eesox", 6))
    532			break;
    533
    534		next = le32_to_cpu(p->start);
    535		if (i)
    536			put_partition(state, slot++, start, next - start);
    537		start = next;
    538	}
    539
    540	if (i != 0) {
    541		sector_t size;
    542
    543		size = get_capacity(state->disk);
    544		put_partition(state, slot++, start, size - start);
    545		strlcat(state->pp_buf, "\n", PAGE_SIZE);
    546	}
    547
    548	return i ? 1 : 0;
    549}
    550#endif