From 91e0379fc96fa13d6966734574f9b07cf620e0a2 Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Sun, 14 Sep 2025 16:58:19 +0300 Subject: [PATCH] syscalls: implement basic execve syscall, no argc, argv, envp support yet --- grubshit/callee.c | 22 +++++++++ grubshit/caller.c | 26 +++++++++++ include/exec_from_file.h | 6 +++ include/vfs.h | 2 + src/fs/vfs.c | 32 +++++++++++++ src/kernel/kernel.c | 2 +- src/tasking/exec_from_file.c | 38 +--------------- src/tasking/sys_exit.asm | 15 +++++++ src/tasking/syscalls.c | 87 ++++++++++++++++++++++++++++++++++++ 9 files changed, 192 insertions(+), 38 deletions(-) create mode 100644 grubshit/callee.c create mode 100644 grubshit/caller.c diff --git a/grubshit/callee.c b/grubshit/callee.c new file mode 100644 index 0000000..59614f0 --- /dev/null +++ b/grubshit/callee.c @@ -0,0 +1,22 @@ +// callee.c +#include +#include + +int main(int argc, char *argv[], char *envp[]) { + printf("--- In callee.c ---\n"); + printf("This program has taken over the process.\n"); + + printf("argc: %d\n", argc); + + printf("\nArguments (argv):\n"); + for (int i = 0; argv[i] != NULL; i++) { + printf(" argv[%d]: %s\n", i, argv[i]); + } + + printf("\nEnvironment Variables (envp):\n"); + for (int i = 0; envp[i] != NULL; i++) { + printf(" %s\n", envp[i]); + } + + return 0; +} diff --git a/grubshit/caller.c b/grubshit/caller.c new file mode 100644 index 0000000..bc6a312 --- /dev/null +++ b/grubshit/caller.c @@ -0,0 +1,26 @@ +// caller.c +#include +#include + +int main() { + printf("--- In caller.c ---\n"); + printf("This message is from the original program.\n"); + printf("Calling execve to run './callee'...\n\n"); + + // Arguments for the new program + // The first argument is conventionally the program name + char *argv[] = {NULL}; //{ "./callee", "first_arg", "second_arg", NULL }; + + // Environment variables for the new program + char *envp[] = {NULL}; //{ "CUSTOM_VAR=Hello from caller!", "ANOTHER_VAR=123", NULL }; + + // The execve system call + // The first argument is the path to the executable + // The second is the array of arguments + // The third is the array of environment variables + execve("callee.", argv, envp); + + // This part of the code will only be reached if execve fails + perror("execve failed"); + return 1; +} diff --git a/include/exec_from_file.h b/include/exec_from_file.h index 6a3c862..f7d07af 100644 --- a/include/exec_from_file.h +++ b/include/exec_from_file.h @@ -3,4 +3,10 @@ #include "../include/vfs.h" #include "../include/lib9660.h" +#define DivRoundUp(number, divisor) ((number + divisor - 1) / divisor) + +#define USER_STACK_TOP 0xBFFFFFF0 // Top of user space memory +#define USER_STACK_SIZE 0x4000 // 16KB stack (4 pages) +#define USER_STACK_BOTTOM (USER_STACK_TOP - USER_STACK_SIZE) + void exec_from_file(const char* filename, const char* dirname); \ No newline at end of file diff --git a/include/vfs.h b/include/vfs.h index dbf92f9..aa98a9c 100644 --- a/include/vfs.h +++ b/include/vfs.h @@ -19,4 +19,6 @@ size_t vfs_read_file_length(l9660_file *file, uint8_t* buffer, size_t length); void test_iso9660(); +int vsf_read_file_by_path(const char* path, uint8_t** buffer, l9660_dir* dir); + #endif \ No newline at end of file diff --git a/src/fs/vfs.c b/src/fs/vfs.c index 9503842..f2dc902 100644 --- a/src/fs/vfs.c +++ b/src/fs/vfs.c @@ -189,4 +189,36 @@ void test_iso9660() printf("Total bytes read: "); printf("0x%X\n", total_bytes); } +} + +int vsf_read_file_by_path(const char* path, uint8_t** buffer, l9660_dir* dir) +{ + l9660_file* file = (l9660_file*)malloc(sizeof(l9660_file)); + + l9660_status err; + + err = l9660_openat(file, dir, path); + if (err != L9660_OK) + { + debug_log("read_file: err: 0x%X\n", err); + return err; + } + + debug_log("HEHE %s\n", path); + + l9660_seek(file, L9660_SEEK_END, 0); + uint32_t file_size = l9660_tell(file); + debug_log("file_size: %X\n", file_size); + l9660_seek(file, L9660_SEEK_SET, 0); + + *buffer = (uint8_t*)malloc(file_size); + debug_log("eeee\n"); + + size_t read; + + read = vfs_read_file(file, *buffer); + free(file); + debug_log("bytes read: 0x%X\n", read); + + return 0; } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 6768305..60b3841 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -131,7 +131,7 @@ void kmain(unsigned int magic, unsigned int info) mount_fs(); - exec_from_file("main.", "."); + exec_from_file("caller.", "."); while(1) { diff --git a/src/tasking/exec_from_file.c b/src/tasking/exec_from_file.c index 0e91ca6..5cc067a 100644 --- a/src/tasking/exec_from_file.c +++ b/src/tasking/exec_from_file.c @@ -6,42 +6,6 @@ #include "../include/paging.h" #include "../include/task.h" -#define DivRoundUp(number, divisor) ((number + divisor - 1) / divisor) - -#define USER_STACK_TOP 0xBFFFFFF0 // Top of user space memory -#define USER_STACK_SIZE 0x4000 // 16KB stack (4 pages) -#define USER_STACK_BOTTOM (USER_STACK_TOP - USER_STACK_SIZE) - -int read_file(const char* path, uint8_t** buffer, l9660_dir* dir) -{ - l9660_file* file = (l9660_file*)malloc(sizeof(l9660_file)); - - l9660_status err; - - err = l9660_openat(file, dir, path); - if (err != L9660_OK) - { - debug_log("read_file: err: 0x%X\n", err); - return err; - } - - l9660_seek(file, L9660_SEEK_END, 0); - uint32_t file_size = l9660_tell(file); - debug_log("file_size: %X\n", file_size); - l9660_seek(file, L9660_SEEK_SET, 0); - - *buffer = (uint8_t*)malloc(file_size); - debug_log("eeee\n"); - - size_t read; - - read = vfs_read_file(file, *buffer); - free(file); - debug_log("bytes read: 0x%X\n", read); - - return 0; -} - void exec_from_file(const char* filename, const char* dirname) { asm volatile("cli"); @@ -58,7 +22,7 @@ void exec_from_file(const char* filename, const char* dirname) uint32_t bss_start, bss_end; - err = read_file(filename, &file, &dir); + err = vsf_read_file_by_path(filename, &file, &dir); if(err != 0) { diff --git a/src/tasking/sys_exit.asm b/src/tasking/sys_exit.asm index e001beb..c92e20f 100644 --- a/src/tasking/sys_exit.asm +++ b/src/tasking/sys_exit.asm @@ -31,5 +31,20 @@ sys_exit_handler: ; Возвращаемся в Ring 3 iret +global execve_return + +execve_return: + mov esp, [esp+4] + + pop gs + pop fs + pop es + pop ds + popa + + add esp, 8 + + iret + section .data sys_exit_msg: db "Returned from Ring 3", 0 \ No newline at end of file diff --git a/src/tasking/syscalls.c b/src/tasking/syscalls.c index f055cd4..6f81440 100644 --- a/src/tasking/syscalls.c +++ b/src/tasking/syscalls.c @@ -247,6 +247,89 @@ int sys_close(TrapFrame *tf) return -1; } +#include "../include/exec_from_file.h" + +extern void execve_return(TrapFrame *tf); + +int sys_execve(TrapFrame *tf) { + const char* filename = (const char*)tf->ebx; + + uint8_t* file_buffer; + int err = vsf_read_file_by_path(filename, &file_buffer, root_dir); + if (err != 0) { + debug_log("execve: failed to read file '%s'\n", filename); + return -1; + } + + Elf32_Ehdr *elf_header = (Elf32_Ehdr*)file_buffer; + if (memcmp(elf_header->e_ident, "\x7F" "ELF", 4) != 0) { + debug_log("execve: '%s' is not a valid ELF file\n", filename); + free(file_buffer); + return -1; + } + + uint32_t* new_page_dir = create_page_dir(); + if (!new_page_dir) { + free(file_buffer); + return -1; + } + uint32_t new_page_dir_phys = (uint32_t)get_physaddr((void*)new_page_dir); + uint32_t* old_page_dir_to_free = current->pagedir; + + set_page_dir(new_page_dir_phys); + current->pagedir = new_page_dir; + + void* kstack_phys = get_physaddr(current->kstack); + map_page(kstack_phys, current->kstack, PAGE_PRESENT | PAGE_RW); + + uint32_t highest_vaddr = 0; + for (int i = 0; i < elf_header->e_phnum; i++) { + Elf32_Phdr *p_header = (Elf32_Phdr *)(file_buffer + elf_header->e_phoff + i * elf_header->e_phentsize); + if (p_header->p_type == PT_LOAD) { + for (uint32_t vaddr = p_header->p_vaddr; vaddr < p_header->p_vaddr + p_header->p_memsz; vaddr += PAGE_SIZE) { + void* phys_addr = alloc_page(); + map_page(phys_addr, (void*)(vaddr & ~0xFFF), PAGE_PRESENT | PAGE_RW | PAGE_USER); + } + memcpy((void*)p_header->p_vaddr, file_buffer + p_header->p_offset, p_header->p_filesz); + if (p_header->p_memsz > p_header->p_filesz) { + memset((void*)(p_header->p_vaddr + p_header->p_filesz), 0, p_header->p_memsz - p_header->p_filesz); + } + if (p_header->p_vaddr + p_header->p_memsz > highest_vaddr) { + highest_vaddr = p_header->p_vaddr + p_header->p_memsz; + } + } + } + + for (uint32_t vaddr = USER_STACK_BOTTOM; vaddr <= USER_STACK_TOP; vaddr += PAGE_SIZE) { + void* phys_addr = alloc_page(); + map_page(phys_addr, (void*)(vaddr & ~0xFFF), PAGE_PRESENT | PAGE_RW | PAGE_USER); + } + uint32_t user_esp = USER_STACK_TOP; + user_esp -= 4; *(uint32_t*)user_esp = 0; // envp + user_esp -= 4; *(uint32_t*)user_esp = 0; // argv + user_esp -= 4; *(uint32_t*)user_esp = 0; // argc + + current->brk = (void*)(DivRoundUp(highest_vaddr, PAGE_SIZE) * PAGE_SIZE); + free(file_buffer); + destroy_page_dir(old_page_dir_to_free); + + tf->gs = SEG_UDATA | DPL_USER; + tf->fs = SEG_UDATA | DPL_USER; + tf->es = SEG_UDATA | DPL_USER; + tf->ds = SEG_UDATA | DPL_USER; + tf->eax = 0; tf->ecx = 0; tf->edx = 0; tf->ebx = 0; + tf->ebp = 0; tf->esi = 0; tf->edi = 0; + tf->eip = elf_header->e_entry; + tf->cs = SEG_UCODE | DPL_USER; + tf->eflags = FL_IF; + tf->usermode_esp = user_esp; + tf->usermode_ss = SEG_UDATA | DPL_USER; + + execve_return(tf); + + return 0; +} + int sys_chdir(TrapFrame *tf) { //strcat(current->cwd->fat->path, "/"); @@ -355,6 +438,10 @@ void handle_syscall(TrapFrame *tf) case 6://close tf->eax = sys_close(tf); break; + + case 11://execve + tf->eax = sys_execve(tf); + break; case 12://chdir tf->eax = sys_chdir(tf);