[HAL]
[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 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 Port = HalpComPortIrqMapping[0][0];
239 for (i = 0; Port; i++)
240 {
241 /* Is this the port we want? */
242 if (Port == (ULONG_PTR)KdComPortInUse)
243 {
244 /* Register it */
245 HalpRegisterVector(IDT_DEVICE | IDT_LATCHED,
246 HalpComPortIrqMapping[i][1],
247 HalpComPortIrqMapping[i][1] +
248 PRIMARY_VECTOR_BASE,
249 HIGH_LEVEL);
250 }
251
252 /* Next port */
253 Port = HalpComPortIrqMapping[i][0];
254 }
255 }
256 }
257
258 /* On non-ACPI systems, we need to build an address map */
259 HalpBuildAddressMap();
260
261 /* Allocate the master raw and translated lists */
262 RawList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, ' laH');
263 TranslatedList = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE * 2, ' laH');
264 if (!(RawList) || !(TranslatedList))
265 {
266 /* Bugcheck the system */
267 KeBugCheckEx(HAL_MEMORY_ALLOCATION,
268 4 * PAGE_SIZE,
269 1,
270 (ULONG_PTR)__FILE__,
271 __LINE__);
272 }
273
274 /* Zero out the lists */
275 RtlZeroMemory(RawList, PAGE_SIZE * 2);
276 RtlZeroMemory(TranslatedList, PAGE_SIZE * 2);
277
278 /* Set the interface type to begin with */
279 RawList->List[0].InterfaceType = InterfaceTypeUndefined;
280
281 /* Loop all IDT entries that are not IRQs */
282 for (i = 0; i < PRIMARY_VECTOR_BASE; i++)
283 {
284 /* Check if the IDT isn't owned */
285 if (!(HalpIDTUsageFlags[i].Flags & IDT_REGISTERED))
286 {
287 /* Then register it for internal usage */
288 HalpIDTUsageFlags[i].Flags = IDT_INTERNAL;
289 HalpIDTUsage[i].BusReleativeVector = i;
290 }
291 }
292
293 /* Our full raw descriptors start here */
294 RawFull = RawList->List;
295
296 /* Keep track of the current partial raw and translated descriptors */
297 CurrentRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)RawList->List;
298 CurrentTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)TranslatedList->List;
299
300 /* Do two passes */
301 for (ReportType = 0; ReportType < 2; ReportType++)
302 {
303 /* Pass 0 is for device usage */
304 if (ReportType == 0)
305 {
306 FlagMatch = IDT_DEVICE & ~IDT_REGISTERED;
307 Interface = InterfaceType;
308 }
309 else
310 {
311 /* Past 1 is for internal HAL usage */
312 FlagMatch = IDT_INTERNAL & ~IDT_REGISTERED;
313 Interface = Internal;
314 }
315
316 /* Reset loop variables */
317 i = Element = 0;
318
319 /* Start looping our address uage list and interrupts */
320 CurrentAddress = HalpAddressUsageList;
321 while (TRUE)
322 {
323 /* Check for valid vector number */
324 if (i <= MAXIMUM_IDTVECTOR)
325 {
326 /* Check if this entry should be parsed */
327 if ((HalpIDTUsageFlags[i].Flags & FlagMatch))
328 {
329 /* Parse it */
330 HalpBuildPartialFromIdt(i, &RawPartial, &TranslatedPartial);
331 i++;
332 }
333 else
334 {
335 /* Skip this entry */
336 i++;
337 continue;
338 }
339 }
340 else
341 {
342 /* This is an address instead */
343 if (!CurrentAddress) break;
344
345 /* Check if the address should be reported */
346 if (!(CurrentAddress->Flags & FlagMatch) ||
347 !(CurrentAddress->Element[Element].Length))
348 {
349 /* Nope, skip it */
350 Element = 0;
351 CurrentAddress = CurrentAddress->Next;
352 continue;
353 }
354
355 /* Otherwise, parse the entry */
356 HalpBuildPartialFromAddress(Interface,
357 CurrentAddress,
358 Element,
359 &RawPartial,
360 &TranslatedPartial);
361 Element++;
362 }
363
364 /* Check for interface change */
365 if (RawFull->InterfaceType != Interface)
366 {
367 /* We need to add another full descriptor */
368 RawList->Count++;
369 TranslatedList->Count++;
370
371 /* The full descriptor follows wherever we were */
372 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
373 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
374
375 /* And it is of this new interface type */
376 RawFull->InterfaceType = Interface;
377 TranslatedFull->InterfaceType = Interface;
378
379 /* And its partial descriptors begin here */
380 RawPartialList = &RawFull->PartialResourceList;
381 TranslatedPartialList = &TranslatedFull->PartialResourceList;
382
383 /* And our next full descriptor should follow here */
384 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
385 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
386 }
387
388 /* We have written a new partial descriptor */
389 RawPartialList->Count++;
390 TranslatedPartialList->Count++;
391
392 /* Copy our local descriptors into the actual list */
393 RtlCopyMemory(CurrentRaw, &RawPartial, sizeof(RawPartial));
394 RtlCopyMemory(CurrentTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
395
396 /* Move to the next partial descriptor */
397 CurrentRaw++;
398 CurrentTranslated++;
399 }
400 }
401
402 /* Get the final list of the size for the kernel call later */
403 ListSize = (ULONG_PTR)CurrentRaw - (ULONG_PTR)RawList;
404
405 /* Now reset back to the first full descriptor */
406 RawFull = RawList->List;
407 TranslatedFull = TranslatedList->List;
408
409 /* And loop all the full descriptors */
410 for (i = 0; i < RawList->Count; i++)
411 {
412 /* Get the first partial descriptor in this list */
413 CurrentRaw = RawFull->PartialResourceList.PartialDescriptors;
414 CurrentTranslated = TranslatedFull->PartialResourceList.PartialDescriptors;
415
416 /* Get the count of partials in this list */
417 Count = RawFull->PartialResourceList.Count;
418
419 /* Loop all the partials in this list */
420 for (j = 0; j < Count; j++)
421 {
422 /* Get the sort value at this point */
423 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
424
425 /* Save the current sort pointer */
426 SortedRaw = CurrentRaw;
427 SortedTranslated = CurrentTranslated;
428
429 /* Loop all descriptors starting from this one */
430 for (k = j; k < Count; k++)
431 {
432 /* Get the sort value at the sort point */
433 HalpGetResourceSortValue(SortedRaw, &SortScale, &SortValue);
434
435 /* Check if a swap needs to occur */
436 if ((SortScale < CurrentScale) ||
437 ((SortScale == CurrentScale) &&
438 (SortValue.QuadPart <= CurrentSortValue.QuadPart)))
439 {
440 /* Swap raw partial with the sort location partial */
441 RtlCopyMemory(&RawPartial, CurrentRaw, sizeof(RawPartial));
442 RtlCopyMemory(CurrentRaw, SortedRaw, sizeof(RawPartial));
443 RtlCopyMemory(SortedRaw, &RawPartial, sizeof(RawPartial));
444
445 /* Swap translated partial in the same way */
446 RtlCopyMemory(&TranslatedPartial, CurrentTranslated, sizeof(TranslatedPartial));
447 RtlCopyMemory(CurrentTranslated, SortedTranslated, sizeof(TranslatedPartial));
448 RtlCopyMemory(SortedTranslated, &TranslatedPartial, sizeof(TranslatedPartial));
449
450 /* Update the sort value at this point */
451 HalpGetResourceSortValue(CurrentRaw, &CurrentScale, &CurrentSortValue);
452 }
453
454 /* The sort location has been updated */
455 SortedRaw++;
456 SortedTranslated++;
457 }
458
459 /* Move to the next partial */
460 CurrentRaw++;
461 CurrentTranslated++;
462 }
463
464 /* Move to the next full descriptor */
465 RawFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentRaw;
466 TranslatedFull = (PCM_FULL_RESOURCE_DESCRIPTOR)CurrentTranslated;
467 }
468
469 /* Mark this is an ACPI system, if it is */
470 HalpMarkAcpiHal();
471
472 /* Tell the kernel about all this */
473 IoReportHalResourceUsage(HalName,
474 RawList,
475 TranslatedList,
476 ListSize);
477
478 /* Free our lists */
479 ExFreePool(RawList);
480 ExFreePool(TranslatedList);
481
482 /* Get the machine's serial number */
483 HalpReportSerialNumber();
484 }
485 #endif
486
487 VOID
488 NTAPI
489 HalpRegisterVector(IN UCHAR Flags,
490 IN ULONG BusVector,
491 IN ULONG SystemVector,
492 IN KIRQL Irql)
493 {
494 /* Save the vector flags */
495 HalpIDTUsageFlags[SystemVector].Flags = Flags;
496
497 /* Save the vector data */
498 HalpIDTUsage[SystemVector].Irql = Irql;
499 HalpIDTUsage[SystemVector].BusReleativeVector = BusVector;
500 }
501
502 #ifndef _MINIHAL_
503 VOID
504 NTAPI
505 HalpEnableInterruptHandler(IN UCHAR Flags,
506 IN ULONG BusVector,
507 IN ULONG SystemVector,
508 IN KIRQL Irql,
509 IN PVOID Handler,
510 IN KINTERRUPT_MODE Mode)
511 {
512 /* Register the vector */
513 HalpRegisterVector(Flags, BusVector, SystemVector, Irql);
514
515 /* Connect the interrupt */
516 KeRegisterInterruptHandler(SystemVector, Handler);
517
518 /* Enable the interrupt */
519 HalEnableSystemInterrupt(SystemVector, Irql, Mode);
520 }
521
522 VOID
523 NTAPI
524 HalpGetNMICrashFlag(VOID)
525 {
526 UNICODE_STRING ValueName;
527 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl");
528 OBJECT_ATTRIBUTES ObjectAttributes;
529 ULONG ResultLength;
530 HANDLE Handle;
531 NTSTATUS Status;
532 KEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
533
534 /* Set default */
535 HalpNMIDumpFlag = 0;
536
537 /* Initialize attributes */
538 InitializeObjectAttributes(&ObjectAttributes,
539 &KeyName,
540 OBJ_CASE_INSENSITIVE,
541 NULL,
542 NULL);
543
544 /* Open crash key */
545 Status = ZwOpenKey(&Handle, KEY_READ, &ObjectAttributes);
546 if (NT_SUCCESS(Status))
547 {
548 /* Query key value */
549 RtlInitUnicodeString(&ValueName, L"NMICrashDump");
550 Status = ZwQueryValueKey(Handle,
551 &ValueName,
552 KeyValuePartialInformation,
553 &KeyValueInformation,
554 sizeof(KeyValueInformation),
555 &ResultLength);
556 if (NT_SUCCESS(Status))
557 {
558 /* Check for valid data */
559 if (ResultLength == sizeof(KEY_VALUE_PARTIAL_INFORMATION))
560 {
561 /* Read the flag */
562 HalpNMIDumpFlag = KeyValueInformation.Data[0];
563 }
564 }
565
566 /* We're done */
567 ZwClose(Handle);
568 }
569 }
570 #endif
571
572 /* EOF */
573