超级调用总结

超级调用总结

阅读了几篇优质文章之后,本人对超级调用又有了进一步的理解,文章主要从这几个方面来写:

  1. 当前疑惑

  2. 理解超级调用

  3. PV超级调用与HVM超级调用

  4. xen4.4中实现超级调用

  5. xen4.11中实现超级调用

优质文章链接为:

XEN添加一个HYPERCALL

Xen Log 3-Add New Hypercall to Xen

全虚拟化下的超级调用

Xen的超级调用

超级调用实现原理

0.当前疑惑

1.到底需不需要在/hvm/hvm.c中增加HYPERVISOR_?

有的加了;有的没有加也实现了;

2.在domain-U中修改头文件时,修改/hvm/hvm.c还是/usr/include/xen/xen.h?两个好像都可以。但是本人在实验过程中,发现xen4.11中并没有/hvm/hvm.c,因此只能在Xen.h中修改?结果是可行的。/usr/include/xen/xen.h 和 hvm/hvm.c之间的区别/xen/arch/x86/hvm/hvm.c,还有/usr/include/xen/sys/privcmd.h

  • 可能需要实验的是,如果不该Xen.h是否会成功
  • 在Xen4.4中如果不修改hvm.c而是修改Xen.h是否会成功
  • hvm.c是不是只与全虚拟化有关系?而xen.h是对于所有的VM都适用?

3.超级调用实现原理文中hvm超级调用失败的原因是什么?

1.理解超级调用

本部分结构如下:

  • 1.1系统调用
  • 1.2超级调用与系统调用的共同点
  • 1.3超级调用与系统调用的区别
  • 1.4Xen中超级调用须知
1.1系统调用
1.1.1 内核态和用户态

计算机是由软件和硬件组成的,除了硬件,可以将软件分为操作系统OS和用户程序。为了保证系统和用户程序之间的隔离性,避免用户程序的误操作对系统产生影响,区分不同程序拥有的权限,系统定义了内核态和用户态。当用户执行一般操作的时候,只需要在用户态运行;当用户需要执行一些敏感操作时,需要向系统调用服务,进入内核态。

1.1.2 特权级

一般地,有Ring0,Ring1,Ring2,Ring3,执行权限依次降低。在没有虚拟化技术的系统中,操作系统运行在Ring0,用户程序运行在Ring3。

虚拟化技术需要将主机系统的资源虚拟化,分配给不同的虚拟机使用,因而在操作系统和用户程序之间增加了一个Hypervisor层,用于协调访问服务器上的所有物理设备和虚拟机。

Xen作为一种Hypervisor,如图1,位于Hardware和操作系统之间,为其上运行的虚拟机内核提供虚拟化环境,因而Xen具有最高的特权级。

xen-arch

Xen半虚拟化 & x86 特权模式

图2左;没有半虚拟化的x86-32:操作系统位于Ring0;应用程序Ring3

图2右;半虚拟化的x86-32:Xen位于Ring0;操作系统Ring1;应用程序Ring3

图3左;没有半虚拟化的x86-64:操作系统位于Ring0;应用程序Ring3

图3右;半虚拟化的x86-64:Xen和操作系统位于Ring0;应用程序Ring3

xen+priviliged

Xen全虚拟化 & x86 特权模式

HVM中运行的是没有修改的OS,操作系统位于Ring0;应用程序Ring3。但是Xen具有最高的特权级,此时Xen运行在根(Root)模式,可以认为运行在-1环。

1.1.3系统调用的实现方式

系统调用是用户空间应用程序和内核提供的服务之间的接口。服务在内核中,因此需要一个进程跨越内核和用户空间。在i386中有两种系统调用实现方式:

中断
快速系统调用(sysenter和sysexit)
1.1.4系统调用中的名词

系统调用:实质是函数调用

系统调用号:每一个系统调用定义了一个唯一的编号

系统调用表:将系统调用号与相应的服务例程关联起来

