1 /* 2 * VideoPort driver 3 * 4 * Copyright (C) 2002, 2003, 2004 ReactOS Team 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 */ 21 22 #include "videoprt.h" 23 24 #include <ndk/kefuncs.h> 25 #include <ndk/halfuncs.h> 26 27 #define NDEBUG 28 #include <debug.h> 29 30 /* PRIVATE FUNCTIONS **********************************************************/ 31 32 #if defined(_M_IX86) || defined(_M_AMD64) 33 NTSTATUS 34 NTAPI 35 IntInitializeVideoAddressSpace(VOID) 36 { 37 OBJECT_ATTRIBUTES ObjectAttributes; 38 UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); 39 NTSTATUS Status; 40 HANDLE PhysMemHandle; 41 PVOID BaseAddress; 42 LARGE_INTEGER Offset; 43 SIZE_T ViewSize; 44 #ifdef _M_IX86 45 CHAR IVTAndBda[1024 + 256]; 46 #endif // _M_IX86 47 48 /* Free the 1MB pre-reserved region. In reality, ReactOS should simply support us mapping the view into the reserved area, but it doesn't. */ 49 BaseAddress = 0; 50 ViewSize = 1024 * 1024; 51 Status = ZwFreeVirtualMemory(NtCurrentProcess(), 52 &BaseAddress, 53 &ViewSize, 54 MEM_RELEASE); 55 if (!NT_SUCCESS(Status)) 56 { 57 DPRINT1("Couldn't unmap reserved memory (%x)\n", Status); 58 return 0; 59 } 60 61 /* Open the physical memory section */ 62 InitializeObjectAttributes(&ObjectAttributes, 63 &PhysMemName, 64 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 65 NULL, 66 NULL); 67 Status = ZwOpenSection(&PhysMemHandle, 68 SECTION_ALL_ACCESS, 69 &ObjectAttributes); 70 if (!NT_SUCCESS(Status)) 71 { 72 DPRINT1("Couldn't open \\Device\\PhysicalMemory\n"); 73 return Status; 74 } 75 76 /* Map the BIOS and device registers into the address space */ 77 Offset.QuadPart = 0xa0000; 78 ViewSize = 0x100000 - 0xa0000; 79 BaseAddress = (PVOID)0xa0000; 80 Status = ZwMapViewOfSection(PhysMemHandle, 81 NtCurrentProcess(), 82 &BaseAddress, 83 0, 84 ViewSize, 85 &Offset, 86 &ViewSize, 87 ViewUnmap, 88 0, 89 PAGE_EXECUTE_READWRITE); 90 if (!NT_SUCCESS(Status)) 91 { 92 DPRINT1("Couldn't map physical memory (%x)\n", Status); 93 ZwClose(PhysMemHandle); 94 return Status; 95 } 96 97 /* Close physical memory section handle */ 98 ZwClose(PhysMemHandle); 99 100 if (BaseAddress != (PVOID)0xa0000) 101 { 102 DPRINT1("Couldn't map physical memory at the right address (was %x)\n", 103 BaseAddress); 104 return STATUS_UNSUCCESSFUL; 105 } 106 107 /* Allocate some low memory to use for the non-BIOS 108 * parts of the v86 mode address space 109 */ 110 BaseAddress = (PVOID)0x1; 111 ViewSize = 0xa0000 - 0x1000; 112 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 113 &BaseAddress, 114 0, 115 &ViewSize, 116 MEM_RESERVE | MEM_COMMIT, 117 PAGE_EXECUTE_READWRITE); 118 if (!NT_SUCCESS(Status)) 119 { 120 DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status); 121 return Status; 122 } 123 if (BaseAddress != (PVOID)0x0) 124 { 125 DPRINT1("Failed to allocate virtual memory at right address (was %x)\n", 126 BaseAddress); 127 return 0; 128 } 129 130 #ifdef _M_IX86 131 /* Get the real mode IVT and BDA from the kernel */ 132 Status = NtVdmControl(VdmInitialize, IVTAndBda); 133 if (!NT_SUCCESS(Status)) 134 { 135 DPRINT1("NtVdmControl failed (status %x)\n", Status); 136 return Status; 137 } 138 #endif // _M_IX86 139 140 /* Return success */ 141 return STATUS_SUCCESS; 142 } 143 #else 144 NTSTATUS 145 NTAPI 146 IntInitializeVideoAddressSpace(VOID) 147 { 148 UNIMPLEMENTED; 149 NT_ASSERT(FALSE); 150 return STATUS_NOT_IMPLEMENTED; 151 } 152 #endif 153 154 VP_STATUS 155 NTAPI 156 IntInt10AllocateBuffer( 157 IN PVOID Context, 158 OUT PUSHORT Seg, 159 OUT PUSHORT Off, 160 IN OUT PULONG Length) 161 { 162 NTSTATUS Status; 163 #ifdef _M_IX86 164 PVOID MemoryAddress; 165 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 166 KAPC_STATE ApcState; 167 SIZE_T Size; 168 169 TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n"); 170 171 IntAttachToCSRSS(&CallingProcess, &ApcState); 172 173 Size = *Length; 174 MemoryAddress = (PVOID)0x20000; 175 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 176 &MemoryAddress, 177 0, 178 &Size, 179 MEM_COMMIT, 180 PAGE_EXECUTE_READWRITE); 181 if (!NT_SUCCESS(Status)) 182 { 183 WARN_(VIDEOPRT, "- ZwAllocateVirtualMemory failed\n"); 184 IntDetachFromCSRSS(&CallingProcess, &ApcState); 185 return ERROR_NOT_ENOUGH_MEMORY; 186 } 187 188 if (MemoryAddress > (PVOID)(0x100000 - Size)) 189 { 190 ZwFreeVirtualMemory(NtCurrentProcess(), 191 &MemoryAddress, 192 &Size, 193 MEM_RELEASE); 194 WARN_(VIDEOPRT, "- Unacceptable memory allocated\n"); 195 IntDetachFromCSRSS(&CallingProcess, &ApcState); 196 return ERROR_NOT_ENOUGH_MEMORY; 197 } 198 199 *Length = (ULONG)Size; 200 *Seg = (USHORT)((ULONG_PTR)MemoryAddress >> 4); 201 *Off = (USHORT)((ULONG_PTR)MemoryAddress & 0xF); 202 203 INFO_(VIDEOPRT, "- Segment: %x\n", (ULONG_PTR)MemoryAddress >> 4); 204 INFO_(VIDEOPRT, "- Offset: %x\n", (ULONG_PTR)MemoryAddress & 0xF); 205 INFO_(VIDEOPRT, "- Length: %x\n", *Length); 206 207 IntDetachFromCSRSS(&CallingProcess, &ApcState); 208 209 return NO_ERROR; 210 #else 211 Status = x86BiosAllocateBuffer(Length, Seg, Off); 212 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY; 213 #endif 214 } 215 216 VP_STATUS 217 NTAPI 218 IntInt10FreeBuffer( 219 IN PVOID Context, 220 IN USHORT Seg, 221 IN USHORT Off) 222 { 223 NTSTATUS Status; 224 #ifdef _M_IX86 225 PVOID MemoryAddress = (PVOID)((ULONG_PTR)(Seg << 4) | Off); 226 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 227 KAPC_STATE ApcState; 228 SIZE_T Size = 0; 229 230 TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n"); 231 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 232 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 233 234 IntAttachToCSRSS(&CallingProcess, &ApcState); 235 Status = ZwFreeVirtualMemory(NtCurrentProcess(), 236 &MemoryAddress, 237 &Size, 238 MEM_RELEASE); 239 240 IntDetachFromCSRSS(&CallingProcess, &ApcState); 241 242 return Status; 243 #else 244 Status = x86BiosFreeBuffer(Seg, Off); 245 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER; 246 #endif 247 } 248 249 VP_STATUS 250 NTAPI 251 IntInt10ReadMemory( 252 IN PVOID Context, 253 IN USHORT Seg, 254 IN USHORT Off, 255 OUT PVOID Buffer, 256 IN ULONG Length) 257 { 258 #ifdef _M_IX86 259 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 260 KAPC_STATE ApcState; 261 262 TRACE_(VIDEOPRT, "IntInt10ReadMemory\n"); 263 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 264 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 265 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer); 266 INFO_(VIDEOPRT, "- Length: %x\n", Length); 267 268 IntAttachToCSRSS(&CallingProcess, &ApcState); 269 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)(Seg << 4) | Off), Length); 270 IntDetachFromCSRSS(&CallingProcess, &ApcState); 271 272 return NO_ERROR; 273 #else 274 NTSTATUS Status; 275 276 Status = x86BiosReadMemory(Seg, Off, Buffer, Length); 277 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER; 278 #endif 279 } 280 281 VP_STATUS 282 NTAPI 283 IntInt10WriteMemory( 284 IN PVOID Context, 285 IN USHORT Seg, 286 IN USHORT Off, 287 IN PVOID Buffer, 288 IN ULONG Length) 289 { 290 #ifdef _M_IX86 291 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 292 KAPC_STATE ApcState; 293 294 TRACE_(VIDEOPRT, "IntInt10WriteMemory\n"); 295 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 296 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 297 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer); 298 INFO_(VIDEOPRT, "- Length: %x\n", Length); 299 300 IntAttachToCSRSS(&CallingProcess, &ApcState); 301 RtlCopyMemory((PVOID)((ULONG_PTR)(Seg << 4) | Off), Buffer, Length); 302 IntDetachFromCSRSS(&CallingProcess, &ApcState); 303 304 return NO_ERROR; 305 #else 306 NTSTATUS Status; 307 308 Status = x86BiosWriteMemory(Seg, Off, Buffer, Length); 309 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER; 310 #endif 311 } 312 313 VP_STATUS 314 NTAPI 315 IntInt10CallBios( 316 IN PVOID Context, 317 IN OUT PINT10_BIOS_ARGUMENTS BiosArguments) 318 { 319 #ifdef _M_AMD64 320 X86_BIOS_REGISTERS BiosContext; 321 #else 322 CONTEXT BiosContext; 323 #endif 324 NTSTATUS Status; 325 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 326 KAPC_STATE ApcState; 327 328 /* Attach to CSRSS */ 329 IntAttachToCSRSS(&CallingProcess, &ApcState); 330 331 /* Clear the context */ 332 RtlZeroMemory(&BiosContext, sizeof(BiosContext)); 333 334 /* Fill out the bios arguments */ 335 BiosContext.Eax = BiosArguments->Eax; 336 BiosContext.Ebx = BiosArguments->Ebx; 337 BiosContext.Ecx = BiosArguments->Ecx; 338 BiosContext.Edx = BiosArguments->Edx; 339 BiosContext.Esi = BiosArguments->Esi; 340 BiosContext.Edi = BiosArguments->Edi; 341 BiosContext.Ebp = BiosArguments->Ebp; 342 BiosContext.SegDs = BiosArguments->SegDs; 343 BiosContext.SegEs = BiosArguments->SegEs; 344 345 /* Do the ROM BIOS call */ 346 (void)KeWaitForMutexObject(&VideoPortInt10Mutex, 347 Executive, 348 KernelMode, 349 FALSE, 350 NULL); 351 352 #ifdef _M_AMD64 353 Status = x86BiosCall(0x10, &BiosContext) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; 354 #else 355 Status = Ke386CallBios(0x10, &BiosContext); 356 #endif 357 358 KeReleaseMutex(&VideoPortInt10Mutex, FALSE); 359 360 /* Return the arguments */ 361 BiosArguments->Eax = BiosContext.Eax; 362 BiosArguments->Ebx = BiosContext.Ebx; 363 BiosArguments->Ecx = BiosContext.Ecx; 364 BiosArguments->Edx = BiosContext.Edx; 365 BiosArguments->Esi = BiosContext.Esi; 366 BiosArguments->Edi = BiosContext.Edi; 367 BiosArguments->Ebp = BiosContext.Ebp; 368 BiosArguments->SegDs = (USHORT)BiosContext.SegDs; 369 BiosArguments->SegEs = (USHORT)BiosContext.SegEs; 370 371 /* Detach and return status */ 372 IntDetachFromCSRSS(&CallingProcess, &ApcState); 373 374 if (NT_SUCCESS(Status)) 375 { 376 return NO_ERROR; 377 } 378 379 return ERROR_INVALID_PARAMETER; 380 } 381 382 /* PUBLIC FUNCTIONS ***********************************************************/ 383 384 /* 385 * @implemented 386 */ 387 VP_STATUS 388 NTAPI 389 VideoPortInt10( 390 IN PVOID HwDeviceExtension, 391 IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments) 392 { 393 INT10_BIOS_ARGUMENTS Int10BiosArguments; 394 VP_STATUS Status; 395 396 if (!CsrssInitialized) 397 { 398 return ERROR_INVALID_PARAMETER; 399 } 400 401 /* Copy arguments to other format */ 402 RtlCopyMemory(&Int10BiosArguments, BiosArguments, sizeof(*BiosArguments)); 403 Int10BiosArguments.SegDs = 0; 404 Int10BiosArguments.SegEs = 0; 405 406 /* Do the BIOS call */ 407 Status = IntInt10CallBios(NULL, &Int10BiosArguments); 408 409 /* Copy results back */ 410 RtlCopyMemory(BiosArguments, &Int10BiosArguments, sizeof(*BiosArguments)); 411 412 return Status; 413 } 414