syscalls: implement basic execve syscall, no argc, argv, envp support yet

This commit is contained in:
2025-09-14 17:17:42 +03:00
parent 4c26652ee2
commit 91e0379fc9
9 changed files with 192 additions and 38 deletions
+22
View File
@@ -0,0 +1,22 @@
// callee.c
#include <stdio.h>
#include <unistd.h>
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;
}
+26
View File
@@ -0,0 +1,26 @@
// caller.c
#include <stdio.h>
#include <unistd.h>
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;
}
+6
View File
@@ -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);
+2
View File
@@ -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
+32
View File
@@ -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;
}
+1 -1
View File
@@ -131,7 +131,7 @@ void kmain(unsigned int magic, unsigned int info)
mount_fs();
exec_from_file("main.", ".");
exec_from_file("caller.", ".");
while(1)
{
+1 -37
View File
@@ -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)
{
+15
View File
@@ -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
+87
View File
@@ -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);