⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 platform_hypercall.c

📁 xen虚拟机源代码安装包
💻 C
字号:
/****************************************************************************** * platform_hypercall.c *  * Hardware platform operations. Intended for use by domain-0 kernel. *  * Copyright (c) 2002-2006, K Fraser */#include <xen/config.h>#include <xen/types.h>#include <xen/lib.h>#include <xen/mm.h>#include <xen/sched.h>#include <xen/domain.h>#include <xen/event.h>#include <xen/domain_page.h>#include <xen/trace.h>#include <xen/console.h>#include <xen/iocap.h>#include <xen/guest_access.h>#include <xen/acpi.h>#include <asm/current.h>#include <public/platform.h>#include <acpi/cpufreq/processor_perf.h>#include <asm/edd.h>#include <asm/mtrr.h>#include "cpu/mtrr/mtrr.h"#include <xsm/xsm.h>extern uint16_t boot_edid_caps;extern uint8_t boot_edid_info[];#ifndef COMPATtypedef long ret_t;DEFINE_SPINLOCK(xenpf_lock);# undef copy_from_compat# define copy_from_compat copy_from_guest# undef copy_to_compat# define copy_to_compat copy_to_guest# undef guest_from_compat_handle# define guest_from_compat_handle(x,y) ((x)=(y))#elseextern spinlock_t xenpf_lock;#endifstatic DEFINE_PER_CPU(uint64_t, freq);extern long set_cx_pminfo(uint32_t cpu, struct xen_processor_power *power);static long cpu_frequency_change_helper(void *data){    return cpu_frequency_change(this_cpu(freq));}ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op){    ret_t ret = 0;    struct xen_platform_op curop, *op = &curop;    if ( !IS_PRIV(current->domain) )        return -EPERM;    if ( copy_from_guest(op, u_xenpf_op, 1) )        return -EFAULT;    if ( op->interface_version != XENPF_INTERFACE_VERSION )        return -EACCES;    spin_lock(&xenpf_lock);    switch ( op->cmd )    {    case XENPF_settime:    {        ret = xsm_xen_settime();        if ( ret )            break;        do_settime(op->u.settime.secs,                    op->u.settime.nsecs,                    op->u.settime.system_time);        ret = 0;    }    break;    case XENPF_add_memtype:    {        ret = xsm_memtype(op->cmd);        if ( ret )            break;        ret = mtrr_add_page(            op->u.add_memtype.mfn,            op->u.add_memtype.nr_mfns,            op->u.add_memtype.type,            1);        if ( ret >= 0 )        {            op->u.add_memtype.handle = 0;            op->u.add_memtype.reg    = ret;            ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;            if ( ret != 0 )                mtrr_del_page(ret, 0, 0);        }    }    break;    case XENPF_del_memtype:    {        ret = xsm_memtype(op->cmd);        if ( ret )            break;        if (op->u.del_memtype.handle == 0            /* mtrr/main.c otherwise does a lookup */            && (int)op->u.del_memtype.reg >= 0)        {            ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);            if ( ret > 0 )                ret = 0;        }        else            ret = -EINVAL;    }    break;    case XENPF_read_memtype:    {        unsigned long mfn, nr_mfns;        mtrr_type     type;        ret = xsm_memtype(op->cmd);        if ( ret )            break;        ret = -EINVAL;        if ( op->u.read_memtype.reg < num_var_ranges )        {            mtrr_if->get(op->u.read_memtype.reg, &mfn, &nr_mfns, &type);            op->u.read_memtype.mfn     = mfn;            op->u.read_memtype.nr_mfns = nr_mfns;            op->u.read_memtype.type    = type;            ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;        }    }    break;    case XENPF_microcode_update:    {        extern int microcode_update(XEN_GUEST_HANDLE(void), unsigned long len);        XEN_GUEST_HANDLE(void) data;        ret = xsm_microcode();        if ( ret )            break;        guest_from_compat_handle(data, op->u.microcode.data);        ret = microcode_update(data, op->u.microcode.length);    }    break;    case XENPF_platform_quirk:    {        extern int opt_noirqbalance;        int quirk_id = op->u.platform_quirk.quirk_id;        ret = xsm_platform_quirk(quirk_id);        if ( ret )            break;        switch ( quirk_id )        {        case QUIRK_NOIRQBALANCING:            printk("Platform quirk -- Disabling IRQ balancing/affinity.\n");            opt_noirqbalance = 1;            setup_ioapic_dest();            break;        case QUIRK_IOAPIC_BAD_REGSEL:        case QUIRK_IOAPIC_GOOD_REGSEL:#ifndef sis_apic_bug            sis_apic_bug = (quirk_id == QUIRK_IOAPIC_BAD_REGSEL);            dprintk(XENLOG_INFO, "Domain 0 says that IO-APIC REGSEL is %s\n",                    sis_apic_bug ? "bad" : "good");#else            BUG_ON(sis_apic_bug != (quirk_id == QUIRK_IOAPIC_BAD_REGSEL));#endif            break;        default:            ret = -EINVAL;            break;        }    }    break;    case XENPF_firmware_info:        switch ( op->u.firmware_info.type )        {        case XEN_FW_DISK_INFO: {            const struct edd_info *info;            u16 length;            ret = -ESRCH;            if ( op->u.firmware_info.index >= bootsym(boot_edd_info_nr) )                break;            info = bootsym(boot_edd_info) + op->u.firmware_info.index;            /* Transfer the EDD info block. */            ret = -EFAULT;            if ( copy_from_compat(&length, op->u.firmware_info.u.                                  disk_info.edd_params, 1) )                break;            if ( length > info->edd_device_params.length )                length = info->edd_device_params.length;            if ( copy_to_compat(op->u.firmware_info.u.disk_info.edd_params,                                (u8 *)&info->edd_device_params,                                length) )                break;            if ( copy_to_compat(op->u.firmware_info.u.disk_info.edd_params,                                &length, 1) )                break;            /* Transfer miscellaneous other information values. */#define C(x) op->u.firmware_info.u.disk_info.x = info->x            C(device);            C(version);            C(interface_support);            C(legacy_max_cylinder);            C(legacy_max_head);            C(legacy_sectors_per_track);#undef C            ret = (copy_field_to_guest(u_xenpf_op, op,                                      u.firmware_info.u.disk_info)                   ? -EFAULT : 0);            break;        }        case XEN_FW_DISK_MBR_SIGNATURE: {            const struct mbr_signature *sig;            ret = -ESRCH;            if ( op->u.firmware_info.index >= bootsym(boot_mbr_signature_nr) )                break;            sig = bootsym(boot_mbr_signature) + op->u.firmware_info.index;            op->u.firmware_info.u.disk_mbr_signature.device = sig->device;            op->u.firmware_info.u.disk_mbr_signature.mbr_signature =                sig->signature;            ret = (copy_field_to_guest(u_xenpf_op, op,                                      u.firmware_info.u.disk_mbr_signature)                   ? -EFAULT : 0);            break;        }        case XEN_FW_VBEDDC_INFO:            ret = -ESRCH;            if ( op->u.firmware_info.index != 0 )                break;            if ( *(u32 *)bootsym(boot_edid_info) == 0x13131313 )                break;            op->u.firmware_info.u.vbeddc_info.capabilities =                bootsym(boot_edid_caps);            op->u.firmware_info.u.vbeddc_info.edid_transfer_time =                bootsym(boot_edid_caps) >> 8;            ret = 0;            if ( copy_field_to_guest(u_xenpf_op, op, u.firmware_info.                                     u.vbeddc_info.capabilities) ||                 copy_field_to_guest(u_xenpf_op, op, u.firmware_info.                                     u.vbeddc_info.edid_transfer_time) ||                 copy_to_compat(op->u.firmware_info.u.vbeddc_info.edid,                                bootsym(boot_edid_info), 128) )                ret = -EFAULT;            break;        default:            ret = -EINVAL;            break;        }        break;    case XENPF_enter_acpi_sleep:        ret = acpi_enter_sleep(&op->u.enter_acpi_sleep);        break;    case XENPF_change_freq:        ret = -ENOSYS;        if ( cpufreq_controller != FREQCTL_dom0_kernel )            break;        ret = -EINVAL;        if ( op->u.change_freq.flags || !cpu_online(op->u.change_freq.cpu) )            break;        per_cpu(freq, op->u.change_freq.cpu) = op->u.change_freq.freq;        ret = continue_hypercall_on_cpu(op->u.change_freq.cpu,                                        cpu_frequency_change_helper,                                        NULL);        break;    case XENPF_getidletime:    {        uint32_t cpu;        uint64_t idletime, now = NOW();        struct vcpu *v;        struct xenctl_cpumap ctlmap;        cpumask_t cpumap;        XEN_GUEST_HANDLE(uint8) cpumap_bitmap;        XEN_GUEST_HANDLE(uint64) idletimes;        ret = -ENOSYS;        if ( cpufreq_controller != FREQCTL_dom0_kernel )            break;        ctlmap.nr_cpus  = op->u.getidletime.cpumap_nr_cpus;        guest_from_compat_handle(cpumap_bitmap,                                 op->u.getidletime.cpumap_bitmap);        ctlmap.bitmap.p = cpumap_bitmap.p; /* handle -> handle_64 conversion */        xenctl_cpumap_to_cpumask(&cpumap, &ctlmap);        guest_from_compat_handle(idletimes, op->u.getidletime.idletime);        for_each_cpu_mask ( cpu, cpumap )        {            if ( (v = idle_vcpu[cpu]) != NULL )            {                idletime = v->runstate.time[RUNSTATE_running];                if ( v->is_running )                    idletime += now - v->runstate.state_entry_time;            }            else            {                idletime = 0;                cpu_clear(cpu, cpumap);            }            ret = -EFAULT;            if ( copy_to_guest_offset(idletimes, cpu, &idletime, 1) )                goto out;        }        op->u.getidletime.now = now;        cpumask_to_xenctl_cpumap(&ctlmap, &cpumap);        ret = copy_to_guest(u_xenpf_op, op, 1) ? -EFAULT : 0;    }    break;    case XENPF_set_processor_pminfo:        switch ( op->u.set_pminfo.type )        {        case XEN_PM_PX:        {            static int cpu_count = 0;            struct xenpf_set_processor_pminfo *xenpmpt = &op->u.set_pminfo;            struct xen_processor_performance *xenpxpt = &op->u.set_pminfo.perf;            int cpuid = get_cpu_id(xenpmpt->id);            struct processor_pminfo *pmpt;            struct processor_performance *pxpt;            if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )            {                ret = -ENOSYS;                break;            }            if ( cpuid < 0 )            {                ret = -EINVAL;                break;            }            pmpt = &processor_pminfo[cpuid];            pxpt = &processor_pminfo[cpuid].perf;            pmpt->acpi_id = xenpmpt->id;            pmpt->id = cpuid;            if ( xenpxpt->flags & XEN_PX_PCT )            {                memcpy ((void *)&pxpt->control_register,                    (void *)&xenpxpt->control_register,                    sizeof(struct xen_pct_register));                memcpy ((void *)&pxpt->status_register,                    (void *)&xenpxpt->status_register,                    sizeof(struct xen_pct_register));                pxpt->init |= XEN_PX_PCT;            }            if ( xenpxpt->flags & XEN_PX_PSS )             {                if ( !(pxpt->states = xmalloc_array(struct xen_processor_px,                    xenpxpt->state_count)) )                {                    ret = -ENOMEM;                    break;                }                if ( copy_from_compat(pxpt->states, xenpxpt->states,                     xenpxpt->state_count) )                {                    xfree(pxpt->states);                    ret = -EFAULT;                    break;                }                pxpt->state_count = xenpxpt->state_count;                pxpt->init |= XEN_PX_PSS;            }            if ( xenpxpt->flags & XEN_PX_PSD )            {                pxpt->shared_type = xenpxpt->shared_type;                memcpy ((void *)&pxpt->domain_info,                    (void *)&xenpxpt->domain_info,                    sizeof(struct xen_psd_package));                pxpt->init |= XEN_PX_PSD;            }            if ( xenpxpt->flags & XEN_PX_PPC )            {                pxpt->ppc = xenpxpt->ppc;                pxpt->init |= XEN_PX_PPC;            }            if ( pxpt->init == ( XEN_PX_PCT | XEN_PX_PSS |                                 XEN_PX_PSD | XEN_PX_PPC ) )            {                pxpt->init |= XEN_PX_INIT;                cpu_count++;            }            if ( cpu_count == num_online_cpus() )            {                if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )                    ret = powernow_cpufreq_init();                else                    ret = acpi_cpufreq_init();            }            break;        }         case XEN_PM_CX:            if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_CX) )            {                ret = -ENOSYS;                break;            }            ret = set_cx_pminfo(op->u.set_pminfo.id, &op->u.set_pminfo.power);            break;        case XEN_PM_TX:            if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_TX) )            {                ret = -ENOSYS;                break;            }            ret = -EINVAL;            break;        default:            ret = -EINVAL;            break;        }        break;     default:        ret = -ENOSYS;        break;    } out:    spin_unlock(&xenpf_lock);    return ret;}/* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -