| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org> |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions |
| 8 | * are met: |
| 9 | * 1. Redistributions of source code must retain the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer. |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer in the |
| 13 | * documentation and/or other materials provided with the distribution. |
| 14 | * |
| 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 25 | * SUCH DAMAGE. |
| 26 | */ |
| 27 | |
| 28 | #ifndef _X86_APICVAR_H_ |
| 29 | #define _X86_APICVAR_H_ |
| 30 | |
| 31 | /* |
| 32 | * Local && I/O APIC variable definitions. |
| 33 | */ |
| 34 | |
| 35 | /* |
| 36 | * Layout of local APIC interrupt vectors: |
| 37 | * |
| 38 | *	0xff (255) +-------------+ |
| 39 | * | | 15 (Spurious / IPIs / Local Interrupts) |
| 40 | *	0xf0 (240) +-------------+ |
| 41 | * | | 14 (I/O Interrupts / Timer) |
| 42 | *	0xe0 (224) +-------------+ |
| 43 | * | | 13 (I/O Interrupts) |
| 44 | *	0xd0 (208) +-------------+ |
| 45 | * | | 12 (I/O Interrupts) |
| 46 | *	0xc0 (192) +-------------+ |
| 47 | * | | 11 (I/O Interrupts) |
| 48 | *	0xb0 (176) +-------------+ |
| 49 | * | | 10 (I/O Interrupts) |
| 50 | *	0xa0 (160) +-------------+ |
| 51 | * | | 9 (I/O Interrupts) |
| 52 | *	0x90 (144) +-------------+ |
| 53 | * | | 8 (I/O Interrupts / System Calls) |
| 54 | *	0x80 (128) +-------------+ |
| 55 | * | | 7 (I/O Interrupts) |
| 56 | *	0x70 (112) +-------------+ |
| 57 | * | | 6 (I/O Interrupts) |
| 58 | *	0x60 (96) +-------------+ |
| 59 | * | | 5 (I/O Interrupts) |
| 60 | *	0x50 (80) +-------------+ |
| 61 | * | | 4 (I/O Interrupts) |
| 62 | *	0x40 (64) +-------------+ |
| 63 | * | | 3 (I/O Interrupts) |
| 64 | *	0x30 (48) +-------------+ |
| 65 | * | | 2 (ATPIC Interrupts) |
| 66 | *	0x20 (32) +-------------+ |
| 67 | * | | 1 (Exceptions, traps, faults, etc.) |
| 68 | *	0x10 (16) +-------------+ |
| 69 | * | | 0 (Exceptions, traps, faults, etc.) |
| 70 | *	0x00 (0) +-------------+ |
| 71 | * |
| 72 | * Note: 0x80 needs to be handled specially and not allocated to an |
| 73 | * I/O device! |
| 74 | */ |
| 75 | |
| 76 | #define	xAPIC_MAX_APIC_ID	0xfe |
| 77 | #define	xAPIC_ID_ALL		0xff |
| 78 | #define	MAX_APIC_ID		0x800 |
| 79 | #define	APIC_ID_ALL		0xffffffff |
| 80 | |
| 81 | /* |
| 82 | * The 0xff ID is used for broadcast IPIs for local APICs when not using |
| 83 | * x2APIC. IPIs are not sent to I/O APICs so it's acceptable for an I/O APIC |
| 84 | * to use that ID. |
| 85 | */ |
| 86 | #define	IOAPIC_MAX_ID		0xff |
| 87 | |
| 88 | /* I/O Interrupts are used for external devices such as ISA, PCI, etc. */ |
| 89 | #define	APIC_IO_INTS	(IDT_IO_INTS + 16) |
| 90 | #define	APIC_NUM_IOINTS	191 |
| 91 | |
| 92 | /* The timer interrupt is used for clock handling and drives hardclock, etc. */ |
| 93 | #define	APIC_TIMER_INT	(APIC_IO_INTS + APIC_NUM_IOINTS) |
| 94 | |
| 95 | /* |
| 96 | ********************* !!! WARNING !!! ****************************** |
| 97 | * Each local apic has an interrupt receive fifo that is two entries deep |
| 98 | * for each interrupt priority class (higher 4 bits of interrupt vector). |
| 99 | * Once the fifo is full the APIC can no longer receive interrupts for this |
| 100 | * class and sending IPIs from other CPUs will be blocked. |
| 101 | * To avoid deadlocks there should be no more than two IPI interrupts |
| 102 | * pending at the same time. |
| 103 | * Currently this is guaranteed by dividing the IPIs in two groups that have |
| 104 | * each at most one IPI interrupt pending. The first group is protected by the |
| 105 | * smp_ipi_mtx and waits for the completion of the IPI (Only one IPI user |
| 106 | * at a time) The second group uses a single interrupt and a bitmap to avoid |
| 107 | * redundant IPI interrupts. |
| 108 | */ |
| 109 | |
| 110 | /* Interrupts for local APIC LVT entries other than the timer. */ |
| 111 | #define	APIC_LOCAL_INTS	240 |
| 112 | #define	APIC_ERROR_INT	APIC_LOCAL_INTS |
| 113 | #define	APIC_THERMAL_INT (APIC_LOCAL_INTS + 1) |
| 114 | #define	APIC_CMC_INT	(APIC_LOCAL_INTS + 2) |
| 115 | #define	APIC_IPI_INTS	(APIC_LOCAL_INTS + 3) |
| 116 | |
| 117 | #define	IPI_RENDEZVOUS	(APIC_IPI_INTS)		/* Inter-CPU rendezvous. */ |
| 118 | #define	IPI_INVLOP	(APIC_IPI_INTS + 1)	/* TLB Shootdown IPIs, amd64 */ |
| 119 | #define	IPI_INVLTLB	(APIC_IPI_INTS + 1)	/* TLB Shootdown IPIs, i386 */ |
| 120 | #define	IPI_INVLPG	(APIC_IPI_INTS + 2) |
| 121 | #define	IPI_INVLRNG	(APIC_IPI_INTS + 3) |
| 122 | #define	IPI_INVLCACHE	(APIC_IPI_INTS + 4) |
| 123 | /* Vector to handle bitmap based IPIs */ |
| 124 | #define	IPI_BITMAP_VECTOR	(APIC_IPI_INTS + 5) |
| 125 | |
| 126 | /* IPIs handled by IPI_BITMAP_VECTOR */ |
| 127 | #define	IPI_AST		0 	/* Generate software trap. */ |
| 128 | #define IPI_PREEMPT 1 |
| 129 | #define IPI_HARDCLOCK 2 |
| 130 | #define	IPI_TRACE	3	/* Collect stack trace. */ |
| 131 | #define	IPI_BITMAP_LAST IPI_TRACE |
| 132 | #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST) |
| 133 | |
| 134 | #define	IPI_STOP	(APIC_IPI_INTS + 6)	/* Stop CPU until restarted. */ |
| 135 | #define	IPI_SUSPEND	(APIC_IPI_INTS + 7)	/* Suspend CPU until restarted. */ |
| 136 | #define	IPI_SWI		(APIC_IPI_INTS + 8)	/* Run clk_intr_event. */ |
| 137 | #define	IPI_DYN_FIRST	(APIC_IPI_INTS + 9) |
| 138 | #define	IPI_DYN_LAST	(254)			/* IPIs allocated at runtime */ |
| 139 | |
| 140 | /* |
| 141 | * IPI_STOP_HARD does not need to occupy a slot in the IPI vector space since |
| 142 | * it is delivered using an NMI anyways. |
| 143 | */ |
| 144 | #define	IPI_NMI_FIRST	255 |
| 145 | #define	IPI_STOP_HARD	255			/* Stop CPU with a NMI. */ |
| 146 | |
| 147 | /* |
| 148 | * The spurious interrupt can share the priority class with the IPIs since |
| 149 | * it is not a normal interrupt. (Does not use the APIC's interrupt fifo) |
| 150 | */ |
| 151 | #define	APIC_SPURIOUS_INT 255 |
| 152 | |
| 153 | #ifndef LOCORE |
| 154 | |
| 155 | #define	APIC_IPI_DEST_SELF	-1 |
| 156 | #define	APIC_IPI_DEST_ALL	-2 |
| 157 | #define	APIC_IPI_DEST_OTHERS	-3 |
| 158 | |
| 159 | #define	APIC_BUS_UNKNOWN	-1 |
| 160 | #define	APIC_BUS_ISA		0 |
| 161 | #define	APIC_BUS_EISA		1 |
| 162 | #define	APIC_BUS_PCI		2 |
| 163 | #define	APIC_BUS_MAX		APIC_BUS_PCI |
| 164 | |
| 165 | #define	IRQ_EXTINT		-1 |
| 166 | #define	IRQ_NMI			-2 |
| 167 | #define	IRQ_SMI			-3 |
| 168 | #define	IRQ_DISABLED		-4 |
| 169 | |
| 170 | /* |
| 171 | * An APIC enumerator is a pseudo bus driver that enumerates APIC's including |
| 172 | * CPU's and I/O APIC's. |
| 173 | */ |
| 174 | struct apic_enumerator { |
| 175 | 	const char *apic_name; |
| 176 | 	int (*apic_probe)(void); |
| 177 | 	int (*apic_probe_cpus)(void); |
| 178 | 	int (*apic_setup_local)(void); |
| 179 | 	int (*apic_setup_io)(void); |
| 180 | 	SLIST_ENTRY(apic_enumerator) apic_next; |
| 181 | }; |
| 182 | |
| 183 | inthand_t |
| 184 | 	IDTVEC(apic_isr1), IDTVEC(apic_isr2), IDTVEC(apic_isr3), |
| 185 | 	IDTVEC(apic_isr4), IDTVEC(apic_isr5), IDTVEC(apic_isr6), |
| 186 | 	IDTVEC(apic_isr7), IDTVEC(cmcint), IDTVEC(errorint), |
| 187 | 	IDTVEC(spuriousint), IDTVEC(timerint), |
| 188 | 	IDTVEC(apic_isr1_pti), IDTVEC(apic_isr2_pti), IDTVEC(apic_isr3_pti), |
| 189 | 	IDTVEC(apic_isr4_pti), IDTVEC(apic_isr5_pti), IDTVEC(apic_isr6_pti), |
| 190 | 	IDTVEC(apic_isr7_pti), IDTVEC(cmcint_pti), IDTVEC(errorint_pti), |
| 191 | 	IDTVEC(spuriousint_pti), IDTVEC(timerint_pti); |
| 192 | |
| 193 | extern vm_paddr_t lapic_paddr; |
| 194 | extern int *apic_cpuids; |
| 195 | |
| 196 | /* Allow to replace the lapic_ipi_vectored implementation. */ |
| 197 | extern void (*ipi_vectored)(u_int, int); |
| 198 | |
| 199 | typedef struct ioapic *ioapic_drv_t; |
| 200 | |
| 201 | void	apic_register_enumerator(struct apic_enumerator *enumerator); |
| 202 | ioapic_drv_t	ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase); |
| 203 | int	ioapic_disable_pin(ioapic_drv_t cookie, u_int pin); |
| 204 | int	ioapic_get_vector(ioapic_drv_t cookie, u_int pin); |
| 205 | void	ioapic_register(ioapic_drv_t cookie); |
| 206 | int	ioapic_remap_vector(ioapic_drv_t cookie, u_int pin, int vector); |
| 207 | int	ioapic_set_bus(ioapic_drv_t cookie, u_int pin, int bus_type); |
| 208 | int	ioapic_set_extint(ioapic_drv_t cookie, u_int pin); |
| 209 | int	ioapic_set_nmi(ioapic_drv_t cookie, u_int pin); |
| 210 | int	ioapic_set_polarity(ioapic_drv_t cookie, u_int pin, enum intr_polarity pol); |
| 211 | int	ioapic_set_triggermode(ioapic_drv_t cookie, u_int pin, |
| 212 | 	 enum intr_trigger trigger); |
| 213 | int	ioapic_set_smi(ioapic_drv_t cookie, u_int pin); |
| 214 | |
| 215 | void	lapic_create(u_int apic_id, int boot_cpu); |
| 216 | void	lapic_init(vm_paddr_t addr); |
| 217 | void	lapic_xapic_mode(void); |
| 218 | bool	lapic_is_x2apic(void); |
| 219 | void	lapic_setup(int boot); |
| 220 | void	lapic_dump(const char *str); |
| 221 | void	lapic_disable(void); |
| 222 | void	lapic_eoi(void); |
| 223 | int	lapic_id(void); |
| 224 | int	lapic_intr_pending(u_int vector); |
| 225 | /* XXX: UNUSED */ |
| 226 | void	lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id); |
| 227 | u_int	apic_cpuid(u_int apic_id); |
| 228 | u_int	apic_alloc_vector(u_int apic_id, u_int irq); |
| 229 | u_int	apic_alloc_vectors(u_int apic_id, u_int *irqs, u_int count, u_int align); |
| 230 | void	apic_enable_vector(u_int apic_id, u_int vector); |
| 231 | void	apic_disable_vector(u_int apic_id, u_int vector); |
| 232 | void	apic_free_vector(u_int apic_id, u_int vector, u_int irq); |
| 233 | void	lapic_calibrate_timer(void); |
| 234 | int	lapic_enable_pcint(void); |
| 235 | void	lapic_disable_pcint(void); |
| 236 | void	lapic_reenable_pcint(void); |
| 237 | void	lapic_enable_cmc(void); |
| 238 | int	lapic_enable_mca_elvt(void); |
| 239 | void	lapic_ipi_raw(register_t icrlo, u_int dest); |
| 240 | |
| 241 | static inline void |
| 242 | lapic_ipi_vectored(u_int vector, int dest) |
| 243 | { |
| 244 | |
| 245 | 	ipi_vectored(vector, dest); |
| 246 | } |
| 247 | |
| 248 | int	lapic_ipi_wait(int delay); |
| 249 | int	lapic_ipi_alloc(inthand_t *ipifunc); |
| 250 | void	lapic_ipi_free(int vector); |
| 251 | int	lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked); |
| 252 | int	lapic_set_lvt_mode(u_int apic_id, u_int lvt, u_int32_t mode); |
| 253 | int	lapic_set_lvt_polarity(u_int apic_id, u_int lvt, |
| 254 | 	 enum intr_polarity pol); |
| 255 | int	lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, |
| 256 | 	 enum intr_trigger trigger); |
| 257 | void	lapic_handle_cmc(void); |
| 258 | void	lapic_handle_error(void); |
| 259 | void	lapic_handle_intr(int vector, struct trapframe *frame); |
| 260 | void	lapic_handle_timer(struct trapframe *frame); |
| 261 | |
| 262 | int	ioapic_get_rid(u_int apic_id, uint16_t *ridp); |
| 263 | device_t ioapic_get_dev(u_int apic_id); |
| 264 | |
| 265 | extern int x2apic_mode; |
| 266 | extern int lapic_eoi_suppression; |
| 267 | |
| 268 | #ifdef _SYS_SYSCTL_H_ |
| 269 | SYSCTL_DECL(_hw_apic); |
| 270 | #endif |
| 271 | |
| 272 | #endif /* !LOCORE */ |
| 273 | #endif /* _X86_APICVAR_H_ */ |