diff --git a/kernel/arch/x86_64/asm.h b/kernel/arch/x86_64/asm.h new file mode 100644 index 00000000..a3d13867 --- /dev/null +++ b/kernel/arch/x86_64/asm.h @@ -0,0 +1,134 @@ +#pragma once + +#include + +#define sti() __asm__ __volatile__("sti\n\t" :: \ + : "memory") //开启外部中断 +#define cli() __asm__ __volatile__("cli\n\t" :: \ + : "memory") //关闭外部中断 +#define nop() __asm__ __volatile__("nop\n\t") +#define hlt() __asm__ __volatile__("hlt\n\t") +#define pause() asm volatile("pause\n\t"); // 处理器等待一段时间 + +//内存屏障 +#define io_mfence() __asm__ __volatile__("mfence\n\t" :: \ + : "memory") // 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成。 +#define io_sfence() __asm__ __volatile__("sfence\n\t" :: \ + : "memory") // 在sfence指令前的写操作必须在sfence指令后的写操作前完成 +#define io_lfence() __asm__ __volatile__("lfence\n\t" :: \ + : "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。 + +#define rdtsc() ({ \ + uint64_t tmp1 = 0, tmp2 = 0; \ + asm volatile("rdtsc" \ + : "=d"(tmp1), "=a"(tmp2)::"memory"); \ + (tmp1 << 32 | tmp2); \ +}) + +/** + * @brief 读取rsp寄存器的值(存储了页目录的基地址) + * + * @return unsigned* rsp的值的指针 + */ +unsigned long *get_rsp() +{ + uint64_t *tmp; + __asm__ __volatile__( + "movq %%rsp, %0\n\t" + : "=r"(tmp)::"memory"); + return tmp; +} + +/** + * @brief 读取rbp寄存器的值(存储了页目录的基地址) + * + * @return unsigned* rbp的值的指针 + */ +unsigned long *get_rbp() +{ + uint64_t *tmp; + __asm__ __volatile__( + "movq %%rbp, %0\n\t" + : "=r"(tmp)::"memory"); + return tmp; +} + +/** + * @brief 读取ds寄存器的值(存储了页目录的基地址) + * + * @return unsigned* ds的值的指针 + */ +unsigned long *get_ds() +{ + uint64_t *tmp; + __asm__ __volatile__( + "movq %%ds, %0\n\t" + : "=r"(tmp)::"memory"); + return tmp; +} + +/** + * @brief 读取rax寄存器的值(存储了页目录的基地址) + * + * @return unsigned* rax的值的指针 + */ +unsigned long *get_rax() +{ + uint64_t *tmp; + __asm__ __volatile__( + "movq %%rax, %0\n\t" + : "=r"(tmp)::"memory"); + return tmp; +} +/** + * @brief 读取rbx寄存器的值(存储了页目录的基地址) + * + * @return unsigned* rbx的值的指针 + */ +unsigned long *get_rbx() +{ + uint64_t *tmp; + __asm__ __volatile__( + "movq %%rbx, %0\n\t" + : "=r"(tmp)::"memory"); + return tmp; +} + +// ========= MSR寄存器组操作 ============= +/** + * @brief 向msr寄存器组的address处的寄存器写入值value + * + * @param address 地址 + * @param value 要写入的值 + */ +void wrmsr(uint64_t address, uint64_t value) +{ + __asm__ __volatile__("wrmsr \n\t" ::"d"(value >> 32), "a"(value & 0xffffffff), "c"(address) + : "memory"); +} + +/** + * @brief 从msr寄存器组的address地址处读取值 + * rdmsr返回高32bits在edx,低32bits在eax + * @param address 地址 + * @return uint64_t address处的寄存器的值 + */ +uint64_t rdmsr(uint64_t address) +{ + unsigned int tmp0, tmp1; + __asm__ __volatile__("rdmsr \n\t" + : "=d"(tmp0), "=a"(tmp1) + : "c"(address) + : "memory"); + return ((uint64_t)tmp0 << 32) | tmp1; +} + +uint64_t get_rflags() +{ + unsigned long tmp = 0; + __asm__ __volatile__("pushfq \n\t" + "movq (%%rsp), %0 \n\t" + "popfq \n\t" + : "=r"(tmp)::"memory"); + return tmp; +} \ No newline at end of file diff --git a/kernel/common/err.h b/kernel/common/err.h index cd3c33c3..825d776e 100644 --- a/kernel/common/err.h +++ b/kernel/common/err.h @@ -28,3 +28,19 @@ static inline long __must_check IS_ERR_OR_NULL(const void* ptr) { return !ptr || IS_ERR_VALUE((uint64_t)ptr); } + +/** + * @brief 将错误码转换为指针 + * + * @param error 错误码 + * @return void* 转换后的指针 + */ +static inline void* __must_check ERR_PTR(long error) +{ + return (void*)(error); +} + +static inline long __must_check PTR_ERR(void * ptr) +{ + return (long)ptr; +} \ No newline at end of file diff --git a/kernel/common/glib.h b/kernel/common/glib.h index 3cd8cc0f..24140b7e 100644 --- a/kernel/common/glib.h +++ b/kernel/common/glib.h @@ -11,29 +11,13 @@ #include #include #include +#include -#define sti() __asm__ __volatile__("sti\n\t" :: \ - : "memory") //开启外部中断 -#define cli() __asm__ __volatile__("cli\n\t" :: \ - : "memory") //关闭外部中断 -#define nop() __asm__ __volatile__("nop\n\t") -#define hlt() __asm__ __volatile__("hlt\n\t") -#define pause() asm volatile("pause\n\t"); // 处理器等待一段时间 - -//内存屏障 -#define io_mfence() __asm__ __volatile__("mfence\n\t" :: \ - : "memory") // 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成。 -#define io_sfence() __asm__ __volatile__("sfence\n\t" :: \ - : "memory") // 在sfence指令前的写操作必须在sfence指令后的写操作前完成 -#define io_lfence() __asm__ __volatile__("lfence\n\t" :: \ - : "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。 - -#define rdtsc() ({ \ - uint64_t tmp1 = 0, tmp2 = 0; \ - asm volatile("rdtsc" \ - : "=d"(tmp1), "=a"(tmp2)::"memory"); \ - (tmp1 << 32 | tmp2); \ -}) +#if ARCH(I386) || ARCH(X86_64) +#include +#else +#error Arch not supported. +#endif /** * @brief 根据结构体变量内某个成员变量member的基地址,计算出该结构体变量的基地址 @@ -83,121 +67,7 @@ static __always_inline ul ALIGN(const ul addr, const ul _align) return (ul)((addr + _align - 1) & (~(_align - 1))); } -//链表数据结构 -struct List -{ - struct List *prev, *next; -}; -//初始化循环链表 -static inline void list_init(struct List *list) -{ - list->next = list; - io_mfence(); - list->prev = list; -} - -/** - * @brief - - * @param entry 给定的节点 - * @param node 待插入的节点 - **/ -static inline void list_add(struct List *entry, struct List *node) -{ - - node->next = entry->next; - barrier(); - node->prev = entry; - barrier(); - node->next->prev = node; - barrier(); - entry->next = node; -} - -/** - * @brief 将node添加到给定的list的结尾(也就是当前节点的前面) - * @param entry 列表的入口 - * @param node 待添加的节点 - */ -static inline void list_append(struct List *entry, struct List *node) -{ - - struct List *tail = entry->prev; - list_add(tail, node); -} - -/** - * @brief 从列表中删除节点 - * @param entry 待删除的节点 - */ -static inline void list_del(struct List *entry) -{ - - entry->next->prev = entry->prev; - entry->prev->next = entry->next; -} - -/** - * @brief 将新的链表结点替换掉旧的链表结点,并使得旧的结点的前后指针均为NULL - * - * @param old 要被替换的结点 - * @param new 新的要换上去的结点 - */ -static inline void list_replace(struct List* old, struct List * new) -{ - if(old->prev!=NULL) - old->prev->next=new; - new->prev = old->prev; - if(old->next!=NULL) - old->next->prev = new; - new->next = old->next; - - old->prev = NULL; - old->next = NULL; -} - - -static inline bool list_empty(struct List *entry) -{ - /** - * @brief 判断循环链表是否为空 - * @param entry 入口 - */ - - if (entry == entry->next && entry->prev == entry) - return true; - else - return false; -} - -/** - * @brief 获取链表的上一个元素 - * - * @param entry - * @return 链表的上一个元素 - */ -static inline struct List *list_prev(struct List *entry) -{ - if (entry->prev != NULL) - return entry->prev; - else - return NULL; -} - -/** - * @brief 获取链表的下一个元素 - * - * @param entry - * @return 链表的下一个元素 - */ -static inline struct List *list_next(struct List *entry) -{ - if (entry->next != NULL) - return entry->next; - else - return NULL; -} void *memset(void *dst, unsigned char C, ul size) { @@ -323,113 +193,6 @@ void io_out32(unsigned short port, unsigned int value) __asm__ __volatile__("cld;rep;outsw;mfence;" ::"d"(port), "S"(buffer), "c"(nr) \ : "memory") -/** - * @brief 读取rsp寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rsp的值的指针 - */ -unsigned long *get_rsp() -{ - ul *tmp; - __asm__ __volatile__( - "movq %%rsp, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -/** - * @brief 读取rbp寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rbp的值的指针 - */ -unsigned long *get_rbp() -{ - ul *tmp; - __asm__ __volatile__( - "movq %%rbp, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -/** - * @brief 读取ds寄存器的值(存储了页目录的基地址) - * - * @return unsigned* ds的值的指针 - */ -unsigned long *get_ds() -{ - ul *tmp; - __asm__ __volatile__( - "movq %%ds, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -/** - * @brief 读取rax寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rax的值的指针 - */ -unsigned long *get_rax() -{ - ul *tmp; - __asm__ __volatile__( - "movq %%rax, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} -/** - * @brief 读取rbx寄存器的值(存储了页目录的基地址) - * - * @return unsigned* rbx的值的指针 - */ -unsigned long *get_rbx() -{ - ul *tmp; - __asm__ __volatile__( - "movq %%rbx, %0\n\t" - : "=r"(tmp)::"memory"); - return tmp; -} - -// ========= MSR寄存器组操作 ============= -/** - * @brief 向msr寄存器组的address处的寄存器写入值value - * - * @param address 地址 - * @param value 要写入的值 - */ -void wrmsr(ul address, ul value) -{ - __asm__ __volatile__("wrmsr \n\t" ::"d"(value >> 32), "a"(value & 0xffffffff), "c"(address) - : "memory"); -} - -/** - * @brief 从msr寄存器组的address地址处读取值 - * rdmsr返回高32bits在edx,低32bits在eax - * @param address 地址 - * @return ul address处的寄存器的值 - */ -ul rdmsr(ul address) -{ - unsigned int tmp0, tmp1; - __asm__ __volatile__("rdmsr \n\t" - : "=d"(tmp0), "=a"(tmp1) - : "c"(address) - : "memory"); - return ((ul)tmp0 << 32) | tmp1; -} - -uint64_t get_rflags() -{ - unsigned long tmp = 0; - __asm__ __volatile__("pushfq \n\t" - "movq (%%rsp), %0 \n\t" - "popfq \n\t" - : "=r"(tmp)::"memory"); - return tmp; -} /** * @brief 验证地址空间是否为用户地址空间 diff --git a/kernel/common/kthread.h b/kernel/common/kthread.h new file mode 100644 index 00000000..fd0c365a --- /dev/null +++ b/kernel/common/kthread.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include + +struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data), + void *data, + int node, + const char name_fmt[], ...); +/** + * @brief 在当前结点上创建一个内核线程 + * + * @param thread_fn 该内核线程要执行的函数 + * @param data 传递给 thread_fn 的参数数据 + * @param name_fmt printf-style format string for the thread name + * @param arg name_fmt的参数 + * + * 请注意,该宏会创建一个内核线程,并将其设置为停止状态 + */ +#define kthread_create(thread_fn, data, name_fmt, arg...) \ + kthread_create_on_node(thread_fn, data, NUMA_NO_NODE, name_fmt, ##arg) + +/** + * @brief 创建内核线程,并将其唤醒 + * + * @param thread_fn 该内核线程要执行的函数 + * @param data 传递给 thread_fn 的参数数据 + * @param name_fmt printf-style format string for the thread name + * @param arg name_fmt的参数 + */ +#define kthread_run(thread_fn, data, name_fmt, ...) \ + ({ \ + struct process_control_block *__kt = kthread_create(thread_fn, data, name_fmt, ##__VA_ARGS__); \ + if (!IS_ERR(__kt)) \ + process_wakeup(__kt); \ + __kt; \ + }) + +/** + * @brief 向kthread发送停止信号,请求其结束 + * + * @param pcb 内核线程的pcb + * @return int 错误码 + */ +int kthread_stop(struct process_control_block * pcb); + +/** + * @brief 内核线程调用该函数,检查自身的标志位,判断自己是否应该执行完任务后退出 + * + * @return true 内核线程应该退出 + * @return false 无需退出 + */ +bool kthread_should_stop(void); + +/** + * @brief 让当前内核线程退出,并返回result参数给kthread_stop()函数 + * + * @param result 返回值 + */ +void kthread_exit(long result); + +/** + * @brief 初始化kthread机制(只应被process_init调用) + * + * @return int 错误码 + */ +int kthread_mechanism_init(); + +/** + * @brief 设置pcb中的worker_private字段(只应被设置一次) + * + * @param pcb pcb + * @return bool 成功或失败 + */ +bool kthread_set_worker_private(struct process_control_block *pcb); \ No newline at end of file diff --git a/kernel/common/list.h b/kernel/common/list.h new file mode 100644 index 00000000..170116ad --- /dev/null +++ b/kernel/common/list.h @@ -0,0 +1,131 @@ +#pragma once +#include + +#if ARCH(I386) || ARCH(X86_64) +#include +#else +#error Arch not supported. +#endif + +//链表数据结构 +struct List +{ + struct List *prev, *next; +}; + +//初始化循环链表 +static inline void list_init(struct List *list) +{ + list->next = list; + io_mfence(); + list->prev = list; +} + +/** + * @brief + + * @param entry 给定的节点 + * @param node 待插入的节点 + **/ +static inline void list_add(struct List *entry, struct List *node) +{ + + node->next = entry->next; + barrier(); + node->prev = entry; + barrier(); + node->next->prev = node; + barrier(); + entry->next = node; +} + +/** + * @brief 将node添加到给定的list的结尾(也就是当前节点的前面) + * @param entry 列表的入口 + * @param node 待添加的节点 + */ +static inline void list_append(struct List *entry, struct List *node) +{ + + struct List *tail = entry->prev; + list_add(tail, node); +} + +/** + * @brief 从列表中删除节点 + * @param entry 待删除的节点 + */ +static inline void list_del(struct List *entry) +{ + + entry->next->prev = entry->prev; + entry->prev->next = entry->next; +} + +/** + * @brief + * + */ +#define list_del_init(entry) \ + list_del(entry); \ + list_init(entry); + +/** + * @brief 将新的链表结点替换掉旧的链表结点,并使得旧的结点的前后指针均为NULL + * + * @param old 要被替换的结点 + * @param new 新的要换上去的结点 + */ +static inline void list_replace(struct List *old, struct List *new) +{ + if (old->prev != NULL) + old->prev->next = new; + new->prev = old->prev; + if (old->next != NULL) + old->next->prev = new; + new->next = old->next; + + old->prev = NULL; + old->next = NULL; +} + +static inline bool list_empty(struct List *entry) +{ + /** + * @brief 判断循环链表是否为空 + * @param entry 入口 + */ + + if (entry == entry->next && entry->prev == entry) + return true; + else + return false; +} + +/** + * @brief 获取链表的上一个元素 + * + * @param entry + * @return 链表的上一个元素 + */ +static inline struct List *list_prev(struct List *entry) +{ + if (entry->prev != NULL) + return entry->prev; + else + return NULL; +} + +/** + * @brief 获取链表的下一个元素 + * + * @param entry + * @return 链表的下一个元素 + */ +static inline struct List *list_next(struct List *entry) +{ + if (entry->next != NULL) + return entry->next; + else + return NULL; +} \ No newline at end of file diff --git a/kernel/common/numa.h b/kernel/common/numa.h new file mode 100644 index 00000000..0394db59 --- /dev/null +++ b/kernel/common/numa.h @@ -0,0 +1,3 @@ +#pragma once + +#define NUMA_NO_NODE (-1) \ No newline at end of file diff --git a/kernel/debug/bug.h b/kernel/debug/bug.h index 7f2b851a..7b566c80 100644 --- a/kernel/debug/bug.h +++ b/kernel/debug/bug.h @@ -7,7 +7,7 @@ /** * @brief 当condition为true时,认为产生了bug - * + * */ #define BUG_ON(condition) ({ \ int __ret_bug_on = !!(condition); \ @@ -27,6 +27,22 @@ unlikely(__ret_warn_on); \ }) +/** + * @brief 当condition不为0时输出警告信息,且只会输出一次警告信息 + * + */ +#define WARN_ON_ONCE(condition) ({ \ + static int __warned; \ + int __ret_warn_once = !!(condition); \ + \ + if (unlikely(__ret_warn_once && !__warned)) \ + { \ + __warned = true; \ + WARN_ON(1); \ + } \ + unlikely(__ret_warn_once); \ +}) + #define FAIL_ON_TO(condition, to) ({ \ int __ret_warn_on = !!(condition); \ if (unlikely(__ret_warn_on)) \ diff --git a/kernel/driver/usb/usb.c b/kernel/driver/usb/usb.c index 63bad85c..fb8673ae 100644 --- a/kernel/driver/usb/usb.c +++ b/kernel/driver/usb/usb.c @@ -18,7 +18,7 @@ static int usb_pdevs_count = 0; * @brief 初始化usb驱动程序 * */ -int usb_init() +int usb_init(void* unused) { kinfo("Initializing usb driver..."); spin_init(&xhci_controller_init_lock); diff --git a/kernel/ktest/ktest.c b/kernel/ktest/ktest.c index 9f480314..9f6b8168 100644 --- a/kernel/ktest/ktest.c +++ b/kernel/ktest/ktest.c @@ -8,7 +8,7 @@ * @param arg 传递给测试函数的参数 * @return pid_t 测试内核线程的pid */ -pid_t ktest_start(uint64_t (*func)(uint64_t arg), uint64_t arg) +pid_t ktest_start(int (*func)(void* arg), void* arg) { return kernel_thread(func, arg, 0); } \ No newline at end of file diff --git a/kernel/ktest/ktest.h b/kernel/ktest/ktest.h index 5a3e6997..b1a69936 100644 --- a/kernel/ktest/ktest.h +++ b/kernel/ktest/ktest.h @@ -1,9 +1,9 @@ #pragma once #include -uint64_t ktest_test_bitree(uint64_t arg); -uint64_t ktest_test_kfifo(uint64_t arg); -uint64_t ktest_test_mutex(uint64_t arg); +int ktest_test_bitree(void* arg); +int ktest_test_kfifo(void* arg); +int ktest_test_mutex(void* arg); /** * @brief 开启一个新的内核线程以进行测试 @@ -12,4 +12,4 @@ uint64_t ktest_test_mutex(uint64_t arg); * @param arg 传递给测试函数的参数 * @return pid_t 测试内核线程的pid */ -pid_t ktest_start(uint64_t (*func)(uint64_t arg), uint64_t arg); \ No newline at end of file +pid_t ktest_start(int (*func)(void* arg), void* arg); \ No newline at end of file diff --git a/kernel/ktest/test-bitree.c b/kernel/ktest/test-bitree.c index ef92bc09..c2e63d7c 100644 --- a/kernel/ktest/test-bitree.c +++ b/kernel/ktest/test-bitree.c @@ -119,7 +119,7 @@ static ktest_case_table kt_bitree_func_table[] = { ktest_bitree_case1, }; -uint64_t ktest_test_bitree(uint64_t arg) +int ktest_test_bitree(void* arg) { kTEST("Testing bitree..."); for (int i = 0; i < sizeof(kt_bitree_func_table) / sizeof(ktest_case_table); ++i) diff --git a/kernel/ktest/test-kfifo.c b/kernel/ktest/test-kfifo.c index 02834c60..e30390ee 100644 --- a/kernel/ktest/test-kfifo.c +++ b/kernel/ktest/test-kfifo.c @@ -152,7 +152,7 @@ static ktest_case_table kt_kfifo_func_table[] = { ktest_kfifo_case0_1, }; -uint64_t ktest_test_kfifo(uint64_t arg) +int ktest_test_kfifo(void* arg) { kTEST("Testing kfifo..."); for (int i = 0; i < sizeof(kt_kfifo_func_table) / sizeof(ktest_case_table); ++i) diff --git a/kernel/ktest/test-mutex.c b/kernel/ktest/test-mutex.c index 1a17f783..c6fa7e43 100644 --- a/kernel/ktest/test-mutex.c +++ b/kernel/ktest/test-mutex.c @@ -31,7 +31,7 @@ static long ktest_mutex_case0(uint64_t arg0, uint64_t arg1) * @param arg * @return long */ -static unsigned long ktest_mutex_case1_pid1(uint64_t arg) +static int ktest_mutex_case1_pid1(void* arg) { kTEST("ktest_mutex_case1_subproc start."); assert(mutex_is_locked(&mtx) == 1); @@ -78,7 +78,7 @@ static ktest_case_table kt_mutex_func_table[] = { ktest_mutex_case0, ktest_mutex_case1, }; -uint64_t ktest_test_mutex(uint64_t arg) +int ktest_test_mutex(void* arg) { kTEST("Testing mutex..."); mutex_init(&mtx); diff --git a/kernel/lib/sys/Makefile b/kernel/lib/sys/Makefile index 4213d9a7..2891405e 100644 --- a/kernel/lib/sys/Makefile +++ b/kernel/lib/sys/Makefile @@ -6,12 +6,9 @@ kernel_lib_sys_objs:= $(shell find ./*.c) ECHO: @echo "$@" -$(kernel_lib_sys_objs): ECHO - $(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)" - $(kernel_lib_sys_objs): ECHO gcc $(CFLAGS) -c $@ -o $@.o -all: $(kernel_lib_sys_objs) $(kernel_lib_sys_objs) +all: $(kernel_lib_sys_objs) @echo $(kernel_lib_sys_objs) diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 87825538..ca459e0b 100644 --- a/kernel/mm/mm.c +++ b/kernel/mm/mm.c @@ -248,6 +248,8 @@ void mm_init() initial_mm.stack_start = _stack_start; initial_mm.vmas = NULL; + + mmio_init(); } @@ -489,8 +491,30 @@ void page_table_init() } } - flush_tlb(); + + barrier(); + // ========= 在IDLE进程的顶层页表中添加对内核地址空间的映射 ===================== + // 由于IDLE进程的顶层页表的高地址部分会被后续进程所复制,为了使所有进程能够共享相同的内核空间, + // 因此需要先在IDLE进程的顶层页表内映射二级页表 + + uint64_t *idle_pml4t_vaddr = (uint64_t *)phys_2_virt((uint64_t)get_CR3() & (~0xfffUL)); + + for (int i = 256; i < 512; ++i) + { + uint64_t *tmp = idle_pml4t_vaddr + i; + barrier(); + if (*tmp == 0) + { + void *pdpt = kmalloc(PAGE_4K_SIZE, 0); + barrier(); + memset(pdpt, 0, PAGE_4K_SIZE); + barrier(); + set_pml4t(tmp, mk_pml4t(virt_2_phys(pdpt), PAGE_KERNEL_PGT)); + } + } + barrier(); + flush_tlb(); kinfo("Page table Initialized. Affects:%d", js); } diff --git a/kernel/process/Makefile b/kernel/process/Makefile index ba4385e3..87172b3c 100644 --- a/kernel/process/Makefile +++ b/kernel/process/Makefile @@ -1,17 +1,21 @@ -all: procs.o process.o - CFLAGS += -I . +kernel_process_objs:= $(shell find ./*.c) + +ECHO: + @echo "$@" + + +$(kernel_process_objs): ECHO + gcc $(CFLAGS) -c $@ -o $@.o procs.o: proc.S gcc -E proc.S > _proc.s as $(ASFLAGS) -o procs.o _proc.s -process.o: process.c - gcc $(CFLAGS) -c process.c -o process.o - +all: procs.o $(kernel_process_objs) clean: diff --git a/kernel/process/kthread.c b/kernel/process/kthread.c new file mode 100644 index 00000000..092a48c2 --- /dev/null +++ b/kernel/process/kthread.c @@ -0,0 +1,305 @@ +#include +#include +#include +#include +#include + +static spinlock_t __kthread_create_lock; // kthread创建过程的锁 +static struct List kthread_create_list; // kthread创建任务的链表 +struct process_control_block *kthreadd_pcb = NULL; // kthreadd守护线程的pcb + +// 枚举各个标志位是在第几位 +enum KTHREAD_BITS +{ + KTHREAD_IS_PER_CPU = 0, + KTHREAD_SHOULD_STOP, + KTHREAD_SHOULD_PARK, +}; + +/** + * @brief kthread的创建信息(仅在创建过程中存在) + * + */ +struct kthread_create_info_t +{ + // 传递给kthread的信息 + int (*thread_fn)(void *data); + void *data; + int node; + + // kthreadd守护进程传递给kthread_create的结果 + struct process_control_block *result; + + struct List list; +}; + +/** + * @brief kthread信息 + * 该结构体将会绑定到pcb的worker_private中 + */ +struct kthread_info_t +{ + uint64_t flags; + uint32_t cpu; + int result; + int (*thread_fn)(void *); + void *data; + // todo: 将这里改为completion机制 + bool exited; // 是否已退出 + char *full_name; // 内核线程的名称 +}; + +/** + * @brief 获取pcb中的kthread结构体 + * + * @param pcb pcb + * @return struct kthread* kthread信息结构体 + */ +static inline struct kthread_info_t *to_kthread(struct process_control_block *pcb) +{ + WARN_ON(!(pcb->flags & PF_KTHREAD)); + return pcb->worker_private; +} + +static struct process_control_block *__kthread_create_on_node(int (*thread_fn)(void *data), void *data, + int node, + const char name_fmt[], va_list args) +{ + struct process_control_block *pcb = NULL; + struct kthread_create_info_t *create = kzalloc(sizeof(struct kthread_create_info_t), 0); + + if (create == NULL) + return ERR_PTR(-ENOMEM); + + create->thread_fn = thread_fn; + create->data = data; + create->node = node; + create->result = NULL; + list_init(&create->list); + + spin_lock(&__kthread_create_lock); + list_append(&kthread_create_list, &create->list); + spin_unlock(&__kthread_create_lock); + kdebug("to wakeup kthread daemon..., current preempt=%d, rflags=%#018lx", current_pcb->preempt_count, get_rflags()); + while (kthreadd_pcb == NULL) // 若kthreadd未初始化,则等待kthreadd启动 + ; + // 唤醒kthreadd守护进程 + process_wakeup_immediately(kthreadd_pcb); + + // 等待创建完成 + // todo: 使用completion机制以降低忙等时间 + while (create->result == NULL) + pause(); + // 获取结果 + pcb = create->result; + if (!IS_ERR(create->result)) + { + // todo: 为内核线程设置名字 + } + + kfree(create); + return pcb; +} + +/** + * @brief 让当前内核线程退出,并返回result参数给kthread_stop()函数 + * + * @param result 返回值 + */ +void kthread_exit(long result) +{ + struct kthread_info_t *kt = to_kthread(current_pcb); + kt->result = result; + kt->exited = true; + process_do_exit(0); +} + +/** + * @brief 在当前结点上创建一个内核线程 + * + * @param thread_fn 该内核线程要执行的函数 + * @param data 传递给 thread_fn 的参数数据 + * @param node 线程的任务和线程结构都分配在这个节点上 + * @param name_fmt printf-style format string for the thread name + * @param arg name_fmt的参数 + * @return 返回一个pcb或者是ERR_PTR(-ENOMEM) + * + * 请注意,该宏会创建一个内核线程,并将其设置为停止状态。您可以使用wake_up_process来启动这个线程。 + * 新的线程的调度策略为SCHED_NORMAL,并且能在所有的cpu上运行 + * + * 当内核线程被唤醒时,会运行thread_fn函数,并将data作为参数传入。 + * 内核线程可以直接返回,也可以在kthread_should_stop为真时返回。 + */ +struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data), void *data, + int node, + const char name_fmt[], ...) +{ + struct process_control_block *pcb; + va_list args; + va_start(args, name_fmt); + pcb = __kthread_create_on_node(thread_fn, data, node, name_fmt, args); + va_end(args); + return pcb; +} +/** + * @brief 内核线程的包裹程序 + * 当内核线程被运行后,从kernel_thread_func跳转到这里。 + * @param _create 内核线程的创建信息 + * @return int 内核线程的退出返回值 + */ +static int kthread(void *_create) +{ + struct kthread_create_info_t *create = _create; + // 将这几个信息从kthread_create_info中拷贝过来。以免在kthread_create_info被free后,数据丢失从而导致错误。 + int (*thread_fn)(void *data) = create->thread_fn; + void *data = create->data; + + int retval = 0; + + struct kthread_info_t *self = to_kthread(current_pcb); + + self->thread_fn = thread_fn; + self->data = data; + + // todo: 增加调度参数设定 + // todo: 当前内核线程继承了kthreadd的优先级以及调度策略,需要在这里进行更新 + + // 设置当前进程为不可被打断 + current_pcb->state = PROC_UNINTERRUPTIBLE; + + // 将当前pcb返回给创建者 + create->result = current_pcb; + + // 发起调度,使得当前内核线程休眠。直到创建者通过process_wakeup将当前内核线程唤醒 + sched(); + + retval = -EINTR; + // 如果发起者没有调用kthread_stop(),则该kthread的功能函数开始执行 + if (!(self->flags & (1 << KTHREAD_SHOULD_STOP))) + { + retval = thread_fn(data); + } + kthread_exit(retval); +} + +static void __create_kthread(struct kthread_create_info_t *create) +{ + pid_t pid = kernel_thread(kthread, create, CLONE_FS | CLONE_SIGNAL); + if (IS_ERR((void *)pid)) + { + // todo: 使用complete机制完善这里 + + create->result = (struct process_control_block *)pid; + } +} + +/** + * @brief kthread守护线程 + * + * @param unused + * @return int 不应当退出 + */ +int kthreadd(void *unused) +{ + kinfo("kthread daemon started!"); + struct process_control_block *pcb = current_pcb; + kthreadd_pcb = current_pcb; + current_pcb->flags |= PF_NOFREEZE; + + for (;;) + { + current_pcb->state = PROC_INTERRUPTIBLE; + // 所有的创建任务都被处理完了 + if (list_empty(&kthread_create_list)) + sched(); + + spin_lock(&__kthread_create_lock); + // 循环取出链表中的任务 + while (!list_empty(&kthread_create_list)) + { + + // 从链表中取出第一个要创建的内核线程任务 + struct kthread_create_info_t *create = container_of(kthread_create_list.next, struct kthread_create_info_t, list); + list_del_init(&create->list); + spin_unlock(&__kthread_create_lock); + + __create_kthread(create); + + spin_lock(&__kthread_create_lock); + } + spin_unlock(&__kthread_create_lock); + } +} + +/** + * @brief 内核线程调用该函数,检查自身的标志位,判断自己是否应该执行完任务后退出 + * + * @return true 内核线程应该退出 + * @return false 无需退出 + */ +bool kthread_should_stop(void) +{ + struct kthread_info_t *self = to_kthread(current_pcb); + if (self->flags & (1 << KTHREAD_SHOULD_STOP)) + return true; + + return false; +} + +/** + * @brief 向kthread发送停止信号,请求其结束 + * + * @param pcb 内核线程的pcb + * @return int 错误码 + */ +int kthread_stop(struct process_control_block *pcb) +{ + int retval; + struct kthread_info_t *target = to_kthread(pcb); + target->flags |= (1 << KTHREAD_SHOULD_STOP); + process_wakeup(pcb); + // 等待指定的内核线程退出 + // todo: 使用completion机制改进这里 + while (target->exited == false) + usleep(5000); + retval = target->result; + + // 释放内核线程的页表 + process_exit_mm(pcb); + process_release_pcb(pcb); + return retval; +} + +/** + * @brief 设置pcb中的worker_private字段(只应被设置一次) + * + * @param pcb pcb + * @return bool 成功或失败 + */ +bool kthread_set_worker_private(struct process_control_block *pcb) +{ + if (WARN_ON_ONCE(to_kthread(pcb))) + return false; + + struct kthread_info_t *kt = kzalloc(sizeof(struct kthread_info_t), 0); + if (kt == NULL) + return false; + pcb->worker_private = kt; + return true; +} + +/** + * @brief 初始化kthread机制(只应被process_init调用) + * + * @return int 错误码 + */ +int kthread_mechanism_init() +{ + kinfo("Initializing kthread mechanism..."); + spin_init(&__kthread_create_lock); + list_init(&kthread_create_list); + // 创建kthreadd守护进程 + kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_SIGNAL); + + return 0; +} \ No newline at end of file diff --git a/kernel/process/proc-types.h b/kernel/process/proc-types.h index 1b186b6a..1d9538cb 100644 --- a/kernel/process/proc-types.h +++ b/kernel/process/proc-types.h @@ -58,6 +58,7 @@ struct thread_struct #define PF_NEED_SCHED (1UL << 1) // 进程需要被调度 #define PF_VFORK (1UL << 2) // 标志进程是否由于vfork而存在资源共享 #define PF_KFORK (1UL << 3) // 标志在内核态下调用fork(临时标记,do_fork()结束后会将其复位) +#define PF_NOFREEZE (1UL << 4) // 当前进程不能被冻结 /** * @brief 进程控制块 @@ -101,6 +102,9 @@ struct process_control_block int32_t exit_code; // 进程退出时的返回码 wait_queue_node_t wait_child_proc_exit; // 子进程退出等待队列 + + /* PF_kTHREAD | PF_IO_WORKER 的进程,worker_private不为NULL*/ + void *worker_private; }; // 将进程的pcb和内核栈融合到一起,8字节对齐 diff --git a/kernel/process/process.c b/kernel/process/process.c index d9eecae8..4043f609 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -278,7 +280,7 @@ static int process_load_elf_file(struct pt_regs *regs, char *path) uint64_t pa = alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys; struct vm_area_struct *vma = NULL; int ret = mm_create_vma(current_pcb->mm, virt_base, PAGE_2M_SIZE, VM_USER | VM_ACCESS_FLAGS, NULL, &vma); - + // 防止内存泄露 if (ret == -EEXIST) free_pages(Phy_to_2M_Page(pa), 1); @@ -578,7 +580,7 @@ ul process_do_exit(ul code) * @return int */ -int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigned long flags) +pid_t kernel_thread(int (*fn)(void*), void* arg, unsigned long flags) { struct pt_regs regs; barrier(); @@ -617,50 +619,9 @@ int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigne void process_init() { kinfo("Initializing process..."); - initial_mm.pgd = (pml4t_t *)get_CR3(); - - initial_mm.code_addr_start = memory_management_struct.kernel_code_start; - initial_mm.code_addr_end = memory_management_struct.kernel_code_end; - - initial_mm.data_addr_start = (ul)&_data; - initial_mm.data_addr_end = memory_management_struct.kernel_data_end; - - initial_mm.rodata_addr_start = (ul)&_rodata; - initial_mm.rodata_addr_end = (ul)&_erodata; - initial_mm.bss_start = (uint64_t)&_bss; - initial_mm.bss_end = (uint64_t)&_ebss; - - initial_mm.brk_start = memory_management_struct.start_brk; - initial_mm.brk_end = current_pcb->addr_limit; - - initial_mm.stack_start = _stack_start; - initial_mm.vmas = NULL; initial_tss[proc_current_cpu_id].rsp0 = initial_thread.rbp; - // ========= 在IDLE进程的顶层页表中添加对内核地址空间的映射 ===================== - - // 由于IDLE进程的顶层页表的高地址部分会被后续进程所复制,为了使所有进程能够共享相同的内核空间, - // 因此需要先在IDLE进程的顶层页表内映射二级页表 - - uint64_t *idle_pml4t_vaddr = (uint64_t *)phys_2_virt((uint64_t)get_CR3() & (~0xfffUL)); - - for (int i = 256; i < 512; ++i) - { - uint64_t *tmp = idle_pml4t_vaddr + i; - barrier(); - if (*tmp == 0) - { - void *pdpt = kmalloc(PAGE_4K_SIZE, 0); - barrier(); - memset(pdpt, 0, PAGE_4K_SIZE); - barrier(); - set_pml4t(tmp, mk_pml4t(virt_2_phys(pdpt), PAGE_KERNEL_PGT)); - } - } - barrier(); - - flush_tlb(); /* kdebug("initial_thread.rbp=%#018lx", initial_thread.rbp); kdebug("initial_tss[0].rsp1=%#018lx", initial_tss[0].rsp1); @@ -672,14 +633,19 @@ void process_init() // 初始化进程的循环链表 list_init(&initial_proc_union.pcb.list); + + // 临时设置IDLE进程的的虚拟运行时间为0,防止下面的这些内核线程的虚拟运行时间出错 + current_pcb->virtual_runtime = 0; barrier(); kernel_thread(initial_kernel_thread, 10, CLONE_FS | CLONE_SIGNAL); // 初始化内核线程 barrier(); + kthread_mechanism_init(); // 初始化kthread机制 initial_proc_union.pcb.state = PROC_RUNNING; initial_proc_union.pcb.preempt_count = 0; initial_proc_union.pcb.cpu_id = 0; initial_proc_union.pcb.virtual_runtime = (1UL << 60); + // 将IDLE进程的虚拟运行时间设置为一个很大的数值 current_pcb->virtual_runtime = (1UL << 60); } @@ -712,6 +678,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned io_mfence(); // 将当前进程的pcb复制到新的pcb内 memcpy(tsk, current_pcb, sizeof(struct process_control_block)); + tsk->worker_private = NULL; io_mfence(); // 初始化进程的循环链表结点 @@ -719,9 +686,17 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned io_mfence(); // 判断是否为内核态调用fork - if (current_pcb->flags & PF_KTHREAD && stack_start != 0) + if ((current_pcb->flags & PF_KTHREAD) && stack_start != 0) tsk->flags |= PF_KFORK; + if (tsk->flags & PF_KTHREAD) + { + // 对于内核线程,设置其worker私有信息 + retval = kthread_set_worker_private(tsk); + if (IS_ERR_VALUE(retval)) + goto copy_flags_failed; + tsk->virtual_runtime = 0; + } tsk->priority = 2; tsk->preempt_count = 0; @@ -815,10 +790,17 @@ struct process_control_block *process_get_pcb(long pid) * * @param pcb 进程的pcb */ -void process_wakeup(struct process_control_block *pcb) +int process_wakeup(struct process_control_block *pcb) { + BUG_ON(pcb == NULL); + if (pcb == current_pcb || pcb == NULL) + return -EINVAL; + // 如果pcb正在调度队列中,则不重复加入调度队列 + if (pcb->state == PROC_RUNNING) + return 0; pcb->state = PROC_RUNNING; sched_enqueue(pcb); + return 0; } /** @@ -826,10 +808,13 @@ void process_wakeup(struct process_control_block *pcb) * * @param pcb 进程的pcb */ -void process_wakeup_immediately(struct process_control_block *pcb) +int process_wakeup_immediately(struct process_control_block *pcb) { - pcb->state = PROC_RUNNING; - sched_enqueue(pcb); + if (pcb->state == PROC_RUNNING) + return 0; + int retval = process_wakeup(pcb); + if (retval != 0) + return retval; // 将当前进程标志为需要调度,缩短新进程被wakeup的时间 current_pcb->flags |= PF_NEED_SCHED; } @@ -1159,6 +1144,17 @@ void process_exit_thread(struct process_control_block *pcb) { } +/** + * @brief 释放pcb + * + * @param pcb + * @return int + */ +int process_release_pcb(struct process_control_block *pcb) +{ + kfree(pcb); + return 0; +} /** * @brief 申请可用的文件句柄 * diff --git a/kernel/process/process.h b/kernel/process/process.h index 8cb93582..c2b9a700 100644 --- a/kernel/process/process.h +++ b/kernel/process/process.h @@ -52,7 +52,6 @@ * */ - // 设置初始进程的tss #define INITIAL_TSS \ { \ @@ -73,17 +72,15 @@ .io_map_base_addr = 0 \ } - - #define GET_CURRENT_PCB \ "movq %rsp, %rbx \n\t" \ "andq $-32768, %rbx\n\t" - /** - * @brief 切换进程上下文 - * 先把rbp和rax保存到栈中,然后将rsp和rip保存到prev的thread结构体中 - * 然后调用__switch_to切换栈,配置其他信息,最后恢复下一个进程的rax rbp。 - */ +/** + * @brief 切换进程上下文 + * 先把rbp和rax保存到栈中,然后将rsp和rip保存到prev的thread结构体中 + * 然后调用__switch_to切换栈,配置其他信息,最后恢复下一个进程的rax rbp。 + */ #define switch_proc(prev, next) \ do \ @@ -134,14 +131,14 @@ struct process_control_block *process_get_pcb(long pid); * * @param pcb 进程的pcb */ -void process_wakeup(struct process_control_block *pcb); +int process_wakeup(struct process_control_block *pcb); /** * @brief 将进程加入到调度器的就绪队列中,并标志当前进程需要被调度 * * @param pcb 进程的pcb */ -void process_wakeup_immediately(struct process_control_block *pcb); +int process_wakeup_immediately(struct process_control_block *pcb); /** * @brief 使当前进程去执行新的代码 @@ -185,7 +182,17 @@ void process_exit_notify(); * @return int */ -int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigned long flags); +pid_t kernel_thread(int (*fn)(void*), void* arg, unsigned long flags); + +int process_fd_alloc(struct vfs_file_t *file); + +/** + * @brief 释放pcb + * + * @param pcb + * @return int + */ +int process_release_pcb(struct process_control_block *pcb); /** * @brief 切换页表 @@ -213,4 +220,3 @@ extern struct mm_struct initial_mm; extern struct thread_struct initial_thread; extern union proc_union initial_proc_union; extern struct process_control_block *initial_proc[MAX_CPU_NUM]; -int process_fd_alloc(struct vfs_file_t *file); diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 862494f0..acbd83a8 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -170,7 +170,7 @@ uint64_t sys_read(struct pt_regs *regs) int64_t count = (int64_t)regs->r10; // 校验buf的空间范围 - if(SYSCALL_FROM_USER(regs) && (!verify_area(buf, count))) + if(SYSCALL_FROM_USER(regs) && (!verify_area((uint64_t)buf, count))) return -EPERM; // kdebug("sys read: fd=%d", fd_num); @@ -210,7 +210,7 @@ uint64_t sys_write(struct pt_regs *regs) int64_t count = (int64_t)regs->r10; // 校验buf的空间范围 - if(SYSCALL_FROM_USER(regs) && (!verify_area(buf, count))) + if(SYSCALL_FROM_USER(regs) && (!verify_area((uint64_t)buf, count))) return -EPERM; kdebug("sys write: fd=%d", fd_num);