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