1 /* 2 * (C) Copyright 2001 3 * Hans-Joerg Frieden, Hyperion Entertainment 4 * Hans-JoergF@hyperion-entertainment.com 5 * 6 * See file CREDITS for list of people who contributed to this 7 * project. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of 12 * the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22 * MA 02111-1307 USA 23 */ 24 #include <common.h> 25 #include <command.h> 26 #include <ide.h> 27 #include "part_amiga.h" 28 29 #ifdef HAVE_BLOCK_DEVICE 30 31 #undef AMIGA_DEBUG 32 33 #ifdef AMIGA_DEBUG 34 #define PRINTF(fmt, args...) printf(fmt ,##args) 35 #else 36 #define PRINTF(fmt, args...) 37 #endif 38 39 struct block_header 40 { 41 u32 id; 42 u32 summed_longs; 43 s32 chk_sum; 44 }; 45 46 static unsigned char block_buffer[DEFAULT_SECTOR_SIZE]; 47 static struct rigid_disk_block rdb = {0}; 48 static struct bootcode_block bootcode = {0}; 49 50 /* 51 * Copy a bcpl to a c string 52 */ 53 static void bcpl_strcpy(char *to, char *from) 54 { 55 int len = *from++; 56 57 while (len) 58 { 59 *to++ = *from++; 60 len--; 61 } 62 *to = 0; 63 } 64 65 /* 66 * Print a BCPL String. BCPL strings start with a byte with the length 67 * of the string, and don't contain a terminating nul character 68 */ 69 static void bstr_print(char *string) 70 { 71 int len = *string++; 72 char buffer[256]; 73 int i; 74 75 i = 0; 76 while (len) 77 { 78 buffer[i++] = *string++; 79 len--; 80 } 81 82 buffer[i] = 0; 83 printf("%-10s", buffer); 84 } 85 86 /* 87 * Sum a block. The checksum of a block must end up at zero 88 * to be valid. The chk_sum field is selected so that adding 89 * it yields zero. 90 */ 91 int sum_block(struct block_header *header) 92 { 93 s32 *block = (s32 *)header; 94 u32 i; 95 s32 sum = 0; 96 97 for (i = 0; i < header->summed_longs; i++) 98 sum += *block++; 99 100 return (sum != 0); 101 } 102 103 /* 104 * Print an AmigaOS disk type. Disk types are a four-byte identifier 105 * describing the file system. They are usually written as a three-letter 106 * word followed by a backslash and a version number. For example, 107 * DOS\0 would be the original file system. SFS\0 would be SmartFileSystem. 108 * DOS\1 is FFS. 109 */ 110 static void print_disk_type(u32 disk_type) 111 { 112 char buffer[6]; 113 buffer[0] = (disk_type & 0xFF000000)>>24; 114 buffer[1] = (disk_type & 0x00FF0000)>>16; 115 buffer[2] = (disk_type & 0x0000FF00)>>8; 116 buffer[3] = '\\'; 117 buffer[4] = (disk_type & 0x000000FF) + '0'; 118 buffer[5] = 0; 119 printf("%s", buffer); 120 } 121 122 /* 123 * Print the info contained within the given partition block 124 */ 125 static void print_part_info(struct partition_block *p) 126 { 127 struct amiga_part_geometry *g; 128 129 g = (struct amiga_part_geometry *)&(p->environment); 130 131 bstr_print(p->drive_name); 132 printf("%6d\t%6d\t", 133 g->low_cyl * g->block_per_track * g->surfaces , 134 (g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1); 135 print_disk_type(g->dos_type); 136 printf("\t%5d\n", g->boot_priority); 137 } 138 139 /* 140 * Search for the Rigid Disk Block. The rigid disk block is required 141 * to be within the first 16 blocks of a drive, needs to have 142 * the ID AMIGA_ID_RDISK ('RDSK') and needs to have a valid 143 * sum-to-zero checksum 144 */ 145 struct rigid_disk_block *get_rdisk(block_dev_desc_t *dev_desc) 146 { 147 int i; 148 int limit; 149 char *s; 150 151 s = getenv("amiga_scanlimit"); 152 if (s) 153 limit = simple_strtoul(s, NULL, 10); 154 else 155 limit = AMIGA_BLOCK_LIMIT; 156 157 for (i=0; i<limit; i++) 158 { 159 ulong res = dev_desc->block_read(dev_desc->dev, i, 1, 160 (ulong *)block_buffer); 161 if (res == 1) 162 { 163 struct rigid_disk_block *trdb = (struct rigid_disk_block *)block_buffer; 164 if (trdb->id == AMIGA_ID_RDISK) 165 { 166 PRINTF("Rigid disk block suspect at %d, checking checksum\n",i); 167 if (sum_block((struct block_header *)block_buffer) == 0) 168 { 169 PRINTF("FOUND\n"); 170 memcpy(&rdb, trdb, sizeof(struct rigid_disk_block)); 171 return (struct rigid_disk_block *)&rdb; 172 } 173 } 174 } 175 } 176 PRINTF("Done scanning, no RDB found\n"); 177 return NULL; 178 } 179 180 /* 181 * Search for boot code 182 * Again, the first boot block must be located somewhere in the first 16 blocks, or rooted in the 183 * Ridgid disk block 184 */ 185 186 struct bootcode_block *get_bootcode(block_dev_desc_t *dev_desc) 187 { 188 int i; 189 int limit; 190 char *s; 191 192 s = getenv("amiga_scanlimit"); 193 if (s) 194 limit = simple_strtoul(s, NULL, 10); 195 else 196 limit = AMIGA_BLOCK_LIMIT; 197 198 PRINTF("Scanning for BOOT from 0 to %d\n", limit); 199 200 for (i = 0; i < limit; i++) 201 { 202 ulong res = dev_desc->block_read(dev_desc->dev, i, 1, (ulong *)block_buffer); 203 if (res == 1) 204 { 205 struct bootcode_block *boot = (struct bootcode_block *)block_buffer; 206 if (boot->id == AMIGA_ID_BOOT) 207 { 208 PRINTF("BOOT block at %d, checking checksum\n", i); 209 if (sum_block((struct block_header *)block_buffer) == 0) 210 { 211 PRINTF("Found valid bootcode block\n"); 212 memcpy(&bootcode, boot, sizeof(struct bootcode_block)); 213 return &bootcode; 214 } 215 } 216 } 217 } 218 219 PRINTF("No boot code found on disk\n"); 220 return 0; 221 } 222 223 /* 224 * Test if the given partition has an Amiga partition table/Rigid 225 * Disk block 226 */ 227 int test_part_amiga(block_dev_desc_t *dev_desc) 228 { 229 struct rigid_disk_block *rdb; 230 struct bootcode_block *bootcode; 231 232 PRINTF("test_part_amiga: Testing for an Amiga RDB partition\n"); 233 234 rdb = get_rdisk(dev_desc); 235 if (rdb) 236 { 237 bootcode = get_bootcode(dev_desc); 238 if (bootcode) 239 PRINTF("test_part_amiga: bootable Amiga disk\n"); 240 else 241 PRINTF("test_part_amiga: non-bootable Amiga disk\n"); 242 243 return 0; 244 } 245 else 246 { 247 PRINTF("test_part_amiga: no RDB found\n"); 248 return -1; 249 } 250 251 } 252 253 /* 254 * Find partition number partnum on the given drive. 255 */ 256 static struct partition_block *find_partition(block_dev_desc_t *dev_desc, int partnum) 257 { 258 struct rigid_disk_block *rdb; 259 struct partition_block *p; 260 u32 block; 261 262 PRINTF("Trying to find partition block %d\n", partnum); 263 rdb = get_rdisk(dev_desc); 264 if (!rdb) 265 { 266 PRINTF("find_partition: no rdb found\n"); 267 return NULL; 268 } 269 270 PRINTF("find_partition: Scanning partition list\n"); 271 272 block = rdb->partition_list; 273 PRINTF("find_partition: partition list at 0x%x\n", block); 274 275 while (block != 0xFFFFFFFF) 276 { 277 ulong res = dev_desc->block_read(dev_desc->dev, block, 1, 278 (ulong *)block_buffer); 279 if (res == 1) 280 { 281 p = (struct partition_block *)block_buffer; 282 if (p->id == AMIGA_ID_PART) 283 { 284 PRINTF("PART block suspect at 0x%x, checking checksum\n",block); 285 if (sum_block((struct block_header *)p) == 0) 286 { 287 if (partnum == 0) break; 288 else 289 { 290 partnum--; 291 block = p->next; 292 } 293 } 294 } else block = 0xFFFFFFFF; 295 } else block = 0xFFFFFFFF; 296 } 297 298 if (block == 0xFFFFFFFF) 299 { 300 PRINTF("PART block not found\n"); 301 return NULL; 302 } 303 304 return (struct partition_block *)block_buffer; 305 } 306 307 /* 308 * Get info about a partition 309 */ 310 int get_partition_info_amiga (block_dev_desc_t *dev_desc, int part, disk_partition_t *info) 311 { 312 struct partition_block *p = find_partition(dev_desc, part-1); 313 struct amiga_part_geometry *g; 314 u32 disk_type; 315 316 if (!p) return -1; 317 318 g = (struct amiga_part_geometry *)&(p->environment); 319 info->start = g->low_cyl * g->block_per_track * g->surfaces; 320 info->size = (g->high_cyl - g->low_cyl + 1) * g->block_per_track * g->surfaces - 1; 321 info->blksz = rdb.block_bytes; 322 bcpl_strcpy(info->name, p->drive_name); 323 324 325 disk_type = g->dos_type; 326 327 info->type[0] = (disk_type & 0xFF000000)>>24; 328 info->type[1] = (disk_type & 0x00FF0000)>>16; 329 info->type[2] = (disk_type & 0x0000FF00)>>8; 330 info->type[3] = '\\'; 331 info->type[4] = (disk_type & 0x000000FF) + '0'; 332 info->type[5] = 0; 333 334 return 0; 335 } 336 337 void print_part_amiga (block_dev_desc_t *dev_desc) 338 { 339 struct rigid_disk_block *rdb; 340 struct bootcode_block *boot; 341 struct partition_block *p; 342 u32 block; 343 int i = 1; 344 345 rdb = get_rdisk(dev_desc); 346 if (!rdb) 347 { 348 PRINTF("print_part_amiga: no rdb found\n"); 349 return; 350 } 351 352 PRINTF("print_part_amiga: Scanning partition list\n"); 353 354 block = rdb->partition_list; 355 PRINTF("print_part_amiga: partition list at 0x%x\n", block); 356 357 printf("Summary: DiskBlockSize: %d\n" 358 " Cylinders : %d\n" 359 " Sectors/Track: %d\n" 360 " Heads : %d\n\n", 361 rdb->block_bytes, rdb->cylinders, rdb->sectors, 362 rdb->heads); 363 364 printf(" First Num. \n" 365 "Nr. Part. Name Block Block Type Boot Priority\n"); 366 367 while (block != 0xFFFFFFFF) 368 { 369 ulong res; 370 371 PRINTF("Trying to load block #0x%X\n", block); 372 373 res = dev_desc->block_read(dev_desc->dev, block, 1, 374 (ulong *)block_buffer); 375 if (res == 1) 376 { 377 p = (struct partition_block *)block_buffer; 378 if (p->id == AMIGA_ID_PART) 379 { 380 PRINTF("PART block suspect at 0x%x, checking checksum\n",block); 381 if (sum_block((struct block_header *)p) == 0) 382 { 383 printf("%-4d ", i); i++; 384 print_part_info(p); 385 block = p->next; 386 } 387 } else block = 0xFFFFFFFF; 388 } else block = 0xFFFFFFFF; 389 } 390 391 boot = get_bootcode(dev_desc); 392 if (boot) 393 { 394 printf("Disk is bootable\n"); 395 } 396 } 397 398 #endif 399