⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reg_ld_str.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Put a long into user memory */int FPU_store_int32(FPU_REG *st0_ptr, u_char st0_tag, long __user *d){  FPU_REG t;  int precision_loss;  if ( st0_tag == TAG_Empty )    {      /* Empty register (stack underflow) */      EXCEPTION(EX_StackUnder);      goto invalid_operand;    }  else if ( st0_tag == TAG_Special )    {      st0_tag = FPU_Special(st0_ptr);      if ( (st0_tag == TW_Infinity) ||	   (st0_tag == TW_NaN) )	{	  EXCEPTION(EX_Invalid);	  goto invalid_operand;	}    }  reg_copy(st0_ptr, &t);  precision_loss = FPU_round_to_int(&t, st0_tag);  if (t.sigh ||      ((t.sigl & 0x80000000) &&       !((t.sigl == 0x80000000) && signnegative(&t))) )    {      EXCEPTION(EX_Invalid);      /* This is a special case: see sec 16.2.5.1 of the 80486 book */    invalid_operand:      if ( control_word & EX_Invalid )	{	  /* Produce something like QNaN "indefinite" */	  t.sigl = 0x80000000;	}      else	return 0;    }  else    {      if ( precision_loss )	set_precision_flag(precision_loss);      if ( signnegative(&t) )	t.sigl = -(long)t.sigl;    }  RE_ENTRANT_CHECK_OFF;  FPU_access_ok(VERIFY_WRITE,d,4);  FPU_put_user(t.sigl, (unsigned long __user *) d);  RE_ENTRANT_CHECK_ON;  return 1;}/* Put a short into user memory */int FPU_store_int16(FPU_REG *st0_ptr, u_char st0_tag, short __user *d){  FPU_REG t;  int precision_loss;  if ( st0_tag == TAG_Empty )    {      /* Empty register (stack underflow) */      EXCEPTION(EX_StackUnder);      goto invalid_operand;    }  else if ( st0_tag == TAG_Special )    {      st0_tag = FPU_Special(st0_ptr);      if ( (st0_tag == TW_Infinity) ||	   (st0_tag == TW_NaN) )	{	  EXCEPTION(EX_Invalid);	  goto invalid_operand;	}    }  reg_copy(st0_ptr, &t);  precision_loss = FPU_round_to_int(&t, st0_tag);  if (t.sigh ||      ((t.sigl & 0xffff8000) &&       !((t.sigl == 0x8000) && signnegative(&t))) )    {      EXCEPTION(EX_Invalid);      /* This is a special case: see sec 16.2.5.1 of the 80486 book */    invalid_operand:      if ( control_word & EX_Invalid )	{	  /* Produce something like QNaN "indefinite" */	  t.sigl = 0x8000;	}      else	return 0;    }  else    {      if ( precision_loss )	set_precision_flag(precision_loss);      if ( signnegative(&t) )	t.sigl = -t.sigl;    }  RE_ENTRANT_CHECK_OFF;  FPU_access_ok(VERIFY_WRITE,d,2);  FPU_put_user((short)t.sigl, d);  RE_ENTRANT_CHECK_ON;  return 1;}/* Put a packed bcd array into user memory */int FPU_store_bcd(FPU_REG *st0_ptr, u_char st0_tag, u_char __user *d){  FPU_REG t;  unsigned long long ll;  u_char b;  int i, precision_loss;  u_char sign = (getsign(st0_ptr) == SIGN_NEG) ? 0x80 : 0;  if ( st0_tag == TAG_Empty )    {      /* Empty register (stack underflow) */      EXCEPTION(EX_StackUnder);      goto invalid_operand;    }  else if ( st0_tag == TAG_Special )    {      st0_tag = FPU_Special(st0_ptr);      if ( (st0_tag == TW_Infinity) ||	   (st0_tag == TW_NaN) )	{	  EXCEPTION(EX_Invalid);	  goto invalid_operand;	}    }  reg_copy(st0_ptr, &t);  precision_loss = FPU_round_to_int(&t, st0_tag);  ll = significand(&t);  /* Check for overflow, by comparing with 999999999999999999 decimal. */  if ( (t.sigh > 0x0de0b6b3) ||      ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )    {      EXCEPTION(EX_Invalid);      /* This is a special case: see sec 16.2.5.1 of the 80486 book */    invalid_operand:      if ( control_word & CW_Invalid )	{	  /* Produce the QNaN "indefinite" */	  RE_ENTRANT_CHECK_OFF;	  FPU_access_ok(VERIFY_WRITE,d,10);	  for ( i = 0; i < 7; i++)	    FPU_put_user(0, d+i); /* These bytes "undefined" */	  FPU_put_user(0xc0, d+7); /* This byte "undefined" */	  FPU_put_user(0xff, d+8);	  FPU_put_user(0xff, d+9);	  RE_ENTRANT_CHECK_ON;	  return 1;	}      else	return 0;    }  else if ( precision_loss )    {      /* Precision loss doesn't stop the data transfer */      set_precision_flag(precision_loss);    }  RE_ENTRANT_CHECK_OFF;  FPU_access_ok(VERIFY_WRITE,d,10);  RE_ENTRANT_CHECK_ON;  for ( i = 0; i < 9; i++)    {      b = FPU_div_small(&ll, 10);      b |= (FPU_div_small(&ll, 10)) << 4;      RE_ENTRANT_CHECK_OFF;      FPU_put_user(b, d+i);      RE_ENTRANT_CHECK_ON;    }  RE_ENTRANT_CHECK_OFF;  FPU_put_user(sign, d+9);  RE_ENTRANT_CHECK_ON;  return 1;}/*===========================================================================*//* r gets mangled such that sig is int, sign:    it is NOT normalized *//* The return value (in eax) is zero if the result is exact,   if bits are changed due to rounding, truncation, etc, then   a non-zero value is returned *//* Overflow is signalled by a non-zero return value (in eax).   In the case of overflow, the returned significand always has the   largest possible value */int FPU_round_to_int(FPU_REG *r, u_char tag){  u_char     very_big;  unsigned eax;  if (tag == TAG_Zero)    {      /* Make sure that zero is returned */      significand(r) = 0;      return 0;        /* o.k. */    }  if (exponent(r) > 63)    {      r->sigl = r->sigh = ~0;      /* The largest representable number */      return 1;        /* overflow */    }  eax = FPU_shrxs(&r->sigl, 63 - exponent(r));  very_big = !(~(r->sigh) | ~(r->sigl));  /* test for 0xfff...fff */#define	half_or_more	(eax & 0x80000000)#define	frac_part	(eax)#define more_than_half  ((eax & 0x80000001) == 0x80000001)  switch (control_word & CW_RC)    {    case RC_RND:      if ( more_than_half               	/* nearest */	  || (half_or_more && (r->sigl & 1)) )	/* odd -> even */	{	  if ( very_big ) return 1;        /* overflow */	  significand(r) ++;	  return PRECISION_LOST_UP;	}      break;    case RC_DOWN:      if (frac_part && getsign(r))	{	  if ( very_big ) return 1;        /* overflow */	  significand(r) ++;	  return PRECISION_LOST_UP;	}      break;    case RC_UP:      if (frac_part && !getsign(r))	{	  if ( very_big ) return 1;        /* overflow */	  significand(r) ++;	  return PRECISION_LOST_UP;	}      break;    case RC_CHOP:      break;    }  return eax ? PRECISION_LOST_DOWN : 0;}/*===========================================================================*/u_char __user *fldenv(fpu_addr_modes addr_modes, u_char __user *s){  unsigned short tag_word = 0;  u_char tag;  int i;  if ( (addr_modes.default_mode == VM86) ||      ((addr_modes.default_mode == PM16)      ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )    {      RE_ENTRANT_CHECK_OFF;      FPU_access_ok(VERIFY_READ, s, 0x0e);      FPU_get_user(control_word, (unsigned short __user *) s);      FPU_get_user(partial_status, (unsigned short __user *) (s+2));      FPU_get_user(tag_word, (unsigned short __user *) (s+4));      FPU_get_user(instruction_address.offset, (unsigned short __user *) (s+6));      FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+8));      FPU_get_user(operand_address.offset, (unsigned short __user *) (s+0x0a));      FPU_get_user(operand_address.selector, (unsigned short __user *) (s+0x0c));      RE_ENTRANT_CHECK_ON;      s += 0x0e;      if ( addr_modes.default_mode == VM86 )	{	  instruction_address.offset	    += (instruction_address.selector & 0xf000) << 4;	  operand_address.offset += (operand_address.selector & 0xf000) << 4;	}    }  else    {      RE_ENTRANT_CHECK_OFF;      FPU_access_ok(VERIFY_READ, s, 0x1c);      FPU_get_user(control_word, (unsigned short __user *) s);      FPU_get_user(partial_status, (unsigned short __user *) (s+4));      FPU_get_user(tag_word, (unsigned short __user *) (s+8));      FPU_get_user(instruction_address.offset, (unsigned long __user *) (s+0x0c));      FPU_get_user(instruction_address.selector, (unsigned short __user *) (s+0x10));      FPU_get_user(instruction_address.opcode, (unsigned short __user *) (s+0x12));      FPU_get_user(operand_address.offset, (unsigned long __user *) (s+0x14));      FPU_get_user(operand_address.selector, (unsigned long __user *) (s+0x18));      RE_ENTRANT_CHECK_ON;      s += 0x1c;    }#ifdef PECULIAR_486  control_word &= ~0xe080;#endif /* PECULIAR_486 */   top = (partial_status >> SW_Top_Shift) & 7;  if ( partial_status & ~control_word & CW_Exceptions )    partial_status |= (SW_Summary | SW_Backward);  else    partial_status &= ~(SW_Summary | SW_Backward);  for ( i = 0; i < 8; i++ )    {      tag = tag_word & 3;      tag_word >>= 2;      if ( tag == TAG_Empty )	/* New tag is empty.  Accept it */	FPU_settag(i, TAG_Empty);      else if ( FPU_gettag(i) == TAG_Empty )	{	  /* Old tag is empty and new tag is not empty.  New tag is determined	     by old reg contents */	  if ( exponent(&fpu_register(i)) == - EXTENDED_Ebias )	    {	      if ( !(fpu_register(i).sigl | fpu_register(i).sigh) )		FPU_settag(i, TAG_Zero);	      else		FPU_settag(i, TAG_Special);	    }	  else if ( exponent(&fpu_register(i)) == 0x7fff - EXTENDED_Ebias )	    {	      FPU_settag(i, TAG_Special);	    }	  else if ( fpu_register(i).sigh & 0x80000000 )	    FPU_settag(i, TAG_Valid);	  else	    FPU_settag(i, TAG_Special);   /* An Un-normal */  	}      /* Else old tag is not empty and new tag is not empty.  Old tag	 remains correct */    }  return s;}void frstor(fpu_addr_modes addr_modes, u_char __user *data_address){  int i, regnr;  u_char __user *s = fldenv(addr_modes, data_address);  int offset = (top & 7) * 10, other = 80 - offset;  /* Copy all registers in stack order. */  RE_ENTRANT_CHECK_OFF;  FPU_access_ok(VERIFY_READ,s,80);  __copy_from_user(register_base+offset, s, other);  if ( offset )    __copy_from_user(register_base, s+other, offset);  RE_ENTRANT_CHECK_ON;  for ( i = 0; i < 8; i++ )    {      regnr = (i+top) & 7;      if ( FPU_gettag(regnr) != TAG_Empty )	/* The loaded data over-rides all other cases. */	FPU_settag(regnr, FPU_tagof(&st(i)));    }}u_char __user *fstenv(fpu_addr_modes addr_modes, u_char __user *d){  if ( (addr_modes.default_mode == VM86) ||      ((addr_modes.default_mode == PM16)      ^ (addr_modes.override.operand_size == OP_SIZE_PREFIX)) )    {      RE_ENTRANT_CHECK_OFF;      FPU_access_ok(VERIFY_WRITE,d,14);#ifdef PECULIAR_486      FPU_put_user(control_word & ~0xe080, (unsigned long __user *) d);#else      FPU_put_user(control_word, (unsigned short __user *) d);#endif /* PECULIAR_486 */      FPU_put_user(status_word(), (unsigned short __user *) (d+2));      FPU_put_user(fpu_tag_word, (unsigned short __user *) (d+4));      FPU_put_user(instruction_address.offset, (unsigned short __user *) (d+6));      FPU_put_user(operand_address.offset, (unsigned short __user *) (d+0x0a));      if ( addr_modes.default_mode == VM86 )	{	  FPU_put_user((instruction_address.offset & 0xf0000) >> 4,		      (unsigned short __user *) (d+8));	  FPU_put_user((operand_address.offset & 0xf0000) >> 4,		      (unsigned short __user *) (d+0x0c));	}      else	{	  FPU_put_user(instruction_address.selector, (unsigned short __user *) (d+8));	  FPU_put_user(operand_address.selector, (unsigned short __user *) (d+0x0c));	}      RE_ENTRANT_CHECK_ON;      d += 0x0e;    }  else    {      RE_ENTRANT_CHECK_OFF;      FPU_access_ok(VERIFY_WRITE, d, 7*4);#ifdef PECULIAR_486      control_word &= ~0xe080;      /* An 80486 sets nearly all of the reserved bits to 1. */      control_word |= 0xffff0040;      partial_status = status_word() | 0xffff0000;      fpu_tag_word |= 0xffff0000;      I387.soft.fcs &= ~0xf8000000;      I387.soft.fos |= 0xffff0000;#endif /* PECULIAR_486 */      if (__copy_to_user(d, &control_word, 7*4))	FPU_abort;      RE_ENTRANT_CHECK_ON;      d += 0x1c;    }    control_word |= CW_Exceptions;  partial_status &= ~(SW_Summary | SW_Backward);  return d;}void fsave(fpu_addr_modes addr_modes, u_char __user *data_address){  u_char __user *d;  int offset = (top & 7) * 10, other = 80 - offset;  d = fstenv(addr_modes, data_address);  RE_ENTRANT_CHECK_OFF;  FPU_access_ok(VERIFY_WRITE,d,80);  /* Copy all registers in stack order. */  if (__copy_to_user(d, register_base+offset, other))    FPU_abort;  if ( offset )    if (__copy_to_user(d+other, register_base, offset))      FPU_abort;  RE_ENTRANT_CHECK_ON;  finit();}/*===========================================================================*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -