700 lines
18 KiB
C
700 lines
18 KiB
C
/*
|
|
* Hardware stacks support
|
|
*
|
|
* Copyright 2001-2015 Salavat S. Guilyazov (atic@mcst.ru)
|
|
*/
|
|
|
|
#ifndef _E2K_HW_STACKS_H
|
|
#define _E2K_HW_STACKS_H
|
|
|
|
#include <asm/types.h>
|
|
#include <asm/cpu_regs_types.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
typedef enum hw_stack_type {
|
|
HW_STACK_TYPE_PS,
|
|
HW_STACK_TYPE_PCS
|
|
} hw_stack_type_t;
|
|
|
|
/*
|
|
* Procedure chain stacks can be mapped to user (user processes)
|
|
* or kernel space (kernel threads). But mapping is always to privileged area
|
|
* and directly can be accessed only by host kernel.
|
|
* SPECIAL CASE: access to current procedure chain stack:
|
|
* 1. Current stack frame must be locked (resident), so access is
|
|
* safety and can use common load/store operations
|
|
* 2. Top of stack can be loaded to the special hardware register file and
|
|
* must be spilled to memory before any access.
|
|
* 3. If items of chain stack are not updated, then spilling is enough to
|
|
* their access
|
|
* 4. If items of chain stack are updated, then interrupts and
|
|
* any calling of function should be disabled in addition to spilling,
|
|
* because of return (done) will fill some part of stack from memory and can be
|
|
* two copy of chain stack items: in memory and in registers file.
|
|
* We can update only in memory and following spill recover not updated
|
|
* value from registers file.
|
|
*/
|
|
static inline unsigned long
|
|
native_get_active_cr_mem_value(e2k_addr_t base,
|
|
e2k_addr_t cr_ind, e2k_addr_t cr_item)
|
|
{
|
|
return *((unsigned long *)(base + cr_ind + cr_item));
|
|
}
|
|
static inline unsigned long
|
|
native_get_active_cr0_lo_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr_mem_value(base, cr_ind, CR0_LO_I);
|
|
}
|
|
static inline unsigned long
|
|
native_get_active_cr0_hi_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr_mem_value(base, cr_ind, CR0_HI_I);
|
|
}
|
|
static inline unsigned long
|
|
native_get_active_cr1_lo_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr_mem_value(base, cr_ind, CR1_LO_I);
|
|
}
|
|
static inline unsigned long
|
|
native_get_active_cr1_hi_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr_mem_value(base, cr_ind, CR1_HI_I);
|
|
}
|
|
static inline void
|
|
native_put_active_cr_mem_value(unsigned long cr_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind, e2k_addr_t cr_item)
|
|
{
|
|
*((unsigned long *)(base + cr_ind + cr_item)) = cr_value;
|
|
}
|
|
static inline void
|
|
native_put_active_cr0_lo_value(unsigned long cr0_lo_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr_mem_value(cr0_lo_value, base, cr_ind, CR0_LO_I);
|
|
}
|
|
static inline void
|
|
native_put_active_cr0_hi_value(unsigned long cr0_hi_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr_mem_value(cr0_hi_value, base, cr_ind, CR0_HI_I);
|
|
}
|
|
static inline void
|
|
native_put_active_cr1_lo_value(unsigned long cr1_lo_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr_mem_value(cr1_lo_value, base, cr_ind, CR1_LO_I);
|
|
}
|
|
static inline void
|
|
native_put_active_cr1_hi_value(unsigned long cr1_hi_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr_mem_value(cr1_hi_value, base, cr_ind, CR1_HI_I);
|
|
}
|
|
|
|
static inline e2k_cr0_lo_t
|
|
native_get_active_cr0_lo(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr0_lo_t cr0_lo;
|
|
|
|
cr0_lo.CR0_lo_half = native_get_active_cr0_lo_value(base, cr_ind);
|
|
return cr0_lo;
|
|
}
|
|
static inline e2k_cr0_hi_t
|
|
native_get_active_cr0_hi(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr0_hi_t cr0_hi;
|
|
|
|
cr0_hi.CR0_hi_half = native_get_active_cr0_hi_value(base, cr_ind);
|
|
return cr0_hi;
|
|
}
|
|
static inline e2k_cr1_lo_t
|
|
native_get_active_cr1_lo(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr1_lo_t cr1_lo;
|
|
|
|
cr1_lo.CR1_lo_half = native_get_active_cr1_lo_value(base, cr_ind);
|
|
return cr1_lo;
|
|
}
|
|
static inline e2k_cr1_hi_t
|
|
native_get_active_cr1_hi(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr1_hi_t cr1_hi;
|
|
|
|
cr1_hi.CR1_hi_half = native_get_active_cr1_hi_value(base, cr_ind);
|
|
return cr1_hi;
|
|
}
|
|
static inline void
|
|
native_put_active_cr0_lo(e2k_cr0_lo_t cr0_lo,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr0_lo_value(cr0_lo.CR0_lo_half, base, cr_ind);
|
|
}
|
|
static inline void
|
|
native_put_active_cr0_hi(e2k_cr0_hi_t cr0_hi,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr0_hi_value(cr0_hi.CR0_hi_half, base, cr_ind);
|
|
}
|
|
static inline void
|
|
native_put_active_cr1_lo(e2k_cr1_lo_t cr1_lo,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr1_lo_value(cr1_lo.CR1_lo_half, base, cr_ind);
|
|
}
|
|
static inline void
|
|
native_put_active_cr1_hi(e2k_cr1_hi_t cr1_hi,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr1_hi_value(cr1_hi.CR1_hi_half, base, cr_ind);
|
|
}
|
|
|
|
static inline int
|
|
native_get_user_cr0_lo(e2k_cr0_lo_t *cr0_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __get_user(AS_WORD_P(cr0_lo),
|
|
(u64 __user *)(base + cr_ind + CR0_LO_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
static inline int
|
|
native_get_user_cr0_hi(e2k_cr0_hi_t *cr0_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __get_user(AS_WORD_P(cr0_hi),
|
|
(u64 __user *)(base + cr_ind + CR0_HI_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
static inline int
|
|
native_get_user_cr1_lo(e2k_cr1_lo_t *cr1_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __get_user(AS_WORD_P(cr1_lo),
|
|
(u64 __user *)(base + cr_ind + CR1_LO_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
static inline int
|
|
native_get_user_cr1_hi(e2k_cr1_hi_t *cr1_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __get_user(AS_WORD_P(cr1_hi),
|
|
(u64 __user *)(base + cr_ind + CR1_HI_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
static inline int
|
|
native_put_user_cr0_lo(e2k_cr0_lo_t cr0_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __put_user(AS_WORD(cr0_lo),
|
|
(u64 __user *)(base + cr_ind + CR0_LO_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
static inline int
|
|
native_put_user_cr0_hi(e2k_cr0_hi_t cr0_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __put_user(AS_WORD(cr0_hi),
|
|
(u64 __user *)(base + cr_ind + CR0_HI_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
static inline int
|
|
native_put_user_cr1_lo(e2k_cr1_lo_t cr1_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __put_user(AS_WORD(cr1_lo),
|
|
(u64 __user *)(base + cr_ind + CR1_LO_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
static inline int
|
|
native_put_user_cr1_hi(e2k_cr1_hi_t cr1_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __put_user(AS_WORD(cr1_hi),
|
|
(u64 __user *)(base + cr_ind + CR1_HI_I));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline void
|
|
native_get_kernel_cr0_lo(e2k_cr0_lo_t *cr0_lo,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
AS_WORD_P(cr0_lo) = *((u64 *)(base + cr_ind + CR0_LO_I));
|
|
}
|
|
static inline void
|
|
native_get_kernel_cr0_hi(e2k_cr0_hi_t *cr0_hi,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
AS_WORD_P(cr0_hi) = *((u64 *)(base + cr_ind + CR0_HI_I));
|
|
}
|
|
static inline void
|
|
native_get_kernel_cr1_lo(e2k_cr1_lo_t *cr1_lo,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
AS_WORD_P(cr1_lo) = *((u64 *)(base + cr_ind + CR1_LO_I));
|
|
}
|
|
static inline void
|
|
native_get_kernel_cr1_hi(e2k_cr1_hi_t *cr1_hi,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
AS_WORD_P(cr1_hi) = *((u64 *)(base + cr_ind + CR1_HI_I));
|
|
}
|
|
static inline void
|
|
native_put_kernel_cr0_lo(e2k_cr0_lo_t cr0_lo,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
*((u64 *)(base + cr_ind + CR0_LO_I)) = AS_WORD(cr0_lo);
|
|
}
|
|
static inline void
|
|
native_put_kernel_cr0_hi(e2k_cr0_hi_t cr0_hi,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
*((u64 *)(base + cr_ind + CR0_HI_I)) = AS_WORD(cr0_hi);
|
|
}
|
|
static inline void
|
|
native_put_kernel_cr1_lo(e2k_cr1_lo_t cr1_lo,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
*((u64 *)(base + cr_ind + CR1_LO_I)) = AS_WORD(cr1_lo);
|
|
}
|
|
static inline void
|
|
native_put_kernel_cr1_hi(e2k_cr1_hi_t cr1_hi,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
*((u64 *)(base + cr_ind + CR1_HI_I)) = AS_WORD(cr1_hi);
|
|
}
|
|
|
|
#ifdef CONFIG_PARAVIRT_GUEST
|
|
/* it is paravirtualized host and guest kernel */
|
|
#include <asm/paravirt/hw_stacks.h>
|
|
#elif defined(CONFIG_KVM_GUEST_KERNEL)
|
|
/* pure guest kernel (not paravirtualized) */
|
|
#include <asm/kvm/guest/hw_stacks.h>
|
|
#else /* ! CONFIG_PARAVIRT_GUEST && ! CONFIG_KVM_GUEST_KERNEL */
|
|
/* it is native kernel with or without virtualization support */
|
|
static inline unsigned long
|
|
get_active_cr0_lo_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr0_lo_value(base, cr_ind);
|
|
}
|
|
static inline unsigned long
|
|
get_active_cr0_hi_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr0_hi_value(base, cr_ind);
|
|
}
|
|
static inline unsigned long
|
|
get_active_cr1_lo_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr1_lo_value(base, cr_ind);
|
|
}
|
|
static inline unsigned long
|
|
get_active_cr1_hi_value(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_active_cr1_hi_value(base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_active_cr0_lo_value(unsigned long cr0_lo_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr0_lo_value(cr0_lo_value, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_active_cr0_hi_value(unsigned long cr0_hi_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr0_hi_value(cr0_hi_value, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_active_cr1_lo_value(unsigned long cr1_lo_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr1_lo_value(cr1_lo_value, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_active_cr1_hi_value(unsigned long cr1_hi_value,
|
|
e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_active_cr1_hi_value(cr1_hi_value, base, cr_ind);
|
|
}
|
|
#endif /* CONFIG_PARAVIRT */
|
|
|
|
static inline e2k_cr0_lo_t
|
|
get_active_cr0_lo(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr0_lo_t cr0_lo;
|
|
|
|
cr0_lo.CR0_lo_half = get_active_cr0_lo_value(base, cr_ind);
|
|
return cr0_lo;
|
|
}
|
|
static inline e2k_cr0_hi_t
|
|
get_active_cr0_hi(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr0_hi_t cr0_hi;
|
|
|
|
cr0_hi.CR0_hi_half = get_active_cr0_hi_value(base, cr_ind);
|
|
return cr0_hi;
|
|
}
|
|
static inline e2k_cr1_lo_t
|
|
get_active_cr1_lo(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr1_lo_t cr1_lo;
|
|
|
|
cr1_lo.CR1_lo_half = get_active_cr1_lo_value(base, cr_ind);
|
|
return cr1_lo;
|
|
}
|
|
static inline e2k_cr1_hi_t
|
|
get_active_cr1_hi(e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
e2k_cr1_hi_t cr1_hi;
|
|
|
|
cr1_hi.CR1_hi_half = get_active_cr1_hi_value(base, cr_ind);
|
|
return cr1_hi;
|
|
}
|
|
static inline void
|
|
put_active_cr0_lo(e2k_cr0_lo_t cr0_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
put_active_cr0_lo_value(cr0_lo.CR0_lo_half, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_active_cr0_hi(e2k_cr0_hi_t cr0_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
put_active_cr0_hi_value(cr0_hi.CR0_hi_half, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_active_cr1_lo(e2k_cr1_lo_t cr1_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
put_active_cr1_lo_value(cr1_lo.CR1_lo_half, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_active_cr1_hi(e2k_cr1_hi_t cr1_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
put_active_cr1_hi_value(cr1_hi.CR1_hi_half, base, cr_ind);
|
|
}
|
|
|
|
static inline int
|
|
get_user_cr0_lo(e2k_cr0_lo_t *cr0_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_user_cr0_lo(cr0_lo, base, cr_ind);
|
|
}
|
|
static inline int
|
|
get_user_cr0_hi(e2k_cr0_hi_t *cr0_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_user_cr0_hi(cr0_hi, base, cr_ind);
|
|
}
|
|
static inline int
|
|
get_user_cr1_lo(e2k_cr1_lo_t *cr1_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_user_cr1_lo(cr1_lo, base, cr_ind);
|
|
}
|
|
static inline int
|
|
get_user_cr1_hi(e2k_cr1_hi_t *cr1_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_get_user_cr1_hi(cr1_hi, base, cr_ind);
|
|
}
|
|
static inline int
|
|
put_user_cr0_lo(e2k_cr0_lo_t cr0_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_put_user_cr0_lo(cr0_lo, base, cr_ind);
|
|
}
|
|
static inline int
|
|
put_user_cr0_hi(e2k_cr0_hi_t cr0_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_put_user_cr0_hi(cr0_hi, base, cr_ind);
|
|
}
|
|
static inline int
|
|
put_user_cr1_lo(e2k_cr1_lo_t cr1_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_put_user_cr1_lo(cr1_lo, base, cr_ind);
|
|
}
|
|
static inline int
|
|
put_user_cr1_hi(e2k_cr1_hi_t cr1_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
return native_put_user_cr1_hi(cr1_hi, base, cr_ind);
|
|
}
|
|
|
|
static inline void
|
|
get_kernel_cr0_lo(e2k_cr0_lo_t *cr0_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_get_kernel_cr0_lo(cr0_lo, base, cr_ind);
|
|
}
|
|
static inline void
|
|
get_kernel_cr0_hi(e2k_cr0_hi_t *cr0_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_get_kernel_cr0_hi(cr0_hi, base, cr_ind);
|
|
}
|
|
static inline void
|
|
get_kernel_cr1_lo(e2k_cr1_lo_t *cr1_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_get_kernel_cr1_lo(cr1_lo, base, cr_ind);
|
|
}
|
|
static inline void
|
|
get_kernel_cr1_hi(e2k_cr1_hi_t *cr1_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_get_kernel_cr1_hi(cr1_hi, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_kernel_cr0_lo(e2k_cr0_lo_t cr0_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_kernel_cr0_lo(cr0_lo, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_kernel_cr0_hi(e2k_cr0_hi_t cr0_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_kernel_cr0_hi(cr0_hi, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_kernel_cr1_lo(e2k_cr1_lo_t cr1_lo, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_kernel_cr1_lo(cr1_lo, base, cr_ind);
|
|
}
|
|
static inline void
|
|
put_kernel_cr1_hi(e2k_cr1_hi_t cr1_hi, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
native_put_kernel_cr1_hi(cr1_hi, base, cr_ind);
|
|
}
|
|
|
|
static inline int
|
|
get_cr0_lo(e2k_cr0_lo_t *cr0_lo, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = get_user_cr0_lo(cr0_lo, base, cr_ind);
|
|
else
|
|
get_kernel_cr0_lo(cr0_lo, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
get_cr0_hi(e2k_cr0_hi_t *cr0_hi, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = get_user_cr0_hi(cr0_hi, base, cr_ind);
|
|
else
|
|
get_kernel_cr0_hi(cr0_hi, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
get_cr1_lo(e2k_cr1_lo_t *cr1_lo, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = get_user_cr1_lo(cr1_lo, base, cr_ind);
|
|
else
|
|
get_kernel_cr1_lo(cr1_lo, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
get_cr1_hi(e2k_cr1_hi_t *cr1_hi, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = get_user_cr1_hi(cr1_hi, base, cr_ind);
|
|
else
|
|
get_kernel_cr1_hi(cr1_hi, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
put_cr0_lo(e2k_cr0_lo_t cr0_lo, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = put_user_cr0_lo(cr0_lo, base, cr_ind);
|
|
else
|
|
put_kernel_cr0_lo(cr0_lo, base, cr_ind);
|
|
return ret;
|
|
}
|
|
static inline int
|
|
put_cr0_hi(e2k_cr0_hi_t cr0_hi, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = put_user_cr0_hi(cr0_hi, base, cr_ind);
|
|
else
|
|
put_kernel_cr0_hi(cr0_hi, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
put_cr1_lo(e2k_cr1_lo_t cr1_lo, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = put_user_cr1_lo(cr1_lo, base, cr_ind);
|
|
else
|
|
put_kernel_cr1_lo(cr1_lo, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
put_cr1_hi(e2k_cr1_hi_t cr1_hi, e2k_addr_t base, u64 cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = put_user_cr1_hi(cr1_hi, base, cr_ind);
|
|
else
|
|
put_kernel_cr1_hi(cr1_hi, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
get_cr0(e2k_cr0_lo_t *cr0_lo, e2k_cr0_hi_t *cr0_hi,
|
|
e2k_pcsp_lo_t pcsp_lo, u64 cr_ind)
|
|
{
|
|
u64 base = pcsp_lo.PCSP_lo_base;
|
|
int ret = 0;
|
|
|
|
ret += get_cr0_lo(cr0_lo, base, cr_ind);
|
|
ret += get_cr0_hi(cr0_hi, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
get_cr1(e2k_cr1_lo_t *cr1_lo, e2k_cr1_hi_t *cr1_hi,
|
|
e2k_pcsp_lo_t pcsp_lo, u64 cr_ind)
|
|
{
|
|
u64 base = pcsp_lo.PCSP_lo_base;
|
|
int ret = 0;
|
|
|
|
ret += get_cr1_lo(cr1_lo, base, cr_ind);
|
|
ret += get_cr1_hi(cr1_hi, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
get_user_crs(e2k_mem_crs_t *crs, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __copy_from_user(crs, (const char __user *)(base + cr_ind),
|
|
sizeof(*crs));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
put_user_crs(e2k_mem_crs_t *crs, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
unsigned long ts_flag;
|
|
int ret;
|
|
|
|
ts_flag = set_ts_flag(TS_KERNEL_SYSCALL);
|
|
ret = __copy_to_user((char __user *)(base + cr_ind), crs,
|
|
sizeof(*crs));
|
|
clear_ts_flag(ts_flag);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline void
|
|
get_kernel_crs(e2k_mem_crs_t *crs, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
get_kernel_cr0_lo(&crs->cr0_lo, base, cr_ind);
|
|
get_kernel_cr0_hi(&crs->cr0_hi, base, cr_ind);
|
|
get_kernel_cr1_lo(&crs->cr1_lo, base, cr_ind);
|
|
get_kernel_cr1_hi(&crs->cr1_hi, base, cr_ind);
|
|
}
|
|
|
|
static inline void
|
|
put_kernel_crs(e2k_mem_crs_t *crs, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
put_kernel_cr0_lo(crs->cr0_lo, base, cr_ind);
|
|
put_kernel_cr0_hi(crs->cr0_hi, base, cr_ind);
|
|
put_kernel_cr1_lo(crs->cr1_lo, base, cr_ind);
|
|
put_kernel_cr1_hi(crs->cr1_hi, base, cr_ind);
|
|
}
|
|
|
|
static inline int
|
|
get_crs(e2k_mem_crs_t *crs, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = get_user_crs(crs, base, cr_ind);
|
|
else
|
|
get_kernel_crs(crs, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
put_crs(e2k_mem_crs_t *crs, e2k_addr_t base, e2k_addr_t cr_ind)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (base < TASK_SIZE)
|
|
ret = put_user_crs(crs, base, cr_ind);
|
|
else
|
|
put_kernel_crs(crs, base, cr_ind);
|
|
return ret;
|
|
}
|
|
|
|
extern int chain_stack_frame_init(e2k_mem_crs_t *crs, void *fn_ptr,
|
|
size_t dstack_size, e2k_psr_t psr,
|
|
int wbs, int wpsz, bool user);
|
|
|
|
extern void __update_psp_regs(unsigned long base, unsigned long size,
|
|
unsigned long new_fp,
|
|
e2k_psp_lo_t *psp_lo, e2k_psp_hi_t *psp_hi);
|
|
extern void update_psp_regs(unsigned long new_fp,
|
|
e2k_psp_lo_t *psp_lo, e2k_psp_hi_t *psp_hi);
|
|
|
|
extern void __update_pcsp_regs(unsigned long base, unsigned long size,
|
|
unsigned long new_fp,
|
|
e2k_pcsp_lo_t *pcsp_lo, e2k_pcsp_hi_t *pcsp_hi);
|
|
extern void update_pcsp_regs(unsigned long new_fp,
|
|
e2k_pcsp_lo_t *pcsp_lo, e2k_pcsp_hi_t *pcsp_hi);
|
|
|
|
#endif /* _E2K_HW_STACKS_H */
|