ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

v86vdm.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            ntoskrnl/ke/i386/v86vdm.c
00005  * PURPOSE:         V8086 and VDM Trap Emulation
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  *                  Alex Ionescu (alex.ionescu@reactos.org)
00008  */
00009 
00010 /* INCLUDES *******************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 #define KiVdmGetInstructionSize(x) ((x) & 0xFF)
00017 #define KiVdmGetPrefixFlags(x)     ((x) & 0xFFFFFF00)
00018 
00019 /* GLOBALS ********************************************************************/
00020 
00021 ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE;
00022 ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
00023 PVOID Ki386IopmSaveArea;
00024 BOOLEAN KeI386VirtualIntExtensions = FALSE;
00025 const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT;
00026 
00027 /* UNHANDLED OPCODES **********************************************************/
00028 
00029 KiVdmUnhandledOpcode(F);
00030 KiVdmUnhandledOpcode(OUTSW);
00031 KiVdmUnhandledOpcode(OUTSB);
00032 KiVdmUnhandledOpcode(INSB);
00033 KiVdmUnhandledOpcode(INSW);
00034 KiVdmUnhandledOpcode(NPX);
00035 KiVdmUnhandledOpcode(INBimm);
00036 KiVdmUnhandledOpcode(INWimm);
00037 KiVdmUnhandledOpcode(OUTBimm);
00038 KiVdmUnhandledOpcode(OUTWimm);
00039 KiVdmUnhandledOpcode(INB);
00040 KiVdmUnhandledOpcode(INW);
00041 KiVdmUnhandledOpcode(OUTB);
00042 KiVdmUnhandledOpcode(OUTW);
00043 KiVdmUnhandledOpcode(HLT);
00044 KiVdmUnhandledOpcode(INTO);
00045 KiVdmUnhandledOpcode(INV);
00046 
00047 /* OPCODE HANDLERS ************************************************************/
00048     
00049 BOOLEAN
00050 FASTCALL
00051 KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame,
00052                  IN ULONG Flags)
00053 {
00054     ULONG Esp, V86EFlags, TrapEFlags;
00055     
00056     /* Check for VME support */
00057     ASSERT(KeI386VirtualIntExtensions == FALSE);
00058 
00059     /* Get current V8086 flags and mask out interrupt flag */
00060     V86EFlags = *KiNtVdmState;
00061     V86EFlags &= ~EFLAGS_INTERRUPT_MASK;
00062 
00063     /* Get trap frame EFLags and leave only align, nested task and interrupt */
00064     TrapEFlags = TrapFrame->EFlags;
00065     V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
00066 
00067     /* Add in those flags if they exist, and add in the IOPL flag */
00068     V86EFlags |= TrapEFlags;
00069     V86EFlags |= EFLAGS_IOPL;
00070     
00071     /* Build flat ESP */
00072     Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
00073     
00074     /* Check for OPER32 */
00075     if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32)
00076     {
00077         /* Save EFlags */
00078         Esp -= 4;
00079         *(PULONG)Esp = V86EFlags;
00080     }
00081     else
00082     {
00083         /* Save EFLags */
00084         Esp -= 2;
00085         *(PUSHORT)Esp = (USHORT)V86EFlags;
00086     }
00087     
00088     /* Set new ESP and EIP */
00089     TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4);
00090     TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
00091     
00092     /* We're done */
00093     return TRUE;
00094 }
00095 
00096 BOOLEAN
00097 FASTCALL
00098 KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame,
00099                 IN ULONG Flags)
00100 {
00101     ULONG Esp, V86EFlags, EFlags, TrapEFlags;
00102     
00103     /* Build flat ESP */
00104     Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
00105     
00106     /* Check for OPER32 */
00107     if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32)
00108     {
00109         /* Read EFlags */
00110         EFlags = *(PULONG)Esp;
00111         Esp += 4;
00112     }
00113     else
00114     {
00115         /* Read EFlags */
00116         EFlags = *(PUSHORT)Esp;
00117         Esp += 2;
00118     }
00119     
00120     /* Set new ESP */
00121     TrapFrame->HardwareEsp = Esp - (TrapFrame->HardwareSegSs << 4);
00122     
00123     /* Mask out IOPL from the flags */
00124     EFlags &= ~EFLAGS_IOPL;
00125     
00126     /* Save the V86 flags, but mask out the nested task flag */
00127     V86EFlags = EFlags & ~EFLAGS_NESTED_TASK;
00128     
00129     /* Now leave only alignment, nested task and interrupt flag */
00130     EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
00131     
00132     /* Get trap EFlags */
00133     TrapEFlags = TrapFrame->EFlags;
00134                 
00135     /* Check for VME support */
00136     ASSERT(KeI386VirtualIntExtensions == FALSE);
00137 
00138     /* Add V86 and Interrupt flag */
00139     V86EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
00140 
00141     /* Update EFlags in trap frame */
00142     TrapFrame->EFlags = V86EFlags;
00143 
00144     /* Check if ESP0 needs to be fixed up */
00145     if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame);
00146     
00147     /* Update the V8086 EFlags state */
00148     KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
00149     KiVdmSetVdmEFlags(EFlags);
00150    
00151     /* FIXME: Check for VDM interrupts */
00152     
00153     /* Update EIP */
00154     TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
00155     
00156     /* We're done */
00157     return TRUE;
00158 }
00159 
00160 BOOLEAN
00161 FASTCALL
00162 KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame,
00163                  IN ULONG Flags)
00164 {
00165     ULONG Esp, V86EFlags, TrapEFlags, Eip, Interrupt;
00166     
00167     /* Read trap frame EFlags */
00168     TrapEFlags = TrapFrame->EFlags;
00169     
00170     /* Remove interrupt flag from V8086 EFlags */
00171     V86EFlags = *KiNtVdmState;
00172     KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
00173     
00174     /* Keep only alignment and interrupt flag from the V8086 state */
00175     V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK);
00176     
00177     /* Check for VME support */
00178     ASSERT(KeI386VirtualIntExtensions == FALSE);
00179     
00180     /* Mask in the relevant V86 EFlags into the trap flags */
00181     V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK);
00182     
00183     /* And mask out the VIF, nested task and TF flag from the trap flags */
00184     TrapFrame->EFlags = TrapEFlags &~ (EFLAGS_VIF | EFLAGS_NESTED_TASK | EFLAGS_TF);
00185     
00186     /* Add the IOPL flag to the local trap flags */
00187     V86EFlags |= EFLAGS_IOPL;
00188     
00189     /* Build flat ESP */
00190     Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
00191     
00192     /* Push EFlags */
00193     Esp -= 2;
00194     *(PUSHORT)(Esp) = (USHORT)V86EFlags;
00195     
00196     /* Push CS */
00197     Esp -= 2;
00198     *(PUSHORT)(Esp) = (USHORT)TrapFrame->SegCs;
00199     
00200     /* Push IP */
00201     Esp -= 2;
00202     *(PUSHORT)(Esp) = (USHORT)TrapFrame->Eip + KiVdmGetInstructionSize(Flags) + 1;
00203     
00204     /* Update ESP */
00205     TrapFrame->HardwareEsp = (USHORT)Esp;
00206     
00207     /* Get flat EIP */
00208     Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
00209     
00210     /* Now get the *next* EIP address (current is original + the count - 1) */
00211     Eip += KiVdmGetInstructionSize(Flags);
00212     
00213     /* Now read the interrupt number */
00214     Interrupt = *(PUCHAR)Eip;
00215         
00216     /* Read the EIP from its IVT entry */
00217     Interrupt = *(PULONG)(Interrupt * 4);
00218     TrapFrame->Eip = (USHORT)Interrupt;
00219     
00220     /* Now get the CS segment */
00221     Interrupt = (USHORT)(Interrupt >> 16);
00222     
00223     /* Check if the trap was not V8086 trap */
00224     if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
00225     {
00226         /* Was it a kernel CS? */
00227         Interrupt |= RPL_MASK;
00228         if (TrapFrame->SegCs == KGDT_R0_CODE)
00229         {
00230             /* Add the RPL mask */
00231             TrapFrame->SegCs = Interrupt;
00232         }
00233         else
00234         {
00235             /* Set user CS */
00236             TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
00237         }
00238     }
00239     else
00240     {
00241         /* Set IVT CS */
00242         TrapFrame->SegCs = Interrupt;
00243     }
00244     
00245     /* We're done */
00246     return TRUE;
00247 }
00248 
00249 BOOLEAN
00250 FASTCALL
00251 KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame,
00252                 IN ULONG Flags)
00253 {
00254     ULONG Esp, V86EFlags, EFlags, TrapEFlags, Eip;
00255 
00256     /* Build flat ESP */
00257     Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
00258     
00259     /* Check for OPER32 */
00260     if (KiVdmGetPrefixFlags(Flags) & PFX_FLAG_OPER32)
00261     {
00262         /* Build segmented EIP */
00263         TrapFrame->Eip = *(PULONG)Esp;
00264         TrapFrame->SegCs = *(PUSHORT)(Esp + 4);
00265         
00266         /* Set new ESP */
00267         TrapFrame->HardwareEsp += 12;
00268         
00269         /* Get EFLAGS */
00270         EFlags = *(PULONG)(Esp + 8);
00271     }
00272     else
00273     {
00274         /* Build segmented EIP */
00275         TrapFrame->Eip = *(PUSHORT)Esp;
00276         TrapFrame->SegCs = *(PUSHORT)(Esp + 2);
00277 
00278         /* Set new ESP */
00279         TrapFrame->HardwareEsp += 6;
00280 
00281         /* Get EFLAGS */
00282         EFlags = *(PUSHORT)(Esp + 4);
00283     }
00284     
00285     /* Mask out EFlags */
00286     EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP);
00287     V86EFlags = EFlags;
00288     
00289     /* Check for VME support */
00290     ASSERT(KeI386VirtualIntExtensions == FALSE);
00291     
00292     /* Add V86 and Interrupt flag */
00293     EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
00294     
00295     /* Update EFlags in trap frame */
00296     TrapEFlags = TrapFrame->EFlags;
00297     TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | EFlags;
00298     
00299     /* Check if ESP0 needs to be fixed up */
00300     if (!(TrapEFlags & EFLAGS_V86_MASK)) Ki386AdjustEsp0(TrapFrame);
00301     
00302     /* Update the V8086 EFlags state */
00303     KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
00304     KiVdmSetVdmEFlags(V86EFlags);
00305     
00306     /* Build flat EIP and check if this is the BOP instruction */
00307     Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
00308     if (*(PUSHORT)Eip == 0xC4C4)
00309     {
00310         /* Dispatch the BOP */
00311         VdmDispatchBop(TrapFrame);
00312     }
00313     else
00314     {
00315         /* FIXME: Check for VDM interrupts */
00316        DPRINT("FIXME: Check for VDM interrupts\n");
00317     }
00318     
00319     /* We're done */
00320     return TRUE;
00321 }
00322 
00323 BOOLEAN
00324 FASTCALL
00325 KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame,
00326                IN ULONG Flags)
00327 {       
00328     /* Check for VME support */
00329     ASSERT(KeI386VirtualIntExtensions == FALSE);
00330 
00331     /* Disable interrupts */
00332     KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
00333     
00334     /* Skip instruction */
00335     TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
00336     
00337     /* Done */
00338     return TRUE;
00339 }
00340 
00341 BOOLEAN
00342 FASTCALL
00343 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame,
00344                IN ULONG Flags)
00345 {
00346     /* Check for VME support */
00347     ASSERT(KeI386VirtualIntExtensions == FALSE);
00348 
00349     /* Enable interrupts */
00350     KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK);
00351     
00352     /* Skip instruction */
00353     TrapFrame->Eip += KiVdmGetInstructionSize(Flags);
00354     
00355     /* Done */
00356     return TRUE;
00357 }
00358 
00359 /* MASTER OPCODE HANDLER ******************************************************/
00360 
00361 BOOLEAN
00362 FASTCALL
00363 KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame,
00364                   IN ULONG Flags)
00365 {
00366     ULONG Eip;
00367     
00368     /* Get flat EIP of the *current* instruction (not the original EIP) */
00369     Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
00370     Eip += KiVdmGetInstructionSize(Flags) - 1;
00371     
00372     /* Read the opcode entry */
00373     switch (*(PUCHAR)Eip)
00374     {
00375         case 0xF:               return KiCallVdmHandler(F);
00376         case 0x26:              return KiCallVdmPrefixHandler(PFX_FLAG_ES);
00377         case 0x2E:              return KiCallVdmPrefixHandler(PFX_FLAG_CS);
00378         case 0x36:              return KiCallVdmPrefixHandler(PFX_FLAG_SS);
00379         case 0x3E:              return KiCallVdmPrefixHandler(PFX_FLAG_DS);
00380         case 0x64:              return KiCallVdmPrefixHandler(PFX_FLAG_FS);
00381         case 0x65:              return KiCallVdmPrefixHandler(PFX_FLAG_GS);
00382         case 0x66:              return KiCallVdmPrefixHandler(PFX_FLAG_OPER32);
00383         case 0x67:              return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32);
00384         case 0xF0:              return KiCallVdmPrefixHandler(PFX_FLAG_LOCK);
00385         case 0xF2:              return KiCallVdmPrefixHandler(PFX_FLAG_REPNE);
00386         case 0xF3:              return KiCallVdmPrefixHandler(PFX_FLAG_REP);
00387         case 0x6C:              return KiCallVdmHandler(INSB);
00388         case 0x6D:              return KiCallVdmHandler(INSW);
00389         case 0x6E:              return KiCallVdmHandler(OUTSB);
00390         case 0x6F:              return KiCallVdmHandler(OUTSW);
00391         case 0x98:              return KiCallVdmHandler(NPX);
00392         case 0xD8:              return KiCallVdmHandler(NPX);
00393         case 0xD9:              return KiCallVdmHandler(NPX);
00394         case 0xDA:              return KiCallVdmHandler(NPX);
00395         case 0xDB:              return KiCallVdmHandler(NPX);
00396         case 0xDC:              return KiCallVdmHandler(NPX);
00397         case 0xDD:              return KiCallVdmHandler(NPX);
00398         case 0xDE:              return KiCallVdmHandler(NPX);
00399         case 0xDF:              return KiCallVdmHandler(NPX);
00400         case 0x9C:              return KiCallVdmHandler(PUSHF);
00401         case 0x9D:              return KiCallVdmHandler(POPF);
00402         case 0xCD:              return KiCallVdmHandler(INTnn);
00403         case 0xCE:              return KiCallVdmHandler(INTO);
00404         case 0xCF:              return KiCallVdmHandler(IRET);   
00405         case 0xE4:              return KiCallVdmHandler(INBimm);   
00406         case 0xE5:              return KiCallVdmHandler(INWimm);
00407         case 0xE6:              return KiCallVdmHandler(OUTBimm);
00408         case 0xE7:              return KiCallVdmHandler(OUTWimm);        
00409         case 0xEC:              return KiCallVdmHandler(INB);
00410         case 0xED:              return KiCallVdmHandler(INW);
00411         case 0xEE:              return KiCallVdmHandler(OUTB);
00412         case 0xEF:              return KiCallVdmHandler(OUTW);
00413         case 0xF4:              return KiCallVdmHandler(HLT);
00414         case 0xFA:              return KiCallVdmHandler(CLI);
00415         case 0xFB:              return KiCallVdmHandler(STI);
00416         default:                return KiCallVdmHandler(INV);
00417     }    
00418 }
00419 
00420 /* PREFIX HANDLER *************************************************************/
00421 
00422 BOOLEAN
00423 FASTCALL
00424 KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame,
00425                   IN ULONG Flags)
00426 {
00427     /* Increase instruction size */
00428     Flags++;
00429     
00430     /* Handle the next opcode */
00431     return KiVdmHandleOpcode(TrapFrame, Flags);
00432 }
00433 
00434 /* TRAP HANDLER ***************************************************************/
00435 
00436 BOOLEAN
00437 FASTCALL
00438 Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame)
00439 {
00440     /* Clean up */
00441     TrapFrame->Eip &= 0xFFFF;
00442     TrapFrame->HardwareEsp &= 0xFFFF;
00443 
00444     /* We start with only 1 byte per instruction */
00445     return KiVdmHandleOpcode(TrapFrame, 1);
00446 }
00447 
00448 ULONG_PTR
00449 FASTCALL
00450 KiExitV86Mode(IN PKTRAP_FRAME TrapFrame)
00451 {
00452     PKV8086_STACK_FRAME StackFrame;
00453     PKGDTENTRY GdtEntry;
00454     PKTHREAD Thread;
00455     PKTRAP_FRAME PmTrapFrame;
00456     PKV86_FRAME V86Frame;
00457     PFX_SAVE_AREA NpxFrame;
00458     
00459     /* Get the stack frame back */
00460     StackFrame = CONTAINING_RECORD(TrapFrame->Esi, KV8086_STACK_FRAME, V86Frame);
00461     PmTrapFrame = &StackFrame->TrapFrame;
00462     V86Frame = &StackFrame->V86Frame;
00463     NpxFrame = &StackFrame->NpxArea;
00464     
00465     /* Copy the FPU frame back */
00466     Thread = KeGetCurrentThread();
00467     RtlCopyMemory(KiGetThreadNpxArea(Thread), NpxFrame, sizeof(FX_SAVE_AREA));
00468 
00469     /* Set initial stack back */
00470     Thread->InitialStack = (PVOID)((ULONG_PTR)V86Frame->ThreadStack + sizeof(FX_SAVE_AREA));
00471     
00472     /* Set ESP0 back in the KTSS */
00473     KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&PmTrapFrame->V86Es;
00474 
00475     /* Restore TEB addresses */
00476     Thread->Teb = V86Frame->ThreadTeb;
00477     KeGetPcr()->NtTib.Self = V86Frame->PcrTeb;
00478     
00479     /* Setup real TEB descriptor */
00480     GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
00481     GdtEntry->BaseLow = (USHORT)((ULONG_PTR)Thread->Teb & 0xFFFF);
00482     GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Thread->Teb >> 16);
00483     GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Thread->Teb >> 24);
00484 
00485     /* Enable interrupts and return a pointer to the trap frame */
00486     _enable();
00487     return (ULONG)PmTrapFrame;
00488 }
00489 
00490 VOID
00491 FASTCALL
00492 KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame)
00493 {
00494     PKTHREAD Thread;
00495     PKGDTENTRY GdtEntry;
00496     PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame;
00497     PKV86_FRAME V86Frame = &StackFrame->V86Frame;
00498     PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea;
00499 
00500     /* Build fake user-mode trap frame */
00501     TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK;
00502     TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0;
00503     TrapFrame->ErrCode = 0;
00504     
00505     /* Get the current thread's initial stack */
00506     Thread = KeGetCurrentThread();
00507     V86Frame->ThreadStack = KiGetThreadNpxArea(Thread);
00508     
00509     /* Save TEB addresses */
00510     V86Frame->ThreadTeb = Thread->Teb;
00511     V86Frame->PcrTeb = KeGetPcr()->NtTib.Self;
00512     
00513     /* Save return EIP */
00514     TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress;
00515     
00516     /* Save our stack (after the frames) */
00517     TrapFrame->Esi = (ULONG_PTR)V86Frame;
00518     TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4;
00519     
00520     /* Sanitize EFlags and enable interrupts */
00521     TrapFrame->EFlags = __readeflags() & 0x60DD7;
00522     TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
00523     
00524     /* Fill out the rest of the frame */
00525     TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
00526     TrapFrame->HardwareEsp = 0x11FFE;
00527     TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
00528     TrapFrame->Dr7 = 0;
00529 
00530     /* Set some debug fields if trap debugging is enabled */
00531     KiFillTrapFrameDebug(TrapFrame);
00532     
00533     /* Disable interrupts */
00534     _disable();
00535     
00536     /* Copy the thread's NPX frame */
00537     RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA));
00538     
00539     /* Clear exception list */
00540     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
00541     
00542     /* Set new ESP0 */
00543     KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es;
00544                              
00545     /* Set new initial stack */
00546     Thread->InitialStack = V86Frame;
00547         
00548     /* Set VDM TEB */
00549     Thread->Teb = (PTEB)TRAMPOLINE_TEB;
00550     KeGetPcr()->NtTib.Self = (PVOID)TRAMPOLINE_TEB;
00551     
00552     /* Setup VDM TEB descriptor */
00553     GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
00554     GdtEntry->BaseLow = (USHORT)((ULONG_PTR)TRAMPOLINE_TEB & 0xFFFF);
00555     GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 16);
00556     GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 24);
00557     
00558     /* Enable interrupts */
00559     _enable();
00560  
00561     /* Start VDM execution */
00562     NtVdmControl(VdmStartExecution, NULL);
00563     
00564     /* Exit to V86 mode */
00565     KiEoiHelper(TrapFrame);
00566 }
00567 
00568 VOID
00569 NTAPI
00570 Ke386SetIOPL(VOID)
00571 {
00572 
00573     PKTHREAD Thread = KeGetCurrentThread();
00574     PKPROCESS Process = Thread->ApcState.Process;
00575     PKTRAP_FRAME TrapFrame;
00576     CONTEXT Context;
00577 
00578     /* IOPL was enabled for this process/thread */
00579     Process->Iopl = TRUE;
00580     Thread->Iopl = TRUE;
00581 
00582     /* Get the trap frame on exit */
00583     TrapFrame = KeGetTrapFrame(Thread);
00584 
00585     /* Convert to a context */
00586     Context.ContextFlags = CONTEXT_CONTROL;
00587     KeTrapFrameToContext(TrapFrame, NULL, &Context);
00588     
00589     /* Set the IOPL flag */
00590     Context.EFlags |= EFLAGS_IOPL;
00591     
00592     /* Convert back to a trap frame */
00593     KeContextToTrapFrame(&Context, NULL, TrapFrame, CONTEXT_CONTROL, UserMode);
00594 }
00595  
00596 /* PUBLIC FUNCTIONS ***********************************************************/
00597 
00598 /*
00599  * @implemented
00600  */
00601 NTSTATUS
00602 NTAPI
00603 Ke386CallBios(IN ULONG Int,
00604               OUT PCONTEXT Context)
00605 {
00606     PUCHAR Trampoline = (PUCHAR)TRAMPOLINE_BASE;
00607     PTEB VdmTeb = (PTEB)TRAMPOLINE_TEB;
00608     PVDM_TIB VdmTib = (PVDM_TIB)TRAMPOLINE_TIB;
00609     ULONG ContextSize = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
00610     PKTHREAD Thread = KeGetCurrentThread();
00611     PKTSS Tss = KeGetPcr()->TSS;
00612     PKPROCESS Process = Thread->ApcState.Process;
00613     PVDM_PROCESS_OBJECTS VdmProcessObjects;
00614     USHORT OldOffset, OldBase;
00615 
00616     /* Start with a clean TEB */
00617     RtlZeroMemory(VdmTeb, sizeof(TEB));
00618 
00619     /* Write the interrupt and bop */
00620     *Trampoline++ = 0xCD;
00621     *Trampoline++ = (UCHAR)Int;
00622     *(PULONG)Trampoline = TRAMPOLINE_BOP;
00623 
00624     /* Setup the VDM TEB and TIB */
00625     VdmTeb->Vdm = (PVOID)TRAMPOLINE_TIB;
00626     RtlZeroMemory(VdmTib, sizeof(VDM_TIB));
00627     VdmTib->Size = sizeof(VDM_TIB);
00628 
00629     /* Set a blank VDM state */
00630     *VdmState = 0;
00631 
00632     /* Copy the context */
00633     RtlCopyMemory(&VdmTib->VdmContext, Context, ContextSize);
00634     VdmTib->VdmContext.SegCs = (ULONG_PTR)Trampoline >> 4;
00635     VdmTib->VdmContext.SegSs = (ULONG_PTR)Trampoline >> 4;
00636     VdmTib->VdmContext.Eip = 0;
00637     VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG_PTR);
00638     VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
00639     VdmTib->VdmContext.ContextFlags = CONTEXT_FULL;
00640 
00641     /* This can't be a real VDM process */
00642     ASSERT(PsGetCurrentProcess()->VdmObjects == NULL);
00643 
00644     /* Allocate VDM structure */
00645     VdmProcessObjects = ExAllocatePoolWithTag(NonPagedPool,
00646                                               sizeof(VDM_PROCESS_OBJECTS),
00647                                               '  eK');
00648     if (!VdmProcessObjects) return STATUS_NO_MEMORY;
00649 
00650     /* Set it up */
00651     RtlZeroMemory(VdmProcessObjects, sizeof(VDM_PROCESS_OBJECTS));
00652     VdmProcessObjects->VdmTib = VdmTib;
00653     PsGetCurrentProcess()->VdmObjects = VdmProcessObjects;
00654 
00655     /* Set the system affinity for the current thread */
00656     KeSetSystemAffinityThread(1);
00657 
00658     /* Make sure there's space for two IOPMs, then copy & clear the current */
00659     ASSERT(((PKIPCR)KeGetPcr())->GDT[KGDT_TSS / 8].LimitLow >=
00660             (0x2000 + IOPM_OFFSET - 1));
00661     RtlCopyMemory(Ki386IopmSaveArea, &Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
00662     RtlZeroMemory(&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2);
00663 
00664     /* Save the old offset and base, and set the new ones */
00665     OldOffset = Process->IopmOffset;
00666     OldBase = Tss->IoMapBase;
00667     Process->IopmOffset = (USHORT)IOPM_OFFSET;
00668     Tss->IoMapBase = (USHORT)IOPM_OFFSET;
00669 
00670     /* Switch stacks and work the magic */
00671     Ki386SetupAndExitToV86Mode(VdmTeb);
00672 
00673     /* Restore IOPM */
00674     RtlCopyMemory(&Tss->IoMaps[0].IoMap, Ki386IopmSaveArea, PAGE_SIZE * 2);
00675     Process->IopmOffset = OldOffset;
00676     Tss->IoMapBase = OldBase;
00677 
00678     /* Restore affinity */
00679     KeRevertToUserAffinityThread();
00680 
00681     /* Restore context */
00682     RtlCopyMemory(Context, &VdmTib->VdmContext, ContextSize);
00683     Context->ContextFlags = CONTEXT_FULL;
00684 
00685     /* Free VDM objects */
00686     ExFreePool(PsGetCurrentProcess()->VdmObjects);
00687     PsGetCurrentProcess()->VdmObjects = NULL;
00688 
00689     /* Return status */
00690     return STATUS_SUCCESS;
00691 }
00692 
00693 /*
00694  * @implemented
00695  */
00696 BOOLEAN
00697 NTAPI
00698 Ke386IoSetAccessProcess(IN PKPROCESS Process,
00699                         IN ULONG MapNumber)
00700 {
00701     USHORT MapOffset;
00702     PKPRCB Prcb;
00703     KAFFINITY TargetProcessors;
00704 
00705     if(MapNumber > IOPM_COUNT)
00706         return FALSE;
00707 
00708     MapOffset = KiComputeIopmOffset(MapNumber);
00709 
00710     Process->IopmOffset = MapOffset;
00711 
00712     TargetProcessors = Process->ActiveProcessors;
00713     Prcb = KeGetCurrentPrcb();
00714     if (TargetProcessors & Prcb->SetMember)
00715         KeGetPcr()->TSS->IoMapBase = MapOffset;
00716 
00717     return TRUE;
00718 }
00719 
00720 /*
00721  * @implemented
00722  */
00723 BOOLEAN
00724 NTAPI
00725 Ke386SetIoAccessMap(IN ULONG MapNumber,
00726                     IN PKIO_ACCESS_MAP IopmBuffer)
00727 {
00728     PKPROCESS CurrentProcess;
00729     PKPRCB Prcb;
00730     PVOID pt;
00731 
00732     if ((MapNumber > IOPM_COUNT) || (MapNumber == IO_ACCESS_MAP_NONE))
00733         return FALSE;
00734 
00735     Prcb = KeGetCurrentPrcb();
00736 
00737     // Copy the IOP map and load the map for the current process.
00738     pt = &(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap);
00739     RtlMoveMemory(pt, (PVOID)IopmBuffer, IOPM_SIZE);
00740     CurrentProcess = Prcb->CurrentThread->ApcState.Process;
00741     KeGetPcr()->TSS->IoMapBase = CurrentProcess->IopmOffset;
00742 
00743     return TRUE;
00744 }
00745 
00746 /*
00747  * @implemented
00748  */
00749 BOOLEAN
00750 NTAPI
00751 Ke386QueryIoAccessMap(IN ULONG MapNumber,
00752                       IN PKIO_ACCESS_MAP IopmBuffer)
00753 {
00754     ULONG i;
00755     PVOID Map;
00756     PUCHAR p;
00757 
00758     if (MapNumber > IOPM_COUNT)
00759         return FALSE;
00760 
00761     if (MapNumber == IO_ACCESS_MAP_NONE)
00762     {
00763         // no access, simply return a map of all 1s
00764         p = (PUCHAR)IopmBuffer;
00765         for (i = 0; i < IOPM_SIZE; i++) {
00766             p[i] = (UCHAR)-1;
00767         }
00768     }
00769     else
00770     {
00771         // copy the bits
00772         Map = (PVOID)&(KeGetPcr()->TSS->IoMaps[MapNumber-1].IoMap);
00773         RtlMoveMemory((PVOID)IopmBuffer, Map, IOPM_SIZE);
00774     }
00775 
00776     return TRUE;
00777 }

Generated on Sun May 27 2012 04:37:32 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.