perf: Report maximum values for counter overflow
[akaros.git] / kern / arch / x86 / apic.h
index 0c46a72..fc0fd97 100644 (file)
@@ -4,38 +4,18 @@
  * See LICENSE for details.
  */
 
-#ifndef ROS_KERN_APIC_H
-#define ROS_KERN_APIC_H
+#pragma once
 
-/* 
+/*
  * Functions and definitions for dealing with the APIC and PIC, specific to
  * Intel.  Does not handle an x2APIC.
  */
-
 #include <arch/mmu.h>
 #include <arch/x86.h>
-#include <arch/ioapic.h>
-
-/* PIC (8259A)
- * When looking at the specs, A0 is our CMD line, and A1 is the DATA line.  This
- * means that blindly writing to PIC1_DATA is an OCW1 (interrupt masks).  When
- * writing to CMD (A0), the chip can determine betweeb OCW2 and OCW3 by the
- * setting of a few specific bits (OCW2 has bit 3 unset, OCW3 has it set). */
-#define PIC1_CMD                                       0x20
-#define PIC1_DATA                                      0x21
-#define PIC2_CMD                                       0xA0
-#define PIC2_DATA                                      0xA1
-// These are also hardcoded into the IRQ_HANDLERs of kern/trapentry.S
-#define PIC1_OFFSET                                    0x20
-#define PIC2_OFFSET                                    0x28
-#define PIC1_SPURIOUS                          (7 + PIC1_OFFSET)
-#define PIC2_SPURIOUS                          (7 + PIC2_OFFSET)
-#define PIC_EOI                                                0x20    /* OCW2 EOI */
-/* These set the next CMD read to return specific values.  Note that the chip
- * remembers what setting we had before (IRR or ISR), if you do other reads of
- * CMD. (not tested, written in the spec sheet) */
-#define PIC_READ_IRR                           0x0a    /* OCW3 irq ready next CMD read */
-#define PIC_READ_ISR                           0x0b    /* OCW3 irq service next CMD read */
+#include <ros/trapframe.h>
+#include <atomic.h>
+#include <endian.h>
+#include <arch/ros/msr-index.h>
 
 // Local APIC
 /* PBASE is the physical address.  It is mapped in at the VADDR LAPIC_BASE.
  * spaces.  We just happen to have a slight 'hole' in addressable physical
  * memory.  We can move the PBASE, but we're limited to 32 bit (physical)
  * addresses. */
-#define LAPIC_PBASE                                    0xfee00000 /* default *physical* address */
-#define LAPIC_EOI                                      (LAPIC_BASE + 0x0b0)
-#define LAPIC_SPURIOUS                         (LAPIC_BASE + 0x0f0)
-#define LAPIC_VERSION                          (LAPIC_BASE + 0x030)
-#define LAPIC_ERROR                                    (LAPIC_BASE + 0x280)
-#define LAPIC_ID                                       (LAPIC_BASE + 0x020)
-#define LAPIC_LOGICAL_ID                       (LAPIC_BASE + 0x0d0)
-// LAPIC Local Vector Table
-#define LAPIC_LVT_TIMER                                (LAPIC_BASE + 0x320)
-#define LAPIC_LVT_LINT0                                (LAPIC_BASE + 0x350)
-#define LAPIC_LVT_LINT1                                (LAPIC_BASE + 0x360)
-#define LAPIC_LVT_ERROR                                (LAPIC_BASE + 0x370)
-#define LAPIC_LVT_PERFMON                      (LAPIC_BASE + 0x340)
-#define LAPIC_LVT_THERMAL                      (LAPIC_BASE + 0x330)
-#define LAPIC_LVT_MASK                         0x00010000
-// LAPIC Timer
-#define LAPIC_TIMER_INIT                       (LAPIC_BASE + 0x380)
-#define LAPIC_TIMER_CURRENT                    (LAPIC_BASE + 0x390)
-#define LAPIC_TIMER_DIVIDE                     (LAPIC_BASE + 0x3e0)
-#define LAPIC_TIMER_DEFAULT_VECTOR     0xeb            /* Aka 235, IRQ203 */
+#define LAPIC_PBASE                                    0xfee00000      /* default *physical* address */
+#define LAPIC_LVT_MASK                                 0x00010000
+
 /* Quick note on the divisor.  The LAPIC timer ticks once per divisor-bus ticks
  * (system bus or APIC bus, depending on the model).  Ex: A divisor of 128 means
  * 128 bus ticks results in 1 timer tick.  The divisor increases the time range
 #define LAPIC_TIMER_DIVISOR_BITS       0x8     /* Div = 32 */
 
 // IPI Interrupt Command Register
