add patch_process_vm(). (in progress)
This function patches specified range of specified user space even if the range is not writable. refs #401
This commit is contained in:
@ -219,6 +219,7 @@ enum x86_pf_error_code {
|
|||||||
PF_RSVD = 1 << 3,
|
PF_RSVD = 1 << 3,
|
||||||
PF_INSTR = 1 << 4,
|
PF_INSTR = 1 << 4,
|
||||||
|
|
||||||
|
PF_PATCH = 1 << 29,
|
||||||
PF_POPULATE = 1 << 30,
|
PF_POPULATE = 1 << 30,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1870,7 +1870,8 @@ enum ihk_mc_pt_attribute arch_vrflag_to_ptattr(unsigned long flag, uint64_t faul
|
|||||||
attr = common_vrflag_to_ptattr(flag, fault, ptep);
|
attr = common_vrflag_to_ptattr(flag, fault, ptep);
|
||||||
|
|
||||||
if ((fault & PF_PROT)
|
if ((fault & PF_PROT)
|
||||||
|| ((fault & PF_POPULATE) && (flag & VR_PRIVATE))) {
|
|| ((fault & (PF_POPULATE | PF_PATCH))
|
||||||
|
&& (flag & VR_PRIVATE))) {
|
||||||
attr |= PTATTR_DIRTY;
|
attr |= PTATTR_DIRTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2282,3 +2283,61 @@ int write_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} /* write_process_vm() */
|
} /* write_process_vm() */
|
||||||
|
|
||||||
|
int patch_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t siz)
|
||||||
|
{
|
||||||
|
const uintptr_t ustart = (uintptr_t)udst;
|
||||||
|
const uintptr_t uend = ustart + siz;
|
||||||
|
uint64_t reason;
|
||||||
|
uintptr_t addr;
|
||||||
|
int error;
|
||||||
|
const void *from;
|
||||||
|
void *to;
|
||||||
|
size_t remain;
|
||||||
|
size_t cpsize;
|
||||||
|
unsigned long pa;
|
||||||
|
void *va;
|
||||||
|
|
||||||
|
kprintf("patch_process_vm(%p,%p,%p,%lx)\n", vm, udst, ksrc, siz);
|
||||||
|
if ((ustart < vm->region.user_start)
|
||||||
|
|| (vm->region.user_end <= ustart)
|
||||||
|
|| ((vm->region.user_end - ustart) < siz)) {
|
||||||
|
kprintf("patch_process_vm(%p,%p,%p,%lx):not in user\n", vm, udst, ksrc, siz);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
reason = PF_PATCH | PF_WRITE | PF_USER;
|
||||||
|
for (addr = ustart & PAGE_MASK; addr < uend; addr += PAGE_SIZE) {
|
||||||
|
error = page_fault_process_vm(vm, (void *)addr, reason);
|
||||||
|
if (error) {
|
||||||
|
kprintf("patch_process_vm(%p,%p,%p,%lx):pf(%lx):%d\n", vm, udst, ksrc, siz, addr, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
from = ksrc;
|
||||||
|
to = udst;
|
||||||
|
remain = siz;
|
||||||
|
while (remain > 0) {
|
||||||
|
cpsize = PAGE_SIZE - ((uintptr_t)to & (PAGE_SIZE - 1));
|
||||||
|
if (cpsize > remain) {
|
||||||
|
cpsize = remain;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = ihk_mc_pt_virt_to_phys(vm->page_table, to, &pa);
|
||||||
|
if (error) {
|
||||||
|
kprintf("patch_process_vm(%p,%p,%p,%lx):v2p(%p):%d\n", vm, udst, ksrc, siz, to, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
va = phys_to_virt(pa);
|
||||||
|
memcpy(va, from, cpsize);
|
||||||
|
|
||||||
|
from += cpsize;
|
||||||
|
to += cpsize;
|
||||||
|
remain -= cpsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
kprintf("patch_process_vm(%p,%p,%p,%lx):%d\n", vm, udst, ksrc, siz, 0);
|
||||||
|
return 0;
|
||||||
|
} /* patch_process_vm() */
|
||||||
|
|||||||
@ -1378,7 +1378,7 @@ static int page_fault_process_memory_range(struct process_vm *vm, struct vm_rang
|
|||||||
ihk_mc_spinlock_lock_noirq(&vm->page_table_lock);
|
ihk_mc_spinlock_lock_noirq(&vm->page_table_lock);
|
||||||
/*****/
|
/*****/
|
||||||
ptep = ihk_mc_pt_lookup_pte(vm->page_table, (void *)fault_addr, &pgaddr, &pgsize, &p2align);
|
ptep = ihk_mc_pt_lookup_pte(vm->page_table, (void *)fault_addr, &pgaddr, &pgsize, &p2align);
|
||||||
if (!(reason & PF_PROT) && ptep && !pte_is_null(ptep)
|
if (!(reason & (PF_PROT | PF_PATCH)) && ptep && !pte_is_null(ptep)
|
||||||
&& !pte_is_fileoff(ptep, pgsize)) {
|
&& !pte_is_fileoff(ptep, pgsize)) {
|
||||||
if (!pte_is_present(ptep)) {
|
if (!pte_is_present(ptep)) {
|
||||||
error = -EFAULT;
|
error = -EFAULT;
|
||||||
@ -1439,7 +1439,10 @@ static int page_fault_process_memory_range(struct process_vm *vm, struct vm_rang
|
|||||||
}
|
}
|
||||||
page = phys_to_page(phys);
|
page = phys_to_page(phys);
|
||||||
/*****/
|
/*****/
|
||||||
if ((range->flag & VR_PRIVATE) && (!page || page_is_in_memobj(page) || page_is_multi_mapped(page))) {
|
if (((range->flag & VR_PRIVATE)
|
||||||
|
|| ((reason & PF_PATCH)
|
||||||
|
&& !(range->flag & VR_PROT_WRITE)))
|
||||||
|
&& (!page || page_is_in_memobj(page) || page_is_multi_mapped(page))) {
|
||||||
if (!(attr & PTATTR_DIRTY)) {
|
if (!(attr & PTATTR_DIRTY)) {
|
||||||
attr &= ~PTATTR_WRITABLE;
|
attr &= ~PTATTR_WRITABLE;
|
||||||
}
|
}
|
||||||
@ -1513,7 +1516,7 @@ static int do_page_fault_process_vm(struct process_vm *vm, void *fault_addr0, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (((range->flag & VR_PROT_MASK) == VR_PROT_NONE)
|
if (((range->flag & VR_PROT_MASK) == VR_PROT_NONE)
|
||||||
|| ((reason & PF_WRITE)
|
|| (((reason & PF_WRITE) && !(reason & PF_PATCH))
|
||||||
&& !(range->flag & VR_PROT_WRITE))
|
&& !(range->flag & VR_PROT_WRITE))
|
||||||
|| ((reason & PF_INSTR)
|
|| ((reason & PF_INSTR)
|
||||||
&& !(range->flag & VR_PROT_EXEC))) {
|
&& !(range->flag & VR_PROT_EXEC))) {
|
||||||
|
|||||||
Reference in New Issue
Block a user