初始化EPT
struct eptp_bits {
unsigned memory_type :; /* 0: UC uncacheable, 6: WB writeback */
unsigned pagewalk_len :; /* value 1 less than EPT page-walk length */
unsigned dirty :; /* dirty flag */
unsigned reserved1 :;
unsigned long pgd :; /* bit N-1:12 of the physical address of the 4-KByte aligned EPT PML4 table, N=40 */
unsigned reserved2 :;
} __attribute__((__packed__)); union eptp {
struct eptp_bits bits;
__u64 value;
}; /* PGD (PML4E)
*
* (N鈥?):12 Physical address of 4-KByte aligned EPT page-directory-pointer
* table referenced by this entry
*
* Since no processors supporting the Intel 64 architecture support more than
* 48 physical-address bits, the size of field "addr" is 36 bits. Ditto for
* other structures. */
struct ept_pgd_bits {
unsigned read :;
unsigned write :;
unsigned exec :;
unsigned reserved1 :;
unsigned accessed :;
unsigned ignored1 :;
unsigned long addr :;
unsigned reserved2 :;
unsigned ignored2 :;
} __attribute__((packed)); union ept_pgd {
struct ept_pgd_bits bits;
__u64 value;
}; /* PUD (PDPTE) */
struct ept_pud_bits {
unsigned read :;
unsigned write :;
unsigned exec :;
unsigned reserved1 :;
unsigned accessed :;
unsigned ignored1 :;
unsigned long addr :;
unsigned reserved2 :;
unsigned ignored2 :;
} __attribute__((packed)); union ept_pud {
struct ept_pud_bits bits;
__u64 value;
}; /* PMD (PDE) */
struct ept_pmd_bits {
unsigned read :;
unsigned write :;
unsigned exec :;
unsigned reserved1 :;
unsigned zero :;
unsigned accessed :;
unsigned ignored1 :;
unsigned long addr :;
unsigned reserved2 :;
unsigned ignored2 :;
} __attribute__((packed)); union ept_pmd {
struct ept_pmd_bits bits;
__u64 value;
}; struct ept_pde_bits {
unsigned read :;
unsigned write :;
unsigned exec :;
unsigned memtype :; //bit3-5
unsigned ignorpat :;
unsigned ispage :;
unsigned accessed :;
unsigned writed :;
unsigned ignored :;
unsigned reserved :;
unsigned long addr :;
unsigned reserved2 :;
unsigned ignored2 :;
} __attribute__((packed)); union ept_pde {
struct ept_pde_bits bits;
__u64 value;
}; /* PTE */
struct ept_pte_bits {
unsigned read :;
unsigned write :;
unsigned exec :;
unsigned mem_type :;
unsigned ignore_pat :;
unsigned ignored1 :;
unsigned accessed :;
unsigned dirty :;
unsigned ignored2 :;
unsigned long addr :;
unsigned reserved1 :;
unsigned ignored3 :;
unsigned suppress_ve :;
} __attribute__((packed)); union ept_pte {
struct ept_pte_bits bits;
__u64 value;
}; /* bits 47:39 */
#define ept_pgd_index(x) ((x >> 39) & 0x1ff) /* bits 38:30 */
#define ept_pud_index(x) ((x >> 30) & 0x1ff) /* bits 29:21 */
#define ept_pmd_index(x) ((x >> 21) & 0x1ff) /* bits 20:12 */
#define ept_pte_index(x) ((x >> 12) & 0x1ff)
上面是一些页表的结构体,下面是初始化ept页表。每个页大小为2MB.
static err_t initEpt(void)
{
union ept_pud* pud;
union ept_pde* pde; int i,j,k, memnum = ;
pgd = (union ept_pgd *)get_zeroed_page(GFP_ATOMIC);
if (NULL == pgd)
{
printk("%s: alloc pgd error!\n", __func__);
goto allocErr;
}
eptph.value = ;
eptph.bits.memory_type = ;
eptph.bits.pagewalk_len = ;
eptph.bits.pgd = __pa(pgd) >>PAGE_SHIFT;
printk("eptp.pgd physical address= 0x%016lx, virtual address = 0x%016lx, pgd = 0x%016lx\n", (unsigned long)(eptph.bits.pgd << PAGE_SHIFT), (unsigned long)__va(eptph.bits.pgd << PAGE_SHIFT), (unsigned long)pgd); for(i = ; i < ; i++)
{
pud = (union ept_pud*)get_zeroed_page(GFP_ATOMIC);
if (NULL == pud)
{
printk("%s: alloc pud error!\n", __func__);
goto allocErr;
}
pgd[i].value = ;
pgd[i].bits.read = ;
pgd[i].bits.write = ;
pgd[i].bits.exec = ;
pgd[i].bits.addr = __pa(pud) >>PAGE_SHIFT;
printk("pgde: va=0x%016lx, pa=0x%016lx\n", (unsigned long)pud, (unsigned long)pgd[i].bits.addr); for (j = ; j < ; j++)
{
pde = (union ept_pde*)get_zeroed_page(GFP_ATOMIC);
if (NULL == pde)
{
printk("%s: alloc pde error!\n", __func__);
goto allocErr;
}
pud[j].value = ;
pud[j].bits.read = ;
pud[j].bits.write = ;
pud[j].bits.exec = ;
pud[j].bits.addr = __pa(pde) >>PAGE_SHIFT;
printk("pude: va=0x%016lx, pa=0x%016lx\n", (unsigned long)pde, (unsigned long)pud[j].bits.addr);
for(k = ; k < ; k++)
{
pde[k].value = ;
pde[k].bits.read = ;
pde[k].bits.write = ;
pde[k].bits.exec = ;
pde[k].bits.memtype = ;
pde[k].bits.ispage = ;
pde[k].bits.addr = memnum++;
if (memnum >= (<<))
{
return SUCCESS;
}
}
}
}
return SUCCESS; allocErr:
printk("initEpt: alloc mem error!\n");
return ERROR_ALLOC_FAILED; }
对创建的EPT页表做测试。
static err_t doMemTest(void)
{
__u64 *page,*page2;
unsigned char buff[];
memset(buff, , sizeof(buff));
page = (__u64*)__get_free_pages(GFP_KERNEL, );
page2 = (__u64*)__get_free_pages(GFP_KERNEL, );
if (page == NULL || page2 == NULL)
{
printk("alloc test mem failed!\n");
return ERROR_ALLOC_FAILED;
}
printk("page = 0x%016lx, page2 = 0x%016lx\n", (unsigned long int)page, (unsigned long int)page2);
cpu_vmcs_vmcall_memtest(VMCALL_MEM_TEST, __pa(page), __pa(page2));
printk("page = 0x%016lx, page2 = 0x%016lx, __pa(page2) = 0x%016lx\n\n\n\n", (unsigned long int)page, (unsigned long int)page2, (unsigned long int)__pa(page2));
//cpu_vmcs_vmcall_memtest(VMCALL_MEM_TEST, __pa(page), __pa(page2));
memcpy(page, "in our do mem test!\n", );
memcpy(buff, page2, );
//memcpy(page2, "in our do mem test!\n", 25);
// memcpy(buff, page2, 25); printk("buff = %s\n", buff); memcpy(page2, "test for test!\n", );
//memcpy(buff, page2, 30); printk("page = %s\n", (char *)page);
return SUCCESS;
}
static __always_inline void cpu_vmcs_vmcall_memtest(unsigned long reason,
unsigned long arg0, unsigned long arg1)
{
__u8 error, vmfailinvalid, vmfailvalid; asm volatile (
/* clear ZF and CF, otherwise guest may think that vmcall
* failed. encapsulated process may trick this by setting rsp to
* zero, but what's the point? */
"test %%rsp, %%rsp\n" "vmcall\n"
"setbe %0\n"
"setb %1\n"
"sete %2\n"
: "=qm"(error), "=qm"(vmfailinvalid), "=qm"(vmfailvalid)
: "D"(reason), "S"(arg0), "d"(arg1) :"cc", "memory"
); if (error)
vmcall_error(reason, vmfailinvalid, vmfailvalid);
}
static void exit_vmcall_trusted(struct vcpu *vcpu)
{
unsigned long arg0, arg1, arg2;
struct shadow_process *shadowp;
struct capsule_params *params;
enum vmcall_reason reason;
struct task_struct *task;
struct capsule *capsule;
bool woken_up; reason = vcpu->regs.rdi;
arg0 = vcpu->regs.rsi; switch (reason) {
case VMCALL_MEM_TEST:
arg1 = vcpu->regs.rdx;
printk("arg0 = 0x%016lx, arg1 = 0x%016lx\n", arg0, arg1);
modifyEpt(arg0, arg1);
break;
static void modifyEpt(__u64 vaddr1, __u64 vaddr2)
{ unsigned long paddr1,paddr2;
paddr1 = getPaddr(vaddr1);
paddr2 = getPaddr(vaddr2);
printk("pfn1 = 0x%016lx, pfn2 = 0x%016lx\n", (unsigned long)paddr1, (unsigned long)paddr2); setPaddr(paddr1, vaddr2); paddr1 = getPaddr(vaddr1);
paddr2 = getPaddr(vaddr2);
printk("pfn1 = 0x%016lx, pfn2 = 0x%016lx\n", (unsigned long)paddr1, (unsigned long)paddr2);
//invept(INVEPT_ALL_CONTEXT, eptph.value);
}
static unsigned long getPaddr(__u64 vaddr)
{
union ept_pgd *pgde;
union ept_pud *pude;
union ept_pde *pdee; //cpsl_dbg(capsule->id, "gpa -> hva: %016lx", gpa);
/* Page Global Dir */
pgde = pgd + ept_pgd_index(vaddr);
printk("pgde = 0x%016lx, physical address = 0x%016lx, pgde->value = 0x%016lx\n",
(unsigned long)pgde, (unsigned long)__pa(pgde), (unsigned long)pgde->value);
/* no entry in EPT PGD? */
if (!ept_pgd_present(pgde))
{
printk("getPaddr : pgd not found!\n");
return ;
}
printk("pgde get success......\n");
printk("pgde->bits.addr = 0x%016lx, va = 0x%016lx, pud_index = 0x%016lx",
(unsigned long)pgde->bits.addr, (unsigned long)__va((unsigned long)pgde->bits.addr << PAGE_SHIFT), (unsigned long)ept_pud_index(vaddr));
/* Page Upper Dir */
pude = (union ept_pud *)ept_pgd_addr(pgde) + ept_pud_index(vaddr);
if (!ept_pud_present(pude))
{
printk("getPaddr : pud not found!\n");
return ;
}
printk("pude get success......\n");
if (pude->value & ( << )) {
hv_err("BUG: huge pud in gpa_to_hva");
return ;
} /* Page Middle Dir */
printk("pude->bits.addr = 0x%016lx, va = 0x%016lx, pmd_index = 0x%016lx\n",
(unsigned long)pude->bits.addr, (unsigned long)__va((unsigned long)(pude->bits.addr << PAGE_SHIFT)), (unsigned long)ept_pmd_index(vaddr));
pdee = (union ept_pde *)ept_pud_addr(pude) + ept_pmd_index(vaddr);
if (!ept_pmd_present((union ept_pmd *)pdee))
{
printk("getPaddr : pde not found!\n");
return ;
}
if (pdee->value & ( << )) {
//hv_err("BUG: large pgd in gpa_to_hva");
printk("find pmd! pdee->value = 0x%016lx, pdee->bits.addr = 0x%016lx---------------\n", (unsigned long)pdee->value, (unsigned long)pdee->bits.addr); //hpa = (unsigned long)(pdee->bits.addr << LARGE_PAGE_SHIFT) + (vaddr & (LARGE_PAGE_SIZE-1));
printk("pdee->bits.addr = 0x%016lx\n", (unsigned long)pdee->bits.addr); return pdee->bits.addr;
}
printk("find pmd failed!\n");
return ;
#if 0
/* Page Table */
pte = ept_pmd_addr(pmde) + ept_pte_index(gpa);
if (!ept_pte_present(pte))
return NULL; hpa = pte->bits.addr << PAGE_SHIFT;
hva = __va(hpa); if (prot != NULL)
*prot = pte->value & EPT_PROT_RWX; return hva;
#endif
} static unsigned long setPaddr(unsigned long paddr, __u64 vaddr)
{
union ept_pgd *pgde;
union ept_pud *pude;
union ept_pde *pdee; //cpsl_dbg(capsule->id, "gpa -> hva: %016lx", gpa); /* Page Global Dir */
pgde = pgd + ept_pgd_index(vaddr);
/* no entry in EPT PGD? */
if (!ept_pgd_present(pgde))
{
printk("getPaddr : pgd not found!\n");
return ;
} /* Page Upper Dir */
pude = ept_pgd_addr(pgde) + ept_pud_index(vaddr);
if (!ept_pud_present(pude))
{
printk("getPaddr : pud not found!\n");
return ;
} if (pude->value & ( << )) {
hv_err("BUG: huge pud in gpa_to_hva");
return ;
} /* Page Middle Dir */
pdee = (union ept_pde *)ept_pud_addr(pude) + ept_pmd_index(vaddr);
if (!ept_pmd_present((union ept_pmd*)pdee))
{
printk("getPaddr : pmd not found!\n");
return ;
}
if (pdee->value & ( << )) {
//hv_err("BUG: large pgd in gpa_to_hva");
printk("find pmd!,now set it!!!!!!!!111\n");
pdee->bits.addr = paddr;
return pdee->bits.addr;
}
printk("find pmd failed!\n");
return ;
#if 0
/* Page Table */
pte = ept_pmd_addr(pmde) + ept_pte_index(gpa);
if (!ept_pte_present(pte))
return NULL; hpa = pte->bits.addr << PAGE_SHIFT;
hva = __va(hpa); if (prot != NULL)
*prot = pte->value & EPT_PROT_RWX; return hva;
#endif
}
线性区的页相关的那些标志。它们存放在vm_area_struct描述符的vm_flags字段中。一些标志给内核提供有关这个线性区全部页的信息,例如它们包含有什么内容,进程访问每个页的权限是什么。 另外的标志描述线性区自身,例如它应该如何增长(这些标志位于include/linux/Mm.h):
VM_READ:页是可读的
VM_WRITE:页是可写的
VM_EXEC:页是可执行的
VM_SHARED:页可以由几个进程共享
VM_MAYREAD:可以设置VM_READ标志
VM_MAYWRITE:可以设置VM_WRITE标志
VM_MAYEXEC:可以设置VM_EXEC标志
VM_MAYSHARE:可以设置VM_SHARE标志
VM_GROWSDOWN:线性区可以向低地址扩展
VM_GROWSUP:线性区可以向高地址扩展
VM_SHM:线性区用于IPC的共享内存
VM_DENYWRITE:线性区映射一个不能打开用于写的文件
VM_EXECUTABLE:线性区映射一个可执行文件
VM_LOCKED:线性区中的页被锁住,且不能换出
VM_IO:线性区映射设备的I/O地址空间
VM_SEQ_READ:应用程序顺序地访问页
VM_RAND_READ:应用程序以真正的随机顺序访问页
VM_DONTCOPY:当创建一个新进程时不拷贝线性区
VM_DONTEXPAND:通过mremap()系统调用禁止线性区扩展
VM_RESERVED:线性区是特殊的(如:它映射某个设备的I/O地址空间),因此它的页不能被交换出去
VM_ACCOUNT:创建IPC共享线性区时检查是否有足够的空闲内存用干映射
VM_HUGETLB:通过扩展分页机制处理线性区中的页
VM_NONLINEAR:线性区实现非线性文件映射
因此,要根据以下规则精简由读、写、执行和共享访问权限的16种可能组合: - 如果页具有写和共享两种访问权限,那么,Read/Write位被设置为1。 - 如果页具有读或执行访问权限,但是既没有写也没有共享访问权限,那么,Read/Write位被清0。 - 如果支持NX位,而且页没有执行访问权限,那么,把NX位设置为1。 - 如果页没有任何访问权限,那么,Presen七位被清0,以便每次访问都产生一个缺页异常。 然而,为了把这种情况与真正的页框不存在的情况相区分,Linux还把Page size位置为1(你可能认为Page size位的这种用法并不正当,因为这个位本来是表示实际页的大小。 但是,Linux可以侥幸逃脱这种骗局,因为80 x 86芯片在页目录项中检查Page size位,而不是在页表的表项中检查该位。)
do_page_fault()函数接收以下输入参数: - pt_regs结构的地址regs,该结构包含当异常发生时的微处理器寄存器的值。 - 3位的error_code,当异常发生时由控制单元压入栈中(参见第四章中的“中断和异常的硬件处理”一节)。这些位有以下含义:
—— 如果第0位被清0,则异常由访问一个不存在的页所引起(页表项中的Present标志被清0);否则,如果第0位被设置,则异常由无效的访问权限所引起。
—— 如果第1位被清0,则异常由读访问或者执行访问所引起;如果该位被设置,则异常由写访问所引起。
—— 如果第2位被清0,则异常发生在处理器处于内核态时;否则,异常发生在处理器处于用户态时。
* bit 3 == 1 means use of reserved bit detected * bit 4 == 1 means fault was an instruction fetch
初始化EPT的更多相关文章
- KVM地址翻译流程及EPT页表的建立过程
本博文为原创,遵循CC3.0协议,转载请注明出处:http://blog.csdn.net/lux_veritas/article/details/9284635 ------------------ ...
- KVm中EPT逆向映射机制分析
2017-05-30 前几天简要分析了linux remap机制,虽然还有些许瑕疵,但总算大致分析的比较清楚.今天分析下EPT下的逆向映射机制.EPT具体的工作流程可参考前面博文,本文对于EPT以及其 ...
- intel EPT 机制详解
2016-11-08 在虚拟化环境下,intel CPU在处理器级别加入了对内存虚拟化的支持.即扩展页表EPT,而AMD也有类似的成为NPT.在此之前,内存虚拟化使用的一个重要技术为影子页表. 背景: ...
- KVM的ept机制
转载:http://ytliu.info/blog/2014/11/24/shi-shang-zui-xiang-xi-de-kvm-mmu-pagejie-gou-he-yong-fa-jie-xi ...
- Java初始化过程
这篇文章主要讲解Java在创建对象的时候,初始化的顺序.主要从以下几个例子中讲解: 继承关系中初始化顺序 初始化块与构造器的顺序 已经加载过的类的初始化顺序 加载父类,会不会加载子类 创建子类对象会不 ...
- nginx源码分析之模块初始化
在nginx启动过程中,模块的初始化是整个启动过程中的重要部分,而且了解了模块初始化的过程对应后面具体分析各个模块会有事半功倍的效果.在我看来,分析源码来了解模块的初始化是最直接不过的了,所以下面主要 ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- Java类变量和成员变量初始化过程
一.类的初始化 对于类的初始化:类的初始化一般只初始化一次,类的初始化主要是初始化静态成员变量. 类的编译决定了类的初始化过程. 编译器生成的class文件主要对定义在源文件中的类进行了如下的更改: ...
- Git学习笔记一:新建本地仓库及初始化
1.百度搜索Git下载安装,直接按默认选项安装即可. 例如:Git-2.7.2-32-bit_setup.1457942412.exe 2.配置Git信息,建立版本仓库 (Alt+PrintScerr ...
随机推荐
- windows下xgboost安装到python
初始环境 在安装之前,我的anaconda2已经安装好,git也有装好 下载相对应的xgboost.dll文件 下载地址 Installing the Python Wrapper for me: x ...
- spring 在web.xml 里面如何使用多个xml配置文件
1, 在web.xml中定义 contextConfigLocation参数.spring会使用这个参数加载.所有逗号分割的xml.如果没有这个参数,spring默认加载web-inf/applica ...
- 因xhost命令和DISPLAY环境变量操作不当导致无法启动Oracle图形化安装界面
在redhat操作系统上安装Oracle 11.1时,遇到在执行runInstaller后无法启动安装图像化界面,甚是郁闷. 问题现象: 使用Xmanager2.0软件登陆AIX桌面,root用户可以 ...
- Go语言标准库之fmt.Print
Go语言fmt.Printf使用指南 本文整理了Go语言的标准输出流(fmt.Printf)在打印到屏幕时的格式化输出操作. 在这里按照占位符将被替换的变量类型划分,更方便查询和记忆. General ...
- (转)Linux传输大文件(分割传输)
1.分拆为多个文件的命令: cat workspace_2018.tar.gz | split -b 1G - workspace_2018.tar.gz. 命令解释: workspace_2018. ...
- 第二章 Vue快速入门-- 23 品牌案例-根据关键字实现数组的过滤
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- 原生js实现简单的下拉刷新功能
前言: 我们在浏览移动端web页面的时候,经常会用到下拉刷新. 现在我们用原生的js实现这个非常简单的下拉刷新功能. (温馨提示:本文比较基础,功能也很简单.写的不好的地方,希望大神提点一二.) 一. ...
- centos7时区同步(时间24小时格式显示)
我们在服务器安装linux系统时,有时会因服务器时间或者时区不正确导致程序出现错误. 首先输入date命令查看当前的时间和时区.要注意CST EDT 等时区的区别 介绍一种与时间服务器上时间同步的 ...
- Unknown or unsupported command 'install'
由于电脑中存在多个python,导致pip install numpy出现标题这样的错误 结局方案; 在想要的python文件夹中的Scripts,shift右键点开命令行,pip.exe insta ...
- cdh本地源安装-自用
yum 安装cm 参考官网 主机名 /etc/hosts hostnamectl set-hostname foo-1.data.com hostnamectl set-hostname foo-2. ...