-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 42038 b: refs/heads/master c: 59f35d5 h: refs/heads/master v: v3
- Loading branch information
Gerald Schaefer
authored and
Martin Schwidefsky
committed
Dec 4, 2006
1 parent
3804d2b
commit c7d4870
Showing
5 changed files
with
191 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: d57de5a36791cb1b7285649c62f183b0d3505f7d | ||
refs/heads/master: 59f35d53fde3987d071ea1c9bf1c9ba29fcb69fe |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/* | ||
* arch/s390/lib/uaccess_pt.c | ||
* | ||
* User access functions based on page table walks. | ||
* | ||
* Copyright IBM Corp. 2006 | ||
* Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com) | ||
*/ | ||
|
||
#include <linux/errno.h> | ||
#include <asm/uaccess.h> | ||
#include <linux/mm.h> | ||
#include <asm/futex.h> | ||
|
||
static inline int __handle_fault(struct mm_struct *mm, unsigned long address, | ||
int write_access) | ||
{ | ||
struct vm_area_struct *vma; | ||
int ret = -EFAULT; | ||
|
||
down_read(&mm->mmap_sem); | ||
vma = find_vma(mm, address); | ||
if (unlikely(!vma)) | ||
goto out; | ||
if (unlikely(vma->vm_start > address)) { | ||
if (!(vma->vm_flags & VM_GROWSDOWN)) | ||
goto out; | ||
if (expand_stack(vma, address)) | ||
goto out; | ||
} | ||
|
||
if (!write_access) { | ||
/* page not present, check vm flags */ | ||
if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) | ||
goto out; | ||
} else { | ||
if (!(vma->vm_flags & VM_WRITE)) | ||
goto out; | ||
} | ||
|
||
survive: | ||
switch (handle_mm_fault(mm, vma, address, write_access)) { | ||
case VM_FAULT_MINOR: | ||
current->min_flt++; | ||
break; | ||
case VM_FAULT_MAJOR: | ||
current->maj_flt++; | ||
break; | ||
case VM_FAULT_SIGBUS: | ||
goto out_sigbus; | ||
case VM_FAULT_OOM: | ||
goto out_of_memory; | ||
default: | ||
BUG(); | ||
} | ||
ret = 0; | ||
out: | ||
up_read(&mm->mmap_sem); | ||
return ret; | ||
|
||
out_of_memory: | ||
up_read(&mm->mmap_sem); | ||
if (current->pid == 1) { | ||
yield(); | ||
goto survive; | ||
} | ||
printk("VM: killing process %s\n", current->comm); | ||
return ret; | ||
|
||
out_sigbus: | ||
up_read(&mm->mmap_sem); | ||
current->thread.prot_addr = address; | ||
current->thread.trap_no = 0x11; | ||
force_sig(SIGBUS, current); | ||
return ret; | ||
} | ||
|
||
static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, | ||
size_t n, int write_user) | ||
{ | ||
struct mm_struct *mm = current->mm; | ||
unsigned long offset, pfn, done, size; | ||
pgd_t *pgd; | ||
pmd_t *pmd; | ||
pte_t *pte; | ||
void *from, *to; | ||
|
||
done = 0; | ||
retry: | ||
spin_lock(&mm->page_table_lock); | ||
do { | ||
pgd = pgd_offset(mm, uaddr); | ||
if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
goto fault; | ||
|
||
pmd = pmd_offset(pgd, uaddr); | ||
if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
goto fault; | ||
|
||
pte = pte_offset_map(pmd, uaddr); | ||
if (!pte || !pte_present(*pte) || | ||
(write_user && !pte_write(*pte))) | ||
goto fault; | ||
|
||
pfn = pte_pfn(*pte); | ||
if (!pfn_valid(pfn)) | ||
goto out; | ||
|
||
offset = uaddr & (PAGE_SIZE - 1); | ||
size = min(n - done, PAGE_SIZE - offset); | ||
if (write_user) { | ||
to = (void *)((pfn << PAGE_SHIFT) + offset); | ||
from = kptr + done; | ||
} else { | ||
from = (void *)((pfn << PAGE_SHIFT) + offset); | ||
to = kptr + done; | ||
} | ||
memcpy(to, from, size); | ||
done += size; | ||
uaddr += size; | ||
} while (done < n); | ||
out: | ||
spin_unlock(&mm->page_table_lock); | ||
return n - done; | ||
fault: | ||
spin_unlock(&mm->page_table_lock); | ||
if (__handle_fault(mm, uaddr, write_user)) | ||
return n - done; | ||
goto retry; | ||
} | ||
|
||
size_t copy_from_user_pt(size_t n, const void __user *from, void *to) | ||
{ | ||
size_t rc; | ||
|
||
if (segment_eq(get_fs(), KERNEL_DS)) { | ||
memcpy(to, (void __kernel __force *) from, n); | ||
return 0; | ||
} | ||
rc = __user_copy_pt((unsigned long) from, to, n, 0); | ||
if (unlikely(rc)) | ||
memset(to + n - rc, 0, rc); | ||
return rc; | ||
} | ||
|
||
size_t copy_to_user_pt(size_t n, void __user *to, const void *from) | ||
{ | ||
if (segment_eq(get_fs(), KERNEL_DS)) { | ||
memcpy((void __kernel __force *) to, from, n); | ||
return 0; | ||
} | ||
return __user_copy_pt((unsigned long) to, (void *) from, n, 1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters