Browse Source

new: kthread机制

fslongjin 2 years ago
parent
commit
02a6b3a303

+ 134 - 0
kernel/arch/x86_64/asm.h

@@ -0,0 +1,134 @@
+#pragma once
+
+#include <stdint.h>
+
+#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;
+}

+ 16 - 0
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;
+}

+ 6 - 243
kernel/common/glib.h

@@ -11,29 +11,13 @@
 #include <common/stddef.h>
 #include <arch/arch.h>
 #include <common/compiler.h>
+#include <common/list.h>
 
-#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 <arch/x86_64/asm.h>
+#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 验证地址空间是否为用户地址空间

+ 77 - 0
kernel/common/kthread.h

@@ -0,0 +1,77 @@
+#pragma once
+
+#include <common/numa.h>
+#include <process/proc-types.h>
+#include <common/err.h>
+#include <process/process.h>
+
+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);

+ 131 - 0
kernel/common/list.h

@@ -0,0 +1,131 @@
+#pragma once
+#include <common/stddef.h>
+
+#if ARCH(I386) || ARCH(X86_64)
+#include <arch/x86_64/asm.h>
+#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;
+}

+ 3 - 0
kernel/common/numa.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define NUMA_NO_NODE (-1)

+ 17 - 1
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))       \

+ 1 - 1
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);

+ 1 - 1
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);
 }

+ 4 - 4
kernel/ktest/ktest.h

@@ -1,9 +1,9 @@
 #pragma once
 #include <common/sys/types.h>
 
-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);
+pid_t ktest_start(int (*func)(void* arg), void* arg);

+ 1 - 1
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)

+ 1 - 1
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)

+ 2 - 2
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);

+ 1 - 4
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 [email protected]
 
-all: $(kernel_lib_sys_objs) $(kernel_lib_sys_objs)
+all: $(kernel_lib_sys_objs)
 	@echo $(kernel_lib_sys_objs)
 

+ 25 - 1
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);
 }
 

+ 9 - 5
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 [email protected]
 
 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:

+ 305 - 0
kernel/process/kthread.c

@@ -0,0 +1,305 @@
+#include <common/kthread.h>
+#include <common/glib.h>
+#include <common/spinlock.h>
+#include <sched/sched.h>
+#include <debug/bug.h>
+
+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;
+}

+ 4 - 0
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字节对齐

+ 44 - 48
kernel/process/process.c

@@ -6,6 +6,7 @@
 #include <common/string.h>
 #include <common/compiler.h>
 #include <common/elf.h>
+#include <common/kthread.h>
 #include <common/time.h>
 #include <common/sys/wait.h>
 #include <driver/video/video.h>
@@ -21,6 +22,7 @@
 #include <sched/sched.h>
 #include <common/unistd.h>
 #include <debug/traceback/traceback.h>
+#include <debug/bug.h>
 #include <driver/disk/ahci/ahci.h>
 
 #include <ktest/ktest.h>
@@ -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 申请可用的文件句柄
  *

+ 18 - 12
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);

+ 2 - 2
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);