📄 dom0_ops.c
字号:
/****************************************************************************** * Arch-specific dom0_ops.c * * Process command requests from domain-0 guest OS. * * Copyright (c) 2002, K A Fraser */#include <xen/config.h>#include <xen/types.h>#include <xen/lib.h>#include <xen/mm.h>#include <public/domctl.h>#include <public/sysctl.h>#include <xen/sched.h>#include <xen/event.h>#include <asm/pdb.h>#include <xen/trace.h>#include <xen/console.h>#include <xen/guest_access.h>#include <asm/vmx.h>#include <asm/dom_fw.h>#include <asm/vhpt.h>#include <xen/iocap.h>#include <xen/errno.h>#include <xen/nodemask.h>#include <asm/dom_fw_utils.h>#include <asm/hvm/support.h>#include <xsm/xsm.h>#include <public/hvm/save.h>#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0)extern unsigned long total_pages;long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl){ long ret = 0; switch ( op->cmd ) { case XEN_DOMCTL_getmemlist: { unsigned long i; struct domain *d = rcu_lock_domain_by_id(op->domain); unsigned long start_page = op->u.getmemlist.start_pfn; unsigned long nr_pages = op->u.getmemlist.max_pfns; uint64_t mfn; if ( d == NULL ) { ret = -EINVAL; break; } if ( !IS_PRIV_FOR(current->domain, d) ) { ret = -EPERM; rcu_unlock_domain(d); break; } for (i = 0 ; i < nr_pages ; i++) { pte_t *pte; pte = (pte_t *)lookup_noalloc_domain_pte(d, (start_page + i) << PAGE_SHIFT); if (pte && pte_present(*pte)) mfn = start_page + i; else mfn = INVALID_MFN; if ( copy_to_guest_offset(op->u.getmemlist.buffer, i, &mfn, 1) ) { ret = -EFAULT; break; } } op->u.getmemlist.num_pfns = i; if (copy_to_guest(u_domctl, op, 1)) ret = -EFAULT; rcu_unlock_domain(d); } break; case XEN_DOMCTL_arch_setup: { xen_domctl_arch_setup_t *ds = &op->u.arch_setup; struct domain *d = rcu_lock_domain_by_id(op->domain); if ( d == NULL) { ret = -EINVAL; break; } if ( !IS_PRIV_FOR(current->domain, d) ) { ret = -EPERM; rcu_unlock_domain(d); break; } if (ds->flags & XEN_DOMAINSETUP_query) { /* Set flags. */ if (is_hvm_domain(d)) ds->flags |= XEN_DOMAINSETUP_hvm_guest; /* Set params. */ ds->bp = 0; /* unknown. */ ds->maxmem = d->arch.convmem_end; ds->xsi_va = d->arch.shared_info_va; ds->hypercall_imm = d->arch.breakimm;#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT ds->vhpt_size_log2 = d->arch.vhpt_size_log2;#endif /* Copy back. */ if ( copy_to_guest(u_domctl, op, 1) ) ret = -EFAULT; } else { if (is_hvm_domain(d) || (ds->flags & (XEN_DOMAINSETUP_hvm_guest | XEN_DOMAINSETUP_sioemu_guest))) { if (!vmx_enabled) { printk("No VMX hardware feature for vmx domain.\n"); ret = -EINVAL; } else { d->is_hvm = 1; if (ds->flags & XEN_DOMAINSETUP_sioemu_guest) d->arch.is_sioemu = 1; xen_ia64_set_convmem_end(d, ds->maxmem); ret = vmx_setup_platform(d); } } else { if (ds->hypercall_imm) { /* dom_fw_setup() reads d->arch.breakimm */ struct vcpu *v; d->arch.breakimm = ds->hypercall_imm; for_each_vcpu (d, v) v->arch.breakimm = d->arch.breakimm; } domain_set_vhpt_size(d, ds->vhpt_size_log2); if (ds->xsi_va) d->arch.shared_info_va = ds->xsi_va; ret = dom_fw_setup(d, ds->bp, ds->maxmem); } if (ret == 0) { /* * XXX IA64_SHARED_INFO_PADDR * assign these pages into guest psudo physical address * space for dom0 to map this page by gmfn. * this is necessary for domain build, save, restore and * dump-core. */ unsigned long i; for (i = 0; i < XSI_SIZE; i += PAGE_SIZE) assign_domain_page(d, IA64_SHARED_INFO_PADDR + i, virt_to_maddr(d->shared_info + i)); } } rcu_unlock_domain(d); } break; case XEN_DOMCTL_shadow_op: { struct domain *d; ret = -ESRCH; d = rcu_lock_domain_by_id(op->domain); if ( d != NULL ) { if ( !IS_PRIV_FOR(current->domain, d) ) { ret = -EPERM; rcu_unlock_domain(d); break; } ret = shadow_mode_control(d, &op->u.shadow_op); rcu_unlock_domain(d); if (copy_to_guest(u_domctl, op, 1)) ret = -EFAULT; } } break; case XEN_DOMCTL_ioport_permission: { struct domain *d; unsigned int fp = op->u.ioport_permission.first_port; unsigned int np = op->u.ioport_permission.nr_ports; unsigned int lp = fp + np - 1; ret = -ESRCH; d = rcu_lock_domain_by_id(op->domain); if (unlikely(d == NULL)) break; if ( !IS_PRIV_FOR(current->domain, d) ) { ret = -EPERM; rcu_unlock_domain(d); break; } if (np == 0) ret = 0; else { if (op->u.ioport_permission.allow_access) ret = ioports_permit_access(d, fp, lp); else ret = ioports_deny_access(d, fp, lp); } rcu_unlock_domain(d); } break; case XEN_DOMCTL_sendtrigger: { struct domain *d; struct vcpu *v; ret = -ESRCH; d = rcu_lock_domain_by_id(op->domain); if ( d == NULL ) break; ret = -EPERM; if ( !IS_PRIV_FOR(current->domain, d) ) { goto sendtrigger_out; } ret = -EINVAL; if ( op->u.sendtrigger.vcpu >= MAX_VIRT_CPUS ) goto sendtrigger_out; ret = -ESRCH; if ( (v = d->vcpu[op->u.sendtrigger.vcpu]) == NULL ) goto sendtrigger_out; ret = 0; switch (op->u.sendtrigger.trigger) { case XEN_DOMCTL_SENDTRIGGER_INIT: { if (VMX_DOMAIN(v)) vmx_pend_pal_init(d); else ret = -ENOSYS; } break; default: ret = -ENOSYS; } sendtrigger_out: rcu_unlock_domain(d); } break; case XEN_DOMCTL_sethvmcontext: { struct hvm_domain_context c; struct domain *d; c.cur = 0; c.size = op->u.hvmcontext.size; c.data = NULL; ret = -ESRCH; d = rcu_lock_domain_by_id(op->domain); if (d == NULL) break; ret = -EPERM; if ( !IS_PRIV_FOR(current->domain, d) ) goto sethvmcontext_out;#ifdef CONFIG_X86 ret = xsm_hvmcontext(d, op->cmd); if (ret) goto sethvmcontext_out;#endif /* CONFIG_X86 */ ret = -EINVAL; if (!is_hvm_domain(d)) goto sethvmcontext_out; ret = -ENOMEM; c.data = xmalloc_bytes(c.size); if (c.data == NULL) goto sethvmcontext_out; ret = -EFAULT; if (copy_from_guest(c.data, op->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; d = rcu_lock_domain_by_id(op->domain);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -