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 *******************************************************************/
14 #include <ndk/inbvfuncs.h>
16 #undef ExAcquireFastMutex
17 #undef ExReleaseFastMutex
18 #undef ExTryToAcquireFastMutex
19 #undef KeAcquireSpinLock
22 #undef KeReleaseSpinLock
24 #define READ_REGISTER_ULONG(r) (*((volatile ULONG * const)(r)))
25 #define WRITE_REGISTER_ULONG(r, v) (*((volatile ULONG *)(r)) = (v))
30 IN PKTRAP_FRAME TrapFrame
,
35 /* DATA **********************************************************************/
37 ULONG HalpCurrentTimeIncrement
, HalpNextTimeIncrement
, HalpNextIntervalCount
;
38 PUCHAR KdComPortInUse
;
40 ULONG HalpIrqlTable
[HIGH_LEVEL
+ 1] =
42 0xFFFFFFFF, // IRQL 0 PASSIVE_LEVEL
43 0xFFFFFFFD, // IRQL 1 APC_LEVEL
44 0xFFFFFFF9, // IRQL 2 DISPATCH_LEVEL
52 0xFFFFE019, // IRQL 10
53 0xFFFFC019, // IRQL 11
54 0xFFFF8019, // IRQL 12
55 0xFFFF0019, // IRQL 13
56 0xFFFE0019, // IRQL 14
57 0xFFFC0019, // IRQL 15
58 0xFFF80019, // IRQL 16
59 0xFFF00019, // IRQL 17
60 0xFFE00019, // IRQL 18
61 0xFFC00019, // IRQL 19
62 0xFF800019, // IRQL 20
63 0xFF000019, // IRQL 21
64 0xFE000019, // IRQL 22
65 0xFC000019, // IRQL 23
66 0xF0000019, // IRQL 24
67 0x80000019, // IRQL 25
69 0x18, // IRQL 27 PROFILE_LEVEL
70 0x10, // IRQL 28 CLOCK2_LEVEL
71 0x00, // IRQL 29 IPI_LEVEL
72 0x00, // IRQL 30 POWER_LEVEL
73 0x00, // IRQL 31 HIGH_LEVEL
76 UCHAR HalpMaskTable
[HIGH_LEVEL
+ 1] =
78 PROFILE_LEVEL
, // INT 0 WATCHDOG
79 APC_LEVEL
, // INT 1 SOFTWARE INTERRUPT
80 DISPATCH_LEVEL
,// INT 2 COMM RX
81 IPI_LEVEL
, // INT 3 COMM TX
82 CLOCK2_LEVEL
, // INT 4 TIMER 0
111 /* FUNCTIONS *****************************************************************/
116 PDRIVER_OBJECT DriverObject
,
117 PUNICODE_STRING RegistryPath
)
121 return STATUS_SUCCESS
;
129 HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource
)
140 HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource
)
151 HalSetProfileInterval(IN ULONG_PTR Interval
)
160 PFAST_MUTEX FastMutex
)
169 PFAST_MUTEX FastMutex
)
176 ExTryToAcquireFastMutex(
177 PFAST_MUTEX FastMutex
)
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(IN KIRQL Irql
,
279 HalCalibratePerformanceCounter(
280 volatile LONG
*Count
,
289 HalDisableSystemInterrupt(ULONG Vector
,
297 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
)
300 // Stub since Windows XP implemented Inbv
307 HalDisplayString(IN PCH String
)
310 // Call the Inbv driver
312 InbvDisplayString(String
);
317 HalQueryDisplayParameters(OUT PULONG DispSizeX
,
318 OUT PULONG DispSizeY
,
319 OUT PULONG CursorPosX
,
320 OUT PULONG CursorPosY
)
323 // Stub since Windows XP implemented Inbv
330 HalSetDisplayParameters(IN ULONG CursorPosX
,
334 // Stub since Windows XP implemented Inbv
341 HalEnableSystemInterrupt(IN UCHAR Vector
,
343 IN KINTERRUPT_MODE InterruptMode
)
353 HalEndSystemInterrupt(IN KIRQL OldIrql
,
354 IN PKTRAP_FRAME TrapFrame
)
362 HalFlushCommonBuffer(
378 PADAPTER_OBJECT AdapterObject
,
380 PHYSICAL_ADDRESS LogicalAddress
,
381 PVOID VirtualAddress
,
382 BOOLEAN CacheEnabled
)
391 PDEVICE_DESCRIPTION DeviceDescription
,
392 PULONG NumberOfMapRegisters
)
396 return (PADAPTER_OBJECT
)NULL
;
403 BUS_DATA_TYPE BusDataType
,
417 HalGetBusDataByOffset(
418 BUS_DATA_TYPE BusDataType
,
433 HalGetEnvironmentVariable(
446 HalGetInterruptVector(
447 INTERFACE_TYPE InterfaceType
,
449 ULONG BusInterruptLevel
,
450 ULONG BusInterruptVector
,
470 HalpGetParameters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
474 /* Make sure we have a loader block and command line */
475 if ((LoaderBlock
) && (LoaderBlock
->LoadOptions
))
477 /* Read the command line */
478 CommandLine
= LoaderBlock
->LoadOptions
;
480 /* Check for initial breakpoint */
481 if (strstr(CommandLine
, "BREAK")) DbgBreakPoint();
486 HalGetInterruptSource(VOID
)
488 ULONG InterruptStatus
;
491 // Get the interrupt status, and return the highest bit set
493 InterruptStatus
= READ_REGISTER_ULONG(VIC_INT_STATUS
);
494 return 31 - _clz(InterruptStatus
);
498 HalpClockInterrupt(VOID
)
501 // Clear the interrupt
503 ASSERT(KeGetCurrentIrql() == CLOCK2_LEVEL
);
504 WRITE_REGISTER_ULONG(TIMER0_INT_CLEAR
, 1);
507 // FIXME: Update HAL Perf counters
511 // FIXME: Check if someone changed the clockrate
517 KeUpdateSystemTime(KeGetCurrentThread()->TrapFrame
,
519 HalpCurrentTimeIncrement
);
527 HalpStallInterrupt(VOID
)
530 // Clear the interrupt
532 WRITE_REGISTER_ULONG(TIMER0_INT_CLEAR
, 1);
536 HalpInitializeInterrupts(VOID
)
538 PKPCR Pcr
= (PKPCR
)KeGetPcr();
540 SP804_CONTROL_REGISTER ControlRegister
;
543 // Fill out the IRQL mappings
545 RtlCopyMemory(Pcr
->IrqlTable
, HalpIrqlTable
, sizeof(Pcr
->IrqlTable
));
546 RtlCopyMemory(Pcr
->IrqlMask
, HalpMaskTable
, sizeof(Pcr
->IrqlMask
));
549 // Setup the clock and profile interrupt
551 Pcr
->InterruptRoutine
[CLOCK2_LEVEL
] = HalpStallInterrupt
;
554 // Configure the interval to 10ms
555 // (INTERVAL (10ms) * TIMCLKfreq (1MHz))
556 // --------------------------------------- == 10^4
557 // (TIMCLKENXdiv (1) * PRESCALEdiv (1))
559 ClockInterval
= 0x2710;
562 // Configure the timer
564 ControlRegister
.AsUlong
= 0;
565 ControlRegister
.Wide
= TRUE
;
566 ControlRegister
.Periodic
= TRUE
;
567 ControlRegister
.Interrupt
= TRUE
;
568 ControlRegister
.Enabled
= TRUE
;
573 WRITE_REGISTER_ULONG(TIMER0_LOAD
, ClockInterval
);
574 WRITE_REGISTER_ULONG(TIMER0_CONTROL
, ControlRegister
.AsUlong
);
582 HalInitSystem(IN ULONG BootPhase
,
583 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
585 PKPRCB Prcb
= KeGetCurrentPrcb();
588 // Check the boot phase
593 // Get command-line parameters
595 HalpGetParameters(LoaderBlock
);
599 // Checked HAL requires checked kernel
601 if (!(Prcb
->BuildType
& PRCB_BUILD_DEBUG
))
604 // No match, bugcheck
606 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 1, 0);
610 // Release build requires release HAL
612 if (Prcb
->BuildType
& PRCB_BUILD_DEBUG
)
615 // No match, bugcheck
617 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 0, 0);
623 // SMP HAL requires SMP kernel
625 if (Prcb
->BuildType
& PRCB_BUILD_UNIPROCESSOR
)
628 // No match, bugcheck
630 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 0, 0);
637 if (Prcb
->MajorVersion
!= PRCB_MAJOR_VERSION
)
640 // Validation failed, bugcheck
642 KeBugCheckEx(MISMATCHED_HAL
, 1, Prcb
->MajorVersion
, 1, 0);
646 // Setup time increments to 10ms and 1ms
648 HalpCurrentTimeIncrement
= 100000;
649 HalpNextTimeIncrement
= 100000;
650 HalpNextIntervalCount
= 0;
651 KeSetTimeIncrement(100000, 10000);
654 // Initialize interrupts
656 HalpInitializeInterrupts();
658 else if (BootPhase
== 1)
661 // Switch to real clock interrupt
663 PCR
->InterruptRoutine
[CLOCK2_LEVEL
] = HalpClockInterrupt
;
675 HalInitializeProcessor(IN ULONG ProcessorNumber
,
676 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
698 HalProcessorIdle(VOID
)
704 #define RTC_DATA (PVOID)0xE00E8000
708 HalQueryRealTimeClock(IN PTIME_FIELDS Time
)
710 LARGE_INTEGER LargeTime
;
714 // Query the RTC value
716 Seconds
= READ_REGISTER_ULONG(RTC_DATA
);
721 RtlSecondsSince1970ToTime(Seconds
, &LargeTime
);
724 // Convert to time-fields
726 RtlTimeToTimeFields(&LargeTime
, Time
);
733 PADAPTER_OBJECT AdapterObject
)
743 HalReportResourceUsage(VOID
)
760 HalRequestSoftwareInterrupt(IN KIRQL Request
)
763 // Force a software interrupt
765 WRITE_REGISTER_ULONG(VIC_SOFT_INT
, 1 << Request
);
770 HalClearSoftwareInterrupt(IN KIRQL Request
)
773 // Clear a software interrupt
775 WRITE_REGISTER_ULONG(VIC_SOFT_INT_CLEAR
, 1 << Request
);
781 FIRMWARE_REENTRY Action
)
790 BUS_DATA_TYPE BusDataType
,
804 HalSetBusDataByOffset(
805 BUS_DATA_TYPE BusDataType
,
820 HalSetEnvironmentVariable(
854 HalStartNextProcessor(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
855 IN PKPROCESSOR_STATE ProcessorState
)
865 HalSystemVectorDispatchEntry(IN ULONG Vector
,
866 OUT PKINTERRUPT_ROUTINE
**FlatDispatch
,
867 OUT PKINTERRUPT_ROUTINE
*NoConnection
)
877 HalTranslateBusAddress(
878 INTERFACE_TYPE InterfaceType
,
880 PHYSICAL_ADDRESS BusAddress
,
882 PPHYSICAL_ADDRESS TranslatedAddress
)
892 HalpAssignDriveLetters(IN
struct _LOADER_PARAMETER_BLOCK
*LoaderBlock
,
893 IN PSTRING NtDeviceName
,
894 OUT PUCHAR NtSystemPath
,
895 OUT PSTRING NtSystemPathString
)
897 /* Call the kernel */
898 IoAssignDriveLetters(LoaderBlock
,
906 HalpReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
908 IN BOOLEAN ReturnRecognizedPartitions
,
909 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
911 /* Call the kernel */
912 return IoReadPartitionTable(DeviceObject
,
914 ReturnRecognizedPartitions
,
920 HalpWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
922 IN ULONG SectorsPerTrack
,
923 IN ULONG NumberOfHeads
,
924 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
926 /* Call the kernel */
927 return IoWritePartitionTable(DeviceObject
,
936 HalpSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
938 IN ULONG PartitionNumber
,
939 IN ULONG PartitionType
)
941 /* Call the kernel */
942 return IoSetPartitionInformation(DeviceObject
,
951 IoFlushAdapterBuffers(
952 PADAPTER_OBJECT AdapterObject
,
954 PVOID MapRegisterBase
,
957 BOOLEAN WriteToDevice
)
967 IoFreeAdapterChannel(
968 PADAPTER_OBJECT AdapterObject
)
977 PADAPTER_OBJECT AdapterObject
,
978 PVOID MapRegisterBase
,
979 ULONG NumberOfMapRegisters
)
988 PADAPTER_OBJECT AdapterObject
,
990 PVOID MapRegisterBase
,
993 BOOLEAN WriteToDevice
)
995 PHYSICAL_ADDRESS Address
;
999 Address
.QuadPart
= 0;
1006 KeFlushWriteBuffer(VOID
)
1013 KeQueryPerformanceCounter(
1014 PLARGE_INTEGER PerformanceFreq
)
1016 LARGE_INTEGER Value
;
1027 KeStallExecutionProcessor(IN ULONG Microseconds
)
1029 SP804_CONTROL_REGISTER ControlRegister
;
1034 WRITE_REGISTER_ULONG(TIMER1_LOAD
, Microseconds
);
1037 // Configure the timer
1039 ControlRegister
.AsUlong
= 0;
1040 ControlRegister
.OneShot
= TRUE
;
1041 ControlRegister
.Wide
= TRUE
;
1042 ControlRegister
.Periodic
= TRUE
;
1043 ControlRegister
.Enabled
= TRUE
;
1044 WRITE_REGISTER_ULONG(TIMER1_CONTROL
, ControlRegister
.AsUlong
);
1047 // Now we will loop until the timer reached 0
1049 while (READ_REGISTER_ULONG(TIMER1_VALUE
));
1054 KfLowerIrql(IN KIRQL NewIrql
)
1056 ULONG InterruptMask
;
1057 ARM_STATUS_REGISTER Flags
;
1058 PKPCR Pcr
= (PKPCR
)KeGetPcr();
1061 // Validate the new IRQL
1063 Flags
= KeArmStatusRegisterGet();
1065 ASSERT(NewIrql
<= Pcr
->CurrentIrql
);
1068 // IRQLs are internally 8 bits
1073 // Setup the interrupt mask for this IRQL
1075 InterruptMask
= KeGetPcr()->IrqlTable
[NewIrql
];
1076 // DPRINT1("[LOWER] IRQL: %d InterruptMask: %lx\n", NewIrql, InterruptMask);
1079 // Clear interrupts associated to the old IRQL
1081 WRITE_REGISTER_ULONG(VIC_INT_CLEAR
, 0xFFFFFFFF);
1084 // Set the new interrupt mask
1085 // PL190 VIC support only for now
1087 WRITE_REGISTER_ULONG(VIC_INT_ENABLE
, InterruptMask
);
1090 // Save the new IRQL
1092 Pcr
->CurrentIrql
= NewIrql
;
1093 if (!Flags
.IrqDisable
) _enable();
1098 KfRaiseIrql(IN KIRQL NewIrql
)
1101 ULONG InterruptMask
;
1102 ARM_STATUS_REGISTER Flags
;
1103 PKPCR Pcr
= (PKPCR
)KeGetPcr();
1106 // Save the current IRQL
1108 Flags
= KeArmStatusRegisterGet();
1110 OldIrql
= Pcr
->CurrentIrql
;
1113 // IRQLs are internally 8 bits
1118 // Setup the interrupt mask for this IRQL
1120 InterruptMask
= KeGetPcr()->IrqlTable
[NewIrql
];
1121 // DPRINT1("[RAISE] IRQL: %d InterruptMask: %lx\n", NewIrql, InterruptMask);
1122 ASSERT(NewIrql
>= OldIrql
);
1125 // Clear interrupts associated to the old IRQL
1127 WRITE_REGISTER_ULONG(VIC_INT_CLEAR
, 0xFFFFFFFF);
1130 // Set the new interrupt mask
1131 // PL190 VIC support only for now
1133 WRITE_REGISTER_ULONG(VIC_INT_ENABLE
, InterruptMask
);
1136 // Save the new IRQL
1138 Pcr
->CurrentIrql
= NewIrql
;
1139 if (!Flags
.IrqDisable
) _enable();
1145 READ_PORT_BUFFER_UCHAR(
1156 READ_PORT_BUFFER_ULONG(
1167 READ_PORT_BUFFER_USHORT(
1211 WRITE_PORT_BUFFER_UCHAR(
1222 WRITE_PORT_BUFFER_USHORT(
1233 WRITE_PORT_BUFFER_ULONG(
1270 KeRaiseIrqlToDpcLevel(VOID
)
1273 // Call the generic routine
1275 return KfRaiseIrql(DISPATCH_LEVEL
);
1279 KeRaiseIrqlToSynchLevel(VOID
)
1282 // Call the generic routine
1284 return KfRaiseIrql(DISPATCH_LEVEL
);
1287 BOOLEAN HalpProcessorIdentified
;
1288 BOOLEAN HalpTestCleanSupported
;
1291 HalpIdentifyProcessor(VOID
)
1293 ARM_ID_CODE_REGISTER IdRegister
;
1296 // Don't do it again
1298 HalpProcessorIdentified
= TRUE
;
1303 IdRegister
= KeArmIdCodeRegisterGet();
1306 // Architecture "6" CPUs support test-and-clean (926EJ-S and 1026EJ-S)
1308 HalpTestCleanSupported
= (IdRegister
.Architecture
== 6);
1312 HalSweepDcache(VOID
)
1315 // We get called very early on, before HalInitSystem or any of the Hal*
1316 // processor routines, so we need to figure out what CPU we're on.
1318 if (!HalpProcessorIdentified
) HalpIdentifyProcessor();
1321 // Check if we can do it the ARMv5TE-J way
1323 if (HalpTestCleanSupported
)
1326 // Test, clean, flush D-Cache
1328 __asm__
__volatile__ ("1: mrc p15, 0, pc, c7, c14, 3; bne 1b");
1333 // We need to do it it by set/way
1340 HalSweepIcache(VOID
)
1343 // All ARM cores support the same Icache flush command, no need for HAL work
1351 #undef KeGetCurrentIrql
1354 KeGetCurrentIrql(VOID
)
1357 return PCR
->CurrentIrql
;
1365 KeLowerIrql(KIRQL NewIrql
)
1367 /* Call the fastcall function */
1368 KfLowerIrql(NewIrql
);
1376 KeRaiseIrql(KIRQL NewIrql
,
1379 /* Call the fastcall function */
1380 *OldIrql
= KfRaiseIrql(NewIrql
);
1388 KeAcquireSpinLock(PKSPIN_LOCK SpinLock
,
1391 /* Call the fastcall function */
1392 *OldIrql
= KfAcquireSpinLock(SpinLock
);
1400 KeAcquireSpinLockRaiseToSynch(PKSPIN_LOCK SpinLock
)
1402 /* Simply raise to dispatch */
1403 return KfRaiseIrql(DISPATCH_LEVEL
);
1411 KeReleaseSpinLock(PKSPIN_LOCK SpinLock
,
1414 /* Call the fastcall function */
1415 KfReleaseSpinLock(SpinLock
, NewIrql
);
1423 KfAcquireSpinLock(PKSPIN_LOCK SpinLock
)
1425 /* Simply raise to dispatch */
1426 return KfRaiseIrql(DISPATCH_LEVEL
);
1434 KfReleaseSpinLock(PKSPIN_LOCK SpinLock
,
1437 /* Simply lower IRQL back */
1438 KfLowerIrql(OldIrql
);
1446 KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
)
1448 /* Simply raise to dispatch */
1449 return KfRaiseIrql(DISPATCH_LEVEL
);
1457 KeAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
)
1459 /* Simply raise to dispatch */
1460 return KfRaiseIrql(DISPATCH_LEVEL
);
1468 KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock
,
1469 IN PKLOCK_QUEUE_HANDLE LockHandle
)
1471 /* Simply raise to dispatch */
1472 LockHandle
->OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1480 KeAcquireInStackQueuedSpinLockRaiseToSynch(IN PKSPIN_LOCK SpinLock
,
1481 IN PKLOCK_QUEUE_HANDLE LockHandle
)
1483 /* Simply raise to synch */
1484 LockHandle
->OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1492 KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1495 /* Simply lower IRQL back */
1496 KfLowerIrql(OldIrql
);
1504 KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle
)
1506 /* Simply lower IRQL back */
1507 KfLowerIrql(LockHandle
->OldIrql
);
1515 KeTryToAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1518 /* Simply raise to dispatch */
1519 *OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1521 /* Always return true on UP Machines */
1530 KeTryToAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1533 /* Simply raise to dispatch */
1534 *OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1536 /* Always return true on UP Machines */