dsemul.c (498495dba268b20e8eadd7fe93c140c68b6cc9d2) | dsemul.c (adcc81f148d733b7e8e641300c5590a2cdc13bf3) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/err.h> 3#include <linux/slab.h> 4#include <linux/mm_types.h> 5#include <linux/sched/task.h> 6 7#include <asm/branch.h> 8#include <asm/cacheflush.h> --- 200 unchanged lines hidden (view full) --- 209 kfree(mm_ctx->bd_emupage_allocmap); 210} 211 212int mips_dsemul(struct pt_regs *regs, mips_instruction ir, 213 unsigned long branch_pc, unsigned long cont_pc) 214{ 215 int isa16 = get_isa16_mode(regs->cp0_epc); 216 mips_instruction break_math; | 1// SPDX-License-Identifier: GPL-2.0 2#include <linux/err.h> 3#include <linux/slab.h> 4#include <linux/mm_types.h> 5#include <linux/sched/task.h> 6 7#include <asm/branch.h> 8#include <asm/cacheflush.h> --- 200 unchanged lines hidden (view full) --- 209 kfree(mm_ctx->bd_emupage_allocmap); 210} 211 212int mips_dsemul(struct pt_regs *regs, mips_instruction ir, 213 unsigned long branch_pc, unsigned long cont_pc) 214{ 215 int isa16 = get_isa16_mode(regs->cp0_epc); 216 mips_instruction break_math; |
217 struct emuframe __user *fr; 218 int err, fr_idx; | 217 unsigned long fr_uaddr; 218 struct emuframe fr; 219 int fr_idx, ret; |
219 220 /* NOP is easy */ 221 if (ir == 0) 222 return -1; 223 224 /* microMIPS instructions */ 225 if (isa16) { 226 union mips_instruction insn = { .word = ir }; --- 18 unchanged lines hidden (view full) --- 245 pr_debug("dsemul 0x%08lx cont at 0x%08lx\n", regs->cp0_epc, cont_pc); 246 247 /* Allocate a frame if we don't already have one */ 248 fr_idx = atomic_read(¤t->thread.bd_emu_frame); 249 if (fr_idx == BD_EMUFRAME_NONE) 250 fr_idx = alloc_emuframe(); 251 if (fr_idx == BD_EMUFRAME_NONE) 252 return SIGBUS; | 220 221 /* NOP is easy */ 222 if (ir == 0) 223 return -1; 224 225 /* microMIPS instructions */ 226 if (isa16) { 227 union mips_instruction insn = { .word = ir }; --- 18 unchanged lines hidden (view full) --- 246 pr_debug("dsemul 0x%08lx cont at 0x%08lx\n", regs->cp0_epc, cont_pc); 247 248 /* Allocate a frame if we don't already have one */ 249 fr_idx = atomic_read(¤t->thread.bd_emu_frame); 250 if (fr_idx == BD_EMUFRAME_NONE) 251 fr_idx = alloc_emuframe(); 252 if (fr_idx == BD_EMUFRAME_NONE) 253 return SIGBUS; |
253 fr = &dsemul_page()[fr_idx]; | |
254 255 /* Retrieve the appropriately encoded break instruction */ 256 break_math = BREAK_MATH(isa16); 257 258 /* Write the instructions to the frame */ 259 if (isa16) { | 254 255 /* Retrieve the appropriately encoded break instruction */ 256 break_math = BREAK_MATH(isa16); 257 258 /* Write the instructions to the frame */ 259 if (isa16) { |
260 err = __put_user(ir >> 16, 261 (u16 __user *)(&fr->emul)); 262 err |= __put_user(ir & 0xffff, 263 (u16 __user *)((long)(&fr->emul) + 2)); 264 err |= __put_user(break_math >> 16, 265 (u16 __user *)(&fr->badinst)); 266 err |= __put_user(break_math & 0xffff, 267 (u16 __user *)((long)(&fr->badinst) + 2)); | 260 union mips_instruction _emul = { 261 .halfword = { ir >> 16, ir } 262 }; 263 union mips_instruction _badinst = { 264 .halfword = { break_math >> 16, break_math } 265 }; 266 267 fr.emul = _emul.word; 268 fr.badinst = _badinst.word; |
268 } else { | 269 } else { |
269 err = __put_user(ir, &fr->emul); 270 err |= __put_user(break_math, &fr->badinst); | 270 fr.emul = ir; 271 fr.badinst = break_math; |
271 } 272 | 272 } 273 |
273 if (unlikely(err)) { | 274 /* Write the frame to user memory */ 275 fr_uaddr = (unsigned long)&dsemul_page()[fr_idx]; 276 ret = access_process_vm(current, fr_uaddr, &fr, sizeof(fr), 277 FOLL_FORCE | FOLL_WRITE); 278 if (unlikely(ret != sizeof(fr))) { |
274 MIPS_FPU_EMU_INC_STATS(errors); 275 free_emuframe(fr_idx, current->mm); 276 return SIGBUS; 277 } 278 279 /* Record the PC of the branch, PC to continue from & frame index */ 280 current->thread.bd_emu_branch_pc = branch_pc; 281 current->thread.bd_emu_cont_pc = cont_pc; 282 atomic_set(¤t->thread.bd_emu_frame, fr_idx); 283 284 /* Change user register context to execute the frame */ | 279 MIPS_FPU_EMU_INC_STATS(errors); 280 free_emuframe(fr_idx, current->mm); 281 return SIGBUS; 282 } 283 284 /* Record the PC of the branch, PC to continue from & frame index */ 285 current->thread.bd_emu_branch_pc = branch_pc; 286 current->thread.bd_emu_cont_pc = cont_pc; 287 atomic_set(¤t->thread.bd_emu_frame, fr_idx); 288 289 /* Change user register context to execute the frame */ |
285 regs->cp0_epc = (unsigned long)&fr->emul | isa16; | 290 regs->cp0_epc = fr_uaddr | isa16; |
286 | 291 |
287 /* Ensure the icache observes our newly written frame */ 288 flush_cache_sigtramp((unsigned long)&fr->emul); 289 | |
290 return 0; 291} 292 293bool do_dsemulret(struct pt_regs *xcp) 294{ 295 /* Cleanup the allocated frame, returning if there wasn't one */ 296 if (!dsemul_thread_cleanup(current)) { 297 MIPS_FPU_EMU_INC_STATS(errors); 298 return false; 299 } 300 301 /* Set EPC to return to post-branch instruction */ 302 xcp->cp0_epc = current->thread.bd_emu_cont_pc; 303 pr_debug("dsemulret to 0x%08lx\n", xcp->cp0_epc); 304 MIPS_FPU_EMU_INC_STATS(ds_emul); 305 return true; 306} | 292 return 0; 293} 294 295bool do_dsemulret(struct pt_regs *xcp) 296{ 297 /* Cleanup the allocated frame, returning if there wasn't one */ 298 if (!dsemul_thread_cleanup(current)) { 299 MIPS_FPU_EMU_INC_STATS(errors); 300 return false; 301 } 302 303 /* Set EPC to return to post-branch instruction */ 304 xcp->cp0_epc = current->thread.bd_emu_cont_pc; 305 pr_debug("dsemulret to 0x%08lx\n", xcp->cp0_epc); 306 MIPS_FPU_EMU_INC_STATS(ds_emul); 307 return true; 308} |