Browse Source

Merge branch 'data_structure'

fslongjin 2 years ago
parent
commit
53fcc0c1e5

+ 3 - 1
.vscode/settings.json

@@ -110,7 +110,9 @@
         "boot_info.h": "c",
         "pci.h": "c",
         "time.h": "c",
-        "ia64_msi.h": "c"
+        "ia64_msi.h": "c",
+        "errno.h": "c",
+        "bug.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 2 - 2
kernel/Makefile

@@ -18,7 +18,7 @@ LD_LIST := head.o
 OBJ_LIST := head.o
 
 
-kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall
+kernel_subdirs := common driver process debug filesystem time arch exception mm smp sched syscall ktest
 	
 
 
@@ -47,7 +47,7 @@ all: kernel
 	
 # 重新链接
 	echo "Re-Linking kernel..."
-	ld -b elf64-x86-64 -z muldefs -o kernel head.o main.o $(shell find . -name "*.o") -T link.lds
+	ld -b elf64-x86-64 -z muldefs -o kernel head.o main.o $(shell find . -name "*.o") ./debug/kallsyms.o -T link.lds
 	echo "Generating kernel ELF file..."
 # 生成内核文件
 	objcopy -I elf64-x86-64 -O elf64-x86-64 -R ".comment" -R ".eh_frame" kernel ../bin/kernel/kernel.elf

+ 5 - 2
kernel/common/Makefile

@@ -3,7 +3,7 @@ CFLAGS += -I .
 
 kernel_common_subdirs:=libELF math
 
-all: glib.o printk.o cpu.o
+all: glib.o printk.o cpu.o bitree.o
 	@list='$(kernel_common_subdirs)'; for subdir in $$list; do \
     		echo "make all in $$subdir";\
     		cd $$subdir;\
@@ -18,4 +18,7 @@ printk.o: printk.c
 	gcc $(CFLAGS) -c printk.c -o printk.o
 
 cpu.o: cpu.c
-	gcc $(CFLAGS) -c cpu.c -o cpu.o
+	gcc $(CFLAGS) -c cpu.c -o cpu.o
+
+bitree.o: bitree.c
+	gcc $(CFLAGS) -c bitree.c -o bitree.o

+ 206 - 0
kernel/common/bitree.c

