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