18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fs/partitions/amiga.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Code extracted from drivers/block/genhd.c 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1991-1998 Linus Torvalds 88c2ecf20Sopenharmony_ci * Re-organised Feb 1998 Russell King 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 158c2ecf20Sopenharmony_ci#include <linux/overflow.h> 168c2ecf20Sopenharmony_ci#include <linux/affs_hardblocks.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "check.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* magic offsets in partition DosEnvVec */ 218c2ecf20Sopenharmony_ci#define NR_HD 3 228c2ecf20Sopenharmony_ci#define NR_SECT 5 238c2ecf20Sopenharmony_ci#define LO_CYL 9 248c2ecf20Sopenharmony_ci#define HI_CYL 10 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic __inline__ u32 278c2ecf20Sopenharmony_cichecksum_block(__be32 *m, int size) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci u32 sum = 0; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci while (size--) 328c2ecf20Sopenharmony_ci sum += be32_to_cpu(*m++); 338c2ecf20Sopenharmony_ci return sum; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciint amiga_partition(struct parsed_partitions *state) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci Sector sect; 398c2ecf20Sopenharmony_ci unsigned char *data; 408c2ecf20Sopenharmony_ci struct RigidDiskBlock *rdb; 418c2ecf20Sopenharmony_ci struct PartitionBlock *pb; 428c2ecf20Sopenharmony_ci u64 start_sect, nr_sects; 438c2ecf20Sopenharmony_ci sector_t blk, end_sect; 448c2ecf20Sopenharmony_ci u32 cylblk; /* rdb_CylBlocks = nr_heads*sect_per_track */ 458c2ecf20Sopenharmony_ci u32 nr_hd, nr_sect, lo_cyl, hi_cyl; 468c2ecf20Sopenharmony_ci int part, res = 0; 478c2ecf20Sopenharmony_ci unsigned int blksize = 1; /* Multiplier for disk block size */ 488c2ecf20Sopenharmony_ci int slot = 1; 498c2ecf20Sopenharmony_ci char b[BDEVNAME_SIZE]; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci for (blk = 0; ; blk++, put_dev_sector(sect)) { 528c2ecf20Sopenharmony_ci if (blk == RDB_ALLOCATION_LIMIT) 538c2ecf20Sopenharmony_ci goto rdb_done; 548c2ecf20Sopenharmony_ci data = read_part_sector(state, blk, §); 558c2ecf20Sopenharmony_ci if (!data) { 568c2ecf20Sopenharmony_ci pr_err("Dev %s: unable to read RDB block %llu\n", 578c2ecf20Sopenharmony_ci bdevname(state->bdev, b), blk); 588c2ecf20Sopenharmony_ci res = -1; 598c2ecf20Sopenharmony_ci goto rdb_done; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci if (*(__be32 *)data != cpu_to_be32(IDNAME_RIGIDDISK)) 628c2ecf20Sopenharmony_ci continue; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci rdb = (struct RigidDiskBlock *)data; 658c2ecf20Sopenharmony_ci if (checksum_block((__be32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0) 668c2ecf20Sopenharmony_ci break; 678c2ecf20Sopenharmony_ci /* Try again with 0xdc..0xdf zeroed, Windows might have 688c2ecf20Sopenharmony_ci * trashed it. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci *(__be32 *)(data+0xdc) = 0; 718c2ecf20Sopenharmony_ci if (checksum_block((__be32 *)data, 728c2ecf20Sopenharmony_ci be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) { 738c2ecf20Sopenharmony_ci pr_err("Trashed word at 0xd0 in block %llu ignored in checksum calculation\n", 748c2ecf20Sopenharmony_ci blk); 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci pr_err("Dev %s: RDB in block %llu has bad checksum\n", 798c2ecf20Sopenharmony_ci bdevname(state->bdev, b), blk); 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* blksize is blocks per 512 byte standard block */ 838c2ecf20Sopenharmony_ci blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci { 868c2ecf20Sopenharmony_ci char tmp[7 + 10 + 1 + 1]; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Be more informative */ 898c2ecf20Sopenharmony_ci snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512); 908c2ecf20Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci blk = be32_to_cpu(rdb->rdb_PartitionList); 938c2ecf20Sopenharmony_ci put_dev_sector(sect); 948c2ecf20Sopenharmony_ci for (part = 1; (s32) blk>0 && part<=16; part++, put_dev_sector(sect)) { 958c2ecf20Sopenharmony_ci /* Read in terms partition table understands */ 968c2ecf20Sopenharmony_ci if (check_mul_overflow(blk, (sector_t) blksize, &blk)) { 978c2ecf20Sopenharmony_ci pr_err("Dev %s: overflow calculating partition block %llu! Skipping partitions %u and beyond\n", 988c2ecf20Sopenharmony_ci bdevname(state->bdev, b), blk, part); 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci data = read_part_sector(state, blk, §); 1028c2ecf20Sopenharmony_ci if (!data) { 1038c2ecf20Sopenharmony_ci pr_err("Dev %s: unable to read partition block %llu\n", 1048c2ecf20Sopenharmony_ci bdevname(state->bdev, b), blk); 1058c2ecf20Sopenharmony_ci res = -1; 1068c2ecf20Sopenharmony_ci goto rdb_done; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci pb = (struct PartitionBlock *)data; 1098c2ecf20Sopenharmony_ci blk = be32_to_cpu(pb->pb_Next); 1108c2ecf20Sopenharmony_ci if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION)) 1118c2ecf20Sopenharmony_ci continue; 1128c2ecf20Sopenharmony_ci if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 ) 1138c2ecf20Sopenharmony_ci continue; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* RDB gives us more than enough rope to hang ourselves with, 1168c2ecf20Sopenharmony_ci * many times over (2^128 bytes if all fields max out). 1178c2ecf20Sopenharmony_ci * Some careful checks are in order, so check for potential 1188c2ecf20Sopenharmony_ci * overflows. 1198c2ecf20Sopenharmony_ci * We are multiplying four 32 bit numbers to one sector_t! 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci nr_hd = be32_to_cpu(pb->pb_Environment[NR_HD]); 1238c2ecf20Sopenharmony_ci nr_sect = be32_to_cpu(pb->pb_Environment[NR_SECT]); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* CylBlocks is total number of blocks per cylinder */ 1268c2ecf20Sopenharmony_ci if (check_mul_overflow(nr_hd, nr_sect, &cylblk)) { 1278c2ecf20Sopenharmony_ci pr_err("Dev %s: heads*sects %u overflows u32, skipping partition!\n", 1288c2ecf20Sopenharmony_ci bdevname(state->bdev, b), cylblk); 1298c2ecf20Sopenharmony_ci continue; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* check for consistency with RDB defined CylBlocks */ 1338c2ecf20Sopenharmony_ci if (cylblk > be32_to_cpu(rdb->rdb_CylBlocks)) { 1348c2ecf20Sopenharmony_ci pr_warn("Dev %s: cylblk %u > rdb_CylBlocks %u!\n", 1358c2ecf20Sopenharmony_ci bdevname(state->bdev, b), cylblk, 1368c2ecf20Sopenharmony_ci be32_to_cpu(rdb->rdb_CylBlocks)); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* RDB allows for variable logical block size - 1408c2ecf20Sopenharmony_ci * normalize to 512 byte blocks and check result. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (check_mul_overflow(cylblk, blksize, &cylblk)) { 1448c2ecf20Sopenharmony_ci pr_err("Dev %s: partition %u bytes per cyl. overflows u32, skipping partition!\n", 1458c2ecf20Sopenharmony_ci bdevname(state->bdev, b), part); 1468c2ecf20Sopenharmony_ci continue; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* Calculate partition start and end. Limit of 32 bit on cylblk 1508c2ecf20Sopenharmony_ci * guarantees no overflow occurs if LBD support is enabled. 1518c2ecf20Sopenharmony_ci */ 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci lo_cyl = be32_to_cpu(pb->pb_Environment[LO_CYL]); 1548c2ecf20Sopenharmony_ci start_sect = ((u64) lo_cyl * cylblk); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci hi_cyl = be32_to_cpu(pb->pb_Environment[HI_CYL]); 1578c2ecf20Sopenharmony_ci nr_sects = (((u64) hi_cyl - lo_cyl + 1) * cylblk); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!nr_sects) 1608c2ecf20Sopenharmony_ci continue; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Warn user if partition end overflows u32 (AmigaDOS limit) */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if ((start_sect + nr_sects) > UINT_MAX) { 1658c2ecf20Sopenharmony_ci pr_warn("Dev %s: partition %u (%llu-%llu) needs 64 bit device support!\n", 1668c2ecf20Sopenharmony_ci bdevname(state->bdev, b), part, 1678c2ecf20Sopenharmony_ci start_sect, start_sect + nr_sects); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (check_add_overflow(start_sect, nr_sects, &end_sect)) { 1718c2ecf20Sopenharmony_ci pr_err("Dev %s: partition %u (%llu-%llu) needs LBD device support, skipping partition!\n", 1728c2ecf20Sopenharmony_ci bdevname(state->bdev, b), part, 1738c2ecf20Sopenharmony_ci start_sect, end_sect); 1748c2ecf20Sopenharmony_ci continue; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Tell Kernel about it */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci put_partition(state,slot++,start_sect,nr_sects); 1808c2ecf20Sopenharmony_ci { 1818c2ecf20Sopenharmony_ci /* Be even more informative to aid mounting */ 1828c2ecf20Sopenharmony_ci char dostype[4]; 1838c2ecf20Sopenharmony_ci char tmp[42]; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci __be32 *dt = (__be32 *)dostype; 1868c2ecf20Sopenharmony_ci *dt = pb->pb_Environment[16]; 1878c2ecf20Sopenharmony_ci if (dostype[3] < ' ') 1888c2ecf20Sopenharmony_ci snprintf(tmp, sizeof(tmp), " (%c%c%c^%c)", 1898c2ecf20Sopenharmony_ci dostype[0], dostype[1], 1908c2ecf20Sopenharmony_ci dostype[2], dostype[3] + '@' ); 1918c2ecf20Sopenharmony_ci else 1928c2ecf20Sopenharmony_ci snprintf(tmp, sizeof(tmp), " (%c%c%c%c)", 1938c2ecf20Sopenharmony_ci dostype[0], dostype[1], 1948c2ecf20Sopenharmony_ci dostype[2], dostype[3]); 1958c2ecf20Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 1968c2ecf20Sopenharmony_ci snprintf(tmp, sizeof(tmp), "(res %d spb %d)", 1978c2ecf20Sopenharmony_ci be32_to_cpu(pb->pb_Environment[6]), 1988c2ecf20Sopenharmony_ci be32_to_cpu(pb->pb_Environment[4])); 1998c2ecf20Sopenharmony_ci strlcat(state->pp_buf, tmp, PAGE_SIZE); 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci res = 1; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci strlcat(state->pp_buf, "\n", PAGE_SIZE); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cirdb_done: 2068c2ecf20Sopenharmony_ci return res; 2078c2ecf20Sopenharmony_ci} 208