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