Xen授权表的使用

完全照搬原文,原文地址:http://fire-flying.diandian.com/。

///

原文的代码可能比较旧,在我的机器上已经不能运行,下面是经我修改过的,先看domU端的代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <xen/interface/xen.h>
#include <xen/interface/io/ring.h>
#include <xen/grant_table.h>
#include <asm/pgtable.h>
#include <asm/sync_bitops.h>
#include <xen/events.h>
//#include <xen/gnttab.h>
#include <asm/xen/page.h>
#include <xen/evtchn.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>

unsigned long page;
struct as_request {
unsigned int id;
unsigned int status;
unsigned int operation;
};
struct as_response {
unsigned int id;
unsigned int status;
unsigned int operation;
};

DEFINE_RING_TYPES(as, struct as_request, struct as_response);
struct info_t {
struct as_front_ring ring;
grant_ref_t gref;
int irq;
int port;
}info;

#define DOM0_ID 0

static struct proc_dir_entry *proc_dir = NULL;
static struct proc_dir_entry *proc_file = NULL;
char proc_data[20];

int send_request_to_dom0(void) 
{
struct as_request *ring_req;
int notify;
static int reqid = 9;
ring_req = RING_GET_REQUEST(&(info.ring), info.ring.req_prod_pvt);
ring_req->id = reqid;
ring_req->operation = reqid;
ring_req->status = reqid;
printk(KERN_DEBUG "\nxen:DomU: Fill in IDX-%d, with id=%d, op=%d, st=%d",
info.ring.req_prod_pvt, ring_req->id, ring_req->operation, ring_req->status);
reqid++;
info.ring.req_prod_pvt += 1;
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&(info.ring), notify);
if (notify) {
printk(KERN_DEBUG "\nxen: DomU: sent a req to Dom0");
notify_remote_via_irq(info.irq);
} else {
printk(KERN_DEBUG "\nxen:DomU: No notify req to Dom0");
notify_remote_via_irq(info.irq);
}
printk("...\n");
return 0;
}

int file_write (struct file *filp, const char __user *buff, unsigned long len, void *data)
{
int value;
printk(KERN_DEBUG "\nxen:domU: file_write %lu bytes", len);
if (copy_from_user(&proc_data[0], buff, len))
return -EFAULT;
proc_data[len] = '\x0';
value = simple_strtol(proc_data, 0, 10);
switch(value) {
case 1:
send_request_to_dom0();
printk(KERN_DEBUG " ,value = %d", value);
break;
default:
printk(KERN_DEBUG " ,value not recongnized!");
}
return len;
}

int file_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
sprintf(page, "%s", proc_data);
return strlen(page);
}
int create_procfs_entry(void) 
{
int ret = 0;
proc_dir = proc_mkdir("demo", NULL);
if (!proc_dir) {
printk(KERN_DEBUG "\nxen:domU could not create demo entry in procfs");
ret = - EAGAIN;
return ret;
}
proc_file = create_proc_entry("file", 0600, proc_dir);
if (proc_file) {
proc_file->read_proc = file_read;
proc_file->write_proc = file_write;
//proc_file->owner = THIS_MODULE;
} else {
printk(KERN_DEBUG "\nxen:domU Could not create /proc/demo/file");
ret = -EAGAIN;
return ret;
}
return ret;
}

static irqreturn_t as_int (int irq, void *dev_id)
{
struct as_response *ring_resp;
RING_IDX i, rp;

printk("\nxen:DomU: as_int called");
again:
rp = info.ring.sring->rsp_prod;
printk(KERN_DEBUG "\nxen:DomU:ring pointers %d to %d", info.ring.rsp_cons, rp);
for (i = info.ring.rsp_cons; i != rp; i++) {
unsigned long id;
ring_resp = RING_GET_RESPONSE(&(info.ring), i);
printk(KERN_DEBUG "\nxen:domU: Recvd in IDX-%d, with id=%d, op=%d, st=%d", i, ring_resp->id, ring_resp->operation, ring_resp->status);
id = ring_resp->id;
switch(ring_resp->operation) {
case 0:
printk(KERN_DEBUG "\nxen:DomU: operation: 0");
break;
default:
break;
}
}
info.ring.rsp_cons = i;
if (i != info.ring.req_prod_pvt) {
int more_to_do;
RING_FINAL_CHECK_FOR_RESPONSES(&info.ring, more_to_do);
if (more_to_do)
goto again;
} else
info.ring.sring->rsp_event = i + 1;
return IRQ_HANDLED;
}

int gnt_init(void)
{
int mfn;
int err;
//int i;
struct as_sring *sring;
//char *p;

struct evtchn_alloc_unbound alloc_unbound;
printk(KERN_INFO "gnt_init\n");

page =  __get_free_pages(GFP_KERNEL, 0);
if (page == 0) {
printk(KERN_DEBUG "\nxen:DomU:could not get free page");
return 0;
}
sring = (struct as_sring *)page;
SHARED_RING_INIT(sring);
FRONT_RING_INIT(&(info.ring), sring, PAGE_SIZE);
mfn = virt_to_mfn(page);
/*
p = (char *)page + PAGE_SIZE - 1;
for (i = 0; i <= 10; i--, p--)
*p = 'A';
*/
///
/*
strcpy((char *)page, "aseem sethi");
for (i = 0; i <= 10; i++)
printk(KERN_DEBUG "%c", ((char *)page)[i]);
*/


printk(KERN_INFO "grant foreign access\n");
info.gref = gnttab_grant_foreign_access(DOM0_ID, mfn, 0);
//info.gref = gnttab_grant_foreign_access(DOM0_ID, mfn, 1);
if (info.gref < 0) {
printk(KERN_DEBUG "\nxen:could not grant foreign access");
free_page((unsigned long)page);
info.ring.sring = NULL;
return 0;
}
printk(KERN_DEBUG "\n gref = %d", info.gref);
alloc_unbound.dom = DOMID_SELF;
alloc_unbound.remote_dom = DOM0_ID;
err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &alloc_unbound);
if (err) {
printk(KERN_DEBUG "\nalloc unbound port failure");
return err;
}

err = bind_evtchn_to_irqhandler(alloc_unbound.port, as_int, 0, "xen-eg", &info);
if (err < 0) {
printk(KERN_DEBUG "\nbind evtchn to irqhandler failure");
return err;
}
/*
err = bind_listening_port_to_irqhandler(DOM0_ID, as_int, 0, "xen-eg", &info);
if (err < 0) {
printk(KERN_DEBUG "\nxen:DomU failed to setup evtchn");
gnttab_end_foreign_access(info.gref, 0, page);
return 0;
}
*/
info.irq = err;
info.port = alloc_unbound.port;
//info.port = irq_to_evtchn_port(info.irq);
printk(KERN_DEBUG " interrupt = %d, local_port = %d", info.irq, info.port);
printk("...\n...");
create_procfs_entry();
return 0;
}

void gnt_exit(void)
{
printk(KERN_DEBUG "\ncleanup grant ref:");
if (gnttab_query_foreign_access(info.gref) == 0) {
printk(KERN_DEBUG "\n xen:No one has mapped this frame");
gnttab_end_foreign_access(info.gref, 0, page);
//gnttab_end_foreign_access(info.gref, 0, sring);
} else {
printk(KERN_DEBUG "\n xen:Someone has mapped this frame");
gnttab_end_foreign_access(info.gref, 0, page);
//gnttab_end_foreign_access(info.gref, 0, sring);
}
remove_proc_entry("file", proc_dir);
remove_proc_entry("demo", NULL);
printk(KERN_DEBUG "...\n...");
}
module_init(gnt_init);
module_exit(gnt_exit);
MODULE_LICENSE("GPL");
DomainU

总结一下,domU端需要做的事情:

1. 获取一页空闲内存,初始化共享环及前端(__get_free_pages, SHARED_RING_INIT, FRONT_RING_INIT);

2.__get_free_pages得到的是虚拟地址,调用virt_to_mfn得到机器页帧号,然后授权Dom0可以访问,得到授权引用(gnttab_grant_foreign_access, 这个函数需要的是机器页帧号);

3. 通过超级调用HYPERVISOR_event_channel_op(EVTCHN_alloc_unbound, ...)分配端口号,调用bind_evtchn_to_irqhandler将端口号与中断处理函数绑定,得到中断号;至此,主要的工作便完成了,为了 便于控制,使用了proc-fs,通过create_procfs_entry创建proc文件系统。

然后再看dom0部分代码:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <xen/grant_table.h>
//#include <xen/interface/io/blkif.h>
#include <xen/interface/io/ring.h>
#include <xen/interface/xen.h>
#include <xen/xen.h>
#include <linux/vmalloc.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
#include <xen/evtchn.h>
#include <xen/events.h>

struct gnttab_map_grant_ref ops;
struct gnttab_unmap_grant_ref unmap_ops;

struct as_request {
unsigned int id;
unsigned int status;
unsigned int operation;
};
struct as_response {
unsigned int id;
unsigned int status;
unsigned int operation;
};
typedef struct as_request as_request_t;
typedef struct as_response as_response_t;

DEFINE_RING_TYPES(as, struct as_request, struct as_response);
typedef struct as_sring as_sring_t;
typedef struct as_front_ring as_front_ring_t;
typedef struct as_back_ring as_back_ring_t;

struct info_t {
int irq;
int gref;
int remoteDomain;
int evtchn;
struct as_back_ring ring;
} info;

int gref;
int port;
module_param(gref, int, 0644);
module_param(port, int, 0644);