系统调用处理程序:用户空间程序和内核服务之间的接口;一个函数;

封装例程:例如一些函数库中的库函数

服务例程:系统调用对应的内核函数

1.1.5系统调用的过程

systemcall-process

其流程可以描述为:

应用程序----封装例程----系统调用的系统调用号---软中断0x80----内核空间的软中断系统调用处理程序---超级调用表---系统调用服务例程---软中断返回封装例程----应用程序
1.1.6系统调用的两种方式
直接调用syscall(),参数为系统调用号
调用库函数中封装例程
1.1.7系统调用中的宏定义
_syscall0 _syscall1 ... _syscall5
#0-5是除了系统调用号的参数个数
eax:系统调用号
ebx ecx edx esi edi:其余参数
1.2超级调用与系统调用的关系
1.2.1名词对应
超级调用号-----系统调用号
超级调用表-----系统调用表
hypercall-----system_call
0x82-----0x80
1.2.2宏定义
_hypercall0 _hypercall1 ... _hypercall5
#0-5是除了系统调用号的参数个数
1.2.3超级调用的过程

hypercallprocess

1.2.4超级调用的两种方式

由于hypercall只能在内核态进行调用,所以可以放到systemcall中或者编译为kernel module在进行加载时调用;xen本身也提供了使用privcmd 的工具能够来调用hypercall。

privcmd
kernel module
1.3超级调用与系统调用的区别
1.3.1超级调用页

系统调用:封装例程直接调用软中断0x80

超级调用:通过超级调用页间接调用软中断指令;封装例程----超级调用页----可能含有0x82(和虚拟化类型有关);

超级调用页的初始化

源代码:/xen/arch/x86/x86_32/traps.c

xen在domain创建时将超级调用页映射到domain的内核空间
根据domain的安装类型初始化超级调用页
为每个超级调用添加处理代码(代码会根据安装类型有区别)

初始化超级调用页的过程感觉就是把一堆一样的代码写进到hypercall_page中;但是并没有具体函数的信息;具体的函数或者超级调用是在超级调用表中进行映射的;也能看出超级调用页区分了各种不同安装类型的超级调用页的初始化;结果是可以指向同一个超级调用表

1.4Xen中超级调用须知
1.4.1内存与超级调用

每个超级调用在超级调用页中对应的代码长度:最大是32B

hypercall-size

2.PV超级调用与HVM超级调用

2.1全虚拟化中的超级调用

在全虚拟化中,由于Guest OS 的代码没有被修改,因此Guest OS 的特权操作, 比如更新页表等主要通过VT 技术的VMX 操作来实现。敏感操作也不像半虚拟化那样通过超级调用来实现,也是通过VMX 的指令来实现。因此全虚拟化下的Guest OS 即HVM 很少使用超级调用。

需要硬件辅助技术:Intel VT(vmx)和AMD SVM技术

客户机domain:客户机模式;无关键指令时;

Xen:根模式;root模式;涉及到关键指令时进入;

只要不涉及到关键指令,客户机就运行在客户机模式下;当涉及到关键指令时,客户机就会退出客户机模式(VM exit),进入root模式,在root模式中执行完相应的关键指令后又会进入到客户机模式(VM entry)。
Intel VT技术:VMCALL调用VM monitor;Xen的hypervisor
AMD:VMMCALL使客户机和VMM通信
2.2半虚拟化中超级调用

半虚拟化中超级调用和系统调用的位置

systemcall

3.Xen4.4中实现超级调用

下边是在Xen4.4中实现超级调用的过程,其中3.0部分与虚拟化模式无关;3.1和3.2分别是半虚拟和全虚拟化虚拟机中测试超级调用的操作过程。

3.0不区分虚拟化模式的修改部分
  • 超级调用号

    xen/include/public/xen.h

     #define __HYPERVISOR_tmem_op 38
     #define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */
    +#define __HYPERVISOR_leeham_hycall 39 /* add this temporarily; 39 is not used before */
    
  • 超级调用表

    xen/arch/x86/x86_64/entry.S

    .byte 1 /* do_tmem_op */
    + .byte 3 /* do_leeham_hycall */
    
  • 函数头文件

    xen/include/asm-x86/hypercall.h

    extern int
    do_leeham_hycall(char* message1,char *message2);
    
  • 自定义超级调用函数

    xen/arch/x86/mm.c

int do_leeham_hycall(char* message1,char *message2)
{
	if(message1&&message2) 
	{
		printk("The message1 is : \n%s\n",message1);
		printk("The message2 is : \n%s\n",message2);
	}
	else printk("no message!\n");
	return 1;
}
3.1半虚拟化

XEN添加一个HYPERCALL

  • 首先修改xen.h

    /usr/include/xen/xen.h中
    添加的__HYPERVISOR_的宏定义
    
  • 编写测试程序

    #include<stdio.h>
    #include<stdlib.h>
    #include<errno.h>
    #include<sys/ioctl.h>
    #include<string.h>
    #include<sys/types.h>
    #include<fcntl.h>
    
    #include<xenctrl.h>
    #include<xen/sys/privcmd.h>
    
    int main(int argc,char* argv[])
    {
    	int fd,ret;
    	char *message1,*message2;
    	if(argc!=3){
    		printf("please put 2 parameter!");
    		return -1;
    	}
    	message1=(char*)malloc(sizeof(char)*(strlen(argv[1])+1));
    	message2=(char*)malloc(sizeof(char)*(strlen(argv[2])+1));
    	strcpy(message1,argv[1]);
    	strcpy(message2,argv[2]);
    	privcmd_hypercall_t hcall={__HYPERVISOR_leeham_hycall,{message1,message2,0,0,0}};
    	fd=open("/proc/xen/privcmd",O_RDWR);
    	if(fd<0){
    		perror("open");
    		exit(1);
    	}
    	else{
    		printf("fd=%d\n",fd);
    	}
    	ret=ioctl(fd,IOCTL_PRIVCMD_HYPERCALL,&hcall);
    	printf("ret=%d\n",ret);
    }
    
  • make install-xen;重启

3.2全虚拟化

这部分我没有实验;请见原文;其中hypercall的名称是create_sim

