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