-#define LAPIC_IPI_ICR_LOWER                    (LAPIC_BASE + 0x300)
-#define LAPIC_IPI_ICR_UPPER                    (LAPIC_BASE + 0x310)
+#define LAPIC_IPI_ICR_LOWER                            0x30
+#define LAPIC_IPI_ICR_UPPER                            0x31
 /* Interrupts being serviced (in-service) and pending (interrupt request reg).
  * Note these registers are not normal bitmaps, but instead are 8 separate
  * 32-bit registers, spaced/aligned on 16 byte boundaries in the LAPIC address
  * space. */
-#define LAPIC_ISR                                      (LAPIC_BASE + 0x100)
-#define LAPIC_IRR                                      (LAPIC_BASE + 0x200)
-
-// PIT (Programmable Interval Timer)
-#define        TIMER_REG_CNTR0 0       /* timer 0 counter port */
-#define        TIMER_REG_CNTR1 1       /* timer 1 counter port */
-#define        TIMER_REG_CNTR2 2       /* timer 2 counter port */
-#define        TIMER_REG_MODE  3       /* timer mode port */
-#define        TIMER_SEL0      0x00    /* select counter 0 */
-#define        TIMER_SEL1      0x40    /* select counter 1 */
-#define        TIMER_SEL2      0x80    /* select counter 2 */
-#define        TIMER_INTTC     0x00    /* mode 0, intr on terminal cnt */
-#define        TIMER_ONESHOT   0x02    /* mode 1, one shot */
-#define        TIMER_RATEGEN   0x04    /* mode 2, rate generator */
-#define        TIMER_SQWAVE    0x06    /* mode 3, square wave */
-#define        TIMER_SWSTROBE  0x08    /* mode 4, s/w triggered strobe */
-#define        TIMER_HWSTROBE  0x0a    /* mode 5, h/w triggered strobe */
-#define        TIMER_LATCH     0x00    /* latch counter for reading */
-#define        TIMER_LSB       0x10    /* r/w counter LSB */
-#define        TIMER_MSB       0x20    /* r/w counter MSB */
-#define        TIMER_16BIT     0x30    /* r/w counter 16 bits, LSB first */
-#define        TIMER_BCD       0x01    /* count in BCD */
-
-#define PIT_FREQ                                       1193182
-
-#define IO_TIMER1   0x40        /* 8253 Timer #1 */
-#define TIMER_CNTR0 (IO_TIMER1 + TIMER_REG_CNTR0)
-#define TIMER_CNTR1 (IO_TIMER1 + TIMER_REG_CNTR1)
-#define TIMER_CNTR2 (IO_TIMER1 + TIMER_REG_CNTR2)
-#define TIMER_MODE  (IO_TIMER1 + TIMER_REG_MODE)
-
-typedef struct system_timing {
-       uint64_t tsc_freq;
-       uint64_t bus_freq;
-       uint64_t timing_overhead;
-       uint16_t pit_divisor;
-       uint8_t pit_mode;
-} system_timing_t;
-
-extern system_timing_t system_timing;
-
-/* Tracks whether it is safe to execute core_id() or not.  If we're using the
- * LAPIC, we need to have the LAPIC mapped into VM.  vm_init() sets this to
- * TRUE.
- *
- * If we're using rdtscp, if the instruction is supported, we can call core_id()
- * without rebooting.  cpuinfo should have panic'd if we're running on a machine
- * that doesn't support rdtscp, before vm_init().
- *
- * If we're using something else (like segmentation), then that will need to get
- * set up before vm_init(), at least for core 0.
- *
- * Note that core_id() will return 0 (or possibly another wrong answer) on cores
- * other than core 0 when it is called before smp_boot completes. */
-extern bool core_id_ready;
-
-void pic_remap(void);
-void pic_mask_irq(uint8_t irq);
-void pic_unmask_irq(uint8_t irq);
-uint16_t pic_get_mask(void);
-uint16_t pic_get_irr(void);
-uint16_t pic_get_isr(void);
+#define LAPIC_ISR                                      0x10
+#define LAPIC_IRR                                      0x20
+#define LAPIC_DFR                                      0x0e
+
+struct irq_handler;    /* include loops */
+
+bool lapic_check_spurious(int trap_nr);
 bool lapic_get_isr_bit(uint8_t vector);
 bool lapic_get_irr_bit(uint8_t vector);
 void lapic_print_isr(void);
