谈虚拟环境中设备访问的实现方法(下)

原创 2007年09月26日 12:49:00

谈虚拟环境中设备访问的实现方法(下)

康华 :主要从事 Linux 操作系统内核、虚拟机、Linux 技术标准、计算机安全、软件测试等领域的研究与开发工作,曾就职 MII-HP 软件实验室 、瞬联软件公司/MOTOROLA,现就职于Lenovo研究院 。其所合写的Linux专栏见http://www.csdn.net/subject/linux/。 如果需要可以联系通过 kanghua151@msn.com (MSN)联系我. 

摘要:在了解了虚拟机中设备访问途径和I/O截获过程后,我们最后以在Qemu中实现光驱刻录为例,具体展示一下设备模拟的实现过程。

 

Qemu的设备模型简介

Qemu 除了模拟执行CPU指令已外,尚有一个重要的组成部分就是:设备模型。设备模型包括了当前PC机常见的各种外设的模拟代码,如鼠标,硬盘控制器,时钟,ACPI等等。具体代码存在与目录../ioemu下。

设备模拟代码的基本原理是按照设备处理数据的相关规范,对I/O截获而来的数据进行处理,并返回模拟结果。因此我们可以将设备模拟代码看作是一个有限状态机(FSM),其中状态集就是设备所处的各种状态,在模拟代码中可以简化理解成一些列模拟积存器在当前状态取值;其起始状态是设备规范中规定的设备状态,在模拟代码中就是各模拟积存器的初值等;输入和状态迁移对应的转换函数可以看成是设备模拟中的分之处理,一般需要分析输入数据,根据输入设置对应模拟积存器值,以及根据硬件规范触发模拟中断等。这些步骤将促成设备状态的迁移。

只有正确的模拟出设备的各种状态,其上的驱动(在GUEST OS中)才可以与其正常交互,原因很明显——驱动是根据设备规范实现的。比如,某个设备的规范是从端口A接受到数据0x101后,执行设备初始化操作。初始化完毕后设备会将端口B0x001,并且发送中断。那么上层的驱动程序会实现成:在接收到中断后,检查端口B,若发现是0x001则认为设备准备好了,可以继续发送数据;否则不继续发送数据。所以如果设备模拟程序没有正确模拟状态迁移,则上层驱动就不能和其正常交互了。

 

如何使得Qemu支持光驱刻录

Qemu中实现光驱刻录的先决条件是:

1 系统中的物理光驱支持刻录功能。

2 宿主系统(比如我们要使用的Linux系统)本身支持光驱刻录。

实现原理

      有关实现I/O截获,以及光驱控制器的状态模拟架构(如PIO/DMA模式,命令解析方式等)这些复杂的工作,Qemu都早已经完成。我们这里需要做的仅仅是锦上添花的工作。下面我们就实现原理进行介绍。

      Linux宿主机上实现Qemu的光驱刻录首先需要了解光驱控制器的操作方法。目前的光驱控制器的操作指令规范有《Multimedia Device Command Set》(简称MMC),以及《SCSI Device Primary Command Set》(简称SPC)。特别是MMC规范是专门针对DVD/CD操作的规范,而SPC规范是对所有SCSI设备操作的通用规范,属于通用操作的光驱操作可以在这个规范中找到。

Qemu中的光驱控制器模拟代码(ide.c)对MMCSPC规范的模拟并不完备,因此不能实现真实光驱设备的所有功能。目前仅仅能实现光驱的读功能,也就是说在guest中只能看到一个只读光驱,而无法执行任何真实写操作。因此需要做的第一步是在qemu的光驱控制器模拟代码中补充光驱刻录所需要的所有Atapi指令(具体指令集见下文)。

另外由于目前Guest OS中所见的光驱是模拟光驱,设备名是QEMU CD-ROM(见函数ide_atapi_identify),其所有属性都是通过模拟代码软件设置(各种Atapi命令除了读数据的GPCMD_READ_*外,所有GPCMD_*命令都是模拟实现,见函数ide_atapi_cmd),只有读数据时才会和真实设备交互——具体是通过Linux系统中的/dev/cdrom设备文件提供的lseekread等接口实现间接访问真实光驱)。那么如果我们想支持光驱刻录,则需要让GUEST看到真实的可刻录光驱设备,否则就在Guest中无法执行刻录操作(因为刻录操作前都需要检测设备属性是否支持刻录)。而要在GUEST中看到真实光驱设备,则需要支持从真实设备获取设备属性和设置设备属性,也就是说要将所有ATAPI命令直接转发到物理设备,而不是模拟执行,返回模拟结果。这种转发依然是通过Linux下的/dev/cdrom设备文件提供的ioctl接口中的CDROM_SEND_PACKET处理分支。所以第二步需要做的是:将ATAPI命令通过ioctl接口转发给真实设备进行处理,并将真实结果返回。

所需要做的理论上就这么多了!下面看看具体实现。

 

 

实现步骤

1 先来说说需要补充的命令集合。我主要测试的Guestvista系统,就vista而言需要实现如下ATAPI命令才能支持刻录:

GPCMD_TEST_UNIT_READY:         

GPCMD_MODE_SENSE_10:

GPCMD_REQUEST_SENSE:

GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:

GPCMD_READ_10:

GPCMD_READ_12:

GPCMD_READ_CD:

GPCMD_WRITE_10:

GPCMD_WRITE_12:

GPCMD_SEEK:

GPCMD_START_STOP_UNIT:

GPCMD_MECHANISM_STATUS:

GPCMD_READ_TOC_PMA_ATIP:

GPCMD_READ_CDVD_CAPACITY:

GPCMD_READ_DISC_INFO:

GPCMD_GET_CONFIGURATION:

GPCMD_SET_SPEED:

GPCMD_INQUIRY:

GPCMD_GET_PERFORMANCE:

GPCMD_MODE_SELECT_10:

GPCMD_REPORT_KEY:

GPCMD_READ_DVD_STRUCTURE:

GPCMD_GET_EVENT_STATUS_NOTIFICATION:

GPCMD_BLANK:

GPCMD_CLOSE_TRACK:

GPCMD_READ_FORMAT_CAPACITIES:

GPCMD_READ_TRACK_RZONE_INFO:

GPMODE_READ_BUFFER_CAPACITY:

GPCMD_FLUSH_CACHE:

GPCMD_VERIFY_10:

GPCMD_SEND_OPC:

GPCMD_FORMAT_UNIT:

GPCMD_SET_STREAMING:

 

2 ioctl进行了封装,让其包含在raw_ioctl中,以符合qemu的设备访问架构。

    在操作表中填加raw_ioctl

BlockDriver bdrv_raw = {

    "raw",

    sizeof(BDRVRawState),

    raw_probe,

    raw_open,

    raw_read,

    raw_write,

    raw_close,

    raw_create,

    raw_flush,

       raw_ioctl,

};

   /dev/cdromioctl进行封装,共给qemu解析ATAPI packet命令时调用。

int raw_ioctl(BlockDriverState *bs)

{

    BDRVRawState *s = bs->opaque;

       struct cdrom_generic_command *cgc=bs->opaque2;

      

       struct cdrom_generic_command _cgc;

       struct request_sense sense;

      

       int ret=0;

      

       ret=ioctl(s->fd,CDROM_SEND_PACKET,cgc);

       if ( ret<0)

       {

              printf("raw_ioctl: error fd=%d/n",s->fd);

       }

       return ret;

       return 0;

}

 

3 状态机状态补充。

目前的Qemu所接收的命令都是读取命令,其输入只需要一个命令,而无需附加参数,这种情况属于不带数据的ATAPI packet命令,如Mode Sense command等。Qemu中目前的模拟代码处理没有问题。

但是对于传入命令以外,还需要附加参数的ATAPI pactet命令,如Mode Select Command(除了命令本身要发给设备外,还需要传入Mode Parameter List等参数)处理上缺失状态迁移,也就是说在接收到命令后,设备状态未能迁移到接受参数状态,因此造成了驱动程序无法将参数传入。

