Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

biosc.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 abiosc.c 00008 00009 Abstract: 00010 00011 This module implements ROM BIOS support C routines for i386 NT. 00012 00013 Author: 00014 00015 Shie-Lin Tzong (shielint) 10-Sept-1992 00016 00017 Environment: 00018 00019 Kernel mode. 00020 00021 00022 Revision History: 00023 00024 --*/ 00025 #include "ki.h" 00026 #pragma hdrstop 00027 #include "vdmntos.h" 00028 00029 00030 #ifdef ALLOC_PRAGMA 00031 #pragma alloc_text(PAGE,Ke386CallBios) 00032 #endif 00033 00034 00035 // 00036 // Never change these equates without checking biosa.asm 00037 // 00038 00039 #define V86_CODE_ADDRESS 0x10000 00040 #define INT_OPCODE 0xcd 00041 #define V86_BOP_OPCODE 0xfec4c4 00042 #define V86_STACK_POINTER 0x1ffe 00043 #define IOPM_OFFSET FIELD_OFFSET(KTSS, IoMaps[0].IoMap) 00044 #define VDM_TIB_ADDRESS 0x12000 00045 #define INT_10_TEB 0x13000 00046 00047 // 00048 // External References 00049 // 00050 00051 PVOID Ki386IopmSaveArea; 00052 BOOLEAN BiosInitialized = FALSE; 00053 VOID 00054 Ki386SetupAndExitToV86Code ( 00055 PVOID ExecutionAddress 00056 ); 00057 00058 00059 NTSTATUS 00060 Ke386CallBios ( 00061 IN ULONG BiosCommand, 00062 IN OUT PCONTEXT BiosArguments 00063 ) 00064 00065 /*++ 00066 00067 Routine Description: 00068 00069 This function invokes specified ROM BIOS code by executing 00070 "INT BiosCommand." Before executing the BIOS code, this function 00071 will setup VDM context, change stack pointer ...etc. If for some reason 00072 the operation fails, a status code will be returned. Otherwise, this 00073 function always returns success reguardless of the result of the BIOS 00074 call. 00075 00076 N.B. This implementation relies on the fact that the direct 00077 I/O access operations between apps are serialized by win user. 00078 00079 Arguments: 00080 00081 BiosCommand - specifies which ROM BIOS function to invoke. 00082 00083 BiosArguments - specifies a pointer to the context which will be used 00084 to invoke ROM BIOS. 00085 00086 Return Value: 00087 00088 NTSTATUS code to specify the failure. 00089 00090 --*/ 00091 00092 { 00093 00094 NTSTATUS Status = STATUS_SUCCESS; 00095 PVDM_TIB VdmTib; 00096 PUCHAR BaseAddress = (PUCHAR)V86_CODE_ADDRESS; 00097 PTEB UserInt10Teb = (PTEB)INT_10_TEB; 00098 PKTSS Tss; 00099 PKPROCESS Process; 00100 PKTHREAD Thread; 00101 USHORT OldIopmOffset, OldIoMapBase; 00102 PVDM_PROCESS_OBJECTS VdmObjects; 00103 ULONG ContextLength; 00104 00105 // KIRQL OldIrql; 00106 //#if DBG 00107 // PULONG IdtAddress; 00108 // ULONG RegionSize; 00109 // ULONG OldProtect; 00110 //#endif 00111 00112 // 00113 // Map in ROM BIOS area to perform the int 10 code 00114 // 00115 00116 if (!BiosInitialized) { 00117 RtlZeroMemory(UserInt10Teb, sizeof(TEB)); 00118 } 00119 00120 //#if DBG 00121 // IdtAddress = 0; 00122 // RegionSize = 0x1000; 00123 // ZwProtectVirtualMemory ( NtCurrentProcess(), 00124 // &IdtAddress, 00125 // &RegionSize, 00126 // PAGE_READWRITE, 00127 // &OldProtect 00128 // ); 00129 //#endif 00130 00131 try { 00132 00133 // 00134 // Write "Int BiosCommand; bop" to reserved user space (0x1000). 00135 // Later control will transfer to the user space to execute 00136 // these two instructions. 00137 // 00138 00139 *BaseAddress++ = INT_OPCODE; 00140 *BaseAddress++ = (UCHAR)BiosCommand; 00141 *(PULONG)BaseAddress = V86_BOP_OPCODE; 00142 00143 // 00144 // Set up Vdm(v86) context to execute the int BiosCommand 00145 // instruction by copying user supplied context to VdmContext 00146 // and updating the control registers to predefined values. 00147 // 00148 00149 // 00150 // We want to use a constant number for the int10. 00151 // 00152 // 00153 // Create a fake TEB so we can switch the thread to it while we 00154 // do an int10 00155 // 00156 00157 UserInt10Teb->Vdm = (PVOID)VDM_TIB_ADDRESS; 00158 VdmTib = (PVDM_TIB)VDM_TIB_ADDRESS; 00159 RtlZeroMemory(VdmTib, sizeof(VDM_TIB)); 00160 VdmTib->Size = sizeof(VDM_TIB); 00161 *pNtVDMState = 0; 00162 00163 // 00164 // extended registers are never going to matter to 00165 // an Int10 call, so only copy the old part of the 00166 // context record. 00167 // 00168 ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 00169 RtlMoveMemory(&(VdmTib->VdmContext), BiosArguments, ContextLength); 00170 VdmTib->VdmContext.SegCs = (ULONG)BaseAddress >> 4; 00171 VdmTib->VdmContext.SegSs = (ULONG)BaseAddress >> 4; 00172 VdmTib->VdmContext.Eip = 0; 00173 VdmTib->VdmContext.Esp = 2 * PAGE_SIZE - sizeof(ULONG); 00174 VdmTib->VdmContext.EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK; 00175 VdmTib->VdmContext.ContextFlags = CONTEXT_FULL; 00176 00177 } except (EXCEPTION_EXECUTE_HANDLER) { 00178 00179 Status = GetExceptionCode(); 00180 } 00181 00182 // 00183 // The vdm kernel code finds the Tib by looking at a pointer cached in 00184 // kernel memory, which was probed at Vdm creation time. Since the 00185 // creation semantics for this vdm are peculiar, we do something similar 00186 // here. 00187 // 00188 00189 try { 00190 00191 // 00192 // We never get here on a process that is a real vdm. If we do, 00193 // bad things will happen (pool leak, failure to execute dos and windows apps) 00194 // 00195 ASSERT(PsGetCurrentProcess()->VdmObjects == NULL); 00196 VdmObjects = ExAllocatePoolWithTag( 00197 NonPagedPool, 00198 sizeof(VDM_PROCESS_OBJECTS), 00199 ' eK' 00200 ); 00201 00202 00203 // 00204 // Since we are doing this on behalf of CSR not a user process, we aren't 00205 // charging quota. 00206 // 00207 if (VdmObjects == NULL) { 00208 Status = STATUS_NO_MEMORY; 00209 } else { 00210 00211 // 00212 // We are only initializing the VdmTib pointer, because that's the only 00213 // part of the VdmObjects we use for ROM calls. We aren't set up 00214 // to simulate interrupts, or any of the other stuff that would be done 00215 // in a conventional vdm 00216 // 00217 RtlZeroMemory( VdmObjects, sizeof(VDM_PROCESS_OBJECTS)); 00218 00219 VdmObjects->VdmTib = VdmTib; 00220 00221 PsGetCurrentProcess()->VdmObjects = VdmObjects; 00222 } 00223 } except (EXCEPTION_EXECUTE_HANDLER) { 00224 00225 Status = GetExceptionCode(); 00226 } 00227 00228 if (Status == STATUS_SUCCESS) { 00229 00230 // 00231 // Since we are going to v86 mode and accessing some I/O ports, we 00232 // need to make sure the IopmOffset is set correctly across context 00233 // swap and the I/O bit map has all the bits cleared. 00234 // N.B. This implementation assumes that there is only one full 00235 // screen DOS app and the io access between full screen DOS 00236 // app and the server code is serialized by win user. That 00237 // means even we change the IOPM, the full screen dos app won't 00238 // be able to run on this IOPM. 00239 // * In another words, IF THERE IS 00240 // * MORE THAN ONE FULL SCREEN DOS APPS, THIS CODE IS BROKEN.* 00241 // 00242 // NOTE This code works on the assumption that winuser serializes 00243 // direct I/O access operations. 00244 // 00245 00246 // 00247 // Call the bios from the processor which booted the machine. 00248 // 00249 00250 Thread = KeGetCurrentThread(); 00251 KeSetSystemAffinityThread(1); 00252 Tss = KeGetPcr()->TSS; 00253 00254 // 00255 // Save away the original IOPM bit map and clear all the IOPM bits 00256 // to allow v86 int 10 code to access ALL the io ports. 00257 // 00258 00259 // 00260 // Make sure there are at least 2 IOPM maps. 00261 // 00262 00263 ASSERT(KeGetPcr()->GDT[KGDT_TSS / 8].LimitLow >= (0x2000 + IOPM_OFFSET - 1)); 00264 RtlMoveMemory (Ki386IopmSaveArea, 00265 (PVOID)&Tss->IoMaps[0].IoMap, 00266 PAGE_SIZE * 2 00267 ); 00268 RtlZeroMemory ((PVOID)&Tss->IoMaps[0].IoMap, PAGE_SIZE * 2); 00269 00270 Process = Thread->ApcState.Process; 00271 OldIopmOffset = Process->IopmOffset; 00272 OldIoMapBase = Tss->IoMapBase; 00273 Process->IopmOffset = (USHORT)(IOPM_OFFSET); // Set Process IoPmOffset before 00274 Tss->IoMapBase = (USHORT)(IOPM_OFFSET); // updating Tss IoMapBase 00275 00276 // 00277 // Call ASM routine to switch stack to exit to v86 mode to 00278 // run Int BiosCommand. 00279 // 00280 00281 Ki386SetupAndExitToV86Code(UserInt10Teb); 00282 00283 // 00284 // After we return from v86 mode, the control comes here. 00285 // 00286 // Restore old IOPM 00287 // 00288 00289 RtlMoveMemory ((PVOID)&Tss->IoMaps[0].IoMap, 00290 Ki386IopmSaveArea, 00291 PAGE_SIZE * 2 00292 ); 00293 00294 Process->IopmOffset = OldIopmOffset; 00295 Tss->IoMapBase = OldIoMapBase; 00296 00297 // 00298 // Restore old affinity for current thread. 00299 // 00300 00301 KeRevertToUserAffinityThread(); 00302 00303 // 00304 // Copy 16 bit vdm context back to caller. 00305 // 00306 // Extended register state is not going to matter, 00307 // so copy only the old part of the context record. 00308 // 00309 ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters); 00310 RtlMoveMemory(BiosArguments, &(VdmTib->VdmContext), ContextLength); 00311 BiosArguments->ContextFlags = CONTEXT_FULL; 00312 00313 // 00314 // Free the pool used for the VdmTib pointer 00315 // 00316 ExFreePool(PsGetCurrentProcess()->VdmObjects); 00317 PsGetCurrentProcess()->VdmObjects = NULL; 00318 00319 } 00320 00321 //#if DBG 00322 // IdtAddress = 0; 00323 // RegionSize = 0x1000; 00324 // ZwProtectVirtualMemory ( NtCurrentProcess(), 00325 // &IdtAddress, 00326 // &RegionSize, 00327 // PAGE_NOACCESS, 00328 // &OldProtect 00329 // ); 00330 //#endif 00331 00332 return(Status); 00333 }

Generated on Sat May 15 19:39:18 2004 for test by doxygen 1.3.7