def _virtual_hv(osdata):
    '''
    Returns detailed hypervisor information from sysfs
    Currently this seems to be used only by Xen
    '''
    grains = {}

    # Bail early if we're not running on Xen
    try:
        if 'xen' not in osdata['virtual']:
            return grains
    except KeyError:
        return grains

    # Try to get the exact hypervisor version from sysfs
    try:
        version = {}
        for fn in ('major', 'minor', 'extra'):
            with salt.utils.files.fopen('/sys/hypervisor/version/{}'.format(fn), 'r') as fhr:
                version[fn] = salt.utils.stringutils.to_unicode(fhr.read().strip())
        grains['virtual_hv_version'] = '{}.{}{}'.format(version['major'], version['minor'], version['extra'])
        grains['virtual_hv_version_info'] = [version['major'], version['minor'], version['extra']]
    except (IOError, OSError, KeyError):
        pass

    # Try to read and decode the supported feature set of the hypervisor
    # Based on https://github.com/brendangregg/Misc/blob/master/xen/xen-features.py
    # Table data from include/xen/interface/features.h
    xen_feature_table = {0: 'writable_page_tables',
                         1: 'writable_descriptor_tables',
                         2: 'auto_translated_physmap',
                         3: 'supervisor_mode_kernel',
                         4: 'pae_pgdir_above_4gb',
                         5: 'mmu_pt_update_preserve_ad',
                         7: 'gnttab_map_avail_bits',
                         8: 'hvm_callback_vector',
                         9: 'hvm_safe_pvclock',
                        10: 'hvm_pirqs',
                        11: 'dom0',
                        12: 'grant_map_identity',
                        13: 'memory_op_vnode_supported',
                        14: 'ARM_SMCCC_supported'}
    try:
        with salt.utils.files.fopen('/sys/hypervisor/properties/features', 'r') as fhr:
            features = salt.utils.stringutils.to_unicode(fhr.read().strip())
        enabled_features = []
        for bit, feat in six.iteritems(xen_feature_table):
            if int(features, 16) & (1 << bit):
                enabled_features.append(feat)
        grains['virtual_hv_features'] = features
        grains['virtual_hv_features_list'] = enabled_features
    except (IOError, OSError, KeyError):
        pass

    return grains
Returns detailed hypervisor information from sysfs
    Currently this seems to be used only by Xen