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);