@@ -0,0 +1,206 @@
+#include "bitree.h"
+#include <mm/slab.h>
+#include <common/errno.h>
+#include <debug/bug.h>
+
+#define smaller(root, a, b) (root->cmp((a)->value, (b)->value) == -1)
+#define equal(root, a, b) (root->cmp((a)->value, (b)->value) == 0)
+#define greater(root, a, b) (root->cmp((a)->value, (b)->value) == 1)
+
+/**
+ * @brief 创建二叉搜索树
+ *
+ * @param node 根节点
+ * @param cmp 比较函数
+ * @param release 用来释放结点的value的函数
+ * @return struct bt_root_t* 树根结构体
+ */
+struct bt_root_t *bt_create_tree(struct bt_node_t *node, int (*cmp)(void *a, void *b), int (*release)(void *value))
+{
+    if (node == NULL || cmp == NULL)
+        return -EINVAL;
+
+    struct bt_root_t *root = (struct bt_root_t *)kmalloc(sizeof(struct bt_root_t), 0);
+    memset((void *)root, 0, sizeof(struct bt_root_t));
+    root->bt_node = node;
+    root->cmp = cmp;
+    root->release = release;
+    root->size = (node == NULL) ? 0 : 1;
+
+    return root;
+}
+
+/**
+ * @brief 创建结点
+ *
+ * @param left 左子节点
+ * @param right 右子节点
+ * @param value 当前节点的值
+ * @return struct bt_node_t*
+ */
+struct bt_node_t *bt_create_node(struct bt_node_t *left, struct bt_node_t *right, struct bt_node_t *parent, void *value)
+{
+    struct bt_node_t *node = (struct bt_node_t *)kmalloc(sizeof(struct bt_node_t), 0);
+    FAIL_ON_TO(node == NULL, nomem);
+    memset((void *)node, 0, sizeof(struct bt_node_t));
+
+    node->left = left;
+    node->right = right;
+    node->value = value;
+    node->parent = parent;
+
+    return node;
+nomem:;
+    return -ENOMEM;
+}
+/**
+ * @brief 插入结点
+ *
+ * @param root 树根结点
+ * @param value 待插入结点的值
+ * @return int 返回码
+ */
+int bt_insert(struct bt_root_t *root, void *value)
+{
+    if (root == NULL)
+        return -EINVAL;
+
+    struct bt_node_t *this_node = root->bt_node;
+    struct bt_node_t *last_node = NULL;
+    struct bt_node_t *insert_node = bt_create_node(NULL, NULL, NULL, value);
+    FAIL_ON_TO((uint64_t)insert_node == (uint64_t)(-ENOMEM), failed);
+
+    while (this_node != NULL)
+    {
+        last_node = this_node;
+        if (smaller(root, insert_node, this_node))
+            this_node = this_node->left;
+        else
+            this_node = this_node->right;
+    }
+
+    insert_node->parent = last_node;
+    if (unlikely(last_node == NULL))
+        root->bt_node = insert_node;
+    else
+    {
+        if (smaller(root, insert_node, last_node))
+            last_node->left = insert_node;
+        else
+            last_node->right = insert_node;
+    }
+    ++root->size;
+    return 0;
+
+failed:;
+    return -ENOMEM;
+}
+
+/**
+ * @brief 搜索值为value的结点
+ *
+ * @param value 值
+ * @param ret_addr 返回的结点基地址
+ * @return int 错误码
+ */
+int bt_query(struct bt_root_t *root, void *value, uint64_t *ret_addr)
+{
+    struct bt_node_t *this_node = root->bt_node;
+    struct bt_node_t tmp_node = {0};
+    tmp_node.value = value;
+
+    // 如果返回地址为0
+    if (ret_addr == NULL)
+        return -EINVAL;
+
+    while (this_node != NULL && !equal(root, this_node, &tmp_node))
+    {
+        if (smaller(root, &tmp_node, this_node))
+            this_node = this_node->left;
+        else
+            this_node = this_node->right;
+    }
+
+    if (this_node != NULL && equal(root, this_node, &tmp_node))
+    {
+        *ret_addr = (uint64_t)this_node;
+        return 0;
+    }
+    else
+    {
+        // 找不到则返回-1,且addr设为0
+        *ret_addr = NULL;
+        return -1;
+    }
+}
+
+static struct bt_node_t *bt_get_minimum(struct bt_node_t *this_node)
+{
+    while (this_node->left != NULL)
+        this_node = this_node->left;
+    return this_node;
+}
+
+/**
+ * @brief 删除结点
+ *
+ * @param root 树根
+ * @param value 待删除结点的值
+ * @return int 返回码
+ */
+int bt_delete(struct bt_root_t *root, void *value)
+{
+    uint64_t tmp_addr;
+    int retval;
+
+    // 寻找待删除结点
+    retval = bt_query(root, value, &tmp_addr);
+    if (retval != 0 || tmp_addr == NULL)
+        return retval;
+
+    struct bt_node_t *this_node = (struct bt_node_t *)tmp_addr;
+    struct bt_node_t *to_delete = NULL, *to_delete_son = NULL;
+    if (this_node->left == NULL || this_node->right == NULL)
+        to_delete = this_node;
+    else
+    {
+        to_delete = bt_get_minimum(this_node->right);
+        // 释放要被删除的值,并把下一个结点的值替换上来
+        root->release(this_node->value);
+        this_node->value = to_delete->value;
+    }
+
+    if (to_delete->left != NULL)
+        to_delete_son = to_delete->left;
+    else
+        to_delete_son = to_delete->right;
+
+    if (to_delete_son != NULL)
+        to_delete_son->parent = to_delete->parent;
+
+    if (to_delete->parent == NULL)
+        root->bt_node = to_delete_son;
+    else
+    {
+        if (to_delete->parent->left == to_delete)
+            to_delete->parent->left = to_delete_son;
+        else
+            to_delete->parent->right = to_delete_son;
+    }
+
+    --root->size;
+    // 释放最终要删除的结点的对象
+    kfree(to_delete);
+}
+
+/**
+ * @brief 释放整个二叉搜索树
+ *
+ * @param root 树的根节点
+ * @return int 错误码
+ */
+int bt_destroy_tree(struct bt_root_t *root)
+{
+    //    todo: 待kfifo完成后,使用kfifo队列来辅助destroy
+    return -1;
+}

+ 79 - 0
kernel/common/bitree.h

@@ -0,0 +1,79 @@
+#pragma once
+#include <common/glib.h>
+
+struct bt_node_t
+{
+    struct bt_node_t *left;
+    struct bt_node_t *right;
+    struct bt_node_t *parent;
+    void *value; // 数据
+
+} __attribute__((aligned(sizeof(long))));
+
+struct bt_root_t
+{
+    struct bt_node_t *bt_node;
+    int32_t size;                 // 树中的元素个数
+    int (*cmp)(void *a, void *b); // 比较函数   a>b 返回1, a==b返回0, a<b返回-1
+    /**
+     * @brief 释放结点的value的函数
+     * @param value 结点的值
+     */
+    int (*release)(void *value);
+};
+
+/**
+ * @brief 创建二叉搜索树
+ *
+ * @param node 根节点
+ * @param cmp 比较函数
+ * @param release 用来释放结点的value的函数
+ * @return struct bt_root_t* 树根结构体
+ */
+struct bt_root_t *bt_create_tree(struct bt_node_t *node, int (*cmp)(void *a, void *b), int (*release)(void *value));
+
+/**
+ * @brief 创建结点
+ *
+ * @param left 左子节点
+ * @param right 右子节点
+ * @param value 当前节点的值
+ * @return struct bt_node_t*
+ */
+struct bt_node_t *bt_create_node(struct bt_node_t *left, struct bt_node_t *right, struct bt_node_t *parent, void *value);
+
+/**
+ * @brief 插入结点
+ *
+ * @param root 树根结点
+ * @param value 待插入结点的值
+ * @return int 返回码
+ */
+int bt_insert(struct bt_root_t *root, void *value);
+
+/**
+ * @brief 搜索值为value的结点
+ *
+ * @param root 树根结点
+ * @param value 值
+ * @param ret_addr 返回的结点基地址
+ * @return int 错误码
+ */
+int bt_query(struct bt_root_t *root, void *value, uint64_t *ret_addr);
+
+/**
+ * @brief 删除结点
+ *
+ * @param root 树根
+ * @param value 待删除结点的值
+ * @return int 返回码
+ */
+int bt_delete(struct bt_root_t *root, void *value);
+
+/**
+ * @brief 释放整个二叉搜索树
+ *
+ * @param root
+ * @return int
+ */
+int bt_destroy_tree(struct bt_root_t *root);

+ 0 - 26
kernel/common/boot_info.h

@@ -21,29 +21,3 @@
     /// 长度
     extern unsigned int boot_info_size;
 
-    /**
-     * @brief 初始化,定义在具体实现中
-     * @return true            成功
-     * @return false           成功
-     */
-    extern int init(void);
-
-    /**
-     * @brief 获取物理内存信息
-     * @return resource_t      物理内存资源信息
-     */
-    //extern resource_t get_memory(void);
-
-    /**
-     * @brief 获取 clint 信息
-     * @return resource_t       clint 资源信息
-     */
-    //extern resource_t get_clint(void);
-    
-    /**
-     * @brief 获取 plic 信息
-     * @return resource_t       plic 资源信息
-     */
-    //extern resource_t get_plic(void);
-
-

+ 7 - 0
kernel/debug/bug.h

@@ -12,3 +12,10 @@
         kwarn("Assertion failed at %s:%d", __FILE__, __LINE__); \
     unlikely(__ret_warn_on);                                    \
 })
+
+#define FAIL_ON_TO(condition, to) ({   \
+    int __ret_warn_on = !!(condition); \
+    if (unlikely(__ret_warn_on))       \
+        goto to;                       \
+    unlikely(__ret_warn_on);           \
+})

+ 9 - 16
kernel/driver/usb/xhci/xhci.c

@@ -9,7 +9,7 @@
 #include <exception/irq.h>
 #include <driver/interrupt/apic/apic.h>
 
-spinlock_t xhci_controller_init_lock; // xhci控制器初始化锁(在usb_init中被初始化)
+spinlock_t xhci_controller_init_lock = {0}; // xhci控制器初始化锁(在usb_init中被初始化)
 
 static int xhci_ctrl_count = 0; // xhci控制器计数
 
