b8eebfa49e82a20f71e4b4c3992b03f19174de0f
[reactos.git] / win32ss / drivers / videoprt / int10.c
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 }