⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interrupt.c

📁 是经典的UNIX的部分源代码
💻 C
字号:
#include "interrupt.h"
#include "io.h"

/*************************************************
* 下面是本函数所要用到的东西的声明               *
*************************************************/

/* idt 表项结构 */
struct interrupt_idt_item_struct{
  unsigned short offset_0_15 ; // 偏移量的0~15位
  unsigned short seg_selector ; // 段选择符
  unsigned char un_used_0 ; // 未使用,须设为全零
  unsigned char saved_1_1_0 : 3 ; // 保留,需设为 110
  unsigned char d : 1 ; // D 位
  unsigned char saved_0 : 1 ; // 保留,需设为0
  unsigned char dpl : 2 ; // 特权位
  unsigned char p : 1 ; // P 位
  unsigned short offset_16_31 ; // 偏移量的16~31位
} ;

/* idt 描述符结构 */
struct interrupt_idt_descriptor_struct{
  unsigned short idt_length_limit ;
  struct interrupt_idt_item_struct *idt_addr ;
} ;

/* 8259A 初始化函数 */
static void interrupt_init_8259A() ;

/* 初始化中断向量表 IDT */
static void interrupt_init_idt() ;

/* 默认中断处理函数 */
void interrupt_asm_default_handle_for_interrupt() ;

/************************************************
* 下面是定义                                    *
************************************************/
static struct interrupt_idt_descriptor_struct interrupt_idt_descriptor ;

static struct interrupt_idt_item_struct interrupt_idt[ 256 ] ;

/************************************************
* 下面是函数的实现                              *
************************************************/

/* 中断初始化函数 */
void interrupt_init()
{
  // 初始化 8259A
  interrupt_init_8259A() ;

  // 初始化中断向量表 IDT
  interrupt_init_idt() ;
}

/* 8259A 初始化函数 */
static void interrupt_init_8259A()
{
  // 给中断寄存器编程
  // 发送 ICW1 : 使用 ICW4,级联工作
  io_write_to_io_port( 0x20 , 0x11 ) ;
  io_write_to_io_port( 0xa0 , 0x11 ) ;

  // 发送 ICW2,中断起始号从 0x20 开始(第一片)及 0x28开始(第二片)
  io_write_to_io_port( 0x21 , 0x20 ) ; 
  io_write_to_io_port( 0xa1 , 0x28 ) ;

  // 发送 ICW3
  io_write_to_io_port( 0x21 , 0x4 ) ;
  io_write_to_io_port( 0xa1 , 0x2 ) ;

  // 发送 ICW4
  io_write_to_io_port( 0x21 , 0x1 ) ;
  io_write_to_io_port( 0xa1 , 0x1 ) ;

  // 设置中断屏蔽位 OCW1 ,屏蔽所有中断请求 
  // 由于主片的 IRQ2 与从边相连,故不屏蔽它
  io_write_to_io_port( 0x21 , 0xfb ) ;
  io_write_to_io_port( 0xa1 , 0xff ) ;
}

/* 初始化中断向量表 */
static void interrupt_init_idt()
{
  struct interrupt_idt_item_struct p ;
  p.d = 1 ;
  p.dpl = 0 ;
  p.offset_0_15 = ( unsigned int )interrupt_asm_default_handle_for_interrupt ;
  p.offset_16_31 = ( unsigned int )interrupt_asm_default_handle_for_interrupt ;
  p.p = 1 ;
  p.saved_0 = 0 ;
  p.saved_1_1_0 = 6 ;
  p.seg_selector = 0x8 ; // 使用系统代码段
  p.un_used_0 = 0 ;

  for( int i = 0 ; i < 256 ; ++i ){
    interrupt_idt[ i ] = p ;
  }

  interrupt_idt_descriptor.idt_addr = interrupt_idt ;
  interrupt_idt_descriptor.idt_length_limit = 256 * 8 ;

  __asm__( "lidt %0" : "=m"( interrupt_idt_descriptor ) ) ;
}

/* 开中断 */
void interrupt_open_interrupt()
{
  __asm__( "sti" ) ;
}

/* 关中断 */
void interrupt_close_interrupt() 
{
  __asm__( "cli" ) ;
}

/* 中断处理程序安装函数 */
void interrupt_install_handle_for_interrupt( unsigned char interrupt_number , void *handle_for_interrupt )
{
  /* 首先关中断 */
  interrupt_close_interrupt() ;

  /* 然后根据中断号用指定的中断处理函数的句柄取代原函数 */
  interrupt_idt[ interrupt_number ].offset_0_15 = ( unsigned int )handle_for_interrupt ;
  interrupt_idt[ interrupt_number ].offset_16_31 = ( unsigned int )handle_for_interrupt >> 16 ;
}

/* 设置中断屏蔽字,自动关中断,但需手动开中断 */
void interrupt_set_interrupt_mask_word( unsigned int irq_number , int dose_enable )
{
  interrupt_close_interrupt() ;
  if( irq_number < 0 || irq_number > 15 ){
    /* 允许设置的屏蔽中断号在 0~15 之间 */
    return ;
  }
  else{
    unsigned char mask_word ;
    if( irq_number < 8 ){
      /* 设置第一片的中断号 */
      /* 读第一片的中断屏蔽字 */
      mask_word = io_read_from_io_port( 0x21 ) ;
    }
    else{
      /* 读第二片的中断屏蔽字 */
      mask_word = io_read_from_io_port( 0xa1 ) ;
    }
    switch( irq_number ){
      case 0 :
      case 8:
        if( dose_enable ){
          mask_word &= 0xfe ; // 0xfe = 1111 1110
        }
        else{
          mask_word |= 0x01 ; // 0x00 = 0000 0001
        }
        break ;
      case 1 :
      case 9:
        if( dose_enable ){
          mask_word &= 0xfd ; // 0xfd = 1111 1101
        }
        else{
          mask_word |= 0x02 ; // 0x01 = 0000 0010
        }
        break ;
      case 2 :
      case 10:
        if( dose_enable ){
          mask_word &= 0xfb ; // 0xfb = 1111 1011
        }
        else{
          mask_word |= 0x04 ; // 0x04 = 0000 0100
        }
        break ;
      case 3 :
      case 11:
        if( dose_enable ){
          mask_word &= 0xf7 ; // 0xf7 = 1111 0111
        }
        else{
          mask_word |= 0x08 ; // 0x08 = 0000 1000
        }
        break ;
      case 4 :
      case 12:
        if( dose_enable ){
          mask_word &= 0xef ; // 0xef = 1110 1111
        }
        else{
          mask_word |= 0x10 ; // 0x10 = 0001 0000
        }
        break ;
      case 5 :
      case 13:
        if( dose_enable ){
          mask_word &= 0xdf ; // 0xdf = 1101 1111
        }
        else{
          mask_word |= 0x20 ; // 0x20 = 0010 0000
        }
        break ;
      case 6 :
      case 14:
        if( dose_enable ){
          mask_word &= 0xbf ; // 0xbf = 1011 1111
        }
        else{
          mask_word |= 0x40 ; // 0x40 = 0100 0000
        }
        break ;
      case 7 :
      case 15:
        if( dose_enable ){
          mask_word &= 0x7f ; // 0x7f = 0111 1111
        }
        else{
          mask_word |= 0x80 ; // 0x80 = 1000 0000
        }
        break ;
    }
    if( irq_number < 8 ){
      /* 发送到主片 */
      io_write_to_io_port( 0x21 , mask_word ) ;
    }
    else{
      /* 发送到从片 */
      io_write_to_io_port( 0xa1 , mask_word ) ;
    }
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -