3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: hal/halarm/generic/hal.c
5 * PURPOSE: Hardware Abstraction Layer
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #undef ExAcquireFastMutex
16 #undef ExReleaseFastMutex
17 #undef ExTryToAcquireFastMutex
18 #undef KeAcquireSpinLock
21 #undef KeReleaseSpinLock
23 #define READ_REGISTER_ULONG(r) (*(volatile ULONG * const)(r))
24 #define WRITE_REGISTER_ULONG(r, v) (*(volatile ULONG *)(r) = (v))
26 /* DATA **********************************************************************/
28 ULONG HalpCurrentTimeIncrement
, HalpNextTimeIncrement
, HalpNextIntervalCount
;
29 ULONG _KdComPortInUse
= 0;
31 ULONG HalpIrqlTable
[HIGH_LEVEL
+ 1] =
33 0xFFFFFFFF, // IRQL 0 PASSIVE_LEVEL
34 0xFFFFFFFD, // IRQL 1 APC_LEVEL
35 0xFFFFFFF9, // IRQL 2 DISPATCH_LEVEL
43 0xFFFFE019, // IRQL 10
44 0xFFFFC019, // IRQL 11
45 0xFFFF8019, // IRQL 12
46 0xFFFF0019, // IRQL 13
47 0xFFFE0019, // IRQL 14
48 0xFFFC0019, // IRQL 15
49 0xFFF80019, // IRQL 16
50 0xFFF00019, // IRQL 17
51 0xFFE00019, // IRQL 18
52 0xFFC00019, // IRQL 19
53 0xFF800019, // IRQL 20
54 0xFF000019, // IRQL 21
55 0xFE000019, // IRQL 22
56 0xFC000019, // IRQL 23
57 0xF0000019, // IRQL 24
58 0x80000019, // IRQL 25
60 0x18, // IRQL 27 PROFILE_LEVEL
61 0x10, // IRQL 28 CLOCK2_LEVEL
62 0x00, // IRQL 29 IPI_LEVEL
63 0x00, // IRQL 30 POWER_LEVEL
64 0x00, // IRQL 31 HIGH_LEVEL
67 UCHAR HalpMaskTable
[HIGH_LEVEL
+ 1] =
69 PROFILE_LEVEL
, // INT 0 WATCHDOG
70 APC_LEVEL
, // INT 1 SOFTWARE INTERRUPT
71 DISPATCH_LEVEL
,// INT 2 COMM RX
72 IPI_LEVEL
, // INT 3 COMM TX
73 CLOCK2_LEVEL
, // INT 4 TIMER 0
102 /* FUNCTIONS *****************************************************************/
107 PDRIVER_OBJECT DriverObject
,
108 PUNICODE_STRING RegistryPath
)
112 return STATUS_SUCCESS
;
120 HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource
)
131 HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource
)
142 HalSetProfileInterval(IN ULONG_PTR Interval
)
151 PFAST_MUTEX FastMutex
)
160 PFAST_MUTEX FastMutex
)
167 ExTryToAcquireFastMutex(
168 PFAST_MUTEX FastMutex
)
178 HalAcquireDisplayOwnership(
179 PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
)
187 HalAdjustResourceList(
188 PCM_RESOURCE_LIST Resources
)
192 return STATUS_SUCCESS
;
201 HalAllProcessorsStarted(VOID
)
210 HalAllocateAdapterChannel(
211 PADAPTER_OBJECT AdapterObject
,
212 PWAIT_CONTEXT_BLOCK WaitContextBlock
,
213 ULONG NumberOfMapRegisters
,
214 PDRIVER_CONTROL ExecutionRoutine
)
218 return STATUS_SUCCESS
;
224 HalAllocateCommonBuffer(
225 PADAPTER_OBJECT AdapterObject
,
227 PPHYSICAL_ADDRESS LogicalAddress
,
228 BOOLEAN CacheEnabled
)
238 HalAllocateCrashDumpRegisters(
239 PADAPTER_OBJECT AdapterObject
,
240 PULONG NumberOfMapRegisters
)
249 HalAssignSlotResources(
250 PUNICODE_STRING RegistryPath
,
251 PUNICODE_STRING DriverClassName
,
252 PDRIVER_OBJECT DriverObject
,
253 PDEVICE_OBJECT DeviceObject
,
254 INTERFACE_TYPE BusType
,
257 PCM_RESOURCE_LIST
*AllocatedResources
)
267 HalBeginSystemInterrupt (KIRQL Irql
,
279 HalCalibratePerformanceCounter(
280 volatile LONG
*Count
,
289 HalDisableSystemInterrupt(
310 HalEnableSystemInterrupt(
313 KINTERRUPT_MODE InterruptMode
)
323 HalEndSystemInterrupt(
333 HalFlushCommonBuffer(
349 PADAPTER_OBJECT AdapterObject
,
351 PHYSICAL_ADDRESS LogicalAddress
,
352 PVOID VirtualAddress
,
353 BOOLEAN CacheEnabled
)
362 PDEVICE_DESCRIPTION DeviceDescription
,
363 PULONG NumberOfMapRegisters
)
367 return (PADAPTER_OBJECT
)NULL
;
374 BUS_DATA_TYPE BusDataType
,
388 HalGetBusDataByOffset(
389 BUS_DATA_TYPE BusDataType
,
404 HalGetEnvironmentVariable(
417 HalGetInterruptVector(
418 INTERFACE_TYPE InterfaceType
,
420 ULONG BusInterruptLevel
,
421 ULONG BusInterruptVector
,
441 HalpGetParameters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
445 /* Make sure we have a loader block and command line */
446 if ((LoaderBlock
) && (LoaderBlock
->LoadOptions
))
448 /* Read the command line */
449 CommandLine
= LoaderBlock
->LoadOptions
;
451 /* Check for initial breakpoint */
452 if (strstr(CommandLine
, "BREAK")) DbgBreakPoint();
457 HalGetInterruptSource(VOID
)
459 ULONG InterruptStatus
;
462 // Get the interrupt status, and return the highest bit set
464 InterruptStatus
= READ_REGISTER_ULONG(VIC_INT_STATUS
);
465 return 31 - _clz(InterruptStatus
);
469 HalpClockInterrupt(VOID
)
472 // Clear the interrupt
474 ASSERT(KeGetCurrentIrql() == CLOCK2_LEVEL
);
475 WRITE_REGISTER_ULONG(TIMER0_INT_CLEAR
, 1);
478 // FIXME: Update HAL Perf counters
482 // FIXME: Check if someone changed the clockrate
488 KeUpdateSystemTime(KeGetCurrentThread()->TrapFrame
,
490 HalpCurrentTimeIncrement
);
498 HalpStallInterrupt(VOID
)
501 // Clear the interrupt
503 WRITE_REGISTER_ULONG(TIMER0_INT_CLEAR
, 1);
507 HalpInitializeInterrupts(VOID
)
509 PKPCR Pcr
= (PKPCR
)KeGetPcr();
511 SP804_CONTROL_REGISTER ControlRegister
;
514 // Fill out the IRQL mappings
516 RtlCopyMemory(Pcr
->IrqlTable
, HalpIrqlTable
, sizeof(Pcr
->IrqlTable
));
517 RtlCopyMemory(Pcr
->IrqlMask
, HalpMaskTable
, sizeof(Pcr
->IrqlMask
));
520 // Setup the clock and profile interrupt
522 Pcr
->InterruptRoutine
[CLOCK2_LEVEL
] = HalpStallInterrupt
;
525 // Configure the interval to 10ms
526 // (INTERVAL (10ms) * TIMCLKfreq (1MHz))
527 // --------------------------------------- == 10^4
528 // (TIMCLKENXdiv (1) * PRESCALEdiv (1))
530 ClockInterval
= 0x2710;
533 // Configure the timer
535 ControlRegister
.AsUlong
= 0;
536 ControlRegister
.Wide
= TRUE
;
537 ControlRegister
.Periodic
= TRUE
;
538 ControlRegister
.Interrupt
= TRUE
;
539 ControlRegister
.Enabled
= TRUE
;
544 WRITE_REGISTER_ULONG(TIMER0_LOAD
, ClockInterval
);
545 WRITE_REGISTER_ULONG(TIMER0_CONTROL
, ControlRegister
.AsUlong
);
553 HalInitSystem(IN ULONG BootPhase
,
554 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
556 PKPRCB Prcb
= KeGetCurrentPrcb();
559 // Check the boot phase
564 // Get command-line parameters
566 HalpGetParameters(LoaderBlock
);
570 // Checked HAL requires checked kernel
572 if (!(Prcb
->BuildType
& PRCB_BUILD_DEBUG
))
575 // No match, bugcheck
577 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 1, 0);
581 // Release build requires release HAL
583 if (Prcb
->BuildType
& PRCB_BUILD_DEBUG
)
586 // No match, bugcheck
588 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 0, 0);
594 // SMP HAL requires SMP kernel
596 if (Prcb
->BuildType
& PRCB_BUILD_UNIPROCESSOR
)
599 // No match, bugcheck
601 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 0, 0);
608 if (Prcb
->MajorVersion
!= PRCB_MAJOR_VERSION
)
611 // Validation failed, bugcheck
613 KeBugCheckEx(MISMATCHED_HAL
, 1, Prcb
->MajorVersion
, 1, 0);
617 // Setup time increments to 10ms and 1ms
619 HalpCurrentTimeIncrement
= 100000;
620 HalpNextTimeIncrement
= 100000;
621 HalpNextIntervalCount
= 0;
622 KeSetTimeIncrement(100000, 10000);
625 // Initialize interrupts
627 HalpInitializeInterrupts();
629 else if (BootPhase
== 1)
632 // Switch to real clock interrupt
634 PCR
->InterruptRoutine
[CLOCK2_LEVEL
] = HalpClockInterrupt
;
646 HalInitializeProcessor(IN ULONG ProcessorNumber
,
647 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
669 HalProcessorIdle(VOID
)
677 HalQueryDisplayOwnership(VOID
)
687 HalQueryDisplayParameters(
688 OUT PULONG DispSizeX
,
689 OUT PULONG DispSizeY
,
690 OUT PULONG CursorPosX
,
691 OUT PULONG CursorPosY
)
696 #define RTC_DATA (PVOID)0xE00E8000
700 HalQueryRealTimeClock(IN PTIME_FIELDS Time
)
702 LARGE_INTEGER LargeTime
;
706 // Query the RTC value
708 Seconds
= READ_REGISTER_ULONG(RTC_DATA
);
713 RtlSecondsSince1970ToTime(Seconds
, &LargeTime
);
716 // Convert to time-fields
718 RtlTimeToTimeFields(&LargeTime
, Time
);
725 PADAPTER_OBJECT AdapterObject
)
735 HalReleaseDisplayOwnership(VOID
)
742 HalReportResourceUsage(VOID
)
759 HalRequestSoftwareInterrupt(IN KIRQL Request
)
762 // Force a software interrupt
764 DPRINT1("[SOFTINT]: %d\n", Request
);
765 WRITE_REGISTER_ULONG(VIC_SOFT_INT
, 1 << Request
);
770 HalClearSoftwareInterrupt(IN KIRQL Request
)
773 // Force a software interrupt
775 DPRINT1("[SOFTINTC] %d\n", Request
);
776 WRITE_REGISTER_ULONG(VIC_SOFT_INT_CLEAR
, 1 << Request
);
782 FIRMWARE_REENTRY Action
)
791 BUS_DATA_TYPE BusDataType
,
805 HalSetBusDataByOffset(
806 BUS_DATA_TYPE BusDataType
,
821 HalSetDisplayParameters(
831 HalSetEnvironmentVariable(
865 HalStartNextProcessor(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
866 IN PKPROCESSOR_STATE ProcessorState
)
876 HalSystemVectorDispatchEntry(
889 HalTranslateBusAddress(
890 INTERFACE_TYPE InterfaceType
,
892 PHYSICAL_ADDRESS BusAddress
,
894 PPHYSICAL_ADDRESS TranslatedAddress
)
904 HalpAssignDriveLetters(IN
struct _LOADER_PARAMETER_BLOCK
*LoaderBlock
,
905 IN PSTRING NtDeviceName
,
906 OUT PUCHAR NtSystemPath
,
907 OUT PSTRING NtSystemPathString
)
909 /* Call the kernel */
910 IoAssignDriveLetters(LoaderBlock
,
918 HalpReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
920 IN BOOLEAN ReturnRecognizedPartitions
,
921 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
923 /* Call the kernel */
924 return IoReadPartitionTable(DeviceObject
,
926 ReturnRecognizedPartitions
,
932 HalpWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
934 IN ULONG SectorsPerTrack
,
935 IN ULONG NumberOfHeads
,
936 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
938 /* Call the kernel */
939 return IoWritePartitionTable(DeviceObject
,
948 HalpSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
950 IN ULONG PartitionNumber
,
951 IN ULONG PartitionType
)
953 /* Call the kernel */
954 return IoSetPartitionInformation(DeviceObject
,
963 IoFlushAdapterBuffers(
964 PADAPTER_OBJECT AdapterObject
,
966 PVOID MapRegisterBase
,
969 BOOLEAN WriteToDevice
)
979 IoFreeAdapterChannel(
980 PADAPTER_OBJECT AdapterObject
)
989 PADAPTER_OBJECT AdapterObject
,
990 PVOID MapRegisterBase
,
991 ULONG NumberOfMapRegisters
)
1000 PADAPTER_OBJECT AdapterObject
,
1002 PVOID MapRegisterBase
,
1005 BOOLEAN WriteToDevice
)
1007 PHYSICAL_ADDRESS Address
;
1011 Address
.QuadPart
= 0;
1018 KeFlushWriteBuffer(VOID
)
1025 KeQueryPerformanceCounter(
1026 PLARGE_INTEGER PerformanceFreq
)
1028 LARGE_INTEGER Value
;
1039 KeStallExecutionProcessor(IN ULONG Microseconds
)
1041 SP804_CONTROL_REGISTER ControlRegister
;
1046 WRITE_REGISTER_ULONG(TIMER1_LOAD
, Microseconds
);
1049 // Configure the timer
1051 ControlRegister
.AsUlong
= 0;
1052 ControlRegister
.OneShot
= TRUE
;
1053 ControlRegister
.Wide
= TRUE
;
1054 ControlRegister
.Periodic
= TRUE
;
1055 ControlRegister
.Enabled
= TRUE
;
1056 WRITE_REGISTER_ULONG(TIMER1_CONTROL
, ControlRegister
.AsUlong
);
1059 // Now we will loop until the timer reached 0
1061 while (READ_REGISTER_ULONG(TIMER1_VALUE
));
1066 KfLowerIrql(IN KIRQL NewIrql
)
1068 ULONG InterruptMask
;
1069 ARM_STATUS_REGISTER Flags
;
1070 PKPCR Pcr
= (PKPCR
)KeGetPcr();
1073 // Validate the new IRQL
1075 Flags
= KeArmStatusRegisterGet();
1077 ASSERT(NewIrql
<= Pcr
->CurrentIrql
);
1080 // IRQLs are internally 8 bits
1085 // Setup the interrupt mask for this IRQL
1087 InterruptMask
= KeGetPcr()->IrqlTable
[NewIrql
];
1088 // DPRINT1("[LOWER] IRQL: %d InterruptMask: %lx\n", NewIrql, InterruptMask);
1091 // Clear interrupts associated to the old IRQL
1093 WRITE_REGISTER_ULONG(VIC_INT_CLEAR
, 0xFFFFFFFF);
1096 // Set the new interrupt mask
1097 // PL190 VIC support only for now
1099 WRITE_REGISTER_ULONG(VIC_INT_ENABLE
, InterruptMask
);
1102 // Save the new IRQL
1104 Pcr
->CurrentIrql
= NewIrql
;
1105 if (!Flags
.IrqDisable
) _enable();
1110 KfRaiseIrql(IN KIRQL NewIrql
)
1113 ULONG InterruptMask
;
1114 ARM_STATUS_REGISTER Flags
;
1115 PKPCR Pcr
= (PKPCR
)KeGetPcr();
1118 // Save the current IRQL
1120 Flags
= KeArmStatusRegisterGet();
1122 OldIrql
= Pcr
->CurrentIrql
;
1125 // IRQLs are internally 8 bits
1130 // Setup the interrupt mask for this IRQL
1132 InterruptMask
= KeGetPcr()->IrqlTable
[NewIrql
];
1133 // DPRINT1("[RAISE] IRQL: %d InterruptMask: %lx\n", NewIrql, InterruptMask);
1134 ASSERT(NewIrql
>= OldIrql
);
1137 // Clear interrupts associated to the old IRQL
1139 WRITE_REGISTER_ULONG(VIC_INT_CLEAR
, 0xFFFFFFFF);
1142 // Set the new interrupt mask
1143 // PL190 VIC support only for now
1145 WRITE_REGISTER_ULONG(VIC_INT_ENABLE
, InterruptMask
);
1148 // Save the new IRQL
1150 Pcr
->CurrentIrql
= NewIrql
;
1151 if (!Flags
.IrqDisable
) _enable();
1157 READ_PORT_BUFFER_UCHAR(
1168 READ_PORT_BUFFER_ULONG(
1179 READ_PORT_BUFFER_USHORT(
1223 WRITE_PORT_BUFFER_UCHAR(
1234 WRITE_PORT_BUFFER_USHORT(
1245 WRITE_PORT_BUFFER_ULONG(
1282 KeRaiseIrqlToDpcLevel(VOID
)
1285 // Call the generic routine
1287 return KfRaiseIrql(DISPATCH_LEVEL
);
1291 KeRaiseIrqlToSynchLevel(VOID
)
1294 // Call the generic routine
1296 return KfRaiseIrql(DISPATCH_LEVEL
);
1299 BOOLEAN HalpProcessorIdentified
;
1300 BOOLEAN HalpTestCleanSupported
;
1303 HalpIdentifyProcessor(VOID
)
1305 ARM_ID_CODE_REGISTER IdRegister
;
1308 // Don't do it again
1310 HalpProcessorIdentified
= TRUE
;
1315 IdRegister
= KeArmIdCodeRegisterGet();
1318 // Architecture "6" CPUs support test-and-clean (926EJ-S and 1026EJ-S)
1320 HalpTestCleanSupported
= (IdRegister
.Architecture
== 6);
1324 HalSweepDcache(VOID
)
1327 // We get called very early on, before HalInitSystem or any of the Hal*
1328 // processor routines, so we need to figure out what CPU we're on.
1330 if (!HalpProcessorIdentified
) HalpIdentifyProcessor();
1333 // Check if we can do it the ARMv5TE-J way
1335 if (HalpTestCleanSupported
)
1338 // Test, clean, flush D-Cache
1340 __asm__
__volatile__ ("1: mrc p15, 0, pc, c7, c14, 3; bne 1b");
1345 // We need to do it it by set/way
1352 HalSweepIcache(VOID
)
1355 // All ARM cores support the same Icache flush command, no need for HAL work
1363 #undef KeGetCurrentIrql
1366 KeGetCurrentIrql(VOID
)
1369 return PCR
->CurrentIrql
;
1377 KeLowerIrql(KIRQL NewIrql
)
1379 /* Call the fastcall function */
1380 KfLowerIrql(NewIrql
);
1388 KeRaiseIrql(KIRQL NewIrql
,
1391 /* Call the fastcall function */
1392 *OldIrql
= KfRaiseIrql(NewIrql
);
1400 KeAcquireSpinLock(PKSPIN_LOCK SpinLock
,
1403 /* Call the fastcall function */
1404 *OldIrql
= KfAcquireSpinLock(SpinLock
);
1412 KeAcquireSpinLockRaiseToSynch(PKSPIN_LOCK SpinLock
)
1414 /* Simply raise to dispatch */
1415 return KfRaiseIrql(DISPATCH_LEVEL
);
1423 KeReleaseSpinLock(PKSPIN_LOCK SpinLock
,
1426 /* Call the fastcall function */
1427 KfReleaseSpinLock(SpinLock
, NewIrql
);
1435 KfAcquireSpinLock(PKSPIN_LOCK SpinLock
)
1437 /* Simply raise to dispatch */
1438 return KfRaiseIrql(DISPATCH_LEVEL
);
1446 KfReleaseSpinLock(PKSPIN_LOCK SpinLock
,
1449 /* Simply lower IRQL back */
1450 KfLowerIrql(OldIrql
);
1458 KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
)
1460 /* Simply raise to dispatch */
1461 return KfRaiseIrql(DISPATCH_LEVEL
);
1469 KeAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
)
1471 /* Simply raise to dispatch */
1472 return KfRaiseIrql(DISPATCH_LEVEL
);
1480 KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock
,
1481 IN PKLOCK_QUEUE_HANDLE LockHandle
)
1483 /* Simply raise to dispatch */
1484 LockHandle
->OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1492 KeAcquireInStackQueuedSpinLockRaiseToSynch(IN PKSPIN_LOCK SpinLock
,
1493 IN PKLOCK_QUEUE_HANDLE LockHandle
)
1495 /* Simply raise to synch */
1496 LockHandle
->OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1504 KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1507 /* Simply lower IRQL back */
1508 KfLowerIrql(OldIrql
);
1516 KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle
)
1518 /* Simply lower IRQL back */
1519 KfLowerIrql(LockHandle
->OldIrql
);
1527 KeTryToAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1530 /* Simply raise to dispatch */
1531 *OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1533 /* Always return true on UP Machines */
1542 KeTryToAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1545 /* Simply raise to dispatch */
1546 *OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1548 /* Always return true on UP Machines */