xref: /reactos/win32ss/drivers/videoprt/int10.c (revision e46c2dd1)
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