我正在从CS.USFCA学习实验4,它为虚拟NIC生成模拟中断。 课程页面: http://cs.usfca.edu/~cruse/cs686s08/
该程序将创建一个模拟的NIC接口,用户可以通过cat proc来手动向NIC发出中断。
步骤:
然后我打印出IOAPIC的内容。条目#18 bit0-7是55,所以我将IntID设置为55。
接下来,我安装模块,并使用 ifconfig 启动eth3。 IRQ是18,这是正确的。
在通过 cat / proc / netframe 模拟中断的同时,内核日志显示 [18828.842375] do_IRQ:1.85没有矢量的irq处理程序(irq -1)
我知道Linux自己管理0-255个中断向量,IOAPIC中的24个条目决定IO设备的中断如何传送到CPU(英特尔)。
在我的情况下,似乎我触发了错误的中断。所以CPU无法找到正确的irq处理程序。
但在我的情况下,中断如何映射到相应的IRQ?
我的代码
#include <linux/module.h> // for init_module()
#include <linux/etherdevice.h> // for alloc_etherdev()
#include <linux/proc_fs.h> // for create_proc_info_entry()
#include <linux/interrupt.h> // for request_irq(), free_irq()
#include <linux/wait.h> // for init_wait_queue_head()
#include <linux/seq_file.h>
#define irqID 0x12 // temporary -- an unused IRQ
#define intID 0x55 // temporary -- IOAPIC mapped
typedef struct {
struct tasklet_struct my_rxtasklet;
wait_queue_head_t my_waitqueue;
spinlock_t my_lock;
} MY_DRIVERDATA;
int my_open( struct net_device * );
int my_stop( struct net_device * );
int my_hard_start_xmit( struct sk_buff *, struct net_device * );
irqreturn_t my_isr( int, void * );
void my_rx_handler( unsigned long );
int my_get_info( char *, char **, off_t, int );
char modname[] = "netframe";
static const struct net_device_ops mynetdev_ops={
.ndo_open=my_open,
.ndo_stop = my_stop,
.ndo_start_xmit = my_hard_start_xmit,
};
struct net_device *netdev;
int my_get_info( char *buf, char **start, off_t off, int count )
{
int len = 0;
int i;
*start = buf;
if ( off == 0 )
{
len += sprintf( buf+len, "simulating an interrupt " );
len += sprintf( buf+len, "by \'%s\' \n", netdev->name );
off += len;
}
else
{
asm(" int %0 " : : "i" (intID) );
}
return len;
}
static int my_seq_open(struct inode *inode,struct file *file){
printk(KERN_ALERT "DEBUG: Enter %s\n",__FUNCTION__);
return single_open(file, &seq_proc_show,NULL);
}
struct file_operations fops = {
.read=my_get_info,
};
static int __init my_init( void )
{
printk( "<1>\nInstalling \'%s\' module\n", modname );
if(!proc_create(modname,0666,NULL,&fops)){
printk(KERN_INFO "ERROR! proc_create\n");
remove_proc_entry(modname,NULL);
return -1;
}
netdev = alloc_etherdev( sizeof( MY_DRIVERDATA ) );
if ( !netdev ) return -ENOMEM;
netdev->irq = irqID;
netdev->netdev_ops=&mynetdev_ops;
return register_netdev( netdev );
}
static void __exit my_exit(void )
{
unregister_netdev( netdev );
free_netdev( netdev );
remove_proc_entry( modname, NULL );
printk( "<1>Removing \'%s\' module\n", modname );
}
int my_open( struct net_device *dev )
{
MY_DRIVERDATA *priv = netdev_priv(dev);
unsigned long devaddr = (unsigned long)dev;
printk( "opening the \'%s\' interface \n", dev->name );
spin_lock_init( &priv->my_lock );
init_waitqueue_head( &priv->my_waitqueue );
tasklet_init( &priv->my_rxtasklet, my_rx_handler, devaddr );
if ( request_irq( dev->irq, my_isr, IRQF_SHARED, dev->name, dev ) < 0) return -EBUSY;
netif_start_queue( dev );
return 0;
}
int my_stop( struct net_device *dev )
{
MY_DRIVERDATA *priv = netdev_priv(dev);
printk( "stopping the \'%s\' interface \n", dev->name );
free_irq( dev->irq, dev );
tasklet_kill( &priv->my_rxtasklet );
netif_stop_queue( dev );
return 0;
}
int my_hard_start_xmit( struct sk_buff *skb, struct net_device *dev )
{
MY_DRIVERDATA *priv = netdev_priv(dev);
printk( "starting transmit on the \'%s\' interface \n", dev->name );
dev->trans_start = jiffies;
dev->stats.tx_packets += 1;
dev->stats.tx_bytes += skb->len;
wait_event_interruptible( priv->my_waitqueue, 1 );
dev_kfree_skb( skb );
return 0;
}
irqreturn_t my_isr( int irq, void *data )
{
struct net_device *dev = (struct net_device*)data;
MY_DRIVERDATA *priv = netdev_priv(dev);
tasklet_schedule( &priv->my_rxtasklet );
wake_up_interruptible( &priv->my_waitqueue );
return IRQ_HANDLED;
}
void my_rx_handler( unsigned long data )
{
struct net_device *dev = (struct net_device *)data;
struct sk_buff *skb;
int rxbytes = 60;
skb = dev_alloc_skb( rxbytes + 2 );
skb->dev = dev;
skb->protocol = eth_type_trans( skb, dev );
skb->ip_summed = CHECKSUM_NONE;
dev->stats.rx_packets += 1;
dev->stats.rx_bytes += rxbytes;
netif_rx( skb );
}
module_init( my_init );
module_exit( my_exit );
MODULE_LICENSE("GPL");