diff options
Diffstat (limited to 'clients/takeover/main.c')
-rw-r--r-- | clients/takeover/main.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/clients/takeover/main.c b/clients/takeover/main.c new file mode 100644 index 0000000..c79ea72 --- /dev/null +++ b/clients/takeover/main.c @@ -0,0 +1,218 @@ +/****************************************************************************** + * 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 <takeover.h> + +extern void call_client_interface(of_arg_t *); + +#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 + + +/* + * These functions are just dummy implemented to resolve symbols for linking to other objects + */ + +int +open(const char *name UNUSED, int flags UNUSED) +{ + return 0; +} + +int +close(int fd UNUSED) +{ + return 0; +} + +ssize_t +read(int fd UNUSED, void *buf UNUSED, size_t count UNUSED) +{ + return 0; +} + +int +ioctl(int fd UNUSED, int req UNUSED, void *data UNUSED) +{ + return 0; +} + +/* + * These functions are required for using libc.a + */ +ssize_t +write(int fd, const void *buf, size_t len) +{ + char dst_buf[512]; + char *dst_buf_ptr; + char *src_buf_ptr; + int i; + + src_buf_ptr = (char *) buf; + if (fd == 1 || fd == 2) + { + dst_buf_ptr = &dst_buf[0]; + for (i = 0; i < len && i < 256; i++) + { + *dst_buf_ptr++ = *src_buf_ptr++; + if (src_buf_ptr[-1] == '\n') + *dst_buf_ptr++ = '\r'; + } + len = dst_buf_ptr - &dst_buf[0]; + src_buf_ptr = &dst_buf[0]; + } + + if(fd < 0 || fd >= FILEIO_MAX + || fd_array[fd].type == FILEIO_TYPE_EMPTY + || fd_array[fd].write == 0) + return -1; + + return fd_array[fd].write(&fd_array[fd], src_buf_ptr, len); +} + +void * +sbrk(int incr) +{ + return (void *) -1; +} + +void +doWait(void) +{ + static const char *wheel = "|/-\\"; + static int i = 0; + volatile int dly = 0xf0000; + while (dly--); + printf("\b%c", wheel[i++]); + i &= 0x3; +} + +void +quiesce(void) +{ + of_arg_t arg = { + p32cast "quiesce", + 0, 0, + }; + call_client_interface(&arg); +} + +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 rcode; + 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", ®, 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) + rcode = 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) { + unsigned long shifter = 0x1 << index; + if (shifter & slaveMask) { + slaveQuitt = index; + while (slaveQuitt); + slaveMask &= ~shifter; + } + index++; + } + + asm volatile(" mtctr %0 ; bctr " : : "r" (TAKEOVERBASEADDRESS+0x180) ); +} + +int +callback(int argc, char *argv[]) +{ + /* Dummy, only for takeover */ + return (0); +} |