/* SPDX-License-Identifier: GPL-2.0 */ 
 | 
/*---------------------------------------------------------------------------+ 
 | 
 |  fpu_system.h                                                             | 
 | 
 |                                                                           | 
 | 
 | Copyright (C) 1992,1994,1997                                              | 
 | 
 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      | 
 | 
 |                       Australia.  E-mail   billm@suburbia.net             | 
 | 
 |                                                                           | 
 | 
 +---------------------------------------------------------------------------*/ 
 | 
  
 | 
#ifndef _FPU_SYSTEM_H 
 | 
#define _FPU_SYSTEM_H 
 | 
  
 | 
/* system dependent definitions */ 
 | 
  
 | 
#include <linux/sched.h> 
 | 
#include <linux/kernel.h> 
 | 
#include <linux/mm.h> 
 | 
  
 | 
#include <asm/desc.h> 
 | 
#include <asm/mmu_context.h> 
 | 
  
 | 
static inline struct desc_struct FPU_get_ldt_descriptor(unsigned seg) 
 | 
{ 
 | 
    static struct desc_struct zero_desc; 
 | 
    struct desc_struct ret = zero_desc; 
 | 
  
 | 
#ifdef CONFIG_MODIFY_LDT_SYSCALL 
 | 
    seg >>= 3; 
 | 
    mutex_lock(¤t->mm->context.lock); 
 | 
    if (current->mm->context.ldt && seg < current->mm->context.ldt->nr_entries) 
 | 
        ret = current->mm->context.ldt->entries[seg]; 
 | 
    mutex_unlock(¤t->mm->context.lock); 
 | 
#endif 
 | 
    return ret; 
 | 
} 
 | 
  
 | 
#define SEG_TYPE_WRITABLE    (1U << 1) 
 | 
#define SEG_TYPE_EXPANDS_DOWN    (1U << 2) 
 | 
#define SEG_TYPE_EXECUTE    (1U << 3) 
 | 
#define SEG_TYPE_EXPAND_MASK    (SEG_TYPE_EXPANDS_DOWN | SEG_TYPE_EXECUTE) 
 | 
#define SEG_TYPE_EXECUTE_MASK    (SEG_TYPE_WRITABLE | SEG_TYPE_EXECUTE) 
 | 
  
 | 
static inline unsigned long seg_get_base(struct desc_struct *d) 
 | 
{ 
 | 
    unsigned long base = (unsigned long)d->base2 << 24; 
 | 
  
 | 
    return base | ((unsigned long)d->base1 << 16) | d->base0; 
 | 
} 
 | 
  
 | 
static inline unsigned long seg_get_limit(struct desc_struct *d) 
 | 
{ 
 | 
    return ((unsigned long)d->limit1 << 16) | d->limit0; 
 | 
} 
 | 
  
 | 
static inline unsigned long seg_get_granularity(struct desc_struct *d) 
 | 
{ 
 | 
    return d->g ? 4096 : 1; 
 | 
} 
 | 
  
 | 
static inline bool seg_expands_down(struct desc_struct *d) 
 | 
{ 
 | 
    return (d->type & SEG_TYPE_EXPAND_MASK) == SEG_TYPE_EXPANDS_DOWN; 
 | 
} 
 | 
  
 | 
static inline bool seg_execute_only(struct desc_struct *d) 
 | 
{ 
 | 
    return (d->type & SEG_TYPE_EXECUTE_MASK) == SEG_TYPE_EXECUTE; 
 | 
} 
 | 
  
 | 
static inline bool seg_writable(struct desc_struct *d) 
 | 
{ 
 | 
    return (d->type & SEG_TYPE_EXECUTE_MASK) == SEG_TYPE_WRITABLE; 
 | 
} 
 | 
  
 | 
#define I387            (¤t->thread.fpu.state) 
 | 
#define FPU_info        (I387->soft.info) 
 | 
  
 | 
#define FPU_CS            (*(unsigned short *) &(FPU_info->regs->cs)) 
 | 
#define FPU_SS            (*(unsigned short *) &(FPU_info->regs->ss)) 
 | 
#define FPU_DS            (*(unsigned short *) &(FPU_info->regs->ds)) 
 | 
#define FPU_EAX            (FPU_info->regs->ax) 
 | 
#define FPU_EFLAGS        (FPU_info->regs->flags) 
 | 
#define FPU_EIP            (FPU_info->regs->ip) 
 | 
#define FPU_ORIG_EIP        (FPU_info->___orig_eip) 
 | 
  
 | 
#define FPU_lookahead           (I387->soft.lookahead) 
 | 
  
 | 
/* nz if ip_offset and cs_selector are not to be set for the current 
 | 
   instruction. */ 
 | 
#define no_ip_update        (*(u_char *)&(I387->soft.no_update)) 
 | 
#define FPU_rm            (*(u_char *)&(I387->soft.rm)) 
 | 
  
 | 
/* Number of bytes of data which can be legally accessed by the current 
 | 
   instruction. This only needs to hold a number <= 108, so a byte will do. */ 
 | 
#define access_limit        (*(u_char *)&(I387->soft.alimit)) 
 | 
  
 | 
#define partial_status        (I387->soft.swd) 
 | 
#define control_word        (I387->soft.cwd) 
 | 
#define fpu_tag_word        (I387->soft.twd) 
 | 
#define registers        (I387->soft.st_space) 
 | 
#define top            (I387->soft.ftop) 
 | 
  
 | 
#define instruction_address    (*(struct address *)&I387->soft.fip) 
 | 
#define operand_address        (*(struct address *)&I387->soft.foo) 
 | 
  
 | 
#define FPU_access_ok(x,y,z)    if ( !access_ok(x,y,z) ) \ 
 | 
                math_abort(FPU_info,SIGSEGV) 
 | 
#define FPU_abort        math_abort(FPU_info, SIGSEGV) 
 | 
  
 | 
#undef FPU_IGNORE_CODE_SEGV 
 | 
#ifdef FPU_IGNORE_CODE_SEGV 
 | 
/* access_ok() is very expensive, and causes the emulator to run 
 | 
   about 20% slower if applied to the code. Anyway, errors due to bad 
 | 
   code addresses should be much rarer than errors due to bad data 
 | 
   addresses. */ 
 | 
#define    FPU_code_access_ok(z) 
 | 
#else 
 | 
/* A simpler test than access_ok() can probably be done for 
 | 
   FPU_code_access_ok() because the only possible error is to step 
 | 
   past the upper boundary of a legal code area. */ 
 | 
#define    FPU_code_access_ok(z) FPU_access_ok(VERIFY_READ,(void __user *)FPU_EIP,z) 
 | 
#endif 
 | 
  
 | 
#define FPU_get_user(x,y)       get_user((x),(y)) 
 | 
#define FPU_put_user(x,y)       put_user((x),(y)) 
 | 
  
 | 
#endif 
 |