Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / takeover / main.c
diff --git a/qemu/roms/SLOF/clients/takeover/main.c b/qemu/roms/SLOF/clients/takeover/main.c
new file mode 100644 (file)
index 0000000..360d8ea
--- /dev/null
@@ -0,0 +1,163 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ *     IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <of.h>
+#include <pci.h>
+#include <cpu.h>
+#include <ioctl.h>
+#include <takeover.h>
+
+extern void call_client_interface(of_arg_t *);
+extern void m_sync(void);
+
+int callback(int argc, char *argv[]);
+
+#define boot_rom_bin_start _binary_______boot_rom_bin_start
+#define boot_rom_bin_end   _binary_______boot_rom_bin_end
+
+extern char boot_rom_bin_start;
+extern char boot_rom_bin_end;
+
+#if defined(__GNUC__)
+# define UNUSED __attribute__((unused))
+#else
+# define UNUSED
+#endif
+
+void *
+sbrk(int incr)
+{
+       return (void *) -1;
+}
+
+static void
+doWait(void)
+{
+       static const char *wheel = "|/-\\";
+       static int i = 0;
+       volatile int dly = 0xf0000;
+       while (dly--)
+               asm volatile (" nop ");
+       printf("\b%c", wheel[i++]);
+       i &= 0x3;
+}
+
+static void
+quiesce(void)
+{
+       of_arg_t arg = {
+               p32cast "quiesce",
+               0, 0,
+       };
+       call_client_interface(&arg);
+}
+
+static int
+startCpu(int num, int addr, int reg)
+{
+       of_arg_t arg = {
+               p32cast "start-cpu",
+               3, 0,
+               {num, addr, reg}
+       };
+       call_client_interface(&arg);
+       return arg.args[3];
+}
+
+volatile unsigned long slaveQuitt;
+int takeoverFlag;
+
+void
+main(int argc, char *argv[])
+{
+       phandle_t cpus;
+       phandle_t cpu;
+       unsigned long slaveMask;
+       extern int slaveLoop[];
+       extern int slaveLoopNoTakeover[];
+       int index = 0;
+       int delay = 100;
+       unsigned long reg;
+       unsigned long msr;
+
+       asm volatile ("mfmsr %0":"=r" (msr));
+       if (msr & 0x1000000000000000)
+               takeoverFlag = 0;
+       else
+               takeoverFlag = 1;
+
+       cpus = of_finddevice("/cpus");
+       cpu = of_child(cpus);
+       slaveMask = 0;
+       while (cpu) {
+               char devType[100];
+               *devType = '\0';
+               of_getprop(cpu, "device_type", devType, sizeof(devType));
+               if (strcmp(devType, "cpu") == 0) {
+                       of_getprop(cpu, "reg", &reg, sizeof(reg));
+                       if (index) {
+                               printf("\r\n takeover on cpu%d (%x, %lx) ", index,
+                                      cpu, reg);
+                               slaveQuitt = -1;
+                               if (takeoverFlag)
+                                       startCpu(cpu, (int)(unsigned long)slaveLoop, index);
+                               else
+                                       startCpu(cpu, (int)(unsigned long)slaveLoopNoTakeover,
+                                                index);
+                               slaveMask |= 0x1 << index;
+                               delay = 100;
+                               while (delay-- && slaveQuitt)
+                                       doWait();
+                       }
+                       index++;
+               }
+               cpu = of_peer(cpu);
+       }
+
+
+       printf("\r\n takeover on master cpu  ");
+       quiesce();
+
+       delay = 5;
+       while (delay--)
+               doWait();
+       if (takeoverFlag)
+               takeover();
+
+       memcpy((void*)TAKEOVERBASEADDRESS, &boot_rom_bin_start, &boot_rom_bin_end - &boot_rom_bin_start);
+       flush_cache((void *)TAKEOVERBASEADDRESS, &boot_rom_bin_end - &boot_rom_bin_start);
+       index = 0;
+
+       while (slaveMask) {
+               m_sync();
+               unsigned long shifter = 0x1 << index;
+               if (shifter & slaveMask) {
+                       slaveQuitt = index;
+                       while (slaveQuitt)
+                               m_sync();
+                       slaveMask &= ~shifter;
+               }
+               index++;
+       }
+
+       asm volatile(" mtctr %0 ; bctr " : : "r" (TAKEOVERBASEADDRESS+0x180) );
+}
+
+int
+callback(int argc, char *argv[])
+{
+       /* Dummy, only for takeover */
+       return (0);
+}