/*
 * hal_special.c - implementation of TLS API for x86_64
 *
 * Copyright (c) 2017 Maxime Villard
 *
 * This file is part of ALMOS-MKH.
 *
 * ALMOS-MKH 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; version 2.0 of the License.
 *
 * ALMOS-MKH 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 ALMOS-MKH.; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <hal_types.h>
#include <hal_apic.h>
#include <hal_special.h>
#include <hal_register.h>
#include <hal_internal.h>

#include <core.h>
#include <thread.h>

struct thread_s;

typedef struct cpu_info {
	void *ci_self;
	uint32_t ci_gid;
	uint32_t ci_lid;
	struct thread_s	*ci_thr;
} cpu_info_t;

cpu_info_t cpu0 __in_kdata;

cpu_info_t *curcpu()
{
	cpu_info_t *ci;

	__asm volatile("movq %%gs:%1, %0" :
	    "=r" (ci) :
	    "m"
	    (*(cpu_info_t * const *)offsetof(cpu_info_t, ci_self)));
	return ci;
}

static void hal_tls_load_cpu(cpu_info_t *ci)
{
	wrmsr(MSR_FSBASE, 0);
	wrmsr(MSR_GSBASE, (uint64_t)ci);
	wrmsr(MSR_KERNELGSBASE, 0);
}

void hal_tls_init_cpu0()
{
	cpu_info_t *ci = &cpu0;

	memset(ci, 0, sizeof(cpu_info_t));

	ci->ci_self = ci;
	ci->ci_gid = hal_lapic_gid();
	ci->ci_lid = 0; /* XXX */

	hal_tls_load_cpu(ci);
}

gid_t hal_get_gid()
{
	return curcpu()->ci_gid;
}

uint64_t hal_get_cycles()
{
	uint64_t cycles;
	core_t *core = CURRENT_THREAD->core;

	/*
	 * Put the value of the TSC everywhere
	 */
	cycles = rdtsc();
	core->time_stamp = cycles;
	core->cycles = cycles;

	return cycles;
}

struct thread_s *hal_get_current_thread()
{
	return curcpu()->ci_thr;
}

void hal_set_current_thread( struct thread_s * thread )
{
	curcpu()->ci_thr = thread;
}

/* -------------------------------------------------------------------------- */

void hal_fpu_enable()
{
	x86_panic((char *)__func__);
}

void hal_fpu_disable()
{
	x86_panic((char *)__func__);
}

uint32_t hal_get_stack()
{
	x86_panic((char *)__func__);
	return 0;
}

uint32_t hal_set_stack( void * new_val )
{
	x86_panic((char *)__func__);
	return 0;
}

uint32_t hal_get_bad_vaddr()
{
	x86_panic((char *)__func__);
	return 0;
}

uint32_t hal_uncached_read( uint32_t * ptr )
{
	x86_panic((char *)__func__);
	return 0;
}

void hal_invalid_dcache_line( void * ptr )
{
	x86_panic((char *)__func__);
}

void hal_wbflush()
{
	x86_panic((char *)__func__);
}

void hal_rdbar()
{
	x86_panic((char *)__func__);
}

void hal_core_sleep()
{
	x86_panic((char *)__func__);
}

void hal_fixed_delay( uint32_t delay )
{
	x86_panic((char *)__func__);
}

void hal_get_mmu_excp( intptr_t * mmu_ins_excp_code,
                       intptr_t * mmu_ins_bad_vaddr,
                       intptr_t * mmu_dat_excp_code,
                       intptr_t * mmu_dat_bad_vaddr )
{
	x86_panic((char *)__func__);
}
