voiddo_exec(void (*func)()) { /* * If the task was created by privilege_task_create() and hasn't initlized * page table, the default value of TTBR0_EL1 is 0x0 */ consttask_t *task = get_current(); uintptr_t sp = USER_VIRT_TOP - sizeof(uintptr_t); // stack address grows towards lower memory address size_t size = PAGE_SIZE; uintptr_t pc = 0x0; // start from 0x0
// allocate page for user void *utext = map_addr_user((void *) pc); // assume size < 4KB void *ustack = map_addr_user((void *) sp); // assume size < 4KB if (!utext || !ustack) { // TODO: reclaim utext and ustack return; }
/* * fork page table of user process * return 0 if success, return -1 if fail. */ intfork_page_table(mm_struct *dst, const mm_struct *src) { if (!src || !dst) return-1; if (!src->pgd || dst->pgd) return-1; // dst's pgd must be uninitialized
/* * On success, the task id of the child process is returned * in the parent, and 0 is returned in the child. On failure, * -1 is returned in the parent. */ int64_tdo_fork(struct TrapFrame *tf) { // create a new task: child int64_t new_task_id = privilege_task_create(NULL); if (new_task_id < 0) return-1; task_t *new_task = get_task_by_id(new_task_id); consttask_t *cur_task = get_current();
// parent process and child process have the same content of TrapFrame void *kstacktop_new = get_kstacktop_by_id(new_task->tid); structTrapFrame *tf_new = (struct TrapFrame *) (kstacktop_new - sizeof(struct TrapFrame)); *tf_new = *tf;
/* create pgd for user space of a specific process * return virtual address of the pgd if success, otherwise return NULL. */ staticvoid *create_pgd(mm_struct *mm) { if (!mm->pgd) { // has't created pgd void *page_virt_addr = page_alloc_kernel(); if (!page_virt_addr) returnNULL; mm->pgd = KVA_TO_PA(page_virt_addr); } return (void *) PA_TO_KVA(mm->pgd); }
/* create pud/pmd/pte for user process * return virtual address of the pud/pmd/pte if success, otherwise return NULL. */ staticvoid *create_pmd_pgd_pte(uint64_t *page_table, uint32_t index) { if (!page_table) returnNULL; if (!page_table[index]) { void *page_virt_addr = page_alloc_kernel(); if (!page_virt_addr) returnNULL; page_table[index] = KVA_TO_PA(page_virt_addr) | PD_TABLE; } return (void *) ((page_table[index] & ~0xfffULL) | KERNEL_VIRT_BASE); }
/* create page for user process * return virtual address of the page if success, otherwise return NULL. */ staticvoid *create_page(uint64_t *pte, uint32_t index) { if (!pte) returnNULL; if (!pte[index]) { void *page_virt_addr = page_alloc_kernel(); if (!page_virt_addr) returnNULL; pte[index] = KVA_TO_PA(page_virt_addr) | PTE_NORMAL_ATTR | PD_ACCESS_PERM_1; } return (void *) ((pte[index] & ~0xfffULL) | KERNEL_VIRT_BASE); }
If the unsigned type has conversion rank greater than or equal to the rank of the signed type, then the operand with the signed type is implicitly converted to the unsigned type.
otherwise, if the target type is unsigned, the value 2^b, where b is the number of bits in the target type, is repeatedly subtracted or added to the source value until the result fits in the target type. In other words, unsigned integers implement modulo arithmetic.