Add qemu 2.4.0
[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         bootscript = malloc(size);
165         if (bootscript == NULL) {
166                 DPRINTF("Can't malloc %d bytes\n", size);
167                 return;
168         }
169
170         if (!is_bootinfo(base)) {
171                 DPRINTF("Not a valid bootinfo memory image\n");
172                 free(bootscript);
173                 return;
174         }
175
176         chrp = 0;
177         tag = 0;
178         taglen = 0;
179         script = 0;
180         scriptvalid = 0;
181         scriptlen = 0;
182         entity = 0;
183         current = 0;
184         while (current < size) {
185
186                 c = base[current++];
187
188                 if (c == '<') {
189                         script = 0;
190                         tag = 1;
191                         taglen = 0;
192                 } else if (c == '>') {
193                         tag = 0;
194                         tagbuf[taglen] = '\0';
195                         if (strncasecmp(tagbuf, "chrp-boot", 9) == 0) {
196                                 chrp = 1;
197                         } else if (chrp == 1) {
198                                 if (strncasecmp(tagbuf, "boot-script", 11) == 0) {
199                                         script = 1;
200                                         scriptlen = 0;
201                                 } else if (strncasecmp(tagbuf, "/boot-script", 12) == 0) {
202
203                                         script = 0;
204                                         bootscript[scriptlen] = '\0';
205
206                                         DPRINTF("got bootscript %s\n",
207                                                 bootscript);
208
209                                         scriptvalid = -1;
210
211                                         break;
212                                 } else if (strncasecmp(tagbuf, "/chrp-boot", 10) == 0)
213                                         break;
214                         }
215                 } else if (tag && taglen < sizeof(tagbuf)) {
216                         tagbuf[taglen++] = c;
217                 } else if (script && c == '&') {
218                         entity = 1;
219                         taglen = 0;
220                 } else if (entity && c ==';') {
221                         entity = 0;
222                         tagbuf[taglen] = '\0';
223                         if (strncasecmp(tagbuf, "lt", 2) == 0) {
224                                 bootscript[scriptlen++] = '<';
225                         } else if (strncasecmp(tagbuf, "gt", 2) == 0) {
226                                 bootscript[scriptlen++] = '>';
227                         } else if (strncasecmp(tagbuf, "device", 6) == 0) {
228                                 strcpy(bootscript + scriptlen, device);
229                                 scriptlen += strlen(device);
230                         } else if (strncasecmp(tagbuf, "partition", 9) == 0) {
231                                 strcpy(bootscript + scriptlen, partition);
232                                 scriptlen += strlen(partition);
233                         } else if (strncasecmp(tagbuf, "directory", 9) == 0) {
234                                 strcpy(bootscript + scriptlen, directory);
235                                 scriptlen += strlen(directory);
236                         } else if (strncasecmp(tagbuf, "filename", 8) == 0) {
237                                 strcpy(bootscript + scriptlen, filename);
238                                 scriptlen += strlen(filename);
239                         } else if (strncasecmp(tagbuf, "full-path", 9) == 0) {
240                                 strcpy(bootscript + scriptlen, bootpath);
241                                 scriptlen += strlen(bootpath);
242                         } else { /* unknown, keep it */
243                                 bootscript[scriptlen] = '&';
244                                 strcpy(bootscript + scriptlen + 1, tagbuf);
245                                 scriptlen += taglen + 1;
246                                 bootscript[scriptlen] = ';';
247                                 scriptlen++;
248                         }
249                 } else if (entity && taglen < sizeof(tagbuf)) {
250                         tagbuf[taglen++] = c;
251                 } else if (script && scriptlen < size) {
252                         bootscript[scriptlen++] = c;
253                 }
254         }
255
256         /* If the payload is bootinfo then we execute it immediately */
257         if (scriptvalid) {
258                 DPRINTF("bootscript: %s\n", bootscript);
259                 feval(bootscript);
260         }
261         else
262                 DPRINTF("Unable to parse bootinfo bootscript\n");
263 }