/* Full PV mode suspension. */ static void xctrl_suspend() { int i, j, k, fpp, suspend_cancelled; unsigned long max_pfn, start_info_mfn; EVENTHANDLER_INVOKE(power_suspend); #ifdef SMP struct thread *td; cpuset_t map; u_int cpuid; /* * Bind us to CPU 0 and stop any other VCPUs. */ td = curthread; thread_lock(td); sched_bind(td, 0); thread_unlock(td); cpuid = PCPU_GET(cpuid); KASSERT(cpuid == 0, ("xen_suspend: not running on cpu 0")); map = all_cpus; CPU_CLR(cpuid, &map); CPU_NAND(&map, &stopped_cpus); if (!CPU_EMPTY(&map)) stop_cpus(map); #endif /* * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE * drivers need this. */ mtx_lock(&Giant); if (DEVICE_SUSPEND(root_bus) != 0) { mtx_unlock(&Giant); printf("%s: device_suspend failed\n", __func__); #ifdef SMP if (!CPU_EMPTY(&map)) restart_cpus(map); #endif return; } mtx_unlock(&Giant); local_irq_disable(); xencons_suspend(); gnttab_suspend(); intr_suspend(); max_pfn = HYPERVISOR_shared_info->arch.max_pfn; void *shared_info = HYPERVISOR_shared_info; HYPERVISOR_shared_info = NULL; pmap_kremove((vm_offset_t) shared_info); PT_UPDATES_FLUSH(); xen_start_info->store_mfn = MFNTOPFN(xen_start_info->store_mfn); xen_start_info->console.domU.mfn = MFNTOPFN(xen_start_info->console.domU.mfn); /* * We'll stop somewhere inside this hypercall. When it returns, * we'll start resuming after the restore. */ start_info_mfn = VTOMFN(xen_start_info); pmap_suspend(); suspend_cancelled = HYPERVISOR_suspend(start_info_mfn); pmap_resume(); pmap_kenter_ma((vm_offset_t) shared_info, xen_start_info->shared_info); HYPERVISOR_shared_info = shared_info; HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = VTOMFN(xen_pfn_to_mfn_frame_list_list); fpp = PAGE_SIZE/sizeof(unsigned long); for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) { if ((j % fpp) == 0) { k++; xen_pfn_to_mfn_frame_list_list[k] = VTOMFN(xen_pfn_to_mfn_frame_list[k]); j = 0; } xen_pfn_to_mfn_frame_list[k][j] = VTOMFN(&xen_phys_machine[i]); } HYPERVISOR_shared_info->arch.max_pfn = max_pfn; gnttab_resume(); intr_resume(suspend_cancelled != 0); local_irq_enable(); xencons_resume(); #ifdef CONFIG_SMP for_each_cpu(i) vcpu_prepare(i); #endif /* * Only resume xenbus /after/ we've prepared our VCPUs; otherwise * the VCPU hotplug callback can race with our vcpu_prepare */ mtx_lock(&Giant); DEVICE_RESUME(root_bus); mtx_unlock(&Giant); #ifdef SMP thread_lock(curthread); sched_unbind(curthread); thread_unlock(curthread); if (!CPU_EMPTY(&map)) restart_cpus(map); #endif EVENTHANDLER_INVOKE(power_resume); }
/* * Initialize the BIOS32 interface. */ void bios32_init(void) { #if 0 /* XXXfvdl need to set up compatibility segment for this */ paddr_t entry = 0; void *p; unsigned char cksum; int i; for (p = (void *)ISA_HOLE_VADDR(BIOS32_START); p < (void *)ISA_HOLE_VADDR(BIOS32_END); p += 16) { if (*(int *)p != BIOS32_MAKESIG('_', '3', '2', '_')) continue; cksum = 0; for (i = 0; i < 16; i++) cksum += *(unsigned char *)(p + i); if (cksum != 0) continue; if (*(p + 9) != 1) continue; entry = *(uint32_t *)(p + 4); aprint_verbose("BIOS32 rev. %d found at 0x%lx\n", *(p + 8), entry); if (entry < BIOS32_START || entry >= BIOS32_END) { aprint_error("BIOS32 entry point outside " "allowable range\n"); entry = 0; } break; } if (entry != 0) { bios32_entry.offset = (void *)ISA_HOLE_VADDR(entry); bios32_entry.segment = GSEL(GCODE_SEL, SEL_KPL); } #endif uint8_t *p; int i; /* see if we have SMBIOS extentions */ for (p = ISA_HOLE_VADDR(SMBIOS_START); p < (uint8_t *)ISA_HOLE_VADDR(SMBIOS_END); p+= 16) { struct smbhdr * sh = (struct smbhdr *)p; uint8_t chksum; vaddr_t eva; paddr_t pa, end; if (sh->sig != BIOS32_MAKESIG('_', 'S', 'M', '_')) continue; i = sh->len; for (chksum = 0; i--; ) chksum += p[i]; if (chksum != 0) continue; p += 0x10; if (p[0] != '_' && p[1] != 'D' && p[2] != 'M' && p[3] != 'I' && p[4] != '_') continue; for (chksum = 0, i = 0xf; i--; ) chksum += p[i]; if (chksum != 0) continue; pa = trunc_page(sh->addr); end = round_page(sh->addr + sh->size); eva = uvm_km_alloc(kernel_map, end - pa, 0, UVM_KMF_VAONLY); if (eva == 0) break; smbios_entry.addr = (uint8_t *)(eva + (sh->addr & PGOFSET)); smbios_entry.len = sh->size; smbios_entry.mjr = sh->majrev; smbios_entry.min = sh->minrev; smbios_entry.count = sh->count; for (; pa < end; pa+= NBPG, eva+= NBPG) #ifdef XEN pmap_kenter_ma(eva, pa, VM_PROT_READ, 0); #else pmap_kenter_pa(eva, pa, VM_PROT_READ, 0); #endif pmap_update(pmap_kernel()); aprint_debug("SMBIOS rev. %d.%d @ 0x%lx (%d entries)\n", sh->majrev, sh->minrev, (u_long)sh->addr, sh->count); break; } }