Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libpart / isofs.c
1 /*
2  * <isofs.c>
3  *
4  * Open Hack'Ware BIOS ISOFS 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 /* ISO FS partitions handlers */
28 #define ISOFS_BLOCSIZE (2048)
29
30 /* Generic ISO fs descriptor */
31 typedef struct isofs_desc_t isofs_desc_t;
32 struct isofs_desc_t {
33     uint8_t type;
34     uint8_t ID[5];
35     uint8_t version;
36     uint8_t data[2041];
37 } __attribute__ ((packed));
38
39 typedef struct iso_primary_desc_t iso_primary_desc_t;
40 struct iso_primary_desc_t {
41     uint8_t type;
42     uint8_t ID[5];
43     uint8_t version;
44     uint8_t pad0;
45     uint8_t system_id[32];
46     uint8_t volume_id[32];
47     uint8_t pad1[8];
48     uint32_t volume_size;
49 } __attribute__ ((packed));
50
51 /* The only descriptor we're interrested in here
52  * is El-torito boot descriptor
53  */
54 typedef struct isofs_bootdesc_t isofs_bootdesc_t;
55 struct isofs_bootdesc_t {
56     uint8_t type;
57     uint8_t ID[5];
58     uint8_t version;
59     uint8_t sys_ID[32];
60     uint8_t pad[32];
61     uint32_t catalog;
62     uint8_t data[1973];
63 } __attribute__ ((packed));
64
65 #define ISO_BOOTABLE 0x88
66 enum {
67     ISOBOOT_IX86 = 0,
68     ISOBOOT_PPC  = 1,
69     ISOBOOT_MAC  = 2,
70 };
71
72 enum {
73     ISOMEDIA_NOEMUL = 0,
74     ISOMEDIA_FL12   = 1,
75     ISOMEDIA_FL144  = 2,
76     ISOMEDIA_FL288  = 3,
77     ISOMEDIA_HD     = 4,
78 };
79
80 typedef struct isofs_validdesc_t isofs_validdesc_t;
81 struct isofs_validdesc_t {
82     uint8_t ID;
83     uint8_t arch;
84     uint8_t pad[2];
85     uint8_t name[24];
86     uint8_t csum[2];
87     uint16_t key;
88 } __attribute__ ((packed));
89
90 typedef struct isofs_bootcat_t isofs_bootcat_t;
91 struct isofs_bootcat_t {
92     uint8_t bootable;
93     uint8_t media;
94     uint8_t segment[2];
95     uint8_t sys_type;
96     uint8_t pad;
97     uint16_t nsect;
98     uint32_t offset;
99     uint8_t data[20];
100 } __attribute__ ((packed));
101
102 part_t *isofs_probe_partitions (bloc_device_t *bd)
103 {
104     unsigned char name[32];
105     void *buffer;
106     union {
107         isofs_desc_t desc;
108         isofs_bootdesc_t bootdesc;
109         iso_primary_desc_t primdesc;
110     } *desc;
111     isofs_validdesc_t *valid;
112     isofs_bootcat_t *bootcat;
113     part_t *part;
114     uint32_t boot_desc;
115     uint32_t nsect, bloc, offset, length;
116     int i, end_reached;
117
118     part = NULL;
119     buffer = malloc(ISOFS_BLOCSIZE);
120     end_reached = 0;
121     desc = buffer;
122     boot_desc = -1;
123     /* The descriptors start at offset 0x8000 */
124     for (bloc = 0x8000 / ISOFS_BLOCSIZE; end_reached == 0; bloc++) {
125         bd_seek(bd, bloc, 0);
126         if (bd_read(bd, buffer, ISOFS_BLOCSIZE) < 0) {
127             ERROR("%s bloc_read %d failed\n", __func__, bloc);
128             goto error;
129         }
130         if (strncmp("CD001", desc->desc.ID, 5) != 0) {
131             //            MSG("\rNo ISO9660 signature\n");
132             goto error;
133         }
134         /* We found at least one valid descriptor */
135         switch (desc->desc.type) {
136         case 0x00:
137             /* El-torito descriptor, great ! */
138             DPRINTF("El-torito descriptor: %08x %d\n", desc->bootdesc.catalog,
139                     (char *)&desc->bootdesc.catalog - (char *)desc);
140             boot_desc = get_le32(&desc->bootdesc.catalog);
141             break;
142         case 0x01:
143             /* ISOFS primary descriptor */
144             DPRINTF("ISOFS primary descriptor (%d %d)\n",
145                     get_le32(&desc->primdesc.volume_size) * 2048,
146                     get_le32(&desc->primdesc.volume_size));
147             break;
148         case 0x02:
149             /* ISOFS suplementary descriptor */
150             DPRINTF("ISOFS suplementary descriptor\n");
151             break;
152         case 0xFF:
153             /* End of descriptor list */
154             DPRINTF("End of descriptor list\n");
155             end_reached = 1;
156             break;
157         }
158     }
159     if (boot_desc != (uint32_t)(-1)) {
160         /* Find the validation descriptor */
161         bd_seek(bd, boot_desc, 0);
162         for (i = 0; i < (ISOFS_BLOCSIZE / 64); i++) {
163             DPRINTF("ISO catalog...\n");
164             bd_read(bd, buffer, 64);
165             valid = buffer;
166 #if 1
167             if (valid->ID != 0x01 || get_le16(&valid->key) != 0xAA55) {
168                 ERROR("ISO catalog with invalid ID/key: %x %x\n",
169                       valid->ID, valid->key);
170                 continue;
171             }
172 #endif
173 #if 0
174 #if defined (__i386__)
175             if (valid->arch != ISOBOOT_IX86) {
176                 ERROR("ISO catalog not for x86: %d\n", valid->arch);
177                 continue;
178             }
179 #elif defined (__powerpc__) || defined (_ARCH_PPC)
180             if (valid->arch != ISOBOOT_PPC && valid->arch != ISOBOOT_MAC) {
181                 ERROR("ISO catalog not for PPC: %d\n", valid->arch);
182                 continue;
183             }
184 #else
185             ERROR("Unknown host architecture !\n");
186             continue;
187 #endif
188 #endif
189             bootcat = (void *)(valid + 1);
190             if (bootcat->bootable != ISO_BOOTABLE) {
191                 ERROR("Non bootable ISO catalog\n");
192                 continue;
193             }
194             nsect = get_le16(&bootcat->nsect);
195             switch (bootcat->media) {
196             case ISOMEDIA_NOEMUL:
197                 length = nsect * ISOFS_BLOCSIZE;
198                 dprintf("No emulation\n");
199                 break;
200             case ISOMEDIA_FL12:
201                 length = 1200 * 1024;
202                 dprintf("1.2 MB floppy\n");
203                 break;
204             case ISOMEDIA_FL144:
205                 length = 1440 * 1024;
206                 dprintf("1.44 MB floppy\n");
207                 break;
208             case ISOMEDIA_FL288:
209                 length = 2880 * 1024;
210                 dprintf("2.88 MB floppy\n");
211                 break;
212             case ISOMEDIA_HD:
213                 length = nsect * ISOFS_BLOCSIZE;
214                 dprintf("HD image\n");
215                 break;
216             default:
217                 ERROR("Unknown media type: %d\n", bootcat->media);
218                 continue;
219             }
220             offset = get_le32(&bootcat->offset);
221             /* Register boot disc */
222             part = malloc(sizeof(part_t));
223             part->bd = bd;
224             part_set_blocsize(bd, part, ISOFS_BLOCSIZE);
225             part->start = offset;
226             part->size = (length + ISOFS_BLOCSIZE - 1) / ISOFS_BLOCSIZE;
227             part->boot_start.bloc = 0;
228             part->boot_start.offset = 0;
229             part->boot_size.bloc = length / ISOFS_BLOCSIZE;
230             part->boot_size.offset = length % ISOFS_BLOCSIZE;
231             part->boot_load = 0;
232             part->boot_entry = 0;
233             if (valid->name[0] == '\0') {
234                 strcpy(name, "ISOFS");
235             } else {
236                 memcpy(name, valid->name, sizeof(valid->name));
237                 name[sizeof(valid->name)] = '\0';
238             }
239             printf("Partition '%s': %p st %0x size %0x %d\n",
240                    name, part, offset, length, bootcat->media);
241             printf("    boot %0x %0x load %0x entry %0x\n",
242                    part->boot_start.bloc, part->boot_size.bloc,
243                    part->boot_load, part->boot_entry);
244             part->flags = PART_TYPE_ISO9660 | PART_FLAG_BOOT;
245             part_register(bd, part, name, i + 1);
246             fs_raw_set_bootfile(part, part->boot_start.bloc,
247                                 part->boot_start.offset,
248                                 part->boot_size.bloc,
249                                 part->boot_size.offset);
250             break;
251         }
252     }
253 error:
254     free(buffer);
255
256     return part;
257 }