+void lapic_mask_irq(struct irq_handler *unused, int apic_vector);
+void lapic_unmask_irq(struct irq_handler *unused, int apic_vector);
 bool ipi_is_pending(uint8_t vector);
 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
 void lapic_set_timer(uint32_t usec, bool periodic);
 uint32_t lapic_get_default_id(void);
-// PIT related
-void pit_set_timer(uint32_t freq, uint32_t mode);
-void timer_init(void);
-void udelay_pit(uint64_t usec);
-// TODO: right now timer defaults to TSC
-uint64_t gettimer(void);
-uint64_t getfreq(void);
-
-static inline void pic_send_eoi(uint32_t irq);
-static inline void lapic_send_eoi(void);
+int apiconline(void);
+void handle_lapic_error(struct hw_trapframe *hw_tf, void *data);
+uint32_t apicrget(uint64_t r);
+void apicrput(uint64_t r, uint32_t data);
+void apicsendipi(uint64_t data);
+void apic_isr_dump(void);
+void apic_irr_dump(void);
+
+static inline void lapic_send_eoi(int unused);
 static inline uint32_t lapic_get_version(void);
 static inline uint32_t lapic_get_error(void);
 static inline uint32_t lapic_get_id(void);
-static inline void lapic_set_id(uint8_t id); // Careful, may not actually work
 static inline uint8_t lapic_get_logid(void);
-static inline void lapic_set_logid(uint8_t id);
 static inline void lapic_disable_timer(void);
 static inline void lapic_disable(void);
 static inline void lapic_enable(void);
-static inline void lapic_wait_to_send(void);
 static inline void send_init_ipi(void);
 static inline void send_startup_ipi(uint8_t vector);
 static inline void send_self_ipi(uint8_t vector);
@@ -180,58 +86,41 @@ static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector);
 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
 static inline void __send_nmi(uint8_t hw_coreid);
 
+/* XXX: remove these */
 #define mask_lapic_lvt(entry) \
-       write_mmreg32(entry, read_mmreg32(entry) | LAPIC_LVT_MASK)
+       apicrput(entry, apicrget(entry) | LAPIC_LVT_MASK)
 #define unmask_lapic_lvt(entry) \
-       write_mmreg32(entry, read_mmreg32(entry) & ~LAPIC_LVT_MASK)
+       apicrput(entry, apicrget(entry) & ~LAPIC_LVT_MASK)
 
