akaros/kern/arch/x86/apic.h
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2009 The Regents of the University of California
   3 * Barret Rhoden <brho@cs.berkeley.edu>
   4 * See LICENSE for details.
   5 */
   6
   7#pragma once
   8
   9/*
  10 * Functions and definitions for dealing with the APIC and PIC, specific to
  11 * Intel.  Does not handle an x2APIC.
  12 */
  13#include <arch/mmu.h>
  14#include <arch/x86.h>
  15#include <ros/trapframe.h>
  16#include <atomic.h>
  17#include <endian.h>
  18#include <arch/ros/msr-index.h>
  19
  20// Local APIC
  21/* PBASE is the physical address.  It is mapped in at the VADDR LAPIC_BASE.
  22 * 64 bit note: it looks like this is mapped to the same place in 64 bit address
  23 * spaces.  We just happen to have a slight 'hole' in addressable physical
  24 * memory.  We can move the PBASE, but we're limited to 32 bit (physical)
  25 * addresses. */
  26#define LAPIC_PBASE             0xfee00000      /* default *physical* address */
  27#define LAPIC_LVT_MASK          0x00010000
  28
  29/* Quick note on the divisor.  The LAPIC timer ticks once per divisor-bus ticks
  30 * (system bus or APIC bus, depending on the model).  Ex: A divisor of 128 means
  31 * 128 bus ticks results in 1 timer tick.  The divisor increases the time range
  32 * and decreases the granularity of the timer.  Numbers are appx, based on 4
  33 * billion ticks, vs 2^32 ticks.
  34 * Ex:   1GHz bus, div 001:    4sec max,    1ns granularity
  35 * Ex:   1GHz bus, div 128:  512sec max,  128ns granularity
  36 * Ex: 100MHz bus, div 001:   40sec max,   10ns granularity
  37 * Ex: 100MHz bus, div 128: 5120sec max, 1280ns granularity */
  38#define LAPIC_TIMER_DIVISOR_VAL         32      /* seems reasonable */
  39#define LAPIC_TIMER_DIVISOR_BITS        0x8     /* Div = 32 */
  40
  41// IPI Interrupt Command Register
  42#define LAPIC_IPI_ICR_LOWER     0x30
  43#define LAPIC_IPI_ICR_UPPER     0x31
  44/* Interrupts being serviced (in-service) and pending (interrupt request reg).
  45 * Note these registers are not normal bitmaps, but instead are 8 separate
  46 * 32-bit registers, spaced/aligned on 16 byte boundaries in the LAPIC address
  47 * space. */
  48#define LAPIC_ISR               0x10
  49#define LAPIC_IRR               0x20
  50#define LAPIC_DFR               0x0e
  51
  52struct irq_handler;     /* include loops */
  53
  54bool lapic_check_spurious(int trap_nr);
  55bool lapic_get_isr_bit(uint8_t vector);
  56bool lapic_get_irr_bit(uint8_t vector);
  57void lapic_print_isr(void);
  58void lapic_mask_irq(struct irq_handler *unused, int apic_vector);
  59void lapic_unmask_irq(struct irq_handler *unused, int apic_vector);
  60bool ipi_is_pending(uint8_t vector);
  61void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
  62void lapic_set_timer(uint32_t usec, bool periodic);
  63uint32_t lapic_get_default_id(void);
  64int apiconline(void);
  65void handle_lapic_error(struct hw_trapframe *hw_tf, void *data);
  66uint32_t apicrget(uint64_t r);
  67void apicrput(uint64_t r, uint32_t data);
  68void apicsendipi(uint64_t data);
  69void apic_isr_dump(void);
  70void apic_irr_dump(void);
  71
  72static inline void lapic_send_eoi(int unused);
  73static inline uint32_t lapic_get_version(void);
  74static inline uint32_t lapic_get_error(void);
  75static inline uint32_t lapic_get_id(void);
  76static inline uint8_t lapic_get_logid(void);
  77static inline void lapic_disable_timer(void);
  78static inline void lapic_disable(void);
  79static inline void lapic_enable(void);
  80static inline void send_init_ipi(void);
  81static inline void send_startup_ipi(uint8_t vector);
  82static inline void send_self_ipi(uint8_t vector);
  83static inline void send_broadcast_ipi(uint8_t vector);
  84static inline void send_all_others_ipi(uint8_t vector);
  85static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector);
  86static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector);
  87static inline void __send_nmi(uint8_t hw_coreid);
  88
  89/* XXX: remove these */
  90#define mask_lapic_lvt(entry) \
  91        apicrput(entry, apicrget(entry) | LAPIC_LVT_MASK)
  92#define unmask_lapic_lvt(entry) \
  93        apicrput(entry, apicrget(entry) & ~LAPIC_LVT_MASK)
  94
  95static inline void lapic_send_eoi(int unused)
  96{
  97        apicrput(MSR_LAPIC_EOI, 0);
  98}
  99
 100static inline uint32_t lapic_get_version(void)
 101{
 102        return apicrget(MSR_LAPIC_VERSION);
 103}
 104
 105static inline uint32_t lapic_get_error(void)
 106{
 107        apicrput(MSR_LAPIC_ESR, 0xdeadbeef);
 108        return apicrget(MSR_LAPIC_ESR);
 109}
 110
 111static inline uint32_t lapic_get_id(void)
 112{
 113        return apicrget(MSR_LAPIC_ID);
 114}
 115
 116static inline uint8_t lapic_get_logid(void)
 117{
 118        return apicrget(MSR_LAPIC_LDR);
 119}
 120
 121static inline void lapic_disable_timer(void)
 122{
 123        apicrput(MSR_LAPIC_LVT_TIMER, 0);
 124}
 125
 126/* There are a couple ways to do it.  The MSR route doesn't seem to work
 127 * in KVM.  It's also a somewhat permanent thing
 128 */
 129static inline void lapic_disable(void)
 130{
 131        apicrput(MSR_LAPIC_SPURIOUS, apicrget(MSR_LAPIC_SPURIOUS) & 0xffffefff);
 132}
 133
 134static inline void lapic_enable(void)
 135{
 136        apicrput(MSR_LAPIC_SPURIOUS, apicrget(MSR_LAPIC_SPURIOUS) | 0x00000100);
 137}
 138
 139static inline void send_init_ipi(void)
 140{
 141        apicsendipi(0xFFFFFFFF000c4500);
 142}
 143
 144static inline void send_startup_ipi(uint8_t vector)
 145{
 146        apicsendipi(0xFFFFFFFF000c4600ULL | vector);
 147}
 148
 149static inline void send_self_ipi(uint8_t vector)
 150{
 151        apicrput(MSR_LAPIC_SELF_IPI, 0x00000000 | vector);
 152}
 153
 154static inline void send_broadcast_ipi(uint8_t vector)
 155{
 156        apicsendipi(0xFFFFFFFF00084000ULL | vector);
 157}
 158
 159static inline void send_all_others_ipi(uint8_t vector)
 160{
 161        apicsendipi(0xFFFFFFFF000c4000ULL | vector);
 162}
 163
 164static inline void __send_ipi(uint8_t hw_coreid, uint8_t vector)
 165{
 166        apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004000 | vector);
 167}
 168
 169static inline void send_group_ipi(uint8_t hw_groupid, uint8_t vector)
 170{
 171        apicsendipi(((uint64_t)hw_groupid << 32) | 0x00004800 | vector);
 172}
 173
 174static inline void __send_nmi(uint8_t hw_coreid)
 175{
 176        if (hw_coreid == 255)
 177                return;
 178        apicsendipi(((uint64_t)hw_coreid << 32) | 0x00004400);
 179}
 180
 181/* To change the LAPIC Base (not recommended):
 182        msr_val = read_msr(IA32_APIC_BASE);
 183        msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
 184        write_msr(IA32_APIC_BASE, msr_val);
 185*/
 186
 187/*
 188 * This file is part of the UCB release of Plan 9. It is subject to the license
 189 * terms in the LICENSE file found in the top-level directory of this
 190 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
 191 * part of the UCB release of Plan 9, including this file, may be copied,
 192 * modified, propagated, or distributed except according to the terms contained
 193 * in the LICENSE file.
 194 */
 195
 196/*
 197 * There are 2 flavours of APIC, Local APIC and IOAPIC,
 198 * Each I/O APIC has a unique physical address,
 199 * Local APICs are all at the same physical address as they can only be
 200 * accessed by the local CPU.  APIC ids are unique to the
 201 * APIC type, so an IOAPIC and APIC both with id 0 is ok.
 202 */
 203
 204struct ioapic {
 205        spinlock_t lock;        /* IOAPIC: register access */
 206        uintptr_t addr;         /* IOAPIC: register base */
 207        uintptr_t paddr;        /* register base */
 208        int nrdt;               /* IOAPIC: size of RDT */
 209        int ibase;              /* global interrupt base */
 210};
 211
 212struct lapic {
 213        int machno;             /* similar to os_coreid, unused */
 214
 215        uint32_t lvt[8];
 216        int nlvt;
 217        int ver;
 218};
 219
 220struct apic {
 221        int useable;                            /* en */
 222        struct ioapic;
 223        struct lapic;
 224};
 225
 226enum {
 227        Nbus = 256,
 228        Napic = 254,    /* xAPIC architectural limit */
 229        Nrdt = 64,
 230};
 231
 232/*
 233 * Common bits for
 234 *      IOAPIC Redirection Table Entry (RDT);
 235 *      APIC Local Vector Table Entry (LVT);
 236 *      APIC Interrupt Command Register (ICR).
 237 * [10:8] Message Type
 238 * [11] Destination Mode (RW)
 239 * [12] Delivery Status (RO)
 240 * [13] Interrupt Input Pin Polarity (RW)
 241 * [14] Remote IRR (RO)
 242 * [15] Trigger Mode (RW)
 243 * [16] Interrupt Mask
 244 */
 245enum {
 246        MTf = 0x00000000,       /* Fixed */
 247        MTlp = 0x00000100,      /* Lowest Priority */
 248        MTsmi = 0x00000200,     /* SMI */
 249        MTrr = 0x00000300,      /* Remote Read */
 250        MTnmi = 0x00000400,     /* NMI */
 251        MTir = 0x00000500,      /* INIT/RESET */
 252        MTsipi = 0x00000600,    /* Startup IPI */
 253        MTei = 0x00000700,      /* ExtINT */
 254
 255        Pm = 0x00000000,        /* Physical Mode */
 256        Lm = 0x00000800,        /* Logical Mode */
 257
 258        Ds = 0x00001000,        /* Delivery Status */
 259        IPhigh = 0x00000000,    /* IIPP High */
 260        IPlow = 0x00002000,     /* IIPP Low */
 261        Rirr = 0x00004000,      /* Remote IRR */
 262        TMedge = 0x00000000,    /* Trigger Mode Edge */
 263        TMlevel = 0x00008000,   /* Trigger Mode Level */
 264        Im = 0x00010000,        /* Interrupt Mask */
 265};
 266
 267extern struct apic xlapic[Napic];
 268extern struct apic xioapic[Napic];
 269
 270#include <arch/ioapic.h>
 271
 272char *apicdump(char *, char *);
 273void apictimerenab(void);
 274void apicinit(int apicno, uintptr_t pa, int isbp);
 275