@@ -123,13 +123,6 @@ hardware_intr_controller xhci_hc_intr_controller =
         ptr->cycle = 1;                                                        \
     } while (0)
 
-#define FAIL_ON(value, to)        \
-    do                            \
-    {                             \
-        if (unlikely(value != 0)) \
-            goto to;              \
-    } while (0)
-
 // Common TRB types
 enum
 {
@@ -387,7 +380,7 @@ static int xhci_hc_pair_ports(int id)
 
     uint32_t next_off = xhci_hc[id].ext_caps_off;
     uint32_t offset, cnt;
-    uint16_t protocol_flags;
+    uint16_t protocol_flags = 0;
 
     // 寻找所有的usb2端口
     while (next_off)
@@ -560,12 +553,12 @@ uint64_t xhci_hc_irq_install(uint64_t irq_num, void *arg)
     struct msi_desc_t msi_desc;
     memset(&msi_desc, 0, sizeof(struct msi_desc_t));
 
-    msi_desc.pci_dev = (struct pci_device_structure_header_t*)xhci_hc[cid].pci_dev_hdr;
+    msi_desc.pci_dev = (struct pci_device_structure_header_t *)xhci_hc[cid].pci_dev_hdr;
     msi_desc.assert = info->assert;
     msi_desc.edge_trigger = info->edge_trigger;
     msi_desc.processor = info->processor;
     msi_desc.pci.msi_attribute.is_64 = 1;
-    // todo: QEMU是使用msix的,因此要先在pci中实现msix  
+    // todo: QEMU是使用msix的,因此要先在pci中实现msix
     int retval = pci_enable_msi(&msi_desc);
     kdebug("pci retval = %d", retval);
     kdebug("xhci irq %d installed.", irq_num);
@@ -643,7 +636,7 @@ static int xhci_reset_port(const int id, const int port)
             break;
         else if (val & (1 << 21))
             break;
-        
+
         --timeout;
         usleep(500);
     }
@@ -854,12 +847,12 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
     }
 
     // 关闭legacy支持
-    FAIL_ON(xhci_hc_stop_legacy(cid), failed);
+    FAIL_ON_TO(xhci_hc_stop_legacy(cid), failed);
 
     // 重置xhci控制器
-    FAIL_ON(xhci_hc_reset(cid), failed);
+    FAIL_ON_TO(xhci_hc_reset(cid), failed);
     // 端口配对
-    FAIL_ON(xhci_hc_pair_ports(cid), failed);
+    FAIL_ON_TO(xhci_hc_pair_ports(cid), failed);
 
     // ========== 设置USB host controller =========
     // 获取页面大小
@@ -900,7 +893,7 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
     // 写入设备通知控制寄存器
     xhci_write_op_reg32(cid, XHCI_OPS_DNCTRL, (1 << 1)); // 目前只有N1被支持
 
-    FAIL_ON(xhci_hc_init_intr(cid), failed_free_dyn);
+    FAIL_ON_TO(xhci_hc_init_intr(cid), failed_free_dyn);
     ++xhci_ctrl_count;
     spin_unlock(&xhci_controller_init_lock);
     return;

+ 8 - 0
kernel/ktest/Makefile

@@ -0,0 +1,8 @@
+
+CFLAGS += -I .
+
+
+all: bitree.o
+
+bitree.o: test-bitree.c
+	gcc $(CFLAGS) -c test-bitree.c -o test-bitree.o

+ 4 - 0
kernel/ktest/ktest.h

@@ -0,0 +1,4 @@
+#pragma once
+#include <common/sys/types.h>
+
+uint64_t ktest_test_bitree(uint64_t arg);

+ 27 - 0
kernel/ktest/ktest_utils.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include <common/printk.h>
+#include <common/compiler.h>
+
+#define assert(condition) ({         \
+    int __condition = !!(condition); \
+    if (unlikely(!(__condition)))        \
+    {                            \   
+        printk("[ kTEST FAILED ] Ktest Assertion Failed, file:%s, Line:%d\n", __FILE__, __LINE__); \
+    }                                \
+    likely(__condition); \
+})
+
+#define kTEST(...)           \
+    do                       \
+    {                        \
+        printk("[ kTEST ] file:%s, Line:%d\t", __FILE__, __LINE__); \
+        printk(__VA_ARGS__); \
+        printk("\n");        \
+    } while (0);
+
+/**
+ * @brief 测试用例函数表
+ * 
+ */
+typedef long (*ktest_case_table)(uint64_t arg0, uint64_t arg1);

