arch/powerpc/kernel/rtas.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kernel/rtas.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kernel/rtas.c
Extension
.c
Size
58431 bytes
Lines
2134
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE1(rtas, struct rtas_args __user *, uargs)
{
	const struct rtas_function *func;
	struct pin_cookie cookie;
	struct rtas_args args;
	unsigned long flags;
	char *buff_copy, *errbuf = NULL;
	int nargs, nret, token;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;

	if (!rtas.entry)
		return -EINVAL;

	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;

	nargs = array_index_nospec(nargs, ARRAY_SIZE(args.args));
	nret = array_index_nospec(nret, ARRAY_SIZE(args.args) - nargs);

	/* Copy in args. */
	if (copy_from_user(args.args, uargs->args,
			   nargs * sizeof(rtas_arg_t)) != 0)
		return -EFAULT;

	/*
	 * If this token doesn't correspond to a function the kernel
	 * understands, you're not allowed to call it.
	 */
	func = rtas_token_to_function_untrusted(token);
	if (!func)
		return -EINVAL;

	args.rets = &args.args[nargs];
	memset(args.rets, 0, nret * sizeof(rtas_arg_t));

	if (block_rtas_call(func, nargs, &args))
		return -EINVAL;

	if (token_is_restricted_errinjct(token)) {
		int err;

		err = security_locked_down(LOCKDOWN_RTAS_ERROR_INJECTION);
		if (err)
			return err;
	}

	/* Need to handle ibm,suspend_me call specially */
	if (token == rtas_function_token(RTAS_FN_IBM_SUSPEND_ME)) {

		/*
		 * rtas_ibm_suspend_me assumes the streamid handle is in cpu
		 * endian, or at least the hcall within it requires it.
		 */
		int rc = 0;
		u64 handle = ((u64)be32_to_cpu(args.args[0]) << 32)
		              | be32_to_cpu(args.args[1]);
		rc = rtas_syscall_dispatch_ibm_suspend_me(handle);
		if (rc == -EAGAIN)
			args.rets[0] = cpu_to_be32(RTAS_NOT_SUSPENDABLE);
		else if (rc == -EIO)
			args.rets[0] = cpu_to_be32(-1);
		else if (rc)
			return rc;
		goto copy_return;
	}

	buff_copy = get_errorlog_buffer();

	/*
	 * If this function has a mutex assigned to it, we must
	 * acquire it to avoid interleaving with any kernel-based uses
	 * of the same function. Kernel-based sequences acquire the
	 * appropriate mutex explicitly.
	 */
	if (func->lock)
		mutex_lock(func->lock);

	raw_spin_lock_irqsave(&rtas_lock, flags);
	cookie = lockdep_pin_lock(&rtas_lock);

Annotation

Implementation Notes