[HAL]: Move all HAL-specific names to halacpi.c and halpcat.c. This includes the...
[reactos.git] / reactos / hal / halx86 / generic / usage.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/usage.c
5 * PURPOSE: HAL Resource Report Routines
6 * PROGRAMMERS: Stefan Ginsberg (stefan.ginsberg@reactos.org)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 BOOLEAN HalpGetInfoFromACPI;
18 BOOLEAN HalpNMIDumpFlag;
19 PUCHAR KdComPortInUse;
20 PADDRESS_USAGE HalpAddressUsageList;
21 IDTUsageFlags HalpIDTUsageFlags[MAXIMUM_IDTVECTOR];
22 IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR];
23
24 USHORT HalpComPortIrqMapping[5][2] =
25 {
26 {0x3F8, 4},
27 {0x2F8, 3},
28 {0x3E8, 4},
29 {0x2E8, 3},
30 {0, 0}
31 };
32
33 ADDRESS_USAGE HalpComIoSpace =
34 {
35 NULL, CmResourceTypePort, IDT_INTERNAL,
36 {
37 {0x2F8, 0x8}, /* COM 1 */
38 {0,0},
39 }
40 };
41
42 ADDRESS_USAGE HalpDefaultIoSpace =
43 {
44 NULL, CmResourceTypePort, IDT_INTERNAL,
45 {
46 {0x2000, 0xC000}, /* Everything */
47 {0xC000, 0x1000}, /* DMA 2 */
48 {0x8000, 0x1000}, /* DMA 1 */
49 {0x2000, 0x200}, /* PIC 1 */
50 {0xA000, 0x200}, /* PIC 2 */
51 {0x4000, 0x400}, /* PIT 1 */
52 {0x4800, 0x400}, /* PIT 2 */
53 {0x9200, 0x100}, /* System Control Port A */
54 {0x7000, 0x200}, /* CMOS */
55 {0xF000, 0x1000}, /* x87 Coprocessor */
56 {0xCF800, 0x800}, /* PCI 0 */
57 {0,0},
58 }
59 };
60
61 /* FUNCTIONS ******************************************************************/
62
63 VOID
64 NTAPI
65 HalpGetResourceSortValue(IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
66 OUT PULONG Scale,
67 OUT PLARGE_INTEGER Value)
68 {
69 /* Sorting depends on resource type */
70 switch (Descriptor->Type)
71 {
72 case CmResourceTypeInterrupt:
73
74 /* Interrupt goes by level */
75 *Scale = 0;
76 *Value = RtlConvertUlongToLargeInteger(Descriptor->u.Interrupt.Level);
77 break;
78
79 case CmResourceTypePort:
80
81 /* Port goes by port address */
82 *Scale = 1;
83 *Value = Descriptor->u.Port.Start;
84 break;
85
86 case CmResourceTypeMemory:
87
88 /* Memory goes by base address */
89 *Scale = 2;
90 *Value = Descriptor->u.Memory.Start;
91 break;
92
93 default:
94
95 /* Anything else */
96 *Scale = 4;
97 *Value = RtlConvertUlongToLargeInteger(0);
98 break;
99 }
100 }
101
102 VOID
103 NTAPI
104 HalpBuildPartialFromIdt(IN ULONG Entry,
105 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
106 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor)
107 {
108 /* Exclusive interrupt entry */
109 RawDescriptor->Type = CmResourceTypeInterrupt;
110 RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
111
112 /* Check the interrupt type */
113 if (HalpIDTUsageFlags[Entry].Flags & IDT_LATCHED)
114 {
115 /* Latched */
116 RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
117 }
118 else
119 {
120 /* Level */
121 RawDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
122 }
123
124 /* Get vector and level from IDT usage */
125 RawDescriptor->u.Interrupt.Vector = HalpIDTUsage[Entry].BusReleativeVector;
126 RawDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].BusReleativeVector;
127
128 /* Affinity is all the CPUs */
129 RawDescriptor->u.Interrupt.Affinity = HalpActiveProcessors;
130
131 /* The translated copy is identical */
132 RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(TranslatedDescriptor));
133
134 /* But the vector and IRQL must be set correctly */
135 TranslatedDescriptor->u.Interrupt.Vector = Entry;
136 TranslatedDescriptor->u.Interrupt.Level = HalpIDTUsage[Entry].Irql;
137 }
138
139 VOID
140 NTAPI
141 HalpBuildPartialFromAddress(IN INTERFACE_TYPE Interface,
142 IN PADDRESS_USAGE CurrentAddress,
143 IN ULONG Element,
144 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR RawDescriptor,
145 IN PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedDescriptor)
146 {
147 ULONG AddressSpace;
148
149 /* Set the type and make it exclusive */
150 RawDescriptor->Type = CurrentAddress->Type;
151 RawDescriptor->ShareDisposition = CmResourceShareDriverExclusive;
152
153 /* Check what this is */
154 if (RawDescriptor->Type == CmResourceTypePort)
155 {
156 /* Write out port data */
157 AddressSpace = 1;
158 RawDescriptor->Flags = CM_RESOURCE_PORT_IO;
159 RawDescriptor->u.Port.Start.HighPart = 0;
160 RawDescriptor->u.Port.Start.LowPart = CurrentAddress->Element[Element].Start;
161 RawDescriptor->u.Port.Length = CurrentAddress->Element[Element].Length;
162
163 /* Determine if 16-bit port addresses are allowed */
164 RawDescriptor->Flags |= HalpIs16BitPortDecodeSupported();
165 }
166 else
167 {
168 /* Write out memory data */
169 AddressSpace = 0;
170 RawDescriptor->Flags = (CurrentAddress->Flags & IDT_READ_ONLY) ?
171 CM_RESOURCE_MEMORY_READ_ONLY :
172 CM_RESOURCE_MEMORY_READ_WRITE;
173 RawDescriptor->u.Memory.Start.HighPart = 0;
174 RawDescriptor->u.Memory.Start.LowPart = CurrentAddress->Element[Element].Start;
175 RawDescriptor->u.Memory.Length = CurrentAddress->Element[Element].Length;
176 }
177
178 /* Make an identical copy to begin with */
179 RtlCopyMemory(TranslatedDescriptor, RawDescriptor, sizeof(TranslatedDescriptor));
180
181 /* Check what this is */
182 if (RawDescriptor->Type == CmResourceTypePort)
183 {
184 /* Translate the port */
185 HalTranslateBusAddress(Interface,
186 0,
187 RawDescriptor->u.Port.Start,
188 &AddressSpace,
189 &TranslatedDescriptor->u.Port.Start);
190
191 /* If it turns out this is memory once translated, flag it */
192 if (AddressSpace == 0) TranslatedDescriptor->Flags = CM_RESOURCE_PORT_MEMORY;
193
194 }
195 else
196 {
197 /* Translate the memory */
198 HalTranslateBusAddress(Interface,
199 0,
200 RawDescriptor->u.Memory.Start,
201 &AddressSpace,
202 &TranslatedDescriptor->u.Memory.Start);
203 }
204 }
205
206 VOID
207 NTAPI
208 HalpReportResourceUsage(IN PUNICODE_STRING HalName,
209 IN INTERFACE_TYPE InterfaceType)
210 {
211 PCM_RESOURCE_LIST RawList, TranslatedList;
212 PCM_FULL_RESOURCE_DESCRIPTOR RawFull, TranslatedFull;
213 PCM_PARTIAL_RESOURCE_DESCRIPTOR CurrentRaw, CurrentTranslated, SortedRaw, SortedTranslated;
214 CM_PARTIAL_RESOURCE_DESCRIPTOR RawPartial, TranslatedPartial;
215 PCM_PARTIAL_RESOURCE_LIST RawPartialList = NULL, TranslatedPartialList = NULL;
216 INTERFACE_TYPE Interface;
217 ULONG i, j, k, ListSize, Count, Port, Element, CurrentScale, SortScale, ReportType, FlagMatch;
218 ADDRESS_USAGE *CurrentAddress;
219 LARGE_INTEGER CurrentSortValue, SortValue;
220 DbgPrint("%wZ Detected\n", HalName);
221
222 /* Check if KD is using a COM port */
223 if (KdComPortInUse)
224 {
225 /* Enter it into the I/O space */
226 HalpComIoSpace.Element[0].Start = (ULONG_PTR)KdComPortInUse;
227 HalpComIoSpace.Next = HalpAddressUsageList;
228 HalpAddressUsageList = &HalpComIoSpace;
229
230 /* Use the debug port table if we have one */
231 HalpGetInfoFromACPI = HalpGetDebugPortTable();
232
233 /* Check if we're using ACPI */
234 if (!HalpGetInfoFromACPI)
235 {
236 /* No, so use our local table */
237 Port = HalpComPortIrqMapping[0][0];
238 for (i = 0; Port; i++)
239 {
240 /* Is this the port we want? */
241 if (Port == (ULONG_PTR)KdComPortInUse)
242 {
243 /* Register it */
244 HalpRegisterVector(IDT_DEVICE | IDT_LATCHED,
245 HalpComPortIrqMapping[i][1],
246 HalpComPortIrqMapping[i][1] +
247 PRIMARY_VECTOR_BASE,
248 HIGH_LEVEL);
249 }
250
251 /* Next port */
252 Port = HalpComPortIrqMapping[i][0];
253 }
254 }
255 }
256
257 /* On non-ACPI systems, we need to build an address map */
258 HalpBuildAddressMap();
259
260 /* Allocate the master raw and translated lists */
261 RawList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, ' laH');
262 TranslatedList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, ' laH');
263 if (!(RawList) || !(TranslatedList))
264 {
265 /* Bugcheck the system */
266 KeBugCheckEx(HAL_MEMORY_ALLOCATION,
267 4 * PAGE_SIZE,
268 1,
269 (ULONG_PTR)__FILE__,
270 __LINE__);
271 }
272
273 /* Zero out the lists */
274 RtlZeroMemory(RawList, PAGE_SIZE * 2);
275 RtlZeroMemory(TranslatedList, PAGE_SIZE * 2);
276
277 /* Set the interface type to begin with */
278 RawList->List[0].InterfaceType = InterfaceTypeUndefined;
279
280 /* Loop all IDT entries that are not IRQs */
281 for (i = 0; i < PRIMARY_VECTOR_BASE; i++)
282 {
283 /* Check if the IDT isn't owned */
284 if (!(HalpIDTUsageFlags[i].Flags & IDT_REGISTERED))
285 {
286 /* Then register it for internal usage */
287 HalpIDTUsageFlags[i].Flags = IDT_INTERNAL;
288 HalpIDTUsage[i].BusReleativeVector = i;
289 }
290 }
291
292 /* Our full raw descriptors start here */
293 RawFull = RawList->List;
294
295 /* Keep track of the current partial raw and translated descriptors */
296 CurrentRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)RawList->List;
297 CurrentTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)TranslatedList->List;
298
299 /* Do two passes */
300 for (ReportType = 0; ReportType < 2; ReportType++)
301 {
302 /* Pass 0 is for device usage */
303 if (ReportType == 0)
304 {
305 FlagMatch = IDT_DEVICE & ~IDT_REGISTERED;
306 Interface = InterfaceType;
307 }
308 else
309 {
310 /* Past 1 is for internal HAL usage */
311 FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED;
312 Interface = Internal;
313 }
314
315 /* Reset loop variables */
316 i = Element = 0;
317
318 /* Start looping our address uage list and interrupts */
319 CurrentAddress = HalpAddressUsageList;
320 while (TRUE)
321 {
322 /* Check for valid vector number */
323 if (i <= MAXIMUM_IDTVECTOR)
324 {
325 /* Check if this entry should be parsed */
326 if ((HalpIDTUsageFlags[i].Flags & FlagMatch))
327 {
328 /* Parse it */
329 HalpBuildPartialFromIdt(i, &RawPartial, &TranslatedPartial);
330 i++;
331 }
332 else
333 {
334 /* Skip this entry */
335 i++;
336 continue;
337 }
338 }
339 else
340 {
341 /* This is an address instead */
342 if (!CurrentAddress) break;
343
344 /* Check if the address should be reported */
345 if (!(CurrentAddress->Flags & FlagMatch) ||
346 !(CurrentAddress->Element[Element].Length))
347 {
348 /* Nope, skip it */
349 Element = 0;
350 CurrentAddress = CurrentAddress->Next;
351 continue;
352 }
353
354 /* Otherwise, parse the entry */
355 HalpBuildPartialFromAddress(Interface,
356 CurrentAddress,
357 Element,
358 &RawPartial,
359 &TranslatedPartial);
360 Element++;
361 }
362
363 /* Check for interface change */
364 if (RawFull->InterfaceType != Interface)
365 {
366 /* We need to add another full descriptor */
367 RawList->Count++;
368 TranslatedList->Count++;
369
370 /* The full descriptor follows wherever we were */
371 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
372 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
373
374 /* And it is of this new interface type */
375 RawFull->InterfaceType = Interface;
376 TranslatedFull->InterfaceType = Interface;
377
378 /* And its partial descriptors begin here */
379 RawPartialList = &RawFull->PartialResourceList;
380 TranslatedPartialList = &TranslatedFull->PartialResourceList;
381
382 /* And our next full descriptor should follow here */
383 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
384 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
385 }
386
387 /* We have written a new partial descriptor */
388 RawPartialList->Count++;
389 TranslatedPartialList->Count++;
390
391 /* Copy our local descriptors into the actual list */
392 RtlCopyMemory(CurrentRaw, &RawPartial, sizeof(RawPartial));
393 RtlCopyMemory(CurrentTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
394
395 /* Move to the next partial descriptor */
396 CurrentRaw++;
397 CurrentTranslated++;
398 }
399 }
400
401 /* Get the final list of the size for the kernel call later */
402 ListSize = (ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList;
403
404 /* Now reset back to the first full descriptor */
405 RawFull = RawList->List;
406 TranslatedFull = TranslatedList->List;
407
408 /* And loop all the full descriptors */
409 for (i = 0; i < RawList->Count; i++)
410 {
411 /* Get the first partial descriptor in this list */
412 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
413 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
414
415 /* Get the count of partials in this list */
416 Count = RawFull->PartialResourceList.Count;
417
418 /* Loop all the partials in this list */
419 for (j = 0; j < Count; j++)
420 {
421 /* Get the sort value at this point */
422 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
423
424 /* Save the current sort pointer */
425 SortedRaw = CurrentRaw;
426 SortedTranslated = CurrentTranslated;
427
428 /* Loop all descriptors starting from this one */
429 for (k = j; k < Count; k++)
430 {
431 /* Get the sort value at the sort point */
432 HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue);
433
434 /* Check if a swap needs to occur */
435 if ((SortScale < CurrentScale) ||
436 ((SortScale == CurrentScale) &&
437 (SortValue.QuadPart <= CurrentSortValue.QuadPart)))
438 {
439 /* Swap raw partial with the sort location partial */
440 RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial));
441 RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial));
442 RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial));
443
444 /* Swap translated partial in the same way */
445 RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial));
446 RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial));
447 RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
448
449 /* Update the sort value at this point */
450 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
451 }
452
453 /* The sort location has been updated */
454 SortedRaw++;
455 SortedTranslated++;
456 }
457
458 /* Move to the next partial */
459 CurrentRaw++;
460 CurrentTranslated++;
461 }
462
463 /* Move to the next full descriptor */
464 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
465 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
466 }
467
468 /* Mark this is an ACPI system, if it is */
469 HalpMarkAcpiHal();
470
471 /* Tell the kernel about all this */
472 IoReportHalResourceUsage(HalName,
473 RawList,
474 TranslatedList,
475 ListSize);
476
477 /* Free our lists */
478 ExFreePool(RawList);
479 ExFreePool(TranslatedList);
480
481 /* Get the machine's serial number */
482 HalpReportSerialNumber();
483 }
484
485 VOID
486 NTAPI
487 HalpRegisterVector(IN UCHAR Flags,
488 IN ULONG BusVector,
489 IN ULONG SystemVector,
490 IN KIRQL Irql)
491 {
492 /* Save the vector flags */
493 HalpIDTUsageFlags[SystemVector].Flags = Flags;
494
495 /* Save the vector data */
496 HalpIDTUsage[SystemVector].Irql = Irql;
497 HalpIDTUsage[SystemVector].BusReleativeVector = BusVector;
498 }
499
500 #ifndef _MINIHAL_
501 VOID
502 NTAPI
503 HalpEnableInterruptHandler(IN UCHAR Flags,
504 IN ULONG BusVector,
505 IN ULONG SystemVector,
506 IN KIRQL Irql,
507 IN PVOID Handler,
508 IN KINTERRUPT_MODE Mode)
509 {
510 UCHAR Entry;
511
512 /* Convert the vector into the IDT entry */
513 Entry = HalVectorToIDTEntry(SystemVector);
514
515 /* Register the vector */
516 HalpRegisterVector(Flags, BusVector, SystemVector, Irql);
517
518 /* Connect the interrupt */
519 ((PKIPCR)KeGetPcr())->IDT[Entry].ExtendedOffset = (USHORT)(((ULONG_PTR)Handler >> 16) & 0xFFFF);
520 ((PKIPCR)KeGetPcr())->IDT[Entry].Offset = (USHORT)((ULONG_PTR)Handler);
521
522 /* Enable the interrupt */
523 HalEnableSystemInterrupt(SystemVector, Irql, Mode);
524 }
525
526 VOID
527 NTAPI
528 HalpGetNMICrashFlag(VOID)
529 {
530 UNICODE_STRING ValueName;
531 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
532 OBJECT_ATTRIBUTES ObjectAttributes;
533 ULONG ResultLength;
534 HANDLE Handle;
535 NTSTATUS Status;
536 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
537
538 /* Set default */
539 HalpNMIDumpFlag = 0;
540
541 /* Initialize attributes */
542 InitializeObjectAttributes(&ObjectAttributes,
543 &KeyName,
544 OBJ_CASE_INSENSITIVE,
545 NULL,
546 NULL);
547
548 /* Open crash key */
549 Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes);
550 if (NT_SUCCESS(Status))
551 {
552 /* Query key value */
553 RtlInitUnicodeString(&ValueName, L"NMICrashDump");
554 Status = ZwQueryValueKey(Handle,
555 &ValueName,
556 KeyValuePartialInformation,
557 &KeyValueInformation,
558 sizeof(KeyValueInformation),
559 &ResultLength);
560 if (NT_SUCCESS(Status))
561 {
562 /* Check for valid data */
563 if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION))
564 {
565 /* Read the flag */
566 HalpNMIDumpFlag = KeyValueInformation.Data[0];
567 }
568 }
569
570 /* We're done */
571 ZwClose(Handle);
572 }
573 }
574 #endif
575
576 /* EOF */
577