fw_emul.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 1,592 行 · 第 1/3 页

C
1,592
字号
void domain_set_time_offset(struct domain *d, int32_t time_offset_seconds){	d->time_offset_seconds = time_offset_seconds;}static efi_status_tefi_emulate_set_time(	unsigned long tv_addr, IA64FAULT *fault){	unsigned long tv;	struct page_info *tv_page = NULL;	efi_status_t status = 0;	if (current->domain != dom0)		return EFI_UNSUPPORTED;	tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);	if (*fault != IA64_NO_FAULT)		goto errout;	spin_lock(&efi_time_services_lock);	status = (*efi.set_time)((efi_time_t *)tv);	spin_unlock(&efi_time_services_lock);errout:	if (tv_page != NULL)		put_page(tv_page);	return status;}static efi_status_tefi_emulate_get_wakeup_time(	unsigned long e_addr, unsigned long p_addr,	unsigned long tv_addr, IA64FAULT *fault){	unsigned long enabled, pending, tv;	struct page_info *e_page = NULL, *p_page = NULL,	                 *tv_page = NULL;	efi_status_t status = 0;	if (current->domain != dom0)		return EFI_UNSUPPORTED;	if (!e_addr || !p_addr || !tv_addr)		return EFI_INVALID_PARAMETER;	enabled = efi_translate_domain_addr(e_addr, fault, &e_page);	if (*fault != IA64_NO_FAULT)		goto errout;	pending = efi_translate_domain_addr(p_addr, fault, &p_page);	if (*fault != IA64_NO_FAULT)		goto errout;	tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);	if (*fault != IA64_NO_FAULT)		goto errout;	spin_lock(&efi_time_services_lock);	status = (*efi.get_wakeup_time)((efi_bool_t *)enabled,	                                (efi_bool_t *)pending,	                                (efi_time_t *)tv);	spin_unlock(&efi_time_services_lock);errout:	if (e_page != NULL)		put_page(e_page);	if (p_page != NULL)		put_page(p_page);	if (tv_page != NULL)		put_page(tv_page);	return status;}static efi_status_tefi_emulate_set_wakeup_time(	unsigned long enabled, unsigned long tv_addr,	IA64FAULT *fault){	unsigned long tv = 0;	struct page_info *tv_page = NULL;	efi_status_t status = 0;	if (current->domain != dom0)		return EFI_UNSUPPORTED;	if (tv_addr) {		tv = efi_translate_domain_addr(tv_addr, fault, &tv_page);		if (*fault != IA64_NO_FAULT)			goto errout;	}	spin_lock(&efi_time_services_lock);	status = (*efi.set_wakeup_time)((efi_bool_t)enabled,	                                (efi_time_t *)tv);	spin_unlock(&efi_time_services_lock);errout:	if (tv_page != NULL)		put_page(tv_page);	return status;}static efi_status_tefi_emulate_get_variable(	unsigned long name_addr, unsigned long vendor_addr,	unsigned long attr_addr, unsigned long data_size_addr,	unsigned long data_addr, IA64FAULT *fault){	unsigned long name, vendor, attr = 0, data_size, data;	struct page_info *name_page = NULL, *vendor_page = NULL,	                 *attr_page = NULL, *data_size_page = NULL,	                 *data_page = NULL;	efi_status_t status = 0;	if (current->domain != dom0)		return EFI_UNSUPPORTED;	name = efi_translate_domain_addr(name_addr, fault, &name_page);	if (*fault != IA64_NO_FAULT)		goto errout;	vendor = efi_translate_domain_addr(vendor_addr, fault, &vendor_page);	if (*fault != IA64_NO_FAULT)		goto errout;	data_size = efi_translate_domain_addr(data_size_addr, fault,	                                      &data_size_page);	if (*fault != IA64_NO_FAULT)		goto errout;	data = efi_translate_domain_addr(data_addr, fault, &data_page);	if (*fault != IA64_NO_FAULT)		goto errout;	if (attr_addr) {		attr = efi_translate_domain_addr(attr_addr, fault, &attr_page);		if (*fault != IA64_NO_FAULT)			goto errout;	}	status = (*efi.get_variable)((efi_char16_t *)name,	                             (efi_guid_t *)vendor,	                             (u32 *)attr,	                             (unsigned long *)data_size,	                             (void *)data);errout:	if (name_page != NULL)		put_page(name_page);	if (vendor_page != NULL)		put_page(vendor_page);	if (attr_page != NULL)		put_page(attr_page);	if (data_size_page != NULL)		put_page(data_size_page);	if (data_page != NULL)		put_page(data_page);	return status;}static efi_status_tefi_emulate_get_next_variable(	unsigned long name_size_addr, unsigned long name_addr,	unsigned long vendor_addr, IA64FAULT *fault){	unsigned long name_size, name, vendor;	struct page_info *name_size_page = NULL, *name_page = NULL,	                 *vendor_page = NULL;	efi_status_t status = 0;	if (current->domain != dom0)		return EFI_UNSUPPORTED;	name_size = efi_translate_domain_addr(name_size_addr, fault,	                                      &name_size_page);	if (*fault != IA64_NO_FAULT)		goto errout;	name = efi_translate_domain_addr(name_addr, fault, &name_page);	if (*fault != IA64_NO_FAULT)		goto errout;	vendor = efi_translate_domain_addr(vendor_addr, fault, &vendor_page);	if (*fault != IA64_NO_FAULT)		goto errout;	status = (*efi.get_next_variable)((unsigned long *)name_size,	                                  (efi_char16_t *)name,	                                  (efi_guid_t *)vendor);errout:	if (name_size_page != NULL)		put_page(name_size_page);	if (name_page != NULL)		put_page(name_page);	if (vendor_page != NULL)		put_page(vendor_page);	return status;}static efi_status_tefi_emulate_set_variable(	unsigned long name_addr, unsigned long vendor_addr, 	unsigned long attr, unsigned long data_size, 	unsigned long data_addr, IA64FAULT *fault){	unsigned long name, vendor, data;	struct page_info *name_page = NULL, *vendor_page = NULL,	                 *data_page = NULL;	efi_status_t status = 0;	if (current->domain != dom0)		return EFI_UNSUPPORTED;	name = efi_translate_domain_addr(name_addr, fault, &name_page);	if (*fault != IA64_NO_FAULT)		goto errout;	vendor = efi_translate_domain_addr(vendor_addr, fault, &vendor_page);	if (*fault != IA64_NO_FAULT)		goto errout;	data = efi_translate_domain_addr(data_addr, fault, &data_page);	if (*fault != IA64_NO_FAULT)		goto errout;	status = (*efi.set_variable)((efi_char16_t *)name,	                             (efi_guid_t *)vendor,	                             attr,	                             data_size,	                             (void *)data);errout:	if (name_page != NULL)		put_page(name_page);	if (vendor_page != NULL)		put_page(vendor_page);	if (data_page != NULL)		put_page(data_page);	return status;}static efi_status_tefi_emulate_set_virtual_address_map(	unsigned long memory_map_size, unsigned long descriptor_size,	u32 descriptor_version, efi_memory_desc_t *virtual_map){	void *efi_map_start, *efi_map_end, *p;	efi_memory_desc_t entry, *md = &entry;	u64 efi_desc_size;	unsigned long *vfn;	struct domain *d = current->domain;	efi_runtime_services_t *efi_runtime = d->arch.efi_runtime;	fpswa_interface_t *fpswa_inf = d->arch.fpswa_inf;	if (descriptor_version != EFI_MEMDESC_VERSION) {		printk ("efi_emulate_set_virtual_address_map: memory "		        "descriptor version unmatched (%d vs %d)\n",		        (int)descriptor_version, EFI_MEMDESC_VERSION);		return EFI_INVALID_PARAMETER;	}	if (descriptor_size != sizeof(efi_memory_desc_t)) {		printk ("efi_emulate_set_virtual_address_map: memory descriptor size unmatched\n");		return EFI_INVALID_PARAMETER;	}	if (d->arch.sal_data->efi_virt_mode)		return EFI_UNSUPPORTED;	efi_map_start = virtual_map;	efi_map_end   = efi_map_start + memory_map_size;	efi_desc_size = sizeof(efi_memory_desc_t);	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {		if (copy_from_user(&entry, p, sizeof(efi_memory_desc_t))) {			printk ("efi_emulate_set_virtual_address_map: copy_from_user() fault. addr=0x%p\n", p);			return EFI_UNSUPPORTED;		}		/* skip over non-PAL_CODE memory descriptors; EFI_RUNTIME is included in PAL_CODE. */                if (md->type != EFI_PAL_CODE)                        continue;#define EFI_HYPERCALL_PATCH_TO_VIRT(tgt,call) \	do { \		vfn = (unsigned long *) domain_mpa_to_imva(d, tgt); \		*vfn++ = FW_HYPERCALL_##call##_INDEX * 16UL + md->virt_addr; \		*vfn++ = 0; \	} while (0)		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_time,EFI_GET_TIME);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_time,EFI_SET_TIME);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_wakeup_time,EFI_GET_WAKEUP_TIME);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_wakeup_time,EFI_SET_WAKEUP_TIME);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_virtual_address_map,EFI_SET_VIRTUAL_ADDRESS_MAP);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_variable,EFI_GET_VARIABLE);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_next_variable,EFI_GET_NEXT_VARIABLE);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->set_variable,EFI_SET_VARIABLE);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->get_next_high_mono_count,EFI_GET_NEXT_HIGH_MONO_COUNT);		EFI_HYPERCALL_PATCH_TO_VIRT(efi_runtime->reset_system,EFI_RESET_SYSTEM);		vfn = (unsigned long *) domain_mpa_to_imva(d, (unsigned long) fpswa_inf->fpswa);		*vfn++ = FW_HYPERCALL_FPSWA_PATCH_INDEX * 16UL + md->virt_addr;		*vfn   = 0;		fpswa_inf->fpswa = (void *) (FW_HYPERCALL_FPSWA_ENTRY_INDEX * 16UL + md->virt_addr);		break;	}	/* The virtual address map has been applied. */	d->arch.sal_data->efi_virt_mode = 1;	return EFI_SUCCESS;}efi_status_tefi_emulator (struct pt_regs *regs, IA64FAULT *fault){	struct vcpu *v = current;	efi_status_t status;	debugger_event(XEN_IA64_DEBUG_ON_EFI);	*fault = IA64_NO_FAULT;	switch (regs->r2) {	    case FW_HYPERCALL_EFI_RESET_SYSTEM:	        {		    u8 reason;		    unsigned long val = vcpu_get_gr(v,32);		    switch (val)		    {		    case EFI_RESET_SHUTDOWN:			    reason = SHUTDOWN_poweroff;			    break;		    case EFI_RESET_COLD:		    case EFI_RESET_WARM:		    default:			    reason = SHUTDOWN_reboot;			    break;		    }		    domain_shutdown (current->domain, reason);		}		status = EFI_UNSUPPORTED;		break;	    case FW_HYPERCALL_EFI_GET_TIME:		status = efi_emulate_get_time (				vcpu_get_gr(v,32),				vcpu_get_gr(v,33),				fault);		break;	    case FW_HYPERCALL_EFI_SET_TIME:		status = efi_emulate_set_time (				vcpu_get_gr(v,32),				fault);		break;	    case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:		status = efi_emulate_get_wakeup_time (				vcpu_get_gr(v,32),				vcpu_get_gr(v,33),				vcpu_get_gr(v,34),				fault);		break;	    case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:		status = efi_emulate_set_wakeup_time (				vcpu_get_gr(v,32),				vcpu_get_gr(v,33),				fault);		break;	    case FW_HYPERCALL_EFI_GET_VARIABLE:		status = efi_emulate_get_variable (				vcpu_get_gr(v,32),				vcpu_get_gr(v,33),				vcpu_get_gr(v,34),				vcpu_get_gr(v,35),				vcpu_get_gr(v,36),				fault);		break;	    case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:		status = efi_emulate_get_next_variable (				vcpu_get_gr(v,32),				vcpu_get_gr(v,33),				vcpu_get_gr(v,34),				fault);		break;	    case FW_HYPERCALL_EFI_SET_VARIABLE:		status = efi_emulate_set_variable (				vcpu_get_gr(v,32),				vcpu_get_gr(v,33),				vcpu_get_gr(v,34),				vcpu_get_gr(v,35),				vcpu_get_gr(v,36),				fault);		break;	    case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:		status = efi_emulate_set_virtual_address_map (				vcpu_get_gr(v,32),				vcpu_get_gr(v,33), 				(u32) vcpu_get_gr(v,34),				(efi_memory_desc_t *) vcpu_get_gr(v,35));		break;	    case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:		// FIXME: need fixes in efi.h from 2.6.9		status = EFI_UNSUPPORTED;		break;	    default:		printk("unknown ia64 fw hypercall %lx\n", regs->r2);		status = EFI_UNSUPPORTED;	}	return status;}voiddo_ssc(unsigned long ssc, struct pt_regs *regs){	unsigned long arg0, arg1, arg2, arg3, retval;	char buf[2];/**/	static int last_fd, last_count;	// FIXME FIXME FIXME/**/					// BROKEN FOR MULTIPLE DOMAINS & SMP/**/	struct ssc_disk_stat { int fd; unsigned count;} *stat, last_stat;	arg0 = vcpu_get_gr(current,32);	switch(ssc) {	    case SSC_PUTCHAR:		buf[0] = arg0;		buf[1] = '\0';		printk(buf);		break;	    case SSC_GETCHAR:		retval = ia64_ssc(0,0,0,0,ssc);		vcpu_set_gr(current,8,retval,0);		break;	    case SSC_WAIT_COMPLETION:		if (arg0) {	// metaphysical address			arg0 = translate_domain_mpaddr(arg0, NULL);/**/			stat = (struct ssc_disk_stat *)__va(arg0);///**/			if (stat->fd == last_fd) stat->count = last_count;/**/			stat->count = last_count;//if (last_count >= PAGE_SIZE) printk("ssc_wait: stat->fd=%d,last_fd=%d,last_count=%d\n",stat->fd,last_fd,last_count);///**/			retval = ia64_ssc(arg0,0,0,0,ssc);/**/			retval = 0;		}		else retval = -1L;		vcpu_set_gr(current,8,retval,0);		break;	    case SSC_OPEN:		arg1 = vcpu_get_gr(current,33);	// access rights		if (!running_on_sim) { 		    printk("SSC_OPEN, not implemented on hardware.  (ignoring...)\n"); 		    arg0 = 0; 		}		if (arg0) {	// metaphysical address			arg0 = translate_domain_mpaddr(arg0, NULL);			retval = ia64_ssc(arg0,arg1,0,0,ssc);		}		else retval = -1L;		vcpu_set_gr(current,8,retval,0);		break;	    case SSC_WRITE:	    case SSC_READ://if (ssc == SSC_WRITE) printk("DOING AN SSC_WRITE\n");		arg1 = vcpu_get_gr(current,33);		arg2 = vcpu_get_gr(current,34);		arg3 = vcpu_get_gr(current,35);		if (arg2) {	// metaphysical address of descriptor			struct ssc_disk_req *req;			unsigned long mpaddr;			long len;			arg2 = translate_domain_mpaddr(arg2, NULL);			req = (struct ssc_disk_req *) __va(arg2);			req->len &= 0xffffffffL;	// avoid strange bug			len = req->len;/**/			last_fd = arg1;/**/			last_count = len;			mpaddr = req->addr;//if (last_count >= PAGE_SIZE) printk("do_ssc: read fd=%d, addr=%p, len=%lx ",last_fd,mpaddr,len);			retval = 0;			if ((mpaddr & PAGE_MASK) != ((mpaddr+len-1) & PAGE_MASK)) {				// do partial page first				req->addr = translate_domain_mpaddr(mpaddr, NULL);				req->len = PAGE_SIZE - (req->addr & ~PAGE_MASK);				len -= req->len; mpaddr += req->len;				retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);				arg3 += req->len; // file offset/**/				last_stat.fd = last_fd;/**/				(void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);//if (last_count >= PAGE_SIZE) printk("ssc(%p,%lx)[part]=%x ",req->addr,req->len,retval);			}			if (retval >= 0) while (len > 0) {				req->addr = translate_domain_mpaddr(mpaddr, NULL);				req->len = (len > PAGE_SIZE) ? PAGE_SIZE : len;				len -= PAGE_SIZE; mpaddr += PAGE_SIZE;				retval = ia64_ssc(arg0,arg1,arg2,arg3,ssc);				arg3 += req->len; // file offset// TEMP REMOVED AGAIN				arg3 += req->len; // file offset/**/				last_stat.fd = last_fd;/**/				(void)ia64_ssc(__pa(&last_stat),0,0,0,SSC_WAIT_COMPLETION);//if (last_count >= PAGE_SIZE) printk("ssc(%p,%lx)=%x ",req->addr,req->len,retval);			}			// set it back to the original value			req->len = last_count;		}		else retval = -1L;		vcpu_set_gr(current,8,retval,0);//if (last_count >= PAGE_SIZE) printk("retval=%x\n",retval);		break;	    case SSC_CONNECT_INTERRUPT:		arg1 = vcpu_get_gr(current,33);		arg2 = vcpu_get_gr(current,34);		arg3 = vcpu_get_gr(current,35);		if (!running_on_sim) { 		    printk("SSC_CONNECT_INTERRUPT, not implemented on hardware.  (ignoring...)\n"); 		    break; 		}		(void)ia64_ssc(arg0,arg1,arg2,arg3,ssc);		break;	    case SSC_NETDEV_PROBE:		vcpu_set_gr(current,8,-1L,0);		break;	    default:		panic_domain(regs,		             "%s: bad ssc code %lx, iip=0x%lx, b0=0x%lx\n",		             __func__, ssc, regs->cr_iip, regs->b0);		break;	}	vcpu_increment_iip(current);}

⌨️ 快捷键说明

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