Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openhackware / src / libpart / prep.c
1 /*
2  * <prep.c>
3  *
4  * Open Hack'Ware PREP BIOS 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 /* PREP image management */
28 typedef struct MSDOS_part_t MSDOS_part_t;
29 struct MSDOS_part_t {
30     uint8_t  boot_ind;
31     uint8_t  start_head;
32     uint8_t  start_sect;
33     uint8_t  start_cyl;
34     uint8_t  sys_ind;
35     uint8_t  end_head;
36     uint8_t  end_sect;
37     uint8_t  end_cyl;
38     uint32_t LBA_start;
39     uint32_t LBA_end;
40 }  __attribute__ ((packed));
41
42 part_t *PREP_find_partition (bloc_device_t *bd)
43 {
44     MSDOS_part_t *p;
45     part_t *part;
46     uint8_t *buffer;
47     uint32_t boot_offset, boot_size;
48     int i;
49
50     part = NULL;
51     buffer = malloc(0x200);
52     bd_seek(bd, 0, 0);
53     if (bd_read(bd, buffer, 0x200) < 0) {
54         ERROR("Unable to read boot sector from boot device. Aborting...\n");
55         goto error;
56     }
57     if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) {
58         ERROR("No MSDOS signature (%x %x %x %x)\n",
59               buffer[0x000], buffer[0x001], buffer[0x1FE], buffer[0x1FF]);
60         goto error;
61     }
62     for (i = 0; i < 4; i++) {
63         p = (void *)(&buffer[0x1BE + (0x10 * i)]);
64         DPRINTF("partition %d: %x is %sbootable - ", i, p->boot_ind,
65                 (p->boot_ind & 0x80) ? "" : "not ");
66         DPRINTF("start %0x end %0x type %x\n",
67                 get_le32(&p->LBA_start), get_le32(&p->LBA_end), p->sys_ind);
68 #if 0
69         if (p->boot_ind != 0x80)
70             continue;
71 #endif
72         switch (p->sys_ind) {
73         case 0x07: /* HPFS/NTFS */
74             goto register_nonboot;
75         case 0x08: /* AIX */
76             goto register_nonboot;
77         case 0x09: /* AIX bootable */
78             /* Not supported by now */
79             break;
80         case 0x0A: /* OS/2 boot manager */
81             /* Not supported by now */
82             break;
83         case 0x41: /* PREP boot */
84             part = malloc(sizeof(part_t));
85             memset(part, 0, sizeof(part_t));
86             part->bd = bd;
87             part_set_blocsize(bd, part, 0x200);
88             /* Convert start and size into LBA */
89             if ((p->start_head != 0 || p->start_cyl != 0 ||
90                  p->start_sect != 0) && p->LBA_start == 0) {
91                 DPRINTF("start: use CHS\n");
92                 part->start = bd_CHS2sect(bd, p->start_cyl,
93                                           p->start_head,
94                                           p->start_sect);
95             } else {
96                 DPRINTF("start: use LBA\n");
97                 part->start = get_le32(&p->LBA_start);
98             }
99             if ((p->end_head != 0 || p->end_cyl != 0 ||
100                  p->end_sect != 0) && p->LBA_end == 0) {
101                 DPRINTF("end: use CHS\n");
102                 part->size = bd_CHS2sect(bd, p->end_cyl,
103                                          p->end_head, p->end_sect);
104             } else {
105                 DPRINTF("end: use LBA\n");
106                 part->size = get_le32(&p->LBA_end);
107             }
108             /* XXX: seems that some (AIX !)
109              * code the size here instead of partition end
110              */
111             if (part->size > part->start)
112                 part->size -= part->start;
113             DPRINTF("LBA: start %0x size: %0x\n", part->start, part->size);
114             /* Now, find and check boot record */
115             part_seek(part, 0, 0);
116             if (bd_read(bd, buffer, part->bloc_size) < 0) {
117                 ERROR("%s sector_read failed (%d)\n", __func__, i);
118                 freep(&part);
119                 goto error;
120             }
121 #if 0
122             if (buffer[0x1FE] != 0x55 || buffer[0x1FF] != 0xAA) {
123                 ERROR("No MSDOS signature on PREP boot record\n");
124                 freep(&part);
125                 goto error;
126             }
127 #endif
128             boot_offset = get_le32(buffer);
129             boot_size =  get_le32(buffer + 4);
130             if ((boot_offset & 3) || /*(boot_size & 3) ||*/
131                 boot_offset == 0 || boot_size == 0) {
132                 DPRINTF("Suspicious PREP boot parameters: %08x %08x %08x %08x\n",
133                     part->start, part->start * 0x200, boot_offset, boot_size);
134 #if 0
135                 freep(&part);
136                 goto error;
137 #else
138                 /* IBM boot blocs respect the norm better than others... */
139                 part->start++;
140                 part_seek(part, 0, 0);
141                 if (bd_read(bd, buffer, part->bloc_size) < 0) {
142                     ERROR("%s sector_read failed (%d)\n", __func__, i);
143                     freep(&part);
144                     goto error;
145                 }
146                 boot_offset = get_le32(buffer);
147                 boot_size =  get_le32(buffer + 4);
148 #endif
149             }
150             DPRINTF("PREP boot parameters: %08x %08x %08x %08x\n",
151                     part->start, part->start * 0x200, boot_offset, boot_size);
152             if (boot_size > (part->size * part->bloc_size)) {
153                 ERROR("PREP boot image greater than boot partition: %0x %0x\n",
154                       boot_size, part->size * part->bloc_size);
155 #if 0
156                 freep(&part);
157                 goto error;
158 #endif
159             }
160             part->boot_start.bloc = 0;
161             part->boot_start.offset = 0;
162             part->boot_size.bloc = boot_size / part->bloc_size;
163             part->boot_size.offset = boot_size % part->bloc_size;
164             part->boot_load = 0;
165             part->boot_entry = boot_offset - part->bloc_size;
166             part->flags = PART_TYPE_PREP | PART_FLAG_BOOT;
167             part_register(bd, part, "PREP boot", i);
168             fs_raw_set_bootfile(part, part->boot_start.bloc,
169                                 part->boot_start.offset,
170                                 part->boot_size.bloc,
171                                 part->boot_size.offset);
172             break;
173         case 0x63: /* GNU Hurd */
174             goto register_nonboot;
175         case 0x83: /* Linux */
176             goto register_nonboot;
177         case 86 ... 87: /* NFTS volume set */
178             /* Not supported by now */
179             break;
180         case 0x8E: /* Linux LVM */
181             /* Not supported by now */
182             break;
183         case 0x96: /* AIX seems to use this to identify ISO 9660 'partitions' */
184             break;
185         case 0xA5: /* FreeBSD */
186             goto register_nonboot;
187         case 0xA6: /* OpenBSD */
188             goto register_nonboot;
189         case 0xA7: /* NeXTSTEP */
190             goto register_nonboot;
191         case 0xA8: /* Darwin UFS */
192             goto register_nonboot;
193         case 0xA9: /* NetBSD */
194             goto register_nonboot;
195         case 0xAB: /* Darwin boot */
196             /* Not supported by now */
197             break;
198         case 0xBE: /* Solaris boot */
199             /* Not supported by now */
200             break;
201         case 0xEB: /* BeOS fs */
202             goto register_nonboot;
203         case 0xFD: /* Linux RAID */
204             /* Not supported by now */
205             break;
206         default:
207             break;
208         register_nonboot:
209             break;
210         }
211     }
212  error:
213     free(buffer);
214
215     return part;
216 }