Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion arch/lkl/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ endif

LDFLAGS_vmlinux += -r
LKL_ENTRY_POINTS := lkl_start_kernel lkl_sys_halt lkl_syscall lkl_trigger_irq \
lkl_get_free_irq lkl_put_irq
lkl_get_free_irq lkl_put_irq lkl_create_syscall_thread \
lkl_stop_syscall_thread

core-y += arch/lkl/kernel/

Expand Down
2 changes: 1 addition & 1 deletion arch/lkl/include/asm/irq.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef _ASM_LKL_IRQ_H
#define _ASM_LKL_IRQ_H

#define NR_IRQS ((int)sizeof(long))
#define NR_IRQS ((int)sizeof(long) * 8)

#include <uapi/asm/irq.h>

Expand Down
2 changes: 1 addition & 1 deletion arch/lkl/include/asm/syscalls.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef _ASM_LKL_SYSCALLS_H
#define _ASM_LKL_SYSCALLS_H

int run_syscalls(void);
int initial_syscall_thread(void *);
long lkl_syscall(long no, long *params);

#define sys_mmap sys_ni_syscall
Expand Down
4 changes: 4 additions & 0 deletions arch/lkl/include/asm/unistd.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include <uapi/asm/unistd.h>

#define __NR_create_syscall_thread __NR_arch_specific_syscall

__SYSCALL(__NR_create_syscall_thread, sys_create_syscall_thread)

#define __SC_ASCII(t, a) #t "," #a

