4 * Open Hack'Ware BIOS CHRP boot file loader
6 * Copyright (c) 2004-2005 Jocelyn Mayer
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
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.
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
27 #include "libfs/libfs.h"
29 /* Simple XML parser */
30 typedef struct XML_tag_t XML_tag_t
;
44 CHRP_TAG_OS_BADGE_ICONS
,
51 CHRP_SCRIPT_IGNORE
= 0,
52 CHRP_SCRIPT_LOAD_BOOT
,
62 static int XML_get_type (const unsigned char *name
)
66 if (strcmp(name
, "CHRP-BOOT") == 0)
67 ret
= CHRP_TAG_CHRP_BOOT
;
68 else if (strcmp(name
, "COMPATIBLE") == 0)
69 ret
= CHRP_TAG_COMPATIBLE
;
70 else if (strcmp(name
, "DESCRIPTION") == 0)
71 ret
= CHRP_TAG_DESCRIPTION
;
72 else if (strcmp(name
, "BOOT-SCRIPT") == 0)
73 ret
= CHRP_TAG_BOOT_SCRIPT
;
74 else if (strcmp(name
, "OS-BADGE-ICONS") == 0)
75 ret
= CHRP_TAG_OS_BADGE_ICONS
;
76 else if (strcmp(name
, "ICON") == 0)
78 else if (strcmp(name
, "BITMAP") == 0)
79 ret
= CHRP_TAG_BITMAP
;
80 else if (strcmp(name
, "LICENSE") == 0)
81 ret
= CHRP_TAG_LICENSE
;
83 ret
= CHRP_TAG_UNKNOWN
;
88 static unsigned char *strfind (const unsigned char *buf
, const unsigned char *str
)
90 const unsigned char *pos
;
91 int len
= strlen(str
);
93 // DPRINTF("Look for '%s' in \n'%s'\n", str, buf);
94 for (pos
= buf
; *pos
!= '\0'; pos
++) {
95 if (memcmp(pos
, str
, len
) == 0)
96 return (unsigned char *)pos
;
102 int exec_load_chrp (inode_t
*file
, void **dest
, void **entry
, void **end
,
105 #define TMPNAME_LEN 512
106 unsigned char tmpname
[TMPNAME_LEN
], *tmpp
, *buf
, *pos
, *endc
, c
;
107 XML_tag_t
*tag
, *tmp
, *first
;
111 int script_type
= CHRP_SCRIPT_IGNORE
;
112 uint32_t crc
, offset
= 0;
116 /* Check the file head */
117 file_seek(file
, loffset
);
118 fs_read(file
, buf
, 11);
119 if (memcmp(buf
, "<CHRP-BOOT>", 11) != 0) {
120 ERROR("Not an Apple CHRP boot file !\n");
123 /* Re-seek at start of the file and start parsing it */
124 file_seek(file
, loffset
);
129 fs_read(file
, &c
, 1);
131 for (state
= XML_STATE_TAG
; state
!= XML_STATE_OUT
;) {
133 fs_read(file
, &c
, 1);
135 if ((state
== XML_STATE_TAG
&& c
!= '>') ||
136 (state
== XML_STATE_DATA
&& c
!= '<')) {
144 if (tag
== NULL
|| strcmp(buf
+ 1, tag
->name
) != 0) {
145 ERROR("XML error: open name: '%s' close name: '%s'\n",
149 DPRINTF("Close tag: '%s'\n", tag
->name
);
150 switch (XML_get_type(tag
->name
)) {
151 case CHRP_TAG_CHRP_BOOT
:
154 case CHRP_TAG_COMPATIBLE
:
157 if (*(char *)tag
->data
== 0x0d) {
160 DPRINTF("Compatible: '%s'\n", pos
);
162 case CHRP_TAG_DESCRIPTION
:
164 if (*(char *)tag
->data
== 0x0d) {
167 DPRINTF("Description: '%s'\n", pos
);
169 case CHRP_TAG_BOOT_SCRIPT
:
170 /* Here is the interresting part... */
171 crc
= crc32(0, tag
->data
, tag
->dlen
);
173 DPRINTF("Forth script: %08x\n%s\n",
174 crc
, (char *)tag
->data
);
178 /* Mandrake 9.1 CD1 boot script */
180 /* Mandrake 10.1 & 10.2 CD1 boot script */
183 /* Gentoo 2004.1 minimal install CD */
184 /* Gentoo 1.4 live CDROM */
185 /* Knopix PPC beta-pre12 */
189 script_type
= CHRP_SCRIPT_LOAD_BOOT
;
194 /* Debian Sarge, installed on a hard disk drive */
195 script_type
= CHRP_SCRIPT_LOAD_BOOT
;
198 /* Linux Fedora Core 3 */
199 script_type
= CHRP_SCRIPT_LOAD_BOOT
;
202 script_type
= CHRP_SCRIPT_LOAD_BOOT
;
210 script_type
= CHRP_SCRIPT_LOAD_BOOT
;
213 /* iBook 2 hw test CDROM */
215 script_type
= CHRP_SCRIPT_LOAD_BOOT
;
220 /* MacOS 9.2 boot script:
221 * the XCOFF loader is embedded in the file...
224 /* iBook 2 restore CD (MacOS X 10.2) */
225 script_type
= CHRP_SCRIPT_EMBEDDED
;
226 pos
= strfind(tag
->data
, "elf-offset");
228 /* Go backward until we get the value */
229 for (--pos
; *pos
< '0' || *pos
> '9'; pos
--)
231 for (; *pos
>= '0' && *pos
<= '9'; pos
--)
233 offset
= strtol(pos
, NULL
, 16);
236 ERROR("Didn't find boot file offset\n");
240 * The executable file is embedded after the script
242 script_type
= CHRP_SCRIPT_EMBEDDED
;
243 DPRINTF("Boot file embedded at the end of boot script\n");
246 ERROR("XML error: unknown Forth script: %08x\n%s\n",
247 crc
, (char *)tag
->data
);
253 switch (script_type
) {
254 case CHRP_SCRIPT_LOAD_BOOT
:
255 pos
= strfind(tag
->data
, "boot");
257 /* Eat everything until file name */
258 for (pos
+= 4; *pos
!= ','; pos
++)
261 for (++pos
; isspace(*pos
) || *pos
== '"'; pos
++)
263 /* Find file name end */
266 *endc
!= ' ' && *endc
!= '"' &&
267 *endc
!= '\n' && *endc
!= '\r';
272 if (memcmp(pos
, "ofwboot", 7) == 0) {
273 for (pos
= endc
+ 1; *pos
== ' '; pos
++)
279 DPRINTF("Real boot file is: '%s'\n", pos
);
280 part
= fs_inode_get_part(file
);
281 /* check if it's a path or just a file */
283 if ((pos
[0] == '/' && pos
[1] == '/') ||
285 unsigned char *bootdir
;
286 bootdir
= fs_get_boot_dirname(part_fs(part
));
287 if (bootdir
== NULL
) {
288 ERROR("Cannot get boot directory name\n");
291 snprintf(tmpname
, TMPNAME_LEN
,
292 "%s/%s", bootdir
, pos
);
293 tmpname
[TMPNAME_LEN
- 1] = '\0';
296 DPRINTF("'%s' => '%s'\n", bootdir
, pos
);
299 inode
= fs_open(part_fs(part
), pos
);
301 ERROR("Real boot inode '%s' not found\n", pos
);
302 /* Try in root directory */
304 for (; *tmpp
== '/'; tmpp
++)
306 snprintf(tmpname
, TMPNAME_LEN
, "/%s", tmpp
);
307 tmpname
[TMPNAME_LEN
- 1] = '\0';
314 ret
= _bootfile_load(inode
, dest
, entry
, end
, 0, -1);
317 case CHRP_SCRIPT_EMBEDDED
:
318 DPRINTF("Exec offset: %d %08x\n", offset
, offset
);
321 case CHRP_SCRIPT_IGNORE
:
325 case CHRP_TAG_OS_BADGE_ICONS
:
329 case CHRP_TAG_BITMAP
:
332 case CHRP_TAG_LICENSE
:
335 if (*(char *)tag
->data
== 0x0d) {
338 DPRINTF("License: '%s'\n", pos
);
341 ERROR("XML error: unknown tag: '%s'\n", tag
->name
);
346 state
= XML_STATE_OUT
;
348 state
= XML_STATE_DATA
;
354 tmp
= malloc(sizeof(XML_tag_t
));
356 ERROR("Cannot allocate new tag\n");
360 /* Ignore tag attributes */
361 pos
= strchr(buf
, ' ');
364 tmp
->name
= strdup(buf
);
368 DPRINTF("Open tag '%s'\n", tag
->name
);
369 state
= XML_STATE_DATA
;
373 if (tag
->data
== NULL
) {
374 tag
->dlen
= pos
- buf
;
375 tag
->data
= malloc(tag
->dlen
);
376 memcpy(tag
->data
, buf
, tag
->dlen
);
378 state
= XML_STATE_TAG
;
384 fs_read(file
, &c
, 1);
385 fs_read(file
, &c
, 1);
389 for (; tag
!= NULL
; tag
= tmp
) {
396 if (ret
== 0 && script_type
== CHRP_SCRIPT_EMBEDDED
) {
397 DPRINTF("Load embedded file from offset %d (%d => %d)\n",
398 offset
, loffset
, loffset
+ offset
);
399 ret
= _bootfile_load(file
, dest
, entry
, end
, loffset
+ offset
, -1);