Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libpart / apple.c
1 /*
2  * <apple.c>
3  *
4  * Open Hack'Ware BIOS Apple partition type management
5  * 
6  * Copyright (c) 2004-2005 Jocelyn Mayer
7  * 
8  *   This program is free software; you can redistribute it and/or
9  *   modify it under the terms of the GNU General Public License V2
10  *   as published by the Free Software Foundation
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include "bios.h"
25 #include "libpart.h"
26
27 /* Apple partitions handler */
28 #define HFS_BLOCSIZE (512)
29
30 typedef struct Mac_head_t Mac_head_t;
31 struct Mac_head_t {
32     /* 0x000 */
33     uint8_t signature[2];
34     uint16_t bloc_size;
35     uint32_t bloc_count;
36     /* 0x008 */
37     uint16_t dev_type;
38     uint16_t dev_ID;
39     uint32_t data;
40     /* 0x010 */
41     uint16_t driver_cnt;
42     uint8_t pad[428];
43     /* 0x01BE */
44     uint8_t part_table[0x40];
45     /* 0x1FE */
46     uint8_t magic[2];
47     /* 0x0200 */
48 } __attribute__ ((packed));
49
50 typedef struct Mac_driver_entry_t Mac_driver_entry_t;
51 struct Mac_driver_entry_t {
52     uint32_t start;
53     uint16_t size;
54     uint16_t type;
55 } __attribute__ ((packed));
56
57 typedef enum Mac_partflags_t Mac_partflags_t;
58 enum Mac_partflags_t {
59     MACPART_SPEC2     = 0x0100,
60     MACPART_SPEC1     = 0x0080,
61     MACPART_PIC       = 0x0040,
62     MACPART_WRITABLE  = 0x0020,
63     MACPART_READABLE  = 0x0010,
64     MACPART_BOOTABLE  = 0x0008,
65     MACPART_INUSE     = 0x0004,
66     MACPART_ALLOCATED = 0x0002,
67     MACPART_VALID     = 0x0001,
68 };
69
70 #define MAC_BOOTABLE_PART (MACPART_VALID | MACPART_INUSE | MACPART_BOOTABLE)
71
72 typedef struct Mac_partmap_t Mac_partmap_t;
73 struct Mac_partmap_t {
74     /* 0x000 */
75     uint8_t signature[2];
76     uint8_t res0[2];
77     uint32_t map_cnt;
78     /* 0x008 */
79     uint32_t start_bloc;
80     uint32_t bloc_cnt;
81     /* 0x010 */
82     uint8_t name[32];
83     /* 0x030 */
84     uint8_t type[32];
85     /* 0x050 */
86     uint32_t data_start;
87     uint32_t data_cnt;
88     /* 0x058 */
89     uint32_t flags;
90     uint32_t boot_start;
91     /* 0x060 */
92     uint32_t boot_size;
93     uint32_t boot_load;
94     /* 0x068 */
95     uint32_t boot_load2;
96     uint32_t boot_entry;
97     /* 0x070 */
98     uint32_t boot_entry2;
99     uint32_t boot_csum;
100     /* 0x078 */
101     uint8_t CPU[16];
102     /* 0x088 */
103     uint8_t boot_args[0x80];
104     /* 0x108 */
105     uint8_t pad0[0xC8];
106     /* 0x1D4  */
107     uint16_t ntype;
108     uint8_t ff[2];
109     /* 0x1D8 */
110     uint8_t pad1[0x24];
111     /* 0x1FC */
112     uint8_t mark[4];
113     /* 0x200 */
114 } __attribute__ ((packed));
115
116 int fs_raw_set_bootfile (part_t *part,
117                          uint32_t start_bloc, uint32_t start_offset,
118                          uint32_t size_bloc, uint32_t size_offset);
119
120 part_t *Apple_probe_partitions (bloc_device_t *bd)
121 {
122     unsigned char tmp[33], *name;
123     Mac_head_t *head;
124     Mac_partmap_t *partmap;
125     part_t *part, *boot_part;
126     unsigned char *type;
127     uint8_t *buffer;
128     uint32_t pos, bloc, start, count;
129     uint32_t bloc_size, flags;
130     int map_count, i, n, len;
131
132     part = NULL;
133     boot_part = NULL;
134     n = 1;
135     buffer = malloc(HFS_BLOCSIZE);
136     /* Read first sector */
137     bd_seek(bd, 0, 0);
138     if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) {
139         ERROR("Unable to read boot sector from boot device. Aborting...\n");
140         goto error;
141     }
142     head = (Mac_head_t *)buffer;
143     if (head->signature[0] != 'E' || head->signature[1] != 'R') {
144         //        MSG("\rNo Apple boot bloc signature...\n");
145         goto error;
146     }
147     MSG("\rFound Apple partition map...\n");
148     bloc = 0;
149     bloc_size = bd_seclen(bd);
150     map_count = 1;
151 #if 0
152     if (head->magic[0] == 0x55 && head->magic[1] == 0xAA) {
153         /* PREP boot image ! Must parse it as MS-DOS boot bloc */
154         ERROR("%s PREP head magic\n", __func__);
155         goto error;
156     }
157 #endif
158     /* Partition table starts in sector 1 */
159     for (i = 1; i < (map_count + 1); i++) {
160         bloc = (i * HFS_BLOCSIZE) / bloc_size;
161         pos = (i * HFS_BLOCSIZE) % bloc_size;
162         DPRINTF("Check part %d of %d (%d %d %d)\n",
163                 i, map_count, bloc, pos, bloc_size);
164         bd_seek(bd, bloc, pos);
165         if (bd_read(bd, buffer, HFS_BLOCSIZE) < 0) {
166             ERROR("%s sector_read failed (%d)\n", __func__, i);
167             goto error;
168         }
169         partmap = (Mac_partmap_t *)buffer;
170         if (partmap->signature[0] != 'P' || partmap->signature[1] != 'M' ) {
171             ERROR("%s bad partition signature (%c %c)\n",
172                   __func__, partmap->signature[0], partmap->signature[1]);
173             goto error;
174         }
175         /* We found at least one Apple partition map,
176          * so we won't have to try to parse with other partition mappings.
177          */
178         for (type = partmap->type; (type - partmap->type) < 32; type++) {
179             if (*type != '\0')
180                 break;
181         }
182         if (partmap->name[0] == '\0') {
183             sprintf(tmp, "part%d", i);
184             name = tmp;
185         } else {
186             name = partmap->name;
187         }
188         /* Regular Apple partition */
189         part = malloc(sizeof(part_t));
190         if (part == NULL) {
191             ERROR("%s: can't allocate partition\n", __func__);
192             return NULL;
193         }
194         memset(part, 0, sizeof(part_t));
195         part->start = partmap->start_bloc;
196         part->size = partmap->bloc_cnt;
197         part_set_blocsize(bd, part, HFS_BLOCSIZE);
198         len = 32 - (type - partmap->type);
199         if (len == 0) {
200             /* Place holder. Skip it */
201             DPRINTF("%s placeholder part\t%d\n", __func__, i);
202             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
203             part_register(bd, part, name, i);
204         } else if (strncmp("Apple_Void", type, 32) == 0) {
205             /* Void partition. Skip it */
206             DPRINTF("%s Void part\t%d [%s]\n", __func__, i, type);
207             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
208             part_register(bd, part, name, i);
209         } else if (strncmp("Apple_Free", type, 32) == 0) {
210             /* Free space. Skip it */
211             DPRINTF("%s Free part (%d)\n", __func__, i);
212             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
213             part_register(bd, part, name, i);
214         } else if (strncmp("Apple_partition_map", type, 32) == 0 ||
215                    strncmp("Apple_Partition_Map", type, 32) == 0
216 #if 0 // Is this really used or is it just a mistake ?
217                 || strncmp("Apple_patition_map", type, 32) == 0
218 #endif
219                    ) {
220             DPRINTF("%s Partition map\t%d [%s]\n", __func__, i, type);
221             /* We are in the partition map descriptor */
222             if (i == 1) {
223                 /* Get the real map blocs count */
224                 map_count = partmap->map_cnt;
225                 DPRINTF("%s: map_count: %d\n", __func__, map_count);
226             } else {
227                 /* Don't about about secondary partition map
228                  * Seems to be used, at least on CDROMs, to describe
229                  * the same partition map with bloc_size = 2048
230                  */
231             }
232             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
233             part_register(bd, part, name, i);
234         } else if (strncmp("Apple_Driver", type, 32) == 0 ||
235                    strncmp("Apple_Driver43", type, 32) == 0 ||
236                    strncmp("Apple_Driver43_CD", type, 32) == 0 ||
237                    strncmp("Apple_Driver_ATA", type, 32) == 0 ||
238                    strncmp("Apple_Driver_ATAPI", type, 32) == 0 ||
239                    strncmp("Apple_FWDriver", type, 32) == 0 ||
240                    strncmp("Apple_Driver_IOKit", type, 32) == 0) {
241             /* Drivers. don't care for now */
242             DPRINTF("%s Drivers part\t%d [%s]\n", __func__, i, type);
243             part->flags = PART_TYPE_APPLE | PART_FLAG_DRIVER;
244             part_register(bd, part, name, i);
245         } else if (strncmp("Apple_Patches", type, 32) == 0) {
246             /* Patches: don't care for now */
247             part->flags = PART_TYPE_APPLE | PART_FLAG_PATCH;
248             part_register(bd, part, name, i);
249             DPRINTF("%s Patches part\t%d [%s]\n", __func__, i, type);
250         } else if (strncmp("Apple_HFS", type, 32) == 0 ||
251                    strncmp("Apple_MFS", type, 32) == 0 ||
252                    strncmp("Apple_UFS", type, 32) == 0 ||
253                    strncmp("Apple_PRODOS", type, 32) == 0 ||
254                    strncmp("Apple_UNIX_SVR2", type, 32) == 0 ||
255                    strncmp("Linux", type, 32) == 0 ||
256                    strncmp("NetBSD/macppc", type, 32) == 0 ||
257                    strncmp("Apple_boot", type, 32) == 0 ||
258                    strncmp("Apple_bootstrap", type, 32) == 0 ||
259                    strncmp("Apple_Bootstrap", type, 32) == 0) {
260             DPRINTF("%s Fs part\t%d [%s]\n", __func__, i, type);
261             /* Filesystems / boot partitions */
262             flags = partmap->flags;
263             start = partmap->start_bloc * HFS_BLOCSIZE;
264             count = partmap->bloc_cnt * HFS_BLOCSIZE;
265             if (partmap->boot_size == 0 || partmap->boot_load == 0) {
266                 printf("Not a bootable partition %d %d (%p %p)\n",
267                        partmap->boot_size, partmap->boot_load,
268                        boot_part, part);
269                 part->flags = PART_TYPE_APPLE | PART_FLAG_FS;
270             } else {
271                 part->boot_start.bloc = partmap->boot_start;
272                 part->boot_start.offset = 0;
273                 part->boot_size.bloc = partmap->boot_size / HFS_BLOCSIZE;
274 #if 0
275                 printf("%0x %0x %0x\n", partmap->boot_size, HFS_BLOCSIZE,
276                        part->boot_size.bloc);
277 #endif
278                 part->boot_size.offset = (partmap->boot_size) % HFS_BLOCSIZE;
279                 part->boot_load = partmap->boot_load;
280                 part->boot_entry = partmap->boot_entry;
281                 fs_raw_set_bootfile(part, part->boot_start.bloc,
282                                     part->boot_start.offset,
283                                     part->boot_size.bloc,
284                                     part->boot_size.offset);
285                 boot_part = part;
286                 part->flags = PART_TYPE_APPLE | PART_FLAG_FS | PART_FLAG_BOOT;
287             }
288             printf("Partition: %d '%s' '%s' st %0x size %0x",
289                     i, name, type, partmap->start_bloc, partmap->bloc_cnt);
290 #ifndef DEBUG
291             printf("\n");
292 #endif
293             DPRINTF(" - %0x %0x %p %p\n",
294                     partmap->boot_start, partmap->boot_size, part, part->fs);
295             DPRINTF("    boot %0x %0x load %0x entry %0x\n",
296                     part->boot_start.bloc, part->boot_size.bloc,
297                     part->boot_load, part->boot_entry);
298             DPRINTF("                           load %0x entry %0x %0x\n",
299                     partmap->boot_load2, partmap->boot_entry2, HFS_BLOCSIZE);
300             part_register(bd, part, name, i);
301         } else {
302             memcpy(tmp, type, 32);
303             tmp[32] = '\0';
304             ERROR("Unknown partition type [%s]\n", tmp);
305             part->flags = PART_TYPE_APPLE | PART_FLAG_DUMMY;
306             part_register(bd, part, name, i);
307         }
308     }
309  error:
310     free(buffer);
311
312     return boot_part;
313
314 }