int rtas_call(int token, int nargs, int nret, int *outputs, ...) { va_list list; int ret, i; spin_lock(&rtas_lock); rtas_args.token = cpu_to_be32(token); rtas_args.nargs = cpu_to_be32(nargs); rtas_args.nret = cpu_to_be32(nret); rtas_args.rets = &rtas_args.args[nargs]; va_start(list, outputs); for (i = 0; i < nargs; ++i) rtas_args.args[i] = cpu_to_be32(va_arg(list, u32)); va_end(list); for (i = 0; i < nret; ++i) rtas_args.rets[i] = 0; enter_rtas(__pa(&rtas_args)); if (nret > 1 && outputs != NULL) for (i = 0; i < nret - 1; ++i) outputs[i] = be32_to_cpu(rtas_args.rets[i + 1]); ret = nret > 0 ? be32_to_cpu(rtas_args.rets[0]) : 0; spin_unlock(&rtas_lock); return ret; }
asmlinkage int ppc64_rtas(struct rtas_args *uargs) { struct rtas_args args; unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; if (args.nargs > ARRAY_SIZE(args.args) || args.nret > ARRAY_SIZE(args.args) || args.nargs + args.nret > ARRAY_SIZE(args.args)) return -EINVAL; /* Copy in args. */ if (copy_from_user(args.args, uargs->args, args.nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; spin_lock_irqsave(&rtas.lock, flags); get_paca()->xRtas = args; enter_rtas((void *)__pa((unsigned long)&get_paca()->xRtas)); args = get_paca()->xRtas; spin_unlock_irqrestore(&rtas.lock, flags); /* Copy out args. */ if (copy_to_user(uargs->args + args.nargs, args.args + args.nargs, args.nret * sizeof(rtas_arg_t)) != 0) return -EFAULT; return 0; }
/** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, * this routine must be called atomically with whatever produced * the error (i.e. with rtas.lock still held from the previous call). */ static int __fetch_rtas_last_error(void) { struct rtas_args err_args, save_args; u32 bufsz; bufsz = rtas_get_error_log_max(); err_args.token = rtas_token("rtas-last-error"); err_args.nargs = 2; err_args.nret = 1; err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); err_args.args[1] = bufsz; err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; enter_rtas(__pa(&rtas.args)); err_args = rtas.args; rtas.args = save_args; return err_args.args[2]; }
__openfirmware long rtas_call(int token, int nargs, int nret, unsigned long *outputs, ...) { va_list list; int i; unsigned long s; struct rtas_args *rtas_args = &(get_paca()->xRtas); PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; #if 0 /* Gotta do something different here, use global lock for now... */ spin_lock_irqsave(&rtas_args->lock, s); #else spin_lock_irqsave(&rtas.lock, s); #endif PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args)); enter_rtas((void *)__pa((unsigned long)rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); #if 0 /* Gotta do something different here, use global lock for now... */ spin_unlock_irqrestore(&rtas_args->lock, s); #else spin_unlock_irqrestore(&rtas.lock, s); #endif ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; return (ulong)((nret > 0) ? rtas_args->rets[0] : 0); }
void call_rtas_display_status(char c) { struct rtas_args *rtas = &(get_paca()->xRtas); rtas->token = 10; rtas->nargs = 1; rtas->nret = 1; rtas->rets = (rtas_arg_t *)&(rtas->args[1]); rtas->args[0] = (int)c; enter_rtas((void *)__pa((unsigned long)rtas)); }
void phys_call_rtas_display_status(char c) { unsigned long offset = reloc_offset(); struct rtas_args *rtas = PTRRELOC(&(get_paca()->xRtas)); rtas->token = 10; rtas->nargs = 1; rtas->nret = 1; rtas->rets = (rtas_arg_t *)PTRRELOC(&(rtas->args[1])); rtas->args[0] = (int)c; enter_rtas(rtas); }
void rtas_stop_self(void) { struct rtas_args *rtas_args = &rtas_stop_self_args; local_irq_disable(); BUG_ON(rtas_args->token == RTAS_UNKNOWN_SERVICE); printk("cpu %u (hwid %u) Ready to die...\n", smp_processor_id(), hard_smp_processor_id()); enter_rtas(__pa(rtas_args)); panic("Alas, I survived.\n"); }
int rtas_call(int token, int nargs, int nret, int *outputs, ...) { va_list list; int i; unsigned long s; struct rtas_args *rtas_args; char *buff_copy = NULL; int ret; if (!rtas.entry || token == RTAS_UNKNOWN_SERVICE) return -1; s = lock_rtas(); rtas_args = &rtas.args; rtas_args->token = cpu_to_be32(token); rtas_args->nargs = cpu_to_be32(nargs); rtas_args->nret = cpu_to_be32(nret); rtas_args->rets = &(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) rtas_args->args[i] = cpu_to_be32(va_arg(list, __u32)); va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; enter_rtas(__pa(rtas_args)); /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (be32_to_cpu(rtas_args->rets[0]) == -1) buff_copy = __fetch_rtas_last_error(NULL); if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = be32_to_cpu(rtas_args->rets[i+1]); ret = (nret > 0)? be32_to_cpu(rtas_args->rets[0]): 0; unlock_rtas(s); if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); if (mem_init_done) kfree(buff_copy); } return ret; }
void call_rtas_display_status(char c) { struct rtas_args *rargs = &(get_paca()->xRtas); unsigned long flags; spin_lock_irqsave(&rtas.lock, flags); rargs->token = 10; rargs->nargs = 1; rargs->nret = 1; rargs->rets = (rtas_arg_t *)(&(rargs->args[1])); rargs->args[0] = (int)c; enter_rtas((void *)__pa((unsigned long)rargs)); spin_unlock_irqrestore(&rtas.lock, flags); }
/* * call_rtas_display_status and call_rtas_display_status_delay * are designed only for very early low-level debugging, which * is why the token is hard-coded to 10. */ static void call_rtas_display_status(unsigned char c) { struct rtas_args *args = &rtas.args; unsigned long s; if (!rtas.base) return; s = lock_rtas(); args->token = cpu_to_be32(10); args->nargs = cpu_to_be32(1); args->nret = cpu_to_be32(1); args->rets = &(args->args[1]); args->args[0] = cpu_to_be32(c); enter_rtas(__pa(args)); unlock_rtas(s); }
/* * call_rtas_display_status and call_rtas_display_status_delay * are designed only for very early low-level debugging, which * is why the token is hard-coded to 10. */ static void call_rtas_display_status(char c) { struct rtas_args *args = &rtas.args; unsigned long s; if (!rtas.base) return; s = lock_rtas(); args->token = 10; args->nargs = 1; args->nret = 1; args->rets = (rtas_arg_t *)&(args->args[1]); args->args[0] = (unsigned char)c; enter_rtas(__pa(args)); unlock_rtas(s); }
static void va_rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, va_list list) { int i; args->token = cpu_to_be32(token); args->nargs = cpu_to_be32(nargs); args->nret = cpu_to_be32(nret); args->rets = &(args->args[nargs]); for (i = 0; i < nargs; ++i) args->args[i] = cpu_to_be32(va_arg(list, __u32)); for (i = 0; i < nret; ++i) args->rets[i] = 0; enter_rtas(__pa(args)); }
void call_rtas_display_status(unsigned char c) { struct rtas_args *args = &rtas.args; unsigned long s; if (!rtas.base) return; spin_lock_irqsave(&rtas.lock, s); args->token = 10; args->nargs = 1; args->nret = 1; args->rets = (rtas_arg_t *)&(args->args[1]); args->args[0] = (int)c; enter_rtas(__pa(args)); spin_unlock_irqrestore(&rtas.lock, s); }
void phys_call_rtas(int token, int nargs, int nret, ...) { va_list list; unsigned long offset = reloc_offset(); struct rtas_args *rtas = PTRRELOC(&(get_paca()->xRtas)); int i; rtas->token = token; rtas->nargs = nargs; rtas->nret = nret; rtas->rets = (rtas_arg_t *)PTRRELOC(&(rtas->args[nargs])); va_start(list, nret); for (i = 0; i < nargs; i++) rtas->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); va_end(list); enter_rtas(rtas); }
/** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, * this routine must be called atomically with whatever produced * the error (i.e. with rtas.lock still held from the previous call). */ static char *__fetch_rtas_last_error(char *altbuf) { struct rtas_args err_args, save_args; u32 bufsz; char *buf = NULL; if (rtas_last_error_token == -1) return NULL; bufsz = rtas_get_error_log_max(); err_args.token = cpu_to_be32(rtas_last_error_token); err_args.nargs = cpu_to_be32(2); err_args.nret = cpu_to_be32(1); err_args.args[0] = cpu_to_be32(__pa(rtas_err_buf)); err_args.args[1] = cpu_to_be32(bufsz); err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; enter_rtas(__pa(&rtas.args)); err_args = rtas.args; rtas.args = save_args; /* Log the error in the unlikely case that there was one. */ if (unlikely(err_args.args[2] == 0)) { if (altbuf) { buf = altbuf; } else { buf = rtas_err_buf; if (mem_init_done) buf = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); } if (buf) memcpy(buf, rtas_err_buf, RTAS_ERROR_LOG_MAX); } return buf; }
/** Return a copy of the detailed error text associated with the * most recent failed call to rtas. Because the error text * might go stale if there are any other intervening rtas calls, * this routine must be called atomically with whatever produced * the error (i.e. with rtas.lock still held from the previous call). */ static int __fetch_rtas_last_error(void) { struct rtas_args err_args, save_args; u32 bufsz; bufsz = rtas_token ("rtas-error-log-max"); if ((bufsz == RTAS_UNKNOWN_SERVICE) || (bufsz > RTAS_ERROR_LOG_MAX)) { printk (KERN_WARNING "RTAS: bad log buffer size %d\n", bufsz); bufsz = RTAS_ERROR_LOG_MAX; } err_args.token = rtas_token("rtas-last-error"); err_args.nargs = 2; err_args.nret = 1; err_args.args[0] = (rtas_arg_t)__pa(rtas_err_buf); err_args.args[1] = bufsz; err_args.args[2] = 0; save_args = rtas.args; rtas.args = err_args; rtas.args.rets = (rtas_arg_t *)&(rtas.args.args[2]); PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", __pa(&err_args)); enter_rtas((void *)__pa((unsigned long)(&rtas.args))); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); err_args = rtas.args; rtas.args = save_args; err_args.rets = (rtas_arg_t *)&(err_args.args[2]); return err_args.rets[0]; }
/* We assume to be passed big endian arguments */ asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { struct rtas_args args; unsigned long flags; char *buff_copy, *errbuf = NULL; int nargs, nret, token; int rc; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; nargs = be32_to_cpu(args.nargs); nret = be32_to_cpu(args.nret); token = be32_to_cpu(args.token); if (nargs > ARRAY_SIZE(args.args) || nret > ARRAY_SIZE(args.args) || nargs + nret > ARRAY_SIZE(args.args)) return -EINVAL; /* Copy in args. */ if (copy_from_user(args.args, uargs->args, nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; if (token == RTAS_UNKNOWN_SERVICE) return -EINVAL; args.rets = &args.args[nargs]; memset(args.rets, 0, nret * sizeof(rtas_arg_t)); /* Need to handle ibm,suspend_me call specially */ if (token == ibm_suspend_me_token) { /* * rtas_ibm_suspend_me assumes args are in cpu endian, or at least the * hcall within it requires it. */ int vasi_rc = 0; u64 handle = ((u64)be32_to_cpu(args.args[0]) << 32) | be32_to_cpu(args.args[1]); rc = rtas_ibm_suspend_me(handle, &vasi_rc); args.rets[0] = cpu_to_be32(vasi_rc); if (rc) return rc; goto copy_return; } buff_copy = get_errorlog_buffer(); flags = lock_rtas(); rtas.args = args; enter_rtas(__pa(&rtas.args)); args = rtas.args; /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (be32_to_cpu(args.rets[0]) == -1) errbuf = __fetch_rtas_last_error(buff_copy); unlock_rtas(flags); if (buff_copy) { if (errbuf) log_error(errbuf, ERR_TYPE_RTAS_LOG, 0); kfree(buff_copy); } copy_return: /* Copy out args. */ if (copy_to_user(uargs->args + nargs, args.args + nargs, nret * sizeof(rtas_arg_t)) != 0) return -EFAULT; return 0; }
asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { struct rtas_args args; unsigned long flags; char *buff_copy, *errbuf = NULL; int nargs; int rc; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; nargs = args.nargs; if (nargs > ARRAY_SIZE(args.args) || args.nret > ARRAY_SIZE(args.args) || nargs + args.nret > ARRAY_SIZE(args.args)) return -EINVAL; /* Copy in args. */ if (copy_from_user(args.args, uargs->args, nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; if (args.token == RTAS_UNKNOWN_SERVICE) return -EINVAL; args.rets = &args.args[nargs]; memset(args.rets, 0, args.nret * sizeof(rtas_arg_t)); /* Need to handle ibm,suspend_me call specially */ if (args.token == ibm_suspend_me_token) { rc = rtas_ibm_suspend_me(&args); if (rc) return rc; goto copy_return; } buff_copy = get_errorlog_buffer(); flags = lock_rtas(); rtas.args = args; enter_rtas(__pa(&rtas.args)); args = rtas.args; /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (args.rets[0] == -1) errbuf = __fetch_rtas_last_error(buff_copy); unlock_rtas(flags); if (buff_copy) { if (errbuf) log_error(errbuf, ERR_TYPE_RTAS_LOG, 0); kfree(buff_copy); } copy_return: /* Copy out args. */ if (copy_to_user(uargs->args + nargs, args.args + nargs, args.nret * sizeof(rtas_arg_t)) != 0) return -EFAULT; return 0; }
__openfirmware long rtas_call(int token, int nargs, int nret, unsigned long *outputs, ...) { va_list list; int i, logit = 0; unsigned long flags; struct rtas_args *rtas_args; char * buff_copy = NULL; unsigned long retval; PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; spin_lock_irqsave(&rtas.lock, flags); rtas_args = &(get_paca()->xRtas); rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong)); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", (void *)__pa((unsigned long)rtas_args)); enter_rtas((void *)__pa((unsigned long)rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); /* A -1 return code indicates that the last command couldn't * be completed due to a hardware error. */ if (rtas_args->rets[0] == -1) logit = (__fetch_rtas_last_error() == 0); ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; retval = (ulong)((nret > 0) ? rtas_args->rets[0] : 0); /* Log the error in the unlikely case that there was one. */ if (unlikely(logit)) { /* Can't call kmalloc if VM subsystem is not yet up. */ if (slabpages>0) { buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); if (buff_copy) { memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); } } } spin_unlock_irqrestore(&rtas.lock, flags); if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); kfree(buff_copy); } return retval; }
asmlinkage int ppc_rtas(struct rtas_args __user *uargs) { struct rtas_args args; unsigned long flags; char * buff_copy; int nargs; int err_rc = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&args, uargs, 3 * sizeof(u32)) != 0) return -EFAULT; nargs = args.nargs; if (nargs > ARRAY_SIZE(args.args) || args.nret > ARRAY_SIZE(args.args) || nargs + args.nret > ARRAY_SIZE(args.args)) return -EINVAL; /* Copy in args. */ if (copy_from_user(args.args, uargs->args, nargs * sizeof(rtas_arg_t)) != 0) return -EFAULT; buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_KERNEL); spin_lock_irqsave(&rtas.lock, flags); rtas.args = args; enter_rtas(__pa(&rtas.args)); args = rtas.args; args.rets = &args.args[nargs]; /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (args.rets[0] == -1) { err_rc = __fetch_rtas_last_error(); if ((err_rc == 0) && buff_copy) { memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); } } spin_unlock_irqrestore(&rtas.lock, flags); if (buff_copy) { if ((args.rets[0] == -1) && (err_rc == 0)) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); } kfree(buff_copy); } /* Copy out args. */ if (copy_to_user(uargs->args + nargs, args.args + nargs, args.nret * sizeof(rtas_arg_t)) != 0) return -EFAULT; return 0; }
int rtas_call(int token, int nargs, int nret, int *outputs, ...) { va_list list; int i, logit = 0; unsigned long s; struct rtas_args *rtas_args; char * buff_copy = NULL; int ret; PPCDBG(PPCDBG_RTAS, "Entering rtas_call\n"); PPCDBG(PPCDBG_RTAS, "\ttoken = 0x%x\n", token); PPCDBG(PPCDBG_RTAS, "\tnargs = %d\n", nargs); PPCDBG(PPCDBG_RTAS, "\tnret = %d\n", nret); PPCDBG(PPCDBG_RTAS, "\t&outputs = 0x%lx\n", outputs); if (token == RTAS_UNKNOWN_SERVICE) return -1; /* Gotta do something different here, use global lock for now... */ spin_lock_irqsave(&rtas.lock, s); rtas_args = &rtas.args; rtas_args->token = token; rtas_args->nargs = nargs; rtas_args->nret = nret; rtas_args->rets = (rtas_arg_t *)&(rtas_args->args[nargs]); va_start(list, outputs); for (i = 0; i < nargs; ++i) { rtas_args->args[i] = va_arg(list, rtas_arg_t); PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%x\n", i, rtas_args->args[i]); } va_end(list); for (i = 0; i < nret; ++i) rtas_args->rets[i] = 0; PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n", __pa(rtas_args)); enter_rtas(__pa(rtas_args)); PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n"); /* A -1 return code indicates that the last command couldn't be completed due to a hardware error. */ if (rtas_args->rets[0] == -1) logit = (__fetch_rtas_last_error() == 0); ifppcdebug(PPCDBG_RTAS) { for(i=0; i < nret ;i++) udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]); } if (nret > 1 && outputs != NULL) for (i = 0; i < nret-1; ++i) outputs[i] = rtas_args->rets[i+1]; ret = (nret > 0)? rtas_args->rets[0]: 0; /* Log the error in the unlikely case that there was one. */ if (unlikely(logit)) { buff_copy = rtas_err_buf; if (mem_init_done) { buff_copy = kmalloc(RTAS_ERROR_LOG_MAX, GFP_ATOMIC); if (buff_copy) memcpy(buff_copy, rtas_err_buf, RTAS_ERROR_LOG_MAX); } } /* Gotta do something different here, use global lock for now... */ spin_unlock_irqrestore(&rtas.lock, s); if (buff_copy) { log_error(buff_copy, ERR_TYPE_RTAS_LOG, 0); if (mem_init_done) kfree(buff_copy); } return ret; }