Index: head/sys/conf/options =================================================================== --- head/sys/conf/options (revision 345437) +++ head/sys/conf/options (revision 345438) @@ -1,1019 +1,1022 @@ # $FreeBSD$ # # On the handling of kernel options # # All kernel options should be listed in NOTES, with suitable # descriptions. Negative options (options that make some code not # compile) should be commented out; LINT (generated from NOTES) should # compile as much code as possible. Try to structure option-using # code so that a single option only switch code on, or only switch # code off, to make it possible to have a full compile-test. If # necessary, you can check for COMPILING_LINT to get maximum code # coverage. # # All new options shall also be listed in either "conf/options" or # "conf/options.". Options that affect a single source-file # .[c|s] should be directed into "opt_.h", while options # that affect multiple files should either go in "opt_global.h" if # this is a kernel-wide option (used just about everywhere), or in # "opt_.h" if it affects only some files. # Note that the effect of listing only an option without a # header-file-name in conf/options (and cousins) is that the last # convention is followed. # # This handling scheme is not yet fully implemented. # # # Format of this file: # Option name filename # # If filename is missing, the default is # opt_.h AAC_DEBUG opt_aac.h AACRAID_DEBUG opt_aacraid.h AHC_ALLOW_MEMIO opt_aic7xxx.h AHC_TMODE_ENABLE opt_aic7xxx.h AHC_DUMP_EEPROM opt_aic7xxx.h AHC_DEBUG opt_aic7xxx.h AHC_DEBUG_OPTS opt_aic7xxx.h AHC_REG_PRETTY_PRINT opt_aic7xxx.h AHD_DEBUG opt_aic79xx.h AHD_DEBUG_OPTS opt_aic79xx.h AHD_TMODE_ENABLE opt_aic79xx.h AHD_REG_PRETTY_PRINT opt_aic79xx.h TWA_DEBUG opt_twa.h # Debugging options. ALT_BREAK_TO_DEBUGGER opt_kdb.h BREAK_TO_DEBUGGER opt_kdb.h BUF_TRACKING opt_global.h DDB DDB_BUFR_SIZE opt_ddb.h DDB_CAPTURE_DEFAULTBUFSIZE opt_ddb.h DDB_CAPTURE_MAXBUFSIZE opt_ddb.h DDB_CTF opt_ddb.h DDB_NUMSYM opt_ddb.h FULL_BUF_TRACKING opt_global.h GDB KDB opt_global.h KDB_TRACE opt_kdb.h KDB_UNATTENDED opt_kdb.h KLD_DEBUG opt_kld.h SYSCTL_DEBUG opt_sysctl.h EARLY_PRINTF opt_global.h TEXTDUMP_PREFERRED opt_ddb.h TEXTDUMP_VERBOSE opt_ddb.h NUM_CORE_FILES opt_global.h TSLOG opt_global.h TSLOGSIZE opt_global.h # Miscellaneous options. ALQ ALTERA_SDCARD_FAST_SIM opt_altera_sdcard.h ATSE_CFI_HACK opt_cfi.h AUDIT opt_global.h BOOTHOWTO opt_global.h BOOTVERBOSE opt_global.h CALLOUT_PROFILING CAPABILITIES opt_capsicum.h CAPABILITY_MODE opt_capsicum.h COMPAT_43 opt_global.h COMPAT_43TTY opt_global.h COMPAT_FREEBSD4 opt_global.h COMPAT_FREEBSD5 opt_global.h COMPAT_FREEBSD6 opt_global.h COMPAT_FREEBSD7 opt_global.h COMPAT_FREEBSD9 opt_global.h COMPAT_FREEBSD10 opt_global.h COMPAT_FREEBSD11 opt_global.h COMPAT_CLOUDABI32 opt_dontuse.h COMPAT_CLOUDABI64 opt_dontuse.h COMPAT_LINUXKPI opt_dontuse.h _COMPAT_LINUX32 opt_compat.h # XXX: make sure opt_compat.h exists COMPILING_LINT opt_global.h CY_PCI_FASTINTR DEADLKRES opt_watchdog.h EXPERIMENTAL opt_global.h EXT_RESOURCES opt_global.h DIRECTIO FILEMON opt_dontuse.h FFCLOCK FULL_PREEMPTION opt_sched.h GZIO opt_gzio.h IMAGACT_BINMISC opt_dontuse.h IPI_PREEMPTION opt_sched.h GEOM_BDE opt_geom.h GEOM_BSD opt_geom.h GEOM_CACHE opt_geom.h GEOM_CONCAT opt_geom.h GEOM_ELI opt_geom.h GEOM_FOX opt_geom.h GEOM_GATE opt_geom.h GEOM_JOURNAL opt_geom.h GEOM_LABEL opt_geom.h GEOM_LABEL_GPT opt_geom.h GEOM_LINUX_LVM opt_geom.h GEOM_MAP opt_geom.h GEOM_MBR opt_geom.h GEOM_MIRROR opt_geom.h GEOM_MOUNTVER opt_geom.h GEOM_MULTIPATH opt_geom.h GEOM_NOP opt_geom.h GEOM_PART_APM opt_geom.h GEOM_PART_BSD opt_geom.h GEOM_PART_BSD64 opt_geom.h GEOM_PART_EBR opt_geom.h GEOM_PART_EBR_COMPAT opt_geom.h GEOM_PART_GPT opt_geom.h GEOM_PART_LDM opt_geom.h GEOM_PART_MBR opt_geom.h GEOM_PART_VTOC8 opt_geom.h GEOM_RAID opt_geom.h GEOM_RAID3 opt_geom.h GEOM_SHSEC opt_geom.h GEOM_STRIPE opt_geom.h GEOM_SUNLABEL opt_geom.h GEOM_UZIP opt_geom.h GEOM_UZIP_DEBUG opt_geom.h GEOM_VINUM opt_geom.h GEOM_VIRSTOR opt_geom.h GEOM_VOL opt_geom.h GEOM_ZERO opt_geom.h IFLIB opt_iflib.h KDTRACE_HOOKS opt_global.h KDTRACE_FRAME opt_kdtrace.h KN_HASHSIZE opt_kqueue.h KSTACK_MAX_PAGES KSTACK_PAGES KSTACK_USAGE_PROF KTRACE KTRACE_REQUEST_POOL opt_ktrace.h LIBICONV MAC opt_global.h MAC_BIBA opt_dontuse.h MAC_BSDEXTENDED opt_dontuse.h MAC_IFOFF opt_dontuse.h MAC_LOMAC opt_dontuse.h MAC_MLS opt_dontuse.h MAC_NONE opt_dontuse.h MAC_NTPD opt_dontuse.h MAC_PARTITION opt_dontuse.h MAC_PORTACL opt_dontuse.h MAC_SEEOTHERUIDS opt_dontuse.h MAC_STATIC opt_mac.h MAC_STUB opt_dontuse.h MAC_TEST opt_dontuse.h MAC_VERIEXEC opt_dontuse.h MAC_VERIEXEC_SHA1 opt_dontuse.h MAC_VERIEXEC_SHA256 opt_dontuse.h MAC_VERIEXEC_SHA384 opt_dontuse.h MAC_VERIEXEC_SHA512 opt_dontuse.h MD_ROOT opt_md.h MD_ROOT_FSTYPE opt_md.h MD_ROOT_READONLY opt_md.h MD_ROOT_SIZE opt_md.h MD_ROOT_MEM opt_md.h MFI_DEBUG opt_mfi.h MFI_DECODE_LOG opt_mfi.h MPROF_BUFFERS opt_mprof.h MPROF_HASH_SIZE opt_mprof.h NEW_PCIB opt_global.h NO_ADAPTIVE_MUTEXES opt_adaptive_mutexes.h NO_ADAPTIVE_RWLOCKS NO_ADAPTIVE_SX NO_EVENTTIMERS opt_timer.h NO_OBSOLETE_CODE opt_global.h NO_SYSCTL_DESCR opt_global.h NSWBUF_MIN opt_param.h MBUF_PACKET_ZONE_DISABLE opt_global.h PANIC_REBOOT_WAIT_TIME opt_panic.h PCI_HP opt_pci.h PCI_IOV opt_global.h PPC_DEBUG opt_ppc.h PPC_PROBE_CHIPSET opt_ppc.h PPS_SYNC opt_ntp.h PREEMPTION opt_sched.h QUOTA SCHED_4BSD opt_sched.h SCHED_STATS opt_sched.h SCHED_ULE opt_sched.h SLEEPQUEUE_PROFILING SLHCI_DEBUG opt_slhci.h STACK opt_stack.h SUIDDIR MSGMNB opt_sysvipc.h MSGMNI opt_sysvipc.h MSGSEG opt_sysvipc.h MSGSSZ opt_sysvipc.h MSGTQL opt_sysvipc.h SEMMNI opt_sysvipc.h SEMMNS opt_sysvipc.h SEMMNU opt_sysvipc.h SEMMSL opt_sysvipc.h SEMOPM opt_sysvipc.h SEMUME opt_sysvipc.h SHMALL opt_sysvipc.h SHMMAX opt_sysvipc.h SHMMAXPGS opt_sysvipc.h SHMMIN opt_sysvipc.h SHMMNI opt_sysvipc.h SHMSEG opt_sysvipc.h SYSVMSG opt_sysvipc.h SYSVSEM opt_sysvipc.h SYSVSHM opt_sysvipc.h SW_WATCHDOG opt_watchdog.h TCPHPTS opt_inet.h TURNSTILE_PROFILING UMTX_PROFILING UMTX_CHAINS opt_global.h VERBOSE_SYSINIT ZSTDIO opt_zstdio.h # Sanitizers COVERAGE opt_global.h KCOV KUBSAN opt_global.h # POSIX kernel options P1003_1B_MQUEUE opt_posix.h P1003_1B_SEMAPHORES opt_posix.h _KPOSIX_PRIORITY_SCHEDULING opt_posix.h # Do we want the config file compiled into the kernel? INCLUDE_CONFIG_FILE opt_config.h # Options for static filesystems. These should only be used at config # time, since the corresponding lkms cannot work if there are any static # dependencies. Unusability is enforced by hiding the defines for the # options in a never-included header. AUTOFS opt_dontuse.h CD9660 opt_dontuse.h EXT2FS opt_dontuse.h FDESCFS opt_dontuse.h FFS opt_dontuse.h FUSEFS opt_dontuse.h MSDOSFS opt_dontuse.h NANDFS opt_dontuse.h NULLFS opt_dontuse.h PROCFS opt_dontuse.h PSEUDOFS opt_dontuse.h SMBFS opt_dontuse.h TMPFS opt_dontuse.h UDF opt_dontuse.h UNIONFS opt_dontuse.h ZFS opt_dontuse.h # Pseudofs debugging PSEUDOFS_TRACE opt_pseudofs.h # In-kernel GSS-API KGSSAPI opt_kgssapi.h KGSSAPI_DEBUG opt_kgssapi.h # These static filesystems have one slightly bogus static dependency in # sys/i386/i386/autoconf.c. If any of these filesystems are # statically compiled into the kernel, code for mounting them as root # filesystems will be enabled - but look below. # NFSCL - client # NFSD - server NFSCL opt_nfs.h NFSD opt_nfs.h # filesystems and libiconv bridge CD9660_ICONV opt_dontuse.h MSDOSFS_ICONV opt_dontuse.h UDF_ICONV opt_dontuse.h # If you are following the conditions in the copyright, # you can enable soft-updates which will speed up a lot of thigs # and make the system safer from crashes at the same time. # otherwise a STUB module will be compiled in. SOFTUPDATES opt_ffs.h # On small, embedded systems, it can be useful to turn off support for # snapshots. It saves about 30-40k for a feature that would be lightly # used, if it is used at all. NO_FFS_SNAPSHOT opt_ffs.h # Enabling this option turns on support for Access Control Lists in UFS, # which can be used to support high security configurations. Depends on # UFS_EXTATTR. UFS_ACL opt_ufs.h # Enabling this option turns on support for extended attributes in UFS-based # filesystems, which can be used to support high security configurations # as well as new filesystem features. UFS_EXTATTR opt_ufs.h UFS_EXTATTR_AUTOSTART opt_ufs.h # Enable fast hash lookups for large directories on UFS-based filesystems. UFS_DIRHASH opt_ufs.h # Enable gjournal-based UFS journal. UFS_GJOURNAL opt_ufs.h # The below sentence is not in English, and neither is this one. # We plan to remove the static dependences above, with a # _ROOT option to control if it usable as root. This list # allows these options to be present in config files already (though # they won't make any difference yet). NFS_ROOT opt_nfsroot.h # SMB/CIFS requester NETSMB opt_netsmb.h # Enable netdump(4) client support. NETDUMP opt_global.h # Options used only in subr_param.c. HZ opt_param.h MAXFILES opt_param.h NBUF opt_param.h NSFBUFS opt_param.h VM_BCACHE_SIZE_MAX opt_param.h VM_SWZONE_SIZE_MAX opt_param.h MAXUSERS DFLDSIZ opt_param.h MAXDSIZ opt_param.h MAXSSIZ opt_param.h # Generic SCSI options. CAM_MAX_HIGHPOWER opt_cam.h CAMDEBUG opt_cam.h CAM_DEBUG_COMPILE opt_cam.h CAM_DEBUG_DELAY opt_cam.h CAM_DEBUG_BUS opt_cam.h CAM_DEBUG_TARGET opt_cam.h CAM_DEBUG_LUN opt_cam.h CAM_DEBUG_FLAGS opt_cam.h CAM_BOOT_DELAY opt_cam.h CAM_IOSCHED_DYNAMIC opt_cam.h CAM_TEST_FAILURE opt_cam.h SCSI_DELAY opt_scsi.h SCSI_NO_SENSE_STRINGS opt_scsi.h SCSI_NO_OP_STRINGS opt_scsi.h # Options used only in cam/ata/ata_da.c ATA_STATIC_ID opt_ada.h # Options used only in cam/scsi/scsi_cd.c CHANGER_MIN_BUSY_SECONDS opt_cd.h CHANGER_MAX_BUSY_SECONDS opt_cd.h # Options used only in cam/scsi/scsi_da.c DA_TRACK_REFS opt_da.h # Options used only in cam/scsi/scsi_sa.c. SA_IO_TIMEOUT opt_sa.h SA_SPACE_TIMEOUT opt_sa.h SA_REWIND_TIMEOUT opt_sa.h SA_ERASE_TIMEOUT opt_sa.h SA_1FM_AT_EOD opt_sa.h # Options used only in cam/scsi/scsi_pt.c SCSI_PT_DEFAULT_TIMEOUT opt_pt.h # Options used only in cam/scsi/scsi_ses.c SES_ENABLE_PASSTHROUGH opt_ses.h # Options used in dev/sym/ (Symbios SCSI driver). SYM_SETUP_SCSI_DIFF opt_sym.h #-HVD support for 825a, 875, 885 # disabled:0 (default), enabled:1 SYM_SETUP_PCI_PARITY opt_sym.h #-PCI parity checking # disabled:0, enabled:1 (default) SYM_SETUP_MAX_LUN opt_sym.h #-Number of LUNs supported # default:8, range:[1..64] # Options used only in dev/isp/* ISP_TARGET_MODE opt_isp.h ISP_FW_CRASH_DUMP opt_isp.h ISP_DEFAULT_ROLES opt_isp.h ISP_INTERNAL_TARGET opt_isp.h ISP_FCTAPE_OFF opt_isp.h # Options used only in dev/iscsi ISCSI_INITIATOR_DEBUG opt_iscsi_initiator.h # Net stuff. ACCEPT_FILTER_DATA ACCEPT_FILTER_DNS ACCEPT_FILTER_HTTP ALTQ opt_global.h ALTQ_CBQ opt_altq.h ALTQ_CDNR opt_altq.h ALTQ_CODEL opt_altq.h ALTQ_DEBUG opt_altq.h ALTQ_HFSC opt_altq.h ALTQ_FAIRQ opt_altq.h ALTQ_NOPCC opt_altq.h ALTQ_PRIQ opt_altq.h ALTQ_RED opt_altq.h ALTQ_RIO opt_altq.h BOOTP opt_bootp.h BOOTP_BLOCKSIZE opt_bootp.h BOOTP_COMPAT opt_bootp.h BOOTP_NFSROOT opt_bootp.h BOOTP_NFSV3 opt_bootp.h BOOTP_WIRED_TO opt_bootp.h DEVICE_POLLING DUMMYNET opt_ipdn.h RATELIMIT opt_ratelimit.h RATELIMIT_DEBUG opt_ratelimit.h INET opt_inet.h INET6 opt_inet6.h IPDIVERT IPFILTER opt_ipfilter.h IPFILTER_DEFAULT_BLOCK opt_ipfilter.h IPFILTER_LOG opt_ipfilter.h IPFILTER_LOOKUP opt_ipfilter.h IPFIREWALL opt_ipfw.h IPFIREWALL_DEFAULT_TO_ACCEPT opt_ipfw.h IPFIREWALL_NAT opt_ipfw.h IPFIREWALL_NAT64 opt_ipfw.h IPFIREWALL_NPTV6 opt_ipfw.h IPFIREWALL_VERBOSE opt_ipfw.h IPFIREWALL_VERBOSE_LIMIT opt_ipfw.h IPFIREWALL_PMOD opt_ipfw.h IPSEC opt_ipsec.h IPSEC_DEBUG opt_ipsec.h IPSEC_SUPPORT opt_ipsec.h IPSTEALTH KRPC LIBALIAS LIBMCHAIN MBUF_PROFILING MBUF_STRESS_TEST MROUTING opt_mrouting.h NFSLOCKD PCBGROUP opt_pcbgroup.h PF_DEFAULT_TO_DROP opt_pf.h RADIX_MPATH opt_mpath.h ROUTETABLES opt_route.h RSS opt_rss.h SLIP_IFF_OPTS opt_slip.h TCPDEBUG TCPPCAP opt_global.h SIFTR TCP_BLACKBOX opt_global.h TCP_HHOOK opt_inet.h TCP_OFFLOAD opt_inet.h # Enable code to dispatch TCP offloading TCP_RFC7413 opt_inet.h TCP_RFC7413_MAX_KEYS opt_inet.h TCP_RFC7413_MAX_PSKS opt_inet.h TCP_SIGNATURE opt_ipsec.h VLAN_ARRAY opt_vlan.h XBONEHACK # # SCTP # SCTP opt_sctp.h SCTP_DEBUG opt_sctp.h # Enable debug printfs SCTP_LOCK_LOGGING opt_sctp.h # Log to KTR lock activity SCTP_MBUF_LOGGING opt_sctp.h # Log to KTR general mbuf aloc/free SCTP_MBCNT_LOGGING opt_sctp.h # Log to KTR mbcnt activity SCTP_PACKET_LOGGING opt_sctp.h # Log to a packet buffer last N packets SCTP_LTRACE_CHUNKS opt_sctp.h # Log to KTR chunks processed SCTP_LTRACE_ERRORS opt_sctp.h # Log to KTR error returns. SCTP_USE_PERCPU_STAT opt_sctp.h # Use per cpu stats. SCTP_MCORE_INPUT opt_sctp.h # Have multiple input threads for input mbufs SCTP_LOCAL_TRACE_BUF opt_sctp.h # Use tracebuffer exported via sysctl SCTP_DETAILED_STR_STATS opt_sctp.h # Use per PR-SCTP policy stream stats # # # # Netgraph(4). Use option NETGRAPH to enable the base netgraph code. # Each netgraph node type can be either be compiled into the kernel # or loaded dynamically. To get the former, include the corresponding # option below. Each type has its own man page, e.g. ng_async(4). NETGRAPH NETGRAPH_DEBUG opt_netgraph.h NETGRAPH_ASYNC opt_netgraph.h NETGRAPH_ATMLLC opt_netgraph.h NETGRAPH_ATM_ATMPIF opt_netgraph.h NETGRAPH_BLUETOOTH opt_netgraph.h NETGRAPH_BLUETOOTH_BT3C opt_netgraph.h NETGRAPH_BLUETOOTH_H4 opt_netgraph.h NETGRAPH_BLUETOOTH_HCI opt_netgraph.h NETGRAPH_BLUETOOTH_L2CAP opt_netgraph.h NETGRAPH_BLUETOOTH_SOCKET opt_netgraph.h NETGRAPH_BLUETOOTH_UBT opt_netgraph.h NETGRAPH_BLUETOOTH_UBTBCMFW opt_netgraph.h NETGRAPH_BPF opt_netgraph.h NETGRAPH_BRIDGE opt_netgraph.h NETGRAPH_CAR opt_netgraph.h NETGRAPH_CHECKSUM opt_netgraph.h NETGRAPH_CISCO opt_netgraph.h NETGRAPH_DEFLATE opt_netgraph.h NETGRAPH_DEVICE opt_netgraph.h NETGRAPH_ECHO opt_netgraph.h NETGRAPH_EIFACE opt_netgraph.h NETGRAPH_ETHER opt_netgraph.h NETGRAPH_ETHER_ECHO opt_netgraph.h NETGRAPH_FEC opt_netgraph.h NETGRAPH_FRAME_RELAY opt_netgraph.h NETGRAPH_GIF opt_netgraph.h NETGRAPH_GIF_DEMUX opt_netgraph.h NETGRAPH_HOLE opt_netgraph.h NETGRAPH_IFACE opt_netgraph.h NETGRAPH_IP_INPUT opt_netgraph.h NETGRAPH_IPFW opt_netgraph.h NETGRAPH_KSOCKET opt_netgraph.h NETGRAPH_L2TP opt_netgraph.h NETGRAPH_LMI opt_netgraph.h NETGRAPH_MPPC_COMPRESSION opt_netgraph.h NETGRAPH_MPPC_ENCRYPTION opt_netgraph.h NETGRAPH_NAT opt_netgraph.h NETGRAPH_NETFLOW opt_netgraph.h NETGRAPH_ONE2MANY opt_netgraph.h NETGRAPH_PATCH opt_netgraph.h NETGRAPH_PIPE opt_netgraph.h NETGRAPH_PPP opt_netgraph.h NETGRAPH_PPPOE opt_netgraph.h NETGRAPH_PPTPGRE opt_netgraph.h NETGRAPH_PRED1 opt_netgraph.h NETGRAPH_RFC1490 opt_netgraph.h NETGRAPH_SOCKET opt_netgraph.h NETGRAPH_SPLIT opt_netgraph.h NETGRAPH_SPPP opt_netgraph.h NETGRAPH_TAG opt_netgraph.h NETGRAPH_TCPMSS opt_netgraph.h NETGRAPH_TEE opt_netgraph.h NETGRAPH_TTY opt_netgraph.h NETGRAPH_UI opt_netgraph.h NETGRAPH_VJC opt_netgraph.h NETGRAPH_VLAN opt_netgraph.h # NgATM options NGATM_ATM opt_netgraph.h NGATM_ATMBASE opt_netgraph.h NGATM_SSCOP opt_netgraph.h NGATM_SSCFU opt_netgraph.h NGATM_UNI opt_netgraph.h NGATM_CCATM opt_netgraph.h # DRM options DRM_DEBUG opt_drm.h TI_SF_BUF_JUMBO opt_ti.h TI_JUMBO_HDRSPLIT opt_ti.h # Misc debug flags. Most of these should probably be replaced with # 'DEBUG', and then let people recompile just the interesting modules # with 'make CC="cc -DDEBUG"'. CLUSTERDEBUG opt_debug_cluster.h DEBUG_1284 opt_ppb_1284.h VP0_DEBUG opt_vpo.h LPT_DEBUG opt_lpt.h PLIP_DEBUG opt_plip.h LOCKF_DEBUG opt_debug_lockf.h SI_DEBUG opt_debug_si.h IFMEDIA_DEBUG opt_ifmedia.h # Fb options FB_DEBUG opt_fb.h FB_INSTALL_CDEV opt_fb.h # ppbus related options PERIPH_1284 opt_ppb_1284.h DONTPROBE_1284 opt_ppb_1284.h # smbus related options ENABLE_ALART opt_intpm.h # These cause changes all over the kernel BLKDEV_IOSIZE opt_global.h BURN_BRIDGES opt_global.h DEBUG opt_global.h DEBUG_LOCKS opt_global.h DEBUG_VFS_LOCKS opt_global.h DFLTPHYS opt_global.h DIAGNOSTIC opt_global.h INVARIANT_SUPPORT opt_global.h INVARIANTS opt_global.h KASSERT_PANIC_OPTIONAL opt_global.h MAXCPU opt_global.h MAXMEMDOM opt_global.h MAXPHYS opt_global.h MCLSHIFT opt_global.h MUTEX_NOINLINE opt_global.h LOCK_PROFILING opt_global.h LOCK_PROFILING_FAST opt_global.h MSIZE opt_global.h REGRESSION opt_global.h RWLOCK_NOINLINE opt_global.h SX_NOINLINE opt_global.h VFS_BIO_DEBUG opt_global.h # These are VM related options VM_KMEM_SIZE opt_vm.h VM_KMEM_SIZE_SCALE opt_vm.h VM_KMEM_SIZE_MAX opt_vm.h VM_NRESERVLEVEL opt_vm.h VM_LEVEL_0_ORDER opt_vm.h NO_SWAPPING opt_vm.h MALLOC_MAKE_FAILURES opt_vm.h MALLOC_PROFILE opt_vm.h MALLOC_DEBUG_MAXZONES opt_vm.h # The MemGuard replacement allocator used for tamper-after-free detection DEBUG_MEMGUARD opt_vm.h # The RedZone malloc(9) protection DEBUG_REDZONE opt_vm.h # Standard SMP options EARLY_AP_STARTUP opt_global.h SMP opt_global.h NUMA opt_global.h # Size of the kernel message buffer MSGBUF_SIZE opt_msgbuf.h # NFS options NFS_MINATTRTIMO opt_nfs.h NFS_MAXATTRTIMO opt_nfs.h NFS_MINDIRATTRTIMO opt_nfs.h NFS_MAXDIRATTRTIMO opt_nfs.h NFS_DEBUG opt_nfs.h # For the Bt848/Bt848A/Bt849/Bt878/Bt879 driver OVERRIDE_CARD opt_bktr.h OVERRIDE_TUNER opt_bktr.h OVERRIDE_DBX opt_bktr.h OVERRIDE_MSP opt_bktr.h BROOKTREE_SYSTEM_DEFAULT opt_bktr.h BROOKTREE_ALLOC_PAGES opt_bktr.h BKTR_OVERRIDE_CARD opt_bktr.h BKTR_OVERRIDE_TUNER opt_bktr.h BKTR_OVERRIDE_DBX opt_bktr.h BKTR_OVERRIDE_MSP opt_bktr.h BKTR_SYSTEM_DEFAULT opt_bktr.h BKTR_ALLOC_PAGES opt_bktr.h BKTR_USE_PLL opt_bktr.h BKTR_GPIO_ACCESS opt_bktr.h BKTR_NO_MSP_RESET opt_bktr.h BKTR_430_FX_MODE opt_bktr.h BKTR_SIS_VIA_MODE opt_bktr.h BKTR_USE_FREEBSD_SMBUS opt_bktr.h BKTR_NEW_MSP34XX_DRIVER opt_bktr.h # Options for uart(4) UART_PPS_ON_CTS opt_uart.h UART_POLL_FREQ opt_uart.h UART_DEV_TOLERANCE_PCT opt_uart.h # options for bus/device framework BUS_DEBUG opt_bus.h # options for USB support USB_DEBUG opt_usb.h USB_HOST_ALIGN opt_usb.h USB_REQ_DEBUG opt_usb.h USB_TEMPLATE opt_usb.h USB_VERBOSE opt_usb.h USB_DMA_SINGLE_ALLOC opt_usb.h USB_EHCI_BIG_ENDIAN_DESC opt_usb.h U3G_DEBUG opt_u3g.h UKBD_DFLT_KEYMAP opt_ukbd.h UPLCOM_INTR_INTERVAL opt_uplcom.h UVSCOM_DEFAULT_OPKTSIZE opt_uvscom.h UVSCOM_INTR_INTERVAL opt_uvscom.h # options for the Realtek rtwn driver RTWN_DEBUG opt_rtwn.h RTWN_WITHOUT_UCODE opt_rtwn.h # Embedded system options INIT_PATH ROOTDEVNAME FDC_DEBUG opt_fdc.h PCFCLOCK_VERBOSE opt_pcfclock.h PCFCLOCK_MAX_RETRIES opt_pcfclock.h KTR opt_global.h KTR_ALQ opt_ktr.h KTR_MASK opt_ktr.h KTR_CPUMASK opt_ktr.h KTR_COMPILE opt_global.h KTR_BOOT_ENTRIES opt_global.h KTR_ENTRIES opt_global.h KTR_VERBOSE opt_ktr.h WITNESS opt_global.h WITNESS_KDB opt_witness.h WITNESS_NO_VNODE opt_witness.h WITNESS_SKIPSPIN opt_witness.h WITNESS_COUNT opt_witness.h OPENSOLARIS_WITNESS opt_global.h # options for ACPI support ACPI_DEBUG opt_acpi.h ACPI_MAX_TASKS opt_acpi.h ACPI_MAX_THREADS opt_acpi.h ACPI_DMAR opt_acpi.h DEV_ACPI opt_acpi.h # ISA support DEV_ISA opt_isa.h ISAPNP opt_isa.h # various 'device presence' options. DEV_BPF opt_bpf.h DEV_CARP opt_carp.h DEV_NETMAP opt_global.h DEV_PCI opt_pci.h DEV_PF opt_pf.h DEV_PFLOG opt_pf.h DEV_PFSYNC opt_pf.h DEV_RANDOM opt_global.h DEV_SPLASH opt_splash.h DEV_VLAN opt_vlan.h # ed driver ED_HPP opt_ed.h ED_3C503 opt_ed.h ED_SIC opt_ed.h # bce driver BCE_DEBUG opt_bce.h BCE_NVRAM_WRITE_SUPPORT opt_bce.h SOCKBUF_DEBUG opt_global.h # options for ubsec driver UBSEC_DEBUG opt_ubsec.h UBSEC_RNDTEST opt_ubsec.h UBSEC_NO_RNG opt_ubsec.h # options for hifn driver HIFN_DEBUG opt_hifn.h HIFN_RNDTEST opt_hifn.h # options for safenet driver SAFE_DEBUG opt_safe.h SAFE_NO_RNG opt_safe.h SAFE_RNDTEST opt_safe.h # syscons/vt options MAXCONS opt_syscons.h SC_ALT_MOUSE_IMAGE opt_syscons.h SC_CUT_SPACES2TABS opt_syscons.h SC_CUT_SEPCHARS opt_syscons.h SC_DEBUG_LEVEL opt_syscons.h SC_DFLT_FONT opt_syscons.h SC_DFLT_TERM opt_syscons.h SC_DISABLE_KDBKEY opt_syscons.h SC_DISABLE_REBOOT opt_syscons.h SC_HISTORY_SIZE opt_syscons.h SC_KERNEL_CONS_ATTR opt_syscons.h SC_KERNEL_CONS_ATTRS opt_syscons.h SC_KERNEL_CONS_REV_ATTR opt_syscons.h SC_MOUSE_CHAR opt_syscons.h SC_NO_CUTPASTE opt_syscons.h SC_NO_FONT_LOADING opt_syscons.h SC_NO_HISTORY opt_syscons.h SC_NO_MODE_CHANGE opt_syscons.h SC_NO_SUSPEND_VTYSWITCH opt_syscons.h SC_NO_SYSMOUSE opt_syscons.h SC_NO_TERM_DUMB opt_syscons.h SC_NO_TERM_SC opt_syscons.h SC_NO_TERM_TEKEN opt_syscons.h SC_NORM_ATTR opt_syscons.h SC_NORM_REV_ATTR opt_syscons.h SC_PIXEL_MODE opt_syscons.h SC_RENDER_DEBUG opt_syscons.h SC_TWOBUTTON_MOUSE opt_syscons.h VT_ALT_TO_ESC_HACK opt_syscons.h VT_FB_DEFAULT_WIDTH opt_syscons.h VT_FB_DEFAULT_HEIGHT opt_syscons.h VT_MAXWINDOWS opt_syscons.h VT_TWOBUTTON_MOUSE opt_syscons.h DEV_SC opt_syscons.h DEV_VT opt_syscons.h # teken terminal emulator options TEKEN_CONS25 opt_teken.h TEKEN_UTF8 opt_teken.h TERMINAL_KERN_ATTR opt_teken.h TERMINAL_NORM_ATTR opt_teken.h # options for printf PRINTF_BUFR_SIZE opt_printf.h BOOT_TAG opt_printf.h BOOT_TAG_SZ opt_printf.h # kbd options KBD_DISABLE_KEYMAP_LOAD opt_kbd.h KBD_INSTALL_CDEV opt_kbd.h KBD_MAXRETRY opt_kbd.h KBD_MAXWAIT opt_kbd.h KBD_RESETDELAY opt_kbd.h KBDIO_DEBUG opt_kbd.h KBDMUX_DFLT_KEYMAP opt_kbdmux.h # options for the Atheros driver ATH_DEBUG opt_ath.h ATH_TXBUF opt_ath.h ATH_RXBUF opt_ath.h ATH_DIAGAPI opt_ath.h ATH_TX99_DIAG opt_ath.h ATH_ENABLE_11N opt_ath.h ATH_ENABLE_DFS opt_ath.h ATH_EEPROM_FIRMWARE opt_ath.h ATH_ENABLE_RADIOTAP_VENDOR_EXT opt_ath.h ATH_DEBUG_ALQ opt_ath.h ATH_KTR_INTR_DEBUG opt_ath.h # options for the Atheros hal # XXX For now, this breaks non-AR9130 chipsets, so only use it # XXX when actually targeting AR9130. AH_SUPPORT_AR9130 opt_ah.h # This is required for AR933x SoC support AH_SUPPORT_AR9330 opt_ah.h AH_SUPPORT_AR9340 opt_ah.h AH_SUPPORT_QCA9530 opt_ah.h AH_SUPPORT_QCA9550 opt_ah.h AH_DEBUG opt_ah.h AH_ASSERT opt_ah.h AH_DEBUG_ALQ opt_ah.h AH_REGOPS_FUNC opt_ah.h AH_WRITE_REGDOMAIN opt_ah.h AH_DEBUG_COUNTRY opt_ah.h AH_WRITE_EEPROM opt_ah.h AH_PRIVATE_DIAG opt_ah.h AH_NEED_DESC_SWAP opt_ah.h AH_USE_INIPDGAIN opt_ah.h AH_MAXCHAN opt_ah.h AH_RXCFG_SDMAMW_4BYTES opt_ah.h AH_INTERRUPT_DEBUGGING opt_ah.h # AR5416 and later interrupt mitigation # XXX do not use this for AR9130 AH_AR5416_INTERRUPT_MITIGATION opt_ah.h # options for the Broadcom BCM43xx driver (bwi) BWI_DEBUG opt_bwi.h BWI_DEBUG_VERBOSE opt_bwi.h # options for the Brodacom BCM43xx driver (bwn) BWN_DEBUG opt_bwn.h BWN_GPL_PHY opt_bwn.h BWN_USE_SIBA opt_bwn.h # Options for the SIBA driver SIBA_DEBUG opt_siba.h # options for the Marvell 8335 wireless driver MALO_DEBUG opt_malo.h MALO_TXBUF opt_malo.h MALO_RXBUF opt_malo.h # options for the Marvell wireless driver MWL_DEBUG opt_mwl.h MWL_TXBUF opt_mwl.h MWL_RXBUF opt_mwl.h MWL_DIAGAPI opt_mwl.h MWL_AGGR_SIZE opt_mwl.h MWL_TX_NODROP opt_mwl.h # Options for the Marvell NETA driver MVNETA_MULTIQUEUE opt_mvneta.h MVNETA_KTR opt_mvneta.h # Options for the Intel 802.11ac wireless driver IWM_DEBUG opt_iwm.h # Options for the Intel 802.11n wireless driver IWN_DEBUG opt_iwn.h # Options for the Intel 3945ABG wireless driver WPI_DEBUG opt_wpi.h # dcons options DCONS_BUF_SIZE opt_dcons.h DCONS_POLL_HZ opt_dcons.h DCONS_FORCE_CONSOLE opt_dcons.h DCONS_FORCE_GDB opt_dcons.h # HWPMC options HWPMC_DEBUG opt_global.h HWPMC_HOOKS HWPMC_MIPS_BACKTRACE opt_hwpmc_hooks.h # 802.11 support layer IEEE80211_DEBUG opt_wlan.h IEEE80211_DEBUG_REFCNT opt_wlan.h IEEE80211_SUPPORT_MESH opt_wlan.h IEEE80211_SUPPORT_SUPERG opt_wlan.h IEEE80211_SUPPORT_TDMA opt_wlan.h IEEE80211_ALQ opt_wlan.h IEEE80211_DFS_DEBUG opt_wlan.h # 802.11 TDMA support TDMA_SLOTLEN_DEFAULT opt_tdma.h TDMA_SLOTCNT_DEFAULT opt_tdma.h TDMA_BINTVAL_DEFAULT opt_tdma.h TDMA_TXRATE_11B_DEFAULT opt_tdma.h TDMA_TXRATE_11G_DEFAULT opt_tdma.h TDMA_TXRATE_11A_DEFAULT opt_tdma.h TDMA_TXRATE_TURBO_DEFAULT opt_tdma.h TDMA_TXRATE_HALF_DEFAULT opt_tdma.h TDMA_TXRATE_QUARTER_DEFAULT opt_tdma.h TDMA_TXRATE_11NA_DEFAULT opt_tdma.h TDMA_TXRATE_11NG_DEFAULT opt_tdma.h # VideoMode PICKMODE_DEBUG opt_videomode.h # Network stack virtualization options VIMAGE opt_global.h VNET_DEBUG opt_global.h # Common Flash Interface (CFI) options CFI_SUPPORT_STRATAFLASH opt_cfi.h CFI_ARMEDANDDANGEROUS opt_cfi.h CFI_HARDWAREBYTESWAP opt_cfi.h # Sound options SND_DEBUG opt_snd.h SND_DIAGNOSTIC opt_snd.h SND_FEEDER_MULTIFORMAT opt_snd.h SND_FEEDER_FULL_MULTIFORMAT opt_snd.h SND_FEEDER_RATE_HP opt_snd.h SND_PCM_64 opt_snd.h SND_OLDSTEREO opt_snd.h X86BIOS # Flattened device tree options FDT opt_platform.h FDT_DTB_STATIC opt_platform.h # OFED Infiniband stack OFED opt_ofed.h OFED_DEBUG_INIT opt_ofed.h SDP opt_ofed.h SDP_DEBUG opt_ofed.h IPOIB opt_ofed.h IPOIB_DEBUG opt_ofed.h IPOIB_CM opt_ofed.h # Resource Accounting RACCT opt_global.h RACCT_DEFAULT_TO_DISABLED opt_global.h # Resource Limits RCTL opt_global.h # Random number generator(s) # With this, no entropy processor is loaded, but the entropy # harvesting infrastructure is present. This means an entropy # processor may be loaded as a module. RANDOM_LOADABLE opt_global.h # This turns on high-rate and potentially expensive harvesting in # the uma slab allocator. RANDOM_ENABLE_UMA opt_global.h RANDOM_ENABLE_ETHER opt_global.h +# This options turns TPM into entropy source. +TPM_HARVEST opt_tpm.h + # BHND(4) driver BHND_LOGLEVEL opt_global.h # GPIO and child devices GPIO_SPI_DEBUG opt_gpio.h # SPI devices SPIGEN_LEGACY_CDEVNAME opt_spi.h # etherswitch(4) driver RTL8366_SOFT_RESET opt_etherswitch.h # evdev protocol support EVDEV_SUPPORT opt_evdev.h EVDEV_DEBUG opt_evdev.h UINPUT_DEBUG opt_evdev.h # Hyper-V network driver HN_DEBUG opt_hn.h # CAM-based MMC stack MMCCAM # Encrypted kernel crash dumps EKCD opt_ekcd.h # NVME options NVME_USE_NVD opt_nvme.h # amdsbwd options AMDSBWD_DEBUG opt_amdsbwd.h # gcov support GCOV opt_global.h LINDEBUGFS Index: head/sys/dev/random/random_harvestq.c =================================================================== --- head/sys/dev/random/random_harvestq.c (revision 345437) +++ head/sys/dev/random/random_harvestq.c (revision 345438) @@ -1,560 +1,561 @@ /*- * Copyright (c) 2017 Oliver Pinter * Copyright (c) 2017 W. Dean Freeman * Copyright (c) 2000-2015 Mark R V Murray * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2004 Robert N. M. Watson * 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 * in this position and unchanged. * 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. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(RANDOM_LOADABLE) #include #include #endif #include #include #include #include #include #include #include #if defined(RANDOM_ENABLE_ETHER) #define _RANDOM_HARVEST_ETHER_OFF 0 #else #define _RANDOM_HARVEST_ETHER_OFF (1u << RANDOM_NET_ETHER) #endif #if defined(RANDOM_ENABLE_UMA) #define _RANDOM_HARVEST_UMA_OFF 0 #else #define _RANDOM_HARVEST_UMA_OFF (1u << RANDOM_UMA) #endif static void random_kthread(void); static void random_sources_feed(void); static u_int read_rate; /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; /* * How many events to queue up. We create this many items in * an 'empty' queue, then transfer them to the 'harvest' queue with * supplied junk. When used, they are transferred back to the * 'empty' queue. */ #define RANDOM_RING_MAX 1024 #define RANDOM_ACCUM_MAX 8 /* 1 to let the kernel thread run, 0 to terminate, -1 to mark completion */ volatile int random_kthread_control; /* Allow the sysadmin to select the broad category of * entropy types to harvest. */ __read_frequently u_int hc_source_mask; /* * Put all the harvest queue context stuff in one place. * this make is a bit easier to lock and protect. */ static struct harvest_context { /* The harvest mutex protects all of harvest_context and * the related data. */ struct mtx hc_mtx; /* Round-robin destination cache. */ u_int hc_destination[ENTROPYSOURCE]; /* The context of the kernel thread processing harvested entropy */ struct proc *hc_kthread_proc; /* * Lockless ring buffer holding entropy events * If ring.in == ring.out, * the buffer is empty. * If ring.in != ring.out, * the buffer contains harvested entropy. * If (ring.in + 1) == ring.out (mod RANDOM_RING_MAX), * the buffer is full. * * NOTE: ring.in points to the last added element, * and ring.out points to the last consumed element. * * The ring.in variable needs locking as there are multiple * sources to the ring. Only the sources may change ring.in, * but the consumer may examine it. * * The ring.out variable does not need locking as there is * only one consumer. Only the consumer may change ring.out, * but the sources may examine it. */ struct entropy_ring { struct harvest_event ring[RANDOM_RING_MAX]; volatile u_int in; volatile u_int out; } hc_entropy_ring; struct fast_entropy_accumulator { volatile u_int pos; uint32_t buf[RANDOM_ACCUM_MAX]; } hc_entropy_fast_accumulator; } harvest_context; static struct kproc_desc random_proc_kp = { "rand_harvestq", random_kthread, &harvest_context.hc_kthread_proc, }; /* Pass the given event straight through to Fortuna/Whatever. */ static __inline void random_harvestq_fast_process_event(struct harvest_event *event) { #if defined(RANDOM_LOADABLE) RANDOM_CONFIG_S_LOCK(); if (p_random_alg_context) #endif p_random_alg_context->ra_event_processor(event); #if defined(RANDOM_LOADABLE) RANDOM_CONFIG_S_UNLOCK(); #endif } static void random_kthread(void) { u_int maxloop, ring_out, i; /* * Locking is not needed as this is the only place we modify ring.out, and * we only examine ring.in without changing it. Both of these are volatile, * and this is a unique thread. */ for (random_kthread_control = 1; random_kthread_control;) { /* Deal with events, if any. Restrict the number we do in one go. */ maxloop = RANDOM_RING_MAX; while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) { ring_out = (harvest_context.hc_entropy_ring.out + 1)%RANDOM_RING_MAX; random_harvestq_fast_process_event(harvest_context.hc_entropy_ring.ring + ring_out); harvest_context.hc_entropy_ring.out = ring_out; if (!--maxloop) break; } random_sources_feed(); /* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */ for (i = 0; i < RANDOM_ACCUM_MAX; i++) { if (harvest_context.hc_entropy_fast_accumulator.buf[i]) { random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA); harvest_context.hc_entropy_fast_accumulator.buf[i] = 0; } } /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */ tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1)); } random_kthread_control = -1; wakeup(&harvest_context.hc_kthread_proc); kproc_exit(0); /* NOTREACHED */ } /* This happens well after SI_SUB_RANDOM */ SYSINIT(random_device_h_proc, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, kproc_start, &random_proc_kp); /* * Run through all fast sources reading entropy for the given * number of rounds, which should be a multiple of the number * of entropy accumulation pools in use; it is 32 for Fortuna. */ static void random_sources_feed(void) { uint32_t entropy[HARVESTSIZE]; struct random_sources *rrs; u_int i, n, local_read_rate; /* * Step over all of live entropy sources, and feed their output * to the system-wide RNG. */ #if defined(RANDOM_LOADABLE) RANDOM_CONFIG_S_LOCK(); if (p_random_alg_context) { /* It's an indenting error. Yeah, Yeah. */ #endif local_read_rate = atomic_readandclear_32(&read_rate); /* Perform at least one read per round */ local_read_rate = MAX(local_read_rate, 1); /* But not exceeding RANDOM_KEYSIZE_WORDS */ local_read_rate = MIN(local_read_rate, RANDOM_KEYSIZE_WORDS); LIST_FOREACH(rrs, &source_list, rrs_entries) { for (i = 0; i < p_random_alg_context->ra_poolcount*local_read_rate; i++) { n = rrs->rrs_source->rs_read(entropy, sizeof(entropy)); KASSERT((n <= sizeof(entropy)), ("%s: rs_read returned too much data (%u > %zu)", __func__, n, sizeof(entropy))); /* It would appear that in some circumstances (e.g. virtualisation), * the underlying hardware entropy source might not always return * random numbers. Accept this but make a noise. If too much happens, * can that source be trusted? */ if (n == 0) { printf("%s: rs_read for hardware device '%s' returned no entropy.\n", __func__, rrs->rrs_source->rs_ident); continue; } random_harvest_direct(entropy, n, rrs->rrs_source->rs_source); } } explicit_bzero(entropy, sizeof(entropy)); #if defined(RANDOM_LOADABLE) } RANDOM_CONFIG_S_UNLOCK(); #endif } void read_rate_increment(u_int chunk) { atomic_add_32(&read_rate, chunk); } /* ARGSUSED */ static int random_check_uint_harvestmask(SYSCTL_HANDLER_ARGS) { static const u_int user_immutable_mask = (((1 << ENTROPYSOURCE) - 1) & (-1UL << RANDOM_PURE_START)) | _RANDOM_HARVEST_ETHER_OFF | _RANDOM_HARVEST_UMA_OFF; int error; u_int value, orig_value; orig_value = value = hc_source_mask; error = sysctl_handle_int(oidp, &value, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (flsl(value) > ENTROPYSOURCE) return (EINVAL); /* * Disallow userspace modification of pure entropy sources. */ hc_source_mask = (value & ~user_immutable_mask) | (orig_value & user_immutable_mask); return (0); } /* ARGSUSED */ static int random_print_harvestmask(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; int error, i; error = sysctl_wire_old_buffer(req, 0); if (error == 0) { sbuf_new_for_sysctl(&sbuf, NULL, 128, req); for (i = ENTROPYSOURCE - 1; i >= 0; i--) sbuf_cat(&sbuf, (hc_source_mask & (1 << i)) ? "1" : "0"); error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); } return (error); } static const char *random_source_descr[ENTROPYSOURCE] = { [RANDOM_CACHED] = "CACHED", [RANDOM_ATTACH] = "ATTACH", [RANDOM_KEYBOARD] = "KEYBOARD", [RANDOM_MOUSE] = "MOUSE", [RANDOM_NET_TUN] = "NET_TUN", [RANDOM_NET_ETHER] = "NET_ETHER", [RANDOM_NET_NG] = "NET_NG", [RANDOM_INTERRUPT] = "INTERRUPT", [RANDOM_SWI] = "SWI", [RANDOM_FS_ATIME] = "FS_ATIME", [RANDOM_UMA] = "UMA", /* ENVIRONMENTAL_END */ [RANDOM_PURE_OCTEON] = "PURE_OCTEON", /* PURE_START */ [RANDOM_PURE_SAFE] = "PURE_SAFE", [RANDOM_PURE_GLXSB] = "PURE_GLXSB", [RANDOM_PURE_UBSEC] = "PURE_UBSEC", [RANDOM_PURE_HIFN] = "PURE_HIFN", [RANDOM_PURE_RDRAND] = "PURE_RDRAND", [RANDOM_PURE_NEHEMIAH] = "PURE_NEHEMIAH", [RANDOM_PURE_RNDTEST] = "PURE_RNDTEST", [RANDOM_PURE_VIRTIO] = "PURE_VIRTIO", [RANDOM_PURE_BROADCOM] = "PURE_BROADCOM", [RANDOM_PURE_CCP] = "PURE_CCP", [RANDOM_PURE_DARN] = "PURE_DARN", + [RANDOM_PURE_TPM] = "PURE_TPM", /* "ENTROPYSOURCE" */ }; /* ARGSUSED */ static int random_print_harvestmask_symbolic(SYSCTL_HANDLER_ARGS) { struct sbuf sbuf; int error, i; bool first; first = true; error = sysctl_wire_old_buffer(req, 0); if (error == 0) { sbuf_new_for_sysctl(&sbuf, NULL, 128, req); for (i = ENTROPYSOURCE - 1; i >= 0; i--) { if (i >= RANDOM_PURE_START && (hc_source_mask & (1 << i)) == 0) continue; if (!first) sbuf_cat(&sbuf, ","); sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "[" : ""); sbuf_cat(&sbuf, random_source_descr[i]); sbuf_cat(&sbuf, !(hc_source_mask & (1 << i)) ? "]" : ""); first = false; } error = sbuf_finish(&sbuf); sbuf_delete(&sbuf); } return (error); } /* ARGSUSED */ static void random_harvestq_init(void *unused __unused) { static const u_int almost_everything_mask = (((1 << (RANDOM_ENVIRONMENTAL_END + 1)) - 1) & ~_RANDOM_HARVEST_ETHER_OFF & ~_RANDOM_HARVEST_UMA_OFF); struct sysctl_oid *random_sys_o; random_sys_o = SYSCTL_ADD_NODE(&random_clist, SYSCTL_STATIC_CHILDREN(_kern_random), OID_AUTO, "harvest", CTLFLAG_RW, 0, "Entropy Device Parameters"); hc_source_mask = almost_everything_mask; SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "mask", CTLTYPE_UINT | CTLFLAG_RW, NULL, 0, random_check_uint_harvestmask, "IU", "Entropy harvesting mask"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "mask_bin", CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, random_print_harvestmask, "A", "Entropy harvesting mask (printable)"); SYSCTL_ADD_PROC(&random_clist, SYSCTL_CHILDREN(random_sys_o), OID_AUTO, "mask_symbolic", CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, random_print_harvestmask_symbolic, "A", "Entropy harvesting mask (symbolic)"); RANDOM_HARVEST_INIT_LOCK(); harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0; } SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL); /* * This is used to prime the RNG by grabbing any early random stuff * known to the kernel, and inserting it directly into the hashing * module, currently Fortuna. */ /* ARGSUSED */ static void random_harvestq_prime(void *unused __unused) { struct harvest_event event; size_t count, size, i; uint8_t *keyfile, *data; /* * Get entropy that may have been preloaded by loader(8) * and use it to pre-charge the entropy harvest queue. */ keyfile = preload_search_by_type(RANDOM_CACHED_BOOT_ENTROPY_MODULE); #ifndef NO_BACKWARD_COMPATIBILITY if (keyfile == NULL) keyfile = preload_search_by_type(RANDOM_LEGACY_BOOT_ENTROPY_MODULE); #endif if (keyfile != NULL) { data = preload_fetch_addr(keyfile); size = preload_fetch_size(keyfile); /* skip the first bit of the stash so others like arc4 can also have some. */ if (size > RANDOM_CACHED_SKIP_START) { data += RANDOM_CACHED_SKIP_START; size -= RANDOM_CACHED_SKIP_START; } /* Trim the size. If the admin has a file with a funny size, we lose some. Tough. */ size -= (size % sizeof(event.he_entropy)); if (data != NULL && size != 0) { for (i = 0; i < size; i += sizeof(event.he_entropy)) { count = sizeof(event.he_entropy); event.he_somecounter = (uint32_t)get_cyclecount(); event.he_size = count; event.he_source = RANDOM_CACHED; event.he_destination = harvest_context.hc_destination[RANDOM_CACHED]++; memcpy(event.he_entropy, data + i, sizeof(event.he_entropy)); random_harvestq_fast_process_event(&event); explicit_bzero(&event, sizeof(event)); } explicit_bzero(data, size); if (bootverbose) printf("random: read %zu bytes from preloaded cache\n", size); } else if (bootverbose) printf("random: no preloaded entropy cache\n"); } } SYSINIT(random_device_prime, SI_SUB_RANDOM, SI_ORDER_FOURTH, random_harvestq_prime, NULL); /* ARGSUSED */ static void random_harvestq_deinit(void *unused __unused) { /* Command the hash/reseed thread to end and wait for it to finish */ random_kthread_control = 0; while (random_kthread_control >= 0) tsleep(&harvest_context.hc_kthread_proc, 0, "harvqterm", hz/5); sysctl_ctx_free(&random_clist); } SYSUNINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_deinit, NULL); /*- * Entropy harvesting queue routine. * * This is supposed to be fast; do not do anything slow in here! * It is also illegal (and morally reprehensible) to insert any * high-rate data here. "High-rate" is defined as a data source * that will usually cause lots of failures of the "Lockless read" * check a few lines below. This includes the "always-on" sources * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. */ /* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle * counters are built in, but on older hardware it will do a real time clock * read which can be quite expensive. */ void random_harvest_queue_(const void *entropy, u_int size, enum random_entropy_source origin) { struct harvest_event *event; u_int ring_in; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); RANDOM_HARVEST_LOCK(); ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX; if (ring_in != harvest_context.hc_entropy_ring.out) { /* The ring is not full */ event = harvest_context.hc_entropy_ring.ring + ring_in; event->he_somecounter = (uint32_t)get_cyclecount(); event->he_source = origin; event->he_destination = harvest_context.hc_destination[origin]++; if (size <= sizeof(event->he_entropy)) { event->he_size = size; memcpy(event->he_entropy, entropy, size); } else { /* Big event, so squash it */ event->he_size = sizeof(event->he_entropy[0]); event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event); } harvest_context.hc_entropy_ring.in = ring_in; } RANDOM_HARVEST_UNLOCK(); } /*- * Entropy harvesting fast routine. * * This is supposed to be very fast; do not do anything slow in here! * This is the right place for high-rate harvested data. */ void random_harvest_fast_(const void *entropy, u_int size) { u_int pos; pos = harvest_context.hc_entropy_fast_accumulator.pos; harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, size, (uint32_t)get_cyclecount()); harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX; } /*- * Entropy harvesting direct routine. * * This is not supposed to be fast, but will only be used during * (e.g.) booting when initial entropy is being gathered. */ void random_harvest_direct_(const void *entropy, u_int size, enum random_entropy_source origin) { struct harvest_event event; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); size = MIN(size, sizeof(event.he_entropy)); event.he_somecounter = (uint32_t)get_cyclecount(); event.he_size = size; event.he_source = origin; event.he_destination = harvest_context.hc_destination[origin]++; memcpy(event.he_entropy, entropy, size); random_harvestq_fast_process_event(&event); explicit_bzero(&event, sizeof(event)); } void random_harvest_register_source(enum random_entropy_source source) { hc_source_mask |= (1 << source); } void random_harvest_deregister_source(enum random_entropy_source source) { hc_source_mask &= ~(1 << source); } MODULE_VERSION(random_harvestq, 1); Index: head/sys/dev/tpm/tpm20.c =================================================================== --- head/sys/dev/tpm/tpm20.c (revision 345437) +++ head/sys/dev/tpm/tpm20.c (revision 345438) @@ -1,276 +1,350 @@ /*- * Copyright (c) 2018 Stormshield. * Copyright (c) 2018 Semihalf. * 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 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. */ #include __FBSDID("$FreeBSD$"); +#include + #include "tpm20.h" +#define TPM_HARVEST_SIZE 16 +/* + * Perform a harvest every 10 seconds. + * Since discrete TPMs are painfully slow + * we don't want to execute this too often + * as the chip is likely to be used by others too. + */ +#define TPM_HARVEST_INTERVAL 10000000 + MALLOC_DECLARE(M_TPM20); MALLOC_DEFINE(M_TPM20, "tpm_buffer", "buffer for tpm 2.0 driver"); static void tpm20_discard_buffer(void *arg); -static int tpm20_save_state(device_t dev, bool suspend); +#ifdef TPM_HARVEST +static void tpm20_harvest(void *arg); +#endif +static int tpm20_save_state(device_t dev, bool suspend); static d_open_t tpm20_open; static d_close_t tpm20_close; static d_read_t tpm20_read; static d_write_t tpm20_write; static d_ioctl_t tpm20_ioctl; static struct cdevsw tpm20_cdevsw = { .d_version = D_VERSION, .d_open = tpm20_open, .d_close = tpm20_close, .d_read = tpm20_read, .d_write = tpm20_write, .d_ioctl = tpm20_ioctl, .d_name = "tpm20", }; int tpm20_read(struct cdev *dev, struct uio *uio, int flags) { struct tpm_sc *sc; size_t bytes_to_transfer; int result = 0; sc = (struct tpm_sc *)dev->si_drv1; callout_stop(&sc->discard_buffer_callout); sx_xlock(&sc->dev_lock); bytes_to_transfer = MIN(sc->pending_data_length, uio->uio_resid); if (bytes_to_transfer > 0) { result = uiomove((caddr_t) sc->buf, bytes_to_transfer, uio); memset(sc->buf, 0, TPM_BUFSIZE); sc->pending_data_length = 0; cv_signal(&sc->buf_cv); } else { result = ETIMEDOUT; } sx_xunlock(&sc->dev_lock); return (result); } int tpm20_write(struct cdev *dev, struct uio *uio, int flags) { struct tpm_sc *sc; size_t byte_count; int result = 0; sc = (struct tpm_sc *)dev->si_drv1; byte_count = uio->uio_resid; if (byte_count < TPM_HEADER_SIZE) { device_printf(sc->dev, "Requested transfer is too small\n"); return (EINVAL); } if (byte_count > TPM_BUFSIZE) { device_printf(sc->dev, "Requested transfer is too large\n"); return (E2BIG); } sx_xlock(&sc->dev_lock); while (sc->pending_data_length != 0) cv_wait(&sc->buf_cv, &sc->dev_lock); result = uiomove(sc->buf, byte_count, uio); if (result != 0) { sx_xunlock(&sc->dev_lock); return (result); } result = sc->transmit(sc, byte_count); if (result == 0) callout_reset(&sc->discard_buffer_callout, TPM_READ_TIMEOUT / tick, tpm20_discard_buffer, sc); sx_xunlock(&sc->dev_lock); return (result); } static void tpm20_discard_buffer(void *arg) { struct tpm_sc *sc; sc = (struct tpm_sc *)arg; if (callout_pending(&sc->discard_buffer_callout)) return; sx_xlock(&sc->dev_lock); memset(sc->buf, 0, TPM_BUFSIZE); sc->pending_data_length = 0; cv_signal(&sc->buf_cv); sx_xunlock(&sc->dev_lock); device_printf(sc->dev, "User failed to read buffer in time\n"); } int tpm20_open(struct cdev *dev, int flag, int mode, struct thread *td) { return (0); } int tpm20_close(struct cdev *dev, int flag, int mode, struct thread *td) { return (0); } int tpm20_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { return (ENOTTY); } int tpm20_init(struct tpm_sc *sc) { struct make_dev_args args; int result; sc->buf = malloc(TPM_BUFSIZE, M_TPM20, M_WAITOK); sx_init(&sc->dev_lock, "TPM driver lock"); cv_init(&sc->buf_cv, "TPM buffer cv"); callout_init(&sc->discard_buffer_callout, 1); +#ifdef TPM_HARVEST + sc->harvest_ticks = TPM_HARVEST_INTERVAL / tick; + callout_init(&sc->harvest_callout, 1); + callout_reset(&sc->harvest_callout, 0, tpm20_harvest, sc); +#endif sc->pending_data_length = 0; make_dev_args_init(&args); args.mda_devsw = &tpm20_cdevsw; args.mda_uid = UID_ROOT; args.mda_gid = GID_WHEEL; args.mda_mode = TPM_CDEV_PERM_FLAG; args.mda_si_drv1 = sc; result = make_dev_s(&args, &sc->sc_cdev, TPM_CDEV_NAME); if (result != 0) tpm20_release(sc); return (result); } void tpm20_release(struct tpm_sc *sc) { +#ifdef TPM_HARVEST + callout_drain(&sc->harvest_callout); +#endif + if (sc->buf != NULL) free(sc->buf, M_TPM20); sx_destroy(&sc->dev_lock); cv_destroy(&sc->buf_cv); if (sc->sc_cdev != NULL) destroy_dev(sc->sc_cdev); } int tpm20_suspend(device_t dev) { return (tpm20_save_state(dev, true)); } int tpm20_shutdown(device_t dev) { return (tpm20_save_state(dev, false)); } + +#ifdef TPM_HARVEST + +/* + * Get TPM_HARVEST_SIZE random bytes and add them + * into system entropy pool. + */ +static void +tpm20_harvest(void *arg) +{ + struct tpm_sc *sc; + unsigned char entropy[TPM_HARVEST_SIZE]; + uint16_t entropy_size; + int result; + uint8_t cmd[] = { + 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ + 0x00, 0x00, 0x00, 0x0c, /* cmd length */ + 0x00, 0x00, 0x01, 0x7b, /* cmd TPM_CC_GetRandom */ + 0x00, TPM_HARVEST_SIZE /* number of bytes requested */ + }; + + + sc = arg; + sx_xlock(&sc->dev_lock); + + memcpy(sc->buf, cmd, sizeof(cmd)); + result = sc->transmit(sc, sizeof(cmd)); + if (result != 0) { + sx_xunlock(&sc->dev_lock); + return; + } + + /* Ignore response size */ + sc->pending_data_length = 0; + + /* The number of random bytes we got is placed right after the header */ + entropy_size = (uint16_t) sc->buf[TPM_HEADER_SIZE + 1]; + if (entropy_size > 0) { + entropy_size = MIN(entropy_size, TPM_HARVEST_SIZE); + memcpy(entropy, + sc->buf + TPM_HEADER_SIZE + sizeof(uint16_t), + entropy_size); + } + + sx_xunlock(&sc->dev_lock); + if (entropy_size > 0) + random_harvest_queue(entropy, entropy_size, RANDOM_PURE_TPM); + + callout_reset(&sc->harvest_callout, sc->harvest_ticks, tpm20_harvest, sc); +} +#endif /* TPM_HARVEST */ static int tpm20_save_state(device_t dev, bool suspend) { struct tpm_sc *sc; uint8_t save_cmd[] = { 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/ 0x00, 0x00, 0x00, 0x0C, /* cmd length */ 0x00, 0x00, 0x01, 0x45, 0x00, 0x00 /* cmd TPM_CC_Shutdown */ }; sc = device_get_softc(dev); /* * Inform the TPM whether we are going to suspend or reboot/shutdown. */ if (suspend) save_cmd[11] = 1; /* TPM_SU_STATE */ if (sc == NULL || sc->buf == NULL) return (0); sx_xlock(&sc->dev_lock); memcpy(sc->buf, save_cmd, sizeof(save_cmd)); sc->transmit(sc, sizeof(save_cmd)); sx_xunlock(&sc->dev_lock); return (0); } int32_t tpm20_get_timeout(uint32_t command) { int32_t timeout; switch (command) { case TPM_CC_CreatePrimary: case TPM_CC_Create: case TPM_CC_CreateLoaded: timeout = TPM_TIMEOUT_LONG; break; case TPM_CC_SequenceComplete: case TPM_CC_Startup: case TPM_CC_SequenceUpdate: case TPM_CC_GetCapability: case TPM_CC_PCR_Extend: case TPM_CC_EventSequenceComplete: case TPM_CC_HashSequenceStart: timeout = TPM_TIMEOUT_C; break; default: timeout = TPM_TIMEOUT_B; break; } return timeout; } Index: head/sys/dev/tpm/tpm20.h =================================================================== --- head/sys/dev/tpm/tpm20.h (revision 345437) +++ head/sys/dev/tpm/tpm20.h (revision 345438) @@ -1,184 +1,190 @@ /*- * Copyright (c) 2018 Stormshield. * Copyright (c) 2018 Semihalf. * 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 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 _TPM20_H_ #define _TPM20_H_ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "opt_acpi.h" +#include "opt_tpm.h" + #define BIT(x) (1 << (x)) /* Timeouts in us */ #define TPM_TIMEOUT_A 750000 #define TPM_TIMEOUT_B 2000000 #define TPM_TIMEOUT_C 200000 #define TPM_TIMEOUT_D 30000 /* * Generating RSA key pair takes ~(10-20s), which is significantly longer than * any timeout defined in spec. Because of that we need a new one. */ #define TPM_TIMEOUT_LONG 40000000 /* List of commands that require TPM_TIMEOUT_LONG time to complete */ #define TPM_CC_CreatePrimary 0x00000131 #define TPM_CC_Create 0x00000153 #define TPM_CC_CreateLoaded 0x00000191 /* List of commands that require only TPM_TIMEOUT_C time to complete */ #define TPM_CC_SequenceComplete 0x0000013e #define TPM_CC_Startup 0x00000144 #define TPM_CC_SequenceUpdate 0x0000015c #define TPM_CC_GetCapability 0x0000017a #define TPM_CC_PCR_Extend 0x00000182 #define TPM_CC_EventSequenceComplete 0x00000185 #define TPM_CC_HashSequenceStart 0x00000186 /* Timeout before data in read buffer is discarded */ #define TPM_READ_TIMEOUT 500000 #define TPM_BUFSIZE 0x1000 #define TPM_HEADER_SIZE 10 #define TPM_CDEV_NAME "tpm0" #define TPM_CDEV_PERM_FLAG 0600 #define TPM2_START_METHOD_ACPI 2 #define TPM2_START_METHOD_TIS 6 #define TPM2_START_METHOD_CRB 7 #define TPM2_START_METHOD_CRB_ACPI 8 struct tpm_sc { device_t dev; struct resource *mem_res; struct resource *irq_res; int mem_rid; int irq_rid; struct cdev *sc_cdev; struct sx dev_lock; struct cv buf_cv; void *intr_cookie; int intr_type; /* Current event type */ bool interrupts; uint8_t *buf; size_t pending_data_length; struct callout discard_buffer_callout; +#ifdef TPM_HARVEST + struct callout harvest_callout; + int harvest_ticks; +#endif int (*transmit)(struct tpm_sc *, size_t); }; int tpm20_suspend(device_t dev); int tpm20_shutdown(device_t dev); int32_t tpm20_get_timeout(uint32_t command); int tpm20_init(struct tpm_sc *sc); void tpm20_release(struct tpm_sc *sc); /* Small helper routines for io ops */ static inline uint8_t RD1(struct tpm_sc *sc, bus_size_t off) { return (bus_read_1(sc->mem_res, off)); } static inline uint32_t RD4(struct tpm_sc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off)); } #ifdef __amd64__ static inline uint64_t RD8(struct tpm_sc *sc, bus_size_t off) { return (bus_read_8(sc->mem_res, off)); } #endif static inline void WR1(struct tpm_sc *sc, bus_size_t off, uint8_t val) { bus_write_1(sc->mem_res, off, val); } static inline void WR4(struct tpm_sc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } static inline void AND4(struct tpm_sc *sc, bus_size_t off, uint32_t val) { WR4(sc, off, RD4(sc, off) & val); } static inline void OR1(struct tpm_sc *sc, bus_size_t off, uint8_t val) { WR1(sc, off, RD1(sc, off) | val); } static inline void OR4(struct tpm_sc *sc, bus_size_t off, uint32_t val) { WR4(sc, off, RD4(sc, off) | val); } #endif /* _TPM20_H_ */ Index: head/sys/dev/tpm/tpm_crb.c =================================================================== --- head/sys/dev/tpm/tpm_crb.c (revision 345437) +++ head/sys/dev/tpm/tpm_crb.c (revision 345438) @@ -1,419 +1,420 @@ /*- * Copyright (c) 2018 Stormshield. * Copyright (c) 2018 Semihalf. * 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 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. */ #include __FBSDID("$FreeBSD$"); #include "tpm20.h" /* * CRB register space as defined in * TCG_PC_Client_Platform_TPM_Profile_PTP_2.0_r1.03_v22 */ #define TPM_LOC_STATE 0x0 #define TPM_LOC_CTRL 0x8 #define TPM_LOC_STS 0xC #define TPM_CRB_INTF_ID 0x30 #define TPM_CRB_CTRL_EXT 0x38 #define TPM_CRB_CTRL_REQ 0x40 #define TPM_CRB_CTRL_STS 0x44 #define TPM_CRB_CTRL_CANCEL 0x48 #define TPM_CRB_CTRL_START 0x4C #define TPM_CRB_INT_ENABLE 0x50 #define TPM_CRB_INT_STS 0x54 #define TPM_CRB_CTRL_CMD_SIZE 0x58 #define TPM_CRB_CTRL_CMD_LADDR 0x5C #define TPM_CRB_CTRL_CMD_HADDR 0x60 #define TPM_CRB_CTRL_RSP_SIZE 0x64 #define TPM_CRB_CTRL_RSP_ADDR 0x68 #define TPM_CRB_CTRL_RSP_HADDR 0x6c #define TPM_CRB_DATA_BUFFER 0x80 #define TPM_LOC_STATE_ESTB BIT(0) #define TPM_LOC_STATE_ASSIGNED BIT(1) #define TPM_LOC_STATE_ACTIVE_MASK 0x9C #define TPM_LOC_STATE_VALID BIT(7) #define TPM_CRB_INTF_ID_TYPE_CRB 0x1 #define TPM_CRB_INTF_ID_TYPE 0x7 #define TPM_LOC_CTRL_REQUEST BIT(0) #define TPM_LOC_CTRL_RELINQUISH BIT(1) #define TPM_CRB_CTRL_REQ_GO_READY BIT(0) #define TPM_CRB_CTRL_REQ_GO_IDLE BIT(1) #define TPM_CRB_CTRL_STS_ERR_BIT BIT(0) #define TPM_CRB_CTRL_STS_IDLE_BIT BIT(1) #define TPM_CRB_CTRL_CANCEL_CMD BIT(0) #define TPM_CRB_CTRL_START_CMD BIT(0) #define TPM_CRB_INT_ENABLE_BIT BIT(31) struct tpmcrb_sc { struct tpm_sc base; bus_size_t cmd_off; bus_size_t rsp_off; size_t cmd_buf_size; size_t rsp_buf_size; }; int tpmcrb_transmit(struct tpm_sc *sc, size_t size); static int tpmcrb_acpi_probe(device_t dev); static int tpmcrb_attach(device_t dev); static int tpmcrb_detach(device_t dev); static ACPI_STATUS tpmcrb_fix_buff_offsets(ACPI_RESOURCE *res, void *arg); static bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val, int32_t timeout); static bool tpmcrb_request_locality(struct tpm_sc *sc, int locality); static void tpmcrb_relinquish_locality(struct tpm_sc *sc); static bool tpmcrb_cancel_cmd(struct tpm_sc *sc); char *tpmcrb_ids[] = {"MSFT0101", NULL}; static int tpmcrb_acpi_probe(device_t dev) { int err; ACPI_TABLE_TPM23 *tbl; ACPI_STATUS status; err = ACPI_ID_PROBE(device_get_parent(dev), dev, tpmcrb_ids, NULL); if (err > 0) return (err); /*Find TPM2 Header*/ status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl); if(ACPI_FAILURE(status) || tbl->StartMethod != TPM2_START_METHOD_CRB) err = ENXIO; device_set_desc(dev, "Trusted Platform Module 2.0, CRB mode"); return (err); } static ACPI_STATUS tpmcrb_fix_buff_offsets(ACPI_RESOURCE *res, void *arg) { struct tpmcrb_sc *crb_sc; size_t length; uint32_t base_addr; crb_sc = (struct tpmcrb_sc *)arg; if (res->Type != ACPI_RESOURCE_TYPE_FIXED_MEMORY32) return (AE_OK); base_addr = res->Data.FixedMemory32.Address; length = res->Data.FixedMemory32.AddressLength; if (crb_sc->cmd_off > base_addr && crb_sc->cmd_off < base_addr + length) crb_sc->cmd_off -= base_addr; if (crb_sc->rsp_off > base_addr && crb_sc->rsp_off < base_addr + length) crb_sc->rsp_off -= base_addr; return (AE_OK); } static int tpmcrb_attach(device_t dev) { struct tpmcrb_sc *crb_sc; struct tpm_sc *sc; ACPI_HANDLE handle; ACPI_STATUS status; int result; crb_sc = device_get_softc(dev); sc = &crb_sc->base; handle = acpi_get_handle(dev); sc->dev = dev; sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) return (ENXIO); if(!tpmcrb_request_locality(sc, 0)) { - tpmcrb_detach(dev); + bus_release_resource(dev, SYS_RES_MEMORY, + sc->mem_rid, sc->mem_res); return (ENXIO); } /* * Disable all interrupts for now, since I don't have a device that * works in CRB mode and supports them. */ AND4(sc, TPM_CRB_INT_ENABLE, ~TPM_CRB_INT_ENABLE_BIT); sc->interrupts = false; /* * Read addresses of Tx/Rx buffers and their sizes. Note that they * can be implemented by a single buffer. Also for some reason CMD * addr is stored in two 4 byte neighboring registers, whereas RSP is * stored in a single 8 byte one. */ #ifdef __amd64__ crb_sc->rsp_off = RD8(sc, TPM_CRB_CTRL_RSP_ADDR); #else crb_sc->rsp_off = RD4(sc, TPM_CRB_CTRL_RSP_ADDR); crb_sc->rsp_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_RSP_HADDR) << 32); #endif crb_sc->cmd_off = RD4(sc, TPM_CRB_CTRL_CMD_LADDR); crb_sc->cmd_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_CMD_HADDR) << 32); crb_sc->cmd_buf_size = RD4(sc, TPM_CRB_CTRL_CMD_SIZE); crb_sc->rsp_buf_size = RD4(sc, TPM_CRB_CTRL_RSP_SIZE); tpmcrb_relinquish_locality(sc); /* Emulator returns address in acpi space instead of an offset */ status = AcpiWalkResources(handle, "_CRS", tpmcrb_fix_buff_offsets, (void *)crb_sc); if (ACPI_FAILURE(status)) { tpmcrb_detach(dev); return (ENXIO); } if (crb_sc->rsp_off == crb_sc->cmd_off) { /* * If Tx/Rx buffers are implemented as one they have to be of * same size */ if (crb_sc->cmd_buf_size != crb_sc->rsp_buf_size) { device_printf(sc->dev, "Overlapping Tx/Rx buffers have different sizes\n"); tpmcrb_detach(dev); return (ENXIO); } } sc->transmit = tpmcrb_transmit; result = tpm20_init(sc); if (result != 0) tpmcrb_detach(dev); return (result); } static int tpmcrb_detach(device_t dev) { struct tpm_sc *sc; sc = device_get_softc(dev); + tpm20_release(sc); if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); - tpm20_release(sc); return (0); } static bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val, int32_t timeout) { /* Check for condition */ if ((RD4(sc, off) & mask) == val) return (true); while (timeout > 0) { if ((RD4(sc, off) & mask) == val) return (true); pause("TPM in polling mode", 1); timeout -= tick; } return (false); } static bool tpmcrb_request_locality(struct tpm_sc *sc, int locality) { uint32_t mask; /* Currently we only support Locality 0 */ if (locality != 0) return (false); mask = TPM_LOC_STATE_VALID | TPM_LOC_STATE_ASSIGNED; OR4(sc, TPM_LOC_CTRL, TPM_LOC_CTRL_REQUEST); if (!tpm_wait_for_u32(sc, TPM_LOC_STATE, mask, mask, TPM_TIMEOUT_C)) return (false); return (true); } static void tpmcrb_relinquish_locality(struct tpm_sc *sc) { OR4(sc, TPM_LOC_CTRL, TPM_LOC_CTRL_RELINQUISH); } static bool tpmcrb_cancel_cmd(struct tpm_sc *sc) { uint32_t mask = ~0; WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CMD); if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START, mask, ~mask, TPM_TIMEOUT_B)) { device_printf(sc->dev, "Device failed to cancel command\n"); return (false); } WR4(sc, TPM_CRB_CTRL_CANCEL, !TPM_CRB_CTRL_CANCEL_CMD); return (true); } int tpmcrb_transmit(struct tpm_sc *sc, size_t length) { struct tpmcrb_sc *crb_sc; uint32_t mask, curr_cmd; int timeout, bytes_available; crb_sc = (struct tpmcrb_sc *)sc; sx_assert(&sc->dev_lock, SA_XLOCKED); if (length > crb_sc->cmd_buf_size) { device_printf(sc->dev, "Requested transfer is bigger than buffer size\n"); return (E2BIG); } if (RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_ERR_BIT) { device_printf(sc->dev, "Device has Error bit set\n"); return (EIO); } if (!tpmcrb_request_locality(sc, 0)) { device_printf(sc->dev, "Failed to obtain locality\n"); return (EIO); } /* Clear cancellation bit */ WR4(sc, TPM_CRB_CTRL_CANCEL, !TPM_CRB_CTRL_CANCEL_CMD); /* Switch device to idle state if necessary */ if (!(RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_IDLE_BIT)) { OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_IDLE); mask = TPM_CRB_CTRL_STS_IDLE_BIT; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS, mask, mask, TPM_TIMEOUT_C)) { device_printf(sc->dev, "Failed to transition to idle state\n"); return (EIO); } } /* Switch to ready state */ OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_READY); mask = TPM_CRB_CTRL_REQ_GO_READY; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS, mask, !mask, TPM_TIMEOUT_C)) { device_printf(sc->dev, "Failed to transition to ready state\n"); return (EIO); } /* * Calculate timeout for current command. * Command code is passed in bytes 6-10. */ curr_cmd = be32toh(*(uint32_t *) (&sc->buf[6])); timeout = tpm20_get_timeout(curr_cmd); /* Send command and tell device to process it. */ bus_write_region_stream_1(sc->mem_res, crb_sc->cmd_off, sc->buf, length); bus_barrier(sc->mem_res, crb_sc->cmd_off, length, BUS_SPACE_BARRIER_WRITE); WR4(sc, TPM_CRB_CTRL_START, TPM_CRB_CTRL_START_CMD); bus_barrier(sc->mem_res, TPM_CRB_CTRL_START, 4, BUS_SPACE_BARRIER_WRITE); mask = ~0; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START, mask, ~mask, timeout)) { device_printf(sc->dev, "Timeout while waiting for device to process cmd\n"); if (!tpmcrb_cancel_cmd(sc)) return (EIO); } /* Read response header. Length is passed in bytes 2 - 6. */ bus_read_region_stream_1(sc->mem_res, crb_sc->rsp_off, sc->buf, TPM_HEADER_SIZE); bytes_available = be32toh(*(uint32_t *) (&sc->buf[2])); if (bytes_available > TPM_BUFSIZE || bytes_available < TPM_HEADER_SIZE) { device_printf(sc->dev, "Incorrect response size: %d\n", bytes_available); return (EIO); } bus_read_region_stream_1(sc->mem_res, crb_sc->rsp_off + TPM_HEADER_SIZE, &sc->buf[TPM_HEADER_SIZE], bytes_available - TPM_HEADER_SIZE); OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_IDLE); tpmcrb_relinquish_locality(sc); sc->pending_data_length = bytes_available; return (0); } /* ACPI Driver */ static device_method_t tpmcrb_methods[] = { DEVMETHOD(device_probe, tpmcrb_acpi_probe), DEVMETHOD(device_attach, tpmcrb_attach), DEVMETHOD(device_detach, tpmcrb_detach), DEVMETHOD(device_shutdown, tpm20_shutdown), DEVMETHOD(device_suspend, tpm20_suspend), {0, 0} }; static driver_t tpmcrb_driver = { "tpmcrb", tpmcrb_methods, sizeof(struct tpmcrb_sc), }; devclass_t tpmcrb_devclass; DRIVER_MODULE(tpmcrb, acpi, tpmcrb_driver, tpmcrb_devclass, 0, 0); Index: head/sys/dev/tpm/tpm_tis.c =================================================================== --- head/sys/dev/tpm/tpm_tis.c (revision 345437) +++ head/sys/dev/tpm/tpm_tis.c (revision 345438) @@ -1,506 +1,506 @@ /*- * Copyright (c) 2018 Stormshield. * Copyright (c) 2018 Semihalf. * 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 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. */ #include __FBSDID("$FreeBSD$"); #include "tpm20.h" /* * TIS register space as defined in * TCG_PC_Client_Platform_TPM_Profile_PTP_2.0_r1.03_v22 */ #define TPM_ACCESS 0x0 #define TPM_INT_ENABLE 0x8 #define TPM_INT_VECTOR 0xc #define TPM_INT_STS 0x10 #define TPM_INTF_CAPS 0x14 #define TPM_STS 0x18 #define TPM_DATA_FIFO 0x24 #define TPM_INTF_ID 0x30 #define TPM_XDATA_FIFO 0x80 #define TPM_DID_VID 0xF00 #define TPM_RID 0xF04 #define TPM_ACCESS_LOC_REQ BIT(1) #define TPM_ACCESS_LOC_Seize BIT(3) #define TPM_ACCESS_LOC_ACTIVE BIT(5) #define TPM_ACCESS_LOC_RELINQUISH BIT(5) #define TPM_ACCESS_VALID BIT(7) #define TPM_INT_ENABLE_GLOBAL_ENABLE BIT(31) #define TPM_INT_ENABLE_CMD_RDY BIT(7) #define TPM_INT_ENABLE_LOC_CHANGE BIT(2) #define TPM_INT_ENABLE_STS_VALID BIT(1) #define TPM_INT_ENABLE_DATA_AVAIL BIT(0) #define TPM_INT_STS_CMD_RDY BIT(7) #define TPM_INT_STS_LOC_CHANGE BIT(2) #define TPM_INT_STS_VALID BIT(1) #define TPM_INT_STS_DATA_AVAIL BIT(0) #define TPM_INTF_CAPS_VERSION 0x70000000 #define TPM_INTF_CAPS_TPM20 0x30000000 #define TPM_STS_VALID BIT(7) #define TPM_STS_CMD_RDY BIT(6) #define TPM_STS_CMD_START BIT(5) #define TPM_STS_DATA_AVAIL BIT(4) #define TPM_STS_DATA_EXPECTED BIT(3) #define TPM_STS_BURST_MASK 0xFFFF00 #define TPM_STS_BURST_OFFSET 0x8 static int tpmtis_transmit(struct tpm_sc *sc, size_t length); static int tpmtis_acpi_probe(device_t dev); static int tpmtis_attach(device_t dev); static int tpmtis_detach(device_t dev); static void tpmtis_intr_handler(void *arg); static ACPI_STATUS tpmtis_get_SIRQ_channel(ACPI_RESOURCE *res, void *arg); static bool tpmtis_setup_intr(struct tpm_sc *sc); static bool tpmtis_read_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf); static bool tpmtis_write_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf); static bool tpmtis_request_locality(struct tpm_sc *sc, int locality); static void tpmtis_relinquish_locality(struct tpm_sc *sc); static bool tpmtis_go_ready(struct tpm_sc *sc); static bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val, int32_t timeout); static uint16_t tpmtis_wait_for_burst(struct tpm_sc *sc); char *tpmtis_ids[] = {"MSFT0101", NULL}; static int tpmtis_acpi_probe(device_t dev) { int err; ACPI_TABLE_TPM23 *tbl; ACPI_STATUS status; err = ACPI_ID_PROBE(device_get_parent(dev), dev, tpmtis_ids, NULL); if (err > 0) return (err); /*Find TPM2 Header*/ status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl); if(ACPI_FAILURE(status) || tbl->StartMethod != TPM2_START_METHOD_TIS) err = ENXIO; device_set_desc(dev, "Trusted Platform Module 2.0, FIFO mode"); return (err); } static int tpmtis_attach(device_t dev) { struct tpm_sc *sc; int result; sc = device_get_softc(dev); sc->dev = dev; sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) return (ENXIO); sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE); if (sc->irq_res != NULL) { if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, tpmtis_intr_handler, sc, &sc->intr_cookie)) sc->interrupts = false; else sc->interrupts = tpmtis_setup_intr(sc); } else { sc->interrupts = false; } sc->intr_type = -1; sc->transmit = tpmtis_transmit; result = tpm20_init(sc); if (result != 0) tpmtis_detach(dev); return (result); } static int tpmtis_detach(device_t dev) { struct tpm_sc *sc; sc = device_get_softc(dev); + tpm20_release(sc); if (sc->intr_cookie != NULL) bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie); if (sc->irq_res != NULL) bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); - tpm20_release(sc); return (0); } static ACPI_STATUS tpmtis_get_SIRQ_channel(ACPI_RESOURCE *res, void *arg) { struct tpm_sc *sc; uint8_t channel; sc = (struct tpm_sc *)arg; switch (res->Type) { case ACPI_RESOURCE_TYPE_IRQ: channel = res->Data.Irq.Interrupts[0]; break; case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: channel = res->Data.ExtendedIrq.Interrupts[0]; break; default: return (AE_OK); } WR1(sc, TPM_INT_VECTOR, channel); return (AE_OK); } static bool tpmtis_setup_intr(struct tpm_sc *sc) { ACPI_STATUS status; ACPI_HANDLE handle; uint32_t irq_mask; handle = acpi_get_handle(sc->dev); if(!tpmtis_request_locality(sc, 0)) return (false); irq_mask = RD4(sc, TPM_INT_ENABLE); irq_mask |= TPM_INT_ENABLE_GLOBAL_ENABLE | TPM_INT_ENABLE_DATA_AVAIL | TPM_INT_ENABLE_LOC_CHANGE | TPM_INT_ENABLE_CMD_RDY | TPM_INT_ENABLE_STS_VALID; WR4(sc, TPM_INT_ENABLE, irq_mask); status = AcpiWalkResources(handle, "_CRS", tpmtis_get_SIRQ_channel, (void *)sc); tpmtis_relinquish_locality(sc); return (ACPI_SUCCESS(status)); } static void tpmtis_intr_handler(void *arg) { struct tpm_sc *sc; uint32_t status; sc = (struct tpm_sc *)arg; status = RD4(sc, TPM_INT_STS); WR4(sc, TPM_INT_STS, status); if (sc->intr_type != -1 && sc->intr_type & status) wakeup(sc); } static bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val, int32_t timeout) { /* Check for condition */ if ((RD4(sc, off) & mask) == val) return (true); /* If interrupts are enabled sleep for timeout duration */ if(sc->interrupts && sc->intr_type != -1) { tsleep(sc, PWAIT, "TPM WITH INTERRUPTS", timeout / tick); sc->intr_type = -1; return ((RD4(sc, off) & mask) == val); } /* If we don't have interrupts poll the device every tick */ while (timeout > 0) { if ((RD4(sc, off) & mask) == val) return (true); pause("TPM POLLING", 1); timeout -= tick; } return (false); } static uint16_t tpmtis_wait_for_burst(struct tpm_sc *sc) { int timeout; uint16_t burst_count; timeout = TPM_TIMEOUT_A; while (timeout-- > 0) { burst_count = (RD4(sc, TPM_STS) & TPM_STS_BURST_MASK) >> TPM_STS_BURST_OFFSET; if (burst_count > 0) break; DELAY(1); } return (burst_count); } static bool tpmtis_read_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf) { uint16_t burst_count; while (count > 0) { burst_count = tpmtis_wait_for_burst(sc); if (burst_count == 0) return (false); burst_count = MIN(burst_count, count); count -= burst_count; while (burst_count-- > 0) *buf++ = RD1(sc, TPM_DATA_FIFO); } return (true); } static bool tpmtis_write_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf) { uint16_t burst_count; while (count > 0) { burst_count = tpmtis_wait_for_burst(sc); if (burst_count == 0) return (false); burst_count = MIN(burst_count, count); count -= burst_count; while (burst_count-- > 0) WR1(sc, TPM_DATA_FIFO, *buf++); } return (true); } static bool tpmtis_request_locality(struct tpm_sc *sc, int locality) { uint8_t mask; int timeout; /* Currently we only support Locality 0 */ if (locality != 0) return (false); mask = TPM_ACCESS_LOC_ACTIVE | TPM_ACCESS_VALID; timeout = TPM_TIMEOUT_A; sc->intr_type = TPM_INT_STS_LOC_CHANGE; WR1(sc, TPM_ACCESS, TPM_ACCESS_LOC_REQ); bus_barrier(sc->mem_res, TPM_ACCESS, 1, BUS_SPACE_BARRIER_WRITE); if(sc->interrupts) { tsleep(sc, PWAIT, "TPMLOCREQUEST with INTR", timeout / tick); return ((RD1(sc, TPM_ACCESS) & mask) == mask); } else { while(timeout > 0) { if ((RD1(sc, TPM_ACCESS) & mask) == mask) return (true); pause("TPMLOCREQUEST POLLING", 1); timeout -= tick; } } return (false); } static void tpmtis_relinquish_locality(struct tpm_sc *sc) { /* * Interrupts can only be cleared when a locality is active. * Clear them now in case interrupt handler didn't make it in time. */ if(sc->interrupts) AND4(sc, TPM_INT_STS, RD4(sc, TPM_INT_STS)); OR1(sc, TPM_ACCESS, TPM_ACCESS_LOC_RELINQUISH); } static bool tpmtis_go_ready(struct tpm_sc *sc) { uint32_t mask; mask = TPM_STS_CMD_RDY; sc->intr_type = TPM_INT_STS_CMD_RDY; OR4(sc, TPM_STS, TPM_STS_CMD_RDY); bus_barrier(sc->mem_res, TPM_STS, 4, BUS_SPACE_BARRIER_WRITE); if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_B)) return (false); AND4(sc, TPM_STS, ~TPM_STS_CMD_RDY); return (true); } static int tpmtis_transmit(struct tpm_sc *sc, size_t length) { size_t bytes_available; uint32_t mask, curr_cmd; int timeout; sx_assert(&sc->dev_lock, SA_XLOCKED); if (!tpmtis_request_locality(sc, 0)) { device_printf(sc->dev, "Failed to obtain locality\n"); return (EIO); } if (!tpmtis_go_ready(sc)) { device_printf(sc->dev, "Failed to switch to ready state\n"); return (EIO); } if (!tpmtis_write_bytes(sc, length, sc->buf)) { device_printf(sc->dev, "Failed to write cmd to device\n"); return (EIO); } mask = TPM_STS_VALID; sc->intr_type = TPM_INT_STS_VALID; if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C)) { device_printf(sc->dev, "Timeout while waiting for valid bit\n"); return (EIO); } if (RD4(sc, TPM_STS) & TPM_STS_DATA_EXPECTED) { device_printf(sc->dev, "Device expects more data even though we already" " sent everything we had\n"); return (EIO); } /* * Calculate timeout for current command. * Command code is passed in bytes 6-10. */ curr_cmd = be32toh(*(uint32_t *) (&sc->buf[6])); timeout = tpm20_get_timeout(curr_cmd); WR4(sc, TPM_STS, TPM_STS_CMD_START); bus_barrier(sc->mem_res, TPM_STS, 4, BUS_SPACE_BARRIER_WRITE); mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; sc->intr_type = TPM_INT_STS_DATA_AVAIL; if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, timeout)) { device_printf(sc->dev, "Timeout while waiting for device to process cmd\n"); /* * Switching to ready state also cancels processing * current command */ if (!tpmtis_go_ready(sc)) return (EIO); /* * After canceling a command we should get a response, * check if there is one. */ sc->intr_type = TPM_INT_STS_DATA_AVAIL; if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C)) return (EIO); } /* Read response header. Length is passed in bytes 2 - 6. */ if(!tpmtis_read_bytes(sc, TPM_HEADER_SIZE, sc->buf)) { device_printf(sc->dev, "Failed to read response header\n"); return (EIO); } bytes_available = be32toh(*(uint32_t *) (&sc->buf[2])); if (bytes_available > TPM_BUFSIZE || bytes_available < TPM_HEADER_SIZE) { device_printf(sc->dev, "Incorrect response size: %zu\n", bytes_available); return (EIO); } if(!tpmtis_read_bytes(sc, bytes_available - TPM_HEADER_SIZE, &sc->buf[TPM_HEADER_SIZE])) { device_printf(sc->dev, "Failed to read response\n"); return (EIO); } tpmtis_relinquish_locality(sc); sc->pending_data_length = bytes_available; return (0); } /* ACPI Driver */ static device_method_t tpmtis_methods[] = { DEVMETHOD(device_probe, tpmtis_acpi_probe), DEVMETHOD(device_attach, tpmtis_attach), DEVMETHOD(device_detach, tpmtis_detach), DEVMETHOD(device_shutdown, tpm20_shutdown), DEVMETHOD(device_suspend, tpm20_suspend), {0, 0} }; static driver_t tpmtis_driver = { "tpmtis", tpmtis_methods, sizeof(struct tpm_sc), }; devclass_t tpmtis_devclass; DRIVER_MODULE(tpmtis, acpi, tpmtis_driver, tpmtis_devclass, 0, 0); Index: head/sys/sys/random.h =================================================================== --- head/sys/sys/random.h (revision 345437) +++ head/sys/sys/random.h (revision 345438) @@ -1,161 +1,162 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2000-2015, 2017 Mark R. V. Murray * 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 * in this position and unchanged. * 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$ */ #ifndef _SYS_RANDOM_H_ #define _SYS_RANDOM_H_ #include #ifdef _KERNEL struct uio; #if defined(DEV_RANDOM) u_int read_random(void *, u_int); int read_random_uio(struct uio *, bool); #else static __inline int read_random_uio(void *a __unused, u_int b __unused) { return (0); } static __inline u_int read_random(void *a __unused, u_int b __unused) { return (0); } #endif /* * Note: if you add or remove members of random_entropy_source, remember to * also update the strings in the static array random_source_descr[] in * random_harvestq.c. */ enum random_entropy_source { RANDOM_START = 0, RANDOM_CACHED = 0, /* Environmental sources */ RANDOM_ATTACH, RANDOM_KEYBOARD, RANDOM_MOUSE, RANDOM_NET_TUN, RANDOM_NET_ETHER, RANDOM_NET_NG, RANDOM_INTERRUPT, RANDOM_SWI, RANDOM_FS_ATIME, RANDOM_UMA, /* Special!! UMA/SLAB Allocator */ RANDOM_ENVIRONMENTAL_END = RANDOM_UMA, /* Fast hardware random-number sources from here on. */ RANDOM_PURE_START, RANDOM_PURE_OCTEON = RANDOM_PURE_START, RANDOM_PURE_SAFE, RANDOM_PURE_GLXSB, RANDOM_PURE_UBSEC, RANDOM_PURE_HIFN, RANDOM_PURE_RDRAND, RANDOM_PURE_NEHEMIAH, RANDOM_PURE_RNDTEST, RANDOM_PURE_VIRTIO, RANDOM_PURE_BROADCOM, RANDOM_PURE_CCP, RANDOM_PURE_DARN, + RANDOM_PURE_TPM, ENTROPYSOURCE }; _Static_assert(ENTROPYSOURCE <= 32, "hardcoded assumption that values fit in a typical word-sized bitset"); #define RANDOM_LEGACY_BOOT_ENTROPY_MODULE "/boot/entropy" #define RANDOM_CACHED_BOOT_ENTROPY_MODULE "boot_entropy_cache" #define RANDOM_CACHED_SKIP_START 256 #if defined(DEV_RANDOM) extern u_int hc_source_mask; void random_harvest_queue_(const void *, u_int, enum random_entropy_source); void random_harvest_fast_(const void *, u_int); void random_harvest_direct_(const void *, u_int, enum random_entropy_source); static __inline void random_harvest_queue(const void *entropy, u_int size, enum random_entropy_source origin) { if (hc_source_mask & (1 << origin)) random_harvest_queue_(entropy, size, origin); } static __inline void random_harvest_fast(const void *entropy, u_int size, enum random_entropy_source origin) { if (hc_source_mask & (1 << origin)) random_harvest_fast_(entropy, size); } static __inline void random_harvest_direct(const void *entropy, u_int size, enum random_entropy_source origin) { if (hc_source_mask & (1 << origin)) random_harvest_direct_(entropy, size, origin); } void random_harvest_register_source(enum random_entropy_source); void random_harvest_deregister_source(enum random_entropy_source); #else #define random_harvest_queue(a, b, c) do {} while (0) #define random_harvest_fast(a, b, c) do {} while (0) #define random_harvest_direct(a, b, c) do {} while (0) #define random_harvest_register_source(a) do {} while (0) #define random_harvest_deregister_source(a) do {} while (0) #endif #if defined(RANDOM_ENABLE_UMA) #define random_harvest_fast_uma(a, b, c) random_harvest_fast(a, b, c) #else /* !defined(RANDOM_ENABLE_UMA) */ #define random_harvest_fast_uma(a, b, c) do {} while (0) #endif /* defined(RANDOM_ENABLE_UMA) */ #if defined(RANDOM_ENABLE_ETHER) #define random_harvest_queue_ether(a, b) random_harvest_queue(a, b, RANDOM_NET_ETHER) #else /* !defined(RANDOM_ENABLE_ETHER) */ #define random_harvest_queue_ether(a, b) do {} while (0) #endif /* defined(RANDOM_ENABLE_ETHER) */ #endif /* _KERNEL */ #define GRND_NONBLOCK 0x1 #define GRND_RANDOM 0x2 __BEGIN_DECLS ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); __END_DECLS #endif /* _SYS_RANDOM_H_ */