kernel, linker, libc: Initial, probably horribly broken, support for some TLS situations
This commit is contained in:
parent
1c2de4d888
commit
230870ad7b
2
Makefile
2
Makefile
@ -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
37
apps/test-tls.c
Normal 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;
|
||||
}
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
61
libc/pthread/pthread_rwlock.c
Normal file
61
libc/pthread/pthread_rwlock.c
Normal 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;
|
||||
}
|
@ -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... */
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user