diff options
author | Richard Braun <rbraun@sceen.net> | 2012-11-09 21:35:49 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2012-11-09 21:40:52 +0100 |
commit | 79b5932c4eea229fca427bc93ba491ffecef10f5 (patch) | |
tree | bf1165e7fa7c2f6232fd8c1e8b6c148b329b42f7 /kern | |
parent | c8ba9280fafe518ada8a6d2a545d6afa2b2dbe23 (diff) |
Implement preliminary thread context
Three new modules are added :
- kern/task: Tasks are thread groups and resource containers for their
threads.
- kern/thread: The well known scheduling unit.
- x86/tcb: The architecture specific thread control block.
The kernel currently loads a single thread context on the main processor.
Diffstat (limited to 'kern')
-rw-r--r-- | kern/kernel.c | 30 | ||||
-rw-r--r-- | kern/task.c | 65 | ||||
-rw-r--r-- | kern/task.h | 58 | ||||
-rw-r--r-- | kern/thread.c | 139 | ||||
-rw-r--r-- | kern/thread.h | 76 |
5 files changed, 365 insertions, 3 deletions
diff --git a/kern/kernel.c b/kern/kernel.c index 52217876..7c83d8d1 100644 --- a/kern/kernel.c +++ b/kern/kernel.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Richard Braun. + * Copyright (c) 2011, 2012 Richard Braun. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,15 +17,39 @@ #include <kern/init.h> #include <kern/kernel.h> +#include <kern/panic.h> +#include <kern/task.h> +#include <kern/thread.h> #include <machine/cpu.h> -void __init -kernel_main(void) +static void __init +kernel_setup(void *arg) { + (void)arg; + + cpu_mp_setup(); + cpu_intr_enable(); for (;;) cpu_idle(); +} + +void __init +kernel_main(void) +{ + struct thread *thread; + int error; + + task_setup(); + thread_setup(); + + error = thread_create(&thread, "core", kernel_task, kernel_setup, NULL); + + if (error) + panic("kernel: unable to create kernel thread"); + + thread_load(thread); /* Never reached */ } diff --git a/kern/task.c b/kern/task.c new file mode 100644 index 00000000..d333776f --- /dev/null +++ b/kern/task.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012 Richard Braun. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <kern/init.h> +#include <kern/kmem.h> +#include <kern/list.h> +#include <kern/stddef.h> +#include <kern/string.h> +#include <kern/task.h> +#include <kern/thread.h> +#include <vm/vm_kmem.h> + +/* + * Kernel task and storage. + */ +static struct task kernel_task_store; +struct task *kernel_task = &kernel_task_store; + +/* + * Cache for allocated tasks. + */ +static struct kmem_cache task_cache; + +/* + * Global list of tasks. + */ +static struct list task_list; + +static void +task_init(struct task *task, const char *name, struct vm_map *map) +{ + list_init(&task->threads); + task->map = map; + strlcpy(task->name, name, sizeof(task->name)); +} + +void __init +task_setup(void) +{ + kmem_cache_init(&task_cache, "task", sizeof(struct task), + 0, NULL, NULL, NULL, 0); + task_init(kernel_task, "x15", kernel_map); + list_init(&task_list); + list_insert(&task_list, &kernel_task->node); +} + +void +task_add_thread(struct task *task, struct thread *thread) +{ + list_insert_tail(&task->threads, &thread->task_node); +} diff --git a/kern/task.h b/kern/task.h new file mode 100644 index 00000000..319651db --- /dev/null +++ b/kern/task.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 Richard Braun. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KERN_TASK_H +#define _KERN_TASK_H + +#include <kern/list.h> + +/* + * Forward declaration. + */ +struct thread; + +/* + * Task name buffer size. + */ +#define TASK_NAME_SIZE 32 + +/* + * Task structure. + */ +struct task { + struct list node; + struct list threads; + struct vm_map *map; + char name[TASK_NAME_SIZE]; +}; + +/* + * The kernel task. + */ +extern struct task *kernel_task; + +/* + * Initialize the task module. + */ +void task_setup(void); + +/* + * Add a thread to a task. + */ +void task_add_thread(struct task *task, struct thread *thread); + +#endif /* _KERN_TASK_H */ diff --git a/kern/thread.c b/kern/thread.c new file mode 100644 index 00000000..24498b01 --- /dev/null +++ b/kern/thread.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2012 Richard Braun. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <kern/error.h> +#include <kern/init.h> +#include <kern/kmem.h> +#include <kern/list.h> +#include <kern/macros.h> +#include <kern/param.h> +#include <kern/stddef.h> +#include <kern/string.h> +#include <kern/thread.h> +#include <machine/cpu.h> +#include <machine/tcb.h> + +/* + * Make sure thread stacks are properly aligned. + */ +#define THREAD_STACK_ALIGN 8 + +/* + * Per processor run queue. + */ +struct thread_runq { + struct list threads; +} __aligned(CPU_L1_SIZE); + +/* + * Per-processor run queues. + */ +static struct thread_runq thread_runqs[MAX_CPUS]; + +/* + * Caches for allocated threads and their stacks. + */ +static struct kmem_cache thread_cache; +static struct kmem_cache thread_stack_cache; + +static void __init +thread_runq_init(struct thread_runq *runq) +{ + list_init(&runq->threads); +} + +void __init +thread_setup(void) +{ + size_t i; + + tcb_setup(); + + kmem_cache_init(&thread_cache, "thread", sizeof(struct thread), + 0, NULL, NULL, NULL, 0); + kmem_cache_init(&thread_stack_cache, "thread_stack", STACK_SIZE, + THREAD_STACK_ALIGN, NULL, NULL, NULL, 0); + + for (i = 0; i < ARRAY_SIZE(thread_runqs); i++) + thread_runq_init(&thread_runqs[i]); +} + +int +thread_create(struct thread **threadp, const char *name, struct task *task, + thread_run_fn_t run_fn, void *arg) +{ + struct thread *thread; + struct tcb *tcb; + void *stack; + int error; + + thread = kmem_cache_alloc(&thread_cache); + + if (thread == NULL) { + error = ERROR_NOMEM; + goto error_thread; + } + + stack = kmem_cache_alloc(&thread_stack_cache); + + if (stack == NULL) { + error = ERROR_NOMEM; + goto error_stack; + } + + error = tcb_create(&tcb, stack, thread); + + if (error) + goto error_tcb; + + if (name == NULL) + name = task->name; + + /* XXX Assign all threads to the main processor for now */ + thread->tcb = tcb; + list_insert_tail(&thread_runqs[0].threads, &thread->runq_node); + task_add_thread(task, thread); + thread->task = task; + thread->stack = stack; + strlcpy(thread->name, name, sizeof(thread->name)); + thread->run_fn = run_fn; + thread->arg = arg; + *threadp = thread; + return 0; + +error_tcb: + kmem_cache_free(&thread_stack_cache, stack); +error_stack: + kmem_cache_free(&thread_cache, thread); +error_thread: + return error; +} + +void __init +thread_load(struct thread *thread) +{ + tcb_load(thread->tcb); +} + +void +thread_main(struct thread *thread) +{ + thread->run_fn(thread->arg); + + for (;;) + cpu_idle(); +} diff --git a/kern/thread.h b/kern/thread.h new file mode 100644 index 00000000..15851ba3 --- /dev/null +++ b/kern/thread.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012 Richard Braun. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _KERN_THREAD_H +#define _KERN_THREAD_H + +#include <kern/list.h> +#include <kern/macros.h> +#include <kern/task.h> +#include <machine/tcb.h> + +/* + * Thread name buffer size. + */ +#define THREAD_NAME_SIZE 32 + +/* + * Type for thread entry point. + */ +typedef void (*thread_run_fn_t)(void *); + +/* + * Thread structure. + */ +struct thread { + struct tcb *tcb; + struct list runq_node; + struct list task_node; + struct task *task; + void *stack; + char name[THREAD_NAME_SIZE]; + thread_run_fn_t run_fn; + void *arg; +}; + +/* + * Initialize the thread module. + */ +void thread_setup(void); + +/* + * Create a thread. + * + * If the given name is null, the task name is used instead. + */ +int thread_create(struct thread **threadp, const char *name, struct task *task, + thread_run_fn_t run_fn, void *arg); + +/* + * Transform into a thread. + * + * This function is used during system initialization by code in "boot context" + * when creating the first thread on their processor. + */ +void __noreturn thread_load(struct thread *thread); + +/* + * Thread entry point. + */ +void __noreturn thread_main(struct thread *thread); + +#endif /* _KERN_THREAD_H */ |