39f23ca1083e108384b187bc8d87435e7af4b844
[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
33 /* We currently don't check the partition type, some users
34  * are putting crap there and still expect it to work...
35  */
36 #undef CHECK_FOR_VALID_MAC_PARTITION_TYPE
37
38 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
39 static const char *valid_mac_partition_types[] = {
40     "apple_unix_svr2",
41     "linux",
42     "apple_hfs",
43     "apple_boot",
44     "apple_bootstrap",
45     NULL
46 };
47 #endif
48     
49
50 /* Local functions */
51 static unsigned long swab32(unsigned long value);
52
53 #define MAX_BLOCK_SIZE  2048
54 static unsigned char block_buffer[MAX_BLOCK_SIZE];
55
56 static void
57 add_new_partition( struct partition_t** list, int part_number,
58                    unsigned long part_start, unsigned long part_size,
59                    unsigned short part_blocksize )
60 {
61         struct partition_t*     part;
62         part = (struct partition_t*)malloc(sizeof(struct partition_t));
63         
64         part->part_number = part_number;
65         part->part_start = part_start;
66         part->part_size = part_size;
67         part->blocksize = part_blocksize;
68
69         /* Tack this entry onto the list */
70         part->next = *list;
71         *list = part;
72 }
73
74 /* Note, we rely on partitions being dev-block-size aligned,
75  * I have to check if it's true. If it's not, then things will get
76  * a bit more complicated
77  */
78 static void
79 partition_mac_lookup( const char *dev_name, prom_handle disk,
80                       unsigned int prom_blksize, struct partition_t** list )
81 {
82         int block, map_size;
83
84         /* block_buffer contains block 0 from the partitions_lookup() stage */
85         struct mac_partition* part = (struct mac_partition *)block_buffer;
86         unsigned short ptable_block_size =
87                         ((struct mac_driver_desc *)block_buffer)->block_size;
88         
89         map_size = 1;
90         for (block=1; block < map_size + 1; block++)
91         {
92 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
93                 int valid = 0;
94                 const char *ptype;
95 #endif
96                 if (prom_readblocks(disk, block, 1, block_buffer) != 1) {
97                         prom_printf("Can't read partition %d\n", block);
98                         break;
99                 }
100                 if (part->signature != MAC_PARTITION_MAGIC) {
101 #if 0
102                         prom_printf("Wrong partition %d signature\n", block);
103 #endif
104                         break;
105                 }
106                 if (block == 1)
107                         map_size = part->map_count;
108                 
109 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
110                 /* We don't bother looking at swap partitions of any type, 
111                  * and the rest are the ones we know about */
112                 for (ptype = valid_mac_partition_types; ptype; ptype++)
113                     if (!strcmp (part->type, ptype))
114                     {
115                         valid = 1;
116                         break;
117                     }
118 #if DEBUG
119                 if (!valid)
120                     prom_printf( "MAC: Unsupported partition #%d; type=%s\n",
121                         block, part->type );
122 #endif
123 #endif
124
125
126 #ifdef CHECK_FOR_VALID_MAC_PARTITION_TYPE
127                 if (valid)
128 #endif
129                 /* We use the partition block size from the partition table.
130                  * The filesystem implmentations are responsible for mapping
131                  * to their own fs blocksize */
132                     add_new_partition(
133                         list, /* partition list */
134                         block, /* partition number */
135                         part->start_block + part->data_start, /* start */
136                         part->data_count, /* size */
137                         ptable_block_size );
138         }
139 }
140
141 /* 
142  * Same function as partition_mac_lookup(), except for fdisk
143  * partitioned disks.
144  */
145 static void
146 partition_fdisk_lookup( const char *dev_name, prom_handle disk,
147                         unsigned int prom_blksize, struct partition_t** list )
148 {
149         int partition;
150
151         /* fdisk partition tables start at offset 0x1be
152          * from byte 0 of the boot drive.
153          */
154         struct fdisk_partition* part = 
155           (struct fdisk_partition *) (block_buffer + 0x1be);
156
157         for (partition=1; partition <= 4 ;partition++, part++) {
158             if (part->sys_ind == LINUX_NATIVE) {
159                 add_new_partition(  list,
160                                     partition,
161                                     swab32(*(unsigned int *)(part->start4)),
162                                     swab32(*(unsigned int *)(part->size4)),
163                                     512 /*blksize*/ );
164             }
165         }
166 }
167
168 /* I don't know if it's possible to handle multisession and other multitrack
169  * stuffs with the current OF disklabel package. This can still be implemented
170  * with direct calls to atapi stuffs.
171  * Currently, we enter this code for any device of block size 0x2048 who lacks
172  * a MacOS partition map signature.
173  */
174 static int
175 identify_iso_fs(ihandle device, unsigned int *iso_root_block)
176 {
177         int block;
178
179         for (block = 16; block < 100; block++) {
180             struct iso_volume_descriptor  * vdp;
181
182             if (prom_readblocks(device, block, 1, block_buffer) != 1) {
183                 prom_printf("Can't read volume desc block %d\n", block);
184                 break;
185             }
186                 
187             vdp = (struct iso_volume_descriptor *)block_buffer;
188             
189             /* Due to the overlapping physical location of the descriptors, 
190              * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure 
191              * proper identification in this case, we first check for ISO.
192              */
193             if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
194                 *iso_root_block = block;
195                 return 1;
196             }
197         }
198         
199         return 0;
200 }
201
202 struct partition_t*
203 partitions_lookup(const char *device)
204 {
205         ihandle disk;
206         struct mac_driver_desc *desc = (struct mac_driver_desc *)block_buffer;
207         struct partition_t* list = NULL;
208         unsigned int prom_blksize, iso_root_block;
209         
210         strncpy(block_buffer, device, 2040);
211         strcat(block_buffer, ":0");
212         
213         /* Open device */
214         disk = prom_open(block_buffer);
215         if (disk == NULL) {
216                 prom_printf("Can't open device <%s>\n", block_buffer);
217                 goto bail;
218         }
219         prom_blksize = prom_getblksize(disk);
220 #if DEBUG
221         prom_printf("block size of device is %d\n", prom_blksize);
222 #endif  
223         if (prom_blksize <= 1)
224                 prom_blksize = 512;
225         if (prom_blksize > MAX_BLOCK_SIZE) {
226                 prom_printf("block_size %d not supported !\n", prom_blksize);
227                 goto bail;
228         }
229         
230         /* Read boot blocs */
231         if (prom_readblocks(disk, 0, 1, block_buffer) != 1) {
232                 prom_printf("Can't read boot blocs\n");
233                 goto bail;
234         }       
235         if (desc->signature == MAC_DRIVER_MAGIC) {
236                 /* pdisk partition format */
237                 partition_mac_lookup(device, disk, prom_blksize, &list);
238         } else if ((block_buffer[510] == 0x55) && (block_buffer[511] == 0xaa)) {
239                 /* fdisk partition format */
240                 partition_fdisk_lookup(device, disk, prom_blksize, &list);
241         } else if (prom_blksize == 2048 && identify_iso_fs(disk, &iso_root_block)) {
242                 add_new_partition(      &list,
243                                 0,
244                                 iso_root_block,
245                                 0,
246                                 prom_blksize);
247                 prom_printf("ISO9660 disk\n");
248         } else {
249                 prom_printf("No supported partition table detected\n");
250                 goto bail;
251         }
252
253 bail:
254         prom_close(disk);
255         
256         return list;
257 }
258
259 /* Freed in reverse order of allocation to help malloc'ator */
260 void
261 partitions_free(struct partition_t* list)
262 {
263         struct partition_t*     next;
264         
265         while(list) {
266                 next = list->next;
267                 free(list);
268                 list = next;
269         }
270 }
271 unsigned long
272 swab32(unsigned long value)
273 {
274         __u32 result;
275
276         __asm__("rlwimi %0,%1,24,16,23\n\t"
277             "rlwimi %0,%1,8,8,15\n\t"
278             "rlwimi %0,%1,24,0,7"
279             : "=r" (result)
280             : "r" (value), "0" (value >> 24));
281         return result;
282 }
283
284