8b35709fbdb3a78744bc5a170a73a75992c592a6
[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 VP_STATUS
154 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 SIZE_T Size;
166
167 TRACE_(VIDEOPRT, "IntInt10AllocateBuffer\n");
168
169 IntAttachToCSRSS(&CallingProcess, &ApcState);
170
171 Size = *Length;
172 MemoryAddress = (PVOID)0x20000;
173 Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
174 &MemoryAddress,
175 0,
176 &Size,
177 MEM_COMMIT,
178 PAGE_EXECUTE_READWRITE);
179 if (!NT_SUCCESS(Status))
180 {
181 WARN_(VIDEOPRT, "- ZwAllocateVirtualMemory failed\n");
182 IntDetachFromCSRSS(&CallingProcess, &ApcState);
183 return ERROR_NOT_ENOUGH_MEMORY;
184 }
185
186 if (MemoryAddress > (PVOID)(0x100000 - Size))
187 {
188 ZwFreeVirtualMemory(NtCurrentProcess(),
189 &MemoryAddress,
190 &Size,
191 MEM_RELEASE);
192 WARN_(VIDEOPRT, "- Unacceptable memory allocated\n");
193 IntDetachFromCSRSS(&CallingProcess, &ApcState);
194 return ERROR_NOT_ENOUGH_MEMORY;
195 }
196
197 *Length = (ULONG)Size;
198 *Seg = (USHORT)((ULONG_PTR)MemoryAddress >> 4);
199 *Off = (USHORT)((ULONG_PTR)MemoryAddress & 0xF);
200
201 INFO_(VIDEOPRT, "- Segment: %x\n", (ULONG_PTR)MemoryAddress >> 4);
202 INFO_(VIDEOPRT, "- Offset: %x\n", (ULONG_PTR)MemoryAddress & 0xF);
203 INFO_(VIDEOPRT, "- Length: %x\n", *Length);
204
205 IntDetachFromCSRSS(&CallingProcess, &ApcState);
206
207 return NO_ERROR;
208 }
209
210 VP_STATUS
211 NTAPI
212 IntInt10FreeBuffer(
213 IN PVOID Context,
214 IN USHORT Seg,
215 IN USHORT Off)
216 {
217 PVOID MemoryAddress = (PVOID)((ULONG_PTR)(Seg << 4) | Off);
218 NTSTATUS Status;
219 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
220 KAPC_STATE ApcState;
221 SIZE_T Size = 0;
222
223 TRACE_(VIDEOPRT, "IntInt10FreeBuffer\n");
224 INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
225 INFO_(VIDEOPRT, "- Offset: %x\n", Off);
226
227 IntAttachToCSRSS(&CallingProcess, &ApcState);
228 Status = ZwFreeVirtualMemory(NtCurrentProcess(),
229 &MemoryAddress,
230 &Size,
231 MEM_RELEASE);
232
233 IntDetachFromCSRSS(&CallingProcess, &ApcState);
234
235 return Status;
236 }
237
238 VP_STATUS
239 NTAPI
240 IntInt10ReadMemory(
241 IN PVOID Context,
242 IN USHORT Seg,
243 IN USHORT Off,
244 OUT PVOID Buffer,
245 IN ULONG Length)
246 {
247 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
248 KAPC_STATE ApcState;
249
250 TRACE_(VIDEOPRT, "IntInt10ReadMemory\n");
251 INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
252 INFO_(VIDEOPRT, "- Offset: %x\n", Off);
253 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer);
254 INFO_(VIDEOPRT, "- Length: %x\n", Length);
255
256 IntAttachToCSRSS(&CallingProcess, &ApcState);
257 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)(Seg << 4) | Off), Length);
258 IntDetachFromCSRSS(&CallingProcess, &ApcState);
259
260 return NO_ERROR;
261 }
262
263 VP_STATUS
264 NTAPI
265 IntInt10WriteMemory(
266 IN PVOID Context,
267 IN USHORT Seg,
268 IN USHORT Off,
269 IN PVOID Buffer,
270 IN ULONG Length)
271 {
272 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
273 KAPC_STATE ApcState;
274
275 TRACE_(VIDEOPRT, "IntInt10WriteMemory\n");
276 INFO_(VIDEOPRT, "- Segment: %x\n", Seg);
277 INFO_(VIDEOPRT, "- Offset: %x\n", Off);
278 INFO_(VIDEOPRT, "- Buffer: %x\n", Buffer);
279 INFO_(VIDEOPRT, "- Length: %x\n", Length);
280
281 IntAttachToCSRSS(&CallingProcess, &ApcState);
282 RtlCopyMemory((PVOID)((ULONG_PTR)(Seg << 4) | Off), Buffer, Length);
283 IntDetachFromCSRSS(&CallingProcess, &ApcState);
284
285 return NO_ERROR;
286 }
287
288 #if defined(_M_IX86)
289 VP_STATUS
290 NTAPI
291 IntInt10CallBios(
292 IN PVOID Context,
293 IN OUT PINT10_BIOS_ARGUMENTS BiosArguments)
294 {
295 CONTEXT BiosContext;
296 NTSTATUS Status;
297 PKPROCESS CallingProcess = (PKPROCESS)PsGetCurrentProcess();
298 KAPC_STATE ApcState;
299
300 /* Attach to CSRSS */
301 IntAttachToCSRSS(&CallingProcess, &ApcState);
302
303 /* Clear the context */
304 RtlZeroMemory(&BiosContext, sizeof(BiosContext));
305
306 /* Fill out the bios arguments */
307 BiosContext.Eax = BiosArguments->Eax;
308 BiosContext.Ebx = BiosArguments->Ebx;
309 BiosContext.Ecx = BiosArguments->Ecx;
310 BiosContext.Edx = BiosArguments->Edx;
311 BiosContext.Esi = BiosArguments->Esi;
312 BiosContext.Edi = BiosArguments->Edi;
313 BiosContext.Ebp = BiosArguments->Ebp;
314 BiosContext.SegDs = BiosArguments->SegDs;
315 BiosContext.SegEs = BiosArguments->SegEs;
316
317 /* Do the ROM BIOS call */
318 (void)KeWaitForMutexObject(&VideoPortInt10Mutex,
319 Executive,
320 KernelMode,
321 FALSE,
322 NULL);
323
324 Status = Ke386CallBios(0x10, &BiosContext);
325
326 KeReleaseMutex(&VideoPortInt10Mutex, FALSE);
327
328 /* Return the arguments */
329 BiosArguments->Eax = BiosContext.Eax;
330 BiosArguments->Ebx = BiosContext.Ebx;
331 BiosArguments->Ecx = BiosContext.Ecx;
332 BiosArguments->Edx = BiosContext.Edx;
333 BiosArguments->Esi = BiosContext.Esi;
334 BiosArguments->Edi = BiosContext.Edi;
335 BiosArguments->Ebp = BiosContext.Ebp;
336 BiosArguments->SegDs = (USHORT)BiosContext.SegDs;
337 BiosArguments->SegEs = (USHORT)BiosContext.SegEs;
338
339 /* Detach and return status */
340 IntDetachFromCSRSS(&CallingProcess, &ApcState);
341
342 if (NT_SUCCESS(Status))
343 {
344 return NO_ERROR;
345 }
346
347 return ERROR_INVALID_PARAMETER;
348 }
349 #else
350 VP_STATUS
351 NTAPI
352 IntInt10CallBios(
353 IN PVOID Context,
354 IN OUT PINT10_BIOS_ARGUMENTS BiosArguments)
355 {
356 DPRINT1("Int10 not available on non-x86!\n");
357 return ERROR_INVALID_FUNCTION;
358 }
359 #endif
360
361 /* PUBLIC FUNCTIONS ***********************************************************/
362
363 /*
364 * @implemented
365 */
366 VP_STATUS
367 NTAPI
368 VideoPortInt10(
369 IN PVOID HwDeviceExtension,
370 IN PVIDEO_X86_BIOS_ARGUMENTS BiosArguments)
371 {
372 INT10_BIOS_ARGUMENTS Int10BiosArguments;
373 VP_STATUS Status;
374
375 if (!CsrssInitialized)
376 {
377 return ERROR_INVALID_PARAMETER;
378 }
379
380 /* Copy arguments to other format */
381 RtlCopyMemory(&Int10BiosArguments, BiosArguments, sizeof(BiosArguments));
382 Int10BiosArguments.SegDs = 0;
383 Int10BiosArguments.SegEs = 0;
384
385 /* Do the BIOS call */
386 Status = IntInt10CallBios(NULL, &Int10BiosArguments);
387
388 /* Copy results back */
389 RtlCopyMemory(BiosArguments, &Int10BiosArguments, sizeof(BiosArguments));
390
391 return Status;
392 }