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