Kernel, libc, userspace: Implement command-line arguments (argv)

The only thing missing now is for sh to pass them on.
This commit is contained in:
apio 2022-10-26 18:57:06 +02:00
parent 0bad662c2f
commit 7d20c507b1
16 changed files with 144 additions and 22 deletions

View File

@ -1,4 +1,4 @@
APPS := init sym sh crash uname uptime hello ps ls
APPS := init sym sh crash uname uptime hello ps ls args
APPS_DIR := $(LUNA_ROOT)/apps
APPS_SRC := $(APPS_DIR)/src

7
apps/src/args.c Normal file
View File

@ -0,0 +1,7 @@
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
{
for (int i = 0; i < argc; i++) puts(argv[i]);
}

View File

@ -50,7 +50,8 @@ int main()
}
if (child == 0)
{
execv("/bin/sh", NULL);
char* argv[] = {"/bin/sh", NULL};
execv(argv[0], argv);
perror("execv");
return 1;
}

View File

@ -113,11 +113,15 @@ void command_execute(command* cmd)
char* buf = malloc(cmd->size + 6);
strlcpy(buf, "/bin/", 6);
strncat(buf, cmd->buffer, cmd->size);
execv(buf, NULL);
char* argv[] = {buf, NULL};
execv(argv[0], argv);
}
}
else
execv(cmd->buffer, NULL);
{
char* argv[] = {cmd->buffer, NULL};
execv(argv[0], argv);
}
perror(cmd->buffer);
exit(127);
}

View File

@ -4,6 +4,7 @@
#define ENOENT 2
#define ESRCH 3
#define EINTR 4
#define E2BIG 7
#define ENOEXEC 8
#define EBADF 9
#define EAGAIN 11

View File

@ -14,7 +14,7 @@
#define SYS_read 9
#define SYS_close 10
#define SYS_seek 11
#define SYS_exec 12
#define SYS_execv 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15
@ -49,7 +49,7 @@ void sys_open(Context* context, const char* filename, int flags);
void sys_read(Context* context, int fd, size_t size, char* buffer);
void sys_close(Context* context, int fd);
void sys_seek(Context* context, int fd, long offset, int whence);
void sys_exec(Context* context, const char* pathname);
void sys_execv(Context* context, const char* pathname, char** argv);
void sys_fcntl(Context* context, int fd, int command, uintptr_t arg);
void sys_mprotect(Context* context, void* address, size_t size, int prot);
void sys_clock(Context* context);

View File

@ -23,7 +23,7 @@ void Syscall::entry(Context* context)
case SYS_read: sys_read(context, (int)context->rdi, context->rsi, (char*)context->rdx); break;
case SYS_close: sys_close(context, (int)context->rdi); break;
case SYS_seek: sys_seek(context, (int)context->rdi, (long)context->rsi, (int)context->rdx); break;
case SYS_exec: sys_exec(context, (const char*)context->rdi); break;
case SYS_execv: sys_execv(context, (const char*)context->rdi, (char**)context->rsi); break;
case SYS_fcntl: sys_fcntl(context, (int)context->rdi, (int)context->rsi, context->rdx); break;
case SYS_mprotect: sys_mprotect(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
case SYS_clock: sys_clock(context); break;

View File

@ -2,6 +2,7 @@
#include "interrupts/Interrupts.h"
#include "log/Log.h"
#include "memory/Memory.h"
#include "memory/MemoryManager.h"
#include "memory/PMM.h"
#include "memory/VMM.h"
@ -56,7 +57,16 @@ void sys_fork(Context* context)
return;
}
void sys_exec(Context* context, const char* pathname)
void push_on_user_stack(uint64_t* rsp, char* value,
size_t size) // FIXME: Handle segments of stack that extend beyond one page.
{
(*rsp) -= size;
char* kvalue = (char*)VMM::get_physical(*rsp);
ASSERT(kvalue != (char*)UINT64_MAX);
memcpy(kvalue, value, size);
}
void sys_execv(Context* context, const char* pathname, char** argv)
{
char* kpathname = strdup_from_user(pathname);
if (!kpathname)
@ -97,6 +107,85 @@ void sys_exec(Context* context, const char* pathname)
return;
}
uint64_t kargc = 0;
char** kargv = nullptr;
char** arg;
auto free_kernel_argv_copy = [&]() {
for (uint64_t i = 0; i < kargc; i++)
{
if (kargv[i]) kfree(kargv[i]);
}
if (kargv) kfree(kargv);
};
do {
if (Memory::is_kernel_address((uintptr_t)argv))
{
free_kernel_argv_copy();
context->rax = -EFAULT;
return;
}
arg = (char**)VMM::get_physical((uint64_t)argv);
if (arg == (char**)UINT64_MAX)
{
free_kernel_argv_copy();
context->rax = -EFAULT;
return;
}
kargv = (char**)krealloc(kargv, (kargc + 1) * sizeof(char*));
if (!kargv)
{
free_kernel_argv_copy();
context->rax = -ENOMEM;
return;
}
if (*arg)
{
char* kcopy = strdup_from_user(*arg);
if (!kcopy)
{
free_kernel_argv_copy();
context->rax = -ENOMEM;
return;
}
kargv[kargc] = kcopy;
}
else
{
kargv[kargc] = nullptr;
break;
}
kargc++;
argv++;
} while (arg != nullptr);
kinfoln("Copied %lu arguments from user process", kargc);
size_t stack_size = 0;
for (uint64_t i = 0; i <= kargc; i++)
{
stack_size += sizeof(char*);
if (kargv[i]) { stack_size += strlen(kargv[i]); }
}
if (stack_size >
((TASK_PAGES_IN_STACK / 2) *
PAGE_SIZE)) // FIXME: Maybe we should allocate a larger stack in this case, but still set a larger upper limit.
{
free_kernel_argv_copy();
context->rax = -E2BIG;
return;
}
char** user_argv = (char**)kcalloc(kargc + 1, sizeof(char*));
if (!user_argv)
{
free_kernel_argv_copy();
context->rax = -ENOMEM;
return;
}
Interrupts::disable();
ASSERT(!Interrupts::are_enabled()); // This part is pretty sensitive.
@ -129,9 +218,29 @@ void sys_exec(Context* context, const char* pathname)
if (file.close_on_exec()) { file.close(); }
}
task->restore_context(context);
for (uint64_t i = 0; i <= kargc; i++)
{
if (kargv[i])
{
push_on_user_stack(&task->regs.rsp, kargv[i], strlen(kargv[i]) + 1);
user_argv[i] = (char*)task->regs.rsp;
}
else
user_argv[i] = nullptr;
}
push_on_user_stack(&task->regs.rsp, (char*)user_argv, (kargc + 1) * sizeof(char*));
task->regs.rdi = kargc; // argc
task->regs.rsi = task->regs.rsp; // argv
task->regs.rsp &= (UINT64_MAX ^ 15); // align it
free_kernel_argv_copy();
kfree(user_argv);
kfree(kpathname);
task->restore_context(context);
return;
}

