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 + -
显示快捷键?