mirror of
https://github.com/drasko/codezero.git
synced 2026-01-12 02:43:15 +01:00
posix: MM0 task page access issues fixed.
This commit is contained in:
@@ -149,7 +149,6 @@ struct tcb_head {
|
||||
struct tcb *find_task(int tid);
|
||||
void global_add_task(struct tcb *task);
|
||||
void global_remove_task(struct tcb *task);
|
||||
void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner);
|
||||
int task_mmap_segments(struct tcb *task, struct vm_file *file, struct exec_file_desc *efd,
|
||||
struct args_struct *args, struct args_struct *env);
|
||||
int task_setup_registers(struct tcb *task, unsigned int pc,
|
||||
@@ -159,13 +158,11 @@ int tcb_destroy(struct tcb *task);
|
||||
int task_start(struct tcb *task);
|
||||
int copy_tcb(struct tcb *to, struct tcb *from, unsigned int flags);
|
||||
int task_release_vmas(struct task_vma_head *vma_head);
|
||||
int task_prefault_regions(struct tcb *task, struct vm_file *f);
|
||||
struct tcb *task_create(struct tcb *orig,
|
||||
struct task_ids *ids,
|
||||
unsigned int ctrl_flags,
|
||||
unsigned int alloc_flags);
|
||||
|
||||
int prefault_range(struct tcb *task, unsigned long start,
|
||||
unsigned long end, unsigned int vm_flags);
|
||||
int task_prefault_range(struct tcb *task, unsigned long start,
|
||||
unsigned long end, unsigned int vm_flags);
|
||||
|
||||
#endif /* __TASK_H__ */
|
||||
|
||||
@@ -227,19 +227,13 @@ void vm_print_objects(struct link *vmo_list);
|
||||
void vm_print_files(struct link *file_list);
|
||||
|
||||
/* Used for pre-faulting a page from mm0 */
|
||||
int prefault_page(struct tcb *task, unsigned long address,
|
||||
unsigned int vmflags);
|
||||
struct page *task_prefault_page(struct tcb *task, unsigned long address,
|
||||
unsigned int vmflags);
|
||||
struct page *page_init(struct page *page);
|
||||
struct page *find_page(struct vm_object *vmo, unsigned long page_offset);
|
||||
void *pager_map_page(struct vm_file *f, unsigned long page_offset);
|
||||
void pager_unmap_page(void *vaddr);
|
||||
|
||||
/* To get currently mapped page of a virtual address on a task */
|
||||
struct page *task_virt_to_page(struct tcb *t, unsigned long virtual,
|
||||
unsigned int vm_flags);
|
||||
int validate_task_range(struct tcb *t, unsigned long start,
|
||||
unsigned long end, unsigned int vmflags);
|
||||
|
||||
/* Changes all shadows and their ptes to read-only */
|
||||
int vm_freeze_shadows(struct tcb *task);
|
||||
|
||||
@@ -247,7 +241,7 @@ int vm_compare_prot_flags(unsigned int current, unsigned int needed);
|
||||
int task_insert_vma(struct vm_area *vma, struct link *vma_list);
|
||||
|
||||
/* Main page fault entry point */
|
||||
int page_fault_handler(struct tcb *faulty_task, fault_kdata_t *fkdata);
|
||||
struct page *page_fault_handler(struct tcb *faulty_task, fault_kdata_t *fkdata);
|
||||
|
||||
int vma_copy_links(struct vm_area *new_vma, struct vm_area *vma);
|
||||
int vma_drop_merge_delete(struct vm_area *vma, struct vm_obj_link *link);
|
||||
|
||||
@@ -78,10 +78,16 @@ void handle_requests(void)
|
||||
/* This has no receive phase */
|
||||
return;
|
||||
|
||||
case L4_IPC_TAG_PFAULT:
|
||||
case L4_IPC_TAG_PFAULT: {
|
||||
struct page *p;
|
||||
|
||||
/* Handle page fault. */
|
||||
ret = page_fault_handler(sender, (fault_kdata_t *)&mr[0]);
|
||||
if (IS_ERR(p = page_fault_handler(sender, (fault_kdata_t *)&mr[0])))
|
||||
ret = (int)p;
|
||||
else
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case L4_IPC_TAG_SHMGET: {
|
||||
ret = sys_shmget((key_t)mr[0], (int)mr[1], (int)mr[2]);
|
||||
|
||||
@@ -649,7 +649,7 @@ struct page *copy_on_write(struct fault_data *fault)
|
||||
* FIXME: Add VM_DIRTY bit for every page that has write-faulted.
|
||||
*/
|
||||
|
||||
int __do_page_fault(struct fault_data *fault)
|
||||
struct page *__do_page_fault(struct fault_data *fault)
|
||||
{
|
||||
unsigned int reason = fault->reason;
|
||||
unsigned int vma_flags = fault->vma->flags;
|
||||
@@ -741,7 +741,7 @@ out_success:
|
||||
page_align(fault->address), fault->task->tid);
|
||||
// vm_object_print(page->owner);
|
||||
|
||||
return 0;
|
||||
return page;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -841,7 +841,7 @@ int vm_freeze_shadows(struct tcb *task)
|
||||
* - page needs write access:
|
||||
* action: read the page in, give write access.
|
||||
*/
|
||||
int do_page_fault(struct fault_data *fault)
|
||||
struct page *do_page_fault(struct fault_data *fault)
|
||||
{
|
||||
unsigned int vma_flags = (fault->vma) ? fault->vma->flags : VM_NONE;
|
||||
unsigned int reason = fault->reason;
|
||||
@@ -869,9 +869,8 @@ int do_page_fault(struct fault_data *fault)
|
||||
return __do_page_fault(fault);
|
||||
}
|
||||
|
||||
int page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata)
|
||||
struct page *page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata)
|
||||
{
|
||||
int err;
|
||||
struct fault_data fault = {
|
||||
/* Fault data from kernel */
|
||||
.kdata = fkdata,
|
||||
@@ -888,14 +887,7 @@ int page_fault_handler(struct tcb *sender, fault_kdata_t *fkdata)
|
||||
"Bad things will happen.\n");
|
||||
|
||||
/* Handle the actual fault */
|
||||
err = do_page_fault(&fault);
|
||||
|
||||
/*
|
||||
* Return the ipc and by doing so restart the faulty thread.
|
||||
* FIXME: We could kill the thread if there was an error???
|
||||
* Perhaps via a kill message to kernel?
|
||||
*/
|
||||
return err;
|
||||
return do_page_fault(&fault);
|
||||
}
|
||||
|
||||
int vm_compare_prot_flags(unsigned int current, unsigned int needed)
|
||||
@@ -914,75 +906,15 @@ int vm_compare_prot_flags(unsigned int current, unsigned int needed)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Makes the virtual to page translation for a given user task.
|
||||
* It traverses the vm_objects and returns the first encountered
|
||||
* instance of the page. If page is not mapped in the task's address
|
||||
* space, (not faulted at all), returns error.
|
||||
*/
|
||||
struct page *task_virt_to_page(struct tcb *t, unsigned long virtual, unsigned int vm_flags)
|
||||
{
|
||||
unsigned long vma_offset;
|
||||
unsigned long file_offset;
|
||||
struct vm_obj_link *vmo_link;
|
||||
struct vm_area *vma;
|
||||
struct page *page;
|
||||
|
||||
/* First find the vma that maps that virtual address */
|
||||
if (!(vma = find_vma(virtual, &t->vm_area_head->list))) {
|
||||
//printf("%s: No VMA found for 0x%x on task: %d\n",
|
||||
// __FUNCTION__, virtual, t->tid);
|
||||
return PTR_ERR(-EINVAL);
|
||||
}
|
||||
|
||||
/* Find the pfn offset of virtual address in this vma */
|
||||
BUG_ON(__pfn(virtual) < vma->pfn_start ||
|
||||
__pfn(virtual) > vma->pfn_end);
|
||||
vma_offset = __pfn(virtual) - vma->pfn_start;
|
||||
|
||||
/* Find the file offset of virtual address in this file */
|
||||
file_offset = vma->file_offset + vma_offset;
|
||||
|
||||
/* Get the first object, either original file or a shadow */
|
||||
if (!(vmo_link = vma_next_link(&vma->vm_obj_list, &vma->vm_obj_list))) {
|
||||
printf("%s:%s: No vm object in vma!\n",
|
||||
__TASKNAME__, __FUNCTION__);
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Traverse the list of read-only vm objects and search for the page */
|
||||
while (IS_ERR(page = vmo_link->obj->pager->ops.page_in(vmo_link->obj,
|
||||
file_offset))) {
|
||||
if (!(vmo_link = vma_next_link(&vmo_link->list,
|
||||
&vma->vm_obj_list))) {
|
||||
printf("%s:%s: Traversed all shadows and the original "
|
||||
"file's vm_object, but could not find the "
|
||||
"page in this vma.\n",__TASKNAME__,
|
||||
__FUNCTION__);
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
/* Found one, but does it have the right permissions */
|
||||
if (!vm_compare_prot_flags(vmo_link->obj->flags, vm_flags))
|
||||
return PTR_ERR(-EFAULT);
|
||||
|
||||
// printf("%s: %s: Found page with file_offset: 0x%x\n",
|
||||
// __TASKNAME__, __FUNCTION__, page->offset);
|
||||
// vm_object_print(vmo_link->obj);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prefaults the page with given virtual address, to given task
|
||||
* with given reasons. Multiple reasons are allowed, they are
|
||||
* handled separately in order.
|
||||
*/
|
||||
int prefault_page(struct tcb *task, unsigned long address,
|
||||
unsigned int vmflags)
|
||||
struct page *task_prefault_page(struct tcb *task, unsigned long address,
|
||||
unsigned int vmflags)
|
||||
{
|
||||
int err;
|
||||
struct page *p;
|
||||
struct fault_data fault = {
|
||||
.task = task,
|
||||
.address = address,
|
||||
@@ -994,30 +926,29 @@ int prefault_page(struct tcb *task, unsigned long address,
|
||||
/* Find the vma */
|
||||
if (!(fault.vma = find_vma(fault.address,
|
||||
&fault.task->vm_area_head->list))) {
|
||||
err = -EINVAL;
|
||||
dprintf("%s: Invalid: No vma for given address. %d\n",
|
||||
__FUNCTION__, err);
|
||||
return err;
|
||||
__FUNCTION__, -EINVAL);
|
||||
return PTR_ERR(-EINVAL);
|
||||
}
|
||||
|
||||
/* Flags may indicate multiple fault reasons. First do the read */
|
||||
if (vmflags & VM_READ) {
|
||||
fault.pte_flags = VM_NONE;
|
||||
fault.reason = VM_READ;
|
||||
if ((err = do_page_fault(&fault)) < 0)
|
||||
return err;
|
||||
if (IS_ERR(p = do_page_fault(&fault)))
|
||||
return p;
|
||||
}
|
||||
/* Now write */
|
||||
if (vmflags & VM_WRITE) {
|
||||
fault.pte_flags = VM_READ;
|
||||
fault.reason = VM_WRITE;
|
||||
if ((err = do_page_fault(&fault)) < 0)
|
||||
return err;
|
||||
if (IS_ERR(p = do_page_fault(&fault)))
|
||||
return p;
|
||||
}
|
||||
/* No exec or any other fault reason allowed. */
|
||||
BUG_ON(vmflags & ~(VM_READ | VM_WRITE));
|
||||
|
||||
return 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -552,16 +552,16 @@ int copy_cache_pages(struct vm_file *vmfile, struct tcb *task, void *buf,
|
||||
copysize = min(copysize, PAGE_SIZE - page_offset(task_offset));
|
||||
|
||||
if (read)
|
||||
page_copy(task_virt_to_page(task, task_offset,
|
||||
VM_READ | VM_WRITE),
|
||||
page_copy(task_prefault_page(task, task_offset,
|
||||
VM_READ | VM_WRITE),
|
||||
file_page,
|
||||
page_offset(task_offset),
|
||||
page_offset(file_offset),
|
||||
copysize);
|
||||
else
|
||||
page_copy(file_page,
|
||||
task_virt_to_page(task, task_offset,
|
||||
VM_READ),
|
||||
task_prefault_page(task, task_offset,
|
||||
VM_READ),
|
||||
page_offset(file_offset),
|
||||
page_offset(task_offset),
|
||||
copysize);
|
||||
|
||||
@@ -150,8 +150,7 @@ int pager_setup_task(void)
|
||||
}
|
||||
|
||||
/* Pager must prefault its utcb */
|
||||
prefault_page(task, task->utcb_address,
|
||||
VM_READ | VM_WRITE);
|
||||
task_prefault_page(task, task->utcb_address, VM_READ | VM_WRITE);
|
||||
|
||||
/* Add the task to the global task list */
|
||||
global_add_task(task);
|
||||
@@ -557,9 +556,9 @@ void copy_init_process(void)
|
||||
}
|
||||
|
||||
/* Prefault it */
|
||||
if ((err = prefault_range(self, (unsigned long)mapped,
|
||||
img_size,
|
||||
VM_READ | VM_WRITE)) < 0) {
|
||||
if ((err = task_prefault_range(self, (unsigned long)mapped,
|
||||
img_size, VM_READ | VM_WRITE))
|
||||
< 0) {
|
||||
printf("FATAL: Prefaulting init image failed.\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ void *pager_validate_map_user_range2(struct tcb *user, void *userptr,
|
||||
|
||||
/* Map every page contiguously in the allocated virtual address range */
|
||||
for (unsigned long addr = start; addr < end; addr += PAGE_SIZE) {
|
||||
struct page *p = task_virt_to_page(user, addr, vm_flags);
|
||||
struct page *p = task_prefault_page(user, addr, vm_flags);
|
||||
|
||||
if (IS_ERR(p)) {
|
||||
/* Unmap pages mapped so far */
|
||||
@@ -191,7 +191,7 @@ void *pager_validate_map_user_range2(struct tcb *user, void *userptr,
|
||||
return p;
|
||||
}
|
||||
|
||||
l4_map((void *)page_to_phys(task_virt_to_page(user, addr, vm_flags)),
|
||||
l4_map((void *)page_to_phys(p),
|
||||
virt, 1, MAP_USR_RW_FLAGS, self_tid());
|
||||
virt += PAGE_SIZE;
|
||||
}
|
||||
|
||||
@@ -383,7 +383,7 @@ int shpage_map_to_task(struct tcb *owner, struct tcb *mapper, unsigned int flags
|
||||
/* Prefault the owner's shared page to mapper's address space */
|
||||
if (flags & SHPAGE_PREFAULT)
|
||||
for (int i = 0; i < __pfn(DEFAULT_SHPAGE_SIZE); i++)
|
||||
prefault_page(mapper, (unsigned long)owner->shared_page +
|
||||
task_prefault_page(mapper, (unsigned long)owner->shared_page +
|
||||
__pfn_to_addr(i), VM_READ | VM_WRITE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -504,14 +504,14 @@ int task_copy_args_to_user(char *user_stack,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int prefault_range(struct tcb *task, unsigned long start,
|
||||
unsigned long size, unsigned int vm_flags)
|
||||
int task_prefault_range(struct tcb *task, unsigned long start,
|
||||
unsigned long size, unsigned int vm_flags)
|
||||
{
|
||||
int err;
|
||||
struct page *p;
|
||||
|
||||
for (unsigned long i = start; i < start + size; i += PAGE_SIZE)
|
||||
if ((err = prefault_page(task, i, vm_flags)) < 0)
|
||||
return err;
|
||||
if (IS_ERR(p = task_prefault_page(task, i, vm_flags)))
|
||||
return (int)p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -553,9 +553,8 @@ int task_map_stack(struct vm_file *f, struct exec_file_desc *efd,
|
||||
return (int)mapped;
|
||||
}
|
||||
|
||||
/* Prefault the stack for writing. */
|
||||
BUG_ON(prefault_range(task, task->args_start,
|
||||
stack_used, VM_READ | VM_WRITE) < 0);
|
||||
/* FIXME: Probably not necessary anymore. Prefault the stack for writing. */
|
||||
//BUG_ON(task_prefault_range(task, task->args_start, stack_used, VM_READ | VM_WRITE) < 0);
|
||||
|
||||
/* Map the stack's part that will contain args and environment */
|
||||
if (IS_ERR(args_on_stack =
|
||||
@@ -597,12 +596,9 @@ int task_map_bss(struct vm_file *f, struct exec_file_desc *efd, struct tcb *task
|
||||
struct page *last_data_page;
|
||||
void *pagebuf, *bss;
|
||||
|
||||
/* Prefault the last data page */
|
||||
BUG_ON(prefault_page(task, task->data_end,
|
||||
VM_READ | VM_WRITE) < 0);
|
||||
/* Get the page */
|
||||
last_data_page = task_virt_to_page(task, task->data_end,
|
||||
VM_READ | VM_WRITE);
|
||||
last_data_page = task_prefault_page(task, task->data_end,
|
||||
VM_READ | VM_WRITE);
|
||||
|
||||
/* Map the page. FIXME: PAGE COLOR!!! */
|
||||
pagebuf = l4_map_helper((void *)page_to_phys(last_data_page), 1);
|
||||
@@ -759,26 +755,3 @@ int task_start(struct tcb *task)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prefaults all mapped regions of a task. The reason we have this is
|
||||
* some servers are in the page fault handling path (e.g. fs0), and we
|
||||
* don't want them to fault and cause deadlocks and circular deps.
|
||||
*
|
||||
* Normally fs0 faults dont cause dependencies because its faults
|
||||
* are handled by the boot pager, which is part of mm0. BUT: It may
|
||||
* cause deadlocks because fs0 may fault while serving a request
|
||||
* from mm0.(Which is expected to also handle the fault).
|
||||
*/
|
||||
int task_prefault_regions(struct tcb *task, struct vm_file *f)
|
||||
{
|
||||
struct vm_area *vma;
|
||||
|
||||
list_foreach_struct(vma, &task->vm_area_head->list, list) {
|
||||
for (int pfn = vma->pfn_start; pfn < vma->pfn_end; pfn++)
|
||||
BUG_ON(prefault_page(task, __pfn_to_addr(pfn),
|
||||
VM_READ | VM_WRITE) < 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,16 +58,16 @@ void *pager_validate_map_user_range(struct tcb *user, void *userptr,
|
||||
return 0;
|
||||
|
||||
/* Map first page and calculate the mapped address of pointer */
|
||||
mapped = l4_map_helper((void *)page_to_phys(task_virt_to_page(user, start,
|
||||
vm_flags)), 1);
|
||||
mapped = l4_map_helper((void *)page_to_phys(task_prefault_page(user, start,
|
||||
vm_flags)), 1);
|
||||
mapped = (void *)(((unsigned long)mapped) |
|
||||
((unsigned long)(PAGE_MASK & (unsigned long)userptr)));
|
||||
|
||||
/* Map the rest of the pages, if any */
|
||||
for (unsigned long i = start + PAGE_SIZE; i < end; i += PAGE_SIZE)
|
||||
l4_map_helper((void *)page_to_phys(task_virt_to_page(user,
|
||||
start + i,
|
||||
vm_flags)), 1);
|
||||
l4_map_helper((void *)
|
||||
page_to_phys(task_prefault_page(user, start + i,
|
||||
vm_flags)), 1);
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ int main(int argc, char *argv[])
|
||||
char *parent_of_all;
|
||||
char pidbuf[10];
|
||||
|
||||
printf("New task started: %d\n", __raw_tid(getpid()));
|
||||
// printf("New task started: %d\n", __raw_tid(getpid()));
|
||||
|
||||
/* Convert current pid to string */
|
||||
sprintf(pidbuf, "%d", getpid());
|
||||
@@ -45,7 +45,7 @@ int main(int argc, char *argv[])
|
||||
goto out;
|
||||
}
|
||||
|
||||
printf("New task continues: %d\n", __raw_tid(getpid()));
|
||||
// printf("New task continues: %d\n", __raw_tid(getpid()));
|
||||
|
||||
/* Get parent of all pid as a string from environment */
|
||||
parent_of_all = getenv("parent_of_all");
|
||||
|
||||
Reference in New Issue
Block a user