b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 2 | /* Signal support for 32-bit kernel builds |
| 3 | * |
| 4 | * Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org> |
| 5 | * Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org> |
| 6 | * |
| 7 | * Code was mostly borrowed from kernel/signal.c. |
| 8 | * See kernel/signal.c for additional Copyrights. |
| 9 | */ |
| 10 | |
| 11 | #include <linux/compat.h> |
| 12 | #include <linux/module.h> |
| 13 | #include <linux/unistd.h> |
| 14 | #include <linux/init.h> |
| 15 | #include <linux/sched.h> |
| 16 | #include <linux/syscalls.h> |
| 17 | #include <linux/types.h> |
| 18 | #include <linux/errno.h> |
| 19 | |
| 20 | #include <linux/uaccess.h> |
| 21 | |
| 22 | #include "signal32.h" |
| 23 | |
| 24 | #define DEBUG_COMPAT_SIG 0 |
| 25 | #define DEBUG_COMPAT_SIG_LEVEL 2 |
| 26 | |
| 27 | #if DEBUG_COMPAT_SIG |
| 28 | #define DBG(LEVEL, ...) \ |
| 29 | ((DEBUG_COMPAT_SIG_LEVEL >= LEVEL) \ |
| 30 | ? printk(__VA_ARGS__) : (void) 0) |
| 31 | #else |
| 32 | #define DBG(LEVEL, ...) |
| 33 | #endif |
| 34 | |
| 35 | long |
| 36 | restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, |
| 37 | struct pt_regs *regs) |
| 38 | { |
| 39 | long err = 0; |
| 40 | compat_uint_t compat_reg; |
| 41 | compat_uint_t compat_regt; |
| 42 | int regn; |
| 43 | |
| 44 | /* When loading 32-bit values into 64-bit registers make |
| 45 | sure to clear the upper 32-bits */ |
| 46 | DBG(2,"restore_sigcontext32: PER_LINUX32 process\n"); |
| 47 | DBG(2,"restore_sigcontext32: sc = 0x%p, rf = 0x%p, regs = 0x%p\n", sc, rf, regs); |
| 48 | DBG(2,"restore_sigcontext32: compat_sigcontext is %#lx bytes\n", sizeof(*sc)); |
| 49 | for(regn=0; regn < 32; regn++){ |
| 50 | err |= __get_user(compat_reg,&sc->sc_gr[regn]); |
| 51 | regs->gr[regn] = compat_reg; |
| 52 | /* Load upper half */ |
| 53 | err |= __get_user(compat_regt,&rf->rf_gr[regn]); |
| 54 | regs->gr[regn] = ((u64)compat_regt << 32) | (u64)compat_reg; |
| 55 | DBG(3,"restore_sigcontext32: gr%02d = %#lx (%#x / %#x)\n", |
| 56 | regn, regs->gr[regn], compat_regt, compat_reg); |
| 57 | } |
| 58 | DBG(2,"restore_sigcontext32: sc->sc_fr = 0x%p (%#lx)\n",sc->sc_fr, sizeof(sc->sc_fr)); |
| 59 | /* XXX: BE WARNED FR's are 64-BIT! */ |
| 60 | err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr)); |
| 61 | |
| 62 | /* Better safe than sorry, pass __get_user two things of |
| 63 | the same size and let gcc do the upward conversion to |
| 64 | 64-bits */ |
| 65 | err |= __get_user(compat_reg, &sc->sc_iaoq[0]); |
| 66 | /* Load upper half */ |
| 67 | err |= __get_user(compat_regt, &rf->rf_iaoq[0]); |
| 68 | regs->iaoq[0] = ((u64)compat_regt << 32) | (u64)compat_reg; |
| 69 | DBG(2,"restore_sigcontext32: upper half of iaoq[0] = %#lx\n", compat_regt); |
| 70 | DBG(2,"restore_sigcontext32: sc->sc_iaoq[0] = %p => %#x\n", |
| 71 | &sc->sc_iaoq[0], compat_reg); |
| 72 | |
| 73 | err |= __get_user(compat_reg, &sc->sc_iaoq[1]); |
| 74 | /* Load upper half */ |
| 75 | err |= __get_user(compat_regt, &rf->rf_iaoq[1]); |
| 76 | regs->iaoq[1] = ((u64)compat_regt << 32) | (u64)compat_reg; |
| 77 | DBG(2,"restore_sigcontext32: upper half of iaoq[1] = %#lx\n", compat_regt); |
| 78 | DBG(2,"restore_sigcontext32: sc->sc_iaoq[1] = %p => %#x\n", |
| 79 | &sc->sc_iaoq[1],compat_reg); |
| 80 | DBG(2,"restore_sigcontext32: iaoq is %#lx / %#lx\n", |
| 81 | regs->iaoq[0],regs->iaoq[1]); |
| 82 | |
| 83 | err |= __get_user(compat_reg, &sc->sc_iasq[0]); |
| 84 | /* Load the upper half for iasq */ |
| 85 | err |= __get_user(compat_regt, &rf->rf_iasq[0]); |
| 86 | regs->iasq[0] = ((u64)compat_regt << 32) | (u64)compat_reg; |
| 87 | DBG(2,"restore_sigcontext32: upper half of iasq[0] = %#lx\n", compat_regt); |
| 88 | |
| 89 | err |= __get_user(compat_reg, &sc->sc_iasq[1]); |
| 90 | /* Load the upper half for iasq */ |
| 91 | err |= __get_user(compat_regt, &rf->rf_iasq[1]); |
| 92 | regs->iasq[1] = ((u64)compat_regt << 32) | (u64)compat_reg; |
| 93 | DBG(2,"restore_sigcontext32: upper half of iasq[1] = %#lx\n", compat_regt); |
| 94 | DBG(2,"restore_sigcontext32: iasq is %#lx / %#lx\n", |
| 95 | regs->iasq[0],regs->iasq[1]); |
| 96 | |
| 97 | err |= __get_user(compat_reg, &sc->sc_sar); |
| 98 | /* Load the upper half for sar */ |
| 99 | err |= __get_user(compat_regt, &rf->rf_sar); |
| 100 | regs->sar = ((u64)compat_regt << 32) | (u64)compat_reg; |
| 101 | DBG(2,"restore_sigcontext32: upper_half & sar = %#lx\n", compat_regt); |
| 102 | DBG(2,"restore_sigcontext32: sar is %#lx\n", regs->sar); |
| 103 | DBG(2,"restore_sigcontext32: r28 is %ld\n", regs->gr[28]); |
| 104 | |
| 105 | return err; |
| 106 | } |
| 107 | |
| 108 | /* |
| 109 | * Set up the sigcontext structure for this process. |
| 110 | * This is not an easy task if the kernel is 64-bit, it will require |
| 111 | * that we examine the process personality to determine if we need to |
| 112 | * truncate for a 32-bit userspace. |
| 113 | */ |
| 114 | long |
| 115 | setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf, |
| 116 | struct pt_regs *regs, int in_syscall) |
| 117 | { |
| 118 | compat_int_t flags = 0; |
| 119 | long err = 0; |
| 120 | compat_uint_t compat_reg; |
| 121 | compat_uint_t compat_regb; |
| 122 | int regn; |
| 123 | |
| 124 | if (on_sig_stack((unsigned long) sc)) |
| 125 | flags |= PARISC_SC_FLAG_ONSTACK; |
| 126 | |
| 127 | if (in_syscall) { |
| 128 | |
| 129 | DBG(1,"setup_sigcontext32: in_syscall\n"); |
| 130 | |
| 131 | flags |= PARISC_SC_FLAG_IN_SYSCALL; |
| 132 | /* Truncate gr31 */ |
| 133 | compat_reg = (compat_uint_t)(regs->gr[31]); |
| 134 | /* regs->iaoq is undefined in the syscall return path */ |
| 135 | err |= __put_user(compat_reg, &sc->sc_iaoq[0]); |
| 136 | DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n", |
| 137 | &sc->sc_iaoq[0], compat_reg); |
| 138 | |
| 139 | /* Store upper half */ |
| 140 | compat_reg = (compat_uint_t)(regs->gr[31] >> 32); |
| 141 | err |= __put_user(compat_reg, &rf->rf_iaoq[0]); |
| 142 | DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg); |
| 143 | |
| 144 | |
| 145 | compat_reg = (compat_uint_t)(regs->gr[31]+4); |
| 146 | err |= __put_user(compat_reg, &sc->sc_iaoq[1]); |
| 147 | DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n", |
| 148 | &sc->sc_iaoq[1], compat_reg); |
| 149 | /* Store upper half */ |
| 150 | compat_reg = (compat_uint_t)((regs->gr[31]+4) >> 32); |
| 151 | err |= __put_user(compat_reg, &rf->rf_iaoq[1]); |
| 152 | DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg); |
| 153 | |
| 154 | /* Truncate sr3 */ |
| 155 | compat_reg = (compat_uint_t)(regs->sr[3]); |
| 156 | err |= __put_user(compat_reg, &sc->sc_iasq[0]); |
| 157 | err |= __put_user(compat_reg, &sc->sc_iasq[1]); |
| 158 | |
| 159 | /* Store upper half */ |
| 160 | compat_reg = (compat_uint_t)(regs->sr[3] >> 32); |
| 161 | err |= __put_user(compat_reg, &rf->rf_iasq[0]); |
| 162 | err |= __put_user(compat_reg, &rf->rf_iasq[1]); |
| 163 | |
| 164 | DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg); |
| 165 | DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg); |
| 166 | DBG(1,"setup_sigcontext32: iaoq %#lx / %#lx\n", |
| 167 | regs->gr[31], regs->gr[31]+4); |
| 168 | |
| 169 | } else { |
| 170 | |
| 171 | compat_reg = (compat_uint_t)(regs->iaoq[0]); |
| 172 | err |= __put_user(compat_reg, &sc->sc_iaoq[0]); |
| 173 | DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n", |
| 174 | &sc->sc_iaoq[0], compat_reg); |
| 175 | /* Store upper half */ |
| 176 | compat_reg = (compat_uint_t)(regs->iaoq[0] >> 32); |
| 177 | err |= __put_user(compat_reg, &rf->rf_iaoq[0]); |
| 178 | DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg); |
| 179 | |
| 180 | compat_reg = (compat_uint_t)(regs->iaoq[1]); |
| 181 | err |= __put_user(compat_reg, &sc->sc_iaoq[1]); |
| 182 | DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n", |
| 183 | &sc->sc_iaoq[1], compat_reg); |
| 184 | /* Store upper half */ |
| 185 | compat_reg = (compat_uint_t)(regs->iaoq[1] >> 32); |
| 186 | err |= __put_user(compat_reg, &rf->rf_iaoq[1]); |
| 187 | DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg); |
| 188 | |
| 189 | |
| 190 | compat_reg = (compat_uint_t)(regs->iasq[0]); |
| 191 | err |= __put_user(compat_reg, &sc->sc_iasq[0]); |
| 192 | DBG(2,"setup_sigcontext32: sc->sc_iasq[0] = %p <= %#x\n", |
| 193 | &sc->sc_iasq[0], compat_reg); |
| 194 | /* Store upper half */ |
| 195 | compat_reg = (compat_uint_t)(regs->iasq[0] >> 32); |
| 196 | err |= __put_user(compat_reg, &rf->rf_iasq[0]); |
| 197 | DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg); |
| 198 | |
| 199 | |
| 200 | compat_reg = (compat_uint_t)(regs->iasq[1]); |
| 201 | err |= __put_user(compat_reg, &sc->sc_iasq[1]); |
| 202 | DBG(2,"setup_sigcontext32: sc->sc_iasq[1] = %p <= %#x\n", |
| 203 | &sc->sc_iasq[1], compat_reg); |
| 204 | /* Store upper half */ |
| 205 | compat_reg = (compat_uint_t)(regs->iasq[1] >> 32); |
| 206 | err |= __put_user(compat_reg, &rf->rf_iasq[1]); |
| 207 | DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg); |
| 208 | |
| 209 | /* Print out the IAOQ for debugging */ |
| 210 | DBG(1,"setup_sigcontext32: ia0q %#lx / %#lx\n", |
| 211 | regs->iaoq[0], regs->iaoq[1]); |
| 212 | } |
| 213 | |
| 214 | err |= __put_user(flags, &sc->sc_flags); |
| 215 | |
| 216 | DBG(1,"setup_sigcontext32: Truncating general registers.\n"); |
| 217 | |
| 218 | for(regn=0; regn < 32; regn++){ |
| 219 | /* Truncate a general register */ |
| 220 | compat_reg = (compat_uint_t)(regs->gr[regn]); |
| 221 | err |= __put_user(compat_reg, &sc->sc_gr[regn]); |
| 222 | /* Store upper half */ |
| 223 | compat_regb = (compat_uint_t)(regs->gr[regn] >> 32); |
| 224 | err |= __put_user(compat_regb, &rf->rf_gr[regn]); |
| 225 | |
| 226 | /* DEBUG: Write out the "upper / lower" register data */ |
| 227 | DBG(2,"setup_sigcontext32: gr%02d = %#x / %#x\n", regn, |
| 228 | compat_regb, compat_reg); |
| 229 | } |
| 230 | |
| 231 | /* Copy the floating point registers (same size) |
| 232 | XXX: BE WARNED FR's are 64-BIT! */ |
| 233 | DBG(1,"setup_sigcontext32: Copying from regs to sc, " |
| 234 | "sc->sc_fr size = %#lx, regs->fr size = %#lx\n", |
| 235 | sizeof(regs->fr), sizeof(sc->sc_fr)); |
| 236 | err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr)); |
| 237 | |
| 238 | compat_reg = (compat_uint_t)(regs->sar); |
| 239 | err |= __put_user(compat_reg, &sc->sc_sar); |
| 240 | DBG(2,"setup_sigcontext32: sar is %#x\n", compat_reg); |
| 241 | /* Store upper half */ |
| 242 | compat_reg = (compat_uint_t)(regs->sar >> 32); |
| 243 | err |= __put_user(compat_reg, &rf->rf_sar); |
| 244 | DBG(2,"setup_sigcontext32: upper half sar = %#x\n", compat_reg); |
| 245 | DBG(1,"setup_sigcontext32: r28 is %ld\n", regs->gr[28]); |
| 246 | |
| 247 | return err; |
| 248 | } |