mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
166 lines
5.5 KiB
C
166 lines
5.5 KiB
C
/*
|
|
* Copyright (C) 2014 René Kijewski <rene.kijewski@fu-berlin.de>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/**
|
|
* The entry points for all interrupts on x86 boards.
|
|
*
|
|
* @ingroup x86
|
|
* @defgroup x86-irq Interrupt handling for i586 boards
|
|
* @{
|
|
* @file
|
|
* @author René Kijewski <rene.kijewski@fu-berlin.de>
|
|
*/
|
|
|
|
#ifndef CPU__X86__INTERRUPTS__H__
|
|
#define CPU__X86__INTERRUPTS__H__
|
|
|
|
#include "ucontext.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
* @brief Initialize interrupts.
|
|
*
|
|
* This function is called during initialization by x86_startup().
|
|
* You must not call this function on your own accord.
|
|
*/
|
|
void x86_init_interrupts(void);
|
|
|
|
#define X86_MAX_INTERRUPTS (0x30)
|
|
|
|
/**
|
|
* @brief The exceptions in an x86 system.
|
|
*
|
|
* http://www.sandpile.org/x86/except.htm
|
|
*/
|
|
enum x86_interrupt_numbers {
|
|
X86_INT_DE = 0x00, /**< divide error */
|
|
X86_INT_DB = 0x01, /**< debug (thrown after each instruction if X86_TF is activated) */
|
|
X86_INT_BP = 0x03, /**< breakpoint (`int3`) */
|
|
X86_INT_OF = 0x04, /**< overflow (`into`) */
|
|
X86_INT_BR = 0x05, /**< boundary range exceeded (`bound`) */
|
|
X86_INT_UD = 0x06, /**< undefined opcode */
|
|
X86_INT_NM = 0x07, /**< device not available (raised on FPU accessing if CR0.TS is set) */
|
|
X86_INT_DF = 0x08, /**< double fault (exceptions during exception handler invocation) */
|
|
X86_INT_GP = 0x0d, /**< general protection */
|
|
X86_INT_PF = 0x0e, /**< page fault */
|
|
X86_INT_MF = 0x10, /**< math fault */
|
|
X86_INT_AC = 0x11, /**< alignment checking */
|
|
X86_INT_MC = 0x12, /**< machine check */
|
|
};
|
|
|
|
/**
|
|
* @brief Bits in the EFLAGS register.
|
|
*
|
|
* http://www.sandpile.org/x86/flags.htm
|
|
*/
|
|
enum x86_eflags {
|
|
X86_CF = 1 << 0, /**< carry */
|
|
X86_PF = 1 << 2, /**< parity */
|
|
X86_AF = 1 << 4, /**< adjust */
|
|
X86_ZF = 1 << 6, /**< zero */
|
|
X86_SF = 1 << 7, /**< signed */
|
|
X86_TF = 1 << 8, /**< singled step (throw #X86_INT_DB after each instruction) */
|
|
X86_IF = 1 << 9, /**< interrupts enabled */
|
|
X86_DF = 1 << 10, /**< direction (0 = movs increses addresses, 1 = movs decreases addresses) */
|
|
X86_OF = 1 << 11, /**< overflow */
|
|
X86_IOPL_0 = 0 << 12, /**< priority level 0 (?) */
|
|
X86_IOPL_1 = 1 << 12, /**< priority level 1 (?) */
|
|
X86_IOPL_2 = 2 << 12, /**< priority level 2 (?) */
|
|
X86_IOPL_3 = 3 << 12, /**< priority level 3 (?) */
|
|
X86_NT = 1 << 14, /**< nested task */
|
|
X86_RF = 1 << 16, /**< resume */
|
|
X86_VM = 1 << 17, /**< virtual 8086 mode */
|
|
X86_AC = 1 << 18, /**< alignment check */
|
|
X86_VIF = 1 << 19, /**< virtual interrupts enabled */
|
|
X86_VIP = 1 << 20, /**< virtual interrupts pendigng */
|
|
X86_ID = 1 << 21, /**< able to use CPUID */
|
|
};
|
|
|
|
/**
|
|
* @brief Datum for the Interrupt Descriptor Table Register.
|
|
*/
|
|
struct idtr_t {
|
|
uint16_t limit; /**< `sizeof (struct idt_desc) * count` */
|
|
void *base; /**< physical address of the start of the IDT */
|
|
} __attribute__((packed));
|
|
|
|
/**
|
|
* @brief One entry in the IDT
|
|
*/
|
|
struct idt_desc {
|
|
uint16_t offset_1; /**< offset bits 0..15 */
|
|
uint16_t selector; /**< a code segment selector in GDT or LDT */
|
|
uint8_t zero; /**< unused, set to 0 */
|
|
uint8_t type_attr; /**< type and attributes, see below */
|
|
uint16_t offset_2; /**< offset bits 16..31 */
|
|
} __attribute__((packed));
|
|
|
|
/**
|
|
* @brief Callback on interrupt.
|
|
* @param intr_num Number of interrupt -- not the number of the IRQ
|
|
* @param orig_ctx (Changable) register set of the calling thread
|
|
* @param error_code Related error code (if applies, otherwise 0)
|
|
*/
|
|
typedef void (*x86_intr_handler_t)(uint8_t intr_num, struct x86_pushad *orig_ctx, unsigned long error_code);
|
|
|
|
/**
|
|
* @brief Set callback function for interrupt.
|
|
* @param num Number of interrupt. Must be less than X86_MAX_INTERRUPTS.
|
|
* @param handler Function to call, or `NULL` to use default interrupt handler.
|
|
*
|
|
* This function is meant to be called by other subsystems (x86_pic.c and x86_threading.c).
|
|
* Any upper level system should use x86_pic_set_handler() or even higher level functions.
|
|
*/
|
|
void x86_interrupt_handler_set(unsigned num, x86_intr_handler_t handler);
|
|
|
|
/**
|
|
* @brief Disable interrupts and return previous EFLAGS.
|
|
*/
|
|
static inline unsigned long __attribute__((always_inline)) x86_pushf_cli(void)
|
|
{
|
|
unsigned long result;
|
|
__asm__ volatile("pushf; cli; pop %0" : "=g"(result));
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @brief Set EFLAGS.
|
|
*/
|
|
static inline void __attribute__((always_inline)) x86_restore_flags(unsigned long stored_value)
|
|
{
|
|
__asm__ volatile("push %0; popf" :: "g"(stored_value));
|
|
}
|
|
|
|
/**
|
|
* @brief Print saved general purposed registers.
|
|
*/
|
|
void x86_print_registers(struct x86_pushad *orig_ctx, unsigned long error_code);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/** @} */
|