/*
* Copyright (c) 2001-2004 Jakub Jermar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @addtogroup kernel_ia32
* @{
*/
/** @file
*/
#ifndef KERN_ia32_APIC_H_
#define KERN_ia32_APIC_H_
#define L_APIC_BASE 0xfee00000
#define IO_APIC_BASE 0xfec00000
#ifndef __ASSEMBLER__
#include <cpu.h>
#include <stdint.h>
#include <genarch/pic/pic_ops.h>
#define FIXED (0 << 0)
#define LOPRI (1 << 0)
#define APIC_ID_COUNT 16
/* local APIC macros */
#define IPI_INIT 0
#define IPI_STARTUP 0
/** Delivery modes. */
#define DELMOD_FIXED 0x0U
#define DELMOD_LOWPRI 0x1U
#define DELMOD_SMI 0x2U
/* 0x3 reserved */
#define DELMOD_NMI 0x4U
#define DELMOD_INIT 0x5U
#define DELMOD_STARTUP 0x6U
#define DELMOD_EXTINT 0x7U
/** Destination modes. */
#define DESTMOD_PHYS 0x0U
#define DESTMOD_LOGIC 0x1U
/** Trigger Modes. */
#define TRIGMOD_EDGE 0x0U
#define TRIGMOD_LEVEL 0x1U
/** Levels. */
#define LEVEL_DEASSERT 0x0U
#define LEVEL_ASSERT 0x1U
/** Destination Shorthands. */
#define SHORTHAND_NONE 0x0U
#define SHORTHAND_SELF 0x1U
#define SHORTHAND_ALL_INCL 0x2U
#define SHORTHAND_ALL_EXCL 0x3U
/** Interrupt Input Pin Polarities. */
#define POLARITY_HIGH 0x0U
#define POLARITY_LOW 0x1U
/** Divide Values. (Bit 2 is always 0) */
#define DIVIDE_2 0x0U
#define DIVIDE_4 0x1U
#define DIVIDE_8 0x2U
#define DIVIDE_16 0x3U
#define DIVIDE_32 0x8U
#define DIVIDE_64 0x9U
#define DIVIDE_128 0xaU
#define DIVIDE_1 0xbU
/** Timer Modes. */
#define TIMER_ONESHOT 0x0U
#define TIMER_PERIODIC 0x1U
/** Delivery status. */
#define DELIVS_IDLE 0x0U
#define DELIVS_PENDING 0x1U
/** Destination masks. */
#define DEST_ALL 0xffU
/** Dest format models. */
#define MODEL_FLAT 0xfU
#define MODEL_CLUSTER 0x0U
/** Interrupt Command Register. */
#define ICRlo (0x300U / sizeof(uint32_t))
#define ICRhi (0x310U / sizeof(uint32_t))
typedef struct {
union {
uint32_t lo;
struct {
uint8_t vector; /**< Interrupt Vector. */
unsigned int delmod : 3; /**< Delivery Mode. */
unsigned int destmod : 1; /**< Destination Mode. */
unsigned int delivs : 1; /**< Delivery status (RO). */
unsigned int : 1; /**< Reserved. */
unsigned int level : 1; /**< Level. */
unsigned int trigger_mode : 1; /**< Trigger Mode. */
unsigned int : 2; /**< Reserved. */
unsigned int shorthand : 2; /**< Destination Shorthand. */
unsigned int : 12; /**< Reserved. */
} __attribute__((packed));
};
union {
uint32_t hi;
struct {
unsigned int : 24; /**< Reserved. */
uint8_t dest; /**< Destination field. */
} __attribute__((packed));
};
} __attribute__((packed)) icr_t;
/* End Of Interrupt. */
#define EOI (0x0b0U / sizeof(uint32_t))
/** Error Status Register. */
#define ESR (0x280U / sizeof(uint32_t))
typedef union {
uint32_t value;
uint8_t err_bitmap;
struct {
unsigned int send_checksum_error : 1;
unsigned int receive_checksum_error : 1;
unsigned int send_accept_error : 1;
unsigned int receive_accept_error : 1;
unsigned int : 1;
unsigned int send_illegal_vector : 1;
unsigned int received_illegal_vector : 1;
unsigned int illegal_register_address : 1;
unsigned int : 24;
} __attribute__((packed));
} esr_t;
/* Task Priority Register */
#define TPR (0x080U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
unsigned int pri_sc : 4; /**< Task Priority Sub-Class. */
unsigned int pri : 4; /**< Task Priority. */
} __attribute__((packed));
} tpr_t;
/** Spurious-Interrupt Vector Register. */
#define SVR (0x0f0U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
uint8_t vector; /**< Spurious Vector. */
unsigned int lapic_enabled : 1; /**< APIC Software Enable/Disable. */
unsigned int focus_checking : 1; /**< Focus Processor Checking. */
unsigned int : 22; /**< Reserved. */
} __attribute__((packed));
} svr_t;
/** Time Divide Configuration Register. */
#define TDCR (0x3e0U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
unsigned int div_value : 4; /**< Divide Value, bit 2 is always 0. */
unsigned int : 28; /**< Reserved. */
} __attribute__((packed));
} tdcr_t;
/* Initial Count Register for Timer */
#define ICRT (0x380U / sizeof(uint32_t))
/* Current Count Register for Timer */
#define CCRT (0x390U / sizeof(uint32_t))
/** LVT Timer register. */
#define LVT_Tm (0x320U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
uint8_t vector; /**< Local Timer Interrupt vector. */
unsigned int : 4; /**< Reserved. */
unsigned int delivs : 1; /**< Delivery status (RO). */
unsigned int : 3; /**< Reserved. */
unsigned int masked : 1; /**< Interrupt Mask. */
unsigned int mode : 1; /**< Timer Mode. */
unsigned int : 14; /**< Reserved. */
} __attribute__((packed));
} lvt_tm_t;
/** LVT LINT registers. */
#define LVT_LINT0 (0x350U / sizeof(uint32_t))
#define LVT_LINT1 (0x360U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
uint8_t vector; /**< LINT Interrupt vector. */
unsigned int delmod : 3; /**< Delivery Mode. */
unsigned int : 1; /**< Reserved. */
unsigned int delivs : 1; /**< Delivery status (RO). */
unsigned int intpol : 1; /**< Interrupt Input Pin Polarity. */
unsigned int irr : 1; /**< Remote IRR (RO). */
unsigned int trigger_mode : 1; /**< Trigger Mode. */
unsigned int masked : 1; /**< Interrupt Mask. */
unsigned int : 15; /**< Reserved. */
} __attribute__((packed));
} lvt_lint_t;
/** LVT Error register. */
#define LVT_Err (0x370U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
uint8_t vector; /**< Local Timer Interrupt vector. */
unsigned int : 4; /**< Reserved. */
unsigned int delivs : 1; /**< Delivery status (RO). */
unsigned int : 3; /**< Reserved. */
unsigned int masked : 1; /**< Interrupt Mask. */
unsigned int : 15; /**< Reserved. */
} __attribute__((packed));
} lvt_error_t;
/** Local APIC ID Register. */
#define L_APIC_ID (0x020U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
unsigned int : 24; /**< Reserved. */
uint8_t apic_id; /**< Local APIC ID. */
} __attribute__((packed));
} l_apic_id_t;
/** Local APIC Version Register */
#define LAVR (0x030U / sizeof(uint32_t))
#define LAVR_Mask 0xffU
#define is_local_apic(x) (((x) & LAVR_Mask & 0xf0U) == 0x1U)
#define is_82489DX_apic(x) ((((x) & LAVR_Mask & 0xf0U) == 0x0U))
#define is_local_xapic(x) (((x) & LAVR_Mask) == 0x14U)
/** Logical Destination Register. */
#define LDR (0x0d0U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
unsigned int : 24; /**< Reserved. */
uint8_t id; /**< Logical APIC ID. */
} __attribute__((packed));
} ldr_t;
/** Destination Format Register. */
#define DFR (0x0e0U / sizeof(uint32_t))
typedef union {
uint32_t value;
struct {
unsigned int : 28; /**< Reserved, all ones. */
unsigned int model : 4; /**< Model. */
} __attribute__((packed));
} dfr_t;
/* IO APIC */
#define IOREGSEL (0x00U / sizeof(uint32_t))
#define IOWIN (0x10U / sizeof(uint32_t))
#define IOAPICID 0x00U
#define IOAPICVER 0x01U
#define IOAPICARB 0x02U
#define IOREDTBL 0x10U
/** I/O Register Select Register. */
typedef union {
uint32_t value;
struct {
uint8_t reg_addr; /**< APIC Register Address. */
unsigned int : 24; /**< Reserved. */
} __attribute__((packed));
} io_regsel_t;
/** I/O Redirection Register. */
typedef struct io_redirection_reg {
union {
uint32_t lo;
struct {
uint8_t intvec; /**< Interrupt Vector. */
unsigned int delmod : 3; /**< Delivery Mode. */
unsigned int destmod : 1; /**< Destination mode. */
unsigned int delivs : 1; /**< Delivery status (RO). */
unsigned int intpol : 1; /**< Interrupt Input Pin Polarity. */
unsigned int irr : 1; /**< Remote IRR (RO). */
unsigned int trigger_mode : 1; /**< Trigger Mode. */
unsigned int masked : 1; /**< Interrupt Mask. */
unsigned int : 15; /**< Reserved. */
} __attribute__((packed));
};
union {
uint32_t hi;
struct {
unsigned int : 24; /**< Reserved. */
uint8_t dest : 8; /**< Destination Field. */
} __attribute__((packed));
};
} __attribute__((packed)) io_redirection_reg_t;
/** IO APIC Identification Register. */
typedef union {
uint32_t value;
struct {
unsigned int : 24; /**< Reserved. */
unsigned int apic_id : 4; /**< IO APIC ID. */
unsigned int : 4; /**< Reserved. */
} __attribute__((packed));
} io_apic_id_t;
extern pic_ops_t apic_pic_ops;
extern volatile uint32_t *l_apic;
extern volatile uint32_t *io_apic;
extern uint32_t apic_id_mask;
extern uint8_t bsp_l_apic;
extern void apic_init(void);
extern void l_apic_init(void);
extern void l_apic_eoi(unsigned int);
extern int l_apic_send_custom_ipi(uint8_t, uint8_t);
extern int l_apic_broadcast_custom_ipi(uint8_t);
extern int l_apic_send_init_ipi(uint8_t);
extern void l_apic_debug(void);
extern uint32_t io_apic_read(uint8_t);
extern void io_apic_write(uint8_t, uint32_t);
extern void io_apic_change_ioredtbl(uint8_t pin, uint8_t dest, uint8_t v, unsigned int);
extern void io_apic_disable_irqs(uint16_t);
extern void io_apic_enable_irqs(uint16_t);
#endif /* __ASSEMBLER__ */
#endif
/** @}
*/