#define __ASCII_MAP0(m,...)
Expand Down
10 changes: 10 additions & 0 deletions arch/lkl/include/uapi/asm/host_ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ struct lkl_sem_t;
* thread handle or NULL if the thread could not be created
* @thread_exit - terminates the current thread
*
* @tls_alloc - allocate a thread local storage key; returns 0 if succesful
* @tls_free - frees a thread local storage key; returns 0 if succesful
* @tls_set - associate data to the thread local storage key; returns 0 if succesful
* @tls_get - return data associated with the thread local storage key or NULL on error
*
* @mem_alloc - allocate memory
* @mem_free - free memory
*
Expand Down Expand Up @@ -70,6 +75,11 @@ struct lkl_host_operations {
int (*thread_create)(void (*f)(void *), void *arg);
void (*thread_exit)(void);

int (*tls_alloc)(unsigned int *key);
int (*tls_free)(unsigned int key);
int (*tls_set)(unsigned int key, void *data);
void *(*tls_get)(unsigned int key);

void* (*mem_alloc)(unsigned long);
void (*mem_free)(void *);

Expand Down
8 changes: 1 addition & 7 deletions arch/lkl/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,10 @@ void __init setup_arch(char **cl)

int run_init_process(const char *init_filename)
{
lkl_ops->sem_up(init_sem);

run_syscalls();
initial_syscall_thread(init_sem);

kernel_halt();

/* We want to kill init without panic()ing */
init_pid_ns.child_reaper = 0;
do_exit(0);

return 0;
}

Expand Down
234 changes: 198 additions & 36 deletions arch/lkl/kernel/syscalls.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
#include <linux/net.h>
#include <linux/task_work.h>
#include <linux/syscalls.h>
#include <linux/kthread.h>
#include <asm/host_ops.h>
#include <asm/syscalls.h>

struct syscall_thread_data;
static asmlinkage long sys_create_syscall_thread(struct syscall_thread_data *);

typedef long (*syscall_handler_t)(long arg1, ...);

#undef __SYSCALL
Expand All @@ -23,15 +27,15 @@ syscall_handler_t syscall_table[__NR_syscalls] = {

struct syscall {
long no, *params, ret;
void *sem;
};

static struct syscall_thread_data {
wait_queue_head_t wqh;
struct syscall *s;
void *mutex, *completion;
} syscall_thread_data;

int irq;
/* to be accessed from Linux context only */
wait_queue_head_t wqh;
} default_syscall_thread_data;

static struct syscall *dequeue_syscall(struct syscall_thread_data *data)
{
Expand All @@ -53,19 +57,52 @@ static long run_syscall(struct syscall *s)

task_work_run();

if (s->sem)
lkl_ops->sem_up(s->sem);
return ret;
}

int run_syscalls(void)
static irqreturn_t syscall_irq_handler(int irq, void *dev_id)
{
struct syscall_thread_data *data = (struct syscall_thread_data *)dev_id;

wake_up(&data->wqh);

return IRQ_HANDLED;
}

int syscall_thread(void *_data)
{
struct syscall_thread_data *data = &syscall_thread_data;
struct syscall_thread_data *data;
struct syscall *s;
int ret;
static int count;

data = (struct syscall_thread_data *)_data;
init_waitqueue_head(&data->wqh);

snprintf(current->comm, sizeof(current->comm), "ksyscalld%d", count++);

current->flags &= ~PF_KTHREAD;
data->irq = lkl_get_free_irq("syscall");
if (data->irq < 0) {
pr_err("lkl: %s: failed to allocate irq: %d\n", __func__,
data->irq);
return data->irq;
}

ret = request_irq(data->irq, syscall_irq_handler, 0, current->comm,
data);
if (ret) {
pr_err("lkl: %s: failed to request irq %d: %d\n", __func__,
data->irq, ret);
lkl_put_irq(data->irq, "syscall");
data->irq = -1;
return ret;
}

snprintf(current->comm, sizeof(current->comm), "init");
pr_info("lkl: syscall thread %s initialized (irq%d)\n", current->comm,
data->irq);

/* system call thread is ready */
lkl_ops->sem_up(data->completion);

while (1) {
wait_event(data->wqh, (s = dequeue_syscall(data)) != NULL);
Expand All @@ -74,48 +111,148 @@ int run_syscalls(void)
break;

run_syscall(s);

lkl_ops->sem_up(data->completion);
}

free_irq(data->irq, data);
lkl_put_irq(data->irq, "syscall");

s->ret = 0;
lkl_ops->sem_up(s->sem);
lkl_ops->sem_up(data->completion);

return 0;
}

static irqreturn_t syscall_irq_handler(int irq, void *dev_id)
static unsigned int syscall_thread_data_key;

static int syscall_thread_data_init(struct syscall_thread_data *data,
void *completion)
{
wake_up(&syscall_thread_data.wqh);
data->s = NULL;

return IRQ_HANDLED;
}
data->mutex = lkl_ops->sem_alloc(1);
if (!data->mutex)
return -ENOMEM;

static struct irqaction syscall_irqaction = {
.handler = syscall_irq_handler,
.flags = IRQF_NOBALANCING,
.dev_id = &syscall_irqaction,
.name = "syscall"
};
if (!completion)
data->completion = lkl_ops->sem_alloc(0);
else
data->completion = completion;
if (!data->completion) {
lkl_ops->sem_free(data->mutex);
return -ENOMEM;
}

static int syscall_irq;
return 0;
}

long lkl_syscall(long no, long *params)
{
struct syscall_thread_data *data = &syscall_thread_data;
struct syscall_thread_data *data = NULL;
struct syscall s;

if (lkl_ops->tls_get)
data = lkl_ops->tls_get(syscall_thread_data_key);
if (!data)
data = &default_syscall_thread_data;

s.no = no;
s.params = params;
s.sem = data->completion;

lkl_ops->sem_down(data->mutex);
data->s = &s;
lkl_trigger_irq(syscall_irq);
lkl_trigger_irq(data->irq);
lkl_ops->sem_down(data->completion);
lkl_ops->sem_up(data->mutex);

if (no == __NR_reboot) {
lkl_ops->sem_free(data->completion);
lkl_ops->sem_free(data->mutex);
if (data != &default_syscall_thread_data)
lkl_ops->mem_free(data);
}

return s.ret;
}

