[WIN32SS] WindowSnap must not affect the taskbar
[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 #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 }