在虛擬機下玩中斷

記得之前學<<Linux Device Driver>>中斷的章節,找了一塊PCI轉並口的卡,而後焊了一塊小板,手動去觸發中斷。
最近看<<linux Kernel development>>中斷的章節,已是兩年後了。由於找到了在虛擬機下調試內核的方法,因此也但願調試中斷的實現能夠在虛擬機下完成,而不是再去焊一塊板子。

virtualbox裏面的串口設置提供了這種功能,其中一個串口如前所述用於調試信息輸出,能夠另外再激活一個串口調試中斷。

==============================================================
Port Number: COM2  IRQ: 3  I/O Port: 0x2F8
Port Mode: Host Pipe
Creat Pipe
Port/File_Path: /home/qianjiang/temp/test/myserial2
==============================================================

這樣,啓動虛擬機後,
# cat /proc/interrupts
           CPU0      
  0:        133    XT-PIC-XT-PIC    timer
  1:         16    XT-PIC-XT-PIC    i8042
  2:          0    XT-PIC-XT-PIC    cascade
  3:         1     XT-PIC-XT-PIC   
  4:        926    XT-PIC-XT-PIC    serial

其中第3個IRQ就是咱們要用於調試的中斷腳了。

寫了一個內核模塊來驗證中斷的生效,以下:

Makefile:
obj-m := uarttest.o

uarttest.c
其中8250控制器的寄存器描述參考:
http://www.doc88.com/p-95426735937.html for register description

==========================================================================
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/io.h>

MODULE_LICENSE("Dual BSD/GPL");


//typedef irqreturn_t (*irq_handler_t)(int, void *);
static irqreturn_t rtc_interrupt(int irq, void * dev_id)
{
    u8 IIR;
    u8 c;

    do
    {
      IIR = inb(0x2fa); //中斷狀態寄存器
      if((IIR & 0x01) == 0x01) break;  //no interrupt

      if((IIR & 0x06) == 0x06) //receive error
      {
        inb(0x2fd); //to clear error
        printk(KERN_ALERT "receive error, clear it\n");
      }
      else if((IIR & 0x04) == 0x04) //receive data
      {
        c = inb(0x2f8);
        printk(KERN_ALERT "got 0x%02x: %c\n", c, c);
      }
      else if((IIR & 0x02) == 0x02) //can send data
      {
        printk(KERN_ALERT "should not happen as we did not enable send data interrupt\n");
      }
      else
      {
        printk(KERN_ALERT "unkown interrupt 0x%02x\n", IIR);
      }
    }while(1);
    return IRQ_HANDLED;
}

static int hello_init(void)
{
    int ret;

    printk(KERN_ALERT "Hello kernel\n");
    ret = request_irq(3, rtc_interrupt, 0, "uart", NULL);
    if(ret != 0)
    {
        printk("reqiest irq 3 failed\n");
    }

    //2fb 線路控制寄存器
    outb(0xe3, 0x2fb);//DLAB=1 to set baudraut
    outb(0x1, 0x2f8); outb(0x0, 0x2f9); //to set baudraut as 115200

    outb(0x63, 0x2fb);//set DLAB=0 and set 8N1

    //clear interrupt
    inb(0x2fd);       //read LSR(線路狀態寄存器) to clear interrupt status if any error during receive
    inb(0x2f8);       //read RBR to clear receive interrupt

    outb(0x5, 0x2f9); //enable interrupt - 包括接收線錯誤中斷和接收到數據中斷

    printk(KERN_ALERT "DLAB=0 2f8: %02x %02x %02x\n", inb(0x2f8), inb(0x2f9), inb(0x2fa));

    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye cruel world\n");
    printk(KERN_ALERT "DLAB=0 2f8: %02x %02x %02x\n", inb(0x2f8), inb(0x2f9), inb(0x2fa));
    outb(0x0, 0x2f9); //disable interrupt
    free_irq(3, NULL);
}

module_init(hello_init);
module_exit(hello_exit);

==========================================================================

make -C ~/prj/pc-kernel/linux-2.6.39.y/ M=$PWD modules

因此再開一個minicom, 鏈接到虛擬機的com2,在這個窗口輸入字符,而後能夠在虛擬機的com1獲得顯示。

 html

相關文章
相關標籤/搜索