初始化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 ...
随机推荐
- 数据库命令行工具USQL、mycli、litecli、pgcli
USQL USQL 是一款使用 Go 语言开发的支持 SQL/NoSQL 数据库的通用命令行工具,它支持多种主流的数据库软件,目前最新版本是usql 0.7.0.比如 PostgreSQL.MySQL ...
- 查看Linux服务器硬件信息
一:查看cpu# 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理CPU个数 X 每颗物理CPU的核数 X 超线程数# 查看物理CPU个数cat /proc/cpui ...
- python tkinter 基本使用
这里只放表格和一个控件基本属性 grid(**options) 属性-- 下方表格详细列举了各个选项的具体含义和用法: 选项 含义column 1. 指定组件插入的列(0 表示第 1 列)2. 默认值 ...
- SecureCRT 连接 Centos7.0 (NAT模式),且能连接公网。
1.打开物理主机运行-输入cmd,输入ipconfig,获取物理主机ip地址. ip:192.168.11.138 2.点击网络适配器,选择NAT模式. 3.点击Centos界面左上角-编辑-虚拟网络 ...
- 《python解释器源码剖析》第0章--python的架构与编译python
本系列是以陈儒先生的<python源码剖析>为学习素材,所记录的学习内容.不同的是陈儒先生的<python源码剖析>所剖析的是python2.5,本系列对应的是python3. ...
- centos6和centos7的区别和常用的简单配置优化
- 本节主要介绍centos6和centos7的区别和常用的简单配置优化:- 第一部分: - 1.对比文件系统 - 2.对比防火墙,内核版本,默认数据库 - 3.对比时间同步,修改时区,修改语言 - ...
- Linux工具之netstat
1.简介 Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicas ...
- windows server没有这台电脑图标
rundll32.exe shell32.dll,Control_RunDLL desk.cpl,,0
- [uboot] (第三章)uboot流程——uboot-spl代码流程 后续2018版本分析
board_init_f在/u-boot-2018.07-fmxx/arch/arm/mach-fmxx/spl.c中定义 board_init_f之后,和转载的部分有出入: u-boot-2018. ...
- 通过实现接口runnable实现多线程
实现Runnable接口实现多线程的步骤(1)编写类实现Runnable接口(2)实现run(方法(3)通过Thread类的start(方法启动线程 静态代理模式Thread >代理 角色MyR ...