View File

@ -6,8 +6,6 @@ extern _fini
extern initialize_libc
extern exit
extern __argv
global _start
_start:
; Set up end of the stack frame linked list.
@ -16,12 +14,15 @@ _start:
push rbp ; rbp=0
mov rbp, rsp
push rdi
push rsi
call initialize_libc
call _init
mov rdi, 0 ; argc = 0
mov rsi, __argv ; Dummy argv which is equal to {NULL}
pop rsi ; argv
pop rdi ; argc
call main

View File

@ -8,6 +8,7 @@ extern int errno;
#define ENOENT 2 // No such file or directory
#define ESRCH 3 // No such process
#define EINTR 4 // Interrupted system call. Not implemented.
#define E2BIG 7 // Argument list too long
#define ENOEXEC 8 // Exec format error
#define EBADF 9 // Bad file descriptor
#define EAGAIN 11 // Resource temporarily unavailable

View File

@ -13,7 +13,7 @@
#define SYS_read 9
#define SYS_close 10
#define SYS_seek 11
#define SYS_exec 12
#define SYS_execv 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15

View File

@ -20,9 +20,8 @@ extern "C"
{
#endif
/* Executes the program program. On success, does not return. The second parameter (arguments) is not implemented
* for now. You can pass NULL to it. */
int execv(const char* program, char* const[]);
/* Executes the program program, passing the arguments in the argument list argv. On success, does not return. */
int execv(const char* program, char* const argv[]);
/* Not implemented. */
int execve(const char*, char* const[], char* const[]);

View File

@ -4,8 +4,6 @@
#include <stdlib.h>
#include <unistd.h>
__lc_used const char* __argv[] = {NULL}; // For now.
static void terminate_libc()
{
fclose(stdout);

View File

@ -261,6 +261,7 @@ extern "C"
case ENOENT: return "No such file or directory";
case ESRCH: return "No such process";
case EINTR: return "Interrupted system call";
case E2BIG: return "Argument list too long";
case ENOEXEC: return "Exec format error";
case EBADF: return "Bad file descriptor";
case EAGAIN: return "Resource temporarily unavailable";

View File

@ -18,10 +18,10 @@ extern "C" long syscall(long number, ...)
case SYS_exit:
case SYS_getprocid:
case SYS_close:
case SYS_exec:
case SYS_mkdir:
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
case SYS_munmap:
case SYS_execv:
case SYS_access:
case SYS_fstat:
case SYS_stat:

View File

@ -8,9 +8,9 @@
extern "C"
{
int execv(const char* program, char* const[])
int execv(const char* program, char* const argv[])
{
return (int)syscall(SYS_exec, program);
return (int)syscall(SYS_execv, program, argv);
}
int execve(const char*, char* const[], char* const[])