Skip to content

Commit

Permalink
kernel+userland(lib): implement auxiliary vector
Browse files Browse the repository at this point in the history
  • Loading branch information
mosmeh committed Sep 1, 2024
1 parent fd073d6 commit 4def15e
Show file tree
Hide file tree
Showing 13 changed files with 153 additions and 56 deletions.
3 changes: 2 additions & 1 deletion common/extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ static inline int32_t divmodi64(int64_t a, int32_t b, int32_t* rem) {
: "=a"(q), "=d"(r)
: "d"((int32_t)(a >> 32)),
"a"((int32_t)(a & 0xffffffff)), [b] "rm"(b));
*rem = r;
if (rem)
*rem = r;
return q;
}

Expand Down
24 changes: 24 additions & 0 deletions kernel/api/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,27 @@ typedef struct {
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4

typedef struct {
uint32_t a_type;
union {
uint32_t a_val;
} a_un;
} Elf32_auxv_t;

#define AT_NULL 0 // End of vector
#define AT_IGNORE 1 // Entry should be ignored
#define AT_PHDR 3 // Program headers for program
#define AT_PHENT 4 // Size of program header entry
#define AT_PHNUM 5 // Number of program headers
#define AT_PAGESZ 6 // System page size
#define AT_ENTRY 9 // Entry point of program
#define AT_UID 11 // Real uid
#define AT_EUID 12 // Effective uid
#define AT_GID 13 // Real gid
#define AT_EGID 14 // Effective gid
#define AT_HWCAP 16 // Machine-dependent hints about processor capabilities.
#define AT_CLKTCK 17 // Frequency of times()
#define AT_SECURE 23 // Boolean, was exec setuid-like?
#define AT_RANDOM 25 // Address of 16 random bytes.
#define AT_EXECFN 31 // Filename of executable.
5 changes: 2 additions & 3 deletions kernel/api/sys/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,5 @@
#define SYS_accept4 364
#define SYS_shutdown 373

// Custom syscalls
#define SYS_sysconf 1024
#define SYS_dbgprint 1025
// Custom syscall
#define SYS_dbgprint 1024
81 changes: 68 additions & 13 deletions kernel/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include <kernel/api/sys/limits.h>
#include <kernel/asm_wrapper.h>
#include <kernel/boot_defs.h>
#include <kernel/cpu.h>
#include <kernel/gdt.h>
#include <kernel/panic.h>
#include <kernel/safe_string.h>
#include <kernel/task.h>
#include <kernel/time.h>

struct string_vec {
size_t count;
Expand Down Expand Up @@ -227,9 +229,7 @@ static int execve(const char* pathname, struct string_vec* argv,
}
vm_enter(vm);

struct ptr_vec envp_ptrs = (struct ptr_vec){0};
struct ptr_vec argv_ptrs = (struct ptr_vec){0};

uintptr_t phdr_virt_addr = 0;
Elf32_Phdr* phdr = (Elf32_Phdr*)(exe_buf + ehdr->e_phoff);
for (size_t i = 0; i < ehdr->e_phnum; ++i, ++phdr) {
if (phdr->p_type != PT_LOAD)
Expand All @@ -239,6 +239,10 @@ static int execve(const char* pathname, struct string_vec* argv,
goto fail_vm;
}

if (phdr->p_offset <= ehdr->e_phoff &&
ehdr->e_phoff < phdr->p_offset + phdr->p_filesz)
phdr_virt_addr = ehdr->e_phoff - phdr->p_offset + phdr->p_vaddr;

uintptr_t region_start = round_down(phdr->p_vaddr, PAGE_SIZE);
uintptr_t region_end =
round_up(phdr->p_vaddr + phdr->p_memsz, PAGE_SIZE);
Expand All @@ -263,10 +267,6 @@ static int execve(const char* pathname, struct string_vec* argv,
}
}

uint32_t entry_point = ehdr->e_entry;
kfree(exe_buf);
exe_buf = NULL;

void* stack_region =
vm_alloc(2 * PAGE_SIZE + STACK_SIZE, VM_READ | VM_WRITE | VM_USER);
if (IS_ERR(stack_region)) {
Expand All @@ -288,21 +288,73 @@ static int execve(const char* pathname, struct string_vec* argv,
uintptr_t sp = stack_base + STACK_SIZE;
memset((void*)stack_base, 0, STACK_SIZE);

ret = push_value(&sp, stack_base, 0); // Sentinel
if (IS_ERR(ret))
goto fail_vm;

struct ptr_vec envp_ptrs = (struct ptr_vec){0};
uintptr_t env_end = sp;
ret = push_strings(&sp, stack_base, &envp_ptrs, envp);
string_vec_destroy(envp);
if (IS_ERR(ret))
goto fail_vm;
uintptr_t env_start = sp;

struct ptr_vec argv_ptrs = (struct ptr_vec){0};
uintptr_t arg_end = sp;
ret = push_strings(&sp, stack_base, &argv_ptrs, argv);
string_vec_destroy(argv);
if (IS_ERR(ret))
goto fail_vm;
uintptr_t arg_start = sp;

ret = push_value(&sp, stack_base, 0);
uint32_t random[4];
nread = random_get(random, sizeof(random));
if (IS_ERR(nread)) {
ret = nread;
goto fail_vm;
}
for (size_t i = 0; i < ARRAY_SIZE(random); ++i) {
ret = push_value(&sp, stack_base, random[i]);
if (IS_ERR(ret))
goto fail_vm;
}
uintptr_t random_ptr = sp;

sp = round_down(sp, 16);

uintptr_t entry_point = ehdr->e_entry;
Elf32_auxv_t auxv[] = {
{AT_PHDR, {phdr_virt_addr}},
{AT_PHENT, {ehdr->e_phentsize}},
{AT_PHNUM, {ehdr->e_phnum}},
{AT_PAGESZ, {PAGE_SIZE}},
{AT_ENTRY, {entry_point}},
{AT_UID, {0}},
{AT_EUID, {0}},
{AT_GID, {0}},
{AT_EGID, {0}},
{AT_HWCAP, {cpu_get_bsp()->features[0]}},
{AT_CLKTCK, {CLK_TCK}},
{AT_SECURE, {0}},
{AT_RANDOM, {random_ptr}},
{AT_EXECFN, {arg_start}},
{AT_NULL, {0}},
};

kfree(exe_buf);
exe_buf = NULL;

for (ssize_t i = ARRAY_SIZE(auxv) - 1; i >= 0; --i) {
ret = push_value(&sp, stack_base, auxv[i].a_un.a_val);
if (IS_ERR(ret))
goto fail_vm;
ret = push_value(&sp, stack_base, auxv[i].a_type);
if (IS_ERR(ret))
goto fail_vm;
}

ret = push_value(&sp, stack_base, 0); // Sentinel
if (IS_ERR(ret))
goto fail_vm;
ret = push_ptrs(&sp, stack_base, &envp_ptrs);
Expand All @@ -311,7 +363,7 @@ static int execve(const char* pathname, struct string_vec* argv,
uintptr_t user_envp = sp;
ptr_vec_destroy(&envp_ptrs);

ret = push_value(&sp, stack_base, 0);
ret = push_value(&sp, stack_base, 0); // Sentinel
if (IS_ERR(ret))
goto fail_vm;
ret = push_ptrs(&sp, stack_base, &argv_ptrs);
Expand All @@ -320,15 +372,18 @@ static int execve(const char* pathname, struct string_vec* argv,
uintptr_t user_argv = sp;
ptr_vec_destroy(&argv_ptrs);

sp = round_down(sp, 16);
ret = push_value(&sp, stack_base, argv->count);
if (IS_ERR(ret))
goto fail_vm;

ret = push_value(&sp, stack_base, user_envp);
// Arguments of the entry point
ret = push_value(&sp, stack_base, user_envp); // envp
if (IS_ERR(ret))
goto fail_vm;
ret = push_value(&sp, stack_base, user_argv);
ret = push_value(&sp, stack_base, user_argv); // argv
if (IS_ERR(ret))
goto fail_vm;
ret = push_value(&sp, stack_base, argv->count);
ret = push_value(&sp, stack_base, argv->count); // argc
if (IS_ERR(ret))
goto fail_vm;
ret = push_value(&sp, stack_base, 0); // fake return address
Expand Down
20 changes: 0 additions & 20 deletions kernel/syscall/syscall.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "syscall.h"
#include <kernel/api/sys/limits.h>
#include <kernel/api/sys/reboot.h>
#include <kernel/api/sys/syscall.h>
#include <kernel/api/unistd.h>
Expand Down Expand Up @@ -48,25 +47,6 @@ int sys_reboot(int magic, int magic2, int op, void* user_arg) {
}
}

long sys_sysconf(int name) {
switch (name) {
case _SC_ARG_MAX:
return ARG_MAX;
case _SC_CLK_TCK:
return CLK_TCK;
case _SC_MONOTONIC_CLOCK:
return 1;
case _SC_OPEN_MAX:
return OPEN_MAX;
case _SC_PAGESIZE:
return PAGE_SIZE;
case _SC_SYMLOOP_MAX:
return SYMLOOP_MAX;
default:
return -EINVAL;
}
}

int sys_uname(struct utsname* user_buf) {
if (copy_to_user(user_buf, utsname(), sizeof(struct utsname)))
return -EFAULT;
Expand Down
2 changes: 0 additions & 2 deletions kernel/syscall/syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
F(listen) \
F(accept4) \
F(shutdown) \
F(sysconf) \
F(dbgprint)

struct registers;
Expand Down Expand Up @@ -138,5 +137,4 @@ int sys_listen(int sockfd, int backlog);
int sys_accept4(int sockfd, struct sockaddr* addr, socklen_t* addrlen,
int flags);
int sys_shutdown(int sockfd, int how);
long sys_sysconf(int name);
int sys_dbgprint(const char* str);
7 changes: 1 addition & 6 deletions userland/fib.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,17 @@ static uint32_t memoized_recursion(uint32_t n) {
return memo[n] = memoized_recursion(n - 1) + memoized_recursion(n - 2);
}

static int clk_tck;

static void measure_and_report(uint32_t (*func)(uint32_t)) {
for (size_t i = 30; i <= MAX_N; ++i) {
clock_t start = clock();
uint32_t res = func(i);
clock_t end = clock();
double elapsed = (double)((end - start) * 1000) / clk_tck;
double elapsed = (double)((end - start) * 1000) / CLOCKS_PER_SEC;
printf("%u%6u ms: %u\n", i, (unsigned)elapsed, res);
}
}

int main(void) {
clk_tck = sysconf(_SC_CLK_TCK);
ASSERT(clk_tck > 0);

puts("memoized recursion:");
measure_and_report(memoized_recursion);

Expand Down
22 changes: 22 additions & 0 deletions userland/lib/crt0.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
#include "errno.h"
#include "stdlib.h"
#include "unistd.h"
#include <common/extra.h>
#include <kernel/api/elf.h>

static uint32_t auxv[32];

unsigned long getauxval(unsigned long type) {
if (type >= ARRAY_SIZE(auxv)) {
errno = ENOENT;
return 0;
}
return auxv[type];
}

int main(int argc, char* const argv[], char* const envp[]);

void _start(int argc, char* const argv[], char* const envp[]) {
environ = (char**)envp;

char** p = environ;
while (*p++)
;
for (Elf32_auxv_t* aux = (Elf32_auxv_t*)p; aux->a_type != AT_NULL; ++aux) {
if (aux->a_type < ARRAY_SIZE(auxv))
auxv[aux->a_type] = aux->a_un.a_val;
}

exit(main(argc, argv, envp));
}
10 changes: 3 additions & 7 deletions userland/lib/stdlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "private.h"
#include "signal.h"
#include "string.h"
#include "sys/auxv.h"
#include "sys/mman.h"
#include "unistd.h"
#include <extra.h>
Expand Down Expand Up @@ -40,16 +41,11 @@ struct malloc_header {
unsigned char data[];
};

static size_t page_size;

void* aligned_alloc(size_t alignment, size_t size) {
if (size == 0)
return NULL;

if (!page_size)
page_size = sysconf(_SC_PAGESIZE);

ASSERT(alignment <= page_size);
ASSERT(alignment <= getauxval(AT_PAGESZ));

size_t data_offset =
round_up(offsetof(struct malloc_header, data), alignment);
Expand Down Expand Up @@ -82,7 +78,7 @@ void* calloc(size_t num, size_t size) {
}

static struct malloc_header* header_from_ptr(void* ptr) {
ASSERT(page_size);
size_t page_size = getauxval(AT_PAGESZ);
uintptr_t addr = round_down((uintptr_t)ptr, page_size);
if ((uintptr_t)ptr - addr < sizeof(struct malloc_header))
addr -= page_size;
Expand Down
5 changes: 5 additions & 0 deletions userland/lib/sys/auxv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

#include <kernel/api/elf.h>

unsigned long getauxval(unsigned long type);
6 changes: 4 additions & 2 deletions userland/lib/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
#include "errno.h"
#include "private.h"
#include "stdio.h"
#include "sys/auxv.h"
#include "sys/times.h"
#include <calendar.h>
#include <common/calendar.h>

clock_t clock(void) {
struct tms tms;
times(&tms);
return tms.tms_utime + tms.tms_stime;
uint64_t ticks = (uint64_t)tms.tms_utime + tms.tms_stime;
return divmodi64(ticks * CLOCKS_PER_SEC, getauxval(AT_CLKTCK), NULL);
}

time_t time(time_t* tloc) {
Expand Down
2 changes: 2 additions & 0 deletions userland/lib/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include <kernel/api/time.h>

#define CLOCKS_PER_SEC 1000000

struct tm {
int tm_sec;
int tm_min;
Expand Down
Loading

0 comments on commit 4def15e

Please sign in to comment.