2021-05-23 20:13:14 +08:00

130 lines
3.7 KiB
C

/*
* 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 <common/kmalloc.h>
#include <common/kprint.h>
#include <common/smp.h>
#include <common/util.h>
#include <common/registers.h>
#include <process/thread.h>
#include <sched/sched.h>
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;
}