domctl.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,086 行 · 第 1/2 页
C
1,086 行
/****************************************************************************** * Arch-specific domctl.c * * Copyright (c) 2002-2006, K A Fraser */#include <xen/config.h>#include <xen/types.h>#include <xen/lib.h>#include <xen/mm.h>#include <xen/guest_access.h>#include <xen/compat.h>#include <xen/pci.h>#include <public/domctl.h>#include <xen/sched.h>#include <xen/domain.h>#include <xen/event.h>#include <xen/domain_page.h>#include <asm/msr.h>#include <xen/trace.h>#include <xen/console.h>#include <xen/iocap.h>#include <asm/paging.h>#include <asm/irq.h>#include <asm/hvm/hvm.h>#include <asm/hvm/support.h>#include <asm/hvm/cacheattr.h>#include <asm/processor.h>#include <xsm/xsm.h>#include <xen/iommu.h>long arch_do_domctl( struct xen_domctl *domctl, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl){ long ret = 0; switch ( domctl->cmd ) { case XEN_DOMCTL_shadow_op: { struct domain *d; ret = -ESRCH; d = rcu_lock_domain_by_id(domctl->domain); if ( d != NULL ) { ret = paging_domctl(d, &domctl->u.shadow_op, guest_handle_cast(u_domctl, void)); rcu_unlock_domain(d); copy_to_guest(u_domctl, domctl, 1); } } break; case XEN_DOMCTL_ioport_permission: { struct domain *d; unsigned int fp = domctl->u.ioport_permission.first_port; unsigned int np = domctl->u.ioport_permission.nr_ports; ret = -EINVAL; if ( (fp + np) > 65536 ) break; ret = -ESRCH; if ( unlikely((d = rcu_lock_domain_by_id(domctl->domain)) == NULL) ) break; ret = xsm_ioport_permission(d, fp, domctl->u.ioport_permission.allow_access); if ( ret ) { rcu_unlock_domain(d); break; } if ( np == 0 ) ret = 0; else if ( domctl->u.ioport_permission.allow_access ) ret = ioports_permit_access(d, fp, fp + np - 1); else ret = ioports_deny_access(d, fp, fp + np - 1); rcu_unlock_domain(d); } break; case XEN_DOMCTL_getpageframeinfo: { struct page_info *page; unsigned long mfn = domctl->u.getpageframeinfo.gmfn; domid_t dom = domctl->domain; struct domain *d; ret = -EINVAL; if ( unlikely(!mfn_valid(mfn)) || unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) break; page = mfn_to_page(mfn); ret = xsm_getpageframeinfo(page); if ( ret ) { rcu_unlock_domain(d); break; } if ( likely(get_page(page, d)) ) { ret = 0; domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_NOTAB; if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) { switch ( page->u.inuse.type_info & PGT_type_mask ) { case PGT_l1_page_table: domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L1TAB; break; case PGT_l2_page_table: domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L2TAB; break; case PGT_l3_page_table: domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L3TAB; break; case PGT_l4_page_table: domctl->u.getpageframeinfo.type = XEN_DOMCTL_PFINFO_L4TAB; break; } } put_page(page); } rcu_unlock_domain(d); copy_to_guest(u_domctl, domctl, 1); } break; case XEN_DOMCTL_getpageframeinfo2: { int n,j; int num = domctl->u.getpageframeinfo2.num; domid_t dom = domctl->domain; struct domain *d; uint32_t *arr32; ret = -ESRCH; if ( unlikely((d = rcu_lock_domain_by_id(dom)) == NULL) ) break; if ( unlikely(num > 1024) ) { ret = -E2BIG; rcu_unlock_domain(d); break; } arr32 = alloc_xenheap_page(); if ( !arr32 ) { ret = -ENOMEM; put_domain(d); break; } ret = 0; for ( n = 0; n < num; ) { int k = PAGE_SIZE / 4; if ( (num - n) < k ) k = num - n; if ( copy_from_guest_offset(arr32, domctl->u.getpageframeinfo2.array, n, k) ) { ret = -EFAULT; break; } for ( j = 0; j < k; j++ ) { struct page_info *page; unsigned long mfn = arr32[j]; page = mfn_to_page(mfn); ret = xsm_getpageframeinfo(page); if ( ret ) continue; if ( likely(mfn_valid(mfn) && get_page(page, d)) ) { unsigned long type = 0; switch( page->u.inuse.type_info & PGT_type_mask ) { case PGT_l1_page_table: type = XEN_DOMCTL_PFINFO_L1TAB; break; case PGT_l2_page_table: type = XEN_DOMCTL_PFINFO_L2TAB; break; case PGT_l3_page_table: type = XEN_DOMCTL_PFINFO_L3TAB; break; case PGT_l4_page_table: type = XEN_DOMCTL_PFINFO_L4TAB; break; } if ( page->u.inuse.type_info & PGT_pinned ) type |= XEN_DOMCTL_PFINFO_LPINTAB; arr32[j] |= type; put_page(page); } else arr32[j] |= XEN_DOMCTL_PFINFO_XTAB; } if ( copy_to_guest_offset(domctl->u.getpageframeinfo2.array, n, arr32, k) ) { ret = -EFAULT; break; } n += k; } free_xenheap_page(arr32); rcu_unlock_domain(d); } break; case XEN_DOMCTL_getmemlist: { int i; struct domain *d = rcu_lock_domain_by_id(domctl->domain); unsigned long max_pfns = domctl->u.getmemlist.max_pfns; uint64_t mfn; struct list_head *list_ent; ret = -EINVAL; if ( d != NULL ) { ret = xsm_getmemlist(d); if ( ret ) { rcu_unlock_domain(d); break; } spin_lock(&d->page_alloc_lock); if ( unlikely(d->is_dying) ) { spin_unlock(&d->page_alloc_lock); goto getmemlist_out; } ret = 0; list_ent = d->page_list.next; for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ ) { mfn = page_to_mfn(list_entry( list_ent, struct page_info, list)); if ( copy_to_guest_offset(domctl->u.getmemlist.buffer, i, &mfn, 1) ) { ret = -EFAULT; break; } list_ent = mfn_to_page(mfn)->list.next; } spin_unlock(&d->page_alloc_lock); domctl->u.getmemlist.num_pfns = i; copy_to_guest(u_domctl, domctl, 1); getmemlist_out: rcu_unlock_domain(d); } } break; case XEN_DOMCTL_hypercall_init: { struct domain *d = rcu_lock_domain_by_id(domctl->domain); unsigned long gmfn = domctl->u.hypercall_init.gmfn; unsigned long mfn; void *hypercall_page; ret = -ESRCH; if ( unlikely(d == NULL) ) break; ret = xsm_hypercall_init(d); if ( ret ) { rcu_unlock_domain(d); break; } mfn = gmfn_to_mfn(d, gmfn); ret = -EACCES; if ( !mfn_valid(mfn) || !get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) ) { rcu_unlock_domain(d); break; } ret = 0; hypercall_page = map_domain_page(mfn); hypercall_page_initialise(d, hypercall_page); unmap_domain_page(hypercall_page); put_page_and_type(mfn_to_page(mfn)); rcu_unlock_domain(d); } break; case XEN_DOMCTL_sethvmcontext: { struct hvm_domain_context c; struct domain *d; c.cur = 0; c.size = domctl->u.hvmcontext.size; c.data = NULL; ret = -ESRCH; if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; ret = xsm_hvmcontext(d, domctl->cmd); if ( ret ) goto sethvmcontext_out; ret = -EINVAL; if ( !is_hvm_domain(d) ) goto sethvmcontext_out; ret = -ENOMEM; if ( (c.data = xmalloc_bytes(c.size)) == NULL ) goto sethvmcontext_out; ret = -EFAULT; if ( copy_from_guest(c.data, domctl->u.hvmcontext.buffer, c.size) != 0) goto sethvmcontext_out; domain_pause(d); ret = hvm_load(d, &c); domain_unpause(d); sethvmcontext_out: if ( c.data != NULL ) xfree(c.data); rcu_unlock_domain(d); } break; case XEN_DOMCTL_gethvmcontext: { struct hvm_domain_context c; struct domain *d; ret = -ESRCH; if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; ret = xsm_hvmcontext(d, domctl->cmd); if ( ret ) goto gethvmcontext_out; ret = -EINVAL; if ( !is_hvm_domain(d) ) goto gethvmcontext_out; c.cur = 0; c.size = hvm_save_size(d); c.data = NULL; if ( guest_handle_is_null(domctl->u.hvmcontext.buffer) ) { /* Client is querying for the correct buffer size */ domctl->u.hvmcontext.size = c.size; ret = 0; goto gethvmcontext_out; } /* Check that the client has a big enough buffer */ ret = -ENOSPC; if ( domctl->u.hvmcontext.size < c.size ) goto gethvmcontext_out; /* Allocate our own marshalling buffer */ ret = -ENOMEM; if ( (c.data = xmalloc_bytes(c.size)) == NULL ) goto gethvmcontext_out; domain_pause(d); ret = hvm_save(d, &c); domain_unpause(d); domctl->u.hvmcontext.size = c.cur; if ( copy_to_guest(domctl->u.hvmcontext.buffer, c.data, c.size) != 0 ) ret = -EFAULT; gethvmcontext_out: if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; if ( c.data != NULL ) xfree(c.data); rcu_unlock_domain(d); } break; case XEN_DOMCTL_set_address_size: { struct domain *d; ret = -ESRCH; if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; ret = xsm_address_size(d, domctl->cmd); if ( ret ) { rcu_unlock_domain(d); break; } switch ( domctl->u.address_size.size ) {#ifdef CONFIG_COMPAT case 32: ret = switch_compat(d); break; case 64: ret = switch_native(d); break;#endif default: ret = (domctl->u.address_size.size == BITS_PER_LONG) ? 0 : -EINVAL; break; } rcu_unlock_domain(d); } break; case XEN_DOMCTL_get_address_size: { struct domain *d; ret = -ESRCH; if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; ret = xsm_address_size(d, domctl->cmd); if ( ret ) { rcu_unlock_domain(d); break; } domctl->u.address_size.size = BITS_PER_GUEST_LONG(d); ret = 0; rcu_unlock_domain(d); if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; } break; case XEN_DOMCTL_set_machine_address_size: { struct domain *d; ret = -ESRCH; if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; ret = xsm_machine_address_size(d, domctl->cmd); if ( ret ) rcu_unlock_domain(d); ret = -EBUSY; if ( d->tot_pages > 0 ) goto set_machine_address_size_out; d->arch.physaddr_bitsize = domctl->u.address_size.size; ret = 0; set_machine_address_size_out: rcu_unlock_domain(d); } break; case XEN_DOMCTL_get_machine_address_size: { struct domain *d; ret = -ESRCH; if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) break; ret = xsm_machine_address_size(d, domctl->cmd); if ( ret ) { rcu_unlock_domain(d); break; } domctl->u.address_size.size = d->arch.physaddr_bitsize; ret = 0; rcu_unlock_domain(d); if ( copy_to_guest(u_domctl, domctl, 1) ) ret = -EFAULT; } break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?