kernel, linker, libc: Initial, probably horribly broken, support for some TLS situations

This commit is contained in:
K. Lange 2021-02-16 18:44:31 +09:00
parent 1c2de4d888
commit 230870ad7b
15 changed files with 196 additions and 10 deletions

View File

@ -101,6 +101,7 @@ KERNEL_OBJS += $(patsubst %.c,%.o,$(wildcard kernel/*/*/*.c))
##
# Kernel objects from kernel/ assembly sources
KERNEL_ASMOBJS = $(filter-out kernel/symbols.o,$(patsubst %.S,%.o,$(wildcard kernel/*.S)))
HEADERS = $(wildcard base/usr/include/kernel/*.h base/usr/include/kernel/*/*.h)
# Kernel
@ -141,7 +142,6 @@ fatbase/mod:
##
# Modules need to be installed on the boot image
MODULES = $(patsubst modules/%.c,fatbase/mod/%.ko,$(wildcard modules/*.c))
HEADERS = $(wildcard base/usr/include/kernel/*.h base/usr/include/kernel/*/*.h)
fatbase/mod/%.ko: modules/%.c ${HEADERS} | fatbase/mod
${KCC} -nostdlib ${KCFLAGS} -c -o $@ $<

37
apps/test-tls.c Normal file
View File

@ -0,0 +1,37 @@
#include <stdio.h>
#include <pthread.h>
#include <sys/sysfunc.h>
__thread int myvalue;
void * getaddressinthread(void * _unused) {
fprintf(stderr, "in thread before:\n");
fprintf(stderr, "&myvalue = %p\n", (void*)&myvalue);
fprintf(stderr, "myvalue = %d\n", myvalue);
myvalue = 1234;
fprintf(stderr, "in thread after:\n");
fprintf(stderr, "&myvalue = %p\n", (void*)&myvalue);
fprintf(stderr, "myvalue = %d\n", myvalue);
return NULL;
}
int main(int argc, char * argv[]) {
myvalue = 42;
fprintf(stderr, "main thread before:\n");
fprintf(stderr, "&myvalue = %p\n", (void*)&myvalue);
fprintf(stderr, "myvalue = %d\n", myvalue);
pthread_t mythread;
pthread_create(&mythread, NULL, getaddressinthread, NULL);
void * retval;
pthread_join(mythread, &retval);
fprintf(stderr, "main thread after:\n");
fprintf(stderr, "&myvalue = %p\n", (void*)&myvalue);
fprintf(stderr, "myvalue = %d\n", myvalue);
return 0;
}

View File

@ -35,6 +35,8 @@ typedef struct thread {
uint8_t padding[32]; /* I don't know */
page_directory_t * page_directory; /* Page Directory */
uintptr_t gsbase;
} thread_t;
/* Portable image struct */

View File

@ -75,6 +75,8 @@ extern uint8_t startswith(const char * str, const char * accept);
extern void gdt_install(void);
extern void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran);
extern void set_kernel_stack(uintptr_t stack);
extern void gdt_set_gsbase(uintptr_t base);
extern uintptr_t gdt_get_gsbase(void);
/* IDT */
extern void idt_install(void);
@ -86,7 +88,7 @@ extern void idt_set_gate(uint8_t num, void (*base)(void), uint16_t sel, uint8_t
* the correct offsets as well.
*/
struct regs {
unsigned int gs, fs, es, ds;
unsigned int _unused, fs, es, ds;
unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
unsigned int int_no, err_code;
unsigned int eip, cs, eflags, useresp, ss;

View File

@ -12,6 +12,12 @@ typedef struct {
} pthread_t;
typedef unsigned int pthread_attr_t;
typedef struct {
int volatile atomic_lock;
int volatile readers;
int writerPid;
} pthread_rwlock_t;
extern int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg);
extern void pthread_exit(void * value);
extern int pthread_kill(pthread_t thread, int sig);
@ -38,5 +44,10 @@ extern int pthread_mutex_destroy(pthread_mutex_t *mutex);
extern int pthread_attr_init(pthread_attr_t *attr);
extern int pthread_attr_destroy(pthread_attr_t *attr);
extern int pthread_rwlock_init(pthread_rwlock_t * lock, void * args);
extern int pthread_rwlock_wrlock(pthread_rwlock_t * lock);
extern int pthread_rwlock_rdlock(pthread_rwlock_t * lock);
extern int pthread_rwlock_unlock(pthread_rwlock_t * lock);
extern int pthread_rwlock_destroy(pthread_rwlock_t * lock);
_End_C_Header

View File

@ -23,6 +23,7 @@
#define TOARU_SYS_FUNC_THREADNAME 11
#define TOARU_SYS_FUNC_DEBUGPRINT 12
#define TOARU_SYS_FUNC_SETVGACURSOR 13
#define TOARU_SYS_FUNC_SETGSBASE 14
_Begin_C_Header
extern int sysfunc(int command, char ** args);

View File

@ -30,9 +30,9 @@ typedef struct {
/* In the future we may need to put a lock on the access of this */
static struct {
gdt_entry_t entries[6];
gdt_pointer_t pointer;
tss_entry_t tss;
gdt_entry_t entries[7];
gdt_pointer_t pointer;
tss_entry_t tss;
} gdt __attribute__((used));
extern void gdt_flush(uintptr_t);
@ -53,6 +53,17 @@ void gdt_set_gate(uint8_t num, uint64_t base, uint64_t limit, uint8_t access, ui
ENTRY(num).access = access;
}
void gdt_set_gsbase(uintptr_t base) {
ENTRY(6).base_low = (base & 0xFFFF);
ENTRY(6).base_middle = (base >> 16) & 0xFF;
ENTRY(6).base_high = (base >> 24) & 0xFF;
asm volatile ("mov %0, %%gs" :: "r"((6 << 3) | 0x3));
}
uintptr_t gdt_get_gsbase(void) {
return (ENTRY(6).base_low) | (ENTRY(6).base_middle << 16) | (ENTRY(6).base_high << 24);
}
static void write_tss(int32_t num, uint16_t ss0, uint32_t esp0);
void gdt_install(void) {
@ -65,8 +76,8 @@ void gdt_install(void) {
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Data segment */
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); /* User code */
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); /* User data */
write_tss(5, 0x10, 0x0);
gdt_set_gate(6, 0, 0xFFFFFFFF, 0xF2, 0xCF);
/* Go go go */
gdt_flush((uintptr_t)gdtp);

View File

@ -784,6 +784,12 @@ static int sys_sysfunc(int fn, char ** args) {
return 0;
case 14:
PTR_VALIDATE(args);
current_process->thread.gsbase = (uintptr_t)args[0];
gdt_set_gsbase(current_process->thread.gsbase);
return 0;
default:
debug_print(ERROR, "Bad system function %d", fn);
break;

View File

@ -218,6 +218,7 @@ uint32_t fork(void) {
new_proc->thread.esp = esp;
new_proc->thread.ebp = ebp;
new_proc->thread.gsbase = current_process->thread.gsbase;
new_proc->is_tasklet = parent->is_tasklet;
@ -272,6 +273,7 @@ int create_kernel_tasklet(tasklet_t tasklet, char * name, void * argp) {
new_proc->thread.esp = esp;
new_proc->thread.ebp = ebp;
new_proc->thread.gsbase = current_process->thread.gsbase;
new_proc->thread.eip = (uintptr_t)tasklet;
@ -339,6 +341,7 @@ clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) {
new_proc->thread.esp = esp;
new_proc->thread.ebp = ebp;
new_proc->thread.gsbase = current_process->thread.gsbase;
new_proc->is_tasklet = parent->is_tasklet;
@ -405,6 +408,7 @@ void switch_task(uint8_t reschedule) {
current_process->thread.eip = eip;
current_process->thread.esp = esp;
current_process->thread.ebp = ebp;
current_process->thread.gsbase = gdt_get_gsbase();
current_process->running = 0;
/* Save floating point state */
@ -432,6 +436,7 @@ void switch_next(void) {
eip = current_process->thread.eip;
esp = current_process->thread.esp;
ebp = current_process->thread.ebp;
gdt_set_gsbase(current_process->thread.gsbase);
unswitch_fpu();
/* Validate */

View File

@ -32,6 +32,8 @@ enter_userspace:
mov %eax, %ds
mov %eax, %es
mov %eax, %fs
mov $0x33, %ax
mov %eax, %gs
/* %ss is handled by iret */

View File

@ -30,8 +30,11 @@ void _exit(int val){
__builtin_unreachable();
}
extern void __make_tls(void);
__attribute__((constructor))
static void _libc_init(void) {
__make_tls();
__stdio_init_buffers();
unsigned int x = 0;

View File

@ -11,6 +11,7 @@
#include <errno.h>
#include <sys/wait.h>
#include <sys/sysfunc.h>
DEFN_SYSCALL3(clone, SYS_CLONE, uintptr_t, uintptr_t, void *);
DEFN_SYSCALL0(gettid, SYS_GETTID);
@ -24,11 +25,39 @@ int gettid() {
return syscall_gettid(); /* never fails */
}
struct pthread {
void * (*entry)(void *);
void * arg;
};
void * ___tls_get_addr(void* input) {
return NULL;
}
void __make_tls(void) {
char * tlsSpace = calloc(1,4096);
char ** tlsSelf = (char **)(tlsSpace + 4096 - sizeof(char *));
*tlsSelf = (char*)tlsSelf;
sysfunc(TOARU_SYS_FUNC_SETGSBASE, (char*[]){(char*)tlsSelf});
}
void * __thread_start(void * thread) {
__make_tls();
struct pthread * me = ((pthread_t *)thread)->ret_val;
((pthread_t *)thread)->ret_val = 0;
return me->entry(me->arg);
}
int pthread_create(pthread_t * thread, pthread_attr_t * attr, void *(*start_routine)(void *), void * arg) {
char * stack = malloc(PTHREAD_STACK_SIZE);
uintptr_t stack_top = (uintptr_t)stack + PTHREAD_STACK_SIZE;
thread->stack = stack;
thread->id = clone(stack_top, (uintptr_t)start_routine, arg);
struct pthread * data = malloc(sizeof(struct pthread));
data->entry = start_routine;
data->arg = arg;
thread->ret_val = data;
thread->id = clone(stack_top, (uintptr_t)__thread_start, thread);
return 0;
}

View File

@ -0,0 +1,61 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <syscall.h>
#include <syscall_nums.h>
#include <signal.h>
#include <pthread.h>
#include <errno.h>
#include <sys/wait.h>
#define ACQUIRE_LOCK() do { while (__sync_lock_test_and_set(&lock->atomic_lock, 0x01)) { syscall_yield(); } } while (0)
#define RELEASE_LOCK() do { __sync_lock_release(&lock->atomic_lock); } while (0)
int pthread_rwlock_init(pthread_rwlock_t * lock, void * args) {
lock->readers = 0;
lock->atomic_lock = 0;
if (args != NULL) {
fprintf(stderr, "pthread: pthread_rwlock_init arg unsupported\n");
return 1;
}
return 0;
}
int pthread_rwlock_wrlock(pthread_rwlock_t * lock) {
ACQUIRE_LOCK();
while (1) {
if (lock->readers == 0) {
lock->readers = -1;
lock->writerPid = syscall_getpid();
RELEASE_LOCK();
return 0;
}
syscall_yield();
}
}
int pthread_rwlock_rdlock(pthread_rwlock_t * lock) {
ACQUIRE_LOCK();
while (1) {
if (lock->readers >= 0) {
lock->readers++;
RELEASE_LOCK();
return 0;
}
syscall_yield();
}
}
int pthread_rwlock_unlock(pthread_rwlock_t * lock) {
ACQUIRE_LOCK();
if (lock->readers > 0) lock->readers--;
else if (lock->readers < 0) lock->readers = 0;
else fprintf(stderr, "pthread: bad lock state detected\n");
RELEASE_LOCK();
return 0;
}
int pthread_rwlock_destroy(pthread_rwlock_t * lock) {
return 0;
}

View File

@ -41,9 +41,7 @@ char *realpath(const char *path, char *resolved_path) {
}
if (!resolved_path) {
/* Can't support this yet. */
errno = -EINVAL;
return NULL;
resolved_path = malloc(PATH_MAX+1);
}
/* If we're lucky, we can do this with no allocations, so let's start here... */

View File

@ -75,6 +75,8 @@ typedef int (*entry_point_t)(int, char *[], char**);
static hashmap_t * dumb_symbol_table;
static hashmap_t * glob_dat;
static hashmap_t * objects_map;
static hashmap_t * tls_map;
static size_t current_tls_offset = 0;
/* Used for dlerror */
static char * last_error = NULL;
@ -388,6 +390,7 @@ static int need_symbol_for_type(unsigned char type) {
case 5:
case 6:
case 7:
case 14:
return 1;
default:
return 0;
@ -471,6 +474,20 @@ static int object_relocate(elf_t * object) {
case 5: /* COPY */
memcpy((void *)(table->r_offset + object->base), (void *)x, sym->st_size);
break;
case 14: /* TLS_TPOFF */
x = *((ssize_t *)(table->r_offset + object->base));
if (!hashmap_has(tls_map, symname)) {
if (!sym->st_size) {
fprintf(stderr, "Haven't placed %s in static TLS yet but don't know its size?\n", symname);
}
current_tls_offset += sym->st_size; /* TODO alignment restrictions */
hashmap_set(tls_map, symname, (void*)(current_tls_offset));
x -= current_tls_offset;
} else {
x -= (size_t)hashmap_get(tls_map, symname);
}
memcpy((void *)(table->r_offset + object->base), &x, sizeof(uintptr_t));
break;
default:
TRACE_LD("Unknown relocation type: %d", type);
}
@ -751,6 +768,7 @@ int main(int argc, char * argv[]) {
dumb_symbol_table = hashmap_create(10);
glob_dat = hashmap_create(10);
objects_map = hashmap_create(10);
tls_map = hashmap_create(10);
/* Setup symbols for built-in exports */
ld_exports_t * ex = ld_builtin_exports;