direct-io.hg

view xen/arch/powerpc/of_handler/ofh.c @ 15490:06a32f040d64

[POWERPC][FIRMWARE] Firmware can now provide an RTAS stub

If the firmwares devtree contains a /rtas node, then firmware will
supply the interfaces that will allow a small RTAS stub to be
instantiated. The RTAS stub is simply an hvcall that passes the RTAS
command block to the hypervisor.

Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
author Jimi Xenidis <jimix@watson.ibm.com>
date Sun Jun 03 10:39:31 2007 -0400 (2007-06-03)
parents 050de6b53961
children
line source
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * Copyright (C) IBM Corp. 2005
17 *
18 * Authors: Jimi Xenidis <jimix@watson.ibm.com>
19 */
21 #include "ofh.h"
22 #include <stdarg.h>
23 #include <xen/lib.h>
25 /*
26 * 6.3.1 Access to the client interface functions
27 * This is the spec'd maximum
28 */
29 #define PFW_MAXSRVCLEN 31
31 static u32 ofh_maxsrvclen;
33 extern s32 debug(const char *fmt, ...);
35 s32 debug(const char *fmt, ...)
36 {
37 s32 sz;
38 va_list ap;
39 char buf[512];
40 va_start(ap, fmt);
41 sz = vsnprintf(buf, 512, fmt, ap);
42 va_end(ap);
43 ofh_cons_write(buf, sz, &sz);
45 return sz;
46 }
50 void
51 assprint(const char *expr, const char *file, int line, const char *fmt, ...)
52 {
53 char a[15];
55 a[0] = '\n';
56 a[1] = '\n';
57 a[2] = 'O';
58 a[3] = 'F';
59 a[4] = 'H';
60 a[5] = ':';
61 a[6] = 'A';
62 a[7] = 'S';
63 a[8] = 'S';
64 a[9] = 'E';
65 a[10] = 'R';
66 a[11] = 'T';
67 a[12] = '!';
68 a[13] = '\n';
69 a[14] = '\n';
71 s32 actual;
72 u32 t = 1;
73 volatile u32 *tp = &t;
75 (void)expr; (void)file; (void)line; (void)fmt;
77 ofh_cons_write(a, sizeof (a), &actual);
79 /* maybe I can break out of this loop manually (like with a
80 * debugger) */
81 while (*tp) {
82 continue;
83 }
84 }
86 /*
87 * we use elf hash since it is pretty standard
88 */
89 static u32
90 of_hash(const char *s)
91 {
92 u32 hash = 0;
93 u32 hnib;
95 if (s != NULL) {
96 while (*s != '\0') {
97 hash = (hash << 4) + *s++;
98 hnib = hash & 0xf0000000UL;
99 if (hnib != 0) {
100 hash ^= hnib >> 24;
101 }
102 hash &= ~hnib;
103 }
104 }
105 return hash;
106 }
108 static void
109 ofh_service_init(ulong b)
110 {
111 ulong sz;
112 int i;
113 int j = 0;
114 struct ofh_srvc *o;
115 struct ofh_srvc *ofs[] = {
116 DRELA(&ofh_srvc[0], b),
117 DRELA(&ofh_isa_srvc[0], b),
118 NULL
119 };
121 j = 0;
122 while (ofs[j] != NULL) {
123 /* find the maximum string length for services */
124 o = &ofs[j][0];
125 while (o->ofs_name != NULL) {
126 const char *n;
128 n = DRELA(&o->ofs_name[0], b);
129 /* fix it up so we don't have to fix it anymore */
130 o->ofs_name = n;
132 sz = strlen(n);
133 if (sz > *DRELA(&ofh_maxsrvclen, b)) {
134 *DRELA(&ofh_maxsrvclen, b) = sz;
135 }
136 o->ofs_hash =
137 of_hash(n);
138 ++i;
139 ++o;
140 }
141 ++j;
142 }
143 }
146 static void
147 ofh_cpu_init(ofdn_t chosen, ulong b)
148 {
149 static struct ofh_ihandle _ih_cpu_0;
150 void *mem = ofd_mem(b);
151 u32 ih = DRELA((ulong)&_ih_cpu_0, b);
152 struct ofh_ihandle *ihp = (struct ofh_ihandle *)((ulong)ih);
153 const char *cpu_type = DRELA((const char*)"cpu",b);
155 ofdn_t cpu = ofd_node_find_by_prop(mem, OFD_ROOT,
156 DRELA((const char*)"device_type",b),
157 cpu_type, 4);
158 ihp->ofi_node = cpu;
159 ofd_prop_add(mem, chosen, DRELA((const char *)"cpu", b),
160 &ih, sizeof (ih));
161 }
162 static s32
163 mmu_translate(u32 nargs, u32 nrets, s32 argp[], s32 retp[], ulong b)
164 {
165 /* FIXME: need a little more here */
166 nargs = nargs;
167 nrets = nrets;
168 argp = argp;
169 retp = retp;
170 b = b;
171 return OF_SUCCESS;
172 }
174 static void
175 ofh_mmu_init(ofdn_t chosen, ulong b)
176 {
177 static struct ofh_methods _mmu_methods[] = {
178 { "translate", mmu_translate },
179 { NULL, NULL},
180 };
181 static struct ofh_ihandle _ih_mmu = {
182 .ofi_methods = _mmu_methods,
183 };
184 void *mem = ofd_mem(b);
185 u32 ih = DRELA((ulong)&_ih_mmu, b);
187 ofd_prop_add(mem, chosen, DRELA((const char *)"mmu", b),
188 &ih, sizeof (ih));
189 }
191 static void
192 ofh_chosen_init(ulong b)
193 {
194 ofdn_t ph;
195 void *mem = ofd_mem(b);
197 ph = ofd_node_find(mem, DRELA((const char *)"/chosen", b));
199 ofh_vty_init(ph, b);
200 ofh_cpu_init(ph, b);
201 ofh_mmu_init(ph, b);
202 }
204 static void
205 ofh_options_init(ulong b)
206 {
207 void *mem = ofd_mem(b);
208 ofdn_t options;
209 u32 size = 1 << 20;
210 u32 base = b;
211 char buf[20];
212 int i;
215 /* fixup the ihandle */
216 options = ofd_node_find(mem,
217 DRELA((const char *)"options", b));
219 i = snprintf(buf, sizeof (buf), "0x%x", base);
220 ofd_prop_add(mem, options, DRELA((const char *)"real-base", b),
221 buf, i);
223 i = snprintf(buf,sizeof (buf), "0x%x", size);
224 ofd_prop_add(mem, options, DRELA((const char *)"real-size", b),
225 buf, i);
226 }
228 static void
229 ofh_init(ulong b)
230 {
231 ulong sz = (ulong)_end - (ulong)__bss_start;
232 /* clear bss */
233 memset(__bss_start + b, 0, sz);
235 ofh_service_init(b);
236 ofh_chosen_init(b);
237 ofh_rtas_init(b);
238 ofh_options_init(b);
239 }
241 static ofh_func_t *
242 ofh_lookup(const char *service, ulong b)
243 {
244 int j;
245 u32 hash;
246 struct ofh_srvc *o;
247 struct ofh_srvc *ofs[] = {
248 DRELA(&ofh_srvc[0], b),
249 DRELA(&ofh_isa_srvc[0], b),
250 NULL
251 };
252 u32 sz;
254 sz = *DRELA(&ofh_maxsrvclen, b);
256 if (strnlen(service, sz + 1) > sz) {
257 return NULL;
258 }
260 hash = of_hash(service);
262 j = 0;
263 while (ofs[j] != NULL) {
264 /* yes this could be quicker */
265 o = &ofs[j][0];
266 while (o->ofs_name != NULL) {
267 if (o->ofs_hash == hash) {
268 const char *n = o->ofs_name;
269 if (strcmp(service, n) == 0) {
270 return o->ofs_func;
271 }
272 }
273 ++o;
274 }
275 ++j;
276 }
277 return NULL;
278 }
280 s32
281 ofh_nosup(u32 nargs __attribute__ ((unused)),
282 u32 nrets __attribute__ ((unused)),
283 s32 argp[] __attribute__ ((unused)),
284 s32 retp[] __attribute__ ((unused)),
285 ulong b __attribute__ ((unused)))
286 {
287 return OF_FAILURE;
288 }
290 s32
291 ofh_test_method(u32 nargs, u32 nrets, s32 argp[], s32 retp[], ulong b)
292 {
293 if (nargs == 2) {
294 if (nrets == 1) {
295 s32 *ap = DRELA(&ofh_active_package, b);
296 u32 service = (s32)argp[0];
297 const char *method = (const char *)(ulong)argp[1];
298 s32 *stat = &retp[0];
300 (void)ap; (void)service; (void)method;
302 *stat = 0;
303 /* we do not do this yet */
304 return OF_FAILURE;
305 }
306 }
307 return OF_FAILURE;
308 }
309 extern u32 _ofh_inited[0];
310 extern u32 _ofh_lastarg[0];
312 s32
313 ofh_handler(struct ofh_args *args, ulong b)
314 {
315 u32 *inited = (u32 *)DRELA(&_ofh_inited[0],b);
316 u32 *lastarg = (u32 *)DRELA(&_ofh_lastarg[0],b);
317 ofh_func_t *f;
319 if (*inited == 0) {
320 ofh_init(b);
322 if ((ulong)ofd_mem(b) < (ulong)_end + b) {
323 static const char msg[] = "PANIC: OFD and BSS collide\n";
324 s32 dummy;
326 ofh_cons_write(DRELA(&msg[0], b), sizeof (msg), &dummy);
327 for (;;);
328 }
330 *inited = 1;
331 }
333 *lastarg = (ulong)args;
335 f = ofh_lookup((char *)((ulong)args->ofa_service), b);
337 if (f == ((ofh_func_t *)~0UL)) {
338 /* do test */
339 if (args->ofa_nargs == 1) {
340 if (args->ofa_nreturns == 1) {
341 char *name = (char *)(ulong)args->ofa_args[0];
342 if (ofh_lookup(name, b) != NULL) {
343 args->ofa_args[args->ofa_nargs] =
344 OF_SUCCESS;
345 return OF_SUCCESS;
346 }
347 }
348 }
349 return OF_FAILURE;
351 } else if (f != NULL) {
352 return leap(args->ofa_nargs,
353 args->ofa_nreturns,
354 args->ofa_args,
355 &args->ofa_args[args->ofa_nargs],
356 b, f);
357 }
358 return OF_FAILURE;
359 }
361 /*
362 * The following code exists solely to run the handler code standalone
363 */
364 void
365 __ofh_start(void)
366 {
367 s32 ret;
368 u32 of_stdout;
369 u32 ihandle;
370 char buf[1024];
371 u32 args_buf[sizeof (struct ofh_args) + (sizeof (u32) * 10)];
372 struct ofh_args *args;
374 args = (struct ofh_args *)args_buf;
376 args->ofa_service = (u32)"finddevice";
377 args->ofa_nargs = 1;
378 args->ofa_nreturns = 1;
379 args->ofa_args[0] = (u32)"/";
380 args->ofa_args[1] = -1;
381 ret = ofh_start(args);
383 if (ret == OF_SUCCESS) {
384 args->ofa_service = (u32)"finddevice";
385 args->ofa_nargs = 1;
386 args->ofa_nreturns = 1;
387 args->ofa_args[0] = (u32)"/chosen";
388 args->ofa_args[1] = -1;
389 ret = ofh_start(args);
390 }
392 if (ret == OF_SUCCESS) {
393 u32 phandle = args->ofa_args[1];
395 args->ofa_service = (u32)"getprop";
396 args->ofa_nargs = 4;
397 args->ofa_nreturns = 1;
398 args->ofa_args[0] = phandle;
399 args->ofa_args[1] = (ulong)"stdout";
400 args->ofa_args[2] = (ulong)&of_stdout;
401 args->ofa_args[3] = sizeof(of_stdout);
402 args->ofa_args[4] = -1;
403 ret = ofh_start(args);
404 }
406 ihandle = *(u32 *)((ulong)args->ofa_args[2]);
408 if (ret == OF_SUCCESS) {
409 /* instance to path */
410 args->ofa_service = (u32)"instance-to-path";
411 args->ofa_nargs = 3;
412 args->ofa_nreturns = 1;
413 args->ofa_args[0] = ihandle;
414 args->ofa_args[1] = (ulong)buf;
415 args->ofa_args[2] = sizeof (buf);
416 args->ofa_args[3] = -1;
417 ret = ofh_start(args);
419 }
421 if (ret == OF_SUCCESS) {
422 /* open rtas */
423 args->ofa_service = (u32)"open";
424 args->ofa_nargs = 1;
425 args->ofa_nreturns = 1;
426 args->ofa_args[0] = (u32)"/rtas";
427 ret = ofh_start(args);
428 if (ret == OF_SUCCESS) {
429 u32 ir = args->ofa_args[1];
430 args->ofa_service = (u32)"call-method";
431 args->ofa_nargs = 3;
432 args->ofa_nreturns = 2;
433 args->ofa_args[0] = (ulong)"instantiate-rtas";
434 args->ofa_args[1] = ir;
435 args->ofa_args[2] = (ulong)buf;
437 ret = ofh_start(args);
438 }
439 }
441 if (ret == OF_SUCCESS) {
442 const char msg[] = "This is a test";
443 u32 msgsz = sizeof(msg) - 1; /* Includes \0 */
445 args->ofa_service = (u32)"write";
446 args->ofa_nargs = 3;
447 args->ofa_nreturns = 1;
448 args->ofa_args[0] = ihandle;
449 args->ofa_args[1] = (ulong)msg;
450 args->ofa_args[2] = msgsz;
451 args->ofa_args[3] = -1;
452 ret = ofh_start(args);
453 }
455 }