Exemple #1
0
int V86HandleOpcode (struct ContextState *state)
{
	bool is_operand32 = FALSE;
	bool is_address32 = FALSE;
	uint32 *sp32;
	uint16 *sp16;
	uint32 eflags;
	uint8 *ip;
		
	uint32 new_ip;
	uint32 new_cs;
	uint8 *vector;

	
	
	
	while (1)
	{
		ip = V86GetAddress (state->return_eip, state->return_cs);
		
		switch (*ip)
		{
			case PREFIX_O32:
				is_operand32 = TRUE;
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				continue;
				
			case PREFIX_A32:
				is_address32 = TRUE;
				ip++;
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				continue;
			
				
			case OPCODE_PUSHF:
				if (is_operand32 == TRUE)
				{
					state->return_esp = ((state->return_esp & 0x0000ffff) - 4) & 0x0000ffff;
					sp32 = V86GetAddress (state->return_esp, state->return_ss);
					eflags = state->return_eflags & V86_EFLAG_MASK;

					*sp32 = (v86_if == TRUE)
							? eflags | EFLAG_IF
							: eflags & ~EFLAG_IF;
				}
				else
				{
					state->return_esp = ((state->return_esp & 0x0000ffff) - 2) & 0x0000ffff; 
					sp16 = V86GetAddress (state->return_esp, state->return_ss);
					eflags = state->return_eflags & V86_EFLAG_MASK;

					*sp16 = (uint16) (v86_if == TRUE)
							? eflags | EFLAG_IF
							: eflags & ~EFLAG_IF;					
					
				}
			
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;
				
			case OPCODE_POPF:
				if (is_operand32 == TRUE)
				{
					sp32 = V86GetAddress (state->return_esp, state->return_ss);
					eflags = *sp32;
					state->return_eflags = (eflags & V86_EFLAG_MASK) | EFLAG_IF | EFLAG_VM;
					v86_if = (eflags & EFLAG_IF) ? TRUE : FALSE;
					state->return_esp = ((state->return_esp & 0x0000ffff) + 4) & 0x0000ffff;
				}
				else
				{
					sp16 = V86GetAddress (state->return_esp, state->return_ss);
					eflags = *sp16;
					state->return_eflags = (eflags & V86_EFLAG_MASK) | EFLAG_IF | EFLAG_VM;
					v86_if = (eflags & EFLAG_IF) ? TRUE : FALSE;
					state->return_esp = ((state->return_esp & 0x0000ffff) + 2) & 0x0000ffff;
				}

				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;

			
			case OPCODE_INT:
			{
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				vector = V86GetAddress (state->return_eip, state->return_cs);
				V86GetInterruptVector (*vector, &new_ip, &new_cs);
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				
				state->return_esp = ((state->return_esp & 0x0000ffff) - 2) & 0x0000ffff;
				sp16 = V86GetAddress (state->return_esp, state->return_ss);
				*sp16 = (uint16) state->return_eip;
				
				state->return_esp = ((state->return_esp & 0x0000ffff) - 2) & 0x0000ffff;
				sp16 = V86GetAddress (state->return_esp, state->return_ss);
				*sp16 = (uint16) state->return_cs;
				
				state->return_esp = ((state->return_esp & 0x0000ffff) - 2) & 0x0000ffff;
				sp16 = V86GetAddress (state->return_esp, state->return_ss);
				
				eflags = (v86_if == TRUE)
						? (state->return_eflags & V86_EFLAG_MASK) | EFLAG_IF
						: (state->return_eflags & V86_EFLAG_MASK) & ~EFLAG_IF;
				
				*sp16 = (uint16) eflags;
				
				state->return_eflags = (state->return_eflags & ~(EFLAG_IF | EFLAG_TF | EFLAG_AC)) | EFLAG_VM;
				v86_if = FALSE;
				
				state->return_eip = new_ip & 0x0000ffff;
				state->return_cs = new_cs & 0x0000ffff;
				
				return 0;
			}
			
			case OPCODE_IRET:
				if (state->return_eip == 0x0002 && state->return_cs == 0x1000)
				{
					return 1;
				}
				else
				{
					sp16 = V86GetAddress (state->return_esp, state->return_ss);
					eflags = *sp16;
					
					eflags = (eflags & 0x257fd5) | (state->return_eflags & 0x1a0000);
					
					state->return_eflags = eflags | EFLAG_IF | EFLAG_VM;
					v86_if = (eflags & EFLAG_IF) ? TRUE : FALSE;
							
					state->return_esp = ((state->return_esp & 0x0000ffff) + 2) & 0x0000ffff;
					
					sp16 = V86GetAddress (state->return_esp, state->return_ss);
					state->return_cs = *sp16;
					state->return_esp = ((state->return_esp & 0x0000ffff) + 2) & 0x0000ffff;
					
					sp16 = V86GetAddress (state->return_esp, state->return_ss);
					state->return_eip = *sp16;
					state->return_esp = ((state->return_esp & 0x0000ffff) + 2) & 0x0000ffff;

					return 0;
				}
							
				
			case OPCODE_CLI:
				v86_if = FALSE;
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;
							
			case OPCODE_STI:
				v86_if = TRUE;
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;
					
		
			case OPCODE_OUTB:
				OutByte (state->edx, state->eax);
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;
			
			case OPCODE_INB:
				state->eax = InByte (state->edx);
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;
			
			case OPCODE_OUTWL:
				if(is_operand32 == FALSE)
					OutWord (state->edx, state->eax);
				else
					OutLong (state->edx, state->eax);
				
				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;
			
			case OPCODE_INWL:
				if(is_operand32 == FALSE)
					state->eax = InWord (state->edx);
				else
					state->eax = InLong (state->edx);

				state->return_eip = (state->return_eip + 1) & 0x0000ffff;
				return 0;

			case OPCODE_OUTB_AL_NN:
				OutByte (*(ip+1), state->eax);
				state->return_eip = (state->return_eip + 2) & 0x0000ffff;
				return 0;

			case OPCODE_INB_NN_AL:
				state->eax = InByte (*(ip+1));
				state->return_eip = (state->return_eip + 2) & 0x0000ffff;
				return 0;
			
			case OPCODE_OUTWL_EAX_NN:
				if (is_operand32 == FALSE)
					OutWord (*(ip+1), state->eax);
				else
					OutLong (*(ip+1), state->eax);

				state->return_eip = (state->return_eip + 2) & 0x0000ffff;
				return 0;
			
			case OPCODE_INWL_NN_EAX:
				if(is_operand32 == FALSE)
					state->eax = InWord (*(ip+1));
				else
					state->eax = InLong (*(ip+1));
				
				state->return_eip = (state->return_eip + 2) & 0x0000ffff;
				return 0;
			
			
			case OPCODE_HLT:
			{
				KPANIC ("Halt in V86");
			}
			
			default:
			{
				KPRINTF ("opcode = %#010x", *ip);
				KPANIC ("#GP Unknown V86 opcode");
			}
		}
	}
}
Exemple #2
0
/**
  This routine returns the current interrupt status and/or the transmitted buffer addresses.
  If the current interrupt status is returned, pending interrupts will be acknowledged by this
  command.  Transmitted buffer addresses that are written to the DB are removed from the transmit
  buffer queue.
  Normally, this command would be polled with interrupts disabled.
  The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].
  The interrupt status is returned in CdbPtr->StatFlags.

  @param  CdbPtr               Pointer to the command descriptor block.
  @param  AdapterInfo          Pointer to the NIC data structure information which
                               the UNDI driver is layering on..

  @return None

**/
VOID
UNDI_Status (
  IN  PXE_CDB           *CdbPtr,
  IN  NIC_DATA_INSTANCE *AdapterInfo
  )
{
  PXE_DB_GET_STATUS *DbPtr;
  PXE_DB_GET_STATUS TmpGetStatus;
  UINT16            Index;
  UINT16            Status;
  UINT16            NumEntries;
  RxFD              *RxPtr;

  //
  // Fill in temporary GetStatus storage.
  //
  RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];

  if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) {
    TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff;
  } else {
    TmpGetStatus.RxFrameLen = 0;
  }

  TmpGetStatus.reserved = 0;

  //
  // Fill in size of next available receive packet and
  // reserved field in caller's DB storage.
  //
  DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;

  if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) {
    CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize);
  } else {
    CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2);
  }

  //
  //
  //
  if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {
    //
    // DBsize of zero is invalid if Tx buffers are requested.
    //
    if (CdbPtr->DBsize == 0) {
      CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
      CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;
      return ;
    }

    //
    // remember this b4 we overwrite
    //
    NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64));

    //
    // We already filled in 2 UINT32s.
    //
    CdbPtr->DBsize = sizeof (UINT32) * 2;

    //
    // will claim any hanging free CBs
    //
    CheckCBList (AdapterInfo);

    if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) {
      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;
    } else {
      for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {
        if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {
          DbPtr->TxBuffer[Index]      = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head];
          AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head);
          CdbPtr->DBsize += sizeof (UINT64);
        } else {
          break;
        }
      }
    }

    if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {
      CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED;

    }
    //
    // check for a receive buffer and give it's size in db
    //
  }
  //
  //
  //
  if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {

    Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);
    AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | Status);

    //
    // acknoledge the interrupts
    //
    OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));

    //
    // report all the outstanding interrupts
    //
    Status = AdapterInfo->Int_Status;
    if ((Status & SCB_STATUS_FR) != 0) {
      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
    }

    if ((Status & SCB_STATUS_SWI) != 0) {
      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;
    }
  }

  //
  // Return current media status
  //
  if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_MEDIA_STATUS) != 0) {
    AdapterInfo->PhyAddress = 0xFF;
    AdapterInfo->CableDetect = 1;

    if (!PhyDetect (AdapterInfo)) {
      CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
    }
  }

  return ;
}