From 5df5d799004b511b769e95ef9bceda21c20c1c36 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Wed, 18 May 2022 18:27:00 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20=E5=8A=A0=E8=BD=BDelf=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 5 +- kernel/Makefile | 27 ++++--- kernel/common/Makefile | 12 +++ kernel/common/libELF/Makefile | 8 ++ kernel/filesystem/fat32/fat32.c | 2 +- kernel/mm/mm.c | 122 ++++++++++++++++++++++------ kernel/mm/mm.h | 9 +++ kernel/process/process.c | 136 +++++++++++++++++++++++++++++--- user/Makefile | 6 +- 9 files changed, 277 insertions(+), 50 deletions(-) create mode 100644 kernel/common/Makefile create mode 100644 kernel/common/libELF/Makefile diff --git a/.vscode/settings.json b/.vscode/settings.json index 8ccf25d5..42f2cf4e 100644 --- a/.vscode/settings.json +++ b/.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": "" diff --git a/kernel/Makefile b/kernel/Makefile index dbeb34c9..20ff3968 100644 --- a/kernel/Makefile +++ b/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: diff --git a/kernel/common/Makefile b/kernel/common/Makefile new file mode 100644 index 00000000..ce0e2e84 --- /dev/null +++ b/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 diff --git a/kernel/common/libELF/Makefile b/kernel/common/libELF/Makefile new file mode 100644 index 00000000..6e228b8a --- /dev/null +++ b/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 diff --git a/kernel/filesystem/fat32/fat32.c b/kernel/filesystem/fat32/fat32.c index 431310e8..a95f643c 100644 --- a/kernel/filesystem/fat32/fat32.c +++ b/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 diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 20b0d449..b0022bb8 100644 --- a/kernel/mm/mm.c +++ b/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; } \ No newline at end of file diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index d18b2ad1..b5242ff8 100644 --- a/kernel/mm/mm.h +++ b/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 调整堆区域的大小(暂时只能增加堆区域) * diff --git a/kernel/process/process.c b/kernel/process/process.c index 6a4fa26c..52d5fe98 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -10,6 +10,7 @@ #include #include #include +#include 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; diff --git a/user/Makefile b/user/Makefile index 7ee73910..6bd0e049 100644 --- a/user/Makefile +++ b/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