fslongjin преди 2 години
родител
ревизия
5df5d79900
променени са 9 файла, в които са добавени 277 реда и са изтрити 50 реда
  1. 4 1
      .vscode/settings.json
  2. 18 9
      kernel/Makefile
  3. 12 0
      kernel/common/Makefile
  4. 8 0
      kernel/common/libELF/Makefile
  5. 1 1
      kernel/filesystem/fat32/fat32.c
  6. 97 25
      kernel/mm/mm.c
  7. 9 0
      kernel/mm/mm.h
  8. 124 12
      kernel/process/process.c
  9. 4 2
      user/Makefile

+ 4 - 1
.vscode/settings.json

@@ -95,7 +95,10 @@
         "types.h": "c",
         "string.h": "c",
         "math.h": "c",
-        "ipi.h": "c"
+        "ipi.h": "c",
+        "arch.h": "c",
+        "elf.h": "c",
+        "stdio.h": "c"
     },
     "C_Cpp.errorSquiggles": "Enabled",
     "esbonio.sphinx.confDir": ""

+ 18 - 9
kernel/Makefile

@@ -1,4 +1,4 @@
-SUBDIR_ROOTS := . common
+SUBDIR_ROOTS := .
 DIRS := . $(shell find $(SUBDIR_ROOTS) -type d)
 GARBAGE_PATTERNS := *.o *.s~ *.s *.S~ *.c~ *.h~ kernel
 GARBAGE := $(foreach DIR,$(DIRS),$(addprefix $(DIR)/,$(GARBAGE_PATTERNS)))
@@ -10,7 +10,7 @@ LIB_FILES := $(foreach DIR,$(DIR_LIB),$(addprefix $(DIR)/,$(lib_patterns)))
 
 # 控制操作系统使用的中断控制器 _INTR_8259A_ _INTR_APIC_
 PIC := _INTR_APIC_
-CFLAGS = $(GLOBAL_CFLAGS) -D $(PIC) -I .
+CFLAGS = $(GLOBAL_CFLAGS) -D $(PIC) -I $(shell pwd)
 
 ASFLAGS := --64
 
@@ -18,6 +18,11 @@ LD_LIST := head.o
 OBJ_LIST := head.o
 
 
+kernel_subdirs := common/libELF
+	
+
+
+
 
 head.o: head.S
 	gcc -E head.S > head.s # 预处理
@@ -143,17 +148,21 @@ uart.o: driver/uart/uart.c
 	gcc $(CFLAGS) -c driver/uart/uart.c -o driver/uart/uart.o
 
 
-
 all: kernel
+
+	ld -b elf64-x86-64 -z muldefs -o kernel  head.o main.o $(shell find . -name "*.o") -T link.lds
 	objcopy -I elf64-x86-64 -O elf64-x86-64 -R ".comment" -R ".eh_frame" kernel ../bin/kernel/kernel.elf
-#
 
 kernel: head.o entry.o procs.o main.o printk.o trap.o mm.o slab.o irq.o pic.o process.o sched.o syscall.o multiboot2.o cpu.o acpi.o ps2_keyboard.o ps2_mouse.o ata.o pci.o ahci.o smp.o apu_boot.o rtc.o HPET.o softirq.o timer.o fat32.o MBR.o VFS.o $(OBJ_LIST)
-	ld -b elf64-x86-64 -z muldefs -o kernel head.o exception/entry.o process/procs.o main.o common/printk.o exception/trap.o exception/irq.o mm/mm.o mm/slab.o process/process.o syscall/syscall.o driver/multiboot2/multiboot2.o \
-	common/cpu.o smp/smp.o smp/apu_boot.o exception/softirq.o sched/sched.o	filesystem/fat32/fat32.o filesystem/MBR.o filesystem/VFS/VFS.o \
-	driver/acpi/acpi.o driver/interrupt/pic.o driver/keyboard/ps2_keyboard.o driver/mouse/ps2_mouse.o driver/disk/ata.o driver/pci/pci.o driver/disk/ahci/ahci.o driver/timers/rtc/rtc.o driver/timers/HPET/HPET.o driver/timers/timer.o \
-	$(LD_LIST)	\
-	-T link.lds
+	
+	@list='$(kernel_subdirs)'; for subdir in $$list; do \
+    		echo "make all in $$subdir";\
+    		cd $$subdir;\
+    		 $(MAKE) all CFLAGS="$(CFLAGS)";\
+    		cd ..;\
+	done
+
+	
 
 
 clean: 

+ 12 - 0
kernel/common/Makefile

@@ -0,0 +1,12 @@
+
+CFLAGS += -I .
+
+kernel_common_subdirs:=libELF
+
+all: 
+	@list='$(kernel_common_subdirs)'; for subdir in $$list; do \
+    		echo "make all in $$subdir";\
+    		cd $$subdir;\
+    		$(MAKE) all CFLAGS="$(CFLAGS) -I";\
+    		cd ..;\
+	done

+ 8 - 0
kernel/common/libELF/Makefile

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

+ 1 - 1
kernel/filesystem/fat32/fat32.c

@@ -845,7 +845,7 @@ long fat32_lseek(struct vfs_file_t *file_ptr, long offset, long whence)
         return -EOVERFLOW;
     file_ptr->position = pos;
     
-    kdebug("fat32 lseek -> position=%d", file_ptr->position);
+    // kdebug("fat32 lseek -> position=%d", file_ptr->position);
     return pos;
 }
 // todo: ioctl

+ 97 - 25
kernel/mm/mm.c

@@ -9,6 +9,34 @@ ul Total_Memory = 0;
 ul total_2M_pages = 0;
 static ul root_page_table_phys_addr = 0; // 内核层根页表的物理地址
 
+/**
+ * @brief 虚拟地址长度所需要的entry数量
+ *
+ */
+typedef struct
+{
+    uint64_t num_PML4E;
+    uint64_t *num_PDPTE;
+    uint64_t *num_PDE;
+    uint64_t num_PTE;
+} mm_pgt_entry_num_t;
+
+/**
+ * @brief 计算虚拟地址长度对应的页表entry数量
+ *
+ * @param length 长度
+ * @param ent 返回的entry数量结构体
+ */
+static void mm_calculate_entry_num(uint64_t length, mm_pgt_entry_num_t *ent)
+{
+    if (ent == NULL)
+        return;
+    ent->num_PML4E = (length + (1UL << PAGE_GDT_SHIFT) - 1) >> PAGE_GDT_SHIFT;
+    ent->num_PDPTE = (length + PAGE_1G_SIZE - 1) >> PAGE_1G_SHIFT;
+    ent->num_PDE = (length + PAGE_2M_SIZE - 1) >> PAGE_2M_SHIFT;
+    ent->num_PTE = (length + PAGE_4K_SIZE - 1) >> PAGE_4K_SHIFT;
+}
+
 /**
  * @brief 从页表中获取pdt页表项的内容
  *
@@ -605,40 +633,50 @@ void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul
  */
 void mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_start, ul phys_addr_start, ul length, ul flags, bool user)
 {
+
     // kdebug("proc_page_table_addr=%#018lx", proc_page_table_addr);
     // 计算线性地址对应的pml4页表项的地址
-    ul *tmp;
-    if (is_phys)
-        tmp = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff));
-    else
-        tmp = (ul *)((ul)proc_page_table_addr & (~0xfffUL)) + ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
+    mm_pgt_entry_num_t pgt_num;
+    mm_calculate_entry_num(length, &pgt_num);
+    kdebug("ent1=%d ent2=%d ent3=%d, ent4=%d", pgt_num.num_PML4E, pgt_num.num_PDPTE, pgt_num.num_PDE, pgt_num.num_PTE);
 
-    if (*tmp == 0)
+    uint64_t pml4e_id = ((virt_addr_start >> PAGE_GDT_SHIFT) & 0x1ff);
+    // 循环填写顶层页表
+    for (int num_pml4e = 0; num_pml4e < pgt_num.num_PML4E && pml4e_id < 512; ++num_pml4e, ++pml4e_id)
     {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pml4t(tmp, mk_pml4t(virt_2_phys(virt_addr), (user ? PAGE_USER_PGT : PAGE_KERNEL_PGT)));
-    }
+        ul *tmp;
+        if (is_phys)
+            tmp = phys_2_virt((ul *)((ul)proc_page_table_addr & (~0xfffUL)) + pml4e_id);
+        else
+            tmp = (ul *)((ul)proc_page_table_addr & (~0xfffUL) + pml4e_id);
 
-    tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr_start >> PAGE_1G_SHIFT) & 0x1ff));
+        if (*tmp == 0)
+        {
+            ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
+            memset(virt_addr, 0, PAGE_4K_SIZE);
+            set_pml4t(tmp, mk_pml4t(virt_2_phys(virt_addr), (user ? PAGE_USER_PGT : PAGE_KERNEL_PGT)));
+        }
 
-    if (*tmp == 0)
-    {
-        ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
-        memset(virt_addr, 0, PAGE_4K_SIZE);
-        set_pdpt(tmp, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
-    }
+        tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr_start >> PAGE_1G_SHIFT) & 0x1ff));
 
-    ul *tmp1;
-    // 初始化2M物理页
-    for (ul i = 0; i < (length); i += PAGE_2M_SIZE)
-    {
-        // 计算当前2M物理页对应的pdt的页表项的物理地址
+        if (*tmp == 0)
+        {
+            ul *virt_addr = kmalloc(PAGE_4K_SIZE, 0);
+            memset(virt_addr, 0, PAGE_4K_SIZE);
+            set_pdpt(tmp, mk_pdpt(virt_2_phys(virt_addr), (user ? PAGE_USER_DIR : PAGE_KERNEL_DIR)));
+        }
 
-        tmp1 = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr_start + i) >> PAGE_2M_SHIFT) & 0x1ff)));
+        ul *tmp1;
+        // 初始化2M物理页
+        for (ul i = 0; i < (length); i += PAGE_2M_SIZE)
+        {
+            // 计算当前2M物理页对应的pdt的页表项的物理地址
 
-        // 页面写穿,禁止缓存
-        set_pdt(tmp1, mk_pdt((ul)phys_addr_start + i, flags | (user ? PAGE_USER_PAGE : PAGE_KERNEL_PAGE)));
+            tmp1 = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr_start + i) >> PAGE_2M_SHIFT) & 0x1ff)));
+
+            // 页面写穿,禁止缓存
+            set_pdt(tmp1, mk_pdt((ul)phys_addr_start + i, flags | (user ? PAGE_USER_PAGE : PAGE_KERNEL_PAGE)));
+        }
     }
 
     flush_tlb();
@@ -830,4 +868,38 @@ uint64_t mm_do_brk(uint64_t old_brk_end_addr, int64_t offset)
         // 在页表中取消映射
     }
     return end_addr;
+}
+
+/**
+ * @brief 检测指定地址是否已经被映射
+ *
+ * @param page_table_phys_addr 页表的物理地址
+ * @param virt_addr 要检测的地址
+ * @return true 已经被映射
+ * @return false
+ */
+bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr)
+{
+    ul *tmp;
+
+    tmp = phys_2_virt((ul *)((ul)page_table_phys_addr & (~0xfffUL)) + ((virt_addr >> PAGE_GDT_SHIFT) & 0x1ff));
+
+    // pml4页表项为0
+    if (*tmp == 0)
+        return 0;
+
+    tmp = phys_2_virt((ul *)(*tmp & (~0xfffUL)) + ((virt_addr >> PAGE_1G_SHIFT) & 0x1ff));
+
+    // pdpt页表项为0
+    if (*tmp == 0)
+        return 0;
+
+    // 读取pdt页表项
+    tmp = phys_2_virt(((ul *)(*tmp & (~0xfffUL)) + (((ul)(virt_addr) >> PAGE_2M_SHIFT) & 0x1ff)));
+
+    // todo: 增加对使用了4K页的页表的检测
+    if (*tmp != 0)
+        return true;
+    else
+        return false;
 }

+ 9 - 0
kernel/mm/mm.h

