Full utcb copying partially works now.

This commit is contained in:
Bahadir Balban
2009-05-19 11:26:45 +03:00
parent b950ec323d
commit 3bbbcdfefa
5 changed files with 49 additions and 5 deletions

View File

@@ -40,11 +40,9 @@ int ipc_full_copy(struct ktcb *to, struct ktcb *from)
int ret;
/* Check that utcb memory accesses won't fault us */
if ((ret = check_access(to->utcb_address, UTCB_SIZE,
MAP_SVC_RW_FLAGS, 0)) < 0)
if ((ret = tcb_check_and_lazy_map_utcb(to)) < 0)
return ret;
if ((ret = check_access(to->utcb_address, UTCB_SIZE,
MAP_SVC_RW_FLAGS, 0)) < 0)
if ((ret = tcb_check_and_lazy_map_utcb(from)) < 0)
return ret;
/* Directly copy from one utcb to another */

View File

@@ -256,7 +256,7 @@ int check_mapping_pgd(unsigned long vaddr, unsigned long size,
BUG_ON(!(flags = space_flags_to_ptflags(flags)));
for (int i = 0; i < npages; i++) {
pte = virt_to_pte(vaddr + i * PAGE_SIZE);
pte = virt_to_pte_from_pgd(vaddr + i * PAGE_SIZE, pgd);
/* Check if pte perms are equal or gt given flags */
if ((pte & PTE_PROT_MASK) >= (flags & PTE_PROT_MASK))
@@ -268,6 +268,11 @@ int check_mapping_pgd(unsigned long vaddr, unsigned long size,
return 1;
}
unsigned long virt_to_phys_by_pgd(unsigned long vaddr, pgd_table_t *pgd)
{
pte_t pte = virt_to_pte_from_pgd(vaddr, pgd);
return pte & ~PAGE_MASK;
}
int check_mapping(unsigned long vaddr, unsigned long size,
unsigned int flags)

View File

@@ -10,6 +10,7 @@
#include <l4/generic/space.h>
#include <l4/lib/idpool.h>
#include <l4/api/kip.h>
#include <l4/api/errno.h>
#include INC_ARCH(exception.h)
#include INC_SUBARCH(mm.h)
#include INC_GLUE(memory.h)
@@ -164,3 +165,41 @@ void task_update_utcb(struct ktcb *cur, struct ktcb *next)
kip.utcb = next->utcb_address;
}
/*
* Checks whether a task's utcb is currently accessible by the kernel
* It returns an error if its not paged in yet, and also maps a non-current
* task's utcb to current task with kernel-access privileges.
*/
int tcb_check_and_lazy_map_utcb(struct ktcb *task)
{
unsigned int phys;
int ret;
BUG_ON(!task->utcb_address);
if ((ret = check_access(task->utcb_address, UTCB_SIZE,
MAP_SVC_RW_FLAGS, 0)) < 0) {
/* Current task simply hasn't mapped its utcb */
if (task == current) {
return -EFAULT;
} else {
if (!(phys = virt_to_phys_by_pgd(task->utcb_address,
TASK_PGD(task)))) {
/* Task hasn't mapped its utcb */
return -EFAULT;
} else {
/*
* Task has utcb but it hasn't yet been mapped
* to current task with kernel access. Do it.
*/
add_mapping_pgd(phys, task->utcb_address,
page_align_up(UTCB_SIZE),
MAP_SVC_RW_FLAGS,
TASK_PGD(current));
}
}
}
return 0;
}