https://git.reactos.org/?p=reactos.git;a=commitdiff;h=16e988d10858ee1dd14d6e...
commit 16e988d10858ee1dd14d6ea17056797a18fa0cff Author: Timo Kreuzer timo.kreuzer@reactos.org AuthorDate: Tue Jun 22 12:53:23 2021 +0200 Commit: Timo Kreuzer timo.kreuzer@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@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