projects/linux·blob master · refs

547 lines · 11.8 KiB

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