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
ProtectLowV86Mem(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
UnprotectLowV86Mem(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
IntInitializeVideoAddressSpace(VOID)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
IntInitializeVideoAddressSpace(VOID)200 IntInitializeVideoAddressSpace(VOID)
201 {
202 UNIMPLEMENTED;
203 NT_ASSERT(FALSE);
204 return STATUS_NOT_IMPLEMENTED;
205 }
206 #endif
207
208 VP_STATUS
209 NTAPI
IntInt10AllocateBuffer(IN PVOID Context,OUT PUSHORT Seg,OUT PUSHORT Off,IN OUT PULONG Length)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
IntInt10FreeBuffer(IN PVOID Context,IN USHORT Seg,IN USHORT Off)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
IntInt10ReadMemory(IN PVOID Context,IN USHORT Seg,IN USHORT Off,OUT PVOID Buffer,IN ULONG Length)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
IntInt10WriteMemory(IN PVOID Context,IN USHORT Seg,IN USHORT Off,IN PVOID Buffer,IN ULONG Length)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
IntInt10CallBios(IN PVOID Context,IN OUT PINT10_BIOS_ARGUMENTS BiosArguments)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
VideoPortInt10(IN PVOID HwDeviceExtension,IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments)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