Module Name: src Committed By: nonaka Date: Fri May 24 14:28:49 UTC 2019
Modified Files: src/sys/arch/amd64/conf: GENERIC src/sys/arch/i386/conf: GENERIC src/sys/arch/x86/include: autoconf.h src/sys/arch/x86/pci: pci_machdep.c src/sys/arch/x86/x86: consinit.c hyperv.c identcpu.c x86_autoconf.c src/sys/arch/xen/x86: autoconf.c src/sys/dev/acpi: vmbus_acpi.c src/sys/dev/hyperv: files.hyperv hypervvar.h vmbus.c vmbusvar.h src/sys/dev/wscons: wsconsio.h Added Files: src/sys/arch/x86/x86: hypervvar.h src/sys/dev/hyperv: genfb_vmbus.c genfb_vmbusvar.h hvkbd.c hvkbdvar.h Log Message: Added drivers for Hyper-V Synthetic Keyboard and Video device. To generate a diff of this commit: cvs rdiff -u -r1.527 -r1.528 src/sys/arch/amd64/conf/GENERIC cvs rdiff -u -r1.1206 -r1.1207 src/sys/arch/i386/conf/GENERIC cvs rdiff -u -r1.5 -r1.6 src/sys/arch/x86/include/autoconf.h cvs rdiff -u -r1.85 -r1.86 src/sys/arch/x86/pci/pci_machdep.c cvs rdiff -u -r1.28 -r1.29 src/sys/arch/x86/x86/consinit.c cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/x86/hyperv.c cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/hypervvar.h cvs rdiff -u -r1.90 -r1.91 src/sys/arch/x86/x86/identcpu.c cvs rdiff -u -r1.77 -r1.78 src/sys/arch/x86/x86/x86_autoconf.c cvs rdiff -u -r1.22 -r1.23 src/sys/arch/xen/x86/autoconf.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/acpi/vmbus_acpi.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/hyperv/files.hyperv \ src/sys/dev/hyperv/hypervvar.h src/sys/dev/hyperv/vmbusvar.h cvs rdiff -u -r0 -r1.1 src/sys/dev/hyperv/genfb_vmbus.c \ src/sys/dev/hyperv/genfb_vmbusvar.h src/sys/dev/hyperv/hvkbd.c \ src/sys/dev/hyperv/hvkbdvar.h cvs rdiff -u -r1.2 -r1.3 src/sys/dev/hyperv/vmbus.c cvs rdiff -u -r1.122 -r1.123 src/sys/dev/wscons/wsconsio.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/amd64/conf/GENERIC diff -u src/sys/arch/amd64/conf/GENERIC:1.527 src/sys/arch/amd64/conf/GENERIC:1.528 --- src/sys/arch/amd64/conf/GENERIC:1.527 Mon May 6 02:24:37 2019 +++ src/sys/arch/amd64/conf/GENERIC Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.527 2019/05/06 02:24:37 sevan Exp $ +# $NetBSD: GENERIC,v 1.528 2019/05/24 14:28:48 nonaka Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/amd64/conf/std.amd64" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.527 $" +#ident "GENERIC-$Revision: 1.528 $" maxusers 64 # estimated number of users @@ -1067,6 +1067,9 @@ vioscsi* at virtio? # Virtio SCSI devi # Hyper-V devices vmbus* at acpi? # Hyper-V VMBus +genfb* at vmbus? # Hyper-V Synthetic Video Framebuffer +hvkbd* at vmbus? # Hyper-V Synthetic Keyboard +wskbd* at hvkbd? console ? mux 1 hvn* at vmbus? # Hyper-V NetVSC hvs* at vmbus? # Hyper-V StorVSC hvheartbeat* at vmbus? # Hyper-V Heartbeat Service Index: src/sys/arch/i386/conf/GENERIC diff -u src/sys/arch/i386/conf/GENERIC:1.1206 src/sys/arch/i386/conf/GENERIC:1.1207 --- src/sys/arch/i386/conf/GENERIC:1.1206 Mon May 6 02:24:37 2019 +++ src/sys/arch/i386/conf/GENERIC Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -# $NetBSD: GENERIC,v 1.1206 2019/05/06 02:24:37 sevan Exp $ +# $NetBSD: GENERIC,v 1.1207 2019/05/24 14:28:48 nonaka Exp $ # # GENERIC machine description file # @@ -22,7 +22,7 @@ include "arch/i386/conf/std.i386" options INCLUDE_CONFIG_FILE # embed config file in kernel binary -#ident "GENERIC-$Revision: 1.1206 $" +#ident "GENERIC-$Revision: 1.1207 $" maxusers 64 # estimated number of users @@ -1406,6 +1406,9 @@ vioscsi* at virtio? # Virtio SCSI devi # Hyper-V devices vmbus* at acpi? # Hyper-V VMBus +genfb* at vmbus? # Hyper-V Synthetic Video Framebuffer +hvkbd* at vmbus? # Hyper-V Synthetic Keyboard +wskbd* at hvkbd? console ? mux 1 hvn* at vmbus? # Hyper-V NetVSC hvs* at vmbus? # Hyper-V StorVSC hvheartbeat* at vmbus? # Hyper-V Heartbeat Service Index: src/sys/arch/x86/include/autoconf.h diff -u src/sys/arch/x86/include/autoconf.h:1.5 src/sys/arch/x86/include/autoconf.h:1.6 --- src/sys/arch/x86/include/autoconf.h:1.5 Sat Dec 22 07:45:58 2018 +++ src/sys/arch/x86/include/autoconf.h Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: autoconf.h,v 1.5 2018/12/22 07:45:58 cherry Exp $ */ +/* $NetBSD: autoconf.h,v 1.6 2019/05/24 14:28:48 nonaka Exp $ */ #ifndef _X86_AUTOCONF_H_ #define _X86_AUTOCONF_H_ @@ -20,6 +20,8 @@ struct mainbus_softc { #endif }; +extern int x86_found_console; + void device_pci_props_register(device_t, void *); device_t device_pci_register(device_t, void *); device_t device_isa_register(device_t, void *); Index: src/sys/arch/x86/pci/pci_machdep.c diff -u src/sys/arch/x86/pci/pci_machdep.c:1.85 src/sys/arch/x86/pci/pci_machdep.c:1.86 --- src/sys/arch/x86/pci/pci_machdep.c:1.85 Fri May 17 18:34:33 2019 +++ src/sys/arch/x86/pci/pci_machdep.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: pci_machdep.c,v 1.85 2019/05/17 18:34:33 christos Exp $ */ +/* $NetBSD: pci_machdep.c,v 1.86 2019/05/24 14:28:48 nonaka Exp $ */ /*- * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. @@ -73,7 +73,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.85 2019/05/17 18:34:33 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.86 2019/05/24 14:28:48 nonaka Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -1117,7 +1117,6 @@ populate_fbinfo(device_t dev, prop_dicti device_t device_pci_register(device_t dev, void *aux) { - static bool found_console = false; device_t parent = device_parent(dev); device_pci_props_register(dev, aux); @@ -1171,7 +1170,7 @@ device_pci_register(device_t dev, void * } } if (parent && device_is_a(parent, "pci") && - found_console == false) { + x86_found_console == false) { struct pci_attach_args *pa = aux; if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY) { @@ -1209,7 +1208,7 @@ device_pci_register(device_t dev, void * vga_posth = vga_post_init(pa->pa_bus, pa->pa_device, pa->pa_function); #endif - found_console = true; + x86_found_console = true; return NULL; } } Index: src/sys/arch/x86/x86/consinit.c diff -u src/sys/arch/x86/x86/consinit.c:1.28 src/sys/arch/x86/x86/consinit.c:1.29 --- src/sys/arch/x86/x86/consinit.c:1.28 Sun Jan 11 19:54:23 2015 +++ src/sys/arch/x86/x86/consinit.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: consinit.c,v 1.28 2015/01/11 19:54:23 is Exp $ */ +/* $NetBSD: consinit.c,v 1.29 2019/05/24 14:28:48 nonaka Exp $ */ /* * Copyright (c) 1998 @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: consinit.c,v 1.28 2015/01/11 19:54:23 is Exp $"); +__KERNEL_RCSID(0, "$NetBSD: consinit.c,v 1.29 2019/05/24 14:28:48 nonaka Exp $"); #include "opt_kgdb.h" #include "opt_puc.h" @@ -36,6 +36,7 @@ __KERNEL_RCSID(0, "$NetBSD: consinit.c,v #include <sys/systm.h> #include <sys/device.h> #include <sys/bus.h> +#include <sys/cpu.h> #include <machine/bootinfo.h> #include <arch/x86/include/genfb_machdep.h> @@ -90,6 +91,13 @@ __KERNEL_RCSID(0, "$NetBSD: consinit.c,v #include <dev/usb/ukbdvar.h> #endif +#ifndef XEN +#include "hvkbd.h" +#if NHVKBD > 0 +#include <dev/hyperv/hvkbdvar.h> +#endif +#endif + #ifndef CONSDEVNAME #define CONSDEVNAME "pc" #endif @@ -205,6 +213,10 @@ dokbd: error = pckbc_cnattach(x86_bus_space_io, IO_KBD, KBCMDP, PCKBC_KBD_SLOT, 0); #endif +#if (NHVKBD > 0) + if (error && vm_guest == VM_GUEST_HV) + error = hvkbd_cnattach(); +#endif #if (NUKBD > 0) if (error) error = ukbd_cnattach(); Index: src/sys/arch/x86/x86/hyperv.c diff -u src/sys/arch/x86/x86/hyperv.c:1.1 src/sys/arch/x86/x86/hyperv.c:1.2 --- src/sys/arch/x86/x86/hyperv.c:1.1 Fri Feb 15 08:54:01 2019 +++ src/sys/arch/x86/x86/hyperv.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: hyperv.c,v 1.1 2019/02/15 08:54:01 nonaka Exp $ */ +/* $NetBSD: hyperv.c,v 1.2 2019/05/24 14:28:48 nonaka Exp $ */ /*- * Copyright (c) 2009-2012,2016-2017 Microsoft Corp. @@ -33,7 +33,7 @@ */ #include <sys/cdefs.h> #ifdef __KERNEL_RCSID -__KERNEL_RCSID(0, "$NetBSD: hyperv.c,v 1.1 2019/02/15 08:54:01 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hyperv.c,v 1.2 2019/05/24 14:28:48 nonaka Exp $"); #endif #ifdef __FBSDID __FBSDID("$FreeBSD: head/sys/dev/hyperv/vmbus/hyperv.c 331757 2018-03-30 02:25:12Z emaste $"); @@ -41,6 +41,9 @@ __FBSDID("$FreeBSD: head/sys/dev/hyperv/ #ifdef _KERNEL_OPT #include "lapic.h" +#include "genfb.h" +#include "opt_ddb.h" +#include "wsdisplay.h" #endif #include <sys/param.h> @@ -57,13 +60,27 @@ __FBSDID("$FreeBSD: head/sys/dev/hyperv/ #include <uvm/uvm_extern.h> +#include <machine/autoconf.h> +#include <machine/bootinfo.h> #include <machine/cpufunc.h> #include <machine/cputypes.h> #include <machine/cpuvar.h> #include <machine/cpu_counter.h> +#include <x86/efi.h> + +#include <dev/wsfb/genfbvar.h> +#include <arch/x86/include/genfb_machdep.h> #include <x86/x86/hypervreg.h> +#include <x86/x86/hypervvar.h> #include <dev/hyperv/vmbusvar.h> +#include <dev/hyperv/genfb_vmbusvar.h> + +#ifdef DDB +#include <machine/db_machdep.h> +#include <ddb/db_sym.h> +#include <ddb/db_extern.h> +#endif struct hyperv_softc { device_t sc_dev; @@ -299,6 +316,26 @@ delay_tc(unsigned int n) } while (now < end); } +static void +delay_msr(unsigned int n) +{ + uint64_t end, now; + u_int last, u; + + now = 0; + end = HYPERV_TIMER_FREQ * n / 1000000ULL; + last = (u_int)rdmsr(MSR_HV_TIME_REF_COUNT); + do { + x86_pause(); + u = (u_int)rdmsr(MSR_HV_TIME_REF_COUNT); + if (u < last) + now += 0xffffffff - last + u + 1; + else + now += u - last; + last = u; + } while (now < end); +} + static __inline uint64_t hyperv_hypercall_md(volatile void *hc_addr, uint64_t in_val, uint64_t in_paddr, uint64_t out_paddr) @@ -341,18 +378,17 @@ hyperv_hypercall(uint64_t control, paddr } static bool -hyperv_identify(void) +hyperv_probe(u_int *maxleaf, u_int *features, u_int *pm_features, + u_int *features3) { - char buf[256]; u_int regs[4]; - u_int maxleaf; if (vm_guest != VM_GUEST_HV) return false; x86_cpuid(CPUID_LEAF_HV_MAXLEAF, regs); - maxleaf = regs[0]; - if (maxleaf < CPUID_LEAF_HV_LIMITS) + *maxleaf = regs[0]; + if (*maxleaf < CPUID_LEAF_HV_LIMITS) return false; x86_cpuid(CPUID_LEAF_HV_INTERFACE, regs); @@ -368,9 +404,23 @@ hyperv_identify(void) return false; } - hyperv_features = regs[0]; - hyperv_pm_features = regs[2]; - hyperv_features3 = regs[3]; + *features = regs[0]; + *pm_features = regs[2]; + *features3 = regs[3]; + + return true; +} + +static bool +hyperv_identify(void) +{ + char buf[256]; + u_int regs[4]; + u_int maxleaf; + + if (!hyperv_probe(&maxleaf, &hyperv_features, &hyperv_pm_features, + &hyperv_features3)) + return false; x86_cpuid(CPUID_LEAF_HV_IDENTITY, regs); hyperv_ver_major = regs[1] >> 16; @@ -439,6 +489,19 @@ hyperv_identify(void) return true; } +void +hyperv_early_init(void) +{ + u_int features, pm_features, features3; + u_int maxleaf; + + if (!hyperv_probe(&maxleaf, &features, &pm_features, &features3)) + return; + + if (features & CPUID_HV_MSR_TIME_REFCNT) + x86_delay = delay_func = delay_msr; +} + static bool hyperv_init(void) { @@ -685,6 +748,13 @@ hyperv_synic_supported(void) return (hyperv_features & CPUID_HV_MSR_SYNIC) ? 1 : 0; } +int +hyperv_is_gen1(void) +{ + + return !bootmethod_efi; +} + void hyperv_send_eom(void) { @@ -917,3 +987,146 @@ hyperv_modcmd(modcmd_t cmd, void *aux) return rv; } + +/* + * genfb at vmbus + */ +static struct genfb_pmf_callback pmf_cb; +static struct genfb_mode_callback mode_cb; + +static bool +x86_genfb_setmode(struct genfb_softc *sc, int newmode) +{ +#if NGENFB > 0 + switch (newmode) { + case WSDISPLAYIO_MODE_EMUL: + x86_genfb_mtrr_init(sc->sc_fboffset, + sc->sc_height * sc->sc_stride); + break; + } +#endif + return true; +} + +static bool +x86_genfb_suspend(device_t dev, const pmf_qual_t *qual) +{ + return true; +} + +static bool +x86_genfb_resume(device_t dev, const pmf_qual_t *qual) +{ +#if NGENFB > 0 + struct genfb_vmbus_softc *sc = device_private(dev); + + genfb_restore_palette(&sc->sc_gen); +#endif + return true; +} + +static void +populate_fbinfo(device_t dev, prop_dictionary_t dict) +{ +#if NWSDISPLAY > 0 && NGENFB > 0 + extern struct vcons_screen x86_genfb_console_screen; + struct rasops_info *ri = &x86_genfb_console_screen.scr_ri; +#endif + const void *fbptr = lookup_bootinfo(BTINFO_FRAMEBUFFER); + struct btinfo_framebuffer fbinfo; + + if (fbptr == NULL) + return; + + memcpy(&fbinfo, fbptr, sizeof(fbinfo)); + + if (fbinfo.physaddr != 0) { + prop_dictionary_set_uint32(dict, "width", fbinfo.width); + prop_dictionary_set_uint32(dict, "height", fbinfo.height); + prop_dictionary_set_uint8(dict, "depth", fbinfo.depth); + prop_dictionary_set_uint16(dict, "linebytes", fbinfo.stride); + + prop_dictionary_set_uint64(dict, "address", fbinfo.physaddr); +#if NWSDISPLAY > 0 && NGENFB > 0 + if (ri->ri_bits != NULL) { + prop_dictionary_set_uint64(dict, "virtual_address", + ri->ri_hwbits != NULL ? + (vaddr_t)ri->ri_hworigbits : + (vaddr_t)ri->ri_origbits); + } +#endif + } +#if notyet + prop_dictionary_set_bool(dict, "splash", + (fbinfo.flags & BI_FB_SPLASH) != 0); +#endif +#if 0 + if (fbinfo.depth == 8) { + gfb_cb.gcc_cookie = NULL; + gfb_cb.gcc_set_mapreg = x86_genfb_set_mapreg; + prop_dictionary_set_uint64(dict, "cmap_callback", + (uint64_t)(uintptr_t)&gfb_cb); + } +#endif + if (fbinfo.physaddr != 0) { + mode_cb.gmc_setmode = x86_genfb_setmode; + prop_dictionary_set_uint64(dict, "mode_callback", + (uint64_t)(uintptr_t)&mode_cb); + } + +#if NWSDISPLAY > 0 && NGENFB > 0 + if (device_is_a(dev, "genfb")) { + prop_dictionary_set_bool(dict, "enable_shadowfb", + ri->ri_hwbits != NULL); + + x86_genfb_set_console_dev(dev); +#ifdef DDB + db_trap_callback = x86_genfb_ddb_trap_callback; +#endif + } +#endif +} + +device_t +device_hyperv_register(device_t dev, void *aux) +{ + device_t parent = device_parent(dev); + + if (parent && device_is_a(parent, "vmbus") && !x86_found_console) { + struct vmbus_attach_args *aa = aux; + + if (memcmp(aa->aa_type, &hyperv_guid_video, + sizeof(*aa->aa_type)) == 0) { + prop_dictionary_t dict = device_properties(dev); + + /* + * framebuffer drivers other than genfb can work + * without the address property + */ + populate_fbinfo(dev, dict); + +#if 1 && NWSDISPLAY > 0 && NGENFB > 0 + /* XXX */ + if (device_is_a(dev, "genfb")) { + prop_dictionary_set_bool(dict, "is_console", + genfb_is_console()); + } else +#endif + prop_dictionary_set_bool(dict, "is_console", true); + + prop_dictionary_set_bool(dict, "clear-screen", false); +#if NWSDISPLAY > 0 && NGENFB > 0 + extern struct vcons_screen x86_genfb_console_screen; + prop_dictionary_set_uint16(dict, "cursor-row", + x86_genfb_console_screen.scr_ri.ri_crow); +#endif + pmf_cb.gpc_suspend = x86_genfb_suspend; + pmf_cb.gpc_resume = x86_genfb_resume; + prop_dictionary_set_uint64(dict, "pmf_callback", + (uint64_t)(uintptr_t)&pmf_cb); + x86_found_console = true; + return NULL; + } + } + return NULL; +} Index: src/sys/arch/x86/x86/identcpu.c diff -u src/sys/arch/x86/x86/identcpu.c:1.90 src/sys/arch/x86/x86/identcpu.c:1.91 --- src/sys/arch/x86/x86/identcpu.c:1.90 Sat May 18 13:44:57 2019 +++ src/sys/arch/x86/x86/identcpu.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: identcpu.c,v 1.90 2019/05/18 13:44:57 maxv Exp $ */ +/* $NetBSD: identcpu.c,v 1.91 2019/05/24 14:28:48 nonaka Exp $ */ /*- * Copyright (c) 1999, 2000, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.90 2019/05/18 13:44:57 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.91 2019/05/24 14:28:48 nonaka Exp $"); #include "opt_xen.h" @@ -53,6 +53,13 @@ __KERNEL_RCSID(0, "$NetBSD: identcpu.c,v #include <x86/x86/vmtreg.h> /* for vmt_hvcall() */ #include <x86/x86/vmtvar.h> /* for vmt_hvcall() */ +#ifndef XEN +#include "hyperv.h" +#if NHYPERV > 0 +#include <x86/x86/hypervvar.h> +#endif +#endif + static const struct x86_cache_info intel_cpuid_cache_info[] = INTEL_CACHE_INFO; static const struct x86_cache_info amd_cpuid_l2cache_assoc_info[] = @@ -1074,9 +1081,12 @@ identify_hypervisor(void) memcpy(&hv_vendor[8], ®s[3], sizeof(*regs)); if (memcmp(hv_vendor, "VMwareVMware", 12) == 0) vm_guest = VM_GUEST_VMWARE; - else if (memcmp(hv_vendor, "Microsoft Hv", 12) == 0) + else if (memcmp(hv_vendor, "Microsoft Hv", 12) == 0) { vm_guest = VM_GUEST_HV; - else if (memcmp(hv_vendor, "KVMKVMKVM\0\0\0", 12) == 0) +#if NHYPERV > 0 + hyperv_early_init(); +#endif + } else if (memcmp(hv_vendor, "KVMKVMKVM\0\0\0", 12) == 0) vm_guest = VM_GUEST_KVM; else if (memcmp(hv_vendor, "XenVMMXenVMM", 12) == 0) vm_guest = VM_GUEST_XEN; Index: src/sys/arch/x86/x86/x86_autoconf.c diff -u src/sys/arch/x86/x86/x86_autoconf.c:1.77 src/sys/arch/x86/x86/x86_autoconf.c:1.78 --- src/sys/arch/x86/x86/x86_autoconf.c:1.77 Thu Jun 7 13:35:31 2018 +++ src/sys/arch/x86/x86/x86_autoconf.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: x86_autoconf.c,v 1.77 2018/06/07 13:35:31 thorpej Exp $ */ +/* $NetBSD: x86_autoconf.c,v 1.78 2019/05/24 14:28:48 nonaka Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: x86_autoconf.c,v 1.77 2018/06/07 13:35:31 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: x86_autoconf.c,v 1.78 2019/05/24 14:28:48 nonaka Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -58,13 +58,20 @@ __KERNEL_RCSID(0, "$NetBSD: x86_autoconf #include "acpica.h" #include "wsdisplay.h" +#ifndef XEN +#include "hyperv.h" +#endif #if NACPICA > 0 #include <dev/acpi/acpivar.h> #endif +#if NHYPERV > 0 +#include <x86/x86/hypervvar.h> +#endif struct disklist *x86_alldisks; int x86_ndisks; +int x86_found_console; #ifdef DEBUG_GEOM #define DPRINTF(a) printf a @@ -583,6 +590,9 @@ device_register(device_t dev, void *aux) isaboot = device_isa_register(dev, aux); pciboot = device_pci_register(dev, aux); +#if NHYPERV > 0 + (void)device_hyperv_register(dev, aux); +#endif if (isaboot == NULL && pciboot == NULL) return; Index: src/sys/arch/xen/x86/autoconf.c diff -u src/sys/arch/xen/x86/autoconf.c:1.22 src/sys/arch/xen/x86/autoconf.c:1.23 --- src/sys/arch/xen/x86/autoconf.c:1.22 Mon Jan 28 21:19:09 2019 +++ src/sys/arch/xen/x86/autoconf.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: autoconf.c,v 1.22 2019/01/28 21:19:09 bad Exp $ */ +/* $NetBSD: autoconf.c,v 1.23 2019/05/24 14:28:48 nonaka Exp $ */ /* NetBSD: autoconf.c,v 1.75 2003/12/30 12:33:22 pk Exp */ /*- @@ -45,7 +45,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.22 2019/01/28 21:19:09 bad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.23 2019/05/24 14:28:48 nonaka Exp $"); #include "opt_xen.h" #include "opt_multiprocessor.h" @@ -86,6 +86,7 @@ static int is_valid_disk(device_t); struct disklist *x86_alldisks; int x86_ndisks; +int x86_found_console; #include "bios32.h" #if NBIOS32 > 0 Index: src/sys/dev/acpi/vmbus_acpi.c diff -u src/sys/dev/acpi/vmbus_acpi.c:1.1 src/sys/dev/acpi/vmbus_acpi.c:1.2 --- src/sys/dev/acpi/vmbus_acpi.c:1.1 Fri Feb 15 08:54:01 2019 +++ src/sys/dev/acpi/vmbus_acpi.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: vmbus_acpi.c,v 1.1 2019/02/15 08:54:01 nonaka Exp $ */ +/* $NetBSD: vmbus_acpi.c,v 1.2 2019/05/24 14:28:48 nonaka Exp $ */ /* * Copyright (c) 2018 Kimihiro Nonaka <non...@netbsd.org> @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vmbus_acpi.c,v 1.1 2019/02/15 08:54:01 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vmbus_acpi.c,v 1.2 2019/05/24 14:28:48 nonaka Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -82,6 +82,8 @@ vmbus_acpi_attach(device_t parent, devic struct acpi_attach_args *aa = opaque; sc->sc.sc_dev = self; + sc->sc.sc_iot = aa->aa_iot; + sc->sc.sc_memt = aa->aa_memt; sc->sc.sc_dmat = aa->aa_dmat64 ? aa->aa_dmat64 : aa->aa_dmat; if (vmbus_attach(&sc->sc)) Index: src/sys/dev/hyperv/files.hyperv diff -u src/sys/dev/hyperv/files.hyperv:1.1 src/sys/dev/hyperv/files.hyperv:1.2 --- src/sys/dev/hyperv/files.hyperv:1.1 Fri Feb 15 08:54:01 2019 +++ src/sys/dev/hyperv/files.hyperv Fri May 24 14:28:48 2019 @@ -1,9 +1,16 @@ -# $NetBSD: files.hyperv,v 1.1 2019/02/15 08:54:01 nonaka Exp $ +# $NetBSD: files.hyperv,v 1.2 2019/05/24 14:28:48 nonaka Exp $ define hypervvmbus {} device vmbus: hypervvmbus file dev/hyperv/vmbus.c vmbus needs-flag +attach genfb at hypervvmbus with genfb_vmbus : splash +file dev/hyperv/genfb_vmbus.c genfb_vmbus + +device hvkbd: wskbddev +attach hvkbd at hypervvmbus +file dev/hyperv/hvkbd.c hvkbd needs-flag + device hvn: ether, ifnet, arp attach hvn at hypervvmbus file dev/hyperv/if_hvn.c hvn Index: src/sys/dev/hyperv/hypervvar.h diff -u src/sys/dev/hyperv/hypervvar.h:1.1 src/sys/dev/hyperv/hypervvar.h:1.2 --- src/sys/dev/hyperv/hypervvar.h:1.1 Fri Feb 15 08:54:01 2019 +++ src/sys/dev/hyperv/hypervvar.h Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: hypervvar.h,v 1.1 2019/02/15 08:54:01 nonaka Exp $ */ +/* $NetBSD: hypervvar.h,v 1.2 2019/05/24 14:28:48 nonaka Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD @@ -62,6 +62,7 @@ __CTASSERT(sizeof(struct hyperv_reftsc) int hyperv_hypercall_enabled(void); int hyperv_synic_supported(void); +int hyperv_is_gen1(void); void hyperv_send_eom(void); void hyperv_intr(void); Index: src/sys/dev/hyperv/vmbusvar.h diff -u src/sys/dev/hyperv/vmbusvar.h:1.1 src/sys/dev/hyperv/vmbusvar.h:1.2 --- src/sys/dev/hyperv/vmbusvar.h:1.1 Fri Feb 15 08:54:02 2019 +++ src/sys/dev/hyperv/vmbusvar.h Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: vmbusvar.h,v 1.1 2019/02/15 08:54:02 nonaka Exp $ */ +/* $NetBSD: vmbusvar.h,v 1.2 2019/05/24 14:28:48 nonaka Exp $ */ /* $OpenBSD: hypervvar.h,v 1.13 2017/06/23 19:05:42 mikeb Exp $ */ /* @@ -133,6 +133,8 @@ struct vmbus_attach_args { struct hyperv_guid *aa_inst; char *aa_ident; struct vmbus_channel *aa_chan; + bus_space_tag_t aa_iot; + bus_space_tag_t aa_memt; }; struct vmbus_dev { @@ -153,6 +155,8 @@ struct vmbus_percpu_data { struct vmbus_softc { device_t sc_dev; + bus_space_tag_t sc_iot; + bus_space_tag_t sc_memt; bus_dma_tag_t sc_dmat; pool_cache_t sc_msgpool; Index: src/sys/dev/hyperv/vmbus.c diff -u src/sys/dev/hyperv/vmbus.c:1.2 src/sys/dev/hyperv/vmbus.c:1.3 --- src/sys/dev/hyperv/vmbus.c:1.2 Fri Feb 15 16:37:54 2019 +++ src/sys/dev/hyperv/vmbus.c Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: vmbus.c,v 1.2 2019/02/15 16:37:54 hannken Exp $ */ +/* $NetBSD: vmbus.c,v 1.3 2019/05/24 14:28:48 nonaka Exp $ */ /* $OpenBSD: hyperv.c,v 1.43 2017/06/27 13:56:15 mikeb Exp $ */ /*- @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vmbus.c,v 1.2 2019/02/15 16:37:54 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vmbus.c,v 1.3 2019/05/24 14:28:48 nonaka Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -2034,6 +2034,8 @@ vmbus_attach_icdevs(struct vmbus_softc * dv->dv_aa.aa_inst = &ch->ch_inst; dv->dv_aa.aa_ident = ch->ch_ident; dv->dv_aa.aa_chan = ch; + dv->dv_aa.aa_iot = sc->sc_iot; + dv->dv_aa.aa_memt = sc->sc_memt; mutex_enter(&sc->sc_icdev_lock); SLIST_INSERT_HEAD(&sc->sc_icdevs, dv, dv_entry); mutex_exit(&sc->sc_icdev_lock); @@ -2068,6 +2070,8 @@ vmbus_attach_devices(struct vmbus_softc dv->dv_aa.aa_inst = &ch->ch_inst; dv->dv_aa.aa_ident = ch->ch_ident; dv->dv_aa.aa_chan = ch; + dv->dv_aa.aa_iot = sc->sc_iot; + dv->dv_aa.aa_memt = sc->sc_memt; mutex_enter(&sc->sc_dev_lock); SLIST_INSERT_HEAD(&sc->sc_devs, dv, dv_entry); mutex_exit(&sc->sc_dev_lock); Index: src/sys/dev/wscons/wsconsio.h diff -u src/sys/dev/wscons/wsconsio.h:1.122 src/sys/dev/wscons/wsconsio.h:1.123 --- src/sys/dev/wscons/wsconsio.h:1.122 Sun Mar 17 00:30:55 2019 +++ src/sys/dev/wscons/wsconsio.h Fri May 24 14:28:48 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: wsconsio.h,v 1.122 2019/03/17 00:30:55 tnn Exp $ */ +/* $NetBSD: wsconsio.h,v 1.123 2019/05/24 14:28:48 nonaka Exp $ */ /* * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. @@ -109,6 +109,7 @@ struct wscons_event { #define WSKBD_TYPE_LUNA 23 /* OMRON SX-9100 LUNA */ #define WSKBD_TYPE_RFB 24 /* Usermode vnc remote keyboard */ #define WSKBD_TYPE_EPOC 25 /* Psion EPOC machine keyboard */ +#define WSKBD_TYPE_HYPERV 26 /* Hyper-V synthetic keyboard */ /* Manipulate the keyboard bell. */ struct wskbd_bell_data { Added files: Index: src/sys/arch/x86/x86/hypervvar.h diff -u /dev/null src/sys/arch/x86/x86/hypervvar.h:1.1 --- /dev/null Fri May 24 14:28:49 2019 +++ src/sys/arch/x86/x86/hypervvar.h Fri May 24 14:28:48 2019 @@ -0,0 +1,37 @@ +/* $NetBSD: hypervvar.h,v 1.1 2019/05/24 14:28:48 nonaka Exp $ */ + +/*- + * Copyright (c) 2009-2012,2016 Microsoft Corp. + * Copyright (c) 2012 NetApp Inc. + * Copyright (c) 2012 Citrix Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _X86_HYPERVVAR_H_ +#define _X86_HYPERVVAR_H_ + +void hyperv_early_init(void); +device_t device_hyperv_register(device_t, void *); + +#endif /* _X86_HYPERVVAR_H_ */ Index: src/sys/dev/hyperv/genfb_vmbus.c diff -u /dev/null src/sys/dev/hyperv/genfb_vmbus.c:1.1 --- /dev/null Fri May 24 14:28:49 2019 +++ src/sys/dev/hyperv/genfb_vmbus.c Fri May 24 14:28:48 2019 @@ -0,0 +1,158 @@ +/* $NetBSD: genfb_vmbus.c,v 1.1 2019/05/24 14:28:48 nonaka Exp $ */ + +/*- + * Copyright (c) 2007 Michael Lorenz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: genfb_vmbus.c,v 1.1 2019/05/24 14:28:48 nonaka Exp $"); + +#include "opt_wsfb.h" +#include "opt_genfb.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/proc.h> +#include <sys/mutex.h> +#include <sys/ioctl.h> +#include <sys/systm.h> +#include <sys/kauth.h> + +#include <dev/wsfb/genfbvar.h> + +#include <dev/hyperv/vmbusvar.h> +#include <dev/hyperv/genfb_vmbusvar.h> + +static int genfb_vmbus_match(device_t, cfdata_t, void *); +static void genfb_vmbus_attach(device_t, device_t, void *); +static int genfb_vmbus_ioctl(void *, void *, u_long, void *, int, + struct lwp *); +static paddr_t genfb_vmbus_mmap(void *, void *, off_t, int); +static int genfb_vmbus_drm_print(void *, const char *); +static bool genfb_vmbus_shutdown(device_t, int); + +CFATTACH_DECL_NEW(genfb_vmbus, sizeof(struct genfb_vmbus_softc), + genfb_vmbus_match, genfb_vmbus_attach, NULL, NULL); + +static int +genfb_vmbus_match(device_t parent, cfdata_t match, void *aux) +{ + struct vmbus_attach_args *aa = aux; + + if (memcmp(aa->aa_type, &hyperv_guid_video, sizeof(*aa->aa_type)) != 0) + return 0; + + if (!genfb_is_enabled()) + return 0; /* explicitly disabled by MD code */ + + /* Use genfb(4) at pci in Gen.1 VM. */ + if (hyperv_is_gen1()) + return 0; + + return 1; +} + +static void +genfb_vmbus_attach(device_t parent, device_t self, void *aux) +{ + static const struct genfb_ops zero_ops; + struct genfb_vmbus_softc *sc = device_private(self); + struct vmbus_attach_args *aa = aux; + struct genfb_ops ops = zero_ops; + + aprint_naive("\n"); + aprint_normal(": Hyper-V Synthetic Video\n"); + + sc->sc_gen.sc_dev = self; + sc->sc_memt = aa->aa_memt; + + genfb_init(&sc->sc_gen); + + /* firmware / MD code responsible for restoring the display */ + if (sc->sc_gen.sc_pmfcb == NULL) + pmf_device_register1(self, NULL, NULL, + genfb_vmbus_shutdown); + else + pmf_device_register1(self, + sc->sc_gen.sc_pmfcb->gpc_suspend, + sc->sc_gen.sc_pmfcb->gpc_resume, + genfb_vmbus_shutdown); + + if ((sc->sc_gen.sc_width == 0) || (sc->sc_gen.sc_fbsize == 0)) { + aprint_debug_dev(self, "not configured by firmware\n"); + return; + } + + ops.genfb_ioctl = genfb_vmbus_ioctl; + ops.genfb_mmap = genfb_vmbus_mmap; + + if (genfb_attach(&sc->sc_gen, &ops) != 0) + return; + + /* now try to attach a DRM */ + config_found_ia(self, "drm", aux, genfb_vmbus_drm_print); +} + +static int +genfb_vmbus_drm_print(void *aux, const char *pnp) +{ + + if (pnp) + aprint_normal("drm at %s", pnp); + return UNCONF; +} + +static int +genfb_vmbus_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, + struct lwp *l) +{ + + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_GENFB; + return 0; + } + + return EPASSTHROUGH; +} + +static paddr_t +genfb_vmbus_mmap(void *v, void *vs, off_t offset, int prot) +{ + struct genfb_vmbus_softc *sc = v; + + return bus_space_mmap(sc->sc_memt, sc->sc_gen.sc_fboffset, offset, prot, + BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_PREFETCHABLE); +} + +static bool +genfb_vmbus_shutdown(device_t self, int flags) +{ + + genfb_enable_polling(self); + return true; +} Index: src/sys/dev/hyperv/genfb_vmbusvar.h diff -u /dev/null src/sys/dev/hyperv/genfb_vmbusvar.h:1.1 --- /dev/null Fri May 24 14:28:49 2019 +++ src/sys/dev/hyperv/genfb_vmbusvar.h Fri May 24 14:28:48 2019 @@ -0,0 +1,40 @@ +/* $NetBSD: genfb_vmbusvar.h,v 1.1 2019/05/24 14:28:48 nonaka Exp $ */ + +/*- + * Copyright (c) 2007 Michael Lorenz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEV_HYPERV_GENFB_VMBUSVAR_H_ +#define _DEV_HYPERV_GENFB_VMBUSVAR_H_ + +#include <dev/wsfb/genfbvar.h> + +struct genfb_vmbus_softc { + struct genfb_softc sc_gen; + + bus_space_tag_t sc_memt; +}; + +#endif /* _DEV_HYPERV_GENFB_VMBUSVAR_H_ */ Index: src/sys/dev/hyperv/hvkbd.c diff -u /dev/null src/sys/dev/hyperv/hvkbd.c:1.1 --- /dev/null Fri May 24 14:28:49 2019 +++ src/sys/dev/hyperv/hvkbd.c Fri May 24 14:28:48 2019 @@ -0,0 +1,644 @@ +/* $NetBSD: hvkbd.c,v 1.1 2019/05/24 14:28:48 nonaka Exp $ */ + +/*- + * Copyright (c) 2017 Microsoft Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: head/sys/dev/hyperv/input/hv_kbd.c 317821 2017-05-05 03:28:30Z sephe $ + * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.c 320490 2017-06-30 03:01:22Z sephe $ + * $FreeBSD: head/sys/dev/hyperv/input/hv_kbdc.h 316515 2017-04-05 05:01:23Z sephe $ + */ + +#ifdef _KERNEL_OPT +#include "opt_pckbd_layout.h" +#include "opt_wsdisplay_compat.h" +#endif /* _KERNEL_OPT */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: hvkbd.c,v 1.1 2019/05/24 14:28:48 nonaka Exp $"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/mutex.h> +#include <sys/kernel.h> +#include <sys/kmem.h> +#include <sys/module.h> +#include <sys/pmf.h> +#include <sys/proc.h> +#include <sys/queue.h> + +#include <dev/hyperv/vmbusvar.h> +#include <dev/hyperv/hvkbdvar.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wskbdvar.h> +#include <dev/wscons/wsksymdef.h> +#include <dev/wscons/wsksymvar.h> +#include <dev/pckbport/wskbdmap_mfii.h> + +#define HVKBD_BUFSIZE (4 * PAGE_SIZE) +#define HVKBD_TX_RING_SIZE (10 * PAGE_SIZE) +#define HVKBD_RX_RING_SIZE (10 * PAGE_SIZE) + +#define HVKBD_VER_MAJOR (1) +#define HVKBD_VER_MINOR (0) +#define HVKBD_VERSION ((HVKBD_VER_MAJOR << 16) | HVKBD_VER_MINOR) + +enum hvkbd_msg_type { + HVKBD_PROTO_REQUEST = 1, + HVKBD_PROTO_RESPONSE = 2, + HVKBD_PROTO_EVENT = 3, + HVKBD_PROTO_LED_INDICATORS = 4 +}; + +struct hvkbd_msg_hdr { + uint32_t type; +} __packed; + +struct hvkbd_proto_req { + struct hvkbd_msg_hdr hdr; + uint32_t ver; +} __packed; + +struct hvkbd_proto_resp { + struct hvkbd_msg_hdr hdr; + uint32_t status; +#define RESP_STATUS_ACCEPTED __BIT(0) +} __packed; + +struct keystroke { + uint16_t makecode; + uint16_t pad0; + uint32_t info; +#define KS_INFO_UNICODE __BIT(0) +#define KS_INFO_BREAK __BIT(1) +#define KS_INFO_E0 __BIT(2) +#define KS_INFO_E1 __BIT(3) +} __packed; + +struct hvkbd_keystroke { + struct hvkbd_msg_hdr hdr; + struct keystroke ks; +} __packed; + +struct hvkbd_keystroke_info { + LIST_ENTRY(hvkbd_keystroke_info) link; + STAILQ_ENTRY(hvkbd_keystroke_info) slink; + struct keystroke ks; +}; + +#define HVKBD_KEYBUF_SIZE 16 + +struct hvkbd_softc { + device_t sc_dev; + + struct vmbus_channel *sc_chan; + void *sc_buf; + + kmutex_t sc_ks_lock; + LIST_HEAD(, hvkbd_keystroke_info) sc_ks_free; + STAILQ_HEAD(, hvkbd_keystroke_info) sc_ks_queue; + + int sc_enabled; + int sc_polling; + int sc_console_keyboard; +#if defined(WSDISPLAY_COMPAT_RAWKBD) + int sc_rawkbd; +#endif + + int sc_connected; + uint32_t sc_connect_status; + + device_t sc_wskbddev; +}; + +static int hvkbd_match(device_t, cfdata_t, void *); +static void hvkbd_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(hvkbd, sizeof(struct hvkbd_softc), + hvkbd_match, hvkbd_attach, NULL, NULL); + +static int hvkbd_alloc_keybuf(struct hvkbd_softc *); +static void hvkbd_free_keybuf(struct hvkbd_softc *); + +static int hvkbd_enable(void *, int); +static void hvkbd_set_leds(void *, int); +static int hvkbd_ioctl(void *, u_long, void *, int, struct lwp *); + +static const struct wskbd_accessops hvkbd_accessops = { + hvkbd_enable, + hvkbd_set_leds, + hvkbd_ioctl, +}; + +static const struct wskbd_mapdata hvkbd_keymapdata = { + pckbd_keydesctab, +#if defined(PCKBD_LAYOUT) + PCKBD_LAYOUT, +#else + KB_US, +#endif +}; + +static int hvkbd_connect(struct hvkbd_softc *); +static void hvkbd_intr(void *); + +static void hvkbd_cngetc(void *, u_int *, int *); +static void hvkbd_cnpollc(void *, int); + +static const struct wskbd_consops hvkbd_consops = { + .getc = hvkbd_cngetc, + .pollc = hvkbd_cnpollc, + .bell = NULL, +}; + +static int hvkbd_is_console; + +static int +hvkbd_match(device_t parent, cfdata_t cf, void *aux) +{ + struct vmbus_attach_args *aa = aux; + + if (memcmp(aa->aa_type, &hyperv_guid_kbd, sizeof(*aa->aa_type)) != 0) + return 0; + + /* If hvkbd(4) is not console, we use pckbd(4) in Gen.1 VM. */ + if (!hvkbd_is_console && hyperv_is_gen1()) + return 0; + + return 1; +} + +static void +hvkbd_attach(device_t parent, device_t self, void *aux) +{ + struct hvkbd_softc *sc = device_private(self); + struct vmbus_attach_args *aa = aux; + struct wskbddev_attach_args a; + + sc->sc_dev = self; + sc->sc_chan = aa->aa_chan; + + aprint_naive("\n"); + aprint_normal(": Hyper-V Synthetic Keyboard\n"); + + mutex_init(&sc->sc_ks_lock, MUTEX_DEFAULT, IPL_TTY); + LIST_INIT(&sc->sc_ks_free); + STAILQ_INIT(&sc->sc_ks_queue); + hvkbd_alloc_keybuf(sc); + + sc->sc_buf = kmem_zalloc(HVKBD_BUFSIZE, cold ? KM_NOSLEEP : KM_SLEEP); + if (sc->sc_buf == NULL) { + aprint_error_dev(self, + "failed to allocate channel data buffer\n"); + return; + } + + if (vmbus_channel_setdeferred(sc->sc_chan, device_xname(self))) { + aprint_error_dev(self, + "failed to create the interrupt thread\n"); + goto free_buf; + } + + sc->sc_chan->ch_flags &= ~CHF_BATCHED; + if (vmbus_channel_open(sc->sc_chan, + HVKBD_TX_RING_SIZE + HVKBD_RX_RING_SIZE, NULL, 0, hvkbd_intr, sc)) { + aprint_error_dev(self, "failed to open channel\n"); + goto free_buf; + } + + if (hvkbd_connect(sc)) + goto free_buf; + + if (!pmf_device_register(self, NULL, NULL)) + aprint_error_dev(self, "couldn't establish power handler\n"); + + sc->sc_console_keyboard = hvkbd_is_console; + if (hvkbd_is_console) + hvkbd_is_console = 0; + + if (sc->sc_console_keyboard) { + wskbd_cnattach(&hvkbd_consops, sc, &hvkbd_keymapdata); + hvkbd_enable(sc, 1); + } + + a.console = sc->sc_console_keyboard; + a.keymap = &hvkbd_keymapdata; + a.accessops = &hvkbd_accessops; + a.accesscookie = sc; + sc->sc_wskbddev = config_found(self, &a, wskbddevprint); + return; + +free_buf: + if (sc->sc_buf != NULL) { + kmem_free(sc->sc_buf, HVKBD_BUFSIZE); + sc->sc_buf = NULL; + } + hvkbd_free_keybuf(sc); +} + +static int +hvkbd_alloc_keybuf(struct hvkbd_softc *sc) +{ + struct hvkbd_keystroke_info *ksi; + int i; + + for (i = 0; i < HVKBD_KEYBUF_SIZE; i++) { + ksi = kmem_zalloc(sizeof(*ksi), cold ? KM_NOSLEEP : KM_SLEEP); + if (ksi != NULL) { + LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link); + continue; + } + + while ((ksi = LIST_FIRST(&sc->sc_ks_free)) != NULL) { + LIST_REMOVE(ksi, link); + kmem_free(ksi, sizeof(*ksi)); + } + return ENOMEM; + + } + + return 0; +} + +static void +hvkbd_free_keybuf(struct hvkbd_softc *sc) +{ + struct hvkbd_keystroke_info *ksi; + + while ((ksi = STAILQ_FIRST(&sc->sc_ks_queue)) != NULL) { + STAILQ_REMOVE(&sc->sc_ks_queue, ksi, hvkbd_keystroke_info, + slink); + kmem_free(ksi, sizeof(*ksi)); + } + while ((ksi = LIST_FIRST(&sc->sc_ks_free)) != NULL) { + LIST_REMOVE(ksi, link); + kmem_free(ksi, sizeof(*ksi)); + } +} + +int +hvkbd_enable(void *v, int on) +{ + struct hvkbd_softc *sc = v; + + sc->sc_enabled = on; + + return 0; +} + +static void +hvkbd_set_leds(void *v, int leds) +{ +} + +static int +hvkbd_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) +{ + struct hvkbd_softc *sc = v; + + switch (cmd) { + case WSKBDIO_GTYPE: + *(int *)data = WSKBD_TYPE_HYPERV; + return 0; + + case WSKBDIO_SETLEDS: + hvkbd_set_leds(v, *(int *)data); + return 0; + + case WSKBDIO_GETLEDS: + *(int *)data = 0; + return 0; + +#if defined(WSDISPLAY_COMPAT_RAWKBD) + case WSKBDIO_SETMODE: + sc->sc_rawkbd = (*(int *)data == WSKBD_RAW); + return 0; +#endif + } + + return EPASSTHROUGH; +} + +static int +hvkbd_connect(struct hvkbd_softc *sc) +{ + struct hvkbd_proto_req req; + int timo = 100; + int error, s; + + sc->sc_connected = 0; + + memset(&req, 0, sizeof(req)); + req.hdr.type = HVKBD_PROTO_REQUEST; + req.ver = HVKBD_VERSION; + error = vmbus_channel_send(sc->sc_chan, &req, sizeof(req), + 0, VMBUS_CHANPKT_TYPE_INBAND, VMBUS_CHANPKT_FLAG_RC); + if (error) { + aprint_error_dev(sc->sc_dev, "failed to send connect: %d\n", + error); + return error; + } + + do { + if (cold) + delay(1000); + else + tsleep(sc, PRIBIO | PCATCH, "hvkbdcon", 1); + s = spltty(); + hvkbd_intr(sc); + splx(s); + } while (--timo > 0 && sc->sc_connected == 0); + + if (timo == 0 && sc->sc_connected == 0) { + aprint_error_dev(sc->sc_dev, "connect timed out\n"); + return ETIMEDOUT; + } + + if (!(sc->sc_connect_status & RESP_STATUS_ACCEPTED)) { + aprint_error_dev(sc->sc_dev, "protocol request failed\n"); + return ENODEV; + } + + return 0; +} + +static int +hvkbd_keybuf_add_keystroke(struct hvkbd_softc *sc, const struct keystroke *ks) +{ + struct hvkbd_keystroke_info *ksi; + + mutex_enter(&sc->sc_ks_lock); + ksi = LIST_FIRST(&sc->sc_ks_free); + if (ksi != NULL) { + LIST_REMOVE(ksi, link); + ksi->ks = *ks; + STAILQ_INSERT_TAIL(&sc->sc_ks_queue, ksi, slink); + } + mutex_exit(&sc->sc_ks_lock); + + return (ksi != NULL) ? 0 : 1; +} + +static int +hvkbd_decode(struct hvkbd_softc *sc, u_int *type, int *scancode) +{ + struct hvkbd_keystroke_info *ksi; + struct keystroke ks; + + mutex_enter(&sc->sc_ks_lock); + ksi = STAILQ_FIRST(&sc->sc_ks_queue); + if (ksi != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_ks_queue, slink); + ks = ksi->ks; + LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link); + } + mutex_exit(&sc->sc_ks_lock); + + if (ksi == NULL) + return 0; + + /* + * XXX: Hyper-V host send unicode to VM through 'Type clipboard text', + * the mapping from unicode to scancode depends on the keymap. + * It is so complicated that we do not plan to support it yet. + */ + if (ks.info & KS_INFO_UNICODE) + return 0; + + *type = (ks.info & KS_INFO_BREAK) ? + WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; + *scancode = ks.makecode; + return 1; +} + +static int +hvkbd_encode(struct hvkbd_softc *sc, u_char *buf, int *len) +{ + struct hvkbd_keystroke_info *ksi; + struct keystroke ks; + int i; + + mutex_enter(&sc->sc_ks_lock); + ksi = STAILQ_FIRST(&sc->sc_ks_queue); + if (ksi != NULL) { + STAILQ_REMOVE_HEAD(&sc->sc_ks_queue, slink); + ks = ksi->ks; + LIST_INSERT_HEAD(&sc->sc_ks_free, ksi, link); + } + mutex_exit(&sc->sc_ks_lock); + + if (ksi == NULL) + return 0; + + /* + * XXX: Hyper-V host send unicode to VM through 'Type clipboard text', + * the mapping from unicode to scancode depends on the keymap. + * It is so complicated that we do not plan to support it yet. + */ + if (ks.info & KS_INFO_UNICODE) + return 0; + + i = 0; + if (ks.info & (KS_INFO_E0|KS_INFO_E1)) { + if (ks.info & KS_INFO_E0) + buf[i++] = 0xe0; + else + buf[i++] = 0xe1; + } + if (ks.info & KS_INFO_BREAK) + buf[i++] = (u_char)ks.makecode & 0x80; + else + buf[i++] = (u_char)ks.makecode; + + KDASSERT(i <= *len); + *len = i; + + return 1; +} + +static void +hvkbd_intr(void *xsc) +{ + struct hvkbd_softc *sc = xsc; + struct vmbus_chanpkt_hdr *cph; + const struct hvkbd_msg_hdr *hdr; + const struct hvkbd_proto_resp *rsp; + const struct hvkbd_keystroke *ks; + uint64_t rid; + uint32_t rlen; + u_int type; + int key, error; + + for (;;) { + error = vmbus_channel_recv(sc->sc_chan, sc->sc_buf, + HVKBD_BUFSIZE, &rlen, &rid, 1); + if (error != 0 || rlen == 0) { + if (error != EAGAIN) + device_printf(sc->sc_dev, + "failed to receive a reply packet\n"); + return; + } + + cph = (struct vmbus_chanpkt_hdr *)sc->sc_buf; + switch (cph->cph_type) { + case VMBUS_CHANPKT_TYPE_INBAND: + hdr = VMBUS_CHANPKT_CONST_DATA(cph); + if (rlen < sizeof(*hdr)) { + device_printf(sc->sc_dev, "Illegal packet\n"); + continue; + } + + switch (hdr->type) { + case HVKBD_PROTO_RESPONSE: + if (!sc->sc_connected) { + rsp = VMBUS_CHANPKT_CONST_DATA(cph); + if (rlen < sizeof(*rsp)) { + device_printf(sc->sc_dev, + "Illegal resp packet\n"); + break; + } + sc->sc_connect_status = rsp->status; + sc->sc_connected = 1; + wakeup(sc); + } + break; + + case HVKBD_PROTO_EVENT: + if (sc->sc_wskbddev == NULL || !sc->sc_enabled) + break; + + ks = VMBUS_CHANPKT_CONST_DATA(cph); + hvkbd_keybuf_add_keystroke(sc, &ks->ks); + if (sc->sc_polling) + break; + +#if defined(WSDISPLAY_COMPAT_RAWKBD) + if (sc->sc_rawkbd) { + u_char buf[2]; + int len; + + len = sizeof(buf); + if (hvkbd_encode(sc, buf, &len)) { + wskbd_rawinput(sc->sc_wskbddev, + buf, len); + } + break; + } +#endif + if (hvkbd_decode(sc, &type, &key)) + wskbd_input(sc->sc_wskbddev, type, key); + break; + + case HVKBD_PROTO_REQUEST: + case HVKBD_PROTO_LED_INDICATORS: + device_printf(sc->sc_dev, + "unhandled message: %d\n", hdr->type); + break; + + default: + device_printf(sc->sc_dev, + "unknown message: %d\n", hdr->type); + break; + } + break; + + case VMBUS_CHANPKT_TYPE_COMP: + case VMBUS_CHANPKT_TYPE_RXBUF: + device_printf(sc->sc_dev, "unhandled event: %d\n", + cph->cph_type); + break; + + default: + device_printf(sc->sc_dev, "unknown event: %d\n", + cph->cph_type); + break; + } + } +} + +int +hvkbd_cnattach(void) +{ + + hvkbd_is_console = 1; + + return 0; +} + +static void +hvkbd_cngetc(void *v, u_int *type, int *data) +{ + struct hvkbd_softc *sc = v; + + while (!hvkbd_decode(sc, type, data)) + hvkbd_intr(sc); +} + +static void +hvkbd_cnpollc(void *v, int on) +{ + struct hvkbd_softc *sc = v; + + sc->sc_polling = on; +} + +MODULE(MODULE_CLASS_DRIVER, hvkbd, "vmbus"); + +#ifdef _MODULE +#include "ioconf.c" +#endif + +static int +hvkbd_modcmd(modcmd_t cmd, void *aux) +{ + int error = 0; + + switch (cmd) { + case MODULE_CMD_INIT: +#ifdef _MODULE + error = config_init_component(cfdriver_ioconf_hvkbd, + cfattach_ioconf_hvkbd, cfdata_ioconf_hvkbd); +#endif + break; + + case MODULE_CMD_FINI: +#ifdef _MODULE + error = config_fini_component(cfdriver_ioconf_hvtkbd, + cfattach_ioconf_hvkbd, cfdata_ioconf_hvkbd); +#endif + break; + + case MODULE_CMD_AUTOUNLOAD: + error = EBUSY; + break; + + default: + error = ENOTTY; + break; + } + + return error; +} Index: src/sys/dev/hyperv/hvkbdvar.h diff -u /dev/null src/sys/dev/hyperv/hvkbdvar.h:1.1 --- /dev/null Fri May 24 14:28:49 2019 +++ src/sys/dev/hyperv/hvkbdvar.h Fri May 24 14:28:48 2019 @@ -0,0 +1,8 @@ +/* $NetBSD: hvkbdvar.h,v 1.1 2019/05/24 14:28:48 nonaka Exp $ */ + +#ifndef _DEV_HYPERV_HVKBDVAR_H_ +#define _DEV_HYPERV_HVKBDVAR_H_ + +int hvkbd_cnattach(void); + +#endif /* _DEV_HYPERV_HVKBDVAR_H_ */