/*
 * Copyright (c) 2007, 2008 University of Tsukuba
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of the University of Tsukuba nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
/*
 * Copyright (c) 2010-2013 Yuichi Watanabe
 */

#ifndef _CORE_PCPU_H
#define _CORE_PCPU_H

#include <common/list.h>
#include <core/cpu.h>
#include <core/spinlock.h>
#include <core/types.h>
#include "asm.h"
#include "desc.h"
#include "seg.h"
#include "svm.h"
#include "thread.h"
#include "vt.h"

#define NUM_OF_SEGDESCTBL 32
#define PCPU_GS_ALIGN  __attribute__ ((aligned (8)))

enum fullvirtualize_type {
	FULLVIRTUALIZE_NONE,
	FULLVIRTUALIZE_VT,
	FULLVIRTUALIZE_SVM,
};

struct pcpu_func {
};

struct timer_data {
	LIST1_DEFINE (struct timer_data);
	bool enable;
	u64 settime;
	u64 interval;
	void (*callback) (void *handle, void *data);
	void *data;
};

struct pcpu {
	struct pcpu_func func;
	struct segdesc segdesctbl[NUM_OF_SEGDESCTBL];
	struct tss32 tss32;
	struct tss64 tss64;
	struct vt_pcpu_data vt;
	struct svm_pcpu_data svm;
	enum fullvirtualize_type fullvirtualize;
	bool bsp;
	apic_id_t apic_id;
	int pid;
	tid_t tid;
	void *stackaddr;
	u64 hz;
	u64 last_tsc;
	u64 last_time;
	u32 int_fatal;
	bool panic;
	int disable_interrupt;

	spinlock_t timer_lock;
	LIST1_DEFINE_HEAD(struct timer_data, timer_on_list);
	LIST1_DEFINE_HEAD(struct timer_data, timer_off_list);
	LIST1_DEFINE_HEAD(struct timer_data, timer_free_list);
};

struct pcpu_gs {
	u64 inthandling PCPU_GS_ALIGN;	/* %gs:0  (int.c, int_handler.s) */
	void *currentcpu PCPU_GS_ALIGN;	/* %gs:8  (pcpu.h) */
	void *syscallstack PCPU_GS_ALIGN;
				   /* %gs:16 (process.c, process_sysenter.s) */
	void *current PCPU_GS_ALIGN;	/* %gs:24 (current.h) */
	u64 nmi;		/* %gs:32 (nmi_pass.c) */
};

extern struct pcpu pcpu_default;
extern struct pcpu *currentcpu asm ("%gs:gs_currentcpu");

static inline bool
currentcpu_available(void)
{
	u16 gs;

	/* FIXME: SWAPGS in 64bit long mode can't be used. */
	asm_rdgs (&gs);
	if (gs == SEG_SEL_PCPU32 || gs == SEG_SEL_PCPU64)
		return true;
	else
		return false;
}

static inline apic_id_t
get_apic_id (void)
{
	return currentcpu->apic_id;
}

apic_id_t get_bsp_apic_id (void);

#endif
