#include <stddef.h>
#include <stdint.h>
#include <string.h>

extern char _stdata[];
#define TDATA ((void *)_stdata)

extern char _ltdata[], _ltbss[];
#define LTDATA ((size_t)_ltdata)
#define LTBSS ((size_t)_ltbss)

struct tcb {
  void *tp;
  void *pad;
};

size_t gilbraltar_tls_size(void) {
  return (LTDATA + LTBSS + sizeof(struct tcb));
}

void gilbraltar_set_tls_base(uintptr_t base) {
  __asm__ __volatile("msr tpidr_el0, %0" ::"r"(base));
}

static uintptr_t tls_data_offset(uintptr_t tls) {
  uintptr_t data;
  data = tls + sizeof(struct tcb);
  return data;
}

void gilbraltar_tls_init(uintptr_t tls) {
  uintptr_t *tmp = (uintptr_t *)tls;
  *tmp = (uintptr_t)tmp;
  memcpy((void *)tls_data_offset(tls), TDATA, LTDATA);
}