static int syscall_threads;

int lkl_create_syscall_thread(void)
{
struct syscall_thread_data *data;
long params[6], ret;

if (!lkl_ops->tls_set)
return -ENOTSUPP;

data = lkl_ops->mem_alloc(sizeof(*data));
if (!data)
return -ENOMEM;

ret = syscall_thread_data_init(data, NULL);
if (ret < 0) {
lkl_ops->mem_free(data);
return ret;
}

params[0] = (long)data;
ret = lkl_syscall(__NR_create_syscall_thread, params);
if (ret < 0) {
lkl_ops->sem_free(data->completion);
lkl_ops->sem_free(data->mutex);
lkl_put_irq(data->irq, "syscall");
lkl_ops->mem_free(data);
return ret;
}

lkl_ops->sem_down(data->completion);

ret = lkl_ops->tls_set(syscall_thread_data_key, data);
if (ret < 0) {
lkl_ops->sem_free(data->completion);
lkl_ops->sem_free(data->mutex);
lkl_put_irq(data->irq, "syscall");
lkl_ops->mem_free(data);
return ret;
}

__sync_fetch_and_add(&syscall_threads, 1);

return 0;
}

int lkl_stop_syscall_thread(void)
{
struct syscall_thread_data *data;
long params[6] = { 0, };
int ret;

if (!lkl_ops->tls_get || !lkl_ops->tls_set)
return -ENOTSUPP;

data = lkl_ops->tls_get(syscall_thread_data_key);
if (!data || data == &default_syscall_thread_data)
return -EINVAL;

ret = lkl_syscall(__NR_reboot, params);
if (ret < 0)
return ret;

ret = lkl_ops->tls_set(syscall_thread_data_key, NULL);
if (ret)
return ret;

params[0] = 0;
params[3] = WEXITED;
ret = lkl_syscall(__NR_waitid, params);
if (ret < 0)
return ret;

__sync_fetch_and_sub(&syscall_threads, 1);
return 0;
}

asmlinkage
ssize_t sys_lkl_pwrite64(unsigned int fd, const char *buf, size_t count,
off_t pos_hi, off_t pos_lo)
Expand All @@ -130,19 +267,44 @@ ssize_t sys_lkl_pread64(unsigned int fd, char *buf, size_t count,
return sys_pread64(fd, buf, count, ((loff_t)pos_hi << 32) + pos_lo);
}

int __init syscall_init(void)
static asmlinkage long
sys_create_syscall_thread(struct syscall_thread_data *data)
{
struct syscall_thread_data *data = &syscall_thread_data;

init_waitqueue_head(&data->wqh);
data->mutex = lkl_ops->sem_alloc(1);
data->completion = lkl_ops->sem_alloc(0);
BUG_ON(!data->mutex || !data->completion);
pid_t pid;

syscall_irq = lkl_get_free_irq("syscall");
setup_irq(syscall_irq, &syscall_irqaction);
pid = kernel_thread(syscall_thread, data, CLONE_VM | CLONE_FS |
CLONE_FILES | SIGCHLD);
if (pid < 0)
return pid;

pr_info("lkl: syscall interface initialized (irq%d)\n", syscall_irq);
return 0;
}
late_initcall(syscall_init);

int initial_syscall_thread(void *sem)
{
int ret = 0;

if (lkl_ops->tls_alloc)
ret = lkl_ops->tls_alloc(&syscall_thread_data_key);
if (ret)
return ret;

init_pid_ns.child_reaper = 0;

ret = syscall_thread_data_init(&default_syscall_thread_data, sem);
if (ret) {
if (lkl_ops->tls_free)
lkl_ops->tls_free(syscall_thread_data_key);
return ret;
}

ret = syscall_thread(&default_syscall_thread_data);
if (lkl_ops->tls_free) {
lkl_ops->tls_free(syscall_thread_data_key);
__sync_synchronize();
BUG_ON(syscall_threads);
}

return ret;
}

Loading