Merge tag 'vfs-6.6-merge-2' of ssh://gitolite.kernel.org/pub/scm/fs/xfs/xfs-linux
[platform/kernel/linux-rpi.git] / block / partitions / amiga.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  fs/partitions/amiga.c
4  *
5  *  Code extracted from drivers/block/genhd.c
6  *
7  *  Copyright (C) 1991-1998  Linus Torvalds
8  *  Re-organised Feb 1998 Russell King
9  */
10
11 #define pr_fmt(fmt) fmt
12
13 #include <linux/types.h>
14 #include <linux/mm_types.h>
15 #include <linux/overflow.h>
16 #include <linux/affs_hardblocks.h>
17
18 #include "check.h"
19
20 /* magic offsets in partition DosEnvVec */
21 #define NR_HD   3
22 #define NR_SECT 5
23 #define LO_CYL  9
24 #define HI_CYL  10
25
26 static __inline__ u32
27 checksum_block(__be32 *m, int size)
28 {
29         u32 sum = 0;
30
31         while (size--)
32                 sum += be32_to_cpu(*m++);
33         return sum;
34 }
35
36 int amiga_partition(struct parsed_partitions *state)
37 {
38         Sector sect;
39         unsigned char *data;
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;
46         int part, res = 0;
47         unsigned int blksize = 1;       /* Multiplier for disk block size */
48         int slot = 1;
49
50         for (blk = 0; ; blk++, put_dev_sector(sect)) {
51                 if (blk == RDB_ALLOCATION_LIMIT)
52                         goto rdb_done;
53                 data = read_part_sector(state, blk, &sect);
54                 if (!data) {
55                         pr_err("Dev %s: unable to read RDB block %llu\n",
56                                state->disk->disk_name, blk);
57                         res = -1;
58                         goto rdb_done;
59                 }
60                 if (*(__be32 *)data != cpu_to_be32(IDNAME_RIGIDDISK))
61                         continue;
62
63                 rdb = (struct RigidDiskBlock *)data;
64                 if (checksum_block((__be32 *)data, be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F) == 0)
65                         break;
66                 /* Try again with 0xdc..0xdf zeroed, Windows might have
67                  * trashed it.
68                  */
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",
73                                blk);
74                         break;
75                 }
76
77                 pr_err("Dev %s: RDB in block %llu has bad checksum\n",
78                        state->disk->disk_name, blk);
79         }
80
81         /* blksize is blocks per 512 byte standard block */
82         blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512;
83
84         {
85                 char tmp[7 + 10 + 1 + 1];
86
87                 /* Be more informative */
88                 snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512);
89                 strlcat(state->pp_buf, tmp, PAGE_SIZE);
90         }
91         blk = be32_to_cpu(rdb->rdb_PartitionList);
92         put_dev_sector(sect);
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);
98                         break;
99                 }
100                 data = read_part_sector(state, blk, &sect);
101                 if (!data) {
102                         pr_err("Dev %s: unable to read partition block %llu\n",
103                                state->disk->disk_name, blk);
104                         res = -1;
105                         goto rdb_done;
106                 }
107                 pb  = (struct PartitionBlock *)data;
108                 blk = be32_to_cpu(pb->pb_Next);
109                 if (pb->pb_ID != cpu_to_be32(IDNAME_PARTITION))
110                         continue;
111                 if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
112                         continue;
113
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
117                  * overflows.
118                  * We are multiplying four 32 bit numbers to one sector_t!
119                  */
120
121                 nr_hd   = be32_to_cpu(pb->pb_Environment[NR_HD]);
122                 nr_sect = be32_to_cpu(pb->pb_Environment[NR_SECT]);
123
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);
128                         continue;
129                 }
130
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));
136                 }
137
138                 /* RDB allows for variable logical block size -
139                  * normalize to 512 byte blocks and check result.
140                  */
141
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);
145                         continue;
146                 }
147
148                 /* Calculate partition start and end. Limit of 32 bit on cylblk
149                  * guarantees no overflow occurs if LBD support is enabled.
150                  */
151
152                 lo_cyl = be32_to_cpu(pb->pb_Environment[LO_CYL]);
153                 start_sect = ((u64) lo_cyl * cylblk);
154
155                 hi_cyl = be32_to_cpu(pb->pb_Environment[HI_CYL]);
156                 nr_sects = (((u64) hi_cyl - lo_cyl + 1) * cylblk);
157
158                 if (!nr_sects)
159                         continue;
160
161                 /* Warn user if partition end overflows u32 (AmigaDOS limit) */
162
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);
167                 }
168
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);
173                         continue;
174                 }
175
176                 /* Tell Kernel about it */
177
178                 put_partition(state,slot++,start_sect,nr_sects);
179                 {
180                         /* Be even more informative to aid mounting */
181                         char dostype[4];
182                         char tmp[42];
183
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] + '@' );
190                         else
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);
199                 }
200                 res = 1;
201         }
202         strlcat(state->pp_buf, "\n", PAGE_SIZE);
203
204 rdb_done:
205         return res;
206 }