Skip to content
This repository was archived by the owner on Oct 3, 2024. It is now read-only.

Commit c335060

Browse files
ozbenhmpe
authored andcommitted
powerpc/mm: Make bad_area* helper functions
Instead of goto labels, instead call those functions and return. This gets us closer to x86 and allows us to shring do_page_fault() even more. The main difference with x86 is that those function return a value which we then return from do_page_fault(). That value is our return value from do_page_fault() which we use to generate kernel faults. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
1 parent d3ca587 commit c335060

File tree

1 file changed

+50
-28
lines changed

1 file changed

+50
-28
lines changed

arch/powerpc/mm/fault.c

Lines changed: 50 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,45 @@ static int store_updates_sp(struct pt_regs *regs)
108108
* do_page_fault error handling helpers
109109
*/
110110

111+
static int
112+
__bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code)
113+
{
114+
/*
115+
* If we are in kernel mode, bail out with a SEGV, this will
116+
* be caught by the assembly which will restore the non-volatile
117+
* registers before calling bad_page_fault()
118+
*/
119+
if (!user_mode(regs))
120+
return SIGSEGV;
121+
122+
_exception(SIGSEGV, regs, si_code, address);
123+
124+
return 0;
125+
}
126+
127+
static noinline int bad_area_nosemaphore(struct pt_regs *regs, unsigned long address)
128+
{
129+
return __bad_area_nosemaphore(regs, address, SEGV_MAPERR);
130+
}
131+
132+
static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code)
133+
{
134+
struct mm_struct *mm = current->mm;
135+
136+
/*
137+
* Something tried to access memory that isn't in our memory map..
138+
* Fix it, but check if it's kernel or user first..
139+
*/
140+
up_read(&mm->mmap_sem);
141+
142+
return __bad_area_nosemaphore(regs, address, si_code);
143+
}
144+
145+
static noinline int bad_area(struct pt_regs *regs, unsigned long address)
146+
{
147+
return __bad_area(regs, address, SEGV_MAPERR);
148+
}
149+
111150
#define MM_FAULT_RETURN 0
112151
#define MM_FAULT_CONTINUE -1
113152
#define MM_FAULT_ERR(sig) (sig)
@@ -231,7 +270,6 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
231270
struct vm_area_struct * vma;
232271
struct mm_struct *mm = current->mm;
233272
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
234-
int code = SEGV_MAPERR;
235273
int is_exec = TRAP(regs) == 0x400;
236274
int is_user = user_mode(regs);
237275
int is_write = page_fault_is_write(error_code);
@@ -317,7 +355,7 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
317355
*/
318356
if (!down_read_trylock(&mm->mmap_sem)) {
319357
if (!is_user && !search_exception_tables(regs->nip))
320-
goto bad_area_nosemaphore;
358+
return bad_area_nosemaphore(regs, address);
321359

322360
retry:
323361
down_read(&mm->mmap_sem);
@@ -332,11 +370,11 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
332370

333371
vma = find_vma(mm, address);
334372
if (!vma)
335-
goto bad_area;
373+
return bad_area(regs, address);
336374
if (vma->vm_start <= address)
337375
goto good_area;
338376
if (!(vma->vm_flags & VM_GROWSDOWN))
339-
goto bad_area;
377+
return bad_area(regs, address);
340378

341379
/*
342380
* N.B. The POWER/Open ABI allows programs to access up to
@@ -351,7 +389,7 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
351389
/* get user regs even if this fault is in kernel mode */
352390
struct pt_regs *uregs = current->thread.regs;
353391
if (uregs == NULL)
354-
goto bad_area;
392+
return bad_area(regs, address);
355393

356394
/*
357395
* A user-mode access to an address a long way below
@@ -366,14 +404,12 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
366404
* expand the stack rather than segfaulting.
367405
*/
368406
if (address + 2048 < uregs->gpr[1] && !store_update_sp)
369-
goto bad_area;
407+
return bad_area(regs, address);
370408
}
371409
if (expand_stack(vma, address))
372-
goto bad_area;
410+
return bad_area(regs, address);
373411

374412
good_area:
375-
code = SEGV_ACCERR;
376-
377413
if (is_exec) {
378414
/*
379415
* Allow execution from readable areas if the MMU does not
@@ -388,16 +424,16 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
388424
if (!(vma->vm_flags & VM_EXEC) &&
389425
(cpu_has_feature(CPU_FTR_NOEXECUTE) ||
390426
!(vma->vm_flags & (VM_READ | VM_WRITE))))
391-
goto bad_area;
427+
return bad_area(regs, address);
392428
/* a write */
393429
} else if (is_write) {
394430
if (!(vma->vm_flags & VM_WRITE))
395-
goto bad_area;
431+
return bad_area(regs, address);
396432
flags |= FAULT_FLAG_WRITE;
397433
/* a read */
398434
} else {
399435
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
400-
goto bad_area;
436+
return bad_area(regs, address);
401437
}
402438
#ifdef CONFIG_PPC_STD_MMU
403439
/*
@@ -462,11 +498,10 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
462498

463499
if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
464500
if (fault & VM_FAULT_SIGSEGV)
465-
goto bad_area_nosemaphore;
501+
return bad_area_nosemaphore(regs, address);
466502
rc = mm_fault_error(regs, address, fault);
467503
if (rc >= MM_FAULT_RETURN)
468504
return rc;
469-
rc = 0;
470505
}
471506

472507
/*
@@ -492,20 +527,7 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
492527
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
493528
regs, address);
494529
}
495-
496-
return rc;
497-
498-
bad_area:
499-
up_read(&mm->mmap_sem);
500-
501-
bad_area_nosemaphore:
502-
/* User mode accesses cause a SIGSEGV */
503-
if (is_user) {
504-
_exception(SIGSEGV, regs, code, address);
505-
return 0;
506-
}
507-
508-
return SIGSEGV;
530+
return 0;
509531
}
510532
NOKPROBE_SYMBOL(__do_page_fault);
511533

0 commit comments

Comments
 (0)