全虚拟化下的超级调用

  • 首先在xen/arch/x86/hvm/hvm.c 中添加该hypercall

    static hvm_hypercall_t *hvm_hypercall32_table[NR_hypercalls] = {
    ......
    HYPERCALL(tmem_op),
    + HYPERCALL(create_sim)
    };
    
  • 在HVM domU 中写一个模块sim.c ,来调用该hypercall, 如下:

    #include <linux/module.h>
        #include <linux/kernel.h>
        #include <linux/vmalloc.h>
        #include <linux/mm.h>
        #include <asm/pgtable.h>
        #define __HYPERVISOR_create_sim 39
        
        char *hypercall_stubs;
    
        /* 下面两个define 可以参考文件asm/hypercall.h */
    
        #define _hypercall2(type, name, a1, a2) /
        ({ /
        type __res; /
        long __ign1, __ign2; /
        asm volatile ( /
        HYPERCALL_STR(name) /
        : "=a" (__res), "=D" (__ign1), "=S" (__ign2) /
        : "1" ((long)(a1)), "2" ((long)(a2)) /
        : "memory" ); /
        __res; /
        })
    
        #define HYPERCALL_STR(name) /
            "mov $("__stringify(__HYPERVISOR_##name)" * 32),%%eax; "/
            "add hypercall_stubs,%%eax; " /
            "call *%%eax"
    
        static int init_hypercall(void)
        {
            uint32_t eax, ebx, ecx, edx, pages, msr, i;
            char signature[13];
        
        /* 通过cpuid 指令获取当前操作系统的状态 */
    
        cpuid(0x40000000, &eax, &ebx, &ecx, &edx);
        *(uint32_t*)(signature + 0) = ebx;
        *(uint32_t*)(signature + 4) = ecx;
        *(uint32_t*)(signature + 8) = edx;
        signature[12] = 0;
    
        /* 判断是不是运行在Xen VMM 上 */
        if (strcmp("XenVMMXenVMM", signature) || (eax < 0x40000002)) {
        printk(KERN_WARNING
            "Detected Xen platform device but not Xen VMM?"
        " (sig %s, eax %x)/n",signature, eax);
        return -EINVAL;
        }
    
        /* 获取xen 的版本号 */
        cpuid(0x40000001, &eax, &ebx, &ecx, &edx);
        printk(KERN_INFO "Xen version %d.%d./n", eax >> 16, eax & 0xffff);
        
        /* 获取超级调用页的数目pages,( 一般情况下只有一页) 以及相应的寄存器值msr */
        cpuid(0x40000002, &pages, &msr, &ecx, &edx);
        printk(KERN_INFO"there are %u pages/n", pages);
    
        /* 分配超级调用页 */
        hypercall_stubs = __vmalloc(pages * PAGE_SIZE,GFP_KERNEL,
                            __pgprot(__PAGE_KERNEL & ~_PAGE_NX));
    
        if (hypercall_stubs == NULL)
            return -ENOMEM;
    
    
        /* 将超级调用页的物理页框号写到MSR 中 */
        for (i = 0; i < pages; i++) {
            unsigned long pfn;
            pfn = vmalloc_to_pfn((char *)hypercall_stubs + i*PAGE_SIZE);
            wrmsrl(msr, ((u64)pfn << PAGE_SHIFT) + i);
        }
    
        printk(KERN_INFO "Hypercall area is %u pages./n", pages);
        _hypercall2(unsigned long, create_sim, 1,3);
        return 0;
        }
        module_init(init_hypercall);
    
  • 编写makefile文件

     Make 文件如下:
        obj-m := sim.o
        all:
            make -C /lib/modules/`uname -r`/build M=`pwd` modules
        clean:
            make -C /lib/modules/`uname -r`/build M=`pwd` clean
    
  • 编译,加载模块

make
insmod sim.ko
  切换到dom 0 中,利用xm dm 查看日志

  (XEN) creat the sim space using shadow page

4.Xen4.11中实现超级调用

类比Xen4.4,我们得到下述内容。

4.0大致运行流程

1.当用户态生成超级调用后,首先进入entry.S;执行下边代码之后会进入do_entry_int82函数;

ENTRY(entry_int82)
	...
	call  do_entry_int82

2.xen-4.11.0.source\xen\arch\x86\pv\traps.c中定义了:do_entry_int82();

void do_entry_int82(struct cpu_user_regs *regs)
{
    if ( unlikely(untrusted_msi) )
        check_for_unexpected_msi((uint8_t)regs->entry_vector);
    pv_hypercall(regs);
}

3.xen-4.11.0.source\xen\arch\x86\pv\hypercall.c中定义了:pv_hypercall()

void pv_hypercall(struct cpu_user_regs *regs)
{
	...
}

4.其中使用到pv_hypercall_table系统调用表\xen\arch\x86\pv\hypercall.c;还用到\xen\arch\x86\hypercall.c中的hypercall_args_table

pv_hypercall_table:
......
#ifdef CONFIG_TMEM
    HYPERCALL(tmem_op),
#endif
......
hypercall_args_table:
...
    ARGS(xenpmu_op, 2),
    ARGS(dm_op, 3),
...
4.1思路说明
4.1.1在Xen源码中修改
  • 超级调用号

xen/include/public/xen.h 修改调用号

...
#define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
...
  • 超级调用表

xen/arch/x86/hypercall.c 增加自定义超级调用的参数个数;

const hypercall_args_t hypercall_args_table[NR_hypercalls] =
{
    ......
    ARGS(xenpmu_op, 2),
    ......
}

xen\arch\x86\pv\hypercall.c修改超级调用表:

......
#ifdef CONFIG_TMEM
    HYPERCALL(tmem_op),
#endif
......
  • 修改函数头文件

/asm-x86/hypercall.h

......
extern long
do_set_trap_table(
    XEN_GUEST_HANDLE_PARAM(const_trap_info_t) traps);
......
  • 添加hypercall定义
目前的理解是对定义文件的内容没有限制。只要在/xen项目中就可以了。
4.1.2在DomainU中测试
  • 首先修改xen.h

    /usr/include/xen/xen.h中
    添加的__HYPERVISOR_的宏定义
    
  • 编写测试程序

    同上

4.2实际操作
4.1.1在Xen中修改代码
  • 超级调用号

xen/include/public/xen.h 修改调用号

...
#define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
+#define __HYPERVISORleeham_hycall       39 /* reserved for XenClient */
...
  • 超级调用表

xen/arch/x86/hypercall.c 增加自定义超级调用的参数个数;

const hypercall_args_t hypercall_args_table[NR_hypercalls] =
{
    ......
    ARGS(leeham_hycall, 2),
    ......
}

xen\arch\x86\pv\hypercall.c修改超级调用表:

......
    HYPERCALL(leeham_hycall),
......
  • 修改函数头文件

/asm-x86/hypercall.h

......
extern int
do_leeham_hycall(char* message1,char *message2);
......
  • 添加hypercall定义
同Xen4.4.0
4.1.2在DomainU中测试
  • 首先修改xen.h

    /usr/include/xen/xen.h中
    添加的__HYPERVISOR_leeham-hycall的宏定义
    
  • 编写测试程序

    同Xen4.4.0
    
  • make install-xen;重启

一些命令

xl dmesg | less
su reboot
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Xen虚拟化技术》主要讲述了:目前,无论是学术界还是工业界,虚拟化技术的研究和应用都是热点。在不断涌现出的虚拟化解决方案中,开源解决方案Xen以其独特的虚拟化设计模式,以及接近单机操作系统的性能被学术界和工业界广泛看好,被认为是未来最有前途的虚拟化解决方案之一。, 《Xen虚拟化技术》以Xen 3.1.0源码为基础,以通过源码剖析原理的方式深入细致地分析了Xen的半虚拟化技术;着重介绍了在x86平台上Xen半虚拟化技术提供的用以控制和管理虚拟机的内核接口,以及相关的原理和操作应用,包括半虚拟化技术的基本机制和策略,Xen的子系统及与安全相关的应用模块。, (1)基本机制和策略,即Xen半虚拟化技术的3大核心机制:与虚拟机启动和管理相关的信息页机制,与虚拟机特权级控制和通信相关的超级调用和事件通道机制,以及与虚拟机数据共享和传输相关的授权表机制。, (2)虚拟化子系统,即CPU虚拟化子系统、内存虚拟化子系统及I/O设备虚拟化子系统。CPU虚拟化子系统主要包括虚拟CPU原理和结构、新架构下中断和异常处理机制的变化、时间和计时器相关操作,以及虚拟CPU的调度原理等;内存虚拟化子系统主要包括分页分段机制、内存分配和地址转换等;I/O设备虚拟化子系统主要包括分离驱动模型(前后端设备模型)、虚拟块设备和网络设备的基本原理机及相关操作等。, (3.)安全相关模块,包括两个模块:访问控制模块(ACM)和虚拟化可信平台模块(vTPM)。详细介绍各个模块的基本原理及相应的实现和使用方法。, (4)Xen前沿工作:对Xen全虚拟化技术的原理进行介绍,通过硬件虚拟化技术实现对Xen全虚拟化的支持,并以Intel VT技术为重点介绍硬件虚拟化的知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值