@@ -379,6 +379,15 @@ void mm_map_proc_page_table(ul proc_page_table_addr, bool is_phys, ul virt_addr_
 
 void mm_map_phys_addr_user(ul virt_addr_start, ul phys_addr_start, ul length, ul flags);
 
+/**
+ * @brief 检测指定地址是否已经被映射
+ * 
+ * @param page_table_phys_addr 页表的物理地址
+ * @param virt_addr 要检测的地址
+ * @return true 已经被映射
+ * @return false 
+ */
+bool mm_check_mapped(ul page_table_phys_addr, uint64_t virt_addr);
 /**
  * @brief 调整堆区域的大小(暂时只能增加堆区域)
  * 

+ 124 - 12
kernel/process/process.c

@@ -10,6 +10,7 @@
 #include <filesystem/fat32/fat32.h>
 #include <common/stdio.h>
 #include <process/spinlock.h>
+#include <common/libELF/elf.h>
 
 spinlock_t process_global_pid_write_lock; // 增加pid的写锁
 long process_global_pid = 1;              // 系统中最大的pid
@@ -353,6 +354,126 @@ struct vfs_file_t *process_open_exec_file(char *path)
 
     return filp;
 }
+
+/**
+ * @brief 加载elf格式的程序文件到内存中,并设置regs
+ *
+ * @param regs 寄存器
+ * @param path 文件路径
+ * @return int
+ */
+static int process_load_elf_file(struct pt_regs *regs, char *path)
+{
+    int retval = 0;
+    struct vfs_file_t *filp = process_open_exec_file(path);
+    if ((unsigned long)filp <= 0)
+    {
+        kdebug("(unsigned long)filp=%d", (long)filp);
+        return (unsigned long)filp;
+    }
+
+    void *buf = kmalloc(sizeof(PAGE_4K_SIZE), 0);
+    uint64_t pos = 0;
+    pos = filp->file_ops->lseek(filp, 0, SEEK_SET);
+    retval = filp->file_ops->read(filp, (char *)buf, sizeof(Elf64_Ehdr), &pos);
+    retval = 0;
+    if (!elf_check(buf))
+    {
+        kerror("Not an ELF file: %s", path);
+        retval = -ENOTSUP;
+        goto load_elf_failed;
+    }
+
+#if ARCH(X86_64)
+    // 暂时只支持64位的文件
+    if (((Elf32_Ehdr *)buf)->e_ident[EI_CLASS] != ELFCLASS64)
+    {
+        kdebug("((Elf32_Ehdr *)buf)->e_ident[EI_CLASS]=%d", ((Elf32_Ehdr *)buf)->e_ident[EI_CLASS]);
+        retval = -EUNSUPPORTED;
+        goto load_elf_failed;
+    }
+    Elf64_Ehdr ehdr = *(Elf64_Ehdr *)buf;
+    // 暂时只支持AMD64架构
+    if (ehdr.e_machine != EM_AMD64)
+    {
+        kerror("e_machine=%d", ehdr.e_machine);
+        retval = -EUNSUPPORTED;
+        goto load_elf_failed;
+    }
+#else
+#error Unsupported architecture!
+#endif
+    if (ehdr.e_type != ET_EXEC)
+    {
+        kdebug("ehdr->e_type=%d", ehdr.e_type);
+        retval = -EUNSUPPORTED;
+        goto load_elf_failed;
+    }
+    kdebug("e_entry=%#018lx", ehdr.e_entry);
+    regs->rip = ehdr.e_entry;
+    current_pcb->mm->code_addr_start = ehdr.e_entry;
+
+    // kdebug("ehdr.e_phoff=%#018lx\t ehdr.e_phentsize=%d, ehdr.e_phnum=%d", ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum);
+    // 将指针移动到program header处
+    pos = ehdr.e_phoff;
+    // 读取所有的phdr
+    pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
+    filp->file_ops->read(filp, (char *)buf, ehdr.e_phentsize * ehdr.e_phnum, &pos);
+    if ((unsigned long)filp <= 0)
+    {
+        kdebug("(unsigned long)filp=%d", (long)filp);
+        return (unsigned long)filp;
+    }
+    Elf64_Phdr *phdr = buf;
+
+    for (int i = 0; i < ehdr.e_phnum; ++i, ++phdr)
+    {
+        // kdebug("phdr[%d] phdr->p_offset=%#018lx phdr->p_vaddr=%#018lx phdr->p_memsz=%ld phdr->p_filesz=%ld  phdr->p_type=%d", i, phdr->p_offset, phdr->p_vaddr, phdr->p_memsz, phdr->p_filesz, phdr->p_type);
+
+        // 不是可加载的段
+        if (phdr->p_type != PT_LOAD)
+            continue;
+
+        int64_t remain_mem_size = phdr->p_memsz;
+        int64_t remain_file_size = phdr->p_filesz;
+        pos = phdr->p_offset;
+
+        uint64_t virt_base = phdr->p_vaddr;
+        while (remain_mem_size > 0)
+        {
+
+            // todo: 改用slab分配4K大小内存块并映射到4K页
+            if (!mm_check_mapped((uint64_t)current_pcb->mm->pgd, virt_base)) // 未映射,则新增物理页
+            {
+                mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, virt_base, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
+            }
+            pos = filp->file_ops->lseek(filp, pos, SEEK_SET);
+            int64_t val = 0;
+            if (remain_file_size != 0)
+            {
+                int64_t to_trans = (remain_file_size > PAGE_2M_SIZE) ? PAGE_2M_SIZE : remain_file_size;
+                val = filp->file_ops->read(filp, (char*)virt_base, to_trans, &pos);
+            }
+
+            if (val < 0)
+                goto load_elf_failed;
+
+            remain_mem_size -= PAGE_2M_SIZE;
+            remain_file_size -= val;
+            virt_base += PAGE_2M_SIZE;
+        }
+    }
+
+    // 分配2MB的栈内存空间
+    regs->rsp = current_pcb->mm->stack_start;
+    regs->rbp = current_pcb->mm->stack_start;
+    mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, current_pcb->mm->stack_start - PAGE_2M_SIZE, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
+
+load_elf_failed:;
+    if (buf != NULL)
+        kfree(buf);
+    return retval;
+}
 /**
  * @brief 使当前进程去执行新的代码
  *
@@ -398,11 +519,9 @@ ul do_execve(struct pt_regs *regs, char *path)
      *
      */
     // 映射1个2MB的物理页
-    unsigned long code_start_addr = 0x800000;
-    unsigned long stack_start_addr = 0xa00000;
-    uint64_t brk_start_addr = 0xc00000;
 
-    mm_map_proc_page_table((uint64_t)current_pcb->mm->pgd, true, code_start_addr, alloc_pages(ZONE_NORMAL, 1, PAGE_PGT_MAPPED)->addr_phys, PAGE_2M_SIZE, PAGE_USER_PAGE, true);
+    unsigned long stack_start_addr = 0x6fffffc00000;
+    uint64_t brk_start_addr = 0x6fffffc00000;
 
     process_switch_mm(current_pcb);
 
@@ -410,7 +529,6 @@ ul do_execve(struct pt_regs *regs, char *path)
     if (!(current_pcb->flags & PF_KTHREAD))
         current_pcb->addr_limit = USER_MAX_LINEAR_ADDR;
 
-    current_pcb->mm->code_addr_start = code_start_addr;
     current_pcb->mm->code_addr_end = 0;
     current_pcb->mm->data_addr_start = 0;
     current_pcb->mm->data_addr_end = 0;
@@ -428,13 +546,7 @@ ul do_execve(struct pt_regs *regs, char *path)
     // 清除进程的vfork标志位
     current_pcb->flags &= ~PF_VFORK;
 
-    struct vfs_file_t *filp = process_open_exec_file(path);
-    if ((unsigned long)filp <= 0)
-        return (unsigned long)filp;
-
-    memset((void *)code_start_addr, 0, PAGE_2M_SIZE);
-    uint64_t pos = 0;
-    int retval = filp->file_ops->read(filp, (char *)code_start_addr, PAGE_2M_SIZE, &pos);
+    process_load_elf_file(regs, path);
     kdebug("execve ok");
 
     return 0;

+ 4 - 2
user/Makefile

@@ -20,12 +20,14 @@ all:
 	$(MAKE) init.o
 	$(MAKE) sys_api_lib
 	
-	objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary sys_api_lib $(ROOT_PATH)/bin/user/init.bin
+# objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary sys_api_lib $(ROOT_PATH)/bin/user/init.bin
+	objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O elf64-x86-64 sys_api_lib $(ROOT_PATH)/bin/user/init.bin
 
 sys_api_lib: init.o
 	
 
-	ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o $(shell find . -name "*.o") -T init.lds
+	ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o  $(shell find . -name "*.o")
+#ld -b elf64-x86-64 -z muldefs -o sys_api_lib init.o $(shell find . -name "*.o") -T init.lds
 
 init.o: init.c 
 	gcc $(current_CFLAGS) -c init.c -o init.o