~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/block/partitions/amiga.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 }
207 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php