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 #include <ndk/mmfuncs.h> 27 28 #define NDEBUG 29 #include <debug.h> 30 31 /* PRIVATE FUNCTIONS **********************************************************/ 32 33 #define IsLowV86Mem(_Seg, _Off) ((((_Seg) << 4) + (_Off)) < (0xa0000)) 34 35 /* Those two functions below are there so that CSRSS can't access low mem. 36 * Expecially, MAKE IT CRASH ON NULL ACCESS */ 37 static 38 VOID 39 ProtectLowV86Mem(VOID) 40 { 41 /* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it 42 * And we truncate one page to get the right range spanned. */ 43 PVOID BaseAddress = (PVOID)1; 44 NTSTATUS Status; 45 SIZE_T ViewSize = 0xa0000 - PAGE_SIZE; 46 47 /* We should only do that for CSRSS. */ 48 ASSERT(PsGetCurrentProcess() == (PEPROCESS)CsrProcess); 49 50 /* Commit (again) the pages, but with PAGE_NOACCESS protection */ 51 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 52 &BaseAddress, 53 0, 54 &ViewSize, 55 MEM_COMMIT, 56 PAGE_NOACCESS); 57 ASSERT(NT_SUCCESS(Status)); 58 } 59 60 static 61 VOID 62 UnprotectLowV86Mem(VOID) 63 { 64 /* We pass a non-NULL address so that ZwAllocateVirtualMemory really does it 65 * And we truncate one page to get the right range spanned. */ 66 PVOID BaseAddress = (PVOID)1; 67 NTSTATUS Status; 68 SIZE_T ViewSize = 0xa0000 - PAGE_SIZE; 69 70 /* We should only do that for CSRSS, for the v86 address space */ 71 ASSERT(PsGetCurrentProcess() == (PEPROCESS)CsrProcess); 72 73 /* Commit (again) the pages, but with PAGE_READWRITE protection */ 74 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 75 &BaseAddress, 76 0, 77 &ViewSize, 78 MEM_COMMIT, 79 PAGE_READWRITE); 80 ASSERT(NT_SUCCESS(Status)); 81 } 82 83 #if defined(_M_IX86) || defined(_M_AMD64) 84 NTSTATUS 85 NTAPI 86 IntInitializeVideoAddressSpace(VOID) 87 { 88 OBJECT_ATTRIBUTES ObjectAttributes; 89 UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); 90 NTSTATUS Status; 91 HANDLE PhysMemHandle; 92 PVOID BaseAddress; 93 LARGE_INTEGER Offset; 94 SIZE_T ViewSize; 95 #ifdef _M_IX86 96 CHAR IVTAndBda[1024 + 256]; 97 #endif // _M_IX86 98 99 /* Free the 1MB pre-reserved region. In reality, ReactOS should simply support us mapping the view into the reserved area, but it doesn't. */ 100 BaseAddress = 0; 101 ViewSize = 1024 * 1024; 102 Status = ZwFreeVirtualMemory(NtCurrentProcess(), 103 &BaseAddress, 104 &ViewSize, 105 MEM_RELEASE); 106 if (!NT_SUCCESS(Status)) 107 { 108 DPRINT1("Couldn't unmap reserved memory (%x)\n", Status); 109 return 0; 110 } 111 112 /* Open the physical memory section */ 113 InitializeObjectAttributes(&ObjectAttributes, 114 &PhysMemName, 115 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 116 NULL, 117 NULL); 118 Status = ZwOpenSection(&PhysMemHandle, 119 SECTION_ALL_ACCESS, 120 &ObjectAttributes); 121 if (!NT_SUCCESS(Status)) 122 { 123 DPRINT1("Couldn't open \\Device\\PhysicalMemory\n"); 124 return Status; 125 } 126 127 /* Map the BIOS and device registers into the address space */ 128 Offset.QuadPart = 0xa0000; 129 ViewSize = 0x100000 - 0xa0000; 130 BaseAddress = (PVOID)0xa0000; 131 Status = ZwMapViewOfSection(PhysMemHandle, 132 NtCurrentProcess(), 133 &BaseAddress, 134 0, 135 ViewSize, 136 &Offset, 137 &ViewSize, 138 ViewUnmap, 139 0, 140 PAGE_EXECUTE_READWRITE); 141 if (!NT_SUCCESS(Status)) 142 { 143 DPRINT1("Couldn't map physical memory (%x)\n", Status); 144 ZwClose(PhysMemHandle); 145 return Status; 146 } 147 148 /* Close physical memory section handle */ 149 ZwClose(PhysMemHandle); 150 151 if (BaseAddress != (PVOID)0xa0000) 152 { 153 DPRINT1("Couldn't map physical memory at the right address (was %x)\n", 154 BaseAddress); 155 return STATUS_UNSUCCESSFUL; 156 } 157 158 /* Allocate some low memory to use for the non-BIOS 159 * parts of the v86 mode address space 160 */ 161 BaseAddress = (PVOID)0x1; 162 ViewSize = 0xa0000 - 0x1000; 163 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 164 &BaseAddress, 165 0, 166 &ViewSize, 167 MEM_RESERVE | MEM_COMMIT, 168 PAGE_EXECUTE_READWRITE); 169 if (!NT_SUCCESS(Status)) 170 { 171 DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status); 172 return Status; 173 } 174 if (BaseAddress != (PVOID)0x0) 175 { 176 DPRINT1("Failed to allocate virtual memory at right address (was %x)\n", 177 BaseAddress); 178 return 0; 179 } 180 181 #ifdef _M_IX86 182 /* Get the real mode IVT and BDA from the kernel */ 183 Status = NtVdmControl(VdmInitialize, IVTAndBda); 184 if (!NT_SUCCESS(Status)) 185 { 186 DPRINT1("NtVdmControl failed (status %x)\n", Status); 187 return Status; 188 } 189 #endif // _M_IX86 190 191 /* Protect the V86 address space after this */ 192 ProtectLowV86Mem(); 193 194 /* Return success */ 195 return STATUS_SUCCESS; 196 } 197 #else 198 NTSTATUS 199 NTAPI 200 IntInitializeVideoAddressSpace(VOID) 201 { 202 UNIMPLEMENTED; 203 NT_ASSERT(FALSE); 204 return STATUS_NOT_IMPLEMENTED; 205 } 206 #endif 207 208 VP_STATUS 209 NTAPI 210 IntInt10AllocateBuffer( 211 IN PVOID Context, 212 OUT PUSHORT Seg, 213 OUT PUSHORT Off, 214 IN OUT PULONG Length) 215 { 216 NTSTATUS Status; 217 #ifdef _M_IX86 218 PVOID MemoryAddress; 219 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 220 KAPC_STATE ApcState; 221 SIZE_T Size; 222 223 TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n"); 224 225 IntAttachToCSRSS(&CallingProcess, &ApcState); 226 227 Size = *Length; 228 MemoryAddress = (PVOID)0x20000; 229 230 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 231 &MemoryAddress, 232 0, 233 &Size, 234 MEM_COMMIT, 235 PAGE_EXECUTE_READWRITE); 236 if (!NT_SUCCESS(Status)) 237 { 238 WARN_(VIDEOPRT, "- ZwAllocateVirtualMemory failed\n"); 239 IntDetachFromCSRSS(&CallingProcess, &ApcState); 240 return ERROR_NOT_ENOUGH_MEMORY; 241 } 242 243 if (MemoryAddress > (PVOID)(0x100000 - Size)) 244 { 245 ZwFreeVirtualMemory(NtCurrentProcess(), 246 &MemoryAddress, 247 &Size, 248 MEM_RELEASE); 249 WARN_(VIDEOPRT, "- Unacceptable memory allocated\n"); 250 IntDetachFromCSRSS(&CallingProcess, &ApcState); 251 return ERROR_NOT_ENOUGH_MEMORY; 252 } 253 254 *Length = (ULONG)Size; 255 *Seg = (USHORT)((ULONG_PTR)MemoryAddress >> 4); 256 *Off = (USHORT)((ULONG_PTR)MemoryAddress & 0xF); 257 258 INFO_(VIDEOPRT, "- Segment: %x\n", (ULONG_PTR)MemoryAddress >> 4); 259 INFO_(VIDEOPRT, "- Offset: %x\n", (ULONG_PTR)MemoryAddress & 0xF); 260 INFO_(VIDEOPRT, "- Length: %x\n", *Length); 261 262 IntDetachFromCSRSS(&CallingProcess, &ApcState); 263 264 return NO_ERROR; 265 #else 266 Status = x86BiosAllocateBuffer(Length, Seg, Off); 267 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_NOT_ENOUGH_MEMORY; 268 #endif 269 } 270 271 VP_STATUS 272 NTAPI 273 IntInt10FreeBuffer( 274 IN PVOID Context, 275 IN USHORT Seg, 276 IN USHORT Off) 277 { 278 NTSTATUS Status; 279 #ifdef _M_IX86 280 PVOID MemoryAddress = (PVOID)((ULONG_PTR)(Seg << 4) | Off); 281 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 282 KAPC_STATE ApcState; 283 SIZE_T Size = 0; 284 285 TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n"); 286 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 287 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 288 289 IntAttachToCSRSS(&CallingProcess, &ApcState); 290 Status = ZwFreeVirtualMemory(NtCurrentProcess(), 291 &MemoryAddress, 292 &Size, 293 MEM_RELEASE); 294 295 IntDetachFromCSRSS(&CallingProcess, &ApcState); 296 297 return Status; 298 #else 299 Status = x86BiosFreeBuffer(Seg, Off); 300 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER; 301 #endif 302 } 303 304 VP_STATUS 305 NTAPI 306 IntInt10ReadMemory( 307 IN PVOID Context, 308 IN USHORT Seg, 309 IN USHORT Off, 310 OUT PVOID Buffer, 311 IN ULONG Length) 312 { 313 #ifdef _M_IX86 314 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 315 KAPC_STATE ApcState; 316 317 TRACE_(VIDEOPRT, "IntInt10ReadMemory\n"); 318 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 319 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 320 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer); 321 INFO_(VIDEOPRT, "- Length: %x\n", Length); 322 323 IntAttachToCSRSS(&CallingProcess, &ApcState); 324 325 if (IsLowV86Mem(Seg, Off)) 326 UnprotectLowV86Mem(); 327 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)(Seg << 4) | Off), Length); 328 if (IsLowV86Mem(Seg, Off)) 329 ProtectLowV86Mem(); 330 331 IntDetachFromCSRSS(&CallingProcess, &ApcState); 332 333 return NO_ERROR; 334 #else 335 NTSTATUS Status; 336 337 Status = x86BiosReadMemory(Seg, Off, Buffer, Length); 338 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER; 339 #endif 340 } 341 342 VP_STATUS 343 NTAPI 344 IntInt10WriteMemory( 345 IN PVOID Context, 346 IN USHORT Seg, 347 IN USHORT Off, 348 IN PVOID Buffer, 349 IN ULONG Length) 350 { 351 #ifdef _M_IX86 352 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 353 KAPC_STATE ApcState; 354 355 TRACE_(VIDEOPRT, "IntInt10WriteMemory\n"); 356 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 357 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 358 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer); 359 INFO_(VIDEOPRT, "- Length: %x\n", Length); 360 361 IntAttachToCSRSS(&CallingProcess, &ApcState); 362 if (IsLowV86Mem(Seg, Off)) 363 UnprotectLowV86Mem(); 364 RtlCopyMemory((PVOID)((ULONG_PTR)(Seg << 4) | Off), Buffer, Length); 365 if (IsLowV86Mem(Seg, Off)) 366 ProtectLowV86Mem(); 367 IntDetachFromCSRSS(&CallingProcess, &ApcState); 368 369 return NO_ERROR; 370 #else 371 NTSTATUS Status; 372 373 Status = x86BiosWriteMemory(Seg, Off, Buffer, Length); 374 return NT_SUCCESS(Status) ? NO_ERROR : ERROR_INVALID_PARAMETER; 375 #endif 376 } 377 378 VP_STATUS 379 NTAPI 380 IntInt10CallBios( 381 IN PVOID Context, 382 IN OUT PINT10_BIOS_ARGUMENTS BiosArguments) 383 { 384 #ifdef _M_AMD64 385 X86_BIOS_REGISTERS BiosContext; 386 #else 387 CONTEXT BiosContext; 388 #endif 389 NTSTATUS Status; 390 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 391 KAPC_STATE ApcState; 392 393 /* Attach to CSRSS */ 394 IntAttachToCSRSS(&CallingProcess, &ApcState); 395 396 /* Clear the context */ 397 RtlZeroMemory(&BiosContext, sizeof(BiosContext)); 398 399 /* Fill out the bios arguments */ 400 BiosContext.Eax = BiosArguments->Eax; 401 BiosContext.Ebx = BiosArguments->Ebx; 402 BiosContext.Ecx = BiosArguments->Ecx; 403 BiosContext.Edx = BiosArguments->Edx; 404 BiosContext.Esi = BiosArguments->Esi; 405 BiosContext.Edi = BiosArguments->Edi; 406 BiosContext.Ebp = BiosArguments->Ebp; 407 BiosContext.SegDs = BiosArguments->SegDs; 408 BiosContext.SegEs = BiosArguments->SegEs; 409 410 /* Do the ROM BIOS call */ 411 (void)KeWaitForMutexObject(&VideoPortInt10Mutex, 412 Executive, 413 KernelMode, 414 FALSE, 415 NULL); 416 417 /* The kernel needs access here */ 418 UnprotectLowV86Mem(); 419 #ifdef _M_AMD64 420 Status = x86BiosCall(0x10, &BiosContext) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; 421 #else 422 Status = Ke386CallBios(0x10, &BiosContext); 423 #endif 424 ProtectLowV86Mem(); 425 426 KeReleaseMutex(&VideoPortInt10Mutex, FALSE); 427 428 /* Return the arguments */ 429 BiosArguments->Eax = BiosContext.Eax; 430 BiosArguments->Ebx = BiosContext.Ebx; 431 BiosArguments->Ecx = BiosContext.Ecx; 432 BiosArguments->Edx = BiosContext.Edx; 433 BiosArguments->Esi = BiosContext.Esi; 434 BiosArguments->Edi = BiosContext.Edi; 435 BiosArguments->Ebp = BiosContext.Ebp; 436 BiosArguments->SegDs = (USHORT)BiosContext.SegDs; 437 BiosArguments->SegEs = (USHORT)BiosContext.SegEs; 438 439 /* Detach and return status */ 440 IntDetachFromCSRSS(&CallingProcess, &ApcState); 441 442 if (NT_SUCCESS(Status)) 443 { 444 return NO_ERROR; 445 } 446 447 return ERROR_INVALID_PARAMETER; 448 } 449 450 /* PUBLIC FUNCTIONS ***********************************************************/ 451 452 /* 453 * @implemented 454 */ 455 VP_STATUS 456 NTAPI 457 VideoPortInt10( 458 IN PVOID HwDeviceExtension, 459 IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments) 460 { 461 INT10_BIOS_ARGUMENTS Int10BiosArguments; 462 VP_STATUS Status; 463 464 if (!CsrProcess) 465 { 466 return ERROR_INVALID_PARAMETER; 467 } 468 469 /* Copy arguments to other format */ 470 RtlCopyMemory(&Int10BiosArguments, BiosArguments, sizeof(*BiosArguments)); 471 Int10BiosArguments.SegDs = 0; 472 Int10BiosArguments.SegEs = 0; 473 474 /* Do the BIOS call */ 475 Status = IntInt10CallBios(NULL, &Int10BiosArguments); 476 477 /* Copy results back */ 478 RtlCopyMemory(BiosArguments, &Int10BiosArguments, sizeof(*BiosArguments)); 479 480 return Status; 481 } 482