🆕 加载elf文件

This commit is contained in:
fslongjin 2022-05-18 18:27:00 +08:00
parent b0a7ec633d
commit 5df5d79900
9 changed files with 277 additions and 50 deletions

View File

@ -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": ""

View File

@ -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
kernel/common/Makefile Normal file
View File

@ -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

View File

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

View File

@ -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

View File

@ -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();
@ -831,3 +869,37 @@ 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;
}

View File

@ -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
*

View File

@ -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;

View File

@ -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