573 lines
18 KiB
C
573 lines
18 KiB
C
/*
|
|
* kvm_thread_info.h: In-kernel KVM guest thread info related definitions
|
|
* Copyright (c) 2011, MCST.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope 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.
|
|
*/
|
|
|
|
#ifndef __E2K_KVM_THREAD_INFO_H
|
|
#define __E2K_KVM_THREAD_INFO_H
|
|
|
|
#include <linux/types.h>
|
|
#include <linux/kvm.h>
|
|
#include <linux/bitops.h>
|
|
|
|
#include <asm/trap_def.h>
|
|
#include <asm/cpu_regs_types.h>
|
|
#include <asm/stacks.h>
|
|
#include <asm/kvm/gpid.h>
|
|
|
|
#ifdef CONFIG_VIRTUALIZATION
|
|
|
|
struct kvm;
|
|
struct kvm_vcpu;
|
|
struct gmm_struct;
|
|
|
|
/* TODO a security hole, undef it - bad guest can cause host to panic() */
|
|
#define GTI_DEBUG_MODE
|
|
|
|
#ifdef GTI_DEBUG_MODE
|
|
#define GTI_BUG_ON(cond) BUG_ON(cond)
|
|
#else /* ! GTI_DEBUG_MODE */
|
|
#define GTI_BUG_ON(cond) do { } while (0)
|
|
#endif /* GTI_DEBUG_MODE */
|
|
|
|
/*
|
|
* Hardware & local data stacks registers state to save/restore guest stacks
|
|
* while hypercalls under paravirtualization without hardware support.
|
|
* It allows to emulate switch (on HCALL) and restore (on HRET) hardware
|
|
* supported extensions.
|
|
*/
|
|
typedef struct guest_hw_stack {
|
|
bool valid; /* stacks are valid */
|
|
e2k_stacks_t stacks; /* pointers to local data & hardware */
|
|
/* stacks */
|
|
e2k_mem_crs_t crs; /* to startup & launch VCPU */
|
|
e2k_cutd_t cutd; /* Compilation Unit table pointer */
|
|
} guest_hw_stack_t;
|
|
|
|
/*
|
|
* Guest kernel pt_regs structure to keep some info about guest state on host
|
|
* It needs to enable recursive traps, system calls, signal handlers
|
|
* (same as on host kernel)
|
|
*/
|
|
typedef enum gpt_regs_type {
|
|
undefined_regs_type, /* unknown or any type */
|
|
start_regs_type, /* start activation of guest */
|
|
trap_regs_type, /* beacause of trap */
|
|
syscall_regs_type, /* system call */
|
|
hypercall_regs_type, /* hypercall */
|
|
sig_handler_regs_type, /* to run signal handler */
|
|
} gpt_regs_type_t;
|
|
|
|
typedef struct gpt_regs {
|
|
gpt_regs_type_t type; /* the reason to have been created */
|
|
/* this instance of structure */
|
|
|
|
/* follow fields to save last guest and host activation state */
|
|
/* to enable recursive kernel activations */
|
|
int g_stk_frame_no; /* number of saved guest kernel */
|
|
/* data stack activation (see below) */
|
|
e2k_addr_t g_usd_size; /* guest kernel data stack size */
|
|
int k_stk_frame_no; /* number of saved host kernel */
|
|
/* data stack activation */
|
|
e2k_addr_t k_usd_size; /* host kernel data stack size */
|
|
e2k_size_t pcsp_ind; /* chain procedure stack index */
|
|
struct pt_regs *pt_regs; /* head of pt_regs structure queue: */
|
|
/* pointer to current pt_regs */
|
|
|
|
/* all structures type of this gpt_regs (same as pt_regs structures) */
|
|
/* allocated into host kernel data stack because of recursive events */
|
|
/* (traps, system calls, hypercalls, signale handler) handled by */
|
|
/* kernel on one stack using stack discipline */
|
|
/* So it can use index into this stack as reference to previous or */
|
|
/* next same structure instead of real pointer (address) to avoid */
|
|
/* complex addresses translation while copy/clone stacks (fork()) */
|
|
e2k_addr_t next_index; /* index of next same structure, */
|
|
/* into host kernel data stack */
|
|
/* which keeps state of previous */
|
|
/* guest kernel activation */
|
|
} gpt_regs_t;
|
|
|
|
typedef struct vcpu_l_gregs {
|
|
local_gregs_t gregs; /* guest user "local" global */
|
|
/* registers to save updated on page */
|
|
/* fault values */
|
|
u64 updated; /* mask of updated registers "local" */
|
|
/* global registers (see above) */
|
|
bool valid; /* gregs is valid */
|
|
int gener; /* generation of valid gregs */
|
|
} vcpu_l_gregs_t;
|
|
|
|
typedef struct kvm_signal_context {
|
|
/* signal stack area is used to store interrupted context */
|
|
/* one for host thread and one for each guest threads */
|
|
struct signal_stack stack;
|
|
atomic_t traps_num; /* counter of recursive traps at the */
|
|
/* signal stack, actual only for guest */
|
|
atomic_t in_work; /* counter of recursive traps in the */
|
|
/* work, actual only for guest */
|
|
atomic_t syscall_num; /* counter of recursive system calls at the */
|
|
/* signal stack, actual only for guest */
|
|
atomic_t in_syscall; /* counter of recursive system calls in the */
|
|
/* work, actual only for guest */
|
|
} kvm_signal_context_t;
|
|
|
|
/*
|
|
* Guest kernel thread info structure
|
|
*/
|
|
typedef struct gthread_info {
|
|
gpid_t *gpid;
|
|
|
|
/* guest kernel stacks pointers */
|
|
e2k_usd_lo_t g_usd_lo;
|
|
e2k_usd_hi_t g_usd_hi;
|
|
e2k_sbr_t g_sbr;
|
|
e2k_psp_lo_t g_psp_lo;
|
|
e2k_psp_hi_t g_psp_hi;
|
|
e2k_pcsp_lo_t g_pcsp_lo;
|
|
e2k_pcsp_hi_t g_pcsp_hi;
|
|
|
|
e2k_size_t us_size; /* guest local data size: */
|
|
/* kernel stack for kernel thread, */
|
|
/* user stack for user */
|
|
guest_hw_stack_t stack_regs; /* state of pointers to local & */
|
|
/* hardware stacks of guest */
|
|
|
|
data_stack_t data_stack;
|
|
void *stack;
|
|
hw_stack_t hw_stacks;
|
|
vcpu_l_gregs_t l_gregs; /* guest user "local" global */
|
|
/* registers to save updated on page */
|
|
/* fault values */
|
|
kernel_gregs_t gk_gregs; /* guest kernel global registers state */
|
|
/* some registers can be updated only */
|
|
/* after migration to other VCPU */
|
|
kernel_gregs_t gu_gregs; /* guest user global regitsers state */
|
|
/* only for global registers which */
|
|
/* used by the guest kernel for its */
|
|
/* own purposes */
|
|
|
|
/* the following flags to mark event: */
|
|
/* hardware stacks bounds trap occured, but 'sge' on guest */
|
|
/* is disabled and the trap is not yet passed to guest kernel */
|
|
bool proc_bounds_waiting; /* procedure stack bounds */
|
|
bool chain_bounds_waiting; /* chain stack bounds */
|
|
|
|
int g_stk_frame_no; /* current number of guest kernel */
|
|
/* data stack activation */
|
|
/* each kernel activation from user */
|
|
/* (trap, system call, signal */
|
|
/* handler) runs on kernel data stack */
|
|
/* Activations can be nested, */
|
|
/* so for each new nested activation */
|
|
/* need new free frame of data stack */
|
|
/* above (for data stack below) */
|
|
/* previous activation */
|
|
int k_stk_frame_no; /* current number of host kernel */
|
|
/* data stack activation */
|
|
|
|
unsigned long flags; /* flags (see below) */
|
|
struct gmm_struct *gmm; /* pointer to current guest mm agent */
|
|
/* on host */
|
|
/* NULL for guest kernel threads */
|
|
hpa_t nonp_root_hpa; /* physical base of nonpaging root PT */
|
|
u64 curr_ctx_key; /* Key of curr context signal stack */
|
|
bool gmm_in_release; /* guest mm is releasing (exit_mm()) */
|
|
|
|
/* following fields should be updated for each multi-stack process */
|
|
/* (task, thread) while switching */
|
|
struct kvm_vcpu *vcpu; /* pointer to VCPU where the thread */
|
|
/* is running now or was run last */
|
|
/* time */
|
|
struct pt_regs fork_regs; /* pt_regs structure of last host */
|
|
/* sys_fork() system call */
|
|
u32 intr_counter; /* number of traps are handling */
|
|
atomic_t signal_counter; /* number of signals are handling */
|
|
struct sw_regs sw_regs; /* user special registers state */
|
|
/* to save/restore while guest */
|
|
/* process switch */
|
|
kvm_signal_context_t signal; /* the host kernel's signal/trap */
|
|
/* stack of contexts */
|
|
|
|
/* follow pointer should be updated by each recursive traps, */
|
|
/* system calls, signal handler running */
|
|
gpt_regs_t *gpt_regs; /* pointer to current state of */
|
|
/* guest kernel */
|
|
|
|
e2k_upsr_t u_upsr; /* guest user is different from */
|
|
e2k_upsr_t k_upsr; /* guest kernel UPSR */
|
|
|
|
/* FIXME: follow fields is added only to debug correct save/restore */
|
|
/* guest UPSR state, delete after debugging completion with some */
|
|
/* debug statements into other source files of kvm */
|
|
bool u_upsr_valid; /* guest user upsr value is valid */
|
|
bool k_upsr_valid; /* guest kernel upsr value is valid */
|
|
|
|
global_regs_t gregs; /* structure to keep guest user */
|
|
/* global registers state */
|
|
/* FIXME: this structure duplicates */
|
|
/* similar structure into sw_regs, */
|
|
/* should use structure into sw_regs */
|
|
/* only */
|
|
bool gregs_active; /* gregs structure above is active */
|
|
/* for user global registers */
|
|
bool gregs_valid; /* gregs structure above contains */
|
|
/* actual global registers state */
|
|
bool gregs_for_currents_valid; /* gregs used for currents pointers */
|
|
/* contain actual global registers */
|
|
/* state, when real global registers */
|
|
/* is set to currents pointers */
|
|
bool task_is_binco; /* the guest task is binary */
|
|
/* application compiler */
|
|
bool task_is_protect; /* the guest task is running at */
|
|
/* protected mode */
|
|
} gthread_info_t;
|
|
|
|
/* guest stacks flag (field at structure above) */
|
|
|
|
/*
|
|
* Guest thread flags
|
|
*/
|
|
#define GTIF_VCPU_START_THREAD 0 /* this thread is booting (start) */
|
|
/* guest kernel thread */
|
|
#define GTIF_KERNEL_THREAD 1 /* this thread is guest kernel */
|
|
/* thread */
|
|
#define GTIF_THREAD_MIGRATED 2 /* the thread was migrated from one */
|
|
/* VCPU to other */
|
|
#define GTIF_USER_THREAD 4 /* the process is user thread on */
|
|
/* common virtual memory (gmm) */
|
|
#define GTIF_HW_PS_LOCKED 16 /* hardware procedure stack */
|
|
/* was locked by host */
|
|
#define GTIF_HW_PCS_LOCKED 17 /* hardware chain stack */
|
|
/* was locked by host */
|
|
#define GTIF_HW_PS_PRESENTED 18 /* hardware procedure stack */
|
|
/* was populated by host */
|
|
#define GTIF_HW_PCS_PRESENTED 19 /* hardware chain stack */
|
|
/* was populated by host */
|
|
#define GTIF_DATA_STACK_HOSTED 20 /* local data stack of guest */
|
|
/* was registered on host */
|
|
#define GTIF_HW_PS_HOSTED 21 /* hardware procedure stack of guest */
|
|
/* was registered on host */
|
|
#define GTIF_HW_PCS_HOSTED 22 /* hardware chain stack of guest */
|
|
/* was registered on host */
|
|
#define GTIF_HW_PS_HAS_GUARD_PAGE 28 /* hardware procedure stack of guest */
|
|
/* has extra guard page */
|
|
#define GTIF_HW_PCS_HAS_GUARD_PAGE 29 /* hardware chain stack of guest */
|
|
/* has extra guard page */
|
|
|
|
#define _GTIF_VCPU_START_THREAD (1UL << GTIF_VCPU_START_THREAD)
|
|
#define _GTIF_KERNEL_THREAD (1UL << GTIF_KERNEL_THREAD)
|
|
#define _GTIF_THREAD_MIGRATED (1UL << GTIF_THREAD_MIGRATED)
|
|
#define _GTIF_USER_THREAD (1UL << GTIF_USER_THREAD)
|
|
#define _GTIF_HW_PS_LOCKED (1UL << GTIF_HW_PS_LOCKED)
|
|
#define _GTIF_HW_PCS_LOCKED (1UL << GTIF_HW_PCS_LOCKED)
|
|
#define _GTIF_HW_PS_PRESENTED (1UL << GTIF_HW_PS_PRESENTED)
|
|
#define _GTIF_HW_PCS_PRESENTED (1UL << GTIF_HW_PCS_PRESENTED)
|
|
#define _GTIF_DATA_STACK_HOSTED (1UL << GTIF_DATA_STACK_HOSTED)
|
|
#define _GTIF_HW_PS_HOSTED (1UL << GTIF_HW_PS_HOSTED)
|
|
#define _GTIF_HW_PCS_HOSTED (1UL << GTIF_HW_PCS_HOSTED)
|
|
#define _GTIF_HW_PS_HAS_GUARD_PAGE (1UL << GTIF_HW_PS_HAS_GUARD_PAGE)
|
|
#define _GTIF_HW_PCS_HAS_GUARD_PAGE (1UL << GTIF_HW_PCS_HAS_GUARD_PAGE)
|
|
|
|
#define GTIF_ALL_STACKS_MASK \
|
|
(_GTIF_HW_PS_LOCKED | _GTIF_HW_PCS_LOCKED | \
|
|
_GTIF_HW_PS_PRESENTED | _GTIF_HW_PCS_PRESENTED | \
|
|
_GTIF_DATA_STACK_HOSTED | _GTIF_HW_PS_HOSTED | \
|
|
_GTIF_HW_PCS_HOSTED)
|
|
|
|
static inline void set_the_flag(unsigned long *flags, int the_flag)
|
|
{
|
|
set_bit(the_flag, flags);
|
|
}
|
|
|
|
static inline void clear_the_flag(unsigned long *flags, int the_flag)
|
|
{
|
|
clear_bit(the_flag, flags);
|
|
}
|
|
|
|
static inline int test_and_set_the_flag(unsigned long *flags, int the_flag)
|
|
{
|
|
return test_and_set_bit(the_flag, flags);
|
|
}
|
|
|
|
static inline int test_and_clear_the_flag(unsigned long *flags, int the_flag)
|
|
{
|
|
return test_and_clear_bit(the_flag, flags);
|
|
}
|
|
|
|
static inline int test_the_flag(unsigned long *flags, int the_flag)
|
|
{
|
|
return test_bit(the_flag, flags);
|
|
}
|
|
|
|
static inline void set_gti_thread_flag(gthread_info_t *gti, int flag)
|
|
{
|
|
set_the_flag(>i->flags, flag);
|
|
}
|
|
|
|
static inline void clear_gti_thread_flag(gthread_info_t *gti, int flag)
|
|
{
|
|
clear_the_flag(>i->flags, flag);
|
|
}
|
|
|
|
static inline int test_and_set_gti_thread_flag(gthread_info_t *gti, int flag)
|
|
{
|
|
return test_and_set_the_flag(>i->flags, flag);
|
|
}
|
|
|
|
static inline int test_and_clear_gti_thread_flag(gthread_info_t *gti, int flag)
|
|
{
|
|
return test_and_clear_the_flag(>i->flags, flag);
|
|
}
|
|
|
|
static inline int test_gti_thread_flag(gthread_info_t *gti, int flag)
|
|
{
|
|
return test_the_flag(>i->flags, flag);
|
|
}
|
|
|
|
#define gti_signal_pt_regs_first(__gti) \
|
|
({ \
|
|
struct pt_regs __user *__sig_regs; \
|
|
if (__gti->signal.stack.used) { \
|
|
__sig_regs = &((struct signal_stack_context __user *) \
|
|
(__gti->signal.stack.base + \
|
|
__gti->signal.stack.used - \
|
|
sizeof(struct signal_stack_context)))->regs; \
|
|
} else { \
|
|
__sig_regs = NULL; \
|
|
} \
|
|
__sig_regs; \
|
|
})
|
|
|
|
/*
|
|
* Hardware stacks bounds control
|
|
*/
|
|
static inline bool test_guest_hw_stack_bounds_waiting(thread_info_t *ti,
|
|
unsigned long trap_mask)
|
|
{
|
|
gthread_info_t *gti = ti->gthread_info;
|
|
bool is_waiting = false;
|
|
|
|
if (gti == NULL)
|
|
return false;
|
|
if (trap_mask & exc_proc_stack_bounds_mask)
|
|
is_waiting |= gti->proc_bounds_waiting;
|
|
if (trap_mask & exc_chain_stack_bounds_mask)
|
|
is_waiting |= gti->chain_bounds_waiting;
|
|
return is_waiting;
|
|
}
|
|
static inline bool test_guest_proc_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
return test_guest_hw_stack_bounds_waiting(ti,
|
|
exc_proc_stack_bounds_mask);
|
|
}
|
|
static inline bool test_guest_chain_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
return test_guest_hw_stack_bounds_waiting(ti,
|
|
exc_chain_stack_bounds_mask);
|
|
}
|
|
static inline void set_guest_hw_stack_bounds_waiting(thread_info_t *ti,
|
|
unsigned long trap_mask)
|
|
{
|
|
gthread_info_t *gti = ti->gthread_info;
|
|
|
|
if (gti == NULL)
|
|
return;
|
|
if (trap_mask & exc_proc_stack_bounds_mask) {
|
|
gti->proc_bounds_waiting = true;
|
|
} else if (trap_mask & exc_chain_stack_bounds_mask) {
|
|
gti->chain_bounds_waiting = true;
|
|
} else {
|
|
BUG_ON(true);
|
|
}
|
|
}
|
|
static inline void set_guest_proc_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
set_guest_hw_stack_bounds_waiting(ti, exc_proc_stack_bounds_mask);
|
|
}
|
|
static inline void set_guest_chain_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
set_guest_hw_stack_bounds_waiting(ti, exc_chain_stack_bounds_mask);
|
|
}
|
|
static inline bool
|
|
test_and_set_guest_hw_stack_bounds_waiting(thread_info_t *ti,
|
|
unsigned long trap_mask)
|
|
{
|
|
bool waiting;
|
|
|
|
waiting = test_guest_hw_stack_bounds_waiting(ti, trap_mask);
|
|
if (!waiting)
|
|
set_guest_hw_stack_bounds_waiting(ti, trap_mask);
|
|
return waiting;
|
|
}
|
|
static inline bool test_and_set_guest_proc_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
return test_and_set_guest_hw_stack_bounds_waiting(ti,
|
|
exc_proc_stack_bounds_mask);
|
|
}
|
|
static inline bool test_and_set_guest_chain_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
return test_and_set_guest_hw_stack_bounds_waiting(ti,
|
|
exc_chain_stack_bounds_mask);
|
|
}
|
|
static inline void clear_guest_hw_stack_bounds_waiting(thread_info_t *ti,
|
|
unsigned long trap_mask)
|
|
{
|
|
gthread_info_t *gti = ti->gthread_info;
|
|
|
|
if (gti == NULL)
|
|
return;
|
|
if (trap_mask & exc_proc_stack_bounds_mask) {
|
|
gti->proc_bounds_waiting = false;
|
|
} else if (trap_mask & exc_chain_stack_bounds_mask) {
|
|
gti->chain_bounds_waiting = false;
|
|
} else {
|
|
BUG_ON(true);
|
|
}
|
|
}
|
|
static inline void clear_guest_proc_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
clear_guest_hw_stack_bounds_waiting(ti, exc_proc_stack_bounds_mask);
|
|
}
|
|
static inline void clear_guest_chain_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
clear_guest_hw_stack_bounds_waiting(ti, exc_chain_stack_bounds_mask);
|
|
}
|
|
static inline bool
|
|
test_and_clear_guest_hw_stack_bounds_waiting(thread_info_t *ti,
|
|
unsigned long trap_mask)
|
|
{
|
|
bool waiting;
|
|
|
|
waiting = test_guest_hw_stack_bounds_waiting(ti, trap_mask);
|
|
if (waiting)
|
|
clear_guest_hw_stack_bounds_waiting(ti, trap_mask);
|
|
return waiting;
|
|
}
|
|
static inline bool test_and_clear_guest_proc_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
return test_and_clear_guest_hw_stack_bounds_waiting(ti,
|
|
exc_proc_stack_bounds_mask);
|
|
}
|
|
static inline bool test_and_clear_guest_chain_bounds_waiting(thread_info_t *ti)
|
|
{
|
|
return test_and_clear_guest_hw_stack_bounds_waiting(ti,
|
|
exc_chain_stack_bounds_mask);
|
|
}
|
|
|
|
/*
|
|
* Set of functions to manipulate with gpt_regs structures
|
|
*/
|
|
|
|
#define ATOMIC_GET_HW_PCS_INDEX() \
|
|
({ \
|
|
unsigned long pcsp_hi_val; \
|
|
unsigned int pcshtp_val; \
|
|
e2k_pcsp_hi_t pcsp_hi; \
|
|
\
|
|
ATOMIC_READ_HW_PCS_SIZES(pcsp_hi_val, pcshtp_val); \
|
|
pcsp_hi.PCSP_hi_half = pcsp_hi_val; \
|
|
pcsp_hi.PCSP_hi_ind + pcshtp_val; \
|
|
})
|
|
|
|
static inline e2k_size_t
|
|
gpt_regs_addr_to_index(thread_info_t *ti, gpt_regs_t *gregs)
|
|
{
|
|
e2k_addr_t bottom;
|
|
e2k_addr_t addr;
|
|
|
|
if (gregs == NULL)
|
|
return -1UL;
|
|
bottom = (e2k_addr_t)thread_info_task(ti)->stack;
|
|
addr = (e2k_addr_t)gregs;
|
|
GTI_BUG_ON(addr < bottom ||
|
|
addr + sizeof(*gregs) > bottom + KERNEL_C_STACK_SIZE);
|
|
return addr - bottom;
|
|
}
|
|
static inline gpt_regs_t *
|
|
gpt_regs_index_to_addr(thread_info_t *ti, e2k_size_t gregs_index)
|
|
{
|
|
e2k_addr_t bottom;
|
|
|
|
if (gregs_index == -1UL)
|
|
return NULL;
|
|
bottom = (e2k_addr_t)thread_info_task(ti)->stack;
|
|
GTI_BUG_ON(gregs_index < 0 ||
|
|
gregs_index + sizeof(gpt_regs_t) > KERNEL_C_STACK_SIZE);
|
|
return (gpt_regs_t *)(bottom + gregs_index);
|
|
}
|
|
static inline gpt_regs_t *
|
|
get_gpt_regs(thread_info_t *ti)
|
|
{
|
|
gthread_info_t *gti = ti->gthread_info;
|
|
|
|
GTI_BUG_ON(gti == NULL);
|
|
return gti->gpt_regs;
|
|
}
|
|
static inline void
|
|
set_gpt_regs(thread_info_t *ti, gpt_regs_t *gregs)
|
|
{
|
|
gthread_info_t *gti = ti->gthread_info;
|
|
|
|
GTI_BUG_ON(gti == NULL);
|
|
gti->gpt_regs = gregs;
|
|
}
|
|
static inline void
|
|
add_gpt_regs(thread_info_t *ti, gpt_regs_t *new_gregs, gpt_regs_type_t type)
|
|
{
|
|
gpt_regs_t *cur_gregs;
|
|
|
|
cur_gregs = get_gpt_regs(ti);
|
|
new_gregs->type = type;
|
|
new_gregs->next_index = gpt_regs_addr_to_index(ti, cur_gregs);
|
|
new_gregs->pcsp_ind = ATOMIC_GET_HW_PCS_INDEX();
|
|
set_gpt_regs(ti, new_gregs);
|
|
}
|
|
static inline gpt_regs_t *
|
|
delete_gpt_regs(thread_info_t *ti)
|
|
{
|
|
gpt_regs_t *cur_gregs;
|
|
|
|
cur_gregs = get_gpt_regs(ti);
|
|
GTI_BUG_ON(cur_gregs == NULL);
|
|
set_gpt_regs(ti, gpt_regs_index_to_addr(ti, cur_gregs->next_index));
|
|
return cur_gregs;
|
|
}
|
|
static inline gpt_regs_t *
|
|
get_next_gpt_regs(thread_info_t *ti, gpt_regs_t *gregs)
|
|
{
|
|
BUG_ON(gregs == NULL);
|
|
return gpt_regs_index_to_addr(ti, gregs->next_index);
|
|
}
|
|
|
|
extern int kvm_pv_guest_thread_info_init(struct kvm *kvm);
|
|
extern void kvm_pv_guest_thread_info_reset(struct kvm *kvm);
|
|
extern void kvm_pv_guest_thread_info_free(struct kvm *kvm);
|
|
extern void kvm_pv_guest_thread_info_destroy(struct kvm *kvm);
|
|
extern void kvm_pv_clear_guest_thread_info(gthread_info_t *gthread_info);
|
|
|
|
#else /* !CONFIG_VIRTUALIZATION */
|
|
|
|
typedef struct guest_hw_stack {
|
|
/* empty structure */
|
|
} guest_hw_stack_t;
|
|
|
|
typedef struct kvm_signal_context {
|
|
/* empty structure */
|
|
} kvm_signal_context_t;
|
|
typedef struct gthread_info {
|
|
/* empty structure */
|
|
} gthread_info_t;
|
|
|
|
#endif /* CONFIG_VIRTUALIZATION */
|
|
|
|
#endif /* __E2K_KVM_THREAD_INFO_H */
|