Commit yaboot 1.3.4-pre3
[yaboot.git] / second / partition.c
1 /* File related stuff
2    
3    Copyright (C) 1999 Benjamin Herrenschmidt
4
5    Todo: Add disklabel (or let OF do it ?). Eventually think about
6          fixing CDROM handling by directly using the ATAPI layer.
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21
22 #include "ctype.h"
23 #include "types.h"
24 #include "stddef.h"
25 #include "stdlib.h"
26 #include "mac-part.h"
27 #include "fdisk-part.h"
28 #include "partition.h"
29 #include "prom.h"
30 #include "string.h"
31 #include "linux/iso_fs.h"
32 #include "debug.h"
33 #include "errors.h"
34
35 /* We currently don't check the partition type, some users
36  * are putting crap there and still expect it to work...
37  */
38 #undef CHECK_FOR_VALID_MAC_PARTITION_TYPE
39
40 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
41 static const char *valid_mac_partition_types[] = {
42     "apple_unix_svr2",
43     "linux",
44     "apple_hfs",
45     "apple_boot",
46     "apple_bootstrap",
47     NULL
48 };
49 #endif
50     
51
52 /* Local functions */
53 static unsigned long swab32(unsigned long value);
54
55 #define MAX_BLOCK_SIZE  2048
56 static unsigned char block_buffer[MAX_BLOCK_SIZE];
57
58 static void
59 add_new_partition(struct partition_t**  list, int part_number, const char *part_type,
60                   const char *part_name, unsigned long part_start, unsigned long part_size,
61                   unsigned short part_blocksize)
62 {
63         struct partition_t*     part;
64         part = (struct partition_t*)malloc(sizeof(struct partition_t));
65         
66         part->part_number = part_number;
67         strncpy(part->part_type, part_type, MAX_PART_NAME);
68         strncpy(part->part_name, part_name, MAX_PART_NAME);
69         part->part_start = part_start;
70         part->part_size = part_size;
71         part->blocksize = part_blocksize;
72
73         /* Tack this entry onto the list */
74         part->next = *list;
75         *list = part;
76 }
77
78 /* Note, we rely on partitions being dev-block-size aligned,
79  * I have to check if it's true. If it's not, then things will get
80  * a bit more complicated
81  */
82 static void
83 partition_mac_lookup( const char *dev_name, prom_handle disk,
84                       unsigned int prom_blksize, struct partition_t** list )
85 {
86         int block, map_size;
87
88         /* block_buffer contains block 0 from the partitions_lookup() stage */
89         struct mac_partition* part = (struct mac_partition *)block_buffer;
90         unsigned short ptable_block_size =
91                         ((struct mac_driver_desc *)block_buffer)->block_size;
92         
93         map_size = 1;
94         for (block=1; block < map_size + 1; block++)
95         {
96 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
97                 int valid = 0;
98                 const char *ptype;
99 #endif
100                 if (prom_readblocks(disk, block, 1, block_buffer) != 1) {
101                         prom_printf("Can't read partition %d\n", block);
102                         break;
103                 }
104                 if (part->signature != MAC_PARTITION_MAGIC) {
105 #if 0
106                         prom_printf("Wrong partition %d signature\n", block);
107 #endif
108                         break;
109                 }
110                 if (block == 1)
111                         map_size = part->map_count;
112                 
113 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
114                 /* We don't bother looking at swap partitions of any type, 
115                  * and the rest are the ones we know about */
116                 for (ptype = valid_mac_partition_types; ptype; ptype++)
117                     if (!strcmp (part->type, ptype))
118                     {
119                         valid = 1;
120                         break;
121                     }
122 #if DEBUG
123                 if (!valid)
124                     prom_printf( "MAC: Unsupported partition #%d; type=%s\n",
125                         block, part->type );
126 #endif
127 #endif
128
129
130 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
131                 if (valid)
132 #endif
133                 /* We use the partition block size from the partition table.
134                  * The filesystem implmentations are responsible for mapping
135                  * to their own fs blocksize */
136                     add_new_partition(
137                         list, /* partition list */
138                         block, /* partition number */
139                         part->type, /* type */
140                         part->name, /* name */
141                         part->start_block + part->data_start, /* start */
142                         part->data_count, /* size */
143                         ptable_block_size );
144         }
145 }
146
147 /* 
148  * Same function as partition_mac_lookup(), except for fdisk
149  * partitioned disks.
150  */
151 static void
152 partition_fdisk_lookup( const char *dev_name, prom_handle disk,
153                         unsigned int prom_blksize, struct partition_t** list )
154 {
155         int partition;
156
157         /* fdisk partition tables start at offset 0x1be
158          * from byte 0 of the boot drive.
159          */
160         struct fdisk_partition* part = 
161           (struct fdisk_partition *) (block_buffer + 0x1be);
162
163         for (partition=1; partition <= 4 ;partition++, part++) {
164             if (part->sys_ind == LINUX_NATIVE) {
165                 add_new_partition(  list,
166                                     partition,
167                                     "Linux", /* type */
168                                     '\0', /* name */
169                                     swab32(*(unsigned int *)(part->start4)),
170                                     swab32(*(unsigned int *)(part->size4)),
171                                     512 /*blksize*/ );
172             }
173         }
174 }
175
176 /* I don't know if it's possible to handle multisession and other multitrack
177  * stuffs with the current OF disklabel package. This can still be implemented
178  * with direct calls to atapi stuffs.
179  * Currently, we enter this code for any device of block size 0x2048 who lacks
180  * a MacOS partition map signature.
181  */
182 static int
183 identify_iso_fs(ihandle device, unsigned int *iso_root_block)
184 {
185         int block;
186
187         for (block = 16; block < 100; block++) {
188             struct iso_volume_descriptor  * vdp;
189
190             if (prom_readblocks(device, block, 1, block_buffer) != 1) {
191                 prom_printf("Can't read volume desc block %d\n", block);
192                 break;
193             }
194                 
195             vdp = (struct iso_volume_descriptor *)block_buffer;
196             
197             /* Due to the overlapping physical location of the descriptors, 
198              * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure 
199              * proper identification in this case, we first check for ISO.
200              */
201             if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
202                 *iso_root_block = block;
203                 return 1;
204             }
205         }
206         
207         return 0;
208 }
209
210 struct partition_t*
211 partitions_lookup(const char *device)
212 {
213         ihandle disk;
214         struct mac_driver_desc *desc = (struct mac_driver_desc *)block_buffer;
215         struct partition_t* list = NULL;
216         unsigned int prom_blksize, iso_root_block;
217         
218         strncpy(block_buffer, device, 2040);
219         strcat(block_buffer, ":0");
220         
221         /* Open device */
222         disk = prom_open(block_buffer);
223         if (disk == NULL) {
224                 prom_printf("Can't open device <%s>\n", block_buffer);
225                 goto bail;
226         }
227         prom_blksize = prom_getblksize(disk);
228         DEBUG_F("block size of device is %d\n", prom_blksize);
229
230         if (prom_blksize <= 1)
231                 prom_blksize = 512;
232         if (prom_blksize > MAX_BLOCK_SIZE) {
233                 prom_printf("block_size %d not supported !\n", prom_blksize);
234                 goto bail;
235         }
236         
237         /* Read boot blocs */
238         if (prom_readblocks(disk, 0, 1, block_buffer) != 1) {
239                 prom_printf("Can't read boot blocks\n");
240                 goto bail;
241         }       
242         if (desc->signature == MAC_DRIVER_MAGIC) {
243                 /* pdisk partition format */
244                 partition_mac_lookup(device, disk, prom_blksize, &list);
245         } else if ((block_buffer[510] == 0x55) && (block_buffer[511] == 0xaa)) {
246                 /* fdisk partition format */
247                 partition_fdisk_lookup(device, disk, prom_blksize, &list);
248         } else if (prom_blksize == 2048 && identify_iso_fs(disk, &iso_root_block)) {
249                 add_new_partition(&list,
250                                   0,
251                                   '\0',
252                                   '\0',
253                                   iso_root_block,
254                                   0,
255                                   prom_blksize);
256                 prom_printf("ISO9660 disk\n");
257         } else {
258                 prom_printf("No supported partition table detected\n");
259                 goto bail;
260         }
261
262 bail:
263         prom_close(disk);
264         
265         return list;
266 }
267
268 char *
269 get_part_type(char *device, int partition)
270 {
271      struct partition_t*        parts;
272      struct partition_t*        p;
273      struct partition_t*        found;
274      char *type = NULL;
275
276      if (prom_get_devtype(device) != FILE_DEVICE_BLOCK)
277           return NULL;
278
279      parts = partitions_lookup(device);
280      found = NULL;
281
282      if (!parts)
283           return '\0';
284
285      for (p = parts; p && !found; p=p->next) {
286           DEBUG_F("number: %02d, start: 0x%08lx, length: 0x%08lx, type: %s, name: %s\n",
287                   p->part_number, p->part_start, p->part_size, p->part_type, p->part_name);
288           if ((partition >= 0) && (partition == p->part_number)) {
289                type = strdup(p->part_type);
290                break;
291           }       
292      }
293      if (parts)
294           partitions_free(parts);
295      return type;
296 }
297
298 /* Freed in reverse order of allocation to help malloc'ator */
299 void
300 partitions_free(struct partition_t* list)
301 {
302         struct partition_t*     next;
303         
304         while(list) {
305                 next = list->next;
306                 free(list);
307                 list = next;
308         }
309 }
310 unsigned long
311 swab32(unsigned long value)
312 {
313         __u32 result;
314
315         __asm__("rlwimi %0,%1,24,16,23\n\t"
316             "rlwimi %0,%1,8,8,15\n\t"
317             "rlwimi %0,%1,24,0,7"
318             : "=r" (result)
319             : "r" (value), "0" (value >> 24));
320         return result;
321 }
322
323
324 /* 
325  * Local variables:
326  * c-file-style: "K&R"
327  * c-basic-offset: 5
328  * End:
329  */