Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / libopenbios / client.c
diff --git a/qemu/roms/openbios/libopenbios/client.c b/qemu/roms/openbios/libopenbios/client.c
new file mode 100644 (file)
index 0000000..8b3d582
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ *   Creation Date: <2003/11/25 14:29:08 samuel>
+ *   Time-stamp: <2004/03/27 01:13:53 samuel>
+ *
+ *     <client.c>
+ *
+ *     OpenFirmware client interface
+ *
+ *   Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   version 2
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "libopenbios/of.h"
+
+/* Uncomment to enable debug printout of client interface calls */
+//#define DEBUG_CIF
+//#define DUMP_IO
+
+/* OF client interface. r3 points to the argument array. On return,
+ * r3 should contain 0==true or -1==false. r4-r12,cr0,cr1 may
+ * be modified freely.
+ *
+ * -1 should only be returned if the control transfer to OF fails
+ * (it doesn't) or if the function is unimplemented.
+ */
+
+#define PROM_MAX_ARGS  10
+typedef struct prom_args {
+    prom_uarg_t service;
+    prom_arg_t  nargs;
+    prom_arg_t  nret;
+    prom_uarg_t args[PROM_MAX_ARGS];
+} __attribute__((packed)) prom_args_t;
+
+static inline const char *
+arg2pointer(prom_uarg_t value)
+{
+    return (char*)(uintptr_t)value;
+}
+
+static inline const char *
+get_service(prom_args_t *pb)
+{
+    return arg2pointer(pb->service);
+}
+
+#ifdef DEBUG_CIF
+static void memdump(const char *mem, unsigned long size)
+{
+       int i;
+       
+       if (size == (unsigned long) -1)
+               return;
+
+       for (i = 0; i < size; i += 16) {
+               int j;
+
+               printk("0x%08lx ", (unsigned long)mem + i);
+
+               for (j = 0; j < 16 && i + j < size; j++)
+                       printk(" %02x", *(unsigned char*)(mem + i + j));
+
+               for ( ; j < 16; j++)
+                       printk(" __");
+
+               printk("  ");
+
+               for (j = 0; j < 16 && i + j < size; j++) {
+                       unsigned char c = *(mem + i + j);
+                       if (isprint(c))
+                               printk("%c", c);
+                       else
+                               printk(".");
+               }
+               printk("\n");
+       }
+}
+
+static void dump_service(prom_args_t *pb)
+{
+       int i;
+       const char *service = get_service(pb);
+       if (strcmp(service, "test") == 0) {
+               printk("test(\"%s\") = ", arg2pointer(pb->args[0]));
+       } else if (strcmp(service, "peer") == 0) {
+               printk("peer(0x" FMT_prom_uargx ") = ", pb->args[0]);
+       } else if (strcmp(service, "child") == 0) {
+               printk("child(0x" FMT_prom_uargx ") = ", pb->args[0]);
+       } else if (strcmp(service, "parent") == 0) {
+               printk("parent(0x" FMT_prom_uargx ") = ", pb->args[0]);
+       } else if (strcmp(service, "instance-to-package") == 0) {
+               printk("instance-to-package(0x" FMT_prom_uargx ") = ", pb->args[0]);
+       } else if (strcmp(service, "getproplen") == 0) {
+               printk("getproplen(0x" FMT_prom_uargx ", \"%s\") = ",
+                       pb->args[0], arg2pointer(pb->args[1]));
+       } else if (strcmp(service, "getprop") == 0) {
+               printk("getprop(0x" FMT_prom_uargx ", \"%s\", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
+                       pb->args[0], arg2pointer(pb->args[1]),
+                       pb->args[2], pb->args[3]);
+       } else if (strcmp(service, "nextprop") == 0) {
+               printk("nextprop(0x" FMT_prom_uargx ", \"%s\", 0x" FMT_prom_uargx ") = ",
+                       pb->args[0], arg2pointer(pb->args[1]), pb->args[2]);
+       } else if (strcmp(service, "setprop") == 0) {
+               printk("setprop(0x" FMT_prom_uargx ", \"%s\", 0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
+                       pb->args[0], arg2pointer(pb->args[1]),
+                       pb->args[2], pb->args[3]);
+               memdump(arg2pointer(pb->args[2]), pb->args[3]);
+               printk(" = ");
+       } else if (strcmp(service, "canon") == 0) {
+               printk("canon(\"%s\", 0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
+                       arg2pointer(pb->args[0]), pb->args[1], pb->args[2]);
+       } else if (strcmp(service, "finddevice") == 0) {
+               printk("finddevice(\"%s\") = ", arg2pointer(pb->args[0]));
+       } else if (strcmp(service, "instance-to-path") == 0) {
+               printk("instance-to-path(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
+                       pb->args[0], pb->args[1], pb->args[2]);
+       } else if (strcmp(service, "package-to-path") == 0) {
+               printk("package-to-path(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
+                       pb->args[0], pb->args[1], pb->args[2]);
+       } else if (strcmp(service, "open") == 0) {
+               printk("open(\"%s\") = ", arg2pointer(pb->args[0]));
+       } else if (strcmp(service, "close") == 0) {
+               printk("close(0x" FMT_prom_uargx ")\n", pb->args[0]);
+       } else if (strcmp(service, "read") == 0) {
+#ifdef DUMP_IO
+               printk("read(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ") = ",
+                       pb->args[0], pb->args[1], pb->args[2]);
+#endif
+       } else if (strcmp(service, "write") == 0) {
+#ifdef DUMP_IO
+               printk("write(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
+                       pb->args[0], pb->args[1], pb->args[2]);
+               memdump(arg2pointer(pb->args[1]), pb->args[2]);
+               printk(" = ");
+#endif
+       } else if (strcmp(service, "seek") == 0) {
+#ifdef DUMP_IO
+               printk("seek(0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ", 0x" FMT_prom_uargx ") = ",
+                       pb->args[0], pb->args[1], pb->args[2]);
+#endif
+       } else if (strcmp(service, "claim") == 0) {
+               printk("claim(0x" FMT_prom_uargx ", " FMT_prom_arg ", " FMT_prom_arg ") = ",
+                       pb->args[0], pb->args[1], pb->args[2]);
+       } else if (strcmp(service, "release") == 0) {
+               printk("release(0x" FMT_prom_uargx ", " FMT_prom_arg ")\n",
+                       pb->args[0], pb->args[1]);
+       } else if (strcmp(service, "boot") == 0) {
+               printk("boot \"%s\"\n", arg2pointer(pb->args[0]));
+       } else if (strcmp(service, "enter") == 0) {
+               printk("enter()\n");
+       } else if (strcmp(service, "exit") == 0) {
+               printk("exit()\n");
+       } else if (strcmp(service, "test-method") == 0) {
+               printk("test-method(0x" FMT_prom_uargx ", \"%s\") = ",
+                       pb->args[0], arg2pointer(pb->args[1]));
+       } else {
+               printk("of_client_interface: %s", service);
+               for( i = 0; i < pb->nargs; i++ )
+                       printk(" " FMT_prom_uargx, pb->args[i]);
+               printk("\n");
+       }
+}
+
+static void dump_return(prom_args_t *pb)
+{
+       int i;
+       const char *service = get_service(pb);
+       if (strcmp(service, "test") == 0) {
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "peer") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "child") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "parent") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "instance-to-package") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "getproplen") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "getprop") == 0) {
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+               if ((prom_arg_t)pb->args[pb->nargs] != -1)
+                       memdump(arg2pointer(pb->args[2]), MIN(pb->args[3], pb->args[pb->nargs]));
+       } else if (strcmp(service, "nextprop") == 0) {
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+               memdump(arg2pointer(pb->args[2]), 32);
+       } else if (strcmp(service, "setprop") == 0) {
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "canon") == 0) {
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+               memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
+       } else if (strcmp(service, "finddevice") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "instance-to-path") == 0) {
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+               memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
+       } else if (strcmp(service, "package-to-path") == 0) {
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+               memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
+       } else if (strcmp(service, "open") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "close") == 0) {
+               /* do nothing */
+       } else if (strcmp(service, "read") == 0) {
+#ifdef DUMP_IO
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+               memdump(arg2pointer(pb->args[1]), pb->args[pb->nargs]);
+#endif
+       } else if (strcmp(service, "write") == 0) {
+#ifdef DUMP_IO
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+#endif
+       } else if (strcmp(service, "seek") == 0) {
+#ifdef DUMP_IO
+               printk(FMT_prom_arg "\n", pb->args[pb->nargs]);
+#endif
+       } else if (strcmp(service, "claim") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else if (strcmp(service, "release") == 0) {
+               /* do nothing */
+       } else if (strcmp(service, "boot") == 0) {
+               /* do nothing */
+       } else if (strcmp(service, "enter") == 0) {
+               /* do nothing */
+       } else if (strcmp(service, "exit") == 0) {
+               /* do nothing */
+       } else if (strcmp(service, "test-method") == 0) {
+               printk("0x" FMT_prom_uargx "\n", pb->args[pb->nargs]);
+       } else {
+               printk("of_client_interface return:");
+               for (i = 0; i < pb->nret; i++) {
+                       printk(" " FMT_prom_uargx, pb->args[pb->nargs + i]);
+               }
+               printk("\n");
+       }
+}
+#endif
+
+/* call-method, interpret */
+static int
+handle_calls(prom_args_t *pb)
+{
+       int i, j, dstacksave;
+       ucell val;
+
+#ifdef DEBUG_CIF
+       printk("%s %s ([" FMT_prom_arg "] -- [" FMT_prom_arg "])\n",
+               get_service(pb), arg2pointer(pb->args[0]), pb->nargs, pb->nret);
+#endif
+
+       dstacksave = dstackcnt;
+       for (i = pb->nargs - 1; i >= 0; i--)
+               PUSH(pb->args[i]);
+
+       push_str(get_service(pb));
+       fword("client-call-iface");
+
+       /* Ignore client-call-iface return */
+       POP();
+
+       /* If the catch result is non-zero, restore stack and exit */
+       val = POP();
+       if (val) {
+               printk("%s %s failed with error " FMT_ucellx "\n", get_service(pb), arg2pointer(pb->args[0]), val);
+               dstackcnt = dstacksave;
+               return 0;
+       }
+
+       /* Store catch result */
+       pb->args[pb->nargs] = val;
+       
+       j = dstackcnt;
+       for (i = 1; i < pb->nret; i++, j--) {
+                if (dstackcnt > dstacksave) {
+                       pb->args[pb->nargs + i] = POP();
+               }
+       }
+
+#ifdef DEBUG_CIF
+       /* useful for debug but not necessarily an error */
+       if (j != dstacksave) {
+               printk("%s '%s': possible argument error (" FMT_prom_arg "--" FMT_prom_arg ") got %d\n",
+                       get_service(pb), arg2pointer(pb->args[0]),
+                       pb->nargs - 2, pb->nret, j - dstacksave);
+       }
+
+       printk("handle_calls return:");
+       for (i = 0; i < pb->nret; i++) {
+               printk(" " FMT_prom_uargx, pb->args[pb->nargs + i]);
+       }
+       printk("\n");
+#endif
+
+       dstackcnt = dstacksave;
+       return 0;
+}
+
+int
+of_client_interface(int *params)
+{
+       prom_args_t *pb = (prom_args_t*)params;
+       ucell val;
+       int i, j, dstacksave;
+
+       if (pb->nargs < 0 || pb->nret < 0 ||
+            pb->nargs + pb->nret > PROM_MAX_ARGS)
+               return -1;
+
+#ifdef DEBUG_CIF
+       dump_service(pb);
+#endif
+
+       /* call-method exceptions are special */
+       if (!strcmp("call-method", get_service(pb)) || !strcmp("interpret", get_service(pb)))
+               return handle_calls(pb);
+
+       dstacksave = dstackcnt;
+       for (i = pb->nargs - 1; i >= 0; i--)
+               PUSH(pb->args[i]);
+
+       push_str(get_service(pb));
+       fword("client-iface");
+
+       val = POP();
+       if (val) {
+               if (val == -1) {
+                       printk("Unimplemented service %s ([" FMT_prom_arg "] -- [" FMT_prom_arg "])\n",
+                               get_service(pb), pb->nargs, pb->nret);
+               } else {
+#ifdef DEBUG_CIF
+                       printk("Error calling client interface: " FMT_ucellx "\n", val);
+#endif
+               }
+
+               dstackcnt = dstacksave;
+               return -1;
+       }
+
+       j = dstackcnt;
+       for (i = 0; i < pb->nret; i++, j--) {
+               if (dstackcnt > dstacksave) {
+                       pb->args[pb->nargs + i] = POP();
+               }
+       }
+
+#ifdef DEBUG_CIF
+       if (j != dstacksave) {
+               printk("service %s: possible argument error (%d %d)\n",
+                      get_service(pb), i, j - dstacksave);
+
+               /* Some clients request less parameters than the CIF method
+               returns, e.g. getprop with OpenSolaris. Hence we drop any
+               stack parameters on exit after issuing a warning above */
+       }
+
+       dump_return(pb);
+#endif
+
+       dstackcnt = dstacksave;
+       return 0;
+}