📄 fw_emul.c
字号:
/* * fw_emul.c: * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * */#include <xen/config.h>#include <asm/system.h>#include <asm/pgalloc.h>#include <linux/efi.h>#include <asm/pal.h>#include <asm/sal.h>#include <asm/sn/sn_sal.h>#include <asm/sn/hubdev.h>#include <asm/xenmca.h>#include <public/sched.h>#include "hpsim_ssc.h"#include <asm/vcpu.h>#include <asm/vmx_vcpu.h>#include <asm/dom_fw.h>#include <asm/uaccess.h>#include <xen/console.h>#include <xen/hypercall.h>#include <xen/softirq.h>#include <xen/time.h>#include <asm/debugger.h>#include <asm/vmx_phy_mode.h>static DEFINE_SPINLOCK(efi_time_services_lock);struct sal_mc_params { u64 param_type; u64 i_or_m; u64 i_or_m_val; u64 timeout; u64 rz_always;} sal_mc_params[SAL_MC_PARAM_CPE_INT + 1];struct sal_vectors { u64 vector_type; u64 handler_addr1; u64 gp1; u64 handler_len1; u64 handler_addr2; u64 gp2; u64 handler_len2;} sal_vectors[SAL_VECTOR_OS_BOOT_RENDEZ + 1];struct smp_call_args_t { u64 type; u64 ret; u64 target; struct domain *domain; int corrected; int status; void *data;}; extern sal_log_record_header_t *sal_record;DEFINE_SPINLOCK(sal_record_lock);extern spinlock_t sal_queue_lock;#define IA64_SAL_NO_INFORMATION_AVAILABLE -5#if defined(IA64_SAL_DEBUG_INFO)static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" };# define IA64_SAL_DEBUG(fmt...) printk("sal_emulator: " fmt)#else# define IA64_SAL_DEBUG(fmt...)#endifvoid get_state_info_on(void *data) { struct smp_call_args_t *arg = data; int flags; spin_lock_irqsave(&sal_record_lock, flags); memset(sal_record, 0, ia64_sal_get_state_info_size(arg->type)); arg->ret = ia64_sal_get_state_info(arg->type, (u64 *)sal_record); IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) on CPU#%d returns %ld.\n", rec_name[arg->type], smp_processor_id(), arg->ret); if (arg->corrected) { sal_record->severity = sal_log_severity_corrected; IA64_SAL_DEBUG("%s: IA64_SAL_CLEAR_STATE_INFO(SAL_INFO_TYPE_MCA)" " force\n", __FUNCTION__); } if (arg->ret > 0) { /* * Save current->domain and set to local(caller) domain for * xencomm_paddr_to_maddr() which calculates maddr from * paddr using mpa value of current->domain. */ struct domain *save; save = current->domain; current->domain = arg->domain; if (xencomm_copy_to_guest((void*)arg->target, sal_record, arg->ret, 0)) { printk("SAL_GET_STATE_INFO can't copy to user!!!!\n"); arg->status = IA64_SAL_NO_INFORMATION_AVAILABLE; arg->ret = 0; } /* Restore current->domain to saved value. */ current->domain = save; } spin_unlock_irqrestore(&sal_record_lock, flags);}void clear_state_info_on(void *data) { struct smp_call_args_t *arg = data; arg->ret = ia64_sal_clear_state_info(arg->type); IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) on CPU#%d returns %ld.\n", rec_name[arg->type], smp_processor_id(), arg->ret);} struct sal_ret_valuessal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7){ struct ia64_sal_retval ret_stuff; unsigned long r9 = 0; unsigned long r10 = 0; long r11 = 0; long status; debugger_event(XEN_IA64_DEBUG_ON_SAL); status = 0; switch (index) { case SAL_FREQ_BASE: if (likely(!running_on_sim)) status = ia64_sal_freq_base(in1,&r9,&r10); else switch (in1) { case SAL_FREQ_BASE_PLATFORM: r9 = 200000000; break; case SAL_FREQ_BASE_INTERVAL_TIMER: r9 = 700000000; break; case SAL_FREQ_BASE_REALTIME_CLOCK: r9 = 1; break; default: status = -1; break; } break; case SAL_PCI_CONFIG_READ: if (current->domain == dom0) { u64 value; // note that args 2&3 are swapped!! status = ia64_sal_pci_config_read(in1,in3,in2,&value); r9 = value; } else printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_READ\n"); break; case SAL_PCI_CONFIG_WRITE: if (current->domain == dom0) { if (((in1 & ~0xffffffffUL) && (in4 == 0)) || (in4 > 1) || (in2 > 8) || (in2 & (in2-1))) printk("*** SAL_PCI_CONF_WRITE?!?(adr=0x%lx,typ=0x%lx,sz=0x%lx,val=0x%lx)\n", in1,in4,in2,in3); // note that args are in a different order!! status = ia64_sal_pci_config_write(in1,in4,in2,in3); } else printk("NON-PRIV DOMAIN CALLED SAL_PCI_CONFIG_WRITE\n"); break; case SAL_SET_VECTORS: if (in1 == SAL_VECTOR_OS_BOOT_RENDEZ) { if (in4 != 0 || in5 != 0 || in6 != 0 || in7 != 0) { /* Sanity check: cs_length1 must be 0, second vector is reserved. */ status = -2; } else { struct domain *d = current->domain; d->arch.sal_data->boot_rdv_ip = in2; d->arch.sal_data->boot_rdv_r1 = in3; } } else if (current->domain == dom0) { if (in1 > sizeof(sal_vectors)/sizeof(sal_vectors[0])-1) { gdprintk(XENLOG_DEBUG, "SAL_SET_VECTORS invalid in1 %ld\n", in1); status = -2; break; } sal_vectors[in1].vector_type = in1; sal_vectors[in1].handler_addr1 = in2; sal_vectors[in1].gp1 = in3; sal_vectors[in1].handler_len1 = in4; sal_vectors[in1].handler_addr2 = in5; sal_vectors[in1].gp2 = in6; sal_vectors[in1].handler_len2 = in7; } else { gdprintk(XENLOG_DEBUG, "NON-PRIV DOMAIN CALLED " "SAL_SET_VECTORS %ld\n", in1); /* * status = -2; * Temporal work around untill gfw support: * windows 2003 sp2/sp1 dislike -2 to crash. */ status = 0; } break; case SAL_GET_STATE_INFO: if (current->domain == dom0) { sal_queue_entry_t *e; unsigned long flags; struct smp_call_args_t arg; spin_lock_irqsave(&sal_queue_lock, flags); if (!sal_queue || list_empty(&sal_queue[in1])) { sal_log_record_header_t header; XEN_GUEST_HANDLE(void) handle = *(XEN_GUEST_HANDLE(void)*)&in3; IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) " "no sal_queue entry found.\n", rec_name[in1]); memset(&header, 0, sizeof(header)); if (copy_to_guest(handle, &header, 1)) { printk("sal_emulator: " "SAL_GET_STATE_INFO can't copy " "empty header to user: 0x%lx\n", in3); } status = IA64_SAL_NO_INFORMATION_AVAILABLE; r9 = 0; spin_unlock_irqrestore(&sal_queue_lock, flags); break; } e = list_entry(sal_queue[in1].next, sal_queue_entry_t, list); list_del(&e->list); spin_unlock_irqrestore(&sal_queue_lock, flags); IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s <= %s) " "on CPU#%d.\n", rec_name[e->sal_info_type], rec_name[in1], e->cpuid); arg.type = e->sal_info_type; arg.target = in3; arg.corrected = !!((in1 != e->sal_info_type) && (e->sal_info_type == SAL_INFO_TYPE_MCA)); arg.domain = current->domain; arg.status = 0; if (e->cpuid == smp_processor_id()) { IA64_SAL_DEBUG("SAL_GET_STATE_INFO: local\n"); get_state_info_on(&arg); } else { int ret; IA64_SAL_DEBUG("SAL_GET_STATE_INFO: remote\n"); ret = smp_call_function_single(e->cpuid, get_state_info_on, &arg, 0, 1); if (ret < 0) { printk("SAL_GET_STATE_INFO " "smp_call_function_single error:" " %d\n", ret); arg.ret = 0; arg.status = IA64_SAL_NO_INFORMATION_AVAILABLE; } } r9 = arg.ret; status = arg.status; if (r9 == 0) { xfree(e); } else { /* Re-add the entry to sal_queue */ spin_lock_irqsave(&sal_queue_lock, flags); list_add(&e->list, &sal_queue[in1]); spin_unlock_irqrestore(&sal_queue_lock, flags); } } else { status = IA64_SAL_NO_INFORMATION_AVAILABLE; r9 = 0; } break; case SAL_GET_STATE_INFO_SIZE: r9 = ia64_sal_get_state_info_size(in1); break; case SAL_CLEAR_STATE_INFO: if (current->domain == dom0) { sal_queue_entry_t *e; unsigned long flags; struct smp_call_args_t arg; spin_lock_irqsave(&sal_queue_lock, flags); if (list_empty(&sal_queue[in1])) { IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) " "no sal_queue entry found.\n", rec_name[in1]); status = IA64_SAL_NO_INFORMATION_AVAILABLE; r9 = 0; spin_unlock_irqrestore(&sal_queue_lock, flags); break; } e = list_entry(sal_queue[in1].next, sal_queue_entry_t, list); list_del(&e->list); spin_unlock_irqrestore(&sal_queue_lock, flags); IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s <= %s) " "on CPU#%d.\n", rec_name[e->sal_info_type], rec_name[in1], e->cpuid); arg.type = e->sal_info_type; arg.status = 0; if (e->cpuid == smp_processor_id()) { IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO: local\n"); clear_state_info_on(&arg); } else { int ret; IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO: remote\n"); ret = smp_call_function_single(e->cpuid, clear_state_info_on, &arg, 0, 1); if (ret < 0) { printk("sal_emulator: " "SAL_CLEAR_STATE_INFO " "smp_call_function_single error:" " %d\n", ret); arg.ret = 0; arg.status = IA64_SAL_NO_INFORMATION_AVAILABLE; } } r9 = arg.ret; status = arg.status; xfree(e); } break; case SAL_MC_RENDEZ: printk("*** CALLED SAL_MC_RENDEZ. IGNORED...\n"); break; case SAL_MC_SET_PARAMS: if (current->domain == dom0) { if (in1 > sizeof(sal_mc_params) / sizeof(sal_mc_params[0])) { gdprintk(XENLOG_DEBUG, "SAL_MC_SET_PARAMS invalid in1 %ld\n", in1); status = -2; break; } sal_mc_params[in1].param_type = in1; sal_mc_params[in1].i_or_m = in2; sal_mc_params[in1].i_or_m_val = in3; sal_mc_params[in1].timeout = in4; sal_mc_params[in1].rz_always = in5; } else { gdprintk(XENLOG_DEBUG, "*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n"); /* * status = -1; * Temporal work around untill gfw support: * windows 2003 sp2/sp1 dislike -1(not implemented) * to crash. */ status = 0; } break; case SAL_CACHE_FLUSH: if (1) { /* Flush using SAL. This method is faster but has a side effect on other vcpu running on this cpu. */ status = ia64_sal_cache_flush (in1); } else { /* Flush with fc all the domain. This method is slower but has no side effects. */ domain_cache_flush (current->domain, in1 == 4 ? 1 : 0); status = 0; } break; case SAL_CACHE_INIT: printk("*** CALLED SAL_CACHE_INIT. IGNORED...\n"); break; case SAL_UPDATE_PAL: printk("*** CALLED SAL_UPDATE_PAL. IGNORED...\n"); break; case SAL_PHYSICAL_ID_INFO: status = -1; break; case SAL_XEN_SAL_RETURN: if (!test_and_set_bit(_VPF_down, ¤t->pause_flags)) vcpu_sleep_nosync(current); break; case SN_SAL_GET_MASTER_NASID: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_GET_MASTER_NASID ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_MASTER_NASID, 0, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_GET_KLCONFIG_ADDR: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_GET_KLCONFIG_ADDR ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_KLCONFIG_ADDR, in1, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_GET_SAPIC_INFO: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_GET_SAPIC_INFO ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SAPIC_INFO, in1, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_GET_SN_INFO: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_GET_SN_INFO ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_SN_INFO, in1, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_IOIF_GET_HUBDEV_INFO: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_IOIF_GET_HUBDEV_INFO ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_IOIF_GET_HUBDEV_INFO, in1, in2, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_IOIF_INIT: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_IOIF_INIT ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_IOIF_INIT, 0, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_GET_PROM_FEATURE_SET: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_GET_PROM_FEATURE_SET ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_GET_PROM_FEATURE_SET, in1, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_SET_OS_FEATURE_SET: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_SET_OS_FEATURE_SET ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SET_OS_FEATURE_SET, in1, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break; case SN_SAL_SET_ERROR_HANDLING_FEATURES: status = -1; if (current->domain == dom0) { /* printk("*** Emulating SN_SAL_SET_ERROR_HANDLING_FEATURES ***\n"); */ SAL_CALL_NOLOCK(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES, in1, 0, 0, 0, 0, 0, 0); status = ret_stuff.status; r9 = ret_stuff.v0; r10 = ret_stuff.v1; r11 = ret_stuff.v2; } break;#if 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -