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

📄 fpu_entry.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 2 页
字号:
			loaded_tag = FPU_Special(&loaded_data);#ifdef PECULIAR_486		      /* This is not really needed, but gives behaviour			 identical to an 80486 */		      if ( (FPU_modrm & 0x28) == 0x20 )			/* fdiv or fsub */			real_2op_NaN(&loaded_data, loaded_tag, 0, &loaded_data);		      else#endif /* PECULIAR_486 */ 			/* fadd, fdivr, fmul, or fsubr */			real_2op_NaN(&loaded_data, loaded_tag, 0, st0_ptr);		    }		  goto reg_mem_instr_done;		}	      if ( unmasked && !((FPU_modrm & 0x30) == 0x10) )		{		  /* Is not a comparison instruction. */		  if ( (FPU_modrm & 0x38) == 0x38 )		    {		      /* fdivr */		      if ( (st0_tag == TAG_Zero) &&			   ((loaded_tag == TAG_Valid)			    || (loaded_tag == TAG_Special				&& isdenormal(&loaded_data))) )			{			  if ( FPU_divide_by_zero(0, getsign(&loaded_data))			       < 0 )			    {			      /* We use the fact here that the unmasked				 exception in the loaded data was for a				 denormal operand */			      /* Restore the state of the denormal op bit */			      partial_status &= ~SW_Denorm_Op;			      partial_status |= status1 & SW_Denorm_Op;			    }			  else			    setsign(st0_ptr, getsign(&loaded_data));			}		    }		  goto reg_mem_instr_done;		}	      switch ( (FPU_modrm >> 3) & 7 )		{		case 0:         /* fadd */		  clear_C1();		  FPU_add(&loaded_data, loaded_tag, 0, control_word);		  break;		case 1:         /* fmul */		  clear_C1();		  FPU_mul(&loaded_data, loaded_tag, 0, control_word);		  break;		case 2:         /* fcom */		  FPU_compare_st_data(&loaded_data, loaded_tag);		  break;		case 3:         /* fcomp */		  if ( !FPU_compare_st_data(&loaded_data, loaded_tag)		       && !unmasked )		    FPU_pop();		  break;		case 4:         /* fsub */		  clear_C1();		  FPU_sub(LOADED|loaded_tag, (int)&loaded_data, control_word);		  break;		case 5:         /* fsubr */		  clear_C1();		  FPU_sub(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);		  break;		case 6:         /* fdiv */		  clear_C1();		  FPU_div(LOADED|loaded_tag, (int)&loaded_data, control_word);		  break;		case 7:         /* fdivr */		  clear_C1();		  if ( st0_tag == TAG_Zero )		    partial_status = status1;  /* Undo any denorm tag,						  zero-divide has priority. */		  FPU_div(REV|LOADED|loaded_tag, (int)&loaded_data, control_word);		  break;		}	    }	  else	    {	      if ( (FPU_modrm & 0x30) == 0x10 )		{		  /* The instruction is fcom or fcomp */		  EXCEPTION(EX_StackUnder);		  setcc(SW_C3 | SW_C2 | SW_C0);		  if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) )		    FPU_pop();             /* fcomp */		}	      else		FPU_stack_underflow();	    }	reg_mem_instr_done:	  operand_address = data_sel_off;	}      else	{	  if ( !(no_ip_update =		 FPU_load_store(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1,				addr_modes, data_address)) )	    {	      operand_address = data_sel_off;	    }	}    }  else    {      /* None of these instructions access user memory */      u_char instr_index = (FPU_modrm & 0x38) | (byte1 & 7);#ifdef PECULIAR_486      /* This is supposed to be undefined, but a real 80486 seems	 to do this: */      operand_address.offset = 0;      operand_address.selector = FPU_DS;#endif /* PECULIAR_486 */      st0_ptr = &st(0);      st0_tag = FPU_gettag0();      switch ( type_table[(int) instr_index] )	{	case _NONE_:   /* also _REGIc: _REGIn */	  break;	case _REG0_:	  if ( !NOT_EMPTY_ST0 )	    {	      FPU_stack_underflow();	      goto FPU_instruction_done;	    }	  break;	case _REGIi:	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )	    {	      FPU_stack_underflow_i(FPU_rm);	      goto FPU_instruction_done;	    }	  break;	case _REGIp:	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )	    {	      FPU_stack_underflow_pop(FPU_rm);	      goto FPU_instruction_done;	    }	  break;	case _REGI_:	  if ( !NOT_EMPTY_ST0 || !NOT_EMPTY(FPU_rm) )	    {	      FPU_stack_underflow();	      goto FPU_instruction_done;	    }	  break;	case _PUSH_:     /* Only used by the fld st(i) instruction */	  break;	case _null_:	  FPU_illegal();	  goto FPU_instruction_done;	default:	  EXCEPTION(EX_INTERNAL|0x111);	  goto FPU_instruction_done;	}      (*st_instr_table[(int) instr_index])();FPU_instruction_done:      ;    }  if ( ! no_ip_update )    instruction_address = entry_sel_off;FPU_fwait_done:#ifdef DEBUG  RE_ENTRANT_CHECK_OFF;  FPU_printall();  RE_ENTRANT_CHECK_ON;#endif /* DEBUG */  if (FPU_lookahead && !current->need_resched)    {      FPU_ORIG_EIP = FPU_EIP - code_base;      if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,			&addr_modes.override) )	goto do_another_FPU_instruction;    }  if ( addr_modes.default_mode )    FPU_EIP -= code_base;  RE_ENTRANT_CHECK_OFF;}/* Support for prefix bytes is not yet complete. To properly handle   all prefix bytes, further changes are needed in the emulator code   which accesses user address space. Access to separate segments is   important for msdos emulation. */static int valid_prefix(u_char *Byte, u_char **fpu_eip,			overrides *override){  u_char byte;  u_char *ip = *fpu_eip;  *override = (overrides) { 0, 0, PREFIX_DEFAULT };       /* defaults */  RE_ENTRANT_CHECK_OFF;  FPU_code_verify_area(1);  FPU_get_user(byte, ip);  RE_ENTRANT_CHECK_ON;  while ( 1 )    {      switch ( byte )	{	case ADDR_SIZE_PREFIX:	  override->address_size = ADDR_SIZE_PREFIX;	  goto do_next_byte;	case OP_SIZE_PREFIX:	  override->operand_size = OP_SIZE_PREFIX;	  goto do_next_byte;	case PREFIX_CS:	  override->segment = PREFIX_CS_;	  goto do_next_byte;	case PREFIX_ES:	  override->segment = PREFIX_ES_;	  goto do_next_byte;	case PREFIX_SS:	  override->segment = PREFIX_SS_;	  goto do_next_byte;	case PREFIX_FS:	  override->segment = PREFIX_FS_;	  goto do_next_byte;	case PREFIX_GS:	  override->segment = PREFIX_GS_;	  goto do_next_byte;	case PREFIX_DS:	  override->segment = PREFIX_DS_;	  goto do_next_byte;/* lock is not a valid prefix for FPU instructions,   let the cpu handle it to generate a SIGILL. *//*	case PREFIX_LOCK: */	  /* rep.. prefixes have no meaning for FPU instructions */	case PREFIX_REPE:	case PREFIX_REPNE:	do_next_byte:	  ip++;	  RE_ENTRANT_CHECK_OFF;	  FPU_code_verify_area(1);	  FPU_get_user(byte, ip);	  RE_ENTRANT_CHECK_ON;	  break;	case FWAIT_OPCODE:	  *Byte = byte;	  return 1;	default:	  if ( (byte & 0xf8) == 0xd8 )	    {	      *Byte = byte;	      *fpu_eip = ip;	      return 1;	    }	  else	    {	      /* Not a valid sequence of prefix bytes followed by		 an FPU instruction. */	      *Byte = byte;  /* Needed for error message. */	      return 0;	    }	}    }}void math_abort(struct info * info, unsigned int signal){	FPU_EIP = FPU_ORIG_EIP;	current->thread.trap_no = 16;	current->thread.error_code = 0;	send_sig(signal,current,1);	RE_ENTRANT_CHECK_OFF;	__asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4));#ifdef PARANOID      printk("ERROR: wm-FPU-emu math_abort failed!\n");#endif /* PARANOID */}#define S387 ((struct i387_soft_struct *)s387)#define sstatus_word() \  ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top))int restore_i387_soft(void *s387, struct _fpstate *buf){  u_char *d = (u_char *)buf;  int offset, other, i, tags, regnr, tag, newtop;  RE_ENTRANT_CHECK_OFF;  FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10);  if (__copy_from_user(&S387->cwd, d, 7*4))    return -1;  RE_ENTRANT_CHECK_ON;  d += 7*4;  S387->ftop = (S387->swd >> SW_Top_Shift) & 7;  offset = (S387->ftop & 7) * 10;  other = 80 - offset;  RE_ENTRANT_CHECK_OFF;  /* Copy all registers in stack order. */  if (__copy_from_user(((u_char *)&S387->st_space)+offset, d, other))    return -1;  if ( offset )    if (__copy_from_user((u_char *)&S387->st_space, d+other, offset))      return -1;  RE_ENTRANT_CHECK_ON;  /* The tags may need to be corrected now. */  tags = S387->twd;  newtop = S387->ftop;  for ( i = 0; i < 8; i++ )    {      regnr = (i+newtop) & 7;      if ( ((tags >> ((regnr & 7)*2)) & 3) != TAG_Empty )	{	  /* The loaded data over-rides all other cases. */	  tag = FPU_tagof((FPU_REG *)((u_char *)S387->st_space + 10*regnr));	  tags &= ~(3 << (regnr*2));	  tags |= (tag & 3) << (regnr*2);	}    }  S387->twd = tags;  return 0;}int save_i387_soft(void *s387, struct _fpstate * buf){  u_char *d = (u_char *)buf;  int offset = (S387->ftop & 7) * 10, other = 80 - offset;  RE_ENTRANT_CHECK_OFF;  FPU_verify_area(VERIFY_WRITE, d, 7*4 + 8*10);#ifdef PECULIAR_486  S387->cwd &= ~0xe080;  /* An 80486 sets nearly all of the reserved bits to 1. */  S387->cwd |= 0xffff0040;  S387->swd = sstatus_word() | 0xffff0000;  S387->twd |= 0xffff0000;  S387->fcs &= ~0xf8000000;  S387->fos |= 0xffff0000;#endif /* PECULIAR_486 */  __copy_to_user(d, &S387->cwd, 7*4);  RE_ENTRANT_CHECK_ON;  d += 7*4;  RE_ENTRANT_CHECK_OFF;  /* Copy all registers in stack order. */  if (__copy_to_user(d, ((u_char *)&S387->st_space)+offset, other))    return -1;  if ( offset )    if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset))      return -1  RE_ENTRANT_CHECK_ON;  return 1;}

⌨️ 快捷键说明

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