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