[HAL:APIC] Improve code

- Use an enum for the APIC registers
- Add support routine for SMP.
This commit is contained in:
Timo Kreuzer 2021-06-22 12:53:23 +02:00
parent e8277e51e2
commit 16e988d108
4 changed files with 175 additions and 64 deletions

View file

@ -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

View file

@ -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 */

View file

@ -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

96
hal/halx86/apic/apicsmp.c Normal file
View file

@ -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