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