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