https://git.reactos.org/?p=reactos.git;a=commitdiff;h=16e988d10858ee1dd14d6…
commit 16e988d10858ee1dd14d6ea17056797a18fa0cff
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Tue Jun 22 12:53:23 2021 +0200
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Sat Jun 26 21:10:43 2021 +0200
[HAL:APIC] Improve code
- Use an enum for the APIC registers
- Add support routine for SMP.
---
hal/halx86/apic.cmake | 1 +
hal/halx86/apic/apic.c | 22 ++++-----
hal/halx86/apic/apicp.h | 120 ++++++++++++++++++++++++++--------------------
hal/halx86/apic/apicsmp.c | 96 +++++++++++++++++++++++++++++++++++++
4 files changed, 175 insertions(+), 64 deletions(-)
diff --git a/hal/halx86/apic.cmake b/hal/halx86/apic.cmake
index 10857eeea8f..8868f40c1a2 100644
--- a/hal/halx86/apic.cmake
+++ b/hal/halx86/apic.cmake
@@ -6,6 +6,7 @@ list(APPEND HAL_APIC_ASM_SOURCE
list(APPEND HAL_APIC_SOURCE
apic/apic.c
apic/apictimer.c
+ apic/apicsmp.c
apic/halinit.c
apic/processor.c
apic/rtctimer.c
diff --git a/hal/halx86/apic/apic.c b/hal/halx86/apic/apic.c
index eae012d61b2..9f204bded55 100644
--- a/hal/halx86/apic/apic.c
+++ b/hal/halx86/apic/apic.c
@@ -136,19 +136,19 @@ ApicReadIORedirectionEntry(
FORCEINLINE
VOID
-ApicRequestInterrupt(IN UCHAR Vector, UCHAR TriggerMode)
+ApicRequestSelfInterrupt(IN UCHAR Vector, UCHAR TriggerMode)
{
- APIC_COMMAND_REGISTER CommandRegister;
+ APIC_INTERRUPT_COMMAND_REGISTER Icr;
/* Setup the command register */
- CommandRegister.Long0 = 0;
- CommandRegister.Vector = Vector;
- CommandRegister.MessageType = APIC_MT_Fixed;
- CommandRegister.TriggerMode = TriggerMode;
- CommandRegister.DestinationShortHand = APIC_DSH_Self;
+ Icr.Long0 = 0;
+ Icr.Vector = Vector;
+ Icr.MessageType = APIC_MT_Fixed;
+ Icr.TriggerMode = TriggerMode;
+ Icr.DestinationShortHand = APIC_DSH_Self;
/* Write the low dword to send the interrupt */
- ApicWrite(APIC_ICR0, CommandRegister.Long0);
+ ApicWrite(APIC_ICR0, Icr.Long0);
}
FORCEINLINE
@@ -615,7 +615,7 @@ FASTCALL
HalRequestSoftwareInterrupt(IN KIRQL Irql)
{
/* Convert irql to vector and request an interrupt */
- ApicRequestInterrupt(IrqlToSoftVector(Irql), APIC_TGM_Edge);
+ ApicRequestSelfInterrupt(IrqlToSoftVector(Irql), APIC_TGM_Edge);
}
VOID
@@ -745,7 +745,7 @@ HalBeginSystemInterrupt(
RedirReg = ApicReadIORedirectionEntry(Index);
/* Re-request the interrupt to be handled later */
- ApicRequestInterrupt(Vector, (UCHAR)RedirReg.TriggerMode);
+ ApicRequestSelfInterrupt(Vector, (UCHAR)RedirReg.TriggerMode);
}
else
{
@@ -753,7 +753,7 @@ HalBeginSystemInterrupt(
ASSERT(Index == APIC_RESERVED_VECTOR);
/* Re-request the interrupt to be handled later */
- ApicRequestInterrupt(Vector, APIC_TGM_Edge);
+ ApicRequestSelfInterrupt(Vector, APIC_TGM_Edge);
}
/* Pretend it was a spurious interrupt */
diff --git a/hal/halx86/apic/apicp.h b/hal/halx86/apic/apicp.h
index bd06a3a0cf6..a532fdcad8d 100644
--- a/hal/halx86/apic/apicp.h
+++ b/hal/halx86/apic/apicp.h
@@ -74,46 +74,52 @@
/* APIC Register Address Map */
-#define APIC_ID 0x0020 /* Local APIC ID Register (R/W) */
-#define APIC_VER 0x0030 /* Local APIC Version Register (R) */
-#define APIC_TPR 0x0080 /* Task Priority Register (R/W) */
-#define APIC_APR 0x0090 /* Arbitration Priority Register (R) */
-#define APIC_PPR 0x00A0 /* Processor Priority Register (R) */
-#define APIC_EOI 0x00B0 /* EOI Register (W) */
-#define APIC_RRR 0x00C0 /* Remote Read Register () */
-#define APIC_LDR 0x00D0 /* Logical Destination Register (R/W) */
-#define APIC_DFR 0x00E0 /* Destination Format Register (0-27 R, 28-31 R/W) */
-#define APIC_SIVR 0x00F0 /* Spurious Interrupt Vector Register (0-3 R, 4-9 R/W) */
-#define APIC_ISR 0x0100 /* Interrupt Service Register 0-255 (R) */
-#define APIC_TMR 0x0180 /* Trigger Mode Register 0-255 (R) */
-#define APIC_IRR 0x0200 /* Interrupt Request Register 0-255 (r) */
-#define APIC_ESR 0x0280 /* Error Status Register (R) */
-#define APIC_ICR0 0x0300 /* Interrupt Command Register 0-31 (R/W) */
-#define APIC_ICR1 0x0310 /* Interrupt Command Register 32-63 (R/W) */
-#define APIC_TMRLVTR 0x0320 /* Timer Local Vector Table (R/W) */
-#define APIC_THRMLVTR 0x0330 /* Thermal Local Vector Table */
-#define APIC_PCLVTR 0x0340 /* Performance Counter Local Vector Table (R/W) */
-#define APIC_LINT0 0x0350 /* LINT0 Local Vector Table (R/W) */
-#define APIC_LINT1 0x0360 /* LINT1 Local Vector Table (R/W) */
-#define APIC_ERRLVTR 0x0370 /* Error Local Vector Table (R/W) */
-#define APIC_TICR 0x0380 /* Initial Count Register for Timer (R/W) */
-#define APIC_TCCR 0x0390 /* Current Count Register for Timer (R) */
-#define APIC_TDCR 0x03E0 /* Timer Divide Configuration Register (R/W) */
-#define APIC_EAFR 0x0400 /* extended APIC Feature register (R/W) */
-#define APIC_EACR 0x0410 /* Extended APIC Control Register (R/W) */
-#define APIC_SEOI 0x0420 /* Specific End Of Interrupt Register (W) */
-#define APIC_EXT0LVTR 0x0500 /* Extended Interrupt 0 Local Vector Table */
-#define APIC_EXT1LVTR 0x0510 /* Extended Interrupt 1 Local Vector Table */
-#define APIC_EXT2LVTR 0x0520 /* Extended Interrupt 2 Local Vector Table */
-#define APIC_EXT3LVTR 0x0530 /* Extended Interrupt 3 Local Vector Table */
+typedef enum _APIC_REGISTER
+{
+ APIC_ID = 0x0020, /* Local APIC ID Register (R/W) */
+ APIC_VER = 0x0030, /* Local APIC Version Register (R) */
+ APIC_TPR = 0x0080, /* Task Priority Register (R/W) */
+ APIC_APR = 0x0090, /* Arbitration Priority Register (R) */
+ APIC_PPR = 0x00A0, /* Processor Priority Register (R) */
+ APIC_EOI = 0x00B0, /* EOI Register (W) */
+ APIC_RRR = 0x00C0, /* Remote Read Register () */
+ APIC_LDR = 0x00D0, /* Logical Destination Register (R/W) */
+ APIC_DFR = 0x00E0, /* Destination Format Register (0-27 R, 28-31 R/W) */
+ APIC_SIVR = 0x00F0, /* Spurious Interrupt Vector Register (0-3 R, 4-9 R/W) */
+ APIC_ISR = 0x0100, /* Interrupt Service Register 0-255 (R) */
+ APIC_TMR = 0x0180, /* Trigger Mode Register 0-255 (R) */
+ APIC_IRR = 0x0200, /* Interrupt Request Register 0-255 (r) */
+ APIC_ESR = 0x0280, /* Error Status Register (R) */
+ APIC_ICR0 = 0x0300, /* Interrupt Command Register 0-31 (R/W) */
+ APIC_ICR1 = 0x0310, /* Interrupt Command Register 32-63 (R/W) */
+ APIC_TMRLVTR = 0x0320, /* Timer Local Vector Table (R/W) */
+ APIC_THRMLVTR = 0x0330, /* Thermal Local Vector Table */
+ APIC_PCLVTR = 0x0340, /* Performance Counter Local Vector Table (R/W) */
+ APIC_LINT0 = 0x0350, /* LINT0 Local Vector Table (R/W) */
+ APIC_LINT1 = 0x0360, /* LINT1 Local Vector Table (R/W) */
+ APIC_ERRLVTR = 0x0370, /* Error Local Vector Table (R/W) */
+ APIC_TICR = 0x0380, /* Initial Count Register for Timer (R/W) */
+ APIC_TCCR = 0x0390, /* Current Count Register for Timer (R) */
+ APIC_TDCR = 0x03E0, /* Timer Divide Configuration Register (R/W) */
+ APIC_EAFR = 0x0400, /* extended APIC Feature register (R/W) */
+ APIC_EACR = 0x0410, /* Extended APIC Control Register (R/W) */
+ APIC_SEOI = 0x0420, /* Specific End Of Interrupt Register (W) */
+ APIC_EXT0LVTR = 0x0500, /* Extended Interrupt 0 Local Vector Table */
+ APIC_EXT1LVTR = 0x0510, /* Extended Interrupt 1 Local Vector Table */
+ APIC_EXT2LVTR = 0x0520, /* Extended Interrupt 2 Local Vector Table */
+ APIC_EXT3LVTR = 0x0530 /* Extended Interrupt 3 Local Vector Table */
+} APIC_REGISTER;
#define MSR_APIC_BASE 0x0000001B
#define IOAPIC_PHYS_BASE 0xFEC00000
#define APIC_CLOCK_INDEX 8
#define ApicLogicalId(Cpu) ((UCHAR)(1<< Cpu))
-/* Message Type */
-enum
+/* The following definitions are based on AMD documentation.
+ They differ slightly in Intel documentation. */
+
+/* Message Type (Intel: "Delivery Mode") */
+typedef enum _APIC_MT
{
APIC_MT_Fixed = 0,
APIC_MT_LowestPriority = 1,
@@ -123,40 +129,48 @@ enum
APIC_MT_INIT = 5,
APIC_MT_Startup = 6,
APIC_MT_ExtInt = 7,
-};
+} APIC_MT;
/* Trigger Mode */
-enum
+typedef enum _APIC_TGM
{
APIC_TGM_Edge,
APIC_TGM_Level
-};
+} APIC_TGM;
-/* Delivery Mode */
-enum
+/* Destination Mode */
+typedef enum _APIC_DM
{
APIC_DM_Physical,
APIC_DM_Logical
-};
+} APIC_DM;
/* Destination Short Hand */
-enum
+typedef enum _APIC_DSH
{
APIC_DSH_Destination,
APIC_DSH_Self,
APIC_DSH_AllIncludingSelf,
APIC_DSH_AllExclusingSelf
-};
+} APIC_DSH;
/* Write Constants */
-enum
+typedef enum _APIC_DF
{
APIC_DF_Flat = 0xFFFFFFFF,
APIC_DF_Cluster = 0x0FFFFFFF
-};
+} APIC_DF;
+
+/* Remote Read Status */
+typedef enum _APIC_RRS
+{
+ APIC_RRS_Invalid = 0,
+ APIC_RRS_Pending = 1,
+ APIC_RRS_Done = 2
+} APIC_RRS;
/* Timer Constants */
-enum
+enum _TIMER_DV
{
TIMER_DV_DivideBy2 = 0,
TIMER_DV_DivideBy4 = 1,
@@ -166,7 +180,7 @@ enum
TIMER_DV_DivideBy64 = 9,
TIMER_DV_DivideBy128 = 10,
TIMER_DV_DivideBy1 = 11,
-};
+} TIMER_DV;
#include <pshpack1.h>
typedef union _APIC_BASE_ADRESS_REGISTER
@@ -220,7 +234,7 @@ typedef union _APIC_EXTENDED_CONTROL_REGISTER
};
} APIC_EXTENDED_CONTROL_REGISTER;
-typedef union _APIC_COMMAND_REGISTER
+typedef union _APIC_INTERRUPT_COMMAND_REGISTER
{
UINT64 LongLong;
struct
@@ -237,12 +251,12 @@ typedef union _APIC_COMMAND_REGISTER
UINT64 ReservedMBZ:1;
UINT64 Level:1;
UINT64 TriggerMode:1;
- UINT64 RemoteReadStatus:2;
+ UINT64 RemoteReadStatus:2; /* Intel: Reserved */
UINT64 DestinationShortHand:2;
UINT64 Reserved2MBZ:36;
UINT64 Destination:8;
};
-} APIC_COMMAND_REGISTER;
+} APIC_INTERRUPT_COMMAND_REGISTER;
typedef union _LVT_REGISTER
{
@@ -304,16 +318,16 @@ typedef union _IOAPIC_REDIRECTION_REGISTER
FORCEINLINE
ULONG
-ApicRead(ULONG Offset)
+ApicRead(APIC_REGISTER Register)
{
- return READ_REGISTER_ULONG((PULONG)(APIC_BASE + Offset));
+ return READ_REGISTER_ULONG((PULONG)(APIC_BASE + Register));
}
FORCEINLINE
VOID
-ApicWrite(ULONG Offset, ULONG Value)
+ApicWrite(APIC_REGISTER Register, ULONG Value)
{
- WRITE_REGISTER_ULONG((PULONG)(APIC_BASE + Offset), Value);
+ WRITE_REGISTER_ULONG((PULONG)(APIC_BASE + Register), Value);
}
VOID
diff --git a/hal/halx86/apic/apicsmp.c b/hal/halx86/apic/apicsmp.c
new file mode 100644
index 00000000000..6379922dda9
--- /dev/null
+++ b/hal/halx86/apic/apicsmp.c
@@ -0,0 +1,96 @@
+/*
+ * PROJECT: ReactOS HAL
+ * LICENSE: GPL-2.0-or-later (
https://spdx.org/licenses/GPL-2.0-or-later)
+ * FILE: hal/halx86/apic/apicsmp.c
+ * PURPOSE: SMP specific APIC code
+ * PROGRAMMERS: Copyright 2021 Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <hal.h>
+#include "apicp.h"
+#define NDEBUG
+#include <debug.h>
+
+/* INTERNAL FUNCTIONS *********************************************************/
+
+/*!
+ \param Vector - Specifies the interrupt vector to be delivered.
+
+ \param MessageType - Specifies the message type sent to the CPU core
+ interrupt handler. This can be one of the following values:
+ APIC_MT_Fixed - Delivers an interrupt to the target local APIC
+ specified in Destination field.
+ APIC_MT_LowestPriority - Delivers an interrupt to the local APIC
+ executing at the lowest priority of all local APICs.
+ APIC_MT_SMI - Delivers an SMI interrupt to target local APIC(s).
+ APIC_MT_RemoteRead - Delivers a read request to read an APIC register
+ in the target local APIC specified in Destination field.
+ APIC_MT_NMI - Delivers a non-maskable interrupt to the target local
+ APIC specified in the Destination field. Vector is ignored.
+ APIC_MT_INIT - Delivers an INIT request to the target local APIC(s)
+ specified in the Destination field. TriggerMode must be
+ APIC_TGM_Edge, Vector must be 0.
+ APIC_MT_Startup - Delivers a start-up request (SIPI) to the target
+ local APIC(s) specified in Destination field. Vector specifies
+ the startup address.
+ APIC_MT_ExtInt - Delivers an external interrupt to the target local
+ APIC specified in Destination field.
+
+ \param TriggerMode - The trigger mode of the interrupt. Can be:
+ APIC_TGM_Edge - The interrupt is edge triggered.
+ APIC_TGM_Level - The interrupt is level triggered.
+
+ \param DestinationShortHand - Specifies where to send the interrupt.
+ APIC_DSH_Destination
+ APIC_DSH_Self
+ APIC_DSH_AllIncludingSelf
+ APIC_DSH_AllExclusingSelf
+
+ \see "AMD64 Architecture Programmer's Manual Volume 2 System
Programming"
+ Chapter 16 "Advanced Programmable Interrupt Controller (APIC)"
+ 16.5 "Interprocessor Interrupts (IPI)"
+
+ */
+FORCEINLINE
+VOID
+ApicRequestGlobalInterrupt(
+ _In_ UCHAR DestinationProcessor,
+ _In_ UCHAR Vector,
+ _In_ APIC_MT MessageType,
+ _In_ APIC_TGM TriggerMode,
+ _In_ APIC_DSH DestinationShortHand)
+{
+ APIC_INTERRUPT_COMMAND_REGISTER Icr;
+
+ /* Setup the command register */
+ Icr.LongLong = 0;
+ Icr.Vector = Vector;
+ Icr.MessageType = MessageType;
+ Icr.DestinationMode = APIC_DM_Physical;
+ Icr.DeliveryStatus = 0;
+ Icr.Level = 0;
+ Icr.TriggerMode = TriggerMode;
+ Icr.RemoteReadStatus = 0;
+ Icr.DestinationShortHand = DestinationShortHand;
+ Icr.Destination = DestinationProcessor;
+
+ /* Write the low dword last to send the interrupt */
+ ApicWrite(APIC_ICR1, Icr.Long1);
+ ApicWrite(APIC_ICR0, Icr.Long0);
+}
+
+
+/* SMP SUPPORT FUNCTIONS ******************************************************/
+
+// Should be called by SMP version of HalRequestIpi
+VOID
+NTAPI
+HalpRequestIpi(KAFFINITY TargetProcessors)
+{
+ UNIMPLEMENTED;
+ __debugbreak();
+}
+
+// APIC specific SMP code here