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))
27 /* DATA **********************************************************************/
29 ULONG HalpCurrentTimeIncrement
, HalpNextTimeIncrement
, HalpNextIntervalCount
;
30 ULONG _KdComPortInUse
= 0;
32 ULONG HalpIrqlTable
[HIGH_LEVEL
+ 1] =
34 0xFFFFFFFF, // IRQL 0 PASSIVE_LEVEL
35 0xFFFFFFFD, // IRQL 1 APC_LEVEL
36 0xFFFFFFF9, // IRQL 2 DISPATCH_LEVEL
44 0xFFFFE019, // IRQL 10
45 0xFFFFC019, // IRQL 11
46 0xFFFF8019, // IRQL 12
47 0xFFFF0019, // IRQL 13
48 0xFFFE0019, // IRQL 14
49 0xFFFC0019, // IRQL 15
50 0xFFF80019, // IRQL 16
51 0xFFF00019, // IRQL 17
52 0xFFE00019, // IRQL 18
53 0xFFC00019, // IRQL 19
54 0xFF800019, // IRQL 20
55 0xFF000019, // IRQL 21
56 0xFE000019, // IRQL 22
57 0xFC000019, // IRQL 23
58 0xF0000019, // IRQL 24
59 0x80000019, // IRQL 25
61 0x18, // IRQL 27 PROFILE_LEVEL
62 0x10, // IRQL 28 CLOCK2_LEVEL
63 0x00, // IRQL 29 IPI_LEVEL
64 0x00, // IRQL 30 POWER_LEVEL
65 0x00, // IRQL 31 HIGH_LEVEL
68 UCHAR HalpMaskTable
[HIGH_LEVEL
+ 1] =
70 PROFILE_LEVEL
, // INT 0 WATCHDOG
71 APC_LEVEL
, // INT 1 SOFTWARE INTERRUPT
72 DISPATCH_LEVEL
,// INT 2 COMM RX
73 IPI_LEVEL
, // INT 3 COMM TX
74 CLOCK2_LEVEL
, // INT 4 TIMER 0
103 /* FUNCTIONS *****************************************************************/
108 PDRIVER_OBJECT DriverObject
,
109 PUNICODE_STRING RegistryPath
)
113 return STATUS_SUCCESS
;
121 HalStopProfileInterrupt(IN KPROFILE_SOURCE ProfileSource
)
132 HalStartProfileInterrupt(IN KPROFILE_SOURCE ProfileSource
)
143 HalSetProfileInterval(IN ULONG_PTR Interval
)
152 PFAST_MUTEX FastMutex
)
161 PFAST_MUTEX FastMutex
)
168 ExTryToAcquireFastMutex(
169 PFAST_MUTEX FastMutex
)
179 HalAdjustResourceList(
180 PCM_RESOURCE_LIST Resources
)
184 return STATUS_SUCCESS
;
193 HalAllProcessorsStarted(VOID
)
202 HalAllocateAdapterChannel(
203 PADAPTER_OBJECT AdapterObject
,
204 PWAIT_CONTEXT_BLOCK WaitContextBlock
,
205 ULONG NumberOfMapRegisters
,
206 PDRIVER_CONTROL ExecutionRoutine
)
210 return STATUS_SUCCESS
;
216 HalAllocateCommonBuffer(
217 PADAPTER_OBJECT AdapterObject
,
219 PPHYSICAL_ADDRESS LogicalAddress
,
220 BOOLEAN CacheEnabled
)
230 HalAllocateCrashDumpRegisters(
231 PADAPTER_OBJECT AdapterObject
,
232 PULONG NumberOfMapRegisters
)
241 HalAssignSlotResources(
242 PUNICODE_STRING RegistryPath
,
243 PUNICODE_STRING DriverClassName
,
244 PDRIVER_OBJECT DriverObject
,
245 PDEVICE_OBJECT DeviceObject
,
246 INTERFACE_TYPE BusType
,
249 PCM_RESOURCE_LIST
*AllocatedResources
)
259 HalBeginSystemInterrupt (KIRQL Irql
,
271 HalCalibratePerformanceCounter(
272 volatile LONG
*Count
,
281 HalDisableSystemInterrupt(
292 HalAcquireDisplayOwnership(IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
)
295 // Stub since Windows XP implemented Inbv
302 HalDisplayString(IN PCH String
)
305 // Call the Inbv driver
307 InbvDisplayString(String
);
312 HalQueryDisplayParameters(OUT PULONG DispSizeX
,
313 OUT PULONG DispSizeY
,
314 OUT PULONG CursorPosX
,
315 OUT PULONG CursorPosY
)
318 // Stub since Windows XP implemented Inbv
325 HalSetDisplayParameters(IN ULONG CursorPosX
,
329 // Stub since Windows XP implemented Inbv
336 HalEnableSystemInterrupt(
339 KINTERRUPT_MODE InterruptMode
)
349 HalEndSystemInterrupt(
359 HalFlushCommonBuffer(
375 PADAPTER_OBJECT AdapterObject
,
377 PHYSICAL_ADDRESS LogicalAddress
,
378 PVOID VirtualAddress
,
379 BOOLEAN CacheEnabled
)
388 PDEVICE_DESCRIPTION DeviceDescription
,
389 PULONG NumberOfMapRegisters
)
393 return (PADAPTER_OBJECT
)NULL
;
400 BUS_DATA_TYPE BusDataType
,
414 HalGetBusDataByOffset(
415 BUS_DATA_TYPE BusDataType
,
430 HalGetEnvironmentVariable(
443 HalGetInterruptVector(
444 INTERFACE_TYPE InterfaceType
,
446 ULONG BusInterruptLevel
,
447 ULONG BusInterruptVector
,
467 HalpGetParameters(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
471 /* Make sure we have a loader block and command line */
472 if ((LoaderBlock
) && (LoaderBlock
->LoadOptions
))
474 /* Read the command line */
475 CommandLine
= LoaderBlock
->LoadOptions
;
477 /* Check for initial breakpoint */
478 if (strstr(CommandLine
, "BREAK")) DbgBreakPoint();
483 HalGetInterruptSource(VOID
)
485 ULONG InterruptStatus
;
488 // Get the interrupt status, and return the highest bit set
490 InterruptStatus
= READ_REGISTER_ULONG(VIC_INT_STATUS
);
491 return 31 - _clz(InterruptStatus
);
495 HalpClockInterrupt(VOID
)
498 // Clear the interrupt
500 ASSERT(KeGetCurrentIrql() == CLOCK2_LEVEL
);
501 WRITE_REGISTER_ULONG(TIMER0_INT_CLEAR
, 1);
504 // FIXME: Update HAL Perf counters
508 // FIXME: Check if someone changed the clockrate
514 KeUpdateSystemTime(KeGetCurrentThread()->TrapFrame
,
516 HalpCurrentTimeIncrement
);
524 HalpStallInterrupt(VOID
)
527 // Clear the interrupt
529 WRITE_REGISTER_ULONG(TIMER0_INT_CLEAR
, 1);
533 HalpInitializeInterrupts(VOID
)
535 PKPCR Pcr
= (PKPCR
)KeGetPcr();
537 SP804_CONTROL_REGISTER ControlRegister
;
540 // Fill out the IRQL mappings
542 RtlCopyMemory(Pcr
->IrqlTable
, HalpIrqlTable
, sizeof(Pcr
->IrqlTable
));
543 RtlCopyMemory(Pcr
->IrqlMask
, HalpMaskTable
, sizeof(Pcr
->IrqlMask
));
546 // Setup the clock and profile interrupt
548 Pcr
->InterruptRoutine
[CLOCK2_LEVEL
] = HalpStallInterrupt
;
551 // Configure the interval to 10ms
552 // (INTERVAL (10ms) * TIMCLKfreq (1MHz))
553 // --------------------------------------- == 10^4
554 // (TIMCLKENXdiv (1) * PRESCALEdiv (1))
556 ClockInterval
= 0x2710;
559 // Configure the timer
561 ControlRegister
.AsUlong
= 0;
562 ControlRegister
.Wide
= TRUE
;
563 ControlRegister
.Periodic
= TRUE
;
564 ControlRegister
.Interrupt
= TRUE
;
565 ControlRegister
.Enabled
= TRUE
;
570 WRITE_REGISTER_ULONG(TIMER0_LOAD
, ClockInterval
);
571 WRITE_REGISTER_ULONG(TIMER0_CONTROL
, ControlRegister
.AsUlong
);
579 HalInitSystem(IN ULONG BootPhase
,
580 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
582 PKPRCB Prcb
= KeGetCurrentPrcb();
585 // Check the boot phase
590 // Get command-line parameters
592 HalpGetParameters(LoaderBlock
);
596 // Checked HAL requires checked kernel
598 if (!(Prcb
->BuildType
& PRCB_BUILD_DEBUG
))
601 // No match, bugcheck
603 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 1, 0);
607 // Release build requires release HAL
609 if (Prcb
->BuildType
& PRCB_BUILD_DEBUG
)
612 // No match, bugcheck
614 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 0, 0);
620 // SMP HAL requires SMP kernel
622 if (Prcb
->BuildType
& PRCB_BUILD_UNIPROCESSOR
)
625 // No match, bugcheck
627 KeBugCheckEx(MISMATCHED_HAL
, 2, Prcb
->BuildType
, 0, 0);
634 if (Prcb
->MajorVersion
!= PRCB_MAJOR_VERSION
)
637 // Validation failed, bugcheck
639 KeBugCheckEx(MISMATCHED_HAL
, 1, Prcb
->MajorVersion
, 1, 0);
643 // Setup time increments to 10ms and 1ms
645 HalpCurrentTimeIncrement
= 100000;
646 HalpNextTimeIncrement
= 100000;
647 HalpNextIntervalCount
= 0;
648 KeSetTimeIncrement(100000, 10000);
651 // Initialize interrupts
653 HalpInitializeInterrupts();
655 else if (BootPhase
== 1)
658 // Switch to real clock interrupt
660 PCR
->InterruptRoutine
[CLOCK2_LEVEL
] = HalpClockInterrupt
;
672 HalInitializeProcessor(IN ULONG ProcessorNumber
,
673 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
695 HalProcessorIdle(VOID
)
701 #define RTC_DATA (PVOID)0xE00E8000
705 HalQueryRealTimeClock(IN PTIME_FIELDS Time
)
707 LARGE_INTEGER LargeTime
;
711 // Query the RTC value
713 Seconds
= READ_REGISTER_ULONG(RTC_DATA
);
718 RtlSecondsSince1970ToTime(Seconds
, &LargeTime
);
721 // Convert to time-fields
723 RtlTimeToTimeFields(&LargeTime
, Time
);
730 PADAPTER_OBJECT AdapterObject
)
740 HalReportResourceUsage(VOID
)
757 HalRequestSoftwareInterrupt(IN KIRQL Request
)
760 // Force a software interrupt
762 WRITE_REGISTER_ULONG(VIC_SOFT_INT
, 1 << Request
);
767 HalClearSoftwareInterrupt(IN KIRQL Request
)
770 // Clear a software interrupt
772 WRITE_REGISTER_ULONG(VIC_SOFT_INT_CLEAR
, 1 << Request
);
778 FIRMWARE_REENTRY Action
)
787 BUS_DATA_TYPE BusDataType
,
801 HalSetBusDataByOffset(
802 BUS_DATA_TYPE BusDataType
,
817 HalSetEnvironmentVariable(
851 HalStartNextProcessor(IN PLOADER_PARAMETER_BLOCK LoaderBlock
,
852 IN PKPROCESSOR_STATE ProcessorState
)
862 HalSystemVectorDispatchEntry(
875 HalTranslateBusAddress(
876 INTERFACE_TYPE InterfaceType
,
878 PHYSICAL_ADDRESS BusAddress
,
880 PPHYSICAL_ADDRESS TranslatedAddress
)
890 HalpAssignDriveLetters(IN
struct _LOADER_PARAMETER_BLOCK
*LoaderBlock
,
891 IN PSTRING NtDeviceName
,
892 OUT PUCHAR NtSystemPath
,
893 OUT PSTRING NtSystemPathString
)
895 /* Call the kernel */
896 IoAssignDriveLetters(LoaderBlock
,
904 HalpReadPartitionTable(IN PDEVICE_OBJECT DeviceObject
,
906 IN BOOLEAN ReturnRecognizedPartitions
,
907 IN OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
909 /* Call the kernel */
910 return IoReadPartitionTable(DeviceObject
,
912 ReturnRecognizedPartitions
,
918 HalpWritePartitionTable(IN PDEVICE_OBJECT DeviceObject
,
920 IN ULONG SectorsPerTrack
,
921 IN ULONG NumberOfHeads
,
922 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer
)
924 /* Call the kernel */
925 return IoWritePartitionTable(DeviceObject
,
934 HalpSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject
,
936 IN ULONG PartitionNumber
,
937 IN ULONG PartitionType
)
939 /* Call the kernel */
940 return IoSetPartitionInformation(DeviceObject
,
949 IoFlushAdapterBuffers(
950 PADAPTER_OBJECT AdapterObject
,
952 PVOID MapRegisterBase
,
955 BOOLEAN WriteToDevice
)
965 IoFreeAdapterChannel(
966 PADAPTER_OBJECT AdapterObject
)
975 PADAPTER_OBJECT AdapterObject
,
976 PVOID MapRegisterBase
,
977 ULONG NumberOfMapRegisters
)
986 PADAPTER_OBJECT AdapterObject
,
988 PVOID MapRegisterBase
,
991 BOOLEAN WriteToDevice
)
993 PHYSICAL_ADDRESS Address
;
997 Address
.QuadPart
= 0;
1004 KeFlushWriteBuffer(VOID
)
1011 KeQueryPerformanceCounter(
1012 PLARGE_INTEGER PerformanceFreq
)
1014 LARGE_INTEGER Value
;
1025 KeStallExecutionProcessor(IN ULONG Microseconds
)
1027 SP804_CONTROL_REGISTER ControlRegister
;
1032 WRITE_REGISTER_ULONG(TIMER1_LOAD
, Microseconds
);
1035 // Configure the timer
1037 ControlRegister
.AsUlong
= 0;
1038 ControlRegister
.OneShot
= TRUE
;
1039 ControlRegister
.Wide
= TRUE
;
1040 ControlRegister
.Periodic
= TRUE
;
1041 ControlRegister
.Enabled
= TRUE
;
1042 WRITE_REGISTER_ULONG(TIMER1_CONTROL
, ControlRegister
.AsUlong
);
1045 // Now we will loop until the timer reached 0
1047 while (READ_REGISTER_ULONG(TIMER1_VALUE
));
1052 KfLowerIrql(IN KIRQL NewIrql
)
1054 ULONG InterruptMask
;
1055 ARM_STATUS_REGISTER Flags
;
1056 PKPCR Pcr
= (PKPCR
)KeGetPcr();
1059 // Validate the new IRQL
1061 Flags
= KeArmStatusRegisterGet();
1063 ASSERT(NewIrql
<= Pcr
->CurrentIrql
);
1066 // IRQLs are internally 8 bits
1071 // Setup the interrupt mask for this IRQL
1073 InterruptMask
= KeGetPcr()->IrqlTable
[NewIrql
];
1074 // DPRINT1("[LOWER] IRQL: %d InterruptMask: %lx\n", NewIrql, InterruptMask);
1077 // Clear interrupts associated to the old IRQL
1079 WRITE_REGISTER_ULONG(VIC_INT_CLEAR
, 0xFFFFFFFF);
1082 // Set the new interrupt mask
1083 // PL190 VIC support only for now
1085 WRITE_REGISTER_ULONG(VIC_INT_ENABLE
, InterruptMask
);
1088 // Save the new IRQL
1090 Pcr
->CurrentIrql
= NewIrql
;
1091 if (!Flags
.IrqDisable
) _enable();
1096 KfRaiseIrql(IN KIRQL NewIrql
)
1099 ULONG InterruptMask
;
1100 ARM_STATUS_REGISTER Flags
;
1101 PKPCR Pcr
= (PKPCR
)KeGetPcr();
1104 // Save the current IRQL
1106 Flags
= KeArmStatusRegisterGet();
1108 OldIrql
= Pcr
->CurrentIrql
;
1111 // IRQLs are internally 8 bits
1116 // Setup the interrupt mask for this IRQL
1118 InterruptMask
= KeGetPcr()->IrqlTable
[NewIrql
];
1119 // DPRINT1("[RAISE] IRQL: %d InterruptMask: %lx\n", NewIrql, InterruptMask);
1120 ASSERT(NewIrql
>= OldIrql
);
1123 // Clear interrupts associated to the old IRQL
1125 WRITE_REGISTER_ULONG(VIC_INT_CLEAR
, 0xFFFFFFFF);
1128 // Set the new interrupt mask
1129 // PL190 VIC support only for now
1131 WRITE_REGISTER_ULONG(VIC_INT_ENABLE
, InterruptMask
);
1134 // Save the new IRQL
1136 Pcr
->CurrentIrql
= NewIrql
;
1137 if (!Flags
.IrqDisable
) _enable();
1143 READ_PORT_BUFFER_UCHAR(
1154 READ_PORT_BUFFER_ULONG(
1165 READ_PORT_BUFFER_USHORT(
1209 WRITE_PORT_BUFFER_UCHAR(
1220 WRITE_PORT_BUFFER_USHORT(
1231 WRITE_PORT_BUFFER_ULONG(
1268 KeRaiseIrqlToDpcLevel(VOID
)
1271 // Call the generic routine
1273 return KfRaiseIrql(DISPATCH_LEVEL
);
1277 KeRaiseIrqlToSynchLevel(VOID
)
1280 // Call the generic routine
1282 return KfRaiseIrql(DISPATCH_LEVEL
);
1285 BOOLEAN HalpProcessorIdentified
;
1286 BOOLEAN HalpTestCleanSupported
;
1289 HalpIdentifyProcessor(VOID
)
1291 ARM_ID_CODE_REGISTER IdRegister
;
1294 // Don't do it again
1296 HalpProcessorIdentified
= TRUE
;
1301 IdRegister
= KeArmIdCodeRegisterGet();
1304 // Architecture "6" CPUs support test-and-clean (926EJ-S and 1026EJ-S)
1306 HalpTestCleanSupported
= (IdRegister
.Architecture
== 6);
1310 HalSweepDcache(VOID
)
1313 // We get called very early on, before HalInitSystem or any of the Hal*
1314 // processor routines, so we need to figure out what CPU we're on.
1316 if (!HalpProcessorIdentified
) HalpIdentifyProcessor();
1319 // Check if we can do it the ARMv5TE-J way
1321 if (HalpTestCleanSupported
)
1324 // Test, clean, flush D-Cache
1326 __asm__
__volatile__ ("1: mrc p15, 0, pc, c7, c14, 3; bne 1b");
1331 // We need to do it it by set/way
1338 HalSweepIcache(VOID
)
1341 // All ARM cores support the same Icache flush command, no need for HAL work
1349 #undef KeGetCurrentIrql
1352 KeGetCurrentIrql(VOID
)
1355 return PCR
->CurrentIrql
;
1363 KeLowerIrql(KIRQL NewIrql
)
1365 /* Call the fastcall function */
1366 KfLowerIrql(NewIrql
);
1374 KeRaiseIrql(KIRQL NewIrql
,
1377 /* Call the fastcall function */
1378 *OldIrql
= KfRaiseIrql(NewIrql
);
1386 KeAcquireSpinLock(PKSPIN_LOCK SpinLock
,
1389 /* Call the fastcall function */
1390 *OldIrql
= KfAcquireSpinLock(SpinLock
);
1398 KeAcquireSpinLockRaiseToSynch(PKSPIN_LOCK SpinLock
)
1400 /* Simply raise to dispatch */
1401 return KfRaiseIrql(DISPATCH_LEVEL
);
1409 KeReleaseSpinLock(PKSPIN_LOCK SpinLock
,
1412 /* Call the fastcall function */
1413 KfReleaseSpinLock(SpinLock
, NewIrql
);
1421 KfAcquireSpinLock(PKSPIN_LOCK SpinLock
)
1423 /* Simply raise to dispatch */
1424 return KfRaiseIrql(DISPATCH_LEVEL
);
1432 KfReleaseSpinLock(PKSPIN_LOCK SpinLock
,
1435 /* Simply lower IRQL back */
1436 KfLowerIrql(OldIrql
);
1444 KeAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
)
1446 /* Simply raise to dispatch */
1447 return KfRaiseIrql(DISPATCH_LEVEL
);
1455 KeAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
)
1457 /* Simply raise to dispatch */
1458 return KfRaiseIrql(DISPATCH_LEVEL
);
1466 KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock
,
1467 IN PKLOCK_QUEUE_HANDLE LockHandle
)
1469 /* Simply raise to dispatch */
1470 LockHandle
->OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1478 KeAcquireInStackQueuedSpinLockRaiseToSynch(IN PKSPIN_LOCK SpinLock
,
1479 IN PKLOCK_QUEUE_HANDLE LockHandle
)
1481 /* Simply raise to synch */
1482 LockHandle
->OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1490 KeReleaseQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1493 /* Simply lower IRQL back */
1494 KfLowerIrql(OldIrql
);
1502 KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle
)
1504 /* Simply lower IRQL back */
1505 KfLowerIrql(LockHandle
->OldIrql
);
1513 KeTryToAcquireQueuedSpinLockRaiseToSynch(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1516 /* Simply raise to dispatch */
1517 *OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1519 /* Always return true on UP Machines */
1528 KeTryToAcquireQueuedSpinLock(IN KSPIN_LOCK_QUEUE_NUMBER LockNumber
,
1531 /* Simply raise to dispatch */
1532 *OldIrql
= KfRaiseIrql(DISPATCH_LEVEL
);
1534 /* Always return true on UP Machines */