📄 platform_hypercall.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 + -