brintos

brintos / linux-shallow public Read only

0
0
Text · 12.0 KiB · d2fc122 Raw
551 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  Copyright (c) 1996-2000 Russell King.4 *5 *  Scan ADFS partitions on hard disk drives.  Unfortunately, there6 *  isn't a standard for partitioning drives on Acorn machines, so7 *  every single manufacturer of SCSI and IDE cards created their own8 *  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	119#define PARTITION_RISCIX_SCSI	220#define PARTITION_LINUX		921 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#endif51 52#ifdef CONFIG_ACORN_PARTITION_RISCIX53 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#endif112#endif113 114#define LINUX_NATIVE_MAGIC 0xdeafa1de115#define LINUX_SWAP_MAGIC   0xdeafab1e116 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#endif157 158#ifdef CONFIG_ACORN_PARTITION_CUMANA159int 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 block171	 * with pointer to next 'drive'.172	 *173	 * There are unknowns in this code - is the 'cylinder number' of the174	 * next partition relative to the start of this one - I'm assuming175	 * it is.176	 *177	 * Also, which ID did Cumana use?178	 *179	 * This is totally unfinished, and will require more work to get it180	 * 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_RISCIX216		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#endif222 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#endif236 237#ifdef CONFIG_ACORN_PARTITION_ADFS238/*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 drive247 *	    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_RISCIX283		case PARTITION_RISCIX_SCSI:284		case PARTITION_RISCIX_MFM:285			riscix_partition(state, start_sect, slot,286						nr_sects);287			break;288#endif289 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#endif300 301#ifdef CONFIG_ACORN_PARTITION_ICS302 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 drive346 *	    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 ignore380		 * this partition - in effect it says that this does not381		 * contain an ADFS filesystem.382		 */383		if (size < 0) {384			size = -size;385 386			/*387			 * Our own extension - We use the first sector388			 * of the partition to identify what type this389			 * partition is.  We must not make this visible390			 * 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#endif407 408#ifdef CONFIG_ACORN_PARTITION_POWERTEC409struct 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 it425	 * 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 drive442 *	    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#endif478 479#ifdef CONFIG_ACORN_PARTITION_EESOX480struct 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 store501 * 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#endif551