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 26 #define NDEBUG 27 #include <debug.h> 28 29 /* PRIVATE FUNCTIONS **********************************************************/ 30 31 #if defined(_M_IX86) || defined(_M_AMD64) 32 NTSTATUS 33 NTAPI 34 IntInitializeVideoAddressSpace(VOID) 35 { 36 OBJECT_ATTRIBUTES ObjectAttributes; 37 UNICODE_STRING PhysMemName = RTL_CONSTANT_STRING(L"\\Device\\PhysicalMemory"); 38 NTSTATUS Status; 39 HANDLE PhysMemHandle; 40 PVOID BaseAddress; 41 LARGE_INTEGER Offset; 42 SIZE_T ViewSize; 43 #ifdef _M_IX86 44 CHAR IVTAndBda[1024+256]; 45 #endif // _M_IX86 46 47 /* Free the 1MB pre-reserved region. In reality, ReactOS should simply support us mapping the view into the reserved area, but it doesn't. */ 48 BaseAddress = 0; 49 ViewSize = 1024 * 1024; 50 Status = ZwFreeVirtualMemory(NtCurrentProcess(), 51 &BaseAddress, 52 &ViewSize, 53 MEM_RELEASE); 54 if (!NT_SUCCESS(Status)) 55 { 56 DPRINT1("Couldn't unmap reserved memory (%x)\n", Status); 57 return 0; 58 } 59 60 /* Open the physical memory section */ 61 InitializeObjectAttributes(&ObjectAttributes, 62 &PhysMemName, 63 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 64 NULL, 65 NULL); 66 Status = ZwOpenSection(&PhysMemHandle, 67 SECTION_ALL_ACCESS, 68 &ObjectAttributes); 69 if (!NT_SUCCESS(Status)) 70 { 71 DPRINT1("Couldn't open \\Device\\PhysicalMemory\n"); 72 return Status; 73 } 74 75 /* Map the BIOS and device registers into the address space */ 76 Offset.QuadPart = 0xa0000; 77 ViewSize = 0x100000 - 0xa0000; 78 BaseAddress = (PVOID)0xa0000; 79 Status = ZwMapViewOfSection(PhysMemHandle, 80 NtCurrentProcess(), 81 &BaseAddress, 82 0, 83 ViewSize, 84 &Offset, 85 &ViewSize, 86 ViewUnmap, 87 0, 88 PAGE_EXECUTE_READWRITE); 89 if (!NT_SUCCESS(Status)) 90 { 91 DPRINT1("Couldn't map physical memory (%x)\n", Status); 92 ZwClose(PhysMemHandle); 93 return Status; 94 } 95 96 /* Close physical memory section handle */ 97 ZwClose(PhysMemHandle); 98 99 if (BaseAddress != (PVOID)0xa0000) 100 { 101 DPRINT1("Couldn't map physical memory at the right address (was %x)\n", 102 BaseAddress); 103 return STATUS_UNSUCCESSFUL; 104 } 105 106 /* Allocate some low memory to use for the non-BIOS 107 * parts of the v86 mode address space 108 */ 109 BaseAddress = (PVOID)0x1; 110 ViewSize = 0xa0000 - 0x1000; 111 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), 112 &BaseAddress, 113 0, 114 &ViewSize, 115 MEM_RESERVE | MEM_COMMIT, 116 PAGE_EXECUTE_READWRITE); 117 if (!NT_SUCCESS(Status)) 118 { 119 DPRINT1("Failed to allocate virtual memory (Status %x)\n", Status); 120 return Status; 121 } 122 if (BaseAddress != (PVOID)0x0) 123 { 124 DPRINT1("Failed to allocate virtual memory at right address (was %x)\n", 125 BaseAddress); 126 return 0; 127 } 128 129 #ifdef _M_IX86 130 /* Get the real mode IVT and BDA from the kernel */ 131 Status = NtVdmControl(VdmInitialize, IVTAndBda); 132 if (!NT_SUCCESS(Status)) 133 { 134 DPRINT1("NtVdmControl failed (status %x)\n", Status); 135 return Status; 136 } 137 #endif // _M_IX86 138 139 /* Return success */ 140 return STATUS_SUCCESS; 141 } 142 #else 143 NTSTATUS 144 NTAPI 145 IntInitializeVideoAddressSpace(VOID) 146 { 147 UNIMPLEMENTED; 148 NT_ASSERT(FALSE); 149 return STATUS_NOT_IMPLEMENTED; 150 } 151 #endif 152 153 #if defined(_M_IX86) 154 VP_STATUS NTAPI 155 IntInt10AllocateBuffer( 156 IN PVOID Context, 157 OUT PUSHORT Seg, 158 OUT PUSHORT Off, 159 IN OUT PULONG Length) 160 { 161 PVOID MemoryAddress; 162 NTSTATUS Status; 163 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 164 KAPC_STATE ApcState; 165 166 TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n"); 167 168 IntAttachToCSRSS(&CallingProcess, &ApcState); 169 170 MemoryAddress = (PVOID)0x20000; 171 Status = ZwAllocateVirtualMemory(NtCurrentProcess(), &MemoryAddress, 0, 172 Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 173 174 if (!NT_SUCCESS(Status)) 175 { 176 WARN_(VIDEOPRT, "- ZwAllocateVirtualMemory failed\n"); 177 IntDetachFromCSRSS(&CallingProcess, &ApcState); 178 return ERROR_NOT_ENOUGH_MEMORY; 179 } 180 181 if (MemoryAddress > (PVOID)(0x100000 - *Length)) 182 { 183 ZwFreeVirtualMemory(NtCurrentProcess(), &MemoryAddress, Length, 184 MEM_RELEASE); 185 WARN_(VIDEOPRT, "- Unacceptable memory allocated\n"); 186 IntDetachFromCSRSS(&CallingProcess, &ApcState); 187 return ERROR_NOT_ENOUGH_MEMORY; 188 } 189 190 *Seg = (USHORT)((ULONG)MemoryAddress >> 4); 191 *Off = (USHORT)((ULONG)MemoryAddress & 0xF); 192 193 INFO_(VIDEOPRT, "- Segment: %x\n", (ULONG)MemoryAddress >> 4); 194 INFO_(VIDEOPRT, "- Offset: %x\n", (ULONG)MemoryAddress & 0xF); 195 INFO_(VIDEOPRT, "- Length: %x\n", *Length); 196 197 IntDetachFromCSRSS(&CallingProcess, &ApcState); 198 199 return NO_ERROR; 200 } 201 202 VP_STATUS NTAPI 203 IntInt10FreeBuffer( 204 IN PVOID Context, 205 IN USHORT Seg, 206 IN USHORT Off) 207 { 208 PVOID MemoryAddress = (PVOID)((Seg << 4) | Off); 209 NTSTATUS Status; 210 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 211 KAPC_STATE ApcState; 212 SIZE_T Size = 0; 213 214 TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n"); 215 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 216 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 217 218 IntAttachToCSRSS(&CallingProcess, &ApcState); 219 Status = ZwFreeVirtualMemory(NtCurrentProcess(), &MemoryAddress, &Size, 220 MEM_RELEASE); 221 IntDetachFromCSRSS(&CallingProcess, &ApcState); 222 223 return Status; 224 } 225 226 VP_STATUS NTAPI 227 IntInt10ReadMemory( 228 IN PVOID Context, 229 IN USHORT Seg, 230 IN USHORT Off, 231 OUT PVOID Buffer, 232 IN ULONG Length) 233 { 234 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 235 KAPC_STATE ApcState; 236 237 TRACE_(VIDEOPRT, "IntInt10ReadMemory\n"); 238 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 239 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 240 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer); 241 INFO_(VIDEOPRT, "- Length: %x\n", Length); 242 243 IntAttachToCSRSS(&CallingProcess, &ApcState); 244 RtlCopyMemory(Buffer, (PVOID)((Seg << 4) | Off), Length); 245 IntDetachFromCSRSS(&CallingProcess, &ApcState); 246 247 return NO_ERROR; 248 } 249 250 VP_STATUS NTAPI 251 IntInt10WriteMemory( 252 IN PVOID Context, 253 IN USHORT Seg, 254 IN USHORT Off, 255 IN PVOID Buffer, 256 IN ULONG Length) 257 { 258 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 259 KAPC_STATE ApcState; 260 261 TRACE_(VIDEOPRT, "IntInt10WriteMemory\n"); 262 INFO_(VIDEOPRT, "- Segment: %x\n", Seg); 263 INFO_(VIDEOPRT, "- Offset: %x\n", Off); 264 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer); 265 INFO_(VIDEOPRT, "- Length: %x\n", Length); 266 267 IntAttachToCSRSS(&CallingProcess, &ApcState); 268 RtlCopyMemory((PVOID)((Seg << 4) | Off), Buffer, Length); 269 IntDetachFromCSRSS(&CallingProcess, &ApcState); 270 271 return NO_ERROR; 272 } 273 274 VP_STATUS 275 NTAPI 276 IntInt10CallBios( 277 IN PVOID Context, 278 IN OUT PINT10_BIOS_ARGUMENTS BiosArguments) 279 { 280 CONTEXT BiosContext; 281 NTSTATUS Status; 282 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 283 KAPC_STATE ApcState; 284 285 /* Attach to CSRSS */ 286 IntAttachToCSRSS(&CallingProcess, &ApcState); 287 288 /* Clear the context */ 289 RtlZeroMemory(&BiosContext, sizeof(CONTEXT)); 290 291 /* Fill out the bios arguments */ 292 BiosContext.Eax = BiosArguments->Eax; 293 BiosContext.Ebx = BiosArguments->Ebx; 294 BiosContext.Ecx = BiosArguments->Ecx; 295 BiosContext.Edx = BiosArguments->Edx; 296 BiosContext.Esi = BiosArguments->Esi; 297 BiosContext.Edi = BiosArguments->Edi; 298 BiosContext.Ebp = BiosArguments->Ebp; 299 BiosContext.SegDs = BiosArguments->SegDs; 300 BiosContext.SegEs = BiosArguments->SegEs; 301 302 /* Do the ROM BIOS call */ 303 (void)KeWaitForMutexObject(&VideoPortInt10Mutex, Executive, KernelMode, FALSE, NULL); 304 Status = Ke386CallBios(0x10, &BiosContext); 305 KeReleaseMutex(&VideoPortInt10Mutex, FALSE); 306 307 /* Return the arguments */ 308 BiosArguments->Eax = BiosContext.Eax; 309 BiosArguments->Ebx = BiosContext.Ebx; 310 BiosArguments->Ecx = BiosContext.Ecx; 311 BiosArguments->Edx = BiosContext.Edx; 312 BiosArguments->Esi = BiosContext.Esi; 313 BiosArguments->Edi = BiosContext.Edi; 314 BiosArguments->Ebp = BiosContext.Ebp; 315 BiosArguments->SegDs = (USHORT)BiosContext.SegDs; 316 BiosArguments->SegEs = (USHORT)BiosContext.SegEs; 317 318 /* Detach and return status */ 319 IntDetachFromCSRSS(&CallingProcess, &ApcState); 320 if (NT_SUCCESS(Status)) return NO_ERROR; 321 return ERROR_INVALID_PARAMETER; 322 } 323 #endif 324 325 /* PUBLIC FUNCTIONS ***********************************************************/ 326 327 /* 328 * @implemented 329 */ 330 331 VP_STATUS NTAPI 332 VideoPortInt10( 333 IN PVOID HwDeviceExtension, 334 IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments) 335 { 336 #if defined(_M_IX86) 337 CONTEXT BiosContext; 338 NTSTATUS Status; 339 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess(); 340 KAPC_STATE ApcState; 341 342 if (!CsrssInitialized) 343 { 344 return ERROR_INVALID_PARAMETER; 345 } 346 347 /* Attach to CSRSS */ 348 IntAttachToCSRSS(&CallingProcess, &ApcState); 349 350 /* Clear the context */ 351 RtlZeroMemory(&BiosContext, sizeof(CONTEXT)); 352 353 /* Fill out the bios arguments */ 354 BiosContext.Eax = BiosArguments->Eax; 355 BiosContext.Ebx = BiosArguments->Ebx; 356 BiosContext.Ecx = BiosArguments->Ecx; 357 BiosContext.Edx = BiosArguments->Edx; 358 BiosContext.Esi = BiosArguments->Esi; 359 BiosContext.Edi = BiosArguments->Edi; 360 BiosContext.Ebp = BiosArguments->Ebp; 361 362 /* Do the ROM BIOS call */ 363 (void)KeWaitForMutexObject(&VideoPortInt10Mutex, Executive, KernelMode, FALSE, NULL); 364 Status = Ke386CallBios(0x10, &BiosContext); 365 KeReleaseMutex(&VideoPortInt10Mutex, FALSE); 366 367 /* Return the arguments */ 368 BiosArguments->Eax = BiosContext.Eax; 369 BiosArguments->Ebx = BiosContext.Ebx; 370 BiosArguments->Ecx = BiosContext.Ecx; 371 BiosArguments->Edx = BiosContext.Edx; 372 BiosArguments->Esi = BiosContext.Esi; 373 BiosArguments->Edi = BiosContext.Edi; 374 BiosArguments->Ebp = BiosContext.Ebp; 375 376 /* Detach from CSRSS */ 377 IntDetachFromCSRSS(&CallingProcess, &ApcState); 378 if (NT_SUCCESS(Status)) return NO_ERROR; 379 return ERROR_INVALID_PARAMETER; 380 #else 381 /* Not implemented for anything else than X86*/ 382 DPRINT1("Int10 not available on non-x86!\n"); 383 return ERROR_INVALID_FUNCTION; 384 #endif 385 } 386