1 // SPDX-License-Identifier: GPL-2.0
3 * fs/partitions/amiga.c
5 * Code extracted from drivers/block/genhd.c
7 * Copyright (C) 1991-1998 Linus Torvalds
8 * Re-organised Feb 1998 Russell King
11 #define pr_fmt(fmt) fmt
13 #include <linux/types.h>
14 #include <linux/mm_types.h>
15 #include <linux/overflow.h>
16 #include <linux/affs_hardblocks.h>
20 /* magic offsets in partition DosEnvVec */
27 checksum_block(__be32
*m
, int size
)
32 sum
+= be32_to_cpu(*m
++);
36 int amiga_partition(struct parsed_partitions
*state
)
40 struct RigidDiskBlock
*rdb
;
41 struct PartitionBlock
*pb
;
42 u64 start_sect
, nr_sects
;
43 sector_t blk
, end_sect
;
44 u32 cylblk
; /* rdb_CylBlocks = nr_heads*sect_per_track */
45 u32 nr_hd
, nr_sect
, lo_cyl
, hi_cyl
;
47 unsigned int blksize
= 1; /* Multiplier for disk block size */
50 for (blk
= 0; ; blk
++, put_dev_sector(sect
)) {
51 if (blk
== RDB_ALLOCATION_LIMIT
)
53 data
= read_part_sector(state
, blk
, §
);
55 pr_err("Dev %s: unable to read RDB block %llu\n",
56 state
->disk
->disk_name
, blk
);
60 if (*(__be32
*)data
!= cpu_to_be32(IDNAME_RIGIDDISK
))
63 rdb
= (struct RigidDiskBlock
*)data
;
64 if (checksum_block((__be32
*)data
, be32_to_cpu(rdb
->rdb_SummedLongs
) & 0x7F) == 0)
66 /* Try again with 0xdc..0xdf zeroed, Windows might have
69 *(__be32
*)(data
+0xdc) = 0;
70 if (checksum_block((__be32
*)data
,
71 be32_to_cpu(rdb
->rdb_SummedLongs
) & 0x7F)==0) {
72 pr_err("Trashed word at 0xd0 in block %llu ignored in checksum calculation\n",
77 pr_err("Dev %s: RDB in block %llu has bad checksum\n",
78 state
->disk
->disk_name
, blk
);
81 /* blksize is blocks per 512 byte standard block */
82 blksize
= be32_to_cpu( rdb
->rdb_BlockBytes
) / 512;
85 char tmp
[7 + 10 + 1 + 1];
87 /* Be more informative */
88 snprintf(tmp
, sizeof(tmp
), " RDSK (%d)", blksize
* 512);
89 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
91 blk
= be32_to_cpu(rdb
->rdb_PartitionList
);
93 for (part
= 1; (s32
) blk
>0 && part
<=16; part
++, put_dev_sector(sect
)) {
94 /* Read in terms partition table understands */
95 if (check_mul_overflow(blk
, (sector_t
) blksize
, &blk
)) {
96 pr_err("Dev %s: overflow calculating partition block %llu! Skipping partitions %u and beyond\n",
97 state
->disk
->disk_name
, blk
, part
);
100 data
= read_part_sector(state
, blk
, §
);
102 pr_err("Dev %s: unable to read partition block %llu\n",
103 state
->disk
->disk_name
, blk
);
107 pb
= (struct PartitionBlock
*)data
;
108 blk
= be32_to_cpu(pb
->pb_Next
);
109 if (pb
->pb_ID
!= cpu_to_be32(IDNAME_PARTITION
))
111 if (checksum_block((__be32
*)pb
, be32_to_cpu(pb
->pb_SummedLongs
) & 0x7F) != 0 )
114 /* RDB gives us more than enough rope to hang ourselves with,
115 * many times over (2^128 bytes if all fields max out).
116 * Some careful checks are in order, so check for potential
118 * We are multiplying four 32 bit numbers to one sector_t!
121 nr_hd
= be32_to_cpu(pb
->pb_Environment
[NR_HD
]);
122 nr_sect
= be32_to_cpu(pb
->pb_Environment
[NR_SECT
]);
124 /* CylBlocks is total number of blocks per cylinder */
125 if (check_mul_overflow(nr_hd
, nr_sect
, &cylblk
)) {
126 pr_err("Dev %s: heads*sects %u overflows u32, skipping partition!\n",
127 state
->disk
->disk_name
, cylblk
);
131 /* check for consistency with RDB defined CylBlocks */
132 if (cylblk
> be32_to_cpu(rdb
->rdb_CylBlocks
)) {
133 pr_warn("Dev %s: cylblk %u > rdb_CylBlocks %u!\n",
134 state
->disk
->disk_name
, cylblk
,
135 be32_to_cpu(rdb
->rdb_CylBlocks
));
138 /* RDB allows for variable logical block size -
139 * normalize to 512 byte blocks and check result.
142 if (check_mul_overflow(cylblk
, blksize
, &cylblk
)) {
143 pr_err("Dev %s: partition %u bytes per cyl. overflows u32, skipping partition!\n",
144 state
->disk
->disk_name
, part
);
148 /* Calculate partition start and end. Limit of 32 bit on cylblk
149 * guarantees no overflow occurs if LBD support is enabled.
152 lo_cyl
= be32_to_cpu(pb
->pb_Environment
[LO_CYL
]);
153 start_sect
= ((u64
) lo_cyl
* cylblk
);
155 hi_cyl
= be32_to_cpu(pb
->pb_Environment
[HI_CYL
]);
156 nr_sects
= (((u64
) hi_cyl
- lo_cyl
+ 1) * cylblk
);
161 /* Warn user if partition end overflows u32 (AmigaDOS limit) */
163 if ((start_sect
+ nr_sects
) > UINT_MAX
) {
164 pr_warn("Dev %s: partition %u (%llu-%llu) needs 64 bit device support!\n",
165 state
->disk
->disk_name
, part
,
166 start_sect
, start_sect
+ nr_sects
);
169 if (check_add_overflow(start_sect
, nr_sects
, &end_sect
)) {
170 pr_err("Dev %s: partition %u (%llu-%llu) needs LBD device support, skipping partition!\n",
171 state
->disk
->disk_name
, part
,
172 start_sect
, end_sect
);
176 /* Tell Kernel about it */
178 put_partition(state
,slot
++,start_sect
,nr_sects
);
180 /* Be even more informative to aid mounting */
184 __be32
*dt
= (__be32
*)dostype
;
185 *dt
= pb
->pb_Environment
[16];
186 if (dostype
[3] < ' ')
187 snprintf(tmp
, sizeof(tmp
), " (%c%c%c^%c)",
188 dostype
[0], dostype
[1],
189 dostype
[2], dostype
[3] + '@' );
191 snprintf(tmp
, sizeof(tmp
), " (%c%c%c%c)",
192 dostype
[0], dostype
[1],
193 dostype
[2], dostype
[3]);
194 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
195 snprintf(tmp
, sizeof(tmp
), "(res %d spb %d)",
196 be32_to_cpu(pb
->pb_Environment
[6]),
197 be32_to_cpu(pb
->pb_Environment
[4]));
198 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
202 strlcat(state
->pp_buf
, "\n", PAGE_SIZE
);