18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*    Signal support for 32-bit kernel builds
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *    Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org>
58c2ecf20Sopenharmony_ci *    Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *    Code was mostly borrowed from kernel/signal.c.
88c2ecf20Sopenharmony_ci *    See kernel/signal.c for additional Copyrights.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/compat.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/unistd.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/sched.h>
168c2ecf20Sopenharmony_ci#include <linux/syscalls.h>
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <linux/errno.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "signal32.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define DEBUG_COMPAT_SIG 0
258c2ecf20Sopenharmony_ci#define DEBUG_COMPAT_SIG_LEVEL 2
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#if DEBUG_COMPAT_SIG
288c2ecf20Sopenharmony_ci#define DBG(LEVEL, ...) \
298c2ecf20Sopenharmony_ci	((DEBUG_COMPAT_SIG_LEVEL >= LEVEL) \
308c2ecf20Sopenharmony_ci	? printk(__VA_ARGS__) : (void) 0)
318c2ecf20Sopenharmony_ci#else
328c2ecf20Sopenharmony_ci#define DBG(LEVEL, ...)
338c2ecf20Sopenharmony_ci#endif
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cilong
368c2ecf20Sopenharmony_cirestore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
378c2ecf20Sopenharmony_ci		struct pt_regs *regs)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	long err = 0;
408c2ecf20Sopenharmony_ci	compat_uint_t compat_reg;
418c2ecf20Sopenharmony_ci	compat_uint_t compat_regt;
428c2ecf20Sopenharmony_ci	int regn;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	/* When loading 32-bit values into 64-bit registers make
458c2ecf20Sopenharmony_ci	   sure to clear the upper 32-bits */
468c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: PER_LINUX32 process\n");
478c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: sc = 0x%p, rf = 0x%p, regs = 0x%p\n", sc, rf, regs);
488c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: compat_sigcontext is %#lx bytes\n", sizeof(*sc));
498c2ecf20Sopenharmony_ci	for(regn=0; regn < 32; regn++){
508c2ecf20Sopenharmony_ci		err |= __get_user(compat_reg,&sc->sc_gr[regn]);
518c2ecf20Sopenharmony_ci		regs->gr[regn] = compat_reg;
528c2ecf20Sopenharmony_ci		/* Load upper half */
538c2ecf20Sopenharmony_ci		err |= __get_user(compat_regt,&rf->rf_gr[regn]);
548c2ecf20Sopenharmony_ci		regs->gr[regn] = ((u64)compat_regt << 32) | (u64)compat_reg;
558c2ecf20Sopenharmony_ci		DBG(3,"restore_sigcontext32: gr%02d = %#lx (%#x / %#x)\n",
568c2ecf20Sopenharmony_ci				regn, regs->gr[regn], compat_regt, compat_reg);
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: sc->sc_fr = 0x%p (%#lx)\n",sc->sc_fr, sizeof(sc->sc_fr));
598c2ecf20Sopenharmony_ci	/* XXX: BE WARNED FR's are 64-BIT! */
608c2ecf20Sopenharmony_ci	err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Better safe than sorry, pass __get_user two things of
638c2ecf20Sopenharmony_ci	   the same size and let gcc do the upward conversion to
648c2ecf20Sopenharmony_ci	   64-bits */
658c2ecf20Sopenharmony_ci	err |= __get_user(compat_reg, &sc->sc_iaoq[0]);
668c2ecf20Sopenharmony_ci	/* Load upper half */
678c2ecf20Sopenharmony_ci	err |= __get_user(compat_regt, &rf->rf_iaoq[0]);
688c2ecf20Sopenharmony_ci	regs->iaoq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
698c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: upper half of iaoq[0] = %#lx\n", compat_regt);
708c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: sc->sc_iaoq[0] = %p => %#x\n",
718c2ecf20Sopenharmony_ci			&sc->sc_iaoq[0], compat_reg);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	err |= __get_user(compat_reg, &sc->sc_iaoq[1]);
748c2ecf20Sopenharmony_ci	/* Load upper half */
758c2ecf20Sopenharmony_ci	err |= __get_user(compat_regt, &rf->rf_iaoq[1]);
768c2ecf20Sopenharmony_ci	regs->iaoq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
778c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: upper half of iaoq[1] = %#lx\n", compat_regt);
788c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: sc->sc_iaoq[1] = %p => %#x\n",
798c2ecf20Sopenharmony_ci			&sc->sc_iaoq[1],compat_reg);
808c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: iaoq is %#lx / %#lx\n",
818c2ecf20Sopenharmony_ci			regs->iaoq[0],regs->iaoq[1]);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	err |= __get_user(compat_reg, &sc->sc_iasq[0]);
848c2ecf20Sopenharmony_ci	/* Load the upper half for iasq */
858c2ecf20Sopenharmony_ci	err |= __get_user(compat_regt, &rf->rf_iasq[0]);
868c2ecf20Sopenharmony_ci	regs->iasq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
878c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: upper half of iasq[0] = %#lx\n", compat_regt);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	err |= __get_user(compat_reg, &sc->sc_iasq[1]);
908c2ecf20Sopenharmony_ci	/* Load the upper half for iasq */
918c2ecf20Sopenharmony_ci	err |= __get_user(compat_regt, &rf->rf_iasq[1]);
928c2ecf20Sopenharmony_ci	regs->iasq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
938c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: upper half of iasq[1] = %#lx\n", compat_regt);
948c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: iasq is %#lx / %#lx\n",
958c2ecf20Sopenharmony_ci		regs->iasq[0],regs->iasq[1]);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	err |= __get_user(compat_reg, &sc->sc_sar);
988c2ecf20Sopenharmony_ci	/* Load the upper half for sar */
998c2ecf20Sopenharmony_ci	err |= __get_user(compat_regt, &rf->rf_sar);
1008c2ecf20Sopenharmony_ci	regs->sar = ((u64)compat_regt << 32) | (u64)compat_reg;
1018c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: upper_half & sar = %#lx\n", compat_regt);
1028c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: sar is %#lx\n", regs->sar);
1038c2ecf20Sopenharmony_ci	DBG(2,"restore_sigcontext32: r28 is %ld\n", regs->gr[28]);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return err;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/*
1098c2ecf20Sopenharmony_ci * Set up the sigcontext structure for this process.
1108c2ecf20Sopenharmony_ci * This is not an easy task if the kernel is 64-bit, it will require
1118c2ecf20Sopenharmony_ci * that we examine the process personality to determine if we need to
1128c2ecf20Sopenharmony_ci * truncate for a 32-bit userspace.
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_cilong
1158c2ecf20Sopenharmony_cisetup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
1168c2ecf20Sopenharmony_ci		struct pt_regs *regs, int in_syscall)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	compat_int_t flags = 0;
1198c2ecf20Sopenharmony_ci	long err = 0;
1208c2ecf20Sopenharmony_ci	compat_uint_t compat_reg;
1218c2ecf20Sopenharmony_ci	compat_uint_t compat_regb;
1228c2ecf20Sopenharmony_ci	int regn;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	if (on_sig_stack((unsigned long) sc))
1258c2ecf20Sopenharmony_ci		flags |= PARISC_SC_FLAG_ONSTACK;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (in_syscall) {
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci		DBG(1,"setup_sigcontext32: in_syscall\n");
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci		flags |= PARISC_SC_FLAG_IN_SYSCALL;
1328c2ecf20Sopenharmony_ci		/* Truncate gr31 */
1338c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->gr[31]);
1348c2ecf20Sopenharmony_ci		/* regs->iaoq is undefined in the syscall return path */
1358c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
1368c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
1378c2ecf20Sopenharmony_ci				&sc->sc_iaoq[0], compat_reg);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		/* Store upper half */
1408c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->gr[31] >> 32);
1418c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
1428c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->gr[31]+4);
1468c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
1478c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
1488c2ecf20Sopenharmony_ci				&sc->sc_iaoq[1], compat_reg);
1498c2ecf20Sopenharmony_ci		/* Store upper half */
1508c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)((regs->gr[31]+4) >> 32);
1518c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
1528c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		/* Truncate sr3 */
1558c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->sr[3]);
1568c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iasq[0]);
1578c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iasq[1]);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		/* Store upper half */
1608c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->sr[3] >> 32);
1618c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iasq[0]);
1628c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iasq[1]);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
1658c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
1668c2ecf20Sopenharmony_ci		DBG(1,"setup_sigcontext32: iaoq %#lx / %#lx\n",
1678c2ecf20Sopenharmony_ci			regs->gr[31], regs->gr[31]+4);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	} else {
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iaoq[0]);
1728c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
1738c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
1748c2ecf20Sopenharmony_ci				&sc->sc_iaoq[0], compat_reg);
1758c2ecf20Sopenharmony_ci		/* Store upper half */
1768c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iaoq[0] >> 32);
1778c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
1788c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iaoq[1]);
1818c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
1828c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
1838c2ecf20Sopenharmony_ci				&sc->sc_iaoq[1], compat_reg);
1848c2ecf20Sopenharmony_ci		/* Store upper half */
1858c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iaoq[1] >> 32);
1868c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
1878c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iasq[0]);
1918c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iasq[0]);
1928c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: sc->sc_iasq[0] = %p <= %#x\n",
1938c2ecf20Sopenharmony_ci				&sc->sc_iasq[0], compat_reg);
1948c2ecf20Sopenharmony_ci		/* Store upper half */
1958c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iasq[0] >> 32);
1968c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iasq[0]);
1978c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iasq[1]);
2018c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_iasq[1]);
2028c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: sc->sc_iasq[1] = %p <= %#x\n",
2038c2ecf20Sopenharmony_ci				&sc->sc_iasq[1], compat_reg);
2048c2ecf20Sopenharmony_ci		/* Store upper half */
2058c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->iasq[1] >> 32);
2068c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &rf->rf_iasq[1]);
2078c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		/* Print out the IAOQ for debugging */
2108c2ecf20Sopenharmony_ci		DBG(1,"setup_sigcontext32: ia0q %#lx / %#lx\n",
2118c2ecf20Sopenharmony_ci			regs->iaoq[0], regs->iaoq[1]);
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	err |= __put_user(flags, &sc->sc_flags);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	DBG(1,"setup_sigcontext32: Truncating general registers.\n");
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	for(regn=0; regn < 32; regn++){
2198c2ecf20Sopenharmony_ci		/* Truncate a general register */
2208c2ecf20Sopenharmony_ci		compat_reg = (compat_uint_t)(regs->gr[regn]);
2218c2ecf20Sopenharmony_ci		err |= __put_user(compat_reg, &sc->sc_gr[regn]);
2228c2ecf20Sopenharmony_ci		/* Store upper half */
2238c2ecf20Sopenharmony_ci		compat_regb = (compat_uint_t)(regs->gr[regn] >> 32);
2248c2ecf20Sopenharmony_ci		err |= __put_user(compat_regb, &rf->rf_gr[regn]);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		/* DEBUG: Write out the "upper / lower" register data */
2278c2ecf20Sopenharmony_ci		DBG(2,"setup_sigcontext32: gr%02d = %#x / %#x\n", regn,
2288c2ecf20Sopenharmony_ci				compat_regb, compat_reg);
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/* Copy the floating point registers (same size)
2328c2ecf20Sopenharmony_ci	   XXX: BE WARNED FR's are 64-BIT! */
2338c2ecf20Sopenharmony_ci	DBG(1,"setup_sigcontext32: Copying from regs to sc, "
2348c2ecf20Sopenharmony_ci	      "sc->sc_fr size = %#lx, regs->fr size = %#lx\n",
2358c2ecf20Sopenharmony_ci		sizeof(regs->fr), sizeof(sc->sc_fr));
2368c2ecf20Sopenharmony_ci	err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	compat_reg = (compat_uint_t)(regs->sar);
2398c2ecf20Sopenharmony_ci	err |= __put_user(compat_reg, &sc->sc_sar);
2408c2ecf20Sopenharmony_ci	DBG(2,"setup_sigcontext32: sar is %#x\n", compat_reg);
2418c2ecf20Sopenharmony_ci	/* Store upper half */
2428c2ecf20Sopenharmony_ci	compat_reg = (compat_uint_t)(regs->sar >> 32);
2438c2ecf20Sopenharmony_ci	err |= __put_user(compat_reg, &rf->rf_sar);
2448c2ecf20Sopenharmony_ci	DBG(2,"setup_sigcontext32: upper half sar = %#x\n", compat_reg);
2458c2ecf20Sopenharmony_ci	DBG(1,"setup_sigcontext32: r28 is %ld\n", regs->gr[28]);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	return err;
2488c2ecf20Sopenharmony_ci}
249