mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	powerpc/mm: Move the DSISR_PROTFAULT sanity check
This has a page of comment explaining what's going on right in the middle of do_page_fault() which makes things a bit hard to follow. Move it to a helper instead. Also do the test earlier as there's no point waiting until after we found the VMA. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
		
							parent
							
								
									04aafdc601
								
							
						
					
					
						commit
						2865d08dd9
					
				
					 1 changed files with 42 additions and 33 deletions
				
			
		| 
						 | 
					@ -239,6 +239,45 @@ static inline void cmo_account_page_fault(void)
 | 
				
			||||||
static inline void cmo_account_page_fault(void) { }
 | 
					static inline void cmo_account_page_fault(void) { }
 | 
				
			||||||
#endif /* CONFIG_PPC_SMLPAR */
 | 
					#endif /* CONFIG_PPC_SMLPAR */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PPC_STD_MMU
 | 
				
			||||||
 | 
					static void sanity_check_fault(bool is_write, unsigned long error_code)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * For hash translation mode, we should never get a
 | 
				
			||||||
 | 
						 * PROTFAULT. Any update to pte to reduce access will result in us
 | 
				
			||||||
 | 
						 * removing the hash page table entry, thus resulting in a DSISR_NOHPTE
 | 
				
			||||||
 | 
						 * fault instead of DSISR_PROTFAULT.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * A pte update to relax the access will not result in a hash page table
 | 
				
			||||||
 | 
						 * entry invalidate and hence can result in DSISR_PROTFAULT.
 | 
				
			||||||
 | 
						 * ptep_set_access_flags() doesn't do a hpte flush. This is why we have
 | 
				
			||||||
 | 
						 * the special !is_write in the below conditional.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * For platforms that doesn't supports coherent icache and do support
 | 
				
			||||||
 | 
						 * per page noexec bit, we do setup things such that we do the
 | 
				
			||||||
 | 
						 * sync between D/I cache via fault. But that is handled via low level
 | 
				
			||||||
 | 
						 * hash fault code (hash_page_do_lazy_icache()) and we should not reach
 | 
				
			||||||
 | 
						 * here in such case.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * For wrong access that can result in PROTFAULT, the above vma->vm_flags
 | 
				
			||||||
 | 
						 * check should handle those and hence we should fall to the bad_area
 | 
				
			||||||
 | 
						 * handling correctly.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * For embedded with per page exec support that doesn't support coherent
 | 
				
			||||||
 | 
						 * icache we do get PROTFAULT and we handle that D/I cache sync in
 | 
				
			||||||
 | 
						 * set_pte_at while taking the noexec/prot fault. Hence this is WARN_ON
 | 
				
			||||||
 | 
						 * is conditional for server MMU.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * For radix, we can get prot fault for autonuma case, because radix
 | 
				
			||||||
 | 
						 * page table will have them marked noaccess for user.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (!radix_enabled() && !is_write)
 | 
				
			||||||
 | 
							WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					static void sanity_check_fault(bool is_write, unsigned long error_code) { }
 | 
				
			||||||
 | 
					#endif /* CONFIG_PPC_STD_MMU */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Define the correct "is_write" bit in error_code based
 | 
					 * Define the correct "is_write" bit in error_code based
 | 
				
			||||||
 * on the processor family
 | 
					 * on the processor family
 | 
				
			||||||
| 
						 | 
					@ -306,6 +345,9 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 | 
				
			||||||
		return SIGBUS;
 | 
							return SIGBUS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Additional sanity check(s) */
 | 
				
			||||||
 | 
						sanity_check_fault(is_write, error_code);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The kernel should never take an execute fault nor should it
 | 
						 * The kernel should never take an execute fault nor should it
 | 
				
			||||||
	 * take a page fault to a kernel address.
 | 
						 * take a page fault to a kernel address.
 | 
				
			||||||
| 
						 | 
					@ -441,39 +483,6 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
 | 
				
			||||||
		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
 | 
							if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
 | 
				
			||||||
			return bad_area(regs, address);
 | 
								return bad_area(regs, address);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#ifdef CONFIG_PPC_STD_MMU
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * For hash translation mode, we should never get a
 | 
					 | 
				
			||||||
	 * PROTFAULT. Any update to pte to reduce access will result in us
 | 
					 | 
				
			||||||
	 * removing the hash page table entry, thus resulting in a DSISR_NOHPTE
 | 
					 | 
				
			||||||
	 * fault instead of DSISR_PROTFAULT.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * A pte update to relax the access will not result in a hash page table
 | 
					 | 
				
			||||||
	 * entry invalidate and hence can result in DSISR_PROTFAULT.
 | 
					 | 
				
			||||||
	 * ptep_set_access_flags() doesn't do a hpte flush. This is why we have
 | 
					 | 
				
			||||||
	 * the special !is_write in the below conditional.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * For platforms that doesn't supports coherent icache and do support
 | 
					 | 
				
			||||||
	 * per page noexec bit, we do setup things such that we do the
 | 
					 | 
				
			||||||
	 * sync between D/I cache via fault. But that is handled via low level
 | 
					 | 
				
			||||||
	 * hash fault code (hash_page_do_lazy_icache()) and we should not reach
 | 
					 | 
				
			||||||
	 * here in such case.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * For wrong access that can result in PROTFAULT, the above vma->vm_flags
 | 
					 | 
				
			||||||
	 * check should handle those and hence we should fall to the bad_area
 | 
					 | 
				
			||||||
	 * handling correctly.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * For embedded with per page exec support that doesn't support coherent
 | 
					 | 
				
			||||||
	 * icache we do get PROTFAULT and we handle that D/I cache sync in
 | 
					 | 
				
			||||||
	 * set_pte_at while taking the noexec/prot fault. Hence this is WARN_ON
 | 
					 | 
				
			||||||
	 * is conditional for server MMU.
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 * For radix, we can get prot fault for autonuma case, because radix
 | 
					 | 
				
			||||||
	 * page table will have them marked noaccess for user.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (!radix_enabled() && !is_write)
 | 
					 | 
				
			||||||
		WARN_ON_ONCE(error_code & DSISR_PROTFAULT);
 | 
					 | 
				
			||||||
#endif /* CONFIG_PPC_STD_MMU */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If for any reason at all we couldn't handle the fault,
 | 
						 * If for any reason at all we couldn't handle the fault,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue