/* * Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), * Shanghai Jiao Tong University (SJTU) OS-Lab-2020 (i.e., ChCore) is licensed * under the Mulan PSL v1. You can use this software according to the terms and * conditions of the Mulan PSL v1. You may obtain a copy of Mulan PSL v1 at: * http://license.coscl.org.cn/MulanPSL * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the * Mulan PSL v1 for more details. */ #include #include #include #include #include #include #include struct thread_ctx *create_thread_ctx(void) { void *kernel_stack; kernel_stack = kzalloc(DEFAULT_KERNEL_STACK_SZ); if (kernel_stack == NULL) { kwarn("create_thread_ctx fails due to lack of memory\n"); return NULL; } return kernel_stack + DEFAULT_KERNEL_STACK_SZ - sizeof(struct thread_ctx); } void destroy_thread_ctx(struct thread *thread) { void *kernel_stack; BUG_ON(!thread->thread_ctx); kernel_stack = (void *)thread->thread_ctx - DEFAULT_KERNEL_STACK_SZ + sizeof(struct thread_ctx); kfree(kernel_stack); } void init_thread_ctx(struct thread *thread, u64 stack, u64 func, u32 prio, u32 type, s32 aff) { /* * Lab3: Your code here * You need to initialize a thread's context here for later eret_to_thread(context) to work properly * * In this function, you need setup the registers and type of the thread's context, including: * 1. Set SP_EL0 to stack. * 2. Set ELR_EL1 to the entrypoint of this thread. * 3. Set SPSR_EL1 to SPSR_EL1_EL0t as the properly PSTATE. One of the most * important field is SPSR_EL1[3:0] (set as 0 to indicate eret to EL0 in eret_to_thread) * * Check out macro in registers.h for more help */ /* Fill the context of the thread */ // 栈寄存器 thread->thread_ctx->ec.reg[SP_EL0] = stack; // PC 计数器 thread->thread_ctx->ec.reg[ELR_EL1] = func; // 状态字寄存器 thread->thread_ctx->ec.reg[SPSR_EL1] = SPSR_EL1_EL0t; /* Set thread type */ thread->thread_ctx->type = type; /* Set the priority and state of the thread */ thread->thread_ctx->prio = prio; thread->thread_ctx->state = TS_INIT; /* Set the cpuid and affinity */ thread->thread_ctx->affinity = aff; /* Set the budget of the thread */ thread->thread_ctx->sc = kmalloc(sizeof(sched_cont_t)); thread->thread_ctx->sc->budget = DEFAULT_BUDGET; } u64 arch_get_thread_stack(struct thread *thread) { return thread->thread_ctx->ec.reg[SP_EL0]; } void arch_set_thread_stack(struct thread *thread, u64 stack) { thread->thread_ctx->ec.reg[SP_EL0] = stack; } void arch_set_thread_return(struct thread *thread, u64 ret) { thread->thread_ctx->ec.reg[X0] = ret; } void arch_set_thread_next_ip(struct thread *thread, u64 ip) { /* Currently, we use fault PC to store the next ip */ // thread->thread_ctx->ec.reg[FaultPC] = ip; /* Only required when we need to change PC */ /* Maybe update ELR_EL1 directly */ thread->thread_ctx->ec.reg[ELR_EL1] = ip; } u64 arch_get_thread_next_ip(struct thread *thread) { return thread->thread_ctx->ec.reg[ELR_EL1]; } void arch_set_thread_info_page(struct thread *thread, u64 info_page_addr) { thread->thread_ctx->ec.reg[X0] = info_page_addr; } void arch_set_thread_arg(struct thread *thread, u64 arg) { thread->thread_ctx->ec.reg[X0] = arg; } void arch_enable_interrupt(struct thread *thread) { thread->thread_ctx->ec.reg[SPSR_EL1] &= ~SPSR_EL1_IRQ; } void arch_disable_interrupt(struct thread *thread) { thread->thread_ctx->ec.reg[SPSR_EL1] |= SPSR_EL1_IRQ; }