plan9fox/sys/src/9/pc/mp.h
cinap_lenrek 1d93a5628a pc, pc64, xen: rewrite interrupt handling code
This implements proper intrdisable() support for all
interrupt controllers.

For enable, (*arch->intrassign)(Vctl*) fills in the
Vctl.enable and Vctl.disable pointers with the
appropriate routines and returns the assigned
vector number.

Once the Vctl struct has been linked to its vector
chain, Vctl.enable(Vctl*, shared) gets called with a
flag if the vector has been already enabled (shared).

This order is important here as enabling the interrupt
on the controller before we have linked the chain can
cause spurious interrupts, expecially on mp system
where the interrupt can target a different cpu than
the caller of intrenable().

The intrdisable() case is the other way around.
We first disable the interrupt on the controller
and after that unlink the Vctl from the chain.
On a multiprocessor, the xfree() of the Vctl struct
is delayed to avoid freeing it while it is still
in use by another cpu.

The xen port now also uses pc/irq.c which has been
made generic enougth to handle xen's irq scheme.
Also, archgeneric is now a separate file to avoid
pulling in dependencies from the 8259 interrupt
controller code.
2020-11-29 17:43:22 +01:00

263 lines
7.3 KiB
C

/*
* MultiProcessor Specification Version 1.[14].
*/
typedef struct { /* floating pointer */
uchar signature[4]; /* "_MP_" */
long physaddr; /* physical address of MP configuration table */
uchar length; /* 1 */
uchar specrev; /* [14] */
uchar checksum; /* all bytes must add up to 0 */
uchar type; /* MP system configuration type */
uchar imcrp;
uchar reserved[3];
} _MP_;
#define _MP_sz (4+4+1+1+1+1+1+3)
typedef struct { /* configuration table header */
uchar signature[4]; /* "PCMP" */
ushort length; /* total table length */
uchar version; /* [14] */
uchar checksum; /* all bytes must add up to 0 */
uchar product[20]; /* product id */
ulong oemtable; /* OEM table pointer */
ushort oemlength; /* OEM table length */
ushort entry; /* entry count */
ulong lapicbase; /* address of local APIC */
ushort xlength; /* extended table length */
uchar xchecksum; /* extended table checksum */
uchar reserved;
} PCMP;
#define PCMPsz (4+2+1+1+20+4+2+2+4+2+1+1)
typedef struct { /* processor table entry */
uchar type; /* entry type (0) */
uchar apicno; /* local APIC id */
uchar version; /* local APIC verison */
uchar flags; /* CPU flags */
uchar signature[4]; /* CPU signature */
ulong feature; /* feature flags from CPUID instruction */
uchar reserved[8];
} PCMPprocessor;
#define PCMPprocessorsz (1+1+1+1+4+4+8)
typedef struct { /* bus table entry */
uchar type; /* entry type (1) */
uchar busno; /* bus id */
char string[6]; /* bus type string */
} PCMPbus;
#define PCMPbussz (1+1+6)
typedef struct { /* I/O APIC table entry */
uchar type; /* entry type (2) */
uchar apicno; /* I/O APIC id */
uchar version; /* I/O APIC version */
uchar flags; /* I/O APIC flags */
ulong addr; /* I/O APIC address */
} PCMPioapic;
#define PCMPioapicsz (1+1+1+1+4)
typedef struct { /* interrupt table entry */
uchar type; /* entry type ([34]) */
uchar intr; /* interrupt type */
ushort flags; /* interrupt flag */
uchar busno; /* source bus id */
uchar irq; /* source bus irq */
uchar apicno; /* destination APIC id */
uchar intin; /* destination APIC [L]INTIN# */
} PCMPintr;
#define PCMPintrsz (1+1+2+1+1+1+1)
typedef struct { /* system address space mapping entry */
uchar type; /* entry type (128) */
uchar length; /* of this entry (20) */
uchar busno; /* bus id */
uchar addrtype;
ulong addrbase[2];
ulong addrlength[2];
} PCMPsasm;
#define PCMPsasmsz (1+1+1+1+8+8)
typedef struct { /* bus hierarchy descriptor entry */
uchar type; /* entry type (129) */
uchar length; /* of this entry (8) */
uchar busno; /* bus id */
uchar info; /* bus info */
uchar parent; /* parent bus */
uchar reserved[3];
} PCMPhierarchy;
#define PCMPhirarchysz (1+1+1+1+1+3)
typedef struct { /* compatibility bus address space modifier entry */
uchar type; /* entry type (130) */
uchar length; /* of this entry (8) */
uchar busno; /* bus id */
uchar modifier; /* address modifier */
ulong range; /* predefined range list */
} PCMPcbasm;
#define PCMPcbasmsz (1+1+1+1+4)
enum { /* table entry types */
PcmpPROCESSOR = 0x00, /* one entry per processor */
PcmpBUS = 0x01, /* one entry per bus */
PcmpIOAPIC = 0x02, /* one entry per I/O APIC */
PcmpIOINTR = 0x03, /* one entry per bus interrupt source */
PcmpLINTR = 0x04, /* one entry per system interrupt source */
PcmpSASM = 0x80,
PcmpHIERARCHY = 0x81,
PcmpCBASM = 0x82,
/* PCMPprocessor and PCMPioapic flags */
PcmpEN = 0x01, /* enabled */
PcmpBP = 0x02, /* bootstrap processor */
/* PCMPiointr and PCMPlintr flags */
PcmpPOMASK = 0x03, /* polarity conforms to specifications of bus */
PcmpHIGH = 0x01, /* active high */
PcmpLOW = 0x03, /* active low */
PcmpELMASK = 0x0C, /* trigger mode of APIC input signals */
PcmpEDGE = 0x04, /* edge-triggered */
PcmpLEVEL = 0x0C, /* level-triggered */
/* PCMPiointr and PCMPlintr interrupt type */
PcmpINT = 0x00, /* vectored interrupt from APIC Rdt */
PcmpNMI = 0x01, /* non-maskable interrupt */
PcmpSMI = 0x02, /* system management interrupt */
PcmpExtINT = 0x03, /* vectored interrupt from external PIC */
/* PCMPsasm addrtype */
PcmpIOADDR = 0x00, /* I/O address */
PcmpMADDR = 0x01, /* memory address */
PcmpPADDR = 0x02, /* prefetch address */
/* PCMPhierarchy info */
PcmpSD = 0x01, /* subtractive decode bus */
/* PCMPcbasm modifier */
PcmpPR = 0x01, /* predefined range list */
};
/*
* Condensed form of the MP Configuration Table.
* This is created during a single pass through the MP Configuration
* table.
*/
typedef struct Aintr Aintr;
typedef struct Bus Bus;
typedef struct Apic Apic;
typedef struct Bus {
uchar type;
uchar busno;
uchar po;
uchar el;
Aintr* aintr; /* interrupts tied to this bus */
Bus* next;
} Bus;
typedef struct Aintr {
PCMPintr* intr;
Apic* apic;
Bus* bus;
Aintr* next;
};
typedef struct Apic {
int type;
int apicno;
ulong* addr; /* register base address */
ulong paddr;
int flags; /* PcmpBP|PcmpEN */
Lock; /* I/O APIC: register access */
int mre; /* I/O APIC: maximum redirection entry */
int gsibase; /* I/O APIC: global system interrupt base (acpi) */
int lintr[2]; /* Local APIC */
int machno;
int online;
} Apic;
enum {
MaxAPICNO = 254, /* 255 is physical broadcast */
};
enum { /* I/O APIC registers */
IoapicID = 0x00, /* ID */
IoapicVER = 0x01, /* version */
IoapicARB = 0x02, /* arbitration ID */
IoapicRDT = 0x10, /* redirection table */
};
/*
* Common bits for
* I/O APIC Redirection Table Entry;
* Local APIC Local Interrupt Vector Table;
* Local APIC Inter-Processor Interrupt;
* Local APIC Timer Vector Table.
*/
enum {
ApicFIXED = 0x00000000, /* [10:8] Delivery Mode */
ApicLOWEST = 0x00000100, /* Lowest priority */
ApicSMI = 0x00000200, /* System Management Interrupt */
ApicRR = 0x00000300, /* Remote Read */
ApicNMI = 0x00000400,
ApicINIT = 0x00000500, /* INIT/RESET */
ApicSTARTUP = 0x00000600, /* Startup IPI */
ApicExtINT = 0x00000700,
ApicPHYSICAL = 0x00000000, /* [11] Destination Mode (RW) */
ApicLOGICAL = 0x00000800,
ApicDELIVS = 0x00001000, /* [12] Delivery Status (RO) */
ApicHIGH = 0x00000000, /* [13] Interrupt Input Pin Polarity (RW) */
ApicLOW = 0x00002000,
ApicRemoteIRR = 0x00004000, /* [14] Remote IRR (RO) */
ApicEDGE = 0x00000000, /* [15] Trigger Mode (RW) */
ApicLEVEL = 0x00008000,
ApicIMASK = 0x00010000, /* [16] Interrupt Mask */
};
extern void ioapicinit(Apic*, int);
extern void ioapicrdtr(Apic*, int, int*, int*);
extern void ioapicrdtw(Apic*, int, int, int);
extern void lapicclock(Ureg*, void*);
extern int lapiceoi(int);
extern void lapicerror(Ureg*, void*);
extern void lapicicrw(ulong, ulong);
extern void lapicinit(Apic*);
extern void lapicintroff(void);
extern void lapicintron(void);
extern int lapicisr(int);
extern void lapicnmidisable(void);
extern void lapicnmienable(void);
extern void lapiconline(void);
extern void lapicspurious(Ureg*, void*);
extern void lapicstartap(Apic*, int);
extern void lapictimerset(uvlong);
extern int mpintrinit(Bus*, PCMPintr*, int, int);
extern void mpinit(void);
extern int mpintrassign(Vctl*);
extern void mpshutdown(void);
extern void mpstartap(Apic*);
extern Bus* mpbus;
extern Bus* mpbuslast;
extern int mpisabus;
extern int mpeisabus;
extern Apic *mpioapic[];
extern Apic *mpapic[];