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:
parent
0bad662c2f
commit
7d20c507b1
@ -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_DIR := $(LUNA_ROOT)/apps
|
||||||
APPS_SRC := $(APPS_DIR)/src
|
APPS_SRC := $(APPS_DIR)/src
|
||||||
|
7
apps/src/args.c
Normal file
7
apps/src/args.c
Normal 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]);
|
||||||
|
}
|
@ -50,7 +50,8 @@ int main()
|
|||||||
}
|
}
|
||||||
if (child == 0)
|
if (child == 0)
|
||||||
{
|
{
|
||||||
execv("/bin/sh", NULL);
|
char* argv[] = {"/bin/sh", NULL};
|
||||||
|
execv(argv[0], argv);
|
||||||
perror("execv");
|
perror("execv");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -113,11 +113,15 @@ void command_execute(command* cmd)
|
|||||||
char* buf = malloc(cmd->size + 6);
|
char* buf = malloc(cmd->size + 6);
|
||||||
strlcpy(buf, "/bin/", 6);
|
strlcpy(buf, "/bin/", 6);
|
||||||
strncat(buf, cmd->buffer, cmd->size);
|
strncat(buf, cmd->buffer, cmd->size);
|
||||||
execv(buf, NULL);
|
char* argv[] = {buf, NULL};
|
||||||
|
execv(argv[0], argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
execv(cmd->buffer, NULL);
|
{
|
||||||
|
char* argv[] = {cmd->buffer, NULL};
|
||||||
|
execv(argv[0], argv);
|
||||||
|
}
|
||||||
perror(cmd->buffer);
|
perror(cmd->buffer);
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#define ENOENT 2
|
#define ENOENT 2
|
||||||
#define ESRCH 3
|
#define ESRCH 3
|
||||||
#define EINTR 4
|
#define EINTR 4
|
||||||
|
#define E2BIG 7
|
||||||
#define ENOEXEC 8
|
#define ENOEXEC 8
|
||||||
#define EBADF 9
|
#define EBADF 9
|
||||||
#define EAGAIN 11
|
#define EAGAIN 11
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#define SYS_read 9
|
#define SYS_read 9
|
||||||
#define SYS_close 10
|
#define SYS_close 10
|
||||||
#define SYS_seek 11
|
#define SYS_seek 11
|
||||||
#define SYS_exec 12
|
#define SYS_execv 12
|
||||||
#define SYS_fcntl 13
|
#define SYS_fcntl 13
|
||||||
#define SYS_mprotect 14
|
#define SYS_mprotect 14
|
||||||
#define SYS_clock 15
|
#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_read(Context* context, int fd, size_t size, char* buffer);
|
||||||
void sys_close(Context* context, int fd);
|
void sys_close(Context* context, int fd);
|
||||||
void sys_seek(Context* context, int fd, long offset, int whence);
|
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_fcntl(Context* context, int fd, int command, uintptr_t arg);
|
||||||
void sys_mprotect(Context* context, void* address, size_t size, int prot);
|
void sys_mprotect(Context* context, void* address, size_t size, int prot);
|
||||||
void sys_clock(Context* context);
|
void sys_clock(Context* context);
|
||||||
|
@ -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_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_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_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_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_mprotect: sys_mprotect(context, (void*)context->rdi, context->rsi, (int)context->rdx); break;
|
||||||
case SYS_clock: sys_clock(context); break;
|
case SYS_clock: sys_clock(context); break;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "interrupts/Interrupts.h"
|
#include "interrupts/Interrupts.h"
|
||||||
#include "log/Log.h"
|
#include "log/Log.h"
|
||||||
|
#include "memory/Memory.h"
|
||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "memory/PMM.h"
|
#include "memory/PMM.h"
|
||||||
#include "memory/VMM.h"
|
#include "memory/VMM.h"
|
||||||
@ -56,7 +57,16 @@ void sys_fork(Context* context)
|
|||||||
return;
|
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);
|
char* kpathname = strdup_from_user(pathname);
|
||||||
if (!kpathname)
|
if (!kpathname)
|
||||||
@ -97,6 +107,85 @@ void sys_exec(Context* context, const char* pathname)
|
|||||||
return;
|
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();
|
Interrupts::disable();
|
||||||
ASSERT(!Interrupts::are_enabled()); // This part is pretty sensitive.
|
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(); }
|
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);
|
kfree(kpathname);
|
||||||
|
|
||||||
|
task->restore_context(context);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
@ -6,8 +6,6 @@ extern _fini
|
|||||||
extern initialize_libc
|
extern initialize_libc
|
||||||
extern exit
|
extern exit
|
||||||
|
|
||||||
extern __argv
|
|
||||||
|
|
||||||
global _start
|
global _start
|
||||||
_start:
|
_start:
|
||||||
; Set up end of the stack frame linked list.
|
; Set up end of the stack frame linked list.
|
||||||
@ -16,12 +14,15 @@ _start:
|
|||||||
push rbp ; rbp=0
|
push rbp ; rbp=0
|
||||||
mov rbp, rsp
|
mov rbp, rsp
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
push rsi
|
||||||
|
|
||||||
call initialize_libc
|
call initialize_libc
|
||||||
|
|
||||||
call _init
|
call _init
|
||||||
|
|
||||||
mov rdi, 0 ; argc = 0
|
pop rsi ; argv
|
||||||
mov rsi, __argv ; Dummy argv which is equal to {NULL}
|
pop rdi ; argc
|
||||||
|
|
||||||
call main
|
call main
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ extern int errno;
|
|||||||
#define ENOENT 2 // No such file or directory
|
#define ENOENT 2 // No such file or directory
|
||||||
#define ESRCH 3 // No such process
|
#define ESRCH 3 // No such process
|
||||||
#define EINTR 4 // Interrupted system call. Not implemented.
|
#define EINTR 4 // Interrupted system call. Not implemented.
|
||||||
|
#define E2BIG 7 // Argument list too long
|
||||||
#define ENOEXEC 8 // Exec format error
|
#define ENOEXEC 8 // Exec format error
|
||||||
#define EBADF 9 // Bad file descriptor
|
#define EBADF 9 // Bad file descriptor
|
||||||
#define EAGAIN 11 // Resource temporarily unavailable
|
#define EAGAIN 11 // Resource temporarily unavailable
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#define SYS_read 9
|
#define SYS_read 9
|
||||||
#define SYS_close 10
|
#define SYS_close 10
|
||||||
#define SYS_seek 11
|
#define SYS_seek 11
|
||||||
#define SYS_exec 12
|
#define SYS_execv 12
|
||||||
#define SYS_fcntl 13
|
#define SYS_fcntl 13
|
||||||
#define SYS_mprotect 14
|
#define SYS_mprotect 14
|
||||||
#define SYS_clock 15
|
#define SYS_clock 15
|
||||||
|
@ -20,9 +20,8 @@ extern "C"
|
|||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Executes the program program. On success, does not return. The second parameter (arguments) is not implemented
|
/* Executes the program program, passing the arguments in the argument list argv. On success, does not return. */
|
||||||
* for now. You can pass NULL to it. */
|
int execv(const char* program, char* const argv[]);
|
||||||
int execv(const char* program, char* const[]);
|
|
||||||
|
|
||||||
/* Not implemented. */
|
/* Not implemented. */
|
||||||
int execve(const char*, char* const[], char* const[]);
|
int execve(const char*, char* const[], char* const[]);
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
__lc_used const char* __argv[] = {NULL}; // For now.
|
|
||||||
|
|
||||||
static void terminate_libc()
|
static void terminate_libc()
|
||||||
{
|
{
|
||||||
fclose(stdout);
|
fclose(stdout);
|
||||||
|
@ -261,6 +261,7 @@ extern "C"
|
|||||||
case ENOENT: return "No such file or directory";
|
case ENOENT: return "No such file or directory";
|
||||||
case ESRCH: return "No such process";
|
case ESRCH: return "No such process";
|
||||||
case EINTR: return "Interrupted system call";
|
case EINTR: return "Interrupted system call";
|
||||||
|
case E2BIG: return "Argument list too long";
|
||||||
case ENOEXEC: return "Exec format error";
|
case ENOEXEC: return "Exec format error";
|
||||||
case EBADF: return "Bad file descriptor";
|
case EBADF: return "Bad file descriptor";
|
||||||
case EAGAIN: return "Resource temporarily unavailable";
|
case EAGAIN: return "Resource temporarily unavailable";
|
||||||
|
@ -18,10 +18,10 @@ extern "C" long syscall(long number, ...)
|
|||||||
case SYS_exit:
|
case SYS_exit:
|
||||||
case SYS_getprocid:
|
case SYS_getprocid:
|
||||||
case SYS_close:
|
case SYS_close:
|
||||||
case SYS_exec:
|
|
||||||
case SYS_mkdir:
|
case SYS_mkdir:
|
||||||
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
|
case SYS_sleep: result = __luna_syscall1(number, va_arg(ap, arg)); break;
|
||||||
case SYS_munmap:
|
case SYS_munmap:
|
||||||
|
case SYS_execv:
|
||||||
case SYS_access:
|
case SYS_access:
|
||||||
case SYS_fstat:
|
case SYS_fstat:
|
||||||
case SYS_stat:
|
case SYS_stat:
|
||||||
|
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
extern "C"
|
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[])
|
int execve(const char*, char* const[], char* const[])
|
||||||
|
Loading…
Reference in New Issue
Block a user