解决办法是按照设备规范补充状态迁移代码即可。具体做法是在收到12字节的命令后,设置DRQ寄存器,并发送中断INTRQ

 

 

4 I/O缓存问题。

由于Linux系统的I/O缓存层的存在,而当我们使用ioctl向光盘写入数据,并不经过I/O缓存层,因此Linux内核并未刷新I/O缓存层(按照道理来说,内核应该刷新或invalidate原缓存,这里可能是Linux内核一个bug),所以不能在使用原来的/dev/cdromread接口读光盘内容,因为read读取是读的I/O缓存中的数据,所以我们需要让读数的时候绕过I/O缓存。方法有1 直接用ioctl读取光盘 ;方法2 使用裸设备方法访问光驱。

 

Mac下PyCharm切换虚拟环境

1.项目设置默认编译环境PyCharm–>Preferences Apply–>OKApply–>OK2.切换虚拟环境每个文件单独修改 Apply–>OK...
  • tymatlab
  • tymatlab
  • 2017年11月02日 12:02
  • 334

让天堂的归天堂,让尘土的归尘土——谈Linux的总线、设备、驱动模型

转自宋宝华老师csdn 公元1951年5月15日的国会听证上,美国陆军五星上将麦克阿瑟建议把朝鲜战争扩大至中国,布莱德利随后发言:“如果我们把战争扩大到共产党中国,那么我们会被卷入到一场错误的时...
  • bingqingsuimeng
  • bingqingsuimeng
  • 2017年06月29日 14:16
  • 278

Linux硬件设备访问

mmap设备操作 mmap系统调用(功能) 实例分析:mmap系统调用 虚拟内存区域:虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同...
  • qq_27522735
  • qq_27522735
  • 2017年02月14日 19:24
  • 341

virtualenv和它的原理

一起研究一下virtualenv是如何做到隔离各个版本的python环境的!
  • Jacketinsysu
  • Jacketinsysu
  • 2017年02月09日 10:52
  • 1526

Spring Mobile是如何判断访问设备的类型的

Spring最近换域名了,去转转,发现了一个有意思的项目:spring mobile。 http://projects.spring.io/spring-mobile/ 这个项目有很多实用的功...
  • hengyunabc
  • hengyunabc
  • 2013年11月17日 08:04
  • 6132

python虚拟环境安装和配置

http://blog.csdn.net/pipisorry/article/details/47008981python虚拟环境virtualenvVirtualEnv用于在一台机器上创建多个独立的...
  • pipisorry
  • pipisorry
  • 2014年10月11日 19:11
  • 31011

Linux——Python虚拟环境

Command Line Python 在前面一篇中,我们直接在python命令行中运行代码,虽然简单明了,但是命令行是不能保存文件的。因此在开发python程序时,我们需要将python代码存为文件...
  • zm714981790
  • zm714981790
  • 2016年05月04日 21:23
  • 1004

python安装虚拟环境

转自:点击打开链接 虚拟环境 虚拟环境是一个将不同项目所需求的依赖分别放在独立的地方的一个工具,它给这些工程创建虚拟的Python环境。它解决了“项目X依赖于版本1.x,而项目Y需要项目4.x”...
  • muyimo
  • muyimo
  • 2017年04月12日 17:57
  • 552

Windows:使用virtualenv创建虚拟环境,安装pip

介绍Windows下Python3.4安装virtualenv创建虚拟环境、pip;本次配置的是Python3.x版本。 工具/原料 Python3.4,这里就不介绍怎么安装了...
  • baidu_21833433
  • baidu_21833433
  • 2016年10月23日 21:38
  • 445

linux中设备的访问

1.设备的访问    1)设备的发现    fdisk -l                           ##查看真实存在被识别的设备    cat  /proc/partitions ...
  • sumin1118
  • sumin1118
  • 2017年04月17日 21:40
  • 149
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:谈虚拟环境中设备访问的实现方法(下)
举报原因:
原因补充:

(最多只允许输入30个字)