These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / openbios / libopenbios / bootinfo_load.c
1 /*
2  *
3  *       <bootinfo_load.c>
4  *
5  *       bootinfo file loader
6  *
7  *   Copyright (C) 2009 Laurent Vivier (Laurent@vivier.eu)
8  *
9  *   Original XML parser by Blue Swirl <blauwirbel@gmail.com>
10  *
11  *   This program is free software; you can redistribute it and/or
12  *   modify it under the terms of the GNU General Public License
13  *   version 2
14  *
15  */
16
17 #include "config.h"
18 #include "libopenbios/bindings.h"
19 #include "libopenbios/bootinfo_load.h"
20 #include "libopenbios/ofmem.h"
21 #include "libc/vsprintf.h"
22
23 //#define DEBUG_BOOTINFO
24
25 #ifdef DEBUG_BOOTINFO
26 #define DPRINTF(fmt, args...) \
27     do { printk("%s: " fmt, __func__ , ##args); } while (0)
28 #else
29 #define DPRINTF(fmt, args...) \
30     do { } while (0)
31 #endif
32
33 static char *
34 get_device( const char *path )
35 {
36         int i;
37         static char buf[1024];
38
39         for (i = 0; i < sizeof(buf) && path[i] && path[i] != ':'; i++)
40                 buf[i] = path[i];
41         buf[i] = 0;
42
43         return buf;
44 }
45
46 static char *
47 get_partition( const char *path )
48 {
49         static char buf[2];
50
51         buf[0] = '\0';
52         buf[1] = '\0';
53
54         while ( *path && *path != ':' )
55                 path++;
56
57         if (!*path)
58                 return buf;
59         path++;
60
61         if (path[0] == ',' || !strchr(path, ',')) /* if there is not a ',' or no partition id then return */
62                 return buf;
63
64         /* Must be a partition id */
65         buf[0] = path[0];
66
67         return buf;
68 }
69
70 static char *
71 get_filename( const char * path , char **dirname)
72 {
73         static char buf[1024];
74         char *filename;
75
76         while ( *path && *path != ':' )
77                 path++;
78
79         if (!*path) {
80                 *dirname = NULL;
81                 return NULL;
82         }
83         path++;
84
85         while ( *path && isdigit(*path) )
86                 path++;
87
88         if (*path == ',')
89                 path++;
90
91         strncpy(buf, path, sizeof(buf));
92         buf[sizeof(buf) - 1] = 0;
93
94         filename = strrchr(buf, '\\');
95         if (filename) {
96                 *dirname = buf;
97                 (*filename++) = 0;
98         } else {
99                 *dirname = NULL;
100                 filename = buf;
101         }
102
103         return filename;
104 }
105
106 int
107 is_bootinfo(char *bootinfo)
108 {
109         return (strncasecmp(bootinfo, "<chrp-boot", 10) ? 0 : -1);
110 }
111
112 int 
113 bootinfo_load(struct sys_info *info, const char *filename)
114 {
115         // Currently not implemented
116         return LOADER_NOT_SUPPORT;
117 }
118
119 /*
120   Parse SGML structure like:
121   <chrp-boot>
122   <description>Debian/GNU Linux Installation on IBM CHRP hardware</description>
123   <os-name>Debian/GNU Linux for PowerPC</os-name>
124   <boot-script>boot &device;:\install\yaboot</boot-script>
125   <icon size=64,64 color-space=3,3,2>
126
127   CHRP system bindings are described at:
128   http://playground.sun.com/1275/bindings/chrp/chrp1_7a.ps
129 */
130
131 void
132 bootinfo_init_program(void)
133 {
134         char *base;
135         int proplen;
136         phandle_t chosen;
137         int tag, taglen, script, scriptlen, scriptvalid, entity, chrp;
138         char tagbuf[128], c;
139         char *device, *filename, *directory, *partition;
140         int current, size;
141         char *bootscript;
142         char *tmp;
143         char bootpath[1024];
144
145         /* Parse the boot script */
146
147         chosen = find_dev("/chosen");
148         tmp = get_property(chosen, "bootpath", &proplen);
149         memcpy(bootpath, tmp, proplen);
150         bootpath[proplen] = 0;
151
152         DPRINTF("bootpath %s\n", bootpath);
153
154         device = get_device(bootpath);
155         partition = get_partition(bootpath);
156         filename = get_filename(bootpath, &directory);
157
158         feval("load-base");
159         base = (char*)cell2pointer(POP());
160
161         feval("load-size");
162         size = POP();
163
164         /* Some bootinfo scripts contain a binary payload after the
165            NULL-terminated Forth string such as OS 9. Restrict our
166            size to just the Forth section, otherwise we end up trying
167            to allocate memory for the entire binary which might fail. */
168         size = strnlen(base, size);
169
170         bootscript = malloc(size);
171         if (bootscript == NULL) {
172                 DPRINTF("Can't malloc %d bytes\n", size);
173                 return;
174         }
175
176         if (!is_bootinfo(base)) {
177                 DPRINTF("Not a valid bootinfo memory image\n");
178                 free(bootscript);
179                 return;
180         }
181
182         chrp = 0;
183         tag = 0;
184         taglen = 0;
185         script = 0;
186         scriptvalid = 0;
187         scriptlen = 0;
188         entity = 0;
189         current = 0;
190         while (current < size) {
191
192                 c = base[current++];
193
194                 if (c == '<') {
195                         script = 0;
196                         tag = 1;
197                         taglen = 0;
198                 } else if (c == '>') {
199                         tag = 0;
200                         tagbuf[taglen] = '\0';
201                         if (strncasecmp(tagbuf, "chrp-boot", 9) == 0) {
202                                 chrp = 1;
203                         } else if (chrp == 1) {
204                                 if (strncasecmp(tagbuf, "boot-script", 11) == 0) {
205                                         script = 1;
206                                         scriptlen = 0;
207                                 } else if (strncasecmp(tagbuf, "/boot-script", 12) == 0) {
208
209                                         script = 0;
210                                         bootscript[scriptlen] = '\0';
211
212                                         DPRINTF("got bootscript %s\n",
213                                                 bootscript);
214
215                                         scriptvalid = -1;
216
217                                         break;
218                                 } else if (strncasecmp(tagbuf, "/chrp-boot", 10) == 0)
219                                         break;
220                         }
221                 } else if (tag && taglen < sizeof(tagbuf)) {
222                         tagbuf[taglen++] = c;
223                 } else if (script && c == '&') {
224                         entity = 1;
225                         taglen = 0;
226                 } else if (entity && c ==';') {
227                         entity = 0;
228                         tagbuf[taglen] = '\0';
229                         if (strncasecmp(tagbuf, "lt", 2) == 0) {
230                                 bootscript[scriptlen++] = '<';
231                         } else if (strncasecmp(tagbuf, "gt", 2) == 0) {
232                                 bootscript[scriptlen++] = '>';
233                         } else if (strncasecmp(tagbuf, "device", 6) == 0) {
234                                 strcpy(bootscript + scriptlen, device);
235                                 scriptlen += strlen(device);
236                         } else if (strncasecmp(tagbuf, "partition", 9) == 0) {
237                                 strcpy(bootscript + scriptlen, partition);
238                                 scriptlen += strlen(partition);
239                         } else if (strncasecmp(tagbuf, "directory", 9) == 0) {
240                                 strcpy(bootscript + scriptlen, directory);
241                                 scriptlen += strlen(directory);
242                         } else if (strncasecmp(tagbuf, "filename", 8) == 0) {
243                                 strcpy(bootscript + scriptlen, filename);
244                                 scriptlen += strlen(filename);
245                         } else if (strncasecmp(tagbuf, "full-path", 9) == 0) {
246                                 strcpy(bootscript + scriptlen, bootpath);
247                                 scriptlen += strlen(bootpath);
248                         } else { /* unknown, keep it */
249                                 bootscript[scriptlen] = '&';
250                                 strcpy(bootscript + scriptlen + 1, tagbuf);
251                                 scriptlen += taglen + 1;
252                                 bootscript[scriptlen] = ';';
253                                 scriptlen++;
254                         }
255                 } else if (entity && taglen < sizeof(tagbuf)) {
256                         tagbuf[taglen++] = c;
257                 } else if (script && scriptlen < size) {
258                         bootscript[scriptlen++] = c;
259                 }
260         }
261
262         /* If the payload is bootinfo then we execute it immediately */
263         if (scriptvalid) {
264                 DPRINTF("bootscript: %s\n", bootscript);
265                 feval(bootscript);
266         }
267         else
268                 DPRINTF("Unable to parse bootinfo bootscript\n");
269 }