mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	MIPS: kernel: unaligned: Handle unaligned accesses for EVA
Handle unaligned accesses when we access userspace memory EVA mode. Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
This commit is contained in:
		
							parent
							
								
									9d8e573683
								
							
						
					
					
						commit
						c1771216ab
					
				
					 1 changed files with 85 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -431,7 +431,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
 | 
			
		|||
	unsigned long origpc;
 | 
			
		||||
	unsigned long orig31;
 | 
			
		||||
	void __user *fault_addr = NULL;
 | 
			
		||||
 | 
			
		||||
#ifdef	CONFIG_EVA
 | 
			
		||||
	mm_segment_t seg;
 | 
			
		||||
#endif
 | 
			
		||||
	origpc = (unsigned long)pc;
 | 
			
		||||
	orig31 = regs->regs[31];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -476,6 +478,88 @@ static void emulate_load_store_insn(struct pt_regs *regs,
 | 
			
		|||
		 * The remaining opcodes are the ones that are really of
 | 
			
		||||
		 * interest.
 | 
			
		||||
		 */
 | 
			
		||||
#ifdef CONFIG_EVA
 | 
			
		||||
	case spec3_op:
 | 
			
		||||
		/*
 | 
			
		||||
		 * we can land here only from kernel accessing user memory,
 | 
			
		||||
		 * so we need to "switch" the address limit to user space, so
 | 
			
		||||
		 * address check can work properly.
 | 
			
		||||
		 */
 | 
			
		||||
		seg = get_fs();
 | 
			
		||||
		set_fs(USER_DS);
 | 
			
		||||
		switch (insn.spec3_format.func) {
 | 
			
		||||
		case lhe_op:
 | 
			
		||||
			if (!access_ok(VERIFY_READ, addr, 2)) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto sigbus;
 | 
			
		||||
			}
 | 
			
		||||
			LoadHW(addr, value, res);
 | 
			
		||||
			if (res) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto fault;
 | 
			
		||||
			}
 | 
			
		||||
			compute_return_epc(regs);
 | 
			
		||||
			regs->regs[insn.spec3_format.rt] = value;
 | 
			
		||||
			break;
 | 
			
		||||
		case lwe_op:
 | 
			
		||||
			if (!access_ok(VERIFY_READ, addr, 4)) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto sigbus;
 | 
			
		||||
			}
 | 
			
		||||
				LoadW(addr, value, res);
 | 
			
		||||
			if (res) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto fault;
 | 
			
		||||
			}
 | 
			
		||||
			compute_return_epc(regs);
 | 
			
		||||
			regs->regs[insn.spec3_format.rt] = value;
 | 
			
		||||
			break;
 | 
			
		||||
		case lhue_op:
 | 
			
		||||
			if (!access_ok(VERIFY_READ, addr, 2)) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto sigbus;
 | 
			
		||||
			}
 | 
			
		||||
			LoadHWU(addr, value, res);
 | 
			
		||||
			if (res) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto fault;
 | 
			
		||||
			}
 | 
			
		||||
			compute_return_epc(regs);
 | 
			
		||||
			regs->regs[insn.spec3_format.rt] = value;
 | 
			
		||||
			break;
 | 
			
		||||
		case she_op:
 | 
			
		||||
			if (!access_ok(VERIFY_WRITE, addr, 2)) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto sigbus;
 | 
			
		||||
			}
 | 
			
		||||
			compute_return_epc(regs);
 | 
			
		||||
			value = regs->regs[insn.spec3_format.rt];
 | 
			
		||||
			StoreHW(addr, value, res);
 | 
			
		||||
			if (res) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto fault;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case swe_op:
 | 
			
		||||
			if (!access_ok(VERIFY_WRITE, addr, 4)) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto sigbus;
 | 
			
		||||
			}
 | 
			
		||||
			compute_return_epc(regs);
 | 
			
		||||
			value = regs->regs[insn.spec3_format.rt];
 | 
			
		||||
			StoreW(addr, value, res);
 | 
			
		||||
			if (res) {
 | 
			
		||||
				set_fs(seg);
 | 
			
		||||
				goto fault;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			set_fs(seg);
 | 
			
		||||
			goto sigill;
 | 
			
		||||
		}
 | 
			
		||||
		set_fs(seg);
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	case lh_op:
 | 
			
		||||
		if (!access_ok(VERIFY_READ, addr, 2))
 | 
			
		||||
			goto sigbus;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue