2 * APIC handling routines. APIC is a requirement for SMP
4 #include "kernel/kernel.h"
8 #include <minix/portio.h>
10 #include <minix/syslib.h>
11 #include <machine/cmos.h>
13 #include "arch_proto.h"
15 #include <minix/u64.h>
19 #include "kernel/clock.h"
26 #include "kernel/watchdog.h"
29 #define APIC_ENABLE 0x100
30 #define APIC_FOCUS_DISABLED (1 << 9)
33 #define APIC_TDCR_2 0x00
34 #define APIC_TDCR_4 0x01
35 #define APIC_TDCR_8 0x02
36 #define APIC_TDCR_16 0x03
37 #define APIC_TDCR_32 0x08
38 #define APIC_TDCR_64 0x09
39 #define APIC_TDCR_128 0x0a
40 #define APIC_TDCR_1 0x0b
42 #define IS_SET(mask) (mask)
43 #define IS_CLEAR(mask) 0
45 #define APIC_LVTT_VECTOR_MASK 0x000000FF
46 #define APIC_LVTT_DS_PENDING (1 << 12)
47 #define APIC_LVTT_MASK (1 << 16)
48 #define APIC_LVTT_TM (1 << 17)
50 #define APIC_LVT_IIPP_MASK 0x00002000
51 #define APIC_LVT_IIPP_AH 0x00002000
52 #define APIC_LVT_IIPP_AL 0x00000000
54 #define APIC_LVT_TM_ONESHOT IS_CLEAR(APIC_LVTT_TM)
55 #define APIC_LVT_TM_PERIODIC IS_SET(APIC_LVTT_TM)
57 #define IOAPIC_REGSEL 0x0
58 #define IOAPIC_RW 0x10
60 #define APIC_ICR_DM_MASK 0x00000700
61 #define APIC_ICR_VECTOR APIC_LVTT_VECTOR_MASK
62 #define APIC_ICR_DM_FIXED (0 << 8)
63 #define APIC_ICR_DM_LOWEST_PRIORITY (1 << 8)
64 #define APIC_ICR_DM_SMI (2 << 8)
65 #define APIC_ICR_DM_RESERVED (3 << 8)
66 #define APIC_ICR_DM_NMI (4 << 8)
67 #define APIC_ICR_DM_INIT (5 << 8)
68 #define APIC_ICR_DM_STARTUP (6 << 8)
69 #define APIC_ICR_DM_EXTINT (7 << 8)
71 #define APIC_ICR_DM_PHYSICAL (0 << 11)
72 #define APIC_ICR_DM_LOGICAL (1 << 11)
74 #define APIC_ICR_DELIVERY_PENDING (1 << 12)
76 #define APIC_ICR_INT_POLARITY (1 << 13)
77 #define APIC_ICR_INTPOL_LOW IS_SET(APIC_ICR_INT_POLARITY)
78 #define APIC_ICR_INTPOL_HIGH IS_CLEAR(APIC_ICR_INT_POLARITY)
80 #define APIC_ICR_LEVEL_ASSERT (1 << 14)
81 #define APIC_ICR_LEVEL_DEASSERT (0 << 14)
83 #define APIC_ICR_TRIGGER (1 << 15)
84 #define APIC_ICR_TM_LEVEL IS_CLEAR(APIC_ICR_TRIGGER)
85 #define APIC_ICR_TM_EDGE IS_CLEAR(APIC_ICR_TRIGGER)
87 #define APIC_ICR_INT_MASK (1 << 16)
89 #define APIC_ICR_DEST_FIELD (0 << 18)
90 #define APIC_ICR_DEST_SELF (1 << 18)
91 #define APIC_ICR_DEST_ALL (2 << 18)
92 #define APIC_ICR_DEST_ALL_BUT_SELF (3 << 18)
94 #define IA32_APIC_BASE 0x1b
95 #define IA32_APIC_BASE_ENABLE_BIT 11
97 /* FIXME we should spread the irqs across as many priority levels as possible
99 #define LAPIC_VECTOR(irq) (IRQ0_VECTOR +(irq))
101 #define IOAPIC_IRQ_STATE_MASKED 0x1
103 /* currently only 2 interrupt priority levels are used */
108 struct io_apic io_apic
[MAX_NR_IOAPICS
];
112 typedef void (* eoi_method_t
)(struct irq
*);
115 struct io_apic
* ioa
;
122 static struct irq io_apic_irq
[NR_IRQ_VECTORS
];
125 * to make APIC work if SMP is not configured, we need to set the maximal number
126 * of CPUS to 1, cpuid to return 0 and the current cpu is always BSP
130 #include "kernel/smp.h"
134 #include "kernel/spinlock.h"
137 #define lapic_write_icr1(val) lapic_write(LAPIC_ICR1, val)
138 #define lapic_write_icr2(val) lapic_write(LAPIC_ICR2, val)
140 #define lapic_read_icr1(x) lapic_read(LAPIC_ICR1)
141 #define lapic_read_icr2(x) lapic_read(LAPIC_ICR2)
143 #define is_boot_apic(apicid) ((apicid) == bsp_lapic_id)
145 #define VERBOSE_APIC(x) x
148 u32_t lapic_addr_vaddr
;
149 vir_bytes lapic_addr
;
150 vir_bytes lapic_eoi_addr
;
153 static volatile unsigned probe_ticks
;
154 static u64_t tsc0
, tsc1
;
155 static u32_t lapic_tctr0
, lapic_tctr1
;
157 static unsigned apic_imcrp
;
158 static const unsigned nlints
= 0;
166 * FIXME this should be a cpulocal variable but there are some problems with
167 * arch specific cpulocals. As this variable is write-once-read-only it is ok to
168 * have at as an array until we resolve the cpulocals properly
170 static u32_t lapic_bus_freq
[CONFIG_MAX_CPUS
];
171 /* the probe period will be roughly 100ms */
172 #define PROBE_TICKS (system_hz / 10)
174 #define IOAPIC_IOREGSEL 0x0
175 #define IOAPIC_IOWIN 0x10
177 static u32_t
ioapic_read(u32_t ioa_base
, u32_t reg
)
179 *((volatile u32_t
*)(ioa_base
+ IOAPIC_IOREGSEL
)) = (reg
& 0xff);
180 return *(volatile u32_t
*)(ioa_base
+ IOAPIC_IOWIN
);
183 static void ioapic_write(u32_t ioa_base
, u8_t reg
, u32_t val
)
185 *((volatile u32_t
*)(ioa_base
+ IOAPIC_IOREGSEL
)) = reg
;
186 *((volatile u32_t
*)(ioa_base
+ IOAPIC_IOWIN
)) = val
;
189 void lapic_microsec_sleep(unsigned count
);
190 void apic_idt_init(const int reset
);
192 static void ioapic_enable_pin(vir_bytes ioapic_addr
, int pin
)
194 u32_t lo
= ioapic_read(ioapic_addr
, IOAPIC_REDIR_TABLE
+ pin
* 2);
196 lo
&= ~APIC_ICR_INT_MASK
;
197 ioapic_write(ioapic_addr
, IOAPIC_REDIR_TABLE
+ pin
* 2, lo
);
200 static void ioapic_disable_pin(vir_bytes ioapic_addr
, int pin
)
202 u32_t lo
= ioapic_read(ioapic_addr
, IOAPIC_REDIR_TABLE
+ pin
* 2);
204 lo
|= APIC_ICR_INT_MASK
;
205 ioapic_write(ioapic_addr
, IOAPIC_REDIR_TABLE
+ pin
* 2, lo
);
209 static void ioapic_redirt_entry_read(void * ioapic_addr
,
214 *lo
= ioapic_read((u32_t
)ioapic_addr
, (u8_t
) (IOAPIC_REDIR_TABLE
+ entry
* 2));
215 *hi
= ioapic_read((u32_t
)ioapic_addr
, (u8_t
) (IOAPIC_REDIR_TABLE
+ entry
* 2 + 1));
220 static void ioapic_redirt_entry_write(void * ioapic_addr
,
226 VERBOSE_APIC(printf("IO apic redir entry %3d "
227 "write 0x%08x 0x%08x\n", entry
, hi
, lo
));
229 ioapic_write((u32_t
)ioapic_addr
, (u8_t
) (IOAPIC_REDIR_TABLE
+ entry
* 2 + 1), hi
);
230 ioapic_write((u32_t
)ioapic_addr
, (u8_t
) (IOAPIC_REDIR_TABLE
+ entry
* 2), lo
);
233 #define apic_read_tmr_vector(vec) \
234 lapic_read(LAPIC_TMR + 0x10 * ((vec) >> 5))
236 #define apic_read_irr_vector(vec) \
237 lapic_read(LAPIC_IRR + 0x10 * ((vec) >> 5))
239 #define apic_read_isr_vector(vec) \
240 lapic_read(LAPIC_ISR + 0x10 * ((vec) >> 5))
242 #define lapic_test_delivery_val(val, vector) ((val) & (1 << ((vector) & 0x1f)))
244 static void ioapic_eoi_level(struct irq
* irq
)
248 tmr
= apic_read_tmr_vector(irq
->vector
);
252 * test if it was a level or edge triggered interrupt. If delivered as
253 * edge exec the workaround for broken chipsets
255 if (!lapic_test_delivery_val(tmr
, irq
->vector
)) {
259 panic("EDGE instead of LEVEL!");
261 lo
= ioapic_read(irq
->ioa
->addr
,
262 IOAPIC_REDIR_TABLE
+ irq
->pin
* 2);
264 is_masked
= lo
& APIC_ICR_INT_MASK
;
266 /* set mask and edge */
267 lo
|= APIC_ICR_INT_MASK
;
268 lo
&= ~APIC_ICR_TRIGGER
;
269 ioapic_write(irq
->ioa
->addr
,
270 IOAPIC_REDIR_TABLE
+ irq
->pin
* 2, lo
);
272 /* set back to level and restore the mask bit */
273 lo
= ioapic_read(irq
->ioa
->addr
,
274 IOAPIC_REDIR_TABLE
+ irq
->pin
* 2);
276 lo
|= APIC_ICR_TRIGGER
;
278 lo
|= APIC_ICR_INT_MASK
;
280 lo
&= ~APIC_ICR_INT_MASK
;
281 ioapic_write(irq
->ioa
->addr
,
282 IOAPIC_REDIR_TABLE
+ irq
->pin
* 2, lo
);
286 static void ioapic_eoi_edge(__unused
struct irq
* irq
)
291 void ioapic_eoi(int irq
)
293 if (ioapic_enabled
) {
294 io_apic_irq
[irq
].eoi(&io_apic_irq
[irq
]);
300 void ioapic_set_id(u32_t addr
, unsigned int id
)
302 ioapic_write(addr
, IOAPIC_ID
, id
<< 24);
305 int ioapic_enable_all(void)
310 /* Select IMCR and disconnect 8259s. */
315 return ioapic_enabled
= 1;
318 /* disables a single IO APIC */
319 static void ioapic_disable(struct io_apic
* ioapic
)
323 for (p
= 0; p
< io_apic
->pins
; p
++) {
325 low_32
= ioapic_read((u32_t
)ioapic
->addr
,
326 (uint8_t) (IOAPIC_REDIR_TABLE
+ p
* 2));
327 hi_32
= ioapic_read((u32_t
)ioapic
->addr
,
328 (uint8_t) (IOAPIC_REDIR_TABLE
+ p
* 2 + 1));
330 if (!(low_32
& APIC_ICR_INT_MASK
)) {
331 low_32
|= APIC_ICR_INT_MASK
;
332 ioapic_write((u32_t
)ioapic
->addr
,
333 (uint8_t) (IOAPIC_REDIR_TABLE
+ p
* 2 + 1), hi_32
);
334 ioapic_write((u32_t
)ioapic
->addr
,
335 (uint8_t) (IOAPIC_REDIR_TABLE
+ p
* 2), low_32
);
340 /* disables all IO APICs */
341 void ioapic_disable_all(void)
347 for (ioa
= 0 ; ioa
< nioapics
; ioa
++)
348 ioapic_disable(&io_apic
[ioa
]);
350 ioapic_enabled
= 0; /* io apic, disabled */
352 /* Enable 8259 - write 0x00 in OCW1 master and slave. */
358 lapic_microsec_sleep(200); /* to enable APIC to switch to PIC */
360 apic_idt_init(TRUE
); /* reset */
364 static void ioapic_disable_irq(unsigned irq
)
366 if(!(io_apic_irq
[irq
].ioa
)) {
367 printf("ioapic_disable_irq: no ioa set for irq %d!\n", irq
);
371 assert(io_apic_irq
[irq
].ioa
);
373 ioapic_disable_pin(io_apic_irq
[irq
].ioa
->addr
, io_apic_irq
[irq
].pin
);
374 io_apic_irq
[irq
].state
|= IOAPIC_IRQ_STATE_MASKED
;
377 static void ioapic_enable_irq(unsigned irq
)
379 if(!(io_apic_irq
[irq
].ioa
)) {
380 printf("ioapic_enable_irq: no ioa set for irq %d!\n", irq
);
384 assert(io_apic_irq
[irq
].ioa
);
386 ioapic_enable_pin(io_apic_irq
[irq
].ioa
->addr
, io_apic_irq
[irq
].pin
);
387 io_apic_irq
[irq
].state
&= ~IOAPIC_IRQ_STATE_MASKED
;
390 void ioapic_unmask_irq(unsigned irq
)
393 ioapic_enable_irq(irq
);
396 irq_8259_unmask(irq
);
399 void ioapic_mask_irq(unsigned irq
)
402 ioapic_disable_irq(irq
);
408 unsigned int apicid(void)
410 return lapic_read(LAPIC_ID
) >> 24;
413 static int calib_clk_handler(irq_hook_t
* UNUSED(hook
))
420 tcrt
= lapic_read(LAPIC_TIMER_CCR
);
423 if (probe_ticks
== 1) {
427 else if (probe_ticks
== PROBE_TICKS
) {
437 static int spurious_irq_handler(irq_hook_t
* UNUSED(hook
))
440 * Do nothing, only unlock the kernel so we do not deadlock!
446 static void apic_calibrate_clocks(unsigned cpu
)
448 u32_t lvtt
, val
, lapic_delta
;
452 irq_hook_t calib_clk
, spurious_irq
;
454 BOOT_VERBOSE(printf("Calibrating clock\n"));
456 * Set Initial count register to the highest value so it does not
457 * underflow during the testing period
460 lapic_write (LAPIC_TIMER_ICR
, val
);
462 /* Set Current count register */
464 lapic_write (LAPIC_TIMER_CCR
, val
);
466 lvtt
= lapic_read(LAPIC_TIMER_DCR
) & ~0x0b;
467 /* Set Divide configuration register to 1 */
469 lapic_write(LAPIC_TIMER_DCR
, lvtt
);
472 * mask the APIC timer interrupt in the LVT Timer Register so that we
473 * don't get an interrupt upon underflow which we don't know how to
474 * handle right know. If underflow happens, the system will not continue
475 * as something is wrong with the clock IRQ 0 and we cannot calibrate
476 * the clock which mean that we cannot run processes
478 lvtt
= lapic_read (LAPIC_LVTTR
);
479 lvtt
|= APIC_LVTT_MASK
;
480 lapic_write (LAPIC_LVTTR
, lvtt
);
482 /* set the probe, we use the legacy timer, IRQ 0 */
483 put_irq_handler(&calib_clk
, CLOCK_IRQ
, calib_clk_handler
);
486 * A spurious interrupt may occur during the clock calibration. Since we
487 * do this calibration in kernel, we need a special handler which will
488 * leave the BKL unlocked like the clock handler. This is a corner case,
489 * boot time only situation
491 put_irq_handler(&spurious_irq
, SPURIOUS_IRQ
, spurious_irq_handler
);
493 /* set the PIC timer to get some time */
494 init_8253A_timer(system_hz
);
497 * We must unlock BKL here as the in-kernel interrupt will lock it
498 * again. The handler will unlock it after it is done. This is
499 * absolutely safe as only the BSP is running. It is just a workaround a
500 * corner case for APIC timer calibration
505 /* loop for some time to get a sample */
506 while(probe_ticks
< PROBE_TICKS
) {
513 /* remove the probe */
514 rm_irq_handler(&calib_clk
);
515 rm_irq_handler(&spurious_irq
);
517 lapic_delta
= lapic_tctr0
- lapic_tctr1
;
518 tsc_delta
= sub64(tsc1
, tsc0
);
520 lapic_bus_freq
[cpuid
] = system_hz
* lapic_delta
/ (PROBE_TICKS
- 1);
521 BOOT_VERBOSE(printf("APIC bus freq %u MHz\n",
522 lapic_bus_freq
[cpuid
] / 1000000));
523 cpu_freq
= mul64(div64u64(tsc_delta
, PROBE_TICKS
- 1), make64(system_hz
, 0));
524 cpu_set_freq(cpuid
, cpu_freq
);
525 cpu_info
[cpuid
].freq
= div64u(cpu_freq
, 1000000);
526 BOOT_VERBOSE(cpu_print_freq(cpuid
));
529 void lapic_set_timer_one_shot(const u32_t usec
)
531 /* sleep in micro seconds */
534 const u8_t cpu
= cpuid
;
536 ticks_per_us
= (lapic_bus_freq
[cpu
] / 1000000) * config_apic_timer_x
;
538 lapic_write(LAPIC_TIMER_ICR
, usec
* ticks_per_us
);
541 lapic_write(LAPIC_TIMER_DCR
, lvtt
);
543 /* configure timer as one-shot */
544 lvtt
= APIC_TIMER_INT_VECTOR
;
545 lapic_write(LAPIC_LVTTR
, lvtt
);
548 void lapic_set_timer_periodic(const unsigned freq
)
550 /* sleep in micro seconds */
552 u32_t lapic_ticks_per_clock_tick
;
553 const u8_t cpu
= cpuid
;
555 lapic_ticks_per_clock_tick
= (lapic_bus_freq
[cpu
] / freq
) * config_apic_timer_x
;
558 lapic_write(LAPIC_TIMER_DCR
, lvtt
);
560 /* configure timer as periodic */
561 lvtt
= APIC_LVTT_TM
| APIC_TIMER_INT_VECTOR
;
562 lapic_write(LAPIC_LVTTR
, lvtt
);
564 lapic_write(LAPIC_TIMER_ICR
, lapic_ticks_per_clock_tick
);
567 void lapic_stop_timer(void)
570 lvtt
= lapic_read(LAPIC_LVTTR
);
571 lapic_write(LAPIC_LVTTR
, lvtt
| APIC_LVTT_MASK
);
572 /* zero the current counter so it can be restarted again */
573 lapic_write(LAPIC_TIMER_ICR
, 0);
574 lapic_write(LAPIC_TIMER_CCR
, 0);
577 void lapic_restart_timer(void)
579 /* restart the timer only if the counter reached zero, i.e. expired */
580 if (lapic_read(LAPIC_TIMER_CCR
) == 0)
581 lapic_set_timer_one_shot(1000000/system_hz
);
584 void lapic_microsec_sleep(unsigned count
)
586 lapic_set_timer_one_shot(count
);
587 while (lapic_read(LAPIC_TIMER_CCR
))
591 static u32_t
lapic_errstatus(void)
593 lapic_write(LAPIC_ESR
, 0);
594 return lapic_read(LAPIC_ESR
);
598 static int lapic_disable_in_msr(void)
600 u32_t msr_hi
, msr_lo
;
602 ia32_msr_read(IA32_APIC_BASE
, &msr_hi
, &msr_lo
);
604 msr_lo
&= ~(1 << IA32_APIC_BASE_ENABLE_BIT
);
605 ia32_msr_write(IA32_APIC_BASE
, msr_hi
, msr_lo
);
609 #endif /* CONFIG_SMP */
611 void lapic_disable(void)
613 /* Disable current APIC and close interrupts from PIC */
620 if (cpu_is_bsp(cpuid
) && !apic_imcrp
)
623 /* leave it enabled if imcr is not set */
624 val
= lapic_read(LAPIC_LINT0
);
625 val
&= ~(APIC_ICR_DM_MASK
|APIC_ICR_INT_MASK
);
626 val
|= APIC_ICR_DM_EXTINT
; /* ExtINT at LINT0 */
627 lapic_write (LAPIC_LINT0
, val
);
632 val
= lapic_read(LAPIC_LINT0
) & 0xFFFE58FF;
633 val
|= APIC_ICR_INT_MASK
;
634 lapic_write (LAPIC_LINT0
, val
);
636 val
= lapic_read(LAPIC_LINT1
) & 0xFFFE58FF;
637 val
|= APIC_ICR_INT_MASK
;
638 lapic_write (LAPIC_LINT1
, val
);
640 val
= lapic_read(LAPIC_SIVR
) & 0xFFFFFF00;
642 lapic_write(LAPIC_SIVR
, val
);
644 lapic_disable_in_msr();
645 #endif /* CONFIG_SMP */
648 static int lapic_enable_in_msr(void)
650 u32_t msr_hi
, msr_lo
;
652 ia32_msr_read(IA32_APIC_BASE
, &msr_hi
, &msr_lo
);
656 /*FIXME this is a problem on AP */
658 * FIXME if the location is different (unlikely) then the one we expect,
661 addr
= (msr_lo
>> 12) | ((msr_hi
& 0xf) << 20);
662 if (addr
!= (lapic_addr
>> 12)) {
664 printf("ERROR : APIC address needs more then 32 bits\n");
667 lapic_addr
= msr_lo
& ~((1 << 12) - 1);
671 msr_lo
|= (1 << IA32_APIC_BASE_ENABLE_BIT
);
672 ia32_msr_write(IA32_APIC_BASE
, msr_hi
, msr_lo
);
677 int lapic_enable(unsigned cpu
)
684 cpu_has_tsc
= _cpufeature(_CPUF_I386_TSC
);
686 printf("CPU lacks timestamp counter, "
687 "cannot calibrate LAPIC timer\n");
691 if (!lapic_enable_in_msr())
694 /* set the highest priority for ever */
695 lapic_write(LAPIC_TPR
, 0x0);
697 lapic_eoi_addr
= LAPIC_EOI
;
698 /* clear error state register. */
699 val
= lapic_errstatus ();
701 /* Enable Local APIC and set the spurious vector to 0xff. */
702 val
= lapic_read(LAPIC_SIVR
);
703 val
|= APIC_ENABLE
| APIC_SPURIOUS_INT_VECTOR
;
704 val
&= ~APIC_FOCUS_DISABLED
;
705 lapic_write(LAPIC_SIVR
, val
);
706 (void) lapic_read(LAPIC_SIVR
);
710 /* Program Logical Destination Register. */
711 val
= lapic_read(LAPIC_LDR
) & ~0xFF000000;
712 val
|= (cpu
& 0xFF) << 24;
713 lapic_write(LAPIC_LDR
, val
);
715 /* Program Destination Format Register for Flat mode. */
716 val
= lapic_read(LAPIC_DFR
) | 0xF0000000;
717 lapic_write (LAPIC_DFR
, val
);
719 val
= lapic_read (LAPIC_LVTER
) & 0xFFFFFF00;
720 lapic_write (LAPIC_LVTER
, val
);
722 nlvt
= (lapic_read(LAPIC_VERSION
)>>16) & 0xFF;
725 val
= lapic_read(LAPIC_LVTTMR
);
726 lapic_write(LAPIC_LVTTMR
, val
| APIC_ICR_INT_MASK
);
730 val
= lapic_read(LAPIC_LVTPCR
);
731 lapic_write(LAPIC_LVTPCR
, val
| APIC_ICR_INT_MASK
);
734 /* setup TPR to allow all interrupts. */
735 val
= lapic_read (LAPIC_TPR
);
736 /* accept all interrupts */
737 lapic_write (LAPIC_TPR
, val
& ~0xFF);
739 (void) lapic_read (LAPIC_SIVR
);
742 apic_calibrate_clocks(cpu
);
743 BOOT_VERBOSE(printf("APIC timer calibrated\n"));
748 void apic_spurios_intr_handler(void)
753 if (x
== 1 || (x
% 100) == 0)
754 printf("WARNING spurious interrupt(s) %d on cpu %d\n", x
, cpuid
);
757 void apic_error_intr_handler(void)
762 if (x
== 1 || (x
% 100) == 0)
763 printf("WARNING apic error (0x%x) interrupt(s) %d on cpu %d\n",
764 lapic_errstatus(), x
, cpuid
);
767 static struct gate_table_s gate_table_ioapic
[] = {
768 { apic_hwint0
, LAPIC_VECTOR( 0), INTR_PRIVILEGE
},
769 { apic_hwint1
, LAPIC_VECTOR( 1), INTR_PRIVILEGE
},
770 { apic_hwint2
, LAPIC_VECTOR( 2), INTR_PRIVILEGE
},
771 { apic_hwint3
, LAPIC_VECTOR( 3), INTR_PRIVILEGE
},
772 { apic_hwint4
, LAPIC_VECTOR( 4), INTR_PRIVILEGE
},
773 { apic_hwint5
, LAPIC_VECTOR( 5), INTR_PRIVILEGE
},
774 { apic_hwint6
, LAPIC_VECTOR( 6), INTR_PRIVILEGE
},
775 { apic_hwint7
, LAPIC_VECTOR( 7), INTR_PRIVILEGE
},
776 { apic_hwint8
, LAPIC_VECTOR( 8), INTR_PRIVILEGE
},
777 { apic_hwint9
, LAPIC_VECTOR( 9), INTR_PRIVILEGE
},
778 { apic_hwint10
, LAPIC_VECTOR(10), INTR_PRIVILEGE
},
779 { apic_hwint11
, LAPIC_VECTOR(11), INTR_PRIVILEGE
},
780 { apic_hwint12
, LAPIC_VECTOR(12), INTR_PRIVILEGE
},
781 { apic_hwint13
, LAPIC_VECTOR(13), INTR_PRIVILEGE
},
782 { apic_hwint14
, LAPIC_VECTOR(14), INTR_PRIVILEGE
},
783 { apic_hwint15
, LAPIC_VECTOR(15), INTR_PRIVILEGE
},
784 { apic_hwint16
, LAPIC_VECTOR(16), INTR_PRIVILEGE
},
785 { apic_hwint17
, LAPIC_VECTOR(17), INTR_PRIVILEGE
},
786 { apic_hwint18
, LAPIC_VECTOR(18), INTR_PRIVILEGE
},
787 { apic_hwint19
, LAPIC_VECTOR(19), INTR_PRIVILEGE
},
788 { apic_hwint20
, LAPIC_VECTOR(20), INTR_PRIVILEGE
},
789 { apic_hwint21
, LAPIC_VECTOR(21), INTR_PRIVILEGE
},
790 { apic_hwint22
, LAPIC_VECTOR(22), INTR_PRIVILEGE
},
791 { apic_hwint23
, LAPIC_VECTOR(23), INTR_PRIVILEGE
},
792 { apic_hwint24
, LAPIC_VECTOR(24), INTR_PRIVILEGE
},
793 { apic_hwint25
, LAPIC_VECTOR(25), INTR_PRIVILEGE
},
794 { apic_hwint26
, LAPIC_VECTOR(26), INTR_PRIVILEGE
},
795 { apic_hwint27
, LAPIC_VECTOR(27), INTR_PRIVILEGE
},
796 { apic_hwint28
, LAPIC_VECTOR(28), INTR_PRIVILEGE
},
797 { apic_hwint29
, LAPIC_VECTOR(29), INTR_PRIVILEGE
},
798 { apic_hwint30
, LAPIC_VECTOR(30), INTR_PRIVILEGE
},
799 { apic_hwint31
, LAPIC_VECTOR(31), INTR_PRIVILEGE
},
800 { apic_hwint32
, LAPIC_VECTOR(32), INTR_PRIVILEGE
},
801 { apic_hwint33
, LAPIC_VECTOR(33), INTR_PRIVILEGE
},
802 { apic_hwint34
, LAPIC_VECTOR(34), INTR_PRIVILEGE
},
803 { apic_hwint35
, LAPIC_VECTOR(35), INTR_PRIVILEGE
},
804 { apic_hwint36
, LAPIC_VECTOR(36), INTR_PRIVILEGE
},
805 { apic_hwint37
, LAPIC_VECTOR(37), INTR_PRIVILEGE
},
806 { apic_hwint38
, LAPIC_VECTOR(38), INTR_PRIVILEGE
},
807 { apic_hwint39
, LAPIC_VECTOR(39), INTR_PRIVILEGE
},
808 { apic_hwint40
, LAPIC_VECTOR(40), INTR_PRIVILEGE
},
809 { apic_hwint41
, LAPIC_VECTOR(41), INTR_PRIVILEGE
},
810 { apic_hwint42
, LAPIC_VECTOR(42), INTR_PRIVILEGE
},
811 { apic_hwint43
, LAPIC_VECTOR(43), INTR_PRIVILEGE
},
812 { apic_hwint44
, LAPIC_VECTOR(44), INTR_PRIVILEGE
},
813 { apic_hwint45
, LAPIC_VECTOR(45), INTR_PRIVILEGE
},
814 { apic_hwint46
, LAPIC_VECTOR(46), INTR_PRIVILEGE
},
815 { apic_hwint47
, LAPIC_VECTOR(47), INTR_PRIVILEGE
},
816 { apic_hwint48
, LAPIC_VECTOR(48), INTR_PRIVILEGE
},
817 { apic_hwint49
, LAPIC_VECTOR(49), INTR_PRIVILEGE
},
818 { apic_hwint50
, LAPIC_VECTOR(50), INTR_PRIVILEGE
},
819 { apic_hwint51
, LAPIC_VECTOR(51), INTR_PRIVILEGE
},
820 { apic_hwint52
, LAPIC_VECTOR(52), INTR_PRIVILEGE
},
821 { apic_hwint53
, LAPIC_VECTOR(53), INTR_PRIVILEGE
},
822 { apic_hwint54
, LAPIC_VECTOR(54), INTR_PRIVILEGE
},
823 { apic_hwint55
, LAPIC_VECTOR(55), INTR_PRIVILEGE
},
824 { apic_hwint56
, LAPIC_VECTOR(56), INTR_PRIVILEGE
},
825 { apic_hwint57
, LAPIC_VECTOR(57), INTR_PRIVILEGE
},
826 { apic_hwint58
, LAPIC_VECTOR(58), INTR_PRIVILEGE
},
827 { apic_hwint59
, LAPIC_VECTOR(59), INTR_PRIVILEGE
},
828 { apic_hwint60
, LAPIC_VECTOR(60), INTR_PRIVILEGE
},
829 { apic_hwint61
, LAPIC_VECTOR(61), INTR_PRIVILEGE
},
830 { apic_hwint62
, LAPIC_VECTOR(62), INTR_PRIVILEGE
},
831 { apic_hwint63
, LAPIC_VECTOR(63), INTR_PRIVILEGE
},
832 { apic_spurios_intr
, APIC_SPURIOUS_INT_VECTOR
, INTR_PRIVILEGE
},
833 { apic_error_intr
, APIC_ERROR_INT_VECTOR
, INTR_PRIVILEGE
},
837 static struct gate_table_s gate_table_common
[] = {
838 { ipc_entry
, IPC_VECTOR
, USER_PRIVILEGE
},
839 { kernel_call_entry
, KERN_CALL_VECTOR
, USER_PRIVILEGE
},
844 static struct gate_table_s gate_table_smp
[] = {
845 { apic_ipi_sched_intr
, APIC_SMP_SCHED_PROC_VECTOR
, INTR_PRIVILEGE
},
846 { apic_ipi_halt_intr
, APIC_SMP_CPU_HALT_VECTOR
, INTR_PRIVILEGE
},
852 static void lapic_set_dummy_handlers(void)
855 int vect
= 32; /* skip the reserved vectors */
857 handler
= &lapic_intr_dummy_handles_start
;
858 handler
+= vect
* LAPIC_INTR_DUMMY_HANDLER_SIZE
;
859 for(; handler
< &lapic_intr_dummy_handles_end
;
860 handler
+= LAPIC_INTR_DUMMY_HANDLER_SIZE
) {
861 int_gate_idt(vect
++, (vir_bytes
) handler
,
862 PRESENT
| INT_GATE_TYPE
|
863 (INTR_PRIVILEGE
<< DPL_SHIFT
));
868 /* Build descriptors for interrupt gates in IDT. */
869 void apic_idt_init(const int reset
)
873 /* Set up idt tables for smp mode.
878 idt_copy_vectors_pic();
879 idt_copy_vectors(gate_table_common
);
883 is_bsp
= is_boot_apic(apicid());
887 printf("APIC debugging is enabled\n");
888 lapic_set_dummy_handlers();
891 /* Build descriptors for interrupt gates in IDT. */
893 idt_copy_vectors(gate_table_ioapic
);
895 idt_copy_vectors_pic();
897 idt_copy_vectors(gate_table_common
);
900 idt_copy_vectors(gate_table_smp
);
903 /* Setup error interrupt vector */
904 val
= lapic_read(LAPIC_LVTER
);
905 val
|= APIC_ERROR_INT_VECTOR
;
906 val
&= ~ APIC_ICR_INT_MASK
;
907 lapic_write(LAPIC_LVTER
, val
);
908 (void) lapic_read(LAPIC_LVTER
);
910 /* configure the timer interupt handler */
912 BOOT_VERBOSE(printf("Initiating APIC timer handler\n"));
913 /* register the timer interrupt handler for this CPU */
914 int_gate_idt(APIC_TIMER_INT_VECTOR
, (vir_bytes
) lapic_timer_int_handler
,
915 PRESENT
| INT_GATE_TYPE
| (INTR_PRIVILEGE
<< DPL_SHIFT
));
920 static int acpi_get_ioapics(struct io_apic
* ioa
, unsigned * nioa
, unsigned max
)
923 struct acpi_madt_ioapic
* acpi_ioa
;
926 acpi_ioa
= acpi_get_ioapic_next();
927 if (acpi_ioa
== NULL
)
930 assert(acpi_ioa
->address
);
932 ioa
[n
].id
= acpi_ioa
->id
;
933 ioa
[n
].addr
= acpi_ioa
->address
;
934 ioa
[n
].paddr
= (phys_bytes
) acpi_ioa
->address
;
935 ioa
[n
].gsi_base
= acpi_ioa
->global_int_base
;
936 ioa
[n
].pins
= ((ioapic_read(ioa
[n
].addr
,
937 IOAPIC_VERSION
) & 0xff0000) >> 16)+1;
938 printf("IO APIC idx %d id %d addr 0x%lx paddr 0x%lx pins %d\n",
939 n
, acpi_ioa
->id
, ioa
[n
].addr
, ioa
[n
].paddr
,
948 int detect_ioapics(void)
952 if (machine
.acpi_rsdp
) {
953 status
= acpi_get_ioapics(io_apic
, &nioapics
, MAX_NR_IOAPICS
);
958 /* try something different like MPS */
966 void apic_send_ipi(unsigned vector
, unsigned cpu
, int type
)
971 /* no need of sending an IPI */
974 while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING
)
977 icr1
= lapic_read_icr1() & 0xFFF0F800;
978 icr2
= lapic_read_icr2() & 0xFFFFFF;
982 if (!cpu_is_ready(cpu
))
984 lapic_write_icr2(icr2
| (cpuid2apicid
[cpu
] << 24));
985 lapic_write_icr1(icr1
| APIC_ICR_DEST_FIELD
| vector
);
988 lapic_write_icr2(icr2
);
989 lapic_write_icr1(icr1
| APIC_ICR_DEST_SELF
| vector
);
991 case APIC_IPI_TO_ALL_BUT_SELF
:
992 lapic_write_icr2(icr2
);
993 lapic_write_icr1(icr1
| APIC_ICR_DEST_ALL_BUT_SELF
| vector
);
995 case APIC_IPI_TO_ALL
:
996 lapic_write_icr2(icr2
);
997 lapic_write_icr1(icr1
| APIC_ICR_DEST_ALL
| vector
);
1000 printf("WARNING : unknown send ipi type request\n");
1005 int apic_send_startup_ipi(unsigned cpu
, phys_bytes trampoline
)
1008 u32_t errstatus
= 0;
1011 /* INIT-SIPI-SIPI sequence */
1013 for (i
= 0; i
< 2; i
++) {
1016 /* clear err status */
1020 val
= lapic_read(LAPIC_ICR2
) & 0xFFFFFF;
1021 val
|= cpuid2apicid
[cpu
] << 24;
1022 lapic_write(LAPIC_ICR2
, val
);
1025 val
= lapic_read(LAPIC_ICR1
) & 0xFFF32000;
1026 val
|= APIC_ICR_LEVEL_ASSERT
|APIC_ICR_DM_STARTUP
;
1027 val
|= (((u32_t
)trampoline
>> 12)&0xff);
1028 lapic_write(LAPIC_ICR1
, val
);
1032 /* wait for 200 micro-seconds*/
1033 lapic_microsec_sleep (200);
1036 while ((lapic_read(LAPIC_ICR1
) & APIC_ICR_DELIVERY_PENDING
) &&
1038 errstatus
= lapic_errstatus();
1040 if (!timeout
) break;
1043 /* skip this one and continue with another cpu */
1051 int apic_send_init_ipi(unsigned cpu
, phys_bytes trampoline
)
1053 u32_t ptr
, errstatus
= 0;
1056 /* set the warm reset vector */
1057 ptr
= (u32_t
)(trampoline
& 0xF);
1058 phys_copy(0x467, vir2phys(&ptr
), sizeof(u16_t
));
1059 ptr
= (u32_t
)(trampoline
>> 4);
1060 phys_copy(0x469, vir2phys(&ptr
), sizeof(u16_t
));
1062 /* set shutdown code */
1063 outb (RTC_INDEX
, 0xF);
1066 /* clear error state register. */
1067 (void) lapic_errstatus();
1069 /* assert INIT IPI , No Shorthand, destination mode : physical */
1070 lapic_write(LAPIC_ICR2
, (lapic_read (LAPIC_ICR2
) & 0xFFFFFF) |
1071 (cpuid2apicid
[cpu
] << 24));
1072 lapic_write(LAPIC_ICR1
, (lapic_read (LAPIC_ICR1
) & 0xFFF32000) |
1073 APIC_ICR_DM_INIT
| APIC_ICR_TM_LEVEL
| APIC_ICR_LEVEL_ASSERT
);
1077 /* sleep for 200 micro-seconds */
1078 lapic_microsec_sleep(200);
1082 while ((lapic_read(LAPIC_ICR1
) & APIC_ICR_DELIVERY_PENDING
) && !errstatus
) {
1083 errstatus
= lapic_errstatus();
1085 if (!timeout
) break;
1089 return -1; /* to continue with a new processor */
1091 /* clear error state register. */
1094 /* deassert INIT IPI , No Shorthand, destination mode : physical */
1095 lapic_write(LAPIC_ICR2
, (lapic_read (LAPIC_ICR2
) & 0xFFFFFF) |
1096 (cpuid2apicid
[cpu
] << 24));
1097 lapic_write(LAPIC_ICR1
, (lapic_read (LAPIC_ICR1
) & 0xFFF32000) |
1098 APIC_ICR_DEST_ALL
| APIC_ICR_TM_LEVEL
);
1103 /* sleep for 200 micro-seconds */
1104 lapic_microsec_sleep(200);
1106 while ((lapic_read(LAPIC_ICR1
)&APIC_ICR_DELIVERY_PENDING
) && !errstatus
) {
1107 errstatus
= lapic_errstatus();
1113 return -1; /* with the new processor */
1115 /* clear error state register. */
1116 (void) lapic_errstatus();
1119 lapic_microsec_sleep (10000);
1126 int apic_single_cpu_init(void)
1128 if (!cpu_feature_apic_on_chip())
1131 lapic_addr
= LOCAL_APIC_DEF_ADDR
;
1134 if (!lapic_enable(0)) {
1139 bsp_lapic_id
= apicid();
1140 printf("Boot cpu apic id %d\n", bsp_lapic_id
);
1144 if (!detect_ioapics()) {
1150 ioapic_enable_all();
1153 machine
.apic_enabled
= 1;
1155 apic_idt_init(0); /* Not a reset ! */
1161 static eoi_method_t
set_eoi_method(unsigned irq
)
1164 * in APIC mode the lowest 16 IRQs are reserved for legacy (E)ISA edge
1165 * triggered interrupts. All the rest is for PCI level triggered
1169 return ioapic_eoi_edge
;
1171 return ioapic_eoi_level
;
1174 void set_irq_redir_low(unsigned irq
, u32_t
* low
)
1178 /* clear the polarity, trigger, mask and vector fields */
1179 val
&= ~(APIC_ICR_VECTOR
| APIC_ICR_INT_MASK
|
1180 APIC_ICR_TRIGGER
| APIC_ICR_INT_POLARITY
);
1183 /* ISA active-high */
1184 val
&= ~APIC_ICR_INT_POLARITY
;
1185 /* ISA edge triggered */
1186 val
&= ~APIC_ICR_TRIGGER
;
1189 /* PCI active-low */
1190 val
|= APIC_ICR_INT_POLARITY
;
1191 /* PCI level triggered */
1192 val
|= APIC_ICR_TRIGGER
;
1195 val
|= io_apic_irq
[irq
].vector
;
1200 void ioapic_set_irq(unsigned irq
)
1204 assert(irq
< NR_IRQ_VECTORS
);
1206 /* shared irq, already set */
1207 if (io_apic_irq
[irq
].ioa
&& io_apic_irq
[irq
].eoi
)
1210 assert(!io_apic_irq
[irq
].ioa
|| !io_apic_irq
[irq
].eoi
);
1212 for (ioa
= 0; ioa
< nioapics
; ioa
++) {
1213 if (io_apic
[ioa
].gsi_base
<= irq
&&
1214 io_apic
[ioa
].gsi_base
+
1215 io_apic
[ioa
].pins
> irq
) {
1216 u32_t hi_32
, low_32
;
1218 io_apic_irq
[irq
].ioa
= &io_apic
[ioa
];
1219 io_apic_irq
[irq
].pin
= irq
- io_apic
[ioa
].gsi_base
;
1220 io_apic_irq
[irq
].eoi
= set_eoi_method(irq
);
1221 io_apic_irq
[irq
].vector
= LAPIC_VECTOR(irq
);
1223 set_irq_redir_low(irq
, &low_32
);
1225 * route the interrupts to the bsp by default
1227 hi_32
= bsp_lapic_id
<< 24;
1228 ioapic_redirt_entry_write((void *) io_apic
[ioa
].addr
,
1229 io_apic_irq
[irq
].pin
, hi_32
, low_32
);
1234 void ioapic_unset_irq(unsigned irq
)
1236 assert(irq
< NR_IRQ_VECTORS
);
1238 ioapic_disable_irq(irq
);
1239 io_apic_irq
[irq
].ioa
= NULL
;
1240 io_apic_irq
[irq
].eoi
= NULL
;
1243 void ioapic_reset_pic(void)
1245 apic_idt_init(TRUE
); /* reset */
1248 /* Enable 8259 - write 0x00 in OCW1
1249 * master and slave. */
1254 static void irq_lapic_status(int irq
)
1257 reg_t tmr
, irr
, isr
;
1261 intr
= &io_apic_irq
[irq
];
1266 vector
= LAPIC_VECTOR(irq
);
1267 tmr
= apic_read_tmr_vector(vector
);
1268 irr
= apic_read_irr_vector(vector
);
1269 isr
= apic_read_isr_vector(vector
);
1272 if (lapic_test_delivery_val(isr
, vector
)) {
1273 printf("IRQ %d vec %d trigger %s irr %d isr %d\n",
1275 lapic_test_delivery_val(tmr
, vector
) ?
1277 lapic_test_delivery_val(irr
, vector
) ? 1 : 0,
1278 lapic_test_delivery_val(isr
, vector
) ? 1 : 0);
1280 printf("IRQ %d vec %d irr %d\n",
1282 lapic_test_delivery_val(irr
, vector
) ? 1 : 0);
1285 lo
= ioapic_read(intr
->ioa
->addr
,
1286 IOAPIC_REDIR_TABLE
+ intr
->pin
* 2);
1287 printf("\tpin %2d vec 0x%02x ioa %d redir_lo 0x%08x %s\n",
1292 intr
->state
& IOAPIC_IRQ_STATE_MASKED
?
1293 "masked" : "unmasked");
1296 void dump_apic_irq_state(void)
1300 printf("--- IRQs state dump ---\n");
1301 for (irq
= 0; irq
< NR_IRQ_VECTORS
; irq
++) {
1302 irq_lapic_status(irq
);
1304 printf("--- all ---\n");