diff --git a/lab4/.gdbinit b/lab4/.gdbinit index 98f1327..52dd98f 100644 --- a/lab4/.gdbinit +++ b/lab4/.gdbinit @@ -13,4 +13,4 @@ define add-symbol-file-auto end add-symbol-file-auto ./build/kernel.img -add-symbol-file-auto ./user/build/ramdisk/testpf.bin +add-symbol-file-auto ./user/build/ramdisk/yield_single.bin diff --git a/lab4/kernel/exception/exception.c b/lab4/kernel/exception/exception.c index 2cdfb34..932a151 100644 --- a/lab4/kernel/exception/exception.c +++ b/lab4/kernel/exception/exception.c @@ -80,6 +80,11 @@ void handle_entry_c(int type, u64 esr, u64 address) case ESR_EL1_EC_DABT_CEL: do_page_fault(esr, address); break; + case ESR_EL1_EC_IABT_LEL: + // 线程退出 + if (address == 0x0) { + sys_exit(0); + } default: kdebug("Unsupported Exception ESR %lx\n", esr); break; diff --git a/lab4/kernel/sched/policy_rr.c b/lab4/kernel/sched/policy_rr.c index 1ce3b5e..5ef239d 100644 --- a/lab4/kernel/sched/policy_rr.c +++ b/lab4/kernel/sched/policy_rr.c @@ -51,7 +51,34 @@ struct thread idle_threads[PLAT_CPU_NUM]; */ int rr_sched_enqueue(struct thread *thread) { - return -1; + s32 dest_core; + + if (thread == NULL || thread->thread_ctx == NULL) { + return -1; + } + + // 空闲线程 + if (thread->thread_ctx->type == TYPE_IDLE) { + return 0; + } + + // 已经进入就绪队列 + if (thread->thread_ctx->state == TS_READY) { + return -1; + } + + // 选择目标核心 + dest_core = thread->thread_ctx->affinity; + if (dest_core == NO_AFF) { + dest_core = smp_get_cpu_id(); + } + + // 入队尾 + list_append(&thread->ready_queue_node, &rr_ready_queue[dest_core]); + thread->thread_ctx->state = TS_READY; + thread->thread_ctx->cpuid = dest_core; + + return 0; } /* @@ -62,7 +89,25 @@ int rr_sched_enqueue(struct thread *thread) */ int rr_sched_dequeue(struct thread *thread) { - return -1; + if (thread == NULL || thread->thread_ctx == NULL) { + return -1; + } + + // 空闲线程 + if (thread->thread_ctx->type == TYPE_IDLE) { + return -1; + } + + // 状态判断 + if (thread->thread_ctx->state != TS_READY) { + return -1; + } + + // 出队 + list_del(&thread->ready_queue_node); + thread->thread_ctx->state = TS_INTER; + + return 0; } /* @@ -78,7 +123,25 @@ int rr_sched_dequeue(struct thread *thread) */ struct thread *rr_sched_choose_thread(void) { - return NULL; + struct thread *result; + struct list_head *queue = &rr_ready_queue[smp_get_cpu_id()]; + + // 队列空 + if (list_empty(queue)) { + return &idle_threads[smp_get_cpu_id()]; + } + + // 选择队首,注意准备队列指针并不是 thread 的开头 + result = (struct thread *) (queue->next - 1); + + // 出队 + if (rr_sched_dequeue(result) != 0) { + return NULL; + } + + kdebug("[RR] Cpu #%d Select thread %lx, sp = %lx\n", + smp_get_cpu_id(), result->thread_ctx, result->thread_ctx->ec.reg[SP_EL0]); + return result; } static inline void rr_sched_refill_budget(struct thread *target, u32 budget) @@ -99,7 +162,25 @@ static inline void rr_sched_refill_budget(struct thread *target, u32 budget) */ int rr_sched(void) { - return -1; + struct thread *dest_thread; + + // 若当前有运行进程,放入队列 + if (current_thread != NULL && current_thread->thread_ctx != NULL + && current_thread->thread_ctx->type != TYPE_IDLE) { + rr_sched_enqueue(current_thread); + kdebug("[RR] Cpu #%d yield thread %lx to queue\n", smp_get_cpu_id(), current_thread->thread_ctx); + } + + // 选择新线程 + dest_thread = rr_sched_choose_thread(); + if (dest_thread == NULL) { + return -1; + } + + // 准备调度 + switch_to_thread(dest_thread); + + return 0; } /* diff --git a/lab4/kernel/sched/sched.c b/lab4/kernel/sched/sched.c index b58b343..d09defa 100644 --- a/lab4/kernel/sched/sched.c +++ b/lab4/kernel/sched/sched.c @@ -140,6 +140,8 @@ u64 switch_context(void) */ void sys_yield(void) { + sched(); + eret_to_thread(switch_context()); } int sched_init(struct sched_ops *sched_ops) diff --git a/lab4/kernel/syscall/syscall.c b/lab4/kernel/syscall/syscall.c index 8493508..acda386 100644 --- a/lab4/kernel/syscall/syscall.c +++ b/lab4/kernel/syscall/syscall.c @@ -45,7 +45,7 @@ u32 sys_getc(void) */ u32 sys_get_cpu_id(void) { - return -1; + return smp_get_cpu_id(); } #pragma clang diagnostic push @@ -57,6 +57,11 @@ u32 sys_get_cpu_id(void) */ const void *syscall_table[NR_SYSCALL] = { [0 ... NR_SYSCALL - 1] = sys_debug, + [SYS_putc] = sys_putc, + [SYS_exit] = sys_exit, + [SYS_create_pmo] = sys_create_pmo, + [SYS_map_pmo] = sys_map_pmo, + [SYS_handle_brk] = sys_handle_brk, /* lab3 syscalls finished */ [SYS_getc] = sys_getc, diff --git a/note.org b/note.org index 4d94523..c2349a2 100644 --- a/note.org +++ b/note.org @@ -145,6 +145,10 @@ ELF Section、Segment 两个概念。 其实连对齐都不用,直接就干上去也行,反正之前页表的时候已经处理了没对齐的情况。 +一定注意对齐!竟然在后面实验翻车了,段开头是有可能非 4k 对齐的,复制要加上偏移。 + +alloc_section = (char *) phys_to_virt(pmo->start) + (p_vaddr & (PAGE_SIZE - 1)); + **** 初始化线程上下文 照着文字写就行,初始化 TCB @@ -195,3 +199,15 @@ boot 阶段的栈是独立的。函数也没调用几个,我猜测可能是 el *** 练习6 原因是 unlock_kernel 后才进行从栈恢复,而且函数退出时内核栈还是空的,所以 unlock 的时候无所谓。 + +*** 练习7 + +虽然没提,但是其实状态设置、控制很重要。以及 BUG 异步输出基本和乱码一样,希望加个打印锁…… + +还有一个重点就是 ready_queue 不是结构体开头,所以不可以直接转成 thread *。 + +sys_yield 要注意必须手动调用切换上下文,不然不会有效果。因为默认的 exception_return 不考虑 current_thread。 + +*** 练习8 + +否则将无法再次在该核上进行调度。