xref: /netbsd-src/external/gpl3/gdb/dist/sim/ppc/pk_disklabel.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
1 /*  This file is part of the program psim.
2 
3     Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au>
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, see <http://www.gnu.org/licenses/>.
17 
18     */
19 
20 
21 #ifndef _PK_DISKLABEL_C_
22 #define _PK_DISKLABEL_C_
23 
24 #ifndef STATIC_INLINE_PK_DISKLABEL
25 #define STATIC_INLINE_PK_DISKLABEL STATIC_INLINE
26 #endif
27 
28 #include "device_table.h"
29 
30 #include "pk.h"
31 
32 #include <stdlib.h>
33 
34 /* PACKAGE
35 
36    disk-label - all knowing disk I/O package
37 
38    DESCRIPTION
39 
40    The disk-label package provides a generic interface to disk
41    devices.  It uses the arguments specified when an instance is being
42    created to determine if the raw disk, a partition, or a file within
43    a partition should be opened.
44 
45    An instance create call to disk-label could result, for instance,
46    in the opening of a DOS file system contained within a dos
47    partition contained within a physical disk.
48 
49    */
50 
51 /* taken from bfd/ppcboot.c by Michael Meissner */
52 
53 /* PPCbug location structure */
54 typedef struct ppcboot_location {
55   uint8_t ind;
56   uint8_t head;
57   uint8_t sector;
58   uint8_t cylinder;
59 } ppcboot_location_t;
60 
61 /* PPCbug partition table layout */
62 typedef struct ppcboot_partition {
63   ppcboot_location_t partition_begin;	/* partition begin */
64   ppcboot_location_t partition_end;	/* partition end */
65   uint8_t sector_begin[4];		/* 32-bit start RBA (zero-based), little endian */
66   uint8_t sector_length[4];		/* 32-bit RBA count (one-based), little endian */
67 } ppcboot_partition_t;
68 
69 #if 0
70 /* PPCbug boot layout.  */
71 typedef struct ppcboot_hdr {
72   uint8_t		pc_compatibility[446];	/* x86 instruction field */
73   ppcboot_partition_t	partition[4];		/* partition information */
74   uint8_t		signature[2];		/* 0x55 and 0xaa */
75   uint8_t		entry_offset[4];	/* entry point offset, little endian */
76   uint8_t		length[4];		/* load image length, little endian */
77   uint8_t		flags;			/* flag field */
78   uint8_t		os_id;			/* OS_ID */
79   char			partition_name[32];	/* partition name */
80   uint8_t		reserved1[470];		/* reserved */
81 } ppcboot_hdr_t;
82 #endif
83 
84 
85 typedef struct _disklabel {
86   device_instance *parent;
87   device_instance *raw_disk;
88   unsigned_word pos;
89   unsigned_word sector_begin;
90   unsigned_word sector_length;
91 } disklabel;
92 
93 
94 static unsigned_word
sector2uw(uint8_t s[4])95 sector2uw(uint8_t s[4])
96 {
97   return ((s[3] << 24)
98 	  + (s[2] << 16)
99 	  + (s[1] << 8)
100 	  + (s[0] << 0));
101 }
102 
103 
104 static void
disklabel_delete(device_instance * instance)105 disklabel_delete(device_instance *instance)
106 {
107   disklabel *label = device_instance_data(instance);
108   device_instance_delete(label->raw_disk);
109   free(label);
110 }
111 
112 
113 static int
disklabel_read(device_instance * instance,void * buf,unsigned_word len)114 disklabel_read(device_instance *instance,
115 	       void *buf,
116 	       unsigned_word len)
117 {
118   disklabel *label = device_instance_data(instance);
119   int nr_read;
120   if (label->pos + len > label->sector_length)
121     len = label->sector_length - label->pos;
122   if (device_instance_seek(label->raw_disk, 0,
123 			   label->sector_begin + label->pos) < 0)
124     return -1;
125   nr_read = device_instance_read(label->raw_disk, buf, len);
126   if (nr_read > 0)
127     label->pos += nr_read;
128   return nr_read;
129 }
130 
131 static int
disklabel_write(device_instance * instance,const void * buf,unsigned_word len)132 disklabel_write(device_instance *instance,
133 		const void *buf,
134 		unsigned_word len)
135 {
136   disklabel *label = device_instance_data(instance);
137   int nr_written;
138   if (label->pos + len > label->sector_length)
139     len = label->sector_length - label->pos;
140   if (device_instance_seek(label->raw_disk, 0,
141 			   label->sector_begin + label->pos) < 0)
142     return -1;
143   nr_written = device_instance_write(label->raw_disk, buf, len);
144   if (nr_written > 0)
145     label->pos += nr_written;
146   return nr_written;
147 }
148 
149 static int
disklabel_seek(device_instance * instance,unsigned_word pos_hi,unsigned_word pos_lo)150 disklabel_seek(device_instance *instance,
151 	       unsigned_word pos_hi,
152 	       unsigned_word pos_lo)
153 {
154   disklabel *label = device_instance_data(instance);
155   if (pos_lo >= label->sector_length || pos_hi != 0)
156     return -1;
157   label->pos = pos_lo;
158   return 0;
159 }
160 
161 
162 static const device_instance_callbacks package_disklabel_callbacks = {
163   disklabel_delete,
164   disklabel_read,
165   disklabel_write,
166   disklabel_seek,
167 };
168 
169 /* Reconize different types of boot block */
170 
171 static int
block0_is_bpb(const uint8_t block[])172 block0_is_bpb(const uint8_t block[])
173 {
174   const char ebdic_ibma[] = { 0xc9, 0xc2, 0xd4, 0xc1 };
175   /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */
176   /* can't start with IBMA */
177   if (memcmp(block, ebdic_ibma, sizeof(ebdic_ibma)) == 0)
178     return 0;
179   /* must have LE 0xAA55 signature at offset 510 */
180   if (block[511] != 0xAA && block[510] != 0x55)
181     return 0;
182   /* valid 16 bit LE bytes per sector - 256, 512, 1024 */
183   if (block[11] != 0
184       || (block[12] != 1 && block[12] != 2 && block[12] != 4))
185     return 0;
186   /* nr fats is 1 or 2 */
187   if (block[16] != 1 && block[16] != 2)
188     return 0;
189   return 1;
190 }
191 
192 
193 /* Verify that the device contains an ISO-9660 File system */
194 
195 static int
is_iso9660(device_instance * raw_disk)196 is_iso9660(device_instance *raw_disk)
197 {
198   /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */
199   uint8_t block[512];
200   if (device_instance_seek(raw_disk, 0, 512 * 64) < 0)
201     return 0;
202   if (device_instance_read(raw_disk, block, sizeof(block)) != sizeof(block))
203     return 0;
204   if (block[0] == 0x01
205       && block[1] == 'C'
206       && block[2] == 'D'
207       && block[3] == '0'
208       && block[4] == '0'
209       && block[5] == '1')
210     return 1;
211   return 0;
212 }
213 
214 
215 /* Verify that the disk block contains a valid DOS partition table.
216    While we're at it have a look around for active partitions etc.
217 
218    Return 0: invalid
219    Return 1..4: valid, value returned is the first active partition
220    Return -1: no active partition */
221 
222 static int
block0_is_fdisk(const uint8_t block[])223 block0_is_fdisk(const uint8_t block[])
224 {
225   const int partition_type_fields[] = { 0, 0x1c2, 0x1d2, 0x1e2, 0x1f2 };
226   const int partition_active_fields[] = { 0, 0x1be, 0x1ce, 0x1de, 0xee };
227   int partition;
228   int active = -1;
229   /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */
230   /* must have LE 0xAA55 signature at offset 510 */
231   if (block[511/*0x1ff*/] != 0xAA && block[510/*0x1fe*/] != 0x55)
232     return 0;
233   /* must contain valid partition types */
234   for (partition = 1; partition <= 4 && active != 0; partition++) {
235     int partition_type = block[partition_type_fields[partition]];
236     int is_active = block[partition_active_fields[partition]] == 0x80;
237     const char *type;
238     switch (partition_type) {
239     case 0x00:
240       type = "UNUSED";
241       break;
242     case 0x01:
243       type = "FAT 12 File system";
244       break;
245     case 0x04:
246       type = "FAT 16 File system";
247       break;
248     case 0x05:
249     case 0x06:
250       type = "rejected - extended/chained partition not supported";
251       active = 0;
252       break;
253     case 0x41:
254       type = "Single program image";
255       break;
256     case 0x82:
257       type = "Solaris?";
258       break;
259     case 0x96:
260       type = "ISO 9660 File system";
261       break;
262     default:
263       type = "rejected - unknown type";
264       active = 0;
265       break;
266     }
267     PTRACE(disklabel, ("partition %d of type 0x%02x - %s%s\n",
268 		       partition,
269 		       partition_type,
270 		       type,
271 		       is_active && active != 0 ? " (active)" : ""));
272     if (partition_type != 0 && is_active && active < 0)
273       active = partition;
274   }
275   return active;
276 }
277 
278 
279 /* Verify that block0 corresponds to a MAC disk */
280 
281 static int
block0_is_mac_disk(const uint8_t block[])282 block0_is_mac_disk(const uint8_t block[])
283 {
284   /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */
285   /* signature - BEx4552 at offset 0 */
286   if (block[0] != 0x45 || block[1] != 0x52)
287     return 0;
288   return 1;
289 }
290 
291 
292 /* Open a logical disk/file */
293 
294 device_instance *
pk_disklabel_create_instance(device_instance * raw_disk,const char * args)295 pk_disklabel_create_instance(device_instance *raw_disk,
296 			     const char *args)
297 {
298   int partition;
299   char *filename;
300 
301   /* parse the arguments */
302   if (args == NULL) {
303     partition = 0;
304     filename = NULL;
305   }
306   else {
307     partition = strtoul((char*)args, &filename, 0);
308     if (filename == args)
309       partition = -1; /* not specified */
310     if (*filename == ',')
311       filename++;
312     if (*filename == '\0')
313       filename = NULL; /* easier */
314   }
315 
316   if (partition == 0) {
317     /* select the raw disk */
318     return raw_disk;
319   }
320   else {
321     uint8_t boot_block[512];
322     /* get the boot block for examination */
323     if (device_instance_seek(raw_disk, 0, 0) < 0)
324       device_error(device_instance_device(raw_disk),
325 		   "Problem seeking on raw disk");
326     if (device_instance_read(raw_disk, &boot_block, sizeof(boot_block))
327 	!= sizeof(boot_block))
328       device_error(device_instance_device(raw_disk), "Problem reading boot block");
329 
330     if (partition < 0) {
331       /* select the active partition */
332       if (block0_is_bpb(boot_block)) {
333 	device_error(device_instance_device(raw_disk), "Unimplemented active BPB");
334       }
335       else if (block0_is_fdisk(boot_block)) {
336 	int active = block0_is_fdisk(boot_block);
337 	device_error(device_instance_device(raw_disk), "Unimplemented active FDISK (%d)",
338 		     active);
339       }
340       else if (is_iso9660(raw_disk)) {
341 	device_error(device_instance_device(raw_disk), "Unimplemented active ISO9660");
342       }
343       else if (block0_is_mac_disk(boot_block)) {
344 	device_error(device_instance_device(raw_disk), "Unimplemented active MAC DISK");
345       }
346       else {
347 	device_error(device_instance_device(raw_disk), "Unreconized bootblock");
348       }
349     }
350     else {
351       /* select the specified disk partition */
352       if (block0_is_bpb(boot_block)) {
353 	device_error(device_instance_device(raw_disk), "Unimplemented BPB");
354       }
355       else if (block0_is_fdisk(boot_block)) {
356 	/* return an instance */
357 	ppcboot_partition_t *partition_table = (ppcboot_partition_t*) &boot_block[446];
358 	ppcboot_partition_t *partition_entry;
359 	disklabel *label;
360 	if (partition > 4)
361 	  device_error(device_instance_device(raw_disk),
362 		       "Only FDISK partitions 1..4 supported");
363 	partition_entry = &partition_table[partition - 1];
364 	label = ZALLOC(disklabel);
365 	label->raw_disk = raw_disk;
366 	label->pos = 0;
367 	label->sector_begin = 512 * sector2uw(partition_entry->sector_begin);
368 	label->sector_length = 512 * sector2uw(partition_entry->sector_length);
369 	PTRACE(disklabel, ("partition %ld, sector-begin %ld, length %ld\n",
370 			   (long)partition,
371 			   (long)label->sector_begin,
372 			   (long)label->sector_length));
373 	if (filename != NULL)
374 	  device_error(device_instance_device(raw_disk),
375 		       "FDISK file names not yet supported");
376 	return device_create_instance_from(NULL, raw_disk,
377 					   label,
378 					   NULL, args,
379 					   &package_disklabel_callbacks);
380       }
381       else if (block0_is_mac_disk(boot_block)) {
382 	device_error(device_instance_device(raw_disk), "Unimplemented MAC DISK");
383       }
384       else {
385 	device_error(device_instance_device(raw_disk),
386 		     "Unreconized bootblock");
387       }
388     }
389   }
390 
391   return NULL;
392 }
393 
394 
395 #endif /* _PK_DISKLABEL_C_ */
396 
397