/* * Functions used for running initial tasks during boot. * * Copyright (C) 2008 Bahadir Balban */ #include #include #include #include #include #include int boottask_setup_regions(struct vm_file *file, struct tcb *task, unsigned long task_start, unsigned long task_end) { /* * Set task's main address space boundaries. Not all tasks * run in the default user boundaries, e.g. mm0 pager. */ task->start = task_start; task->end = task_end; /* Task stack starts right after the environment. */ task->stack_end = task->end; task->stack_start = task->stack_end - DEFAULT_STACK_SIZE; /* Prepare environment boundaries. */ task->args_end = task->stack_end; task->args_start = task->stack_start - DEFAULT_ENV_SIZE; /* Currently RO text and RW data are one region. TODO: Fix this */ task->data_start = task->start; task->data_end = task->start + page_align_up(file->length); task->text_start = task->data_start; task->text_end = task->data_end; task->entry = task->text_start; /* Task's region available for mmap */ task->map_start = task->data_end; task->map_end = task->stack_start; return 0; } /* * Used for mmapping boot task regions. These are slightly different * from a vfs executable file. */ int boottask_mmap_regions(struct tcb *task, struct vm_file *file) { void *mapped; struct vm_file *shm; /* * mmap each task's physical image to task's address space. * TODO: Map data and text separately when available from bootdesc. */ if (IS_ERR(mapped = do_mmap(file, 0, task, task->text_start, VM_READ | VM_WRITE | VM_EXEC | VMA_PRIVATE, __pfn(page_align_up(task->text_end) - task->text_start)))) { printf("do_mmap: failed with %d.\n", (int)mapped); return (int)mapped; } /* mmap each task's stack as anonymous memory. */ if (IS_ERR(mapped = do_mmap(0, 0, task, task->stack_start, VM_READ | VM_WRITE | VMA_PRIVATE | VMA_ANONYMOUS, __pfn(task->stack_end - task->stack_start)))) { printf("do_mmap: Mapping stack failed with %d.\n", (int)mapped); return (int)mapped; } /* Task's default shared page */ task->shared_page = shm_new_address(DEFAULT_SHPAGE_SIZE/PAGE_SIZE); /* Create a shared memory segment available for shmat() */ if (IS_ERR(shm = shm_new((key_t)task->shared_page, __pfn(DEFAULT_SHPAGE_SIZE)))) return (int)shm; task_setup_utcb(task); return 0; } /* * Main entry point for the creation, initialisation and * execution of a new task. */ struct tcb *boottask_exec(struct vm_file *f, unsigned long task_region_start, unsigned long task_region_end, struct task_ids *ids) { struct tcb *task; int err; if (IS_ERR(task = task_create(0, ids, THREAD_NEW_SPACE, TCB_NO_SHARING))) return task; if ((err = boottask_setup_regions(f, task, task_region_start, task_region_end)) < 0) return PTR_ERR(err); if ((err = boottask_mmap_regions(task, f)) < 0) return PTR_ERR(err); if ((err = task_setup_registers(task, 0, 0, 0)) < 0) return PTR_ERR(err); /* Add the task to the global task list */ global_add_task(task); /* Add the file to global vm lists */ global_add_vm_file(f); /* Prefault all its regions */ if (ids->tid == VFS_TID) task_prefault_regions(task, f); /* Start the task */ if ((err = task_start(task)) < 0) return PTR_ERR(err); return task; }