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