From 3bbbcdfefad72ee5dc282a6cce3f59dc15194875 Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Tue, 19 May 2009 11:26:45 +0300 Subject: [PATCH] Full utcb copying partially works now. --- include/l4/generic/tcb.h | 1 + include/l4/glue/arm/memory.h | 1 + src/api/ipc.c | 6 ++---- src/arch/arm/v5/mm.c | 7 ++++++- src/generic/tcb.c | 39 ++++++++++++++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/include/l4/generic/tcb.h b/include/l4/generic/tcb.h index eaa5f9e..d61ad4e 100644 --- a/include/l4/generic/tcb.h +++ b/include/l4/generic/tcb.h @@ -145,6 +145,7 @@ void tcb_delete(struct ktcb *tcb); void init_ktcb_list(void); void task_update_utcb(struct ktcb *cur, struct ktcb *next); +int tcb_check_and_lazy_map_utcb(struct ktcb *task); #endif /* __TCB_H__ */ diff --git a/include/l4/glue/arm/memory.h b/include/l4/glue/arm/memory.h index 572d6e4..bed1db9 100644 --- a/include/l4/glue/arm/memory.h +++ b/include/l4/glue/arm/memory.h @@ -130,6 +130,7 @@ int check_mapping(unsigned long vaddr, unsigned long size, void copy_pgd_kern_all(pgd_table_t *); pte_t virt_to_pte(unsigned long virtual); pte_t virt_to_pte_from_pgd(unsigned long virtual, pgd_table_t *pgd); +unsigned long virt_to_phys_by_pgd(unsigned long vaddr, pgd_table_t *pgd); #endif /* __GLUE_ARM_MEMORY_H__ */ diff --git a/src/api/ipc.c b/src/api/ipc.c index 95ee620..edab585 100644 --- a/src/api/ipc.c +++ b/src/api/ipc.c @@ -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 */ diff --git a/src/arch/arm/v5/mm.c b/src/arch/arm/v5/mm.c index 80f2275..f5ec267 100644 --- a/src/arch/arm/v5/mm.c +++ b/src/arch/arm/v5/mm.c @@ -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) diff --git a/src/generic/tcb.c b/src/generic/tcb.c index dbdfe0b..67d18e1 100644 --- a/src/generic/tcb.c +++ b/src/generic/tcb.c @@ -10,6 +10,7 @@ #include #include #include +#include #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; +} + +