Sync with trunk revision 64099.
[reactos.git] / hal / halx86 / amd64 / x86bios.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL, See COPYING in the top level directory
4 * FILE: hal/halx86/generic/amd64/x86bios.c
5 * PURPOSE:
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <hal.h>
12 //#define NDEBUG
13 #include <debug.h>
14
15 //#include "x86emu.h"
16
17 /* This page serves as fallback for pages used by Mm */
18 #define DEFAULT_PAGE 0x21
19
20 /* GLOBALS *******************************************************************/
21
22 BOOLEAN x86BiosIsInitialized;
23 LONG x86BiosBufferIsAllocated = 0;
24 PUCHAR x86BiosMemoryMapping;
25
26
27 VOID
28 NTAPI
29 DbgDumpPage(PUCHAR MemBuffer, USHORT Segment)
30 {
31 ULONG x, y, Offset;
32
33 for (y = 0; y < 0x100; y++)
34 {
35 for (x = 0; x < 0x10; x++)
36 {
37 Offset = Segment * 16 + y * 16 + x;
38 DbgPrint("%02x ", MemBuffer[Offset]);
39 }
40 DbgPrint("\n");
41 }
42 }
43
44 VOID
45 NTAPI
46 HalInitializeBios(ULONG Unknown, PLOADER_PARAMETER_BLOCK LoaderBlock)
47 {
48 PPFN_NUMBER PfnArray;
49 PFN_NUMBER Pfn, Last;
50 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
51 PLIST_ENTRY ListEntry;
52 PMDL Mdl;
53
54 /* Allocate an MDL for 1MB */
55 Mdl = IoAllocateMdl(NULL, 0x100000, FALSE, FALSE, NULL);
56 if (!Mdl)
57 {
58 ASSERT(FALSE);
59 }
60
61 /* Get pointer to the pfn array */
62 PfnArray = MmGetMdlPfnArray(Mdl);
63
64 /* Fill the array with low memory PFNs */
65 for (Pfn = 0; Pfn < 0x100; Pfn++)
66 {
67 PfnArray[Pfn] = Pfn;
68 }
69
70 /* Loop the memory descriptors */
71 for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
72 ListEntry != &LoaderBlock->MemoryDescriptorListHead;
73 ListEntry = ListEntry->Flink)
74 {
75 /* Get the memory descriptor */
76 Descriptor = CONTAINING_RECORD(ListEntry,
77 MEMORY_ALLOCATION_DESCRIPTOR,
78 ListEntry);
79
80 /* Check if the memory is in the low range */
81 if (Descriptor->BasePage < 0x100)
82 {
83 /* Check if the memory type is firmware */
84 if (Descriptor->MemoryType != LoaderFirmwarePermanent &&
85 Descriptor->MemoryType != LoaderSpecialMemory)
86 {
87 /* It's something else, so don't use it! */
88 Last = min(Descriptor->BasePage + Descriptor->PageCount, 0x100);
89 for (Pfn = Descriptor->BasePage; Pfn < Last; Pfn++)
90 {
91 /* Set each page to the default page */
92 PfnArray[Pfn] = DEFAULT_PAGE;
93 }
94 }
95 }
96 }
97
98 Mdl->MdlFlags = MDL_PAGES_LOCKED;
99
100 /* Map the MDL to system space */
101 x86BiosMemoryMapping = MmGetSystemAddressForMdlSafe(Mdl, HighPagePriority);
102 ASSERT(x86BiosMemoryMapping);
103
104 DPRINT1("memory: %p, %p\n", *(PVOID*)x86BiosMemoryMapping, *(PVOID*)(x86BiosMemoryMapping + 8));
105 //DbgDumpPage(x86BiosMemoryMapping, 0xc351);
106
107 x86BiosIsInitialized = TRUE;
108
109 HalpBiosDisplayReset();
110 }
111
112 NTSTATUS
113 NTAPI
114 x86BiosAllocateBuffer(
115 ULONG *Size,
116 USHORT *Segment,
117 USHORT *Offset)
118 {
119 /* Check if the system is initialized and the buffer is large enough */
120 if (!x86BiosIsInitialized || *Size > PAGE_SIZE)
121 {
122 /* Something was wrong, fail! */
123 return STATUS_INSUFFICIENT_RESOURCES;
124 }
125
126 /* Check if the buffer is already allocated */
127 if (InterlockedBitTestAndSet(&x86BiosBufferIsAllocated, 0))
128 {
129 /* Buffer was already allocated, fail */
130 return STATUS_INSUFFICIENT_RESOURCES;
131 }
132
133 /* The buffer is sufficient, return hardcoded address and size */
134 *Size = PAGE_SIZE;
135 *Segment = 0x2000;
136 *Offset = 0;
137
138 return STATUS_SUCCESS;;
139 }
140
141 NTSTATUS
142 NTAPI
143 x86BiosFreeBuffer(
144 USHORT Segment,
145 USHORT Offset)
146 {
147 /* Check if the system is initialized and if the address matches */
148 if (!x86BiosIsInitialized || Segment != 0x2000 || Offset != 0)
149 {
150 /* Something was wrong, fail */
151 return STATUS_INVALID_PARAMETER;
152 }
153
154 /* Check if the buffer was allocated */
155 if (!InterlockedBitTestAndReset(&x86BiosBufferIsAllocated, 0))
156 {
157 /* It was not, fail */
158 return STATUS_INVALID_PARAMETER;
159 }
160
161 /* Buffer is freed, nothing more to do */
162 return STATUS_SUCCESS;;
163 }
164
165 NTSTATUS
166 NTAPI
167 x86BiosReadMemory(
168 USHORT Segment,
169 USHORT Offset,
170 PVOID Buffer,
171 ULONG Size)
172 {
173 ULONG_PTR Address;
174
175 /* Calculate the physical address */
176 Address = (Segment << 4) + Offset;
177
178 /* Check if it's valid */
179 if (!x86BiosIsInitialized || Address + Size > 0x100000)
180 {
181 /* Invalid */
182 return STATUS_INVALID_PARAMETER;
183 }
184
185 /* Copy the memory to the buffer */
186 RtlCopyMemory(Buffer, x86BiosMemoryMapping + Address, Size);
187
188 /* Return success */
189 return STATUS_SUCCESS;
190 }
191
192 NTSTATUS
193 NTAPI
194 x86BiosWriteMemory(
195 USHORT Segment,
196 USHORT Offset,
197 PVOID Buffer,
198 ULONG Size)
199 {
200 ULONG_PTR Address;
201
202 /* Calculate the physical address */
203 Address = (Segment << 4) + Offset;
204
205 /* Check if it's valid */
206 if (!x86BiosIsInitialized || Address + Size > 0x100000)
207 {
208 /* Invalid */
209 return STATUS_INVALID_PARAMETER;
210 }
211
212 /* Copy the memory from the buffer */
213 RtlCopyMemory(x86BiosMemoryMapping + Address, Buffer, Size);
214
215 /* Return success */
216 return STATUS_SUCCESS;
217 }
218
219 #if 0
220 BOOLEAN
221 NTAPI
222 x86BiosCall(
223 ULONG InterruptNumber,
224 X86_BIOS_REGISTERS *Registers)
225 {
226 X86_VM_STATE VmState;
227 struct
228 {
229 USHORT Ip;
230 USHORT SegCs;
231 } *InterrupTable;
232
233 /* Zero the VmState */
234 RtlZeroMemory(&VmState, sizeof(VmState));
235
236 /* Copy the registers */
237 VmState.BiosRegisters = *Registers;
238
239 /* Set the physical memory buffer */
240 VmState.MemBuffer = x86BiosMemoryMapping;
241
242 /* Set Eflags */
243 VmState.Registers.Eflags.Long = 0; // FIXME
244
245 /* Setup stack */
246 VmState.Registers.SegSs = 0; // FIXME
247 VmState.Registers.Sp = 0x2000 - 2; // FIXME
248
249 /* Initialize IP from the interrupt vector table */
250 InterrupTable = (PVOID)x86BiosMemoryMapping;
251 VmState.Registers.SegCs = InterrupTable[InterruptNumber].SegCs;
252 VmState.Registers.Eip = InterrupTable[InterruptNumber].Ip;
253
254 /* Make the function return on IRET */
255 VmState.Flags.ReturnOnIret = 1;
256
257 /* Call the x86 emulator */
258 x86Emulator(&VmState);
259
260 /* Copy registers back to caller */
261 *Registers = VmState.BiosRegisters;
262
263 return TRUE;
264 }
265 #endif
266
267 BOOLEAN
268 NTAPI
269 HalpBiosDisplayReset(VOID)
270 {
271 #if 0
272 X86_BIOS_REGISTERS Registers;
273 ULONG OldEflags;
274
275 /* Save flags and disable interrupts */
276 OldEflags = __readeflags();
277 _disable();
278
279 /* Set AH = 0 (Set video mode), AL = 0x12 (640x480x16 vga) */
280 Registers.Eax = 0x12;
281
282 /* Call INT 0x10 */
283 x86BiosCall(0x10, &Registers);
284
285 // FIXME: check result
286
287 /* Restore previous flags */
288 __writeeflags(OldEflags);
289 #endif
290 return TRUE;
291 }
292