记得2007年的时候,第一次开始学习ldd3这本书,到书的后面需要设计到真实硬件才可以验证学习的内容,当时废了好大的力气。为了验证书里面并口的内容,专门买了电脑、LED灯、电焊、锡、面包板什么的,然后把LED灯焊接在并口的9号和10号引脚并接到面包板上,通过拉高电平触发并口中断,看输出也要看LED灯的闪烁,费死劲了。这几天叫我弟驱动变成,突然想到用虚拟化设备来触发中断,让他验证short设备,于是就改了一下qemu,来从hypervisor里主动触发中断,这样妈妈再也不用担心我的电烙铁烫到我了。这样就大大降低了学习linux驱动的门槛,让我们这些软件程序猿再也不用苦恼于没有硬件设备,无法入门了。话不多说,这里来记录一下我的代码修改和实验方法,供新入行的小朋友参考,尽快入手驱动的编写。
我用的qemu版本是:v3.0.0-rc4
首先我们知道LDD3的short设备占用的知名IO端口是并口的,端口地址是 0x378,有了这些知识后,就可以知道并口模拟代码在 hw/char/parallel.c中。触发中断的函数是:parallel_update_irq() ,可以看到做法是发现有中断pending,那么先拉高电平,处理完后,irq_pending为0,那么拉低电平,表示处理完成,以便下一次触发
static void parallel_update_irq(ParallelState *s)
{
if (s->irq_pending)
qemu_irq_raise(s->irq);
else
qemu_irq_lower(s->irq);
}
那么我们就可以增加我们的触发函数了,hmp_trigger_parallel_update_irq(), 注意我们把irq_pending设为1后,强制用parallel_update_irq拉高电平触发中断,但是千万注意还需要把 irq_pending 设置0,再次用parallel_update_irq把中断线的电平拉低,恢复状态,告诉虚拟中断控制器中断处理完成了。只有这样,才可以再次触发中断,千万注意!!
/*
* begin liufeng
* HMO trigger parallel dev intr
*/
ParallelState *g_hmp_parallel_s = NULL;
void hmp_trigger_parallel_update_irq(void)
{
int irq_pending_store = 0;
if(!g_hmp_parallel_s){
printf("%s: can not trigger intr because ParallelState is null \n",__func__);
}
printf("%s: trigger a parallel intr\n",__func__);
irq_pending_store = g_hmp_parallel_s->irq_pending;
/*forece rasie up irq,*/
g_hmp_parallel_s->irq_pending = 1;
parallel_update_irq(g_hmp_parallel_s);
/*remember to lower donw the level*/
g_hmp_parallel_s->irq_pending = 0;
parallel_update_irq(g_hmp_parallel_s);
g_hmp_parallel_s->irq_pending = irq_pending_store;
return;
}
/*end liufeng*/
static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
{
static int index;
ISADevice *isadev = ISA_DEVICE(dev);
ISAParallelState *isa = ISA_PARALLEL(dev);
ParallelState *s = &isa->state;
/* begin liufeng
* hmp trigger intr
*/
g_hmp_parallel_s = s;
/*end liufeng*/
int base;
uint8_t dummy;
//.................
}
同时把hmp_trigger_parallel_update_irq(), 声明到头文件里面 include/hw/char/parallel.h
/*
* begin liufeng
* HMO trigger parallel dev intr
*/
void hmp_trigger_parallel_update_irq(void);
/*end liufeng*/
有了功能函数,下面,我们需要添加qemu命令行,就可以按需触发中断了
hmp-commands.hx 中加入
{
.name = "parallel_intr_trigger",
.args_type = "",
.params = "",
.help = "trigger parallel interrupt",
.cmd = hmp_parallel_trigger_intr,
},
STEXI
@item hmp_parallel_trigger_intr
@findex hmp_parallel_trigger_intr
trigger parallel interrupt. Parallel dev must be exsisted
ETEXI
hmp.c中加入
/* begin liufeng
* trigger intr
*/
void hmp_parallel_trigger_intr(Monitor *mon, const QDict *qdict)
{
monitor_printf(mon, "%s: begin trigger parallel intr\n", __func__);
printf("%s: begin trigger parallel intr\n", __func__);
hmp_trigger_parallel_update_irq();
monitor_printf(mon, "%s: trigger parallel intr done\n", __func__);
printf("%s: trigger parallel intr done\n", __func__);
}
/*end liufeng*/
hmp.h中加入声明
/*begin liufeng
* trigger parallel dev
*/
void hmp_parallel_trigger_intr(Monitor *mon, const QDict *qdict);
/* end */
我们现在就可以启动虚拟机实验试一下了,注意qemu中加入如下参数 “ -monitor stdio -parallel /dev/pts/2 ” 来是能hmp和并口设备,我的命令行如下
sudo gdb --args /home/liufeng/workspace/tools/bin/qemu-system-x86_64 -machine accel=kvm -m 4G \
-hda /home/kvm/disk/vm0.img \
-vnc 192.168.199.166:0 -monitor stdio \
-netdev type=tap,id=eth0,ifname=tap30,script=no,downscript=no -device e1000,netdev=eth0,mac=12:03:04:05:06:08 \
-parallel /dev/pts/2
启动后,看看qemu命令行是否存在 parallel_intr_trigger
我们进入虚拟机,加载short驱动,我们可以看到 0x378开始的7个端口,给了short设备
然后验证一下中断是否起作用,在qemu中运行命令行
运行3次命令行后,在虚拟机中查看中断触发情况,可以看到 short设备注册的7号中断有3次触发
运行short设备的实验情况,可以看到interrupt的中断正常触发了读写
好了,到这里我们可以正常玩弄第十章的所有实验了,对入门同学最难找到环境的 硬件端口通信和中断就可以快速入手验证和学习了,希望对大家有所帮助,再见