LONG TCP_IPIdentification = 0;
static BOOLEAN TCPInitialized = FALSE;
static NPAGED_LOOKASIDE_LIST TCPSegmentList;
- LIST_ENTRY SignalledConnectionsList;
- KSPIN_LOCK SignalledConnectionsLock;
- LIST_ENTRY SleepingThreadsList;
- FAST_MUTEX SleepingThreadsLock;
- RECURSIVE_MUTEX TCPLock;
PORT_SET TCPPorts;
+ CLIENT_DATA ClientInfo;
- static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
- NTSTATUS Status = STATUS_SUCCESS;
- PTCP_COMPLETION_ROUTINE Complete;
+ VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection)
+ {
- PTDI_BUCKET Bucket;
- PLIST_ENTRY Entry;
+ PTDI_BUCKET Bucket;
+ PLIST_ENTRY Entry;
+ NTSTATUS Status;
- PIRP Irp;
- PMDL Mdl;
+ PIRP Irp;
+ PMDL Mdl;
+ ULONG SocketError = 0;
+ KIRQL OldIrql;
+ PTCP_COMPLETION_ROUTINE Complete;
- ASSERT_LOCKED(&TCPLock);
+ if (ClientInfo.Unlocked)
+ LockObjectAtDpcLevel(Connection);
- TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n",
- Connection, Connection->SocketContext));
+ TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n",
+ Connection, Connection->SocketContext));
- if( Connection->SignalState & SEL_FIN ) {
- TI_DbgPrint(DEBUG_TCP, ("EOF From socket\n"));
+ if( Connection->SignalState & SEL_FIN ) {
+ TI_DbgPrint(DEBUG_TCP, ("EOF From socket\n"));
- while ((Entry = ExInterlockedRemoveHeadList( &Connection->ReceiveRequest,
- &Connection->Lock )) != NULL)
+ /* If OskitTCP initiated the disconnect, try to read the socket error that occurred */
+ if (Connection->SocketContext)
+ SocketError = TCPTranslateError(OskitTCPGetSocketError(Connection->SocketContext));
+
+ /* Default to STATUS_CANCELLED if we initiated the disconnect or no socket error was reported */
+ if (!Connection->SocketContext || !SocketError)
+ SocketError = STATUS_CANCELLED;
+
+ while (!IsListEmpty(&Connection->ReceiveRequest))
- {
+ {
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete = Bucket->Request.RequestNotifyObject;
+ Entry = RemoveHeadList( &Connection->ReceiveRequest );
- /* We have to notify oskittcp of the abortion */
- TCPDisconnect
- ( Connection,
- TDI_DISCONNECT_RELEASE | TDI_DISCONNECT_ABORT,
- NULL,
- NULL,
- Bucket->Request.RequestNotifyObject,
- (PIRP)Bucket->Request.RequestContext );
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
+ Bucket->Status = SocketError;
+ Bucket->Information = 0;
- exFreePool(Bucket);
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
+ }
- while ((Entry = ExInterlockedRemoveHeadList( &Connection->SendRequest,
- &Connection->Lock )) != NULL)
+ while (!IsListEmpty(&Connection->SendRequest))
- {
+ {
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete = Bucket->Request.RequestNotifyObject;
+ Entry = RemoveHeadList( &Connection->SendRequest );
- /* We have to notify oskittcp of the abortion */
- TCPDisconnect
- ( Connection,
- TDI_DISCONNECT_RELEASE,
- NULL,
- NULL,
- Bucket->Request.RequestNotifyObject,
- (PIRP)Bucket->Request.RequestContext );
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
++ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
+ Bucket->Status = SocketError;
+ Bucket->Information = 0;
- exFreePool(Bucket);
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
+ }
- while ((Entry = ExInterlockedRemoveHeadList( &Connection->ListenRequest,
- &Connection->Lock )) != NULL)
+ while (!IsListEmpty(&Connection->ListenRequest))
- {
+ {
+ Entry = RemoveHeadList( &Connection->ListenRequest );
+
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete = Bucket->Request.RequestNotifyObject;
- /* We have to notify oskittcp of the abortion */
- TCPAbortListenForSocket(Connection->AddressFile->Listener,
- Connection);
+ Bucket->Status = SocketError;
+ Bucket->Information = 0;
+ DereferenceObject(Bucket->AssociatedEndpoint);
- Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
+ }
- while ((Entry = ExInterlockedRemoveHeadList( &Connection->ConnectRequest,
- &Connection->Lock )) != NULL)
+ while (!IsListEmpty(&Connection->ConnectRequest))
- {
+ {
+ Entry = RemoveHeadList( &Connection->ConnectRequest );
+
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete = Bucket->Request.RequestNotifyObject;
- Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
+ Bucket->Status = SocketError;
+ Bucket->Information = 0;
+
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
+ }
- Connection->SignalState = 0;
+ Connection->SignalState = SEL_FIN;
}
- /* Things that can happen when we try the initial connection */
- if( Connection->SignalState & SEL_CONNECT ) {
+ /* Things that can happen when we try the initial connection */
+ if( Connection->SignalState & SEL_CONNECT ) {
- while( (Entry = ExInterlockedRemoveHeadList( &Connection->ConnectRequest,
- &Connection->Lock )) != NULL ) {
+ while (!IsListEmpty(&Connection->ConnectRequest)) {
+ Entry = RemoveHeadList( &Connection->ConnectRequest );
-
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+
- TI_DbgPrint(DEBUG_TCP, ("Connect Event\n"));
-
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Complete = Bucket->Request.RequestNotifyObject;
- TI_DbgPrint(DEBUG_TCP,
- ("Completing Request %x\n", Bucket->Request.RequestContext));
- Complete( Bucket->Request.RequestContext, STATUS_SUCCESS, 0 );
+ Bucket->Status = STATUS_SUCCESS;
+ Bucket->Information = 0;
- /* Frees the bucket allocated in TCPConnect */
- exFreePool( Bucket );
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
- }
+ }
+ }
- if( Connection->SignalState & SEL_ACCEPT ) {
- /* Handle readable on a listening socket --
- * TODO: Implement filtering
- */
- TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n",
- Connection,
- IsListEmpty(&Connection->ListenRequest) ?
- "empty" : "nonempty"));
+ if( Connection->SignalState & SEL_ACCEPT ) {
+ /* Handle readable on a listening socket --
+ * TODO: Implement filtering
+ */
-
+ TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n",
+ Connection,
+ IsListEmpty(&Connection->ListenRequest) ?
+ "empty" : "nonempty"));
- while( (Entry = ExInterlockedRemoveHeadList( &Connection->ListenRequest,
- &Connection->Lock )) != NULL ) {
+ while (!IsListEmpty(&Connection->ListenRequest)) {
- PIO_STACK_LOCATION IrpSp;
+ PIO_STACK_LOCATION IrpSp;
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ Entry = RemoveHeadList( &Connection->ListenRequest );
+
- Complete = Bucket->Request.RequestNotifyObject;
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Irp = Bucket->Request.RequestContext;
- IrpSp = IoGetCurrentIrpStackLocation( Irp );
+ Irp = Bucket->Request.RequestContext;
+ IrpSp = IoGetCurrentIrpStackLocation( Irp );
- TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
+ TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
+
- Status = TCPServiceListeningSocket
- ( Connection->AddressFile->Listener,
- Bucket->AssociatedEndpoint,
- (PTDI_REQUEST_KERNEL)&IrpSp->Parameters );
+ Status = TCPServiceListeningSocket
+ ( Connection->AddressFile->Listener,
+ Bucket->AssociatedEndpoint,
+ (PTDI_REQUEST_KERNEL)&IrpSp->Parameters );
- TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
+ TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
- if( Status == STATUS_PENDING ) {
+ if( Status == STATUS_PENDING ) {
- ExInterlockedInsertHeadList( &Connection->ListenRequest, &Bucket->Entry, &Connection->Lock );
+ InsertHeadList( &Connection->ListenRequest, &Bucket->Entry );
- break;
- } else {
+ break;
+ } else {
- Complete( Bucket->Request.RequestContext, Status, 0 );
- exFreePool( Bucket );
+ Bucket->Status = Status;
+ Bucket->Information = 0;
+ DereferenceObject(Bucket->AssociatedEndpoint);
+
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
- }
- }
+ }
+ }
+ }
- /* Things that happen after we're connected */
- if( Connection->SignalState & SEL_READ ) {
- TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n",
- IsListEmpty(&Connection->ReceiveRequest) ?
- "empty" : "nonempty"));
+ /* Things that happen after we're connected */
+ if( Connection->SignalState & SEL_READ ) {
+ TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n",
+ IsListEmpty(&Connection->ReceiveRequest) ?
+ "empty" : "nonempty"));
- while( (Entry = ExInterlockedRemoveHeadList( &Connection->ReceiveRequest,
- &Connection->Lock )) != NULL ) {
+ while (!IsListEmpty(&Connection->ReceiveRequest)) {
- OSK_UINT RecvLen = 0, Received = 0;
- PVOID RecvBuffer = 0;
+ OSK_UINT RecvLen = 0, Received = 0;
+ PVOID RecvBuffer = 0;
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ Entry = RemoveHeadList( &Connection->ReceiveRequest );
+
- Complete = Bucket->Request.RequestNotifyObject;
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Irp = Bucket->Request.RequestContext;
- Mdl = Irp->MdlAddress;
+ Irp = Bucket->Request.RequestContext;
+ Mdl = Irp->MdlAddress;
- TI_DbgPrint(DEBUG_TCP,
- ("Getting the user buffer from %x\n", Mdl));
+ TI_DbgPrint(DEBUG_TCP,
+ ("Getting the user buffer from %x\n", Mdl));
- NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
+ NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
- TI_DbgPrint(DEBUG_TCP,
- ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
+ TI_DbgPrint(DEBUG_TCP,
+ ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
- TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
- TI_DbgPrint
- (DEBUG_TCP,
- ("Connection->SocketContext: %x\n",
- Connection->SocketContext));
- TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
+ TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
+ TI_DbgPrint
+ (DEBUG_TCP,
+ ("Connection->SocketContext: %x\n",
+ Connection->SocketContext));
+ TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
- Status = TCPTranslateError
- ( OskitTCPRecv( Connection->SocketContext,
- RecvBuffer,
- RecvLen,
- &Received,
- 0 ) );
+ Status = TCPTranslateError
+ ( OskitTCPRecv( Connection->SocketContext,
+ RecvBuffer,
+ RecvLen,
+ &Received,
+ 0 ) );
- TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
+ TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
- if( Status == STATUS_SUCCESS ) {
- TI_DbgPrint(DEBUG_TCP,("Received %d bytes with status %x\n",
- Received, Status));
-
- Complete( Bucket->Request.RequestContext,
- STATUS_SUCCESS, Received );
- exFreePool( Bucket );
- } else if( Status == STATUS_PENDING ) {
- ExInterlockedInsertHeadList
- ( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
+ if( Status == STATUS_PENDING ) {
+ InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
- break;
- } else {
- TI_DbgPrint(DEBUG_TCP,
- ("Completing Receive request: %x %x\n",
- Bucket->Request, Status));
+ break;
+ } else {
+ TI_DbgPrint(DEBUG_TCP,
+ ("Completing Receive request: %x %x\n",
+ Bucket->Request, Status));
- Complete( Bucket->Request.RequestContext, Status, 0 );
- exFreePool( Bucket );
+
+ Bucket->Status = Status;
+ Bucket->Information = (Status == STATUS_SUCCESS) ? Received : 0;
+
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
- }
- }
- if( Connection->SignalState & SEL_WRITE ) {
- TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
- IsListEmpty(&Connection->SendRequest) ?
- "empty" : "nonempty"));
+ }
+ }
+ }
+ if( Connection->SignalState & SEL_WRITE ) {
+ TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
+ IsListEmpty(&Connection->SendRequest) ?
+ "empty" : "nonempty"));
- while( (Entry = ExInterlockedRemoveHeadList( &Connection->SendRequest,
- &Connection->Lock )) != NULL ) {
+ while (!IsListEmpty(&Connection->SendRequest)) {
- OSK_UINT SendLen = 0, Sent = 0;
- PVOID SendBuffer = 0;
+ OSK_UINT SendLen = 0, Sent = 0;
+ PVOID SendBuffer = 0;
- Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ Entry = RemoveHeadList( &Connection->SendRequest );
+
- Complete = Bucket->Request.RequestNotifyObject;
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
- Irp = Bucket->Request.RequestContext;
- Mdl = Irp->MdlAddress;
+ Irp = Bucket->Request.RequestContext;
+ Mdl = Irp->MdlAddress;
- TI_DbgPrint(DEBUG_TCP,
- ("Getting the user buffer from %x\n", Mdl));
+ TI_DbgPrint(DEBUG_TCP,
+ ("Getting the user buffer from %x\n", Mdl));
- NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
+ NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
- TI_DbgPrint(DEBUG_TCP,
- ("Writing %d bytes to %x\n", SendLen, SendBuffer));
+ TI_DbgPrint(DEBUG_TCP,
+ ("Writing %d bytes to %x\n", SendLen, SendBuffer));
- TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
- TI_DbgPrint
+ TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
+ TI_DbgPrint
(DEBUG_TCP,
("Connection->SocketContext: %x\n",
Connection->SocketContext));
- Status = TCPTranslateError
- ( OskitTCPSend( Connection->SocketContext,
- SendBuffer,
- SendLen,
- &Sent,
- 0 ) );
+ Status = TCPTranslateError
+ ( OskitTCPSend( Connection->SocketContext,
+ SendBuffer,
+ SendLen,
+ &Sent,
+ 0 ) );
- TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
+ TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
- if( Status == STATUS_SUCCESS ) {
- TI_DbgPrint(DEBUG_TCP,("Sent %d bytes with status %x\n",
- Sent, Status));
-
- Complete( Bucket->Request.RequestContext,
- STATUS_SUCCESS, Sent );
- exFreePool( Bucket );
- } else if( Status == STATUS_PENDING ) {
- ExInterlockedInsertHeadList
- ( &Connection->SendRequest, &Bucket->Entry, &Connection->Lock );
+ if( Status == STATUS_PENDING ) {
+ InsertHeadList( &Connection->SendRequest, &Bucket->Entry );
- break;
- } else {
- TI_DbgPrint(DEBUG_TCP,
- ("Completing Send request: %x %x\n",
- Bucket->Request, Status));
+ break;
+ } else {
+ TI_DbgPrint(DEBUG_TCP,
+ ("Completing Send request: %x %x\n",
+ Bucket->Request, Status));
- Complete( Bucket->Request.RequestContext, Status, 0 );
- exFreePool( Bucket );
+
+ Bucket->Status = Status;
+ Bucket->Information = (Status == STATUS_SUCCESS) ? Sent : 0;
+
+ InsertTailList(&Connection->CompletionQueue, &Bucket->Entry);
- }
- }
- }
+ }
+ }
+ }
- Connection->SignalState = 0;
- Connection->Signalled = FALSE;
+ ReferenceObject(Connection);
+ if (ClientInfo.Unlocked)
+ {
+ UnlockObjectFromDpcLevel(Connection);
+ KeReleaseSpinLock(&ClientInfo.Lock, ClientInfo.OldIrql);
- }
+}
+ else
+ {
+ UnlockObject(Connection, Connection->OldIrql);
+ }
+
+ while ((Entry = ExInterlockedRemoveHeadList(&Connection->CompletionQueue,
+ &Connection->Lock)))
+ {
+ Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
+ Complete = Bucket->Request.RequestNotifyObject;
- VOID DrainSignals() {
- PCONNECTION_ENDPOINT Connection;
- PLIST_ENTRY ListEntry;
+ Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
- while( (ListEntry = ExInterlockedRemoveHeadList(&SignalledConnectionsList,
- &SignalledConnectionsLock)) != NULL) {
- Connection = CONTAINING_RECORD( ListEntry, CONNECTION_ENDPOINT,
- SignalList );
- HandleSignalledConnection( Connection );
- }
- }
+ ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
+ }
+
+ if (!ClientInfo.Unlocked)
+ {
+ LockObject(Connection, &OldIrql);
+ }
+ else
+ {
+ KeAcquireSpinLock(&ClientInfo.Lock, &ClientInfo.OldIrql);
+ }
+ DereferenceObject(Connection);
+
+ /* If the socket is dead, remove the reference we added for oskit */
+ if (Connection->SignalState & SEL_FIN)
+ DereferenceObject(Connection);
+ }
+
+ VOID ConnectionFree(PVOID Object) {
+ PCONNECTION_ENDPOINT Connection = Object;
+ KIRQL OldIrql;
+
+ TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
+
+ TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
+ RemoveEntryList(&Connection->ListEntry);
+ TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
+
+ ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
+ }
PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
PCONNECTION_ENDPOINT Connection =
AddressToConnect.sin_family = AF_INET;
AddressToBind = AddressToConnect;
- AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
+
+ LockObject(Connection, &OldIrql);
+
+ if (!Connection->AddressFile)
+ {
+ UnlockObject(Connection, OldIrql);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (AddrIsUnspecified(&Connection->AddressFile->Address))
+ {
+ if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
+ {
+ UnlockObject(Connection, OldIrql);
+ return STATUS_NETWORK_UNREACHABLE;
+ }
+
+ AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
+ }
+ else
+ {
+ AddressToBind.sin_addr.s_addr = Connection->AddressFile->Address.Address.IPv4Address;
+ }
Status = TCPTranslateError
( OskitTCPBind( Connection->SocketContext,
Bucket->Request.RequestNotifyObject = (PVOID)Complete;
Bucket->Request.RequestContext = Context;
-
+
- IoMarkIrpPending((PIRP)Context);
-
- ExInterlockedInsertTailList( &Connection->ConnectRequest, &Bucket->Entry, &Connection->Lock );
+ InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
}
}
Bucket->Request.RequestNotifyObject = Complete;
Bucket->Request.RequestContext = Context;
*BytesSent = 0;
-
+
- IoMarkIrpPending((PIRP)Context);
-
- ExInterlockedInsertTailList( &Connection->SendRequest, &Bucket->Entry, &Connection->Lock );
+ InsertTailList( &Connection->SendRequest, &Bucket->Entry );
TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
} else {
TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
*BytesSent = Sent;
}
-
+
+ UnlockObject(Connection, OldIrql);
+
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
return Status;
#define Running 2
#define WrDispatchInt 0x1F
- Dividend: .float 4195835.0
- Divisor: .float 3145727.0
- Result1: .float 0
- Result2: .float 0
-
/* FUNCTIONS ****************************************************************/
- .globl _KiIsNpxErrataPresent@0
- .func KiIsNpxErrataPresent@0
- _KiIsNpxErrataPresent@0:
-
- /* Disable interrupts */
- cli
-
- /* Get CR0 and mask out FPU flags */
- mov eax, cr0
- mov ecx, eax
- and eax, ~(CR0_MP + CR0_TS + CR0_EM)
- mov cr0, eax
-
- /* Initialize the FPU */
- fninit
-
- /* Do the divison and inverse multiplication */
- fld qword ptr Dividend
- fstp qword ptr Result1
- fld qword ptr Divisor
- fstp qword ptr Result2
- fld qword ptr Result1
- fdiv qword ptr Result2
- fmul qword ptr Result2
-
- /* Do the compare and check flags */
- fcomp qword ptr Result1
- fstsw ax
- sahf
-
- /* Restore CR0 and interrupts */
- mov cr0, ecx
- sti
-
- /* Return errata status */
- xor eax, eax
- jz NoErrata
- inc eax
-
- NoErrata:
- ret
- .endfunc
-
- .globl _KiIsNpxPresent@0
- .func KiIsNpxPresent@0
- _KiIsNpxPresent@0:
-
- /* Save stack */
- push ebp
-
- /* Get CR0 and mask out FPU flags */
- mov eax, cr0
- and eax, ~(CR0_MP + CR0_TS + CR0_EM + CR0_ET)
-
- /* Initialize the FPU and assume FALSE for return */
- xor edx, edx
- fninit
-
- /* Save magic value on stack */
- mov ecx, 0x42424242
- push ecx
-
- /* Setup stack for FPU store */
- mov ebp ,esp
- fnstsw [ebp]
-
- /* Now check if our magic got cleared */
- cmp byte ptr [ebp], 0
- jnz NoFpu
-
- /* Enable FPU, set return to TRUE */
- or eax, CR0_ET
- mov edx, 1
-
- /* If this is a 486 or higher, enable INT 16 as well */
- cmp dword ptr fs:KPCR_PRCB_CPU_TYPE, 3
- jbe NoFpu
- or eax, CR0_NE
-
- NoFpu:
- /* Set emulation enabled during the first boot phase and set the CR0 */
- or eax, (CR0_EM + CR0_TS)
- mov cr0, eax
-
- /* Restore stack */
- pop eax
- pop ebp
-
- /* Return true or false */
- mov eax, edx
- ret
- .endfunc
-
- .globl _KiFlushNPXState@4
- .func KiFlushNPXState@4
- _KiFlushNPXState@4:
-
- /* Save volatiles and disable interrupts */
- push esi
- push edi
- push ebx
- pushfd
- cli
-
- /* Save the PCR and get the current thread */
- mov edi, fs:[KPCR_SELF]
- mov esi, [edi+KPCR_CURRENT_THREAD]
-
- /* Check if we're already loaded */
- cmp byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_LOADED
- je IsValid
-
- /* Check if we're supposed to get it */
- cmp dword ptr [esp+20], 0
- je Return
-
- #if DBG
- /* Assert Fxsr support */
- test byte ptr _KeI386FxsrPresent, 1
- jnz AssertOk
- int 3
- AssertOk:
- #endif
-
- /* Get CR0 and test if it's valid */
- mov ebx, cr0
- test bl, CR0_MP + CR0_TS + CR0_EM
- jz Cr0OK
-
- /* Enable fnsave to work */
- and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
- mov cr0, ebx
-
- Cr0OK:
- /* Check if we are the NPX Thread */
- mov eax, [edi+KPCR_NPX_THREAD]
- or eax, eax
- jz DontSave
-
- /* Check if it's not loaded */
- cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
- jnz DontSave
-
- #if DBG
- /* We are the NPX Thread with an unloaded NPX State... this isn't normal! */
- int 3
- #endif
-
- /* Save the NPX State */
- mov ecx, [eax+KTHREAD_INITIAL_STACK]
- sub ecx, NPX_FRAME_LENGTH
- fxsave [ecx]
- mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
-
- DontSave:
- /* Load the NPX State */
- mov ecx, [esi+KTHREAD_INITIAL_STACK]
- sub ecx, NPX_FRAME_LENGTH
- fxrstor [ecx]
-
- /* Get the CR0 state and destination */
- mov edx, [ecx+FN_CR0_NPX_STATE]
- mov ecx, [esp+20]
- jmp DoneLoad
-
- IsValid:
- /* We already have a valid state, flush it */
- mov ebx, cr0
- test bl, CR0_MP + CR0_TS + CR0_EM
- jz Cr0OK2
-
- /* Enable fnsave to work */
- and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
- mov cr0, ebx
-
- Cr0OK2:
- /* Get the kernel stack */
- mov ecx, [esi+KTHREAD_INITIAL_STACK]
- test byte ptr _KeI386FxsrPresent, 1
- lea ecx, [ecx-NPX_FRAME_LENGTH]
-
- /* Set the NPX State */
- mov byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
-
- /* Get Cr0 */
- mov edx, [ecx+FN_CR0_NPX_STATE]
- jz DoneLoad
-
- /* Save the FX State */
- fxsave [ecx]
-
- /* Check if we also have to save it in the parameter */
- mov ecx, [esp+20]
- jecxz NoSave
-
- DoneLoad:
- /* Save the Fn state in the parameter we got */
- fnsave [ecx]
- fwait
-
- NoSave:
- /* Clear eax */
- xor eax, eax
-
- /* Add NPX State */
- or ebx, NPX_STATE_NOT_LOADED
-
- /* Clear the NPX thread */
- mov [edi+KPCR_NPX_THREAD], eax
-
- /* Add saved CR0 into NPX State, and set it */
- or ebx, edx
- mov cr0, ebx
-
- /* Re-enable interrupts and return */
- Return:
- popf
- pop ebx
- pop edi
- pop esi
- ret 4
-
- .endfunc
-
- /*++
- * KiThreadStartup
- *
- * The KiThreadStartup routine is the beginning of any thread.
- *
- * Params:
- * SystemRoutine - Pointer to the System Startup Routine. Either
- * PspUserThreadStartup or PspSystemThreadStartup
- *
- * StartRoutine - For Kernel Threads only, specifies the starting execution
- * point of the new thread.
- *
- * StartContext - For Kernel Threads only, specifies a pointer to variable
- * context data to be sent to the StartRoutine above.
- *
- * UserThread - Indicates whether or not this is a user thread. This tells
- * us if the thread has a context or not.
- *
- * TrapFrame - Pointer to the KTHREAD to which the caller wishes to
- * switch from.
- *
- * Returns:
- * Should never return for a system thread. Returns through the System Call
- * Exit Dispatcher for a user thread.
- *
- * Remarks:
- * If a return from a system thread is detected, a bug check will occur.
- *
- *--*/
- .func KiThreadStartup@156
- .globl _KiThreadStartup@156
- _KiThreadStartup@156:
-
- /*
- * Clear all the non-volatile registers, so the thread won't be tempted to
- * expect any static data (like some badly coded usermode/win9x apps do)
- */
- xor ebx, ebx
- xor esi, esi
- xor edi, edi
- xor ebp, ebp
-
- /* It's now safe to go to APC */
- mov ecx, APC_LEVEL
- call @KfLowerIrql@4
-
- /*
- * Call the System Routine which is right on our stack now.
- * After we pop the pointer, the Start Routine/Context will be on the
- * stack, as parameters to the System Routine
- */
- pop eax
- call eax
-
- /* The thread returned... was it a user-thread? */
- pop ecx
- or ecx, ecx
- jz BadThread
-
- /* Yes it was, set our trapframe for the System Call Exit Dispatcher */
- mov ebp, esp
-
- /* Exit back to user-mode */
- jmp _KiServiceExit2
-
- BadThread:
-
- /* A system thread returned...this is very bad! */
- int 3
- .endfunc
-
/*++
- * KiSwapContextInternal
+ * KiSwapContextInternal
*
+ * \brief
* The KiSwapContextInternal routine switches context to another thread.
*
+ * BOOLEAN USERCALL KiSwapContextInternal();
+ *
* Params:
* ESI - Pointer to the KTHREAD to which the caller wishes to
* switch to.