+ 132 - 0
kernel/ktest/test-bitree.c

@@ -0,0 +1,132 @@
+#include "ktest.h"
+#include <ktest/ktest_utils.h>
+
+#include <common/unistd.h>
+#include <common/kprint.h>
+#include <common/bitree.h>
+#include <common/errno.h>
+
+#include <mm/slab.h>
+
+struct test_value_t
+{
+    uint64_t tv;
+};
+static int compare(void *a, void *b)
+{
+    if (((struct test_value_t *)a)->tv > ((struct test_value_t *)b)->tv)
+        return 1;
+    else if (((struct test_value_t *)a)->tv == ((struct test_value_t *)b)->tv)
+        return 0;
+    else
+        return -1;
+}
+
+static int release(void *value)
+{
+    // kdebug("release");
+}
+
+/**
+ * @brief 测试创建二叉树
+ *
+ * @return int
+ */
+static long ktest_bitree_case1(uint64_t arg0, uint64_t arg1)
+{
+    int val;
+    // ========== 测试创建树
+    struct test_value_t *tv1 = (struct test_value_t *)kmalloc(sizeof(struct test_value_t), 0);
+    tv1->tv = 20;
+    struct bt_node_t *rn = bt_create_node(NULL, NULL, NULL, tv1);
+
+    assert(rn != NULL);
+    assert((int64_t)rn != (-EINVAL));
+    assert(rn->value == tv1);
+
+    struct bt_root_t *tree = bt_create_tree(rn, compare, release);
+    assert(tree != NULL);
+    assert(tree->bt_node == rn);
+    assert(tree->cmp == compare);
+    assert(tree->release == release);
+    assert(tree->size == 1);
+
+    // ========= 向树中插入数据10、30
+    struct test_value_t *tv2 = (struct test_value_t *)kmalloc(sizeof(struct test_value_t), 0);
+    assert(tv2 != NULL);
+    tv2->tv = 10;
+    {
+        int last_size = tree->size;
+        val = bt_insert(tree, tv2);
+        assert(val == 0);
+        assert(last_size + 1 == tree->size);
+    }
+    struct test_value_t *tv3 = (struct test_value_t *)kmalloc(sizeof(struct test_value_t), 0);
+    assert(tv3 != NULL);
+    tv3->tv = 30;
+    {
+        int last_size = tree->size;
+        val = bt_insert(tree, tv3);
+        assert(val == 0);
+        assert(last_size + 1 == tree->size);
+    }
+
+    // 检测树的形状
+    assert(((struct test_value_t *)tree->bt_node->left->value)->tv == tv2->tv);
+    assert(((struct test_value_t *)tree->bt_node->right->value)->tv == tv3->tv);
+
+    // ========= 查询结点
+    // 查询值为tv2的结点
+    struct bt_node_t *node2;
+    assert(bt_query(tree, tv2, (uint64_t*)(&node2)) == 0);
+    assert(node2 != NULL);
+    assert(node2->value == tv2);
+
+    // ========= 插入第4个结点:15
+    struct test_value_t *tv4 = (struct test_value_t *)kmalloc(sizeof(struct test_value_t), 0);
+    assert(tv4 != NULL);
+    tv4->tv = 15;
+    {
+        int last_size = tree->size;
+        val = bt_insert(tree, tv4);
+        assert(val == 0);
+        assert(last_size + 1 == tree->size);
+    }
+
+    assert(((struct test_value_t *)node2->right->value)->tv == tv4->tv);
+
+    // ======= 查询不存在的值
+    struct bt_node_t *node_not_exists;
+    struct test_value_t *tv_not_exists = (struct test_value_t *)kmalloc(sizeof(struct test_value_t), 0);
+    assert(tv_not_exists != NULL);
+    tv_not_exists->tv = 100;
+    assert(bt_query(tree, tv_not_exists, (uint64_t*)(&node_not_exists)) == -1);
+    // kdebug("node_not_exists.val=%d", ((struct test_value_t*)node_not_exists->value)->tv);
+    assert(node_not_exists == NULL);
+
+    // 删除根节点
+    assert(bt_delete(tree, rn->value) == 0);
+    assert(((struct test_value_t *)tree->bt_node->value)->tv != 20);
+    assert(tree->bt_node->right == NULL);
+
+    // 删除树
+    assert(bt_destroy_tree(tree) == 0);
+
+    return 0;
+}
+
+static ktest_case_table kt_bitree_func_table[] = {
+    ktest_bitree_case1,
+};
+
+uint64_t ktest_test_bitree(uint64_t arg)
+{
+    kTEST("Testing bitree...");
+    for (int i = 0; i < sizeof(kt_bitree_func_table) / sizeof(ktest_case_table); ++i)
+    {
+        kTEST("Testing case %d", i);
+        kt_bitree_func_table[i](0, 0);
+    }
+    kdebug("bitree Test done.");
+    return 0;
+}

+ 1 - 1
kernel/mm/mm.c

@@ -641,7 +641,7 @@ int mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_s
                 {
                     if (unlikely(*pde_ptr != 0 && user))
                     {
-                        kwarn("page already mapped!");
+                        // kwarn("page already mapped!");
                         // 如果是用户态可访问的页,则释放当前新获取的物理页
                         if (likely(((ul)phys_addr_start + length_mapped) < total_2M_pages)) // 校验是否为内存中的物理页
                             free_pages(Phy_to_2M_Page((ul)phys_addr_start + length_mapped), 1);

+ 6 - 4
kernel/process/process.c

@@ -15,6 +15,7 @@
 #include <syscall/syscall_num.h>
 #include <sched/sched.h>
 
+#include <ktest/ktest.h>
 
 spinlock_t process_global_pid_write_lock; // 增加pid的写锁
 long process_global_pid = 1;              // 系统中最大的pid
@@ -385,7 +386,7 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
         regs->rdi = argc;
         regs->rsi = (uint64_t)dst_argv;
     }
-    kdebug("execve ok");
+    // kdebug("execve ok");
 
     regs->cs = USER_CS | 3;
     regs->ds = USER_DS | 3;
@@ -413,7 +414,8 @@ ul initial_kernel_thread(ul arg)
     fat32_init();
     usb_init();
 
-
+    pid_t test_thread_pid = kernel_thread(ktest_test_bitree, 1, 0);
+    kdebug("test_thread_pid=%d", test_thread_pid);
     // 准备切换到用户态
     struct pt_regs *regs;
 
@@ -569,7 +571,7 @@ void process_init()
     spin_init(&process_global_pid_write_lock);
     // 初始化进程的循环链表
     list_init(&initial_proc_union.pcb.list);
-    kernel_thread(initial_kernel_thread, 10, CLONE_FS | CLONE_SIGNAL); // 初始化内核
+    kernel_thread(initial_kernel_thread, 10, CLONE_FS | CLONE_SIGNAL); // 初始化内核线
     initial_proc_union.pcb.state = PROC_RUNNING;
     initial_proc_union.pcb.preempt_count = 0;
     initial_proc_union.pcb.cpu_id = 0;
@@ -586,7 +588,6 @@ void process_init()
  * @param stack_size 堆栈大小
  * @return unsigned long
  */
-
 unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size)
 {
     int retval = 0;
@@ -642,6 +643,7 @@ unsigned long do_fork(struct pt_regs *regs, unsigned long clone_flags, unsigned
     if (process_copy_flags(clone_flags, tsk))
         goto copy_flags_failed;
 
+    kdebug("before copy mm");
     // 拷贝内存空间分布结构体
     if (process_copy_mm(clone_flags, tsk))
         goto copy_mm_failed;

+ 11 - 0
kernel/process/process.h

@@ -326,6 +326,17 @@ ul process_do_exit(ul code);
  */
 void process_exit_notify();
 
+/**
+ * @brief 初始化内核进程
+ *
+ * @param fn 目标程序的地址
+ * @param arg 向目标程序传入的参数
+ * @param flags
+ * @return int
+ */
+
+int kernel_thread(unsigned long (*fn)(unsigned long), unsigned long arg, unsigned long flags);
+
 /**
  * @brief 切换页表
  * @param prev 前一个进程的pcb