-static inline void pic_send_eoi(uint32_t irq)
+static inline void lapic_send_eoi(int unused)
 {
-       // all irqs beyond the first seven need to be chained to the slave
-       if (irq > 7)
-               outb(PIC2_CMD, PIC_EOI);
-       outb(PIC1_CMD, PIC_EOI);
-}
-
-static inline void lapic_send_eoi(void)
-{
-       write_mmreg32(LAPIC_EOI, 0);
+       apicrput(MSR_LAPIC_EOI, 0);
 }
 
 static inline uint32_t lapic_get_version(void)
 {
-       return read_mmreg32(LAPIC_VERSION);     
+       return apicrget(MSR_LAPIC_VERSION);
 }
 
 static inline uint32_t lapic_get_error(void)
 {
-       write_mmreg32(LAPIC_ERROR, 0xdeadbeef);
-       return read_mmreg32(LAPIC_ERROR);
+       apicrput(MSR_LAPIC_ESR, 0xdeadbeef);
+       return apicrget(MSR_LAPIC_ESR);
 }
 
 static inline uint32_t lapic_get_id(void)
 {
-       return read_mmreg32(LAPIC_ID) >> 24;
-}
-
-static inline void lapic_set_id(uint8_t id)
-{
-       write_mmreg32(LAPIC_ID, id << 24);
+       return apicrget(MSR_LAPIC_ID);
 }
 
 static inline uint8_t lapic_get_logid(void)
 {
-       return read_mmreg32(LAPIC_LOGICAL_ID) >> 24;
-}
-
-static inline void lapic_set_logid(uint8_t id)
-{
-       write_mmreg32(LAPIC_LOGICAL_ID, id << 24);
+       return apicrget(MSR_LAPIC_LDR);
 }
 
 static inline void lapic_disable_timer(void)
 {
-       write_mmreg32(LAPIC_LVT_TIMER, 0);
+       apicrput(MSR_LAPIC_LVT_TIMER, 0);
 }
 
 /* There are a couple ways to do it.  The MSR route doesn't seem to work
@@ -239,75 +128,55 @@ static inline void lapic_disable_timer(void)
  */
 static inline void lapic_disable(void)
 {
-       write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) & 0xffffefff);
+       apicrput(MSR_LAPIC_SPURIOUS, apicrget(MSR_LAPIC_SPURIOUS) & 0xffffefff);
        //write_msr(IA32_APIC_BASE, read_msr(IA32_APIC_BASE) & ~MSR_APIC_ENABLE);
 }
 
-/* Spins until previous IPIs are delivered.  Not sure if we want it inlined
- * Also not sure when we really need to do this. 
- */
-static inline void lapic_wait_to_send(void)
-{
-       while(read_mmreg32(LAPIC_IPI_ICR_LOWER) & 0x1000)
-               __cpu_relax();
-}
-
 static inline void lapic_enable(void)
 {
-       write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) | 0x00000100);
+       apicrput(MSR_LAPIC_SPURIOUS, apicrget(MSR_LAPIC_SPURIOUS) | 0x00000100);
 }
 
 static inline void send_init_ipi(void)
 {
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4500);
-       lapic_wait_to_send();
+       apicsendipi(0xFFFFFFFF000c4500);
 }
 
 static inline void send_startup_ipi(uint8_t vector)
 {
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4600 | vector);
-       lapic_wait_to_send();
+       apicsendipi(0xFFFFFFFF000c4600ULL | vector);
 }
 
 static inline void send_self_ipi(uint8_t vector)
 {
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00044000 | vector);
-       lapic_wait_to_send();
+       apicrput(MSR_LAPIC_SELF_IPI, 0x00000000 | vector);
 }
 
 static inline void send_broadcast_ipi(uint8_t vector)
 {
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00084000 | vector);
-       lapic_wait_to_send();
+       apicsendipi(0xFFFFFFFF00084000ULL | vector);
 }
 
 static inline void send_all_others_ipi(uint8_t vector)
 {
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4000 | vector);
-       lapic_wait_to_send();
+       apicsendipi(0xFFFFFFFF000c4000ULL | vector);
 }
 
 static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector)
 {
-       write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004000 | vector);
-       lapic_wait_to_send();
+       apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004000 | vector);
 }
 
 static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
 {
-       write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_groupid << 24);
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004800 | vector);
-       lapic_wait_to_send();
+       apicsendipi(((uint64_t)hw_groupid << 32) | 0x00004800 | vector);
 }
 
 static inline void __send_nmi(uint8_t hw_coreid)
 {
        if (hw_coreid == 255)
                return;
-       write_mmreg32(LAPIC_IPI_ICR_UPPER, hw_coreid << 24);
-       write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004400);
-       lapic_wait_to_send();
+       apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004400);
 }
 
 /* To change the LAPIC Base (not recommended):
@@ -315,4 +184,92 @@ static inline void __send_nmi(uint8_t hw_coreid)
        msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
        write_msr(IA32_APIC_BASE, msr_val);
 */
-#endif /* ROS_KERN_APIC_H */
+
+/*
+ * This file is part of the UCB release of Plan 9. It is subject to the license
+ * terms in the LICENSE file found in the top-level directory of this
+ * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
+ * part of the UCB release of Plan 9, including this file, may be copied,
+ * modified, propagated, or distributed except according to the terms contained
+ * in the LICENSE file.
+ */
+
+/*
+ * There are 2 flavours of APIC, Local APIC and IOAPIC,
+ * Each I/O APIC has a unique physical address,
+ * Local APICs are all at the same physical address as they can only be
+ * accessed by the local CPU.  APIC ids are unique to the
+ * APIC type, so an IOAPIC and APIC both with id 0 is ok.
+ */
+
+struct ioapic {
+       spinlock_t lock;                        /* IOAPIC: register access */
+       uintptr_t addr;                         /* IOAPIC: register base */
+       uintptr_t paddr;                        /* register base */
+       int nrdt;                                       /* IOAPIC: size of RDT */
+       int ibase;                                      /* global interrupt base */
+};
+
+struct lapic {
+       int machno;                                     /* similar to os_coreid, unused */
+
+       uint32_t lvt[8];
+       int nlvt;
+       int ver;
+};
+
+struct apic {
+       int useable;                            /* en */
+       struct ioapic;
+       struct lapic;
+};
+
+enum {
+       Nbus = 256,
+       Napic = 254,    /* xAPIC architectural limit */
+       Nrdt = 64,
+};
+
+/*
+ * Common bits for
+ *     IOAPIC Redirection Table Entry (RDT);
+ *     APIC Local Vector Table Entry (LVT);
+ *     APIC Interrupt Command Register (ICR).
+ * [10:8] Message Type
+ * [11] Destination Mode (RW)
+ * [12] Delivery Status (RO)
+ * [13] Interrupt Input Pin Polarity (RW)
+ * [14] Remote IRR (RO)
+ * [15] Trigger Mode (RW)
+ * [16] Interrupt Mask
+ */
+enum {
+       MTf = 0x00000000,                       /* Fixed */
+       MTlp = 0x00000100,      /* Lowest Priority */
+       MTsmi = 0x00000200,     /* SMI */
+       MTrr = 0x00000300,      /* Remote Read */
+       MTnmi = 0x00000400,     /* NMI */
+       MTir = 0x00000500,      /* INIT/RESET */
+       MTsipi = 0x00000600,    /* Startup IPI */
+       MTei = 0x00000700,      /* ExtINT */
+
+       Pm = 0x00000000,        /* Physical Mode */
+       Lm = 0x00000800,        /* Logical Mode */
+
+       Ds = 0x00001000,        /* Delivery Status */
+       IPhigh = 0x00000000,    /* IIPP High */
+       IPlow = 0x00002000,     /* IIPP Low */
+       Rirr = 0x00004000,      /* Remote IRR */
+       TMedge = 0x00000000,    /* Trigger Mode Edge */
+       TMlevel = 0x00008000,   /* Trigger Mode Level */
+       Im = 0x00010000,        /* Interrupt Mask */
+};
+
+extern struct apic xlapic[Napic];
+extern struct apic xioapic[Napic];
+
+#include <arch/ioapic.h>
+
+char *apicdump(char *, char *);
+void apictimerenab(void);
+void apicinit(int apicno, uintptr_t pa, int isbp);