0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/buffer_head.h>
0011 #include <linux/adfs_fs.h>
0012
0013 #include "check.h"
0014
0015
0016
0017
0018 #define PARTITION_RISCIX_MFM 1
0019 #define PARTITION_RISCIX_SCSI 2
0020 #define PARTITION_LINUX 9
0021
0022 #if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
0023 defined(CONFIG_ACORN_PARTITION_ADFS)
0024 static struct adfs_discrecord *
0025 adfs_partition(struct parsed_partitions *state, char *name, char *data,
0026 unsigned long first_sector, int slot)
0027 {
0028 struct adfs_discrecord *dr;
0029 unsigned int nr_sects;
0030
0031 if (adfs_checkbblk(data))
0032 return NULL;
0033
0034 dr = (struct adfs_discrecord *)(data + 0x1c0);
0035
0036 if (dr->disc_size == 0 && dr->disc_size_high == 0)
0037 return NULL;
0038
0039 nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) |
0040 (le32_to_cpu(dr->disc_size) >> 9);
0041
0042 if (name) {
0043 strlcat(state->pp_buf, " [", PAGE_SIZE);
0044 strlcat(state->pp_buf, name, PAGE_SIZE);
0045 strlcat(state->pp_buf, "]", PAGE_SIZE);
0046 }
0047 put_partition(state, slot, first_sector, nr_sects);
0048 return dr;
0049 }
0050 #endif
0051
0052 #ifdef CONFIG_ACORN_PARTITION_RISCIX
0053
0054 struct riscix_part {
0055 __le32 start;
0056 __le32 length;
0057 __le32 one;
0058 char name[16];
0059 };
0060
0061 struct riscix_record {
0062 __le32 magic;
0063 #define RISCIX_MAGIC cpu_to_le32(0x4a657320)
0064 __le32 date;
0065 struct riscix_part part[8];
0066 };
0067
0068 #if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
0069 defined(CONFIG_ACORN_PARTITION_ADFS)
0070 static int riscix_partition(struct parsed_partitions *state,
0071 unsigned long first_sect, int slot,
0072 unsigned long nr_sects)
0073 {
0074 Sector sect;
0075 struct riscix_record *rr;
0076
0077 rr = read_part_sector(state, first_sect, §);
0078 if (!rr)
0079 return -1;
0080
0081 strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE);
0082
0083
0084 if (rr->magic == RISCIX_MAGIC) {
0085 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
0086 int part;
0087
0088 strlcat(state->pp_buf, " <", PAGE_SIZE);
0089
0090 put_partition(state, slot++, first_sect, size);
0091 for (part = 0; part < 8; part++) {
0092 if (rr->part[part].one &&
0093 memcmp(rr->part[part].name, "All\0", 4)) {
0094 put_partition(state, slot++,
0095 le32_to_cpu(rr->part[part].start),
0096 le32_to_cpu(rr->part[part].length));
0097 strlcat(state->pp_buf, "(", PAGE_SIZE);
0098 strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE);
0099 strlcat(state->pp_buf, ")", PAGE_SIZE);
0100 }
0101 }
0102
0103 strlcat(state->pp_buf, " >\n", PAGE_SIZE);
0104 } else {
0105 put_partition(state, slot++, first_sect, nr_sects);
0106 }
0107
0108 put_dev_sector(sect);
0109 return slot;
0110 }
0111 #endif
0112 #endif
0113
0114 #define LINUX_NATIVE_MAGIC 0xdeafa1de
0115 #define LINUX_SWAP_MAGIC 0xdeafab1e
0116
0117 struct linux_part {
0118 __le32 magic;
0119 __le32 start_sect;
0120 __le32 nr_sects;
0121 };
0122
0123 #if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
0124 defined(CONFIG_ACORN_PARTITION_ADFS)
0125 static int linux_partition(struct parsed_partitions *state,
0126 unsigned long first_sect, int slot,
0127 unsigned long nr_sects)
0128 {
0129 Sector sect;
0130 struct linux_part *linuxp;
0131 unsigned long size = nr_sects > 2 ? 2 : nr_sects;
0132
0133 strlcat(state->pp_buf, " [Linux]", PAGE_SIZE);
0134
0135 put_partition(state, slot++, first_sect, size);
0136
0137 linuxp = read_part_sector(state, first_sect, §);
0138 if (!linuxp)
0139 return -1;
0140
0141 strlcat(state->pp_buf, " <", PAGE_SIZE);
0142 while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) ||
0143 linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) {
0144 if (slot == state->limit)
0145 break;
0146 put_partition(state, slot++, first_sect +
0147 le32_to_cpu(linuxp->start_sect),
0148 le32_to_cpu(linuxp->nr_sects));
0149 linuxp ++;
0150 }
0151 strlcat(state->pp_buf, " >", PAGE_SIZE);
0152
0153 put_dev_sector(sect);
0154 return slot;
0155 }
0156 #endif
0157
0158 #ifdef CONFIG_ACORN_PARTITION_CUMANA
0159 int adfspart_check_CUMANA(struct parsed_partitions *state)
0160 {
0161 unsigned long first_sector = 0;
0162 unsigned int start_blk = 0;
0163 Sector sect;
0164 unsigned char *data;
0165 char *name = "CUMANA/ADFS";
0166 int first = 1;
0167 int slot = 1;
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182 do {
0183 struct adfs_discrecord *dr;
0184 unsigned int nr_sects;
0185
0186 data = read_part_sector(state, start_blk * 2 + 6, §);
0187 if (!data)
0188 return -1;
0189
0190 if (slot == state->limit)
0191 break;
0192
0193 dr = adfs_partition(state, name, data, first_sector, slot++);
0194 if (!dr)
0195 break;
0196
0197 name = NULL;
0198
0199 nr_sects = (data[0x1fd] + (data[0x1fe] << 8)) *
0200 (dr->heads + (dr->lowsector & 0x40 ? 1 : 0)) *
0201 dr->secspertrack;
0202
0203 if (!nr_sects)
0204 break;
0205
0206 first = 0;
0207 first_sector += nr_sects;
0208 start_blk += nr_sects >> (BLOCK_SIZE_BITS - 9);
0209 nr_sects = 0;
0210
0211 switch (data[0x1fc] & 15) {
0212 case 0:
0213 break;
0214
0215 #ifdef CONFIG_ACORN_PARTITION_RISCIX
0216 case PARTITION_RISCIX_SCSI:
0217
0218 slot = riscix_partition(state, first_sector, slot,
0219 nr_sects);
0220 break;
0221 #endif
0222
0223 case PARTITION_LINUX:
0224 slot = linux_partition(state, first_sector, slot,
0225 nr_sects);
0226 break;
0227 }
0228 put_dev_sector(sect);
0229 if (slot == -1)
0230 return -1;
0231 } while (1);
0232 put_dev_sector(sect);
0233 return first ? 0 : 1;
0234 }
0235 #endif
0236
0237 #ifdef CONFIG_ACORN_PARTITION_ADFS
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250 int adfspart_check_ADFS(struct parsed_partitions *state)
0251 {
0252 unsigned long start_sect, nr_sects, sectscyl, heads;
0253 Sector sect;
0254 unsigned char *data;
0255 struct adfs_discrecord *dr;
0256 unsigned char id;
0257 int slot = 1;
0258
0259 data = read_part_sector(state, 6, §);
0260 if (!data)
0261 return -1;
0262
0263 dr = adfs_partition(state, "ADFS", data, 0, slot++);
0264 if (!dr) {
0265 put_dev_sector(sect);
0266 return 0;
0267 }
0268
0269 heads = dr->heads + ((dr->lowsector >> 6) & 1);
0270 sectscyl = dr->secspertrack * heads;
0271 start_sect = ((data[0x1fe] << 8) + data[0x1fd]) * sectscyl;
0272 id = data[0x1fc] & 15;
0273 put_dev_sector(sect);
0274
0275
0276
0277
0278 nr_sects = get_capacity(state->disk) - start_sect;
0279
0280 if (start_sect) {
0281 switch (id) {
0282 #ifdef CONFIG_ACORN_PARTITION_RISCIX
0283 case PARTITION_RISCIX_SCSI:
0284 case PARTITION_RISCIX_MFM:
0285 riscix_partition(state, start_sect, slot,
0286 nr_sects);
0287 break;
0288 #endif
0289
0290 case PARTITION_LINUX:
0291 linux_partition(state, start_sect, slot,
0292 nr_sects);
0293 break;
0294 }
0295 }
0296 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0297 return 1;
0298 }
0299 #endif
0300
0301 #ifdef CONFIG_ACORN_PARTITION_ICS
0302
0303 struct ics_part {
0304 __le32 start;
0305 __le32 size;
0306 };
0307
0308 static int adfspart_check_ICSLinux(struct parsed_partitions *state,
0309 unsigned long block)
0310 {
0311 Sector sect;
0312 unsigned char *data = read_part_sector(state, block, §);
0313 int result = 0;
0314
0315 if (data) {
0316 if (memcmp(data, "LinuxPart", 9) == 0)
0317 result = 1;
0318 put_dev_sector(sect);
0319 }
0320
0321 return result;
0322 }
0323
0324
0325
0326
0327 static inline int valid_ics_sector(const unsigned char *data)
0328 {
0329 unsigned long sum;
0330 int i;
0331
0332 for (i = 0, sum = 0x50617274; i < 508; i++)
0333 sum += data[i];
0334
0335 sum -= le32_to_cpu(*(__le32 *)(&data[508]));
0336
0337 return sum == 0;
0338 }
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350 int adfspart_check_ICS(struct parsed_partitions *state)
0351 {
0352 const unsigned char *data;
0353 const struct ics_part *p;
0354 int slot;
0355 Sector sect;
0356
0357
0358
0359
0360 data = read_part_sector(state, 0, §);
0361 if (!data)
0362 return -1;
0363
0364 if (!valid_ics_sector(data)) {
0365 put_dev_sector(sect);
0366 return 0;
0367 }
0368
0369 strlcat(state->pp_buf, " [ICS]", PAGE_SIZE);
0370
0371 for (slot = 1, p = (const struct ics_part *)data; p->size; p++) {
0372 u32 start = le32_to_cpu(p->start);
0373 s32 size = le32_to_cpu(p->size);
0374
0375 if (slot == state->limit)
0376 break;
0377
0378
0379
0380
0381
0382
0383 if (size < 0) {
0384 size = -size;
0385
0386
0387
0388
0389
0390
0391
0392 if (size > 1 && adfspart_check_ICSLinux(state, start)) {
0393 start += 1;
0394 size -= 1;
0395 }
0396 }
0397
0398 if (size)
0399 put_partition(state, slot++, start, size);
0400 }
0401
0402 put_dev_sector(sect);
0403 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0404 return 1;
0405 }
0406 #endif
0407
0408 #ifdef CONFIG_ACORN_PARTITION_POWERTEC
0409 struct ptec_part {
0410 __le32 unused1;
0411 __le32 unused2;
0412 __le32 start;
0413 __le32 size;
0414 __le32 unused5;
0415 char type[8];
0416 };
0417
0418 static inline int valid_ptec_sector(const unsigned char *data)
0419 {
0420 unsigned char checksum = 0x2a;
0421 int i;
0422
0423
0424
0425
0426
0427 if (data[510] == 0x55 && data[511] == 0xaa)
0428 return 0;
0429
0430 for (i = 0; i < 511; i++)
0431 checksum += data[i];
0432
0433 return checksum == data[511];
0434 }
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446 int adfspart_check_POWERTEC(struct parsed_partitions *state)
0447 {
0448 Sector sect;
0449 const unsigned char *data;
0450 const struct ptec_part *p;
0451 int slot = 1;
0452 int i;
0453
0454 data = read_part_sector(state, 0, §);
0455 if (!data)
0456 return -1;
0457
0458 if (!valid_ptec_sector(data)) {
0459 put_dev_sector(sect);
0460 return 0;
0461 }
0462
0463 strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE);
0464
0465 for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
0466 u32 start = le32_to_cpu(p->start);
0467 u32 size = le32_to_cpu(p->size);
0468
0469 if (size)
0470 put_partition(state, slot++, start, size);
0471 }
0472
0473 put_dev_sector(sect);
0474 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0475 return 1;
0476 }
0477 #endif
0478
0479 #ifdef CONFIG_ACORN_PARTITION_EESOX
0480 struct eesox_part {
0481 char magic[6];
0482 char name[10];
0483 __le32 start;
0484 __le32 unused6;
0485 __le32 unused7;
0486 __le32 unused8;
0487 };
0488
0489
0490
0491
0492 static const char eesox_name[] = {
0493 'N', 'e', 'i', 'l', ' ',
0494 'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
0495 };
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507 int adfspart_check_EESOX(struct parsed_partitions *state)
0508 {
0509 Sector sect;
0510 const unsigned char *data;
0511 unsigned char buffer[256];
0512 struct eesox_part *p;
0513 sector_t start = 0;
0514 int i, slot = 1;
0515
0516 data = read_part_sector(state, 7, §);
0517 if (!data)
0518 return -1;
0519
0520
0521
0522
0523 for (i = 0; i < 256; i++)
0524 buffer[i] = data[i] ^ eesox_name[i & 15];
0525
0526 put_dev_sector(sect);
0527
0528 for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
0529 sector_t next;
0530
0531 if (memcmp(p->magic, "Eesox", 6))
0532 break;
0533
0534 next = le32_to_cpu(p->start);
0535 if (i)
0536 put_partition(state, slot++, start, next - start);
0537 start = next;
0538 }
0539
0540 if (i != 0) {
0541 sector_t size;
0542
0543 size = get_capacity(state->disk);
0544 put_partition(state, slot++, start, size - start);
0545 strlcat(state->pp_buf, "\n", PAGE_SIZE);
0546 }
0547
0548 return i ? 1 : 0;
0549 }
0550 #endif