static irqreturn_t as_int(int irq, void *dev_id)
{
RING_IDX rc, rp;
as_request_t req;
as_response_t resp;
int more_to_do, notify;
printk(KERN_DEBUG "\nxen:Dom0: as_int called with dev_id %x info=%x", (unsigned int )dev_id, (unsigned int) &info);
rc = info.ring.req_cons;
rp = info.ring.sring->req_prod;
printk(KERN_DEBUG " rc = %d rp = %d", rc, rp);
while (rc != rp) {
if (RING_REQUEST_CONS_OVERFLOW(&info.ring, rc))
break;
memcpy(&req, RING_GET_REQUEST(&info.ring, rc), sizeof(req));
resp.id = req.id;
resp.operation = req.operation;
resp.status = req.status + 1;
printk(KERN_DEBUG "\nxen:Dom0:Recvd at IDX-%d: id = %d, op=%d, status=%d", rc, req.id, req.operation, req.status);
info.ring.req_cons = ++rc;
barrier();
switch(req.operation) {
case 0:
printk(KERN_DEBUG "\nxen:dom0:req.operation = 0");
break;
default:
printk(KERN_DEBUG "\nxen:dom0:req.operation = %d", req.operation);
break;
}
memcpy(RING_GET_RESPONSE(&info.ring, info.ring.rsp_prod_pvt), &resp, sizeof(resp));
info.ring.rsp_prod_pvt++;
RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&info.ring, notify);
if (info.ring.rsp_prod_pvt == info.ring.req_cons) {
RING_FINAL_CHECK_FOR_REQUESTS(&info.ring, more_to_do);
} else if (RING_HAS_UNCONSUMED_REQUESTS(&info.ring)) {
more_to_do = 1;
}
if (notify) {
printk(KERN_DEBUG "\nxen:dom0:send notify to domu");
notify_remote_via_irq(info.irq);
}
}
return IRQ_HANDLED;
}

static int gnt_init(void) 
{
struct vm_struct *v_start;
int err;
//int i;
//char *p;
as_sring_t *sring;
info.gref = gref;
info.remoteDomain = 1;
info.evtchn = port;
printk(KERN_DEBUG "\nxen: dom0: gnt_init with gref = %d", info.gref);
v_start = alloc_vm_area(PAGE_SIZE);//dom需要将授权访问的内存页映射到自己的地址空间中,分配一个非连续的内存区域
if (v_start == 0) {
free_vm_area(v_start);
printk("\nxen: dom0:could not allocate page");
return -EFAULT;
}

gnttab_set_map_op(&ops, (unsigned long)v_start->addr, GNTMAP_host_map, info.gref, info.remoteDomain);//为下面的hypercall的参数做准备
if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &ops, 1)) {//页面映射
printk(KERN_DEBUG "\nxen:dom0: HYPERVISOR map grant ref failed");
return -EFAULT;
}
if (ops.status) {
printk(KERN_DEBUG "\nxen: dom0: HYPERVISOR map grant ref failed status = %d", ops.status);
return -EFAULT;
}
printk(KERN_DEBUG "\nxen:dom0:shared_page=%x, handle = %x, status = %x", (unsigned int)v_start->addr, ops.handle, ops.status);

unmap_ops.host_addr = (unsigned long)(v_start->addr);
unmap_ops.handle = ops.handle;
//
/*
p = (char *)(v_start->addr) + PAGE_SIZE - 1;
printk(KERN_DEBUG "\nbytes in page");
for (i = 0;i <= 10; i++, p--) {
printk(KERN_DEBUG "%c", *p);
}
*/
////
sring = (as_sring_t *)v_start->addr;
BACK_RING_INIT(&info.ring, sring, PAGE_SIZE);
err = bind_interdomain_evtchn_to_irqhandler(info.remoteDomain, info.evtchn, as_int, 0, "dom0-backend", &info);
if (err < 0) {
printk(KERN_DEBUG "\nxen:dom0: gnt_init failed binding to evtchn");
err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmap_ops, 1);
return -EFAULT;
}
info.irq = err;
printk(KERN_DEBUG "\nxen:dom0:end gnt_int: int = %d", info.irq);
return 0;
}

static void gnt_exit(void)
{
int ret;
printk(KERN_DEBUG "\nxen:dom0:gnt_exit");
ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &unmap_ops, 1);
if (ret == 0) {
printk(KERN_DEBUG "gnt_exit: unmapped shared frame");
} else {
printk(KERN_DEBUG "gnt_exit: unmapped shared frame failed");
}
printk("...\n");
}
module_init(gnt_init);
module_exit(gnt_exit);
MODULE_LICENSE("GPL");
Domain0

dom0所做的工作:

1. 因为我们需要将domU的一部分内存映射到dom0内,因此调用alloc_vm_area预留一段内核空间和页表,但是实际并没有映射;

2. 调用gnttab_set_map_op为超级调用的参数做准备,然后调用HYPERVISOR_grant_table_op(GTNTABOP_map_grant_ref, ...)进行页面映射;

3. 调用BACK_RING_INIT初始化共享环后端;

4. 调用bind_interdomain_evtchn_to_irqhandler将端口与中断处理程序绑定,这样会得到中断号,注意端口号是模块函数的参数。

转载于:https://www.cnblogs.com/jiangyunmenglong/p/3868089.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值