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