diff --git a/configs/defconfig b/configs/defconfig new file mode 100644 index 000000000..ea710a459 --- /dev/null +++ b/configs/defconfig @@ -0,0 +1,5293 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/x86 6.6.34 Kernel Configuration +# +CONFIG_CC_VERSION_TEXT="gcc (GCC) 15.2.1 20250813" +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=150201 +CONFIG_CLANG_VERSION=0 +CONFIG_AS_IS_GNU=y +CONFIG_AS_VERSION=24500 +CONFIG_LD_IS_BFD=y +CONFIG_LD_VERSION=24500 +CONFIG_LLD_VERSION=0 +CONFIG_CC_CAN_LINK=y +CONFIG_CC_CAN_LINK_STATIC=y +CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y +CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y +CONFIG_TOOLS_SUPPORT_RELR=y +CONFIG_CC_HAS_ASM_INLINE=y +CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y +CONFIG_PAHOLE_VERSION=130 +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_TABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_WERROR=y +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_BUILD_SALT="" +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_BZIP2=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_HAVE_KERNEL_LZ4=y +CONFIG_HAVE_KERNEL_ZSTD=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_XZ is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_KERNEL_LZ4 is not set +# CONFIG_KERNEL_ZSTD is not set +CONFIG_DEFAULT_INIT="" +CONFIG_DEFAULT_HOSTNAME="(none)" +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_SYSVIPC_COMPAT=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_WATCH_QUEUE is not set +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_PENDING_IRQ=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_IRQ_MSI_IOMMU=y +CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y +CONFIG_GENERIC_IRQ_RESERVATION_MODE=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +# end of IRQ subsystem + +CONFIG_CLOCKSOURCE_WATCHDOG=y +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y +CONFIG_GENERIC_CMOS_UPDATE=y +CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=125 +# end of Timers subsystem + +CONFIG_BPF=y +CONFIG_HAVE_EBPF_JIT=y +CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y + +# +# BPF subsystem +# +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_BPF_JIT_DEFAULT_ON=y +CONFIG_BPF_UNPRIV_DEFAULT_OFF=y +# CONFIG_BPF_PRELOAD is not set +# CONFIG_BPF_LSM is not set +# end of BPF subsystem + +CONFIG_PREEMPT_BUILD=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set +CONFIG_PREEMPT_COUNT=y +CONFIG_PREEMPTION=y +CONFIG_PREEMPT_DYNAMIC=y +# CONFIG_SCHED_CORE is not set + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +CONFIG_BSD_PROCESS_ACCT=y +# CONFIG_BSD_PROCESS_ACCT_V3 is not set +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +# CONFIG_PSI is not set +# end of CPU/Task time and stats accounting + +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +CONFIG_PREEMPT_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_TREE_SRCU=y +CONFIG_TASKS_RCU_GENERIC=y +CONFIG_TASKS_RCU=y +CONFIG_TASKS_TRACE_RCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +# end of RCU Subsystem + +# CONFIG_IKCONFIG is not set +# CONFIG_IKHEADERS is not set +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +# CONFIG_PRINTK_INDEX is not set +CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y + +# +# Scheduler features +# +# CONFIG_UCLAMP_TASK is not set +# end of Scheduler features + +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y +CONFIG_CC_HAS_INT128=y +CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" +CONFIG_GCC10_NO_ARRAY_BOUNDS=y +CONFIG_CC_NO_ARRAY_BOUNDS=y +CONFIG_ARCH_SUPPORTS_INT128=y +# CONFIG_NUMA_BALANCING is not set +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +# CONFIG_CGROUP_FAVOR_DYNMODS is not set +# CONFIG_MEMCG is not set +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +# CONFIG_CFS_BANDWIDTH is not set +# CONFIG_RT_GROUP_SCHED is not set +CONFIG_SCHED_MM_CID=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_RDMA=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +# CONFIG_CGROUP_BPF is not set +CONFIG_CGROUP_MISC=y +CONFIG_CGROUP_DEBUG=y +CONFIG_SOCK_CGROUP_DATA=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_TIME_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +CONFIG_RELAY=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +CONFIG_RD_BZIP2=y +CONFIG_RD_LZMA=y +CONFIG_RD_XZ=y +CONFIG_RD_LZO=y +CONFIG_RD_LZ4=y +CONFIG_RD_ZSTD=y +# CONFIG_BOOT_CONFIG is not set +CONFIG_INITRAMFS_PRESERVE_MTIME=y +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_LD_ORPHAN_WARN=y +CONFIG_LD_ORPHAN_WARN_LEVEL="error" +CONFIG_SYSCTL=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_HAVE_PCSPKR_PLATFORM=y +# CONFIG_EXPERT is not set +CONFIG_UID16=y +CONFIG_MULTIUSER=y +CONFIG_SGETMASK_SYSCALL=y +CONFIG_SYSFS_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_PCSPKR_PLATFORM=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_SELFTEST is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y +CONFIG_KALLSYMS_BASE_RELATIVE=y +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_KCMP=y +CONFIG_RSEQ=y +CONFIG_CACHESTAT_SYSCALL=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_GUEST_PERF_EVENTS=y + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +# end of Kernel Performance Events And Counters + +CONFIG_SYSTEM_DATA_VERIFICATION=y +CONFIG_PROFILING=y +CONFIG_TRACEPOINTS=y + +# +# Kexec and crash features +# +CONFIG_CRASH_CORE=y +CONFIG_KEXEC_CORE=y +CONFIG_KEXEC=y +# CONFIG_KEXEC_FILE is not set +# CONFIG_KEXEC_JUMP is not set +CONFIG_CRASH_DUMP=y +CONFIG_CRASH_HOTPLUG=y +CONFIG_CRASH_MAX_MEMORY_RANGES=8192 +# end of Kexec and crash features +# end of General setup + +CONFIG_64BIT=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_INSTRUCTION_DECODER=y +CONFIG_OUTPUT_FORMAT="elf64-x86-64" +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_MMU=y +CONFIG_ARCH_MMAP_RND_BITS_MIN=28 +CONFIG_ARCH_MMAP_RND_BITS_MAX=32 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_GENERIC_ISA_DMA=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_ARCH_MAY_HAVE_PC_FDC=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ARCH_HAS_CPU_RELAX=y +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_AUDIT_ARCH=y +CONFIG_HAVE_INTEL_TXT=y +CONFIG_X86_64_SMP=y +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=5 +CONFIG_CC_HAS_SANE_STACKPROTECTOR=y + +# +# Processor type and features +# +CONFIG_SMP=y +# CONFIG_X86_X2APIC is not set +CONFIG_X86_MPPARSE=y +# CONFIG_GOLDFISH is not set +# CONFIG_X86_CPU_RESCTRL is not set +CONFIG_X86_EXTENDED_PLATFORM=y +# CONFIG_X86_VSMP is not set +# CONFIG_X86_GOLDFISH is not set +# CONFIG_X86_INTEL_MID is not set +# CONFIG_X86_INTEL_LPSS is not set +# CONFIG_X86_AMD_PLATFORM_DEVICE is not set +CONFIG_IOSF_MBI=y +# CONFIG_IOSF_MBI_DEBUG is not set +CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y +CONFIG_SCHED_OMIT_FRAME_POINTER=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +# CONFIG_PARAVIRT_DEBUG is not set +# CONFIG_PARAVIRT_SPINLOCKS is not set +CONFIG_X86_HV_CALLBACK_VECTOR=y +# CONFIG_XEN is not set +CONFIG_KVM_GUEST=y +CONFIG_ARCH_CPUIDLE_HALTPOLL=y +# CONFIG_PVH is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +CONFIG_PARAVIRT_CLOCK=y +# CONFIG_JAILHOUSE_GUEST is not set +# CONFIG_ACRN_GUEST is not set +# CONFIG_MK8 is not set +# CONFIG_MPSC is not set +# CONFIG_MCORE2 is not set +# CONFIG_MATOM is not set +CONFIG_GENERIC_CPU=y +CONFIG_X86_INTERNODE_CACHE_SHIFT=6 +CONFIG_X86_L1_CACHE_SHIFT=6 +CONFIG_X86_TSC=y +CONFIG_X86_CMPXCHG64=y +CONFIG_X86_CMOV=y +CONFIG_X86_MINIMUM_CPU_FAMILY=64 +CONFIG_X86_DEBUGCTLMSR=y +CONFIG_IA32_FEAT_CTL=y +CONFIG_X86_VMX_FEATURE_NAMES=y +CONFIG_CPU_SUP_INTEL=y +CONFIG_CPU_SUP_AMD=y +CONFIG_CPU_SUP_HYGON=y +CONFIG_CPU_SUP_CENTAUR=y +CONFIG_CPU_SUP_ZHAOXIN=y +CONFIG_HPET_TIMER=y +CONFIG_HPET_EMULATE_RTC=y +CONFIG_DMI=y +# CONFIG_GART_IOMMU is not set +# CONFIG_MAXSMP is not set +CONFIG_NR_CPUS_RANGE_BEGIN=2 +CONFIG_NR_CPUS_RANGE_END=512 +CONFIG_NR_CPUS_DEFAULT=64 +CONFIG_NR_CPUS=64 +CONFIG_SCHED_CLUSTER=y +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_MC_PRIO=y +CONFIG_X86_LOCAL_APIC=y +CONFIG_X86_IO_APIC=y +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +CONFIG_X86_MCE=y +# CONFIG_X86_MCELOG_LEGACY is not set +CONFIG_X86_MCE_INTEL=y +CONFIG_X86_MCE_AMD=y +CONFIG_X86_MCE_THRESHOLD=y +# CONFIG_X86_MCE_INJECT is not set + +# +# Performance monitoring +# +CONFIG_PERF_EVENTS_INTEL_UNCORE=y +CONFIG_PERF_EVENTS_INTEL_RAPL=y +CONFIG_PERF_EVENTS_INTEL_CSTATE=y +# CONFIG_PERF_EVENTS_AMD_POWER is not set +CONFIG_PERF_EVENTS_AMD_UNCORE=y +# CONFIG_PERF_EVENTS_AMD_BRS is not set +# end of Performance monitoring + +CONFIG_X86_16BIT=y +CONFIG_X86_ESPFIX64=y +CONFIG_X86_VSYSCALL_EMULATION=y +CONFIG_X86_IOPL_IOPERM=y +CONFIG_MICROCODE=y +# CONFIG_MICROCODE_LATE_LOADING is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_X86_5LEVEL=y +CONFIG_X86_DIRECT_GBPAGES=y +# CONFIG_X86_CPA_STATISTICS is not set +# CONFIG_AMD_MEM_ENCRYPT is not set +CONFIG_NUMA=y +CONFIG_AMD_NUMA=y +CONFIG_X86_64_ACPI_NUMA=y +# CONFIG_NUMA_EMU is not set +CONFIG_NODES_SHIFT=6 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_PROC_KCORE_TEXT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +# CONFIG_X86_PMEM_LEGACY is not set +CONFIG_X86_CHECK_BIOS_CORRUPTION=y +CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK=y +CONFIG_MTRR=y +# CONFIG_MTRR_SANITIZER is not set +CONFIG_X86_PAT=y +CONFIG_ARCH_USES_PG_UNCACHED=y +CONFIG_X86_UMIP=y +CONFIG_CC_HAS_IBT=y +CONFIG_X86_CET=y +CONFIG_X86_KERNEL_IBT=y +CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y +CONFIG_X86_INTEL_TSX_MODE_OFF=y +# CONFIG_X86_INTEL_TSX_MODE_ON is not set +# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set +# CONFIG_X86_USER_SHADOW_STACK is not set +CONFIG_EFI=y +CONFIG_EFI_STUB=y +CONFIG_EFI_HANDOVER_PROTOCOL=y +CONFIG_EFI_MIXED=y +# CONFIG_EFI_FAKE_MEMMAP is not set +CONFIG_EFI_RUNTIME_MAP=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +# CONFIG_HZ_300 is not set +CONFIG_HZ_1000=y +CONFIG_HZ=1000 +CONFIG_SCHED_HRTICK=y +CONFIG_ARCH_SUPPORTS_KEXEC=y +CONFIG_ARCH_SUPPORTS_KEXEC_FILE=y +CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY=y +CONFIG_ARCH_SUPPORTS_KEXEC_SIG=y +CONFIG_ARCH_SUPPORTS_KEXEC_SIG_FORCE=y +CONFIG_ARCH_SUPPORTS_KEXEC_BZIMAGE_VERIFY_SIG=y +CONFIG_ARCH_SUPPORTS_KEXEC_JUMP=y +CONFIG_ARCH_SUPPORTS_CRASH_DUMP=y +CONFIG_ARCH_SUPPORTS_CRASH_HOTPLUG=y +CONFIG_PHYSICAL_START=0x1000000 +CONFIG_RELOCATABLE=y +CONFIG_RANDOMIZE_BASE=y +CONFIG_X86_NEED_RELOCS=y +CONFIG_PHYSICAL_ALIGN=0x200000 +CONFIG_DYNAMIC_MEMORY_LAYOUT=y +CONFIG_RANDOMIZE_MEMORY=y +CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0x0 +# CONFIG_ADDRESS_MASKING is not set +CONFIG_HOTPLUG_CPU=y +# CONFIG_COMPAT_VDSO is not set +CONFIG_LEGACY_VSYSCALL_XONLY=y +# CONFIG_LEGACY_VSYSCALL_NONE is not set +# CONFIG_CMDLINE_BOOL is not set +CONFIG_MODIFY_LDT_SYSCALL=y +# CONFIG_STRICT_SIGALTSTACK_SIZE is not set +CONFIG_HAVE_LIVEPATCH=y +# end of Processor type and features + +CONFIG_CC_HAS_SLS=y +CONFIG_CC_HAS_RETURN_THUNK=y +CONFIG_CC_HAS_ENTRY_PADDING=y +CONFIG_FUNCTION_PADDING_CFI=11 +CONFIG_FUNCTION_PADDING_BYTES=16 +CONFIG_CALL_PADDING=y +CONFIG_HAVE_CALL_THUNKS=y +CONFIG_CALL_THUNKS=y +CONFIG_PREFIX_SYMBOLS=y +CONFIG_CPU_MITIGATIONS=y +CONFIG_PAGE_TABLE_ISOLATION=y +CONFIG_RETPOLINE=y +CONFIG_RETHUNK=y +CONFIG_CPU_UNRET_ENTRY=y +CONFIG_CALL_DEPTH_TRACKING=y +# CONFIG_CALL_THUNKS_DEBUG is not set +CONFIG_CPU_IBPB_ENTRY=y +CONFIG_CPU_IBRS_ENTRY=y +CONFIG_CPU_SRSO=y +# CONFIG_SLS is not set +# CONFIG_GDS_FORCE_MITIGATION is not set +CONFIG_MITIGATION_RFDS=y +CONFIG_MITIGATION_SPECTRE_BHI=y +CONFIG_ARCH_HAS_ADD_PAGES=y + +# +# Power management and ACPI options +# +CONFIG_ARCH_HIBERNATION_HEADER=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HIBERNATE_CALLBACKS=y +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_SNAPSHOT_DEV=y +CONFIG_PM_STD_PARTITION="" +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_USERSPACE_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +CONFIG_PM_DEBUG=y +# CONFIG_PM_ADVANCED_DEBUG is not set +# CONFIG_PM_TEST_SUSPEND is not set +CONFIG_PM_SLEEP_DEBUG=y +CONFIG_PM_TRACE=y +CONFIG_PM_TRACE_RTC=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_SUPPORTS_ACPI=y +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y +CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y +# CONFIG_ACPI_DEBUGGER is not set +CONFIG_ACPI_SPCR_TABLE=y +# CONFIG_ACPI_FPDT is not set +CONFIG_ACPI_LPIT=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y +# CONFIG_ACPI_EC_DEBUGFS is not set +CONFIG_ACPI_AC=y +CONFIG_ACPI_BATTERY=y +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_VIDEO=y +CONFIG_ACPI_FAN=y +# CONFIG_ACPI_TAD is not set +CONFIG_ACPI_DOCK=y +CONFIG_ACPI_CPU_FREQ_PSS=y +CONFIG_ACPI_PROCESSOR_CSTATE=y +CONFIG_ACPI_PROCESSOR_IDLE=y +CONFIG_ACPI_CPPC_LIB=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_HOTPLUG_CPU=y +# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set +CONFIG_ACPI_THERMAL=y +CONFIG_ARCH_HAS_ACPI_TABLE_UPGRADE=y +CONFIG_ACPI_TABLE_UPGRADE=y +# CONFIG_ACPI_DEBUG is not set +# CONFIG_ACPI_PCI_SLOT is not set +CONFIG_ACPI_CONTAINER=y +CONFIG_ACPI_HOTPLUG_IOAPIC=y +# CONFIG_ACPI_SBS is not set +# CONFIG_ACPI_HED is not set +# CONFIG_ACPI_CUSTOM_METHOD is not set +CONFIG_ACPI_BGRT=y +# CONFIG_ACPI_NFIT is not set +CONFIG_ACPI_NUMA=y +# CONFIG_ACPI_HMAT is not set +CONFIG_HAVE_ACPI_APEI=y +CONFIG_HAVE_ACPI_APEI_NMI=y +# CONFIG_ACPI_APEI is not set +# CONFIG_ACPI_DPTF is not set +# CONFIG_ACPI_CONFIGFS is not set +# CONFIG_ACPI_PFRUT is not set +CONFIG_ACPI_PCC=y +# CONFIG_ACPI_FFH is not set +# CONFIG_PMIC_OPREGION is not set +CONFIG_ACPI_PRMT=y +CONFIG_X86_PM_TIMER=y + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +# CONFIG_CPU_FREQ_STAT is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y + +# +# CPU frequency scaling drivers +# +CONFIG_X86_INTEL_PSTATE=y +# CONFIG_X86_PCC_CPUFREQ is not set +# CONFIG_X86_AMD_PSTATE is not set +# CONFIG_X86_AMD_PSTATE_UT is not set +CONFIG_X86_ACPI_CPUFREQ=y +CONFIG_X86_ACPI_CPUFREQ_CPB=y +# CONFIG_X86_POWERNOW_K8 is not set +# CONFIG_X86_AMD_FREQ_SENSITIVITY is not set +# CONFIG_X86_SPEEDSTEP_CENTRINO is not set +# CONFIG_X86_P4_CLOCKMOD is not set + +# +# shared options +# +# end of CPU Frequency scaling + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +CONFIG_CPU_IDLE_GOV_HALTPOLL=y +CONFIG_HALTPOLL_CPUIDLE=y +# end of CPU Idle + +# CONFIG_INTEL_IDLE is not set +# end of Power management and ACPI options + +# +# Bus options (PCI etc.) +# +CONFIG_PCI_DIRECT=y +CONFIG_PCI_MMCONFIG=y +CONFIG_MMCONF_FAM10H=y +CONFIG_ISA_DMA_API=y +CONFIG_AMD_NB=y +# end of Bus options (PCI etc.) + +# +# Binary Emulations +# +CONFIG_IA32_EMULATION=y +# CONFIG_X86_X32_ABI is not set +CONFIG_COMPAT_32=y +CONFIG_COMPAT=y +CONFIG_COMPAT_FOR_U64_ALIGNMENT=y +# end of Binary Emulations + +CONFIG_HAVE_KVM=y +CONFIG_HAVE_KVM_PFNCACHE=y +CONFIG_HAVE_KVM_IRQCHIP=y +CONFIG_HAVE_KVM_IRQFD=y +CONFIG_HAVE_KVM_IRQ_ROUTING=y +CONFIG_HAVE_KVM_DIRTY_RING=y +CONFIG_HAVE_KVM_DIRTY_RING_TSO=y +CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y +CONFIG_HAVE_KVM_EVENTFD=y +CONFIG_KVM_MMIO=y +CONFIG_KVM_ASYNC_PF=y +CONFIG_HAVE_KVM_MSI=y +CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y +CONFIG_KVM_VFIO=y +CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y +CONFIG_KVM_COMPAT=y +CONFIG_HAVE_KVM_IRQ_BYPASS=y +CONFIG_HAVE_KVM_NO_POLL=y +CONFIG_KVM_XFER_TO_GUEST_WORK=y +CONFIG_HAVE_KVM_PM_NOTIFIER=y +CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=y +CONFIG_KVM_INTEL=m +CONFIG_KVM_AMD=m +CONFIG_KVM_SMM=y +# CONFIG_KVM_XEN is not set +CONFIG_AS_AVX512=y +CONFIG_AS_SHA1_NI=y +CONFIG_AS_SHA256_NI=y +CONFIG_AS_TPAUSE=y +CONFIG_AS_GFNI=y +CONFIG_AS_WRUSS=y +CONFIG_ARCH_CONFIGURES_CPU_MITIGATIONS=y + +# +# General architecture-dependent options +# +CONFIG_HOTPLUG_SMT=y +CONFIG_HOTPLUG_CORE_SYNC=y +CONFIG_HOTPLUG_CORE_SYNC_DEAD=y +CONFIG_HOTPLUG_CORE_SYNC_FULL=y +CONFIG_HOTPLUG_SPLIT_STARTUP=y +CONFIG_HOTPLUG_PARALLEL=y +CONFIG_GENERIC_ENTRY=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +# CONFIG_STATIC_CALL_SELFTEST is not set +CONFIG_OPTPROBES=y +CONFIG_UPROBES=y +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y +CONFIG_KRETPROBES=y +CONFIG_KRETPROBE_ON_RETHOOK=y +CONFIG_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_IOREMAP_PROT=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_OPTPROBES=y +CONFIG_HAVE_KPROBES_ON_FTRACE=y +CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE=y +CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y +CONFIG_HAVE_NMI=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_ARCH_HAS_SET_DIRECT_MAP=y +CONFIG_ARCH_HAS_CPU_FINALIZE_INIT=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT=y +CONFIG_ARCH_WANTS_NO_INSTR=y +CONFIG_HAVE_ASM_MODVERSIONS=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_RUST=y +CONFIG_HAVE_FUNCTION_ARG_ACCESS_API=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y +CONFIG_HAVE_USER_RETURN_NOTIFIER=y +CONFIG_HAVE_PERF_EVENTS_NMI=y +CONFIG_HAVE_HARDLOCKUP_DETECTOR_PERF=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_MMU_GATHER_TABLE_FREE=y +CONFIG_MMU_GATHER_RCU_TABLE_FREE=y +CONFIG_MMU_GATHER_MERGE_VMAS=y +CONFIG_MMU_LAZY_TLB_REFCOUNT=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_ARCH_WANT_OLD_COMPAT_IPC=y +CONFIG_HAVE_ARCH_SECCOMP=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP=y +CONFIG_SECCOMP_FILTER=y +# CONFIG_SECCOMP_CACHE_DEBUG is not set +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_SUPPORTS_LTO_CLANG=y +CONFIG_ARCH_SUPPORTS_LTO_CLANG_THIN=y +CONFIG_LTO_NONE=y +CONFIG_ARCH_SUPPORTS_CFI_CLANG=y +CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y +CONFIG_HAVE_CONTEXT_TRACKING_USER=y +CONFIG_HAVE_CONTEXT_TRACKING_USER_OFFSTACK=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_MOVE_PUD=y +CONFIG_HAVE_MOVE_PMD=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_ARCH_HUGE_VMALLOC=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_HAVE_ARCH_SOFT_DIRTY=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y +CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y +CONFIG_SOFTIRQ_ON_OWN_STACK=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_HAVE_EXIT_THREAD=y +CONFIG_ARCH_MMAP_RND_BITS=28 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=8 +CONFIG_HAVE_ARCH_COMPAT_MMAP_BASES=y +CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +CONFIG_PAGE_SIZE_LESS_THAN_256KB=y +CONFIG_HAVE_OBJTOOL=y +CONFIG_HAVE_JUMP_LABEL_HACK=y +CONFIG_HAVE_NOINSTR_HACK=y +CONFIG_HAVE_NOINSTR_VALIDATION=y +CONFIG_HAVE_UACCESS_VALIDATION=y +CONFIG_HAVE_STACK_VALIDATION=y +CONFIG_HAVE_RELIABLE_STACKTRACE=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET=y +CONFIG_RANDOMIZE_KSTACK_OFFSET=y +# CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT is not set +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y +# CONFIG_LOCK_EVENT_COUNTS is not set +CONFIG_ARCH_HAS_MEM_ENCRYPT=y +CONFIG_HAVE_STATIC_CALL=y +CONFIG_HAVE_STATIC_CALL_INLINE=y +CONFIG_HAVE_PREEMPT_DYNAMIC=y +CONFIG_HAVE_PREEMPT_DYNAMIC_CALL=y +CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y +CONFIG_ARCH_HAS_ELFCORE_COMPAT=y +CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y +CONFIG_DYNAMIC_SIGFRAME=y +CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +# end of GCOV-based kernel profiling + +CONFIG_HAVE_GCC_PLUGINS=y +CONFIG_GCC_PLUGINS=y +# CONFIG_GCC_PLUGIN_LATENT_ENTROPY is not set +CONFIG_FUNCTION_ALIGNMENT_4B=y +CONFIG_FUNCTION_ALIGNMENT_16B=y +CONFIG_FUNCTION_ALIGNMENT=16 +# end of General architecture-dependent options + +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_DEBUG is not set +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODULE_UNLOAD_TAINT_TRACKING is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +CONFIG_MODULE_COMPRESS_NONE=y +# CONFIG_MODULE_COMPRESS_GZIP is not set +# CONFIG_MODULE_COMPRESS_XZ is not set +# CONFIG_MODULE_COMPRESS_ZSTD is not set +# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set +CONFIG_MODPROBE_PATH="/sbin/modprobe" +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLOCK_LEGACY_AUTOLOAD=y +CONFIG_BLK_RQ_ALLOC_TIME=y +CONFIG_BLK_DEV_BSG_COMMON=y +# CONFIG_BLK_DEV_BSGLIB is not set +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_WBT is not set +CONFIG_BLK_CGROUP_IOLATENCY=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_BLK_CGROUP_IOPRIO=y +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set +# CONFIG_BLK_INLINE_ENCRYPTION is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_EFI_PARTITION=y +# end of Partition Types + +CONFIG_BLK_MQ_PCI=y +CONFIG_BLK_MQ_VIRTIO=y +CONFIG_BLK_PM=y +CONFIG_BLOCK_HOLDER_DEPRECATED=y +CONFIG_BLK_MQ_STACKING=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +# CONFIG_IOSCHED_BFQ is not set +# end of IO Schedulers + +CONFIG_PREEMPT_NOTIFIERS=y +CONFIG_ASN1=y +CONFIG_UNINLINE_SPIN_UNLOCK=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y +CONFIG_ARCH_HAS_SYNC_CORE_BEFORE_USERMODE=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_BINFMT_SCRIPT=y +CONFIG_BINFMT_MISC=y +CONFIG_COREDUMP=y +# end of Executable file formats + +# +# Memory Management options +# +CONFIG_SWAP=y +# CONFIG_ZSWAP is not set + +# +# SLAB allocator options +# +# CONFIG_SLAB_DEPRECATED is not set +CONFIG_SLUB=y +CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +# CONFIG_SLUB_STATS is not set +CONFIG_SLUB_CPU_PARTIAL=y +# CONFIG_RANDOM_KMALLOC_CACHES is not set +# end of SLAB allocator options + +# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SPARSEMEM=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_ARCH_WANT_OPTIMIZE_DAX_VMEMMAP=y +CONFIG_ARCH_WANT_OPTIMIZE_HUGETLB_VMEMMAP=y +CONFIG_HAVE_FAST_GUP=y +CONFIG_EXCLUSIVE_SYSTEM_RAM=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK=y +CONFIG_COMPACTION=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +# CONFIG_PAGE_REPORTING is not set +CONFIG_MIGRATION=y +CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_MMU_NOTIFIER=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +CONFIG_ARCH_WANT_GENERAL_HUGETLB=y +CONFIG_ARCH_WANTS_THP_SWAP=y +# CONFIG_TRANSPARENT_HUGEPAGE is not set +CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y +CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y +CONFIG_USE_PERCPU_NUMA_NODE_ID=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y +# CONFIG_CMA is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_ARCH_HAS_CURRENT_STACK_POINTER=y +CONFIG_ARCH_HAS_PTE_DEVMAP=y +CONFIG_ZONE_DMA=y +CONFIG_ZONE_DMA32=y +CONFIG_VMAP_PFN=y +CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y +CONFIG_ARCH_HAS_PKEYS=y +CONFIG_VM_EVENT_COUNTERS=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_TEST is not set +# CONFIG_DMAPOOL_TEST is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_MEMFD_CREATE=y +CONFIG_SECRETMEM=y +# CONFIG_ANON_VMA_NAME is not set +# CONFIG_USERFAULTFD is not set +# CONFIG_LRU_GEN is not set +CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y +CONFIG_PER_VMA_LOCK=y +CONFIG_LOCK_MM_AND_FIND_VMA=y + +# +# Data Access Monitoring +# +# CONFIG_DAMON is not set +# end of Data Access Monitoring +# end of Memory Management options + +CONFIG_NET=y +CONFIG_NET_INGRESS=y +CONFIG_NET_EGRESS=y +CONFIG_NET_XGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +CONFIG_AF_UNIX_OOB=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +CONFIG_XFRM_ALGO=y +CONFIG_XFRM_USER=y +# CONFIG_XFRM_USER_COMPAT is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_AH=y +CONFIG_XFRM_ESP=y +# CONFIG_NET_KEY is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_NET_HANDSHAKE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=y +CONFIG_IP_MROUTE_COMMON=y +CONFIG_IP_MROUTE=y +# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +# CONFIG_NET_IPVTI is not set +# CONFIG_NET_FOU is not set +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +CONFIG_INET_TABLE_PERTURB_ORDER=16 +CONFIG_INET_TUNNEL=y +# CONFIG_INET_DIAG is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_NV is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +# CONFIG_TCP_CONG_VENO is not set +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +# CONFIG_TCP_CONG_DCTCP is not set +# CONFIG_TCP_CONG_CDG is not set +# CONFIG_TCP_CONG_BBR is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +# CONFIG_INET6_ESP_OFFLOAD is not set +# CONFIG_INET6_ESPINTCP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_IPV6_VTI is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_IPV6_RPL_LWTUNNEL is not set +# CONFIG_IPV6_IOAM6_LWTUNNEL is not set +CONFIG_NETLABEL=y +# CONFIG_MPTCP is not set +CONFIG_NETWORK_SECMARK=y +CONFIG_NET_PTP_CLASSIFY=y +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_ADVANCED is not set + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_EGRESS=y +CONFIG_NETFILTER_SKIP_EGRESS=y +CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_BPF_LINK=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_LOG_SYSLOG=m +CONFIG_NF_CONNTRACK_SECMARK=y +# CONFIG_NF_CONNTRACK_PROCFS is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_IRC=y +# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set +CONFIG_NF_CONNTRACK_SIP=y +CONFIG_NF_CT_NETLINK=y +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_SIP=y +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=y +# CONFIG_NETFILTER_XTABLES_COMPAT is not set + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=m + +# +# Xtables targets +# +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +CONFIG_NETFILTER_XT_TARGET_MASQUERADE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +# end of Core Netfilter Configuration + +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +CONFIG_NF_LOG_ARP=m +CONFIG_NF_LOG_IPV4=m +CONFIG_NF_REJECT_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_RAW is not set +# end of IP: Netfilter Configuration + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +CONFIG_NF_REJECT_IPV6=y +CONFIG_NF_LOG_IPV6=m +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_IPV6HEADER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +# CONFIG_IP6_NF_RAW is not set +# end of IPv6: Netfilter Configuration + +CONFIG_NF_DEFRAG_IPV6=y +# CONFIG_NF_CONNTRACK_BRIDGE is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC2 is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +# CONFIG_NET_SCH_FQ_CODEL is not set +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_INGRESS is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_ETS is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_FLOW is not set +CONFIG_NET_CLS_CGROUP=y +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +# CONFIG_NET_EMATCH_U32 is not set +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +# CONFIG_NET_EMATCH_IPT is not set +CONFIG_NET_CLS_ACT=y +# CONFIG_NET_ACT_POLICE is not set +# CONFIG_NET_ACT_GACT is not set +# CONFIG_NET_ACT_MIRRED is not set +# CONFIG_NET_ACT_SAMPLE is not set +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_ACT_MPLS is not set +# CONFIG_NET_ACT_VLAN is not set +# CONFIG_NET_ACT_BPF is not set +# CONFIG_NET_ACT_SKBMOD is not set +# CONFIG_NET_ACT_IFE is not set +# CONFIG_NET_ACT_TUNNEL_KEY is not set +# CONFIG_NET_ACT_GATE is not set +# CONFIG_NET_TC_SKB_EXT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_MPLS is not set +# CONFIG_NET_NSH is not set +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_QRTR is not set +# CONFIG_NET_NCSI is not set +CONFIG_PCPU_DEV_REFCNT=y +CONFIG_MAX_SKB_FRAGS=17 +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_SOCK_RX_QUEUE_MAPPING=y +CONFIG_XPS=y +CONFIG_CGROUP_NET_PRIO=y +CONFIG_CGROUP_NET_CLASSID=y +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_NET_DROP_MONITOR is not set +# end of Network testing +# end of Networking options + +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +# CONFIG_MCTP is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_CFG80211=y +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y +CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y +CONFIG_CFG80211_DEFAULT_PS=y +# CONFIG_CFG80211_DEBUGFS is not set +CONFIG_CFG80211_CRDA_SUPPORT=y +# CONFIG_CFG80211_WEXT is not set +CONFIG_MAC80211=y +CONFIG_MAC80211_HAS_RC=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_MAC80211_MESH is not set +CONFIG_MAC80211_LEDS=y +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +CONFIG_RFKILL=y +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +CONFIG_NET_9P=y +CONFIG_NET_9P_FD=y +CONFIG_NET_9P_VIRTIO=y +# CONFIG_NET_9P_DEBUG is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +CONFIG_NET_SELFTESTS=y +CONFIG_NET_SOCK_MSG=y +CONFIG_PAGE_POOL=y +# CONFIG_PAGE_POOL_STATS is not set +CONFIG_FAILOVER=y +CONFIG_ETHTOOL_NETLINK=y + +# +# Device Drivers +# +CONFIG_HAVE_EISA=y +# CONFIG_EISA is not set +CONFIG_HAVE_PCI=y +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCIEPORTBUS=y +# CONFIG_HOTPLUG_PCI_PCIE is not set +# CONFIG_PCIEAER is not set +CONFIG_PCIEASPM=y +CONFIG_PCIEASPM_DEFAULT=y +# CONFIG_PCIEASPM_POWERSAVE is not set +# CONFIG_PCIEASPM_POWER_SUPERSAVE is not set +# CONFIG_PCIEASPM_PERFORMANCE is not set +CONFIG_PCIE_PME=y +# CONFIG_PCIE_PTM is not set +CONFIG_PCI_MSI=y +CONFIG_PCI_QUIRKS=y +# CONFIG_PCI_DEBUG is not set +# CONFIG_PCI_STUB is not set +CONFIG_PCI_ATS=y +CONFIG_PCI_LOCKLESS_CONFIG=y +# CONFIG_PCI_IOV is not set +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_PCI_LABEL=y +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_ACPI is not set +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCI controller drivers +# +# CONFIG_VMD is not set + +# +# Cadence-based PCIe controllers +# +# end of Cadence-based PCIe controllers + +# +# DesignWare-based PCIe controllers +# +# CONFIG_PCI_MESON is not set +# CONFIG_PCIE_DW_PLAT_HOST is not set +# end of DesignWare-based PCIe controllers + +# +# Mobiveil-based PCIe controllers +# +# end of Mobiveil-based PCIe controllers +# end of PCI controller drivers + +# +# PCI Endpoint +# +# CONFIG_PCI_ENDPOINT is not set +# end of PCI Endpoint + +# +# PCI switch controller drivers +# +# CONFIG_PCI_SW_SWITCHTEC is not set +# end of PCI switch controller drivers + +# CONFIG_CXL_BUS is not set +CONFIG_PCCARD=y +CONFIG_PCMCIA=y +CONFIG_PCMCIA_LOAD_CIS=y +CONFIG_CARDBUS=y + +# +# PC-card bridges +# +CONFIG_YENTA=y +CONFIG_YENTA_O2=y +CONFIG_YENTA_RICOH=y +CONFIG_YENTA_TI=y +CONFIG_YENTA_ENE_TUNE=y +CONFIG_YENTA_TOSHIBA=y +# CONFIG_PD6729 is not set +# CONFIG_I82092 is not set +CONFIG_PCCARD_NONSTATIC=y +# CONFIG_RAPIDIO is not set + +# +# Generic Driver Options +# +CONFIG_AUXILIARY_BUS=y +# CONFIG_UEVENT_HELPER is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_DEVTMPFS_SAFE is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_FW_LOADER_USER_HELPER is not set +# CONFIG_FW_LOADER_COMPRESS is not set +CONFIG_FW_CACHE=y +# CONFIG_FW_UPLOAD is not set +# end of Firmware loader + +CONFIG_ALLOW_DEV_COREDUMP=y +# CONFIG_DEBUG_DRIVER is not set +CONFIG_DEBUG_DEVRES=y +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_GENERIC_CPU_VULNERABILITIES=y +CONFIG_REGMAP=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +# CONFIG_FW_DEVLINK_SYNC_STATE_TIMEOUT is not set +# end of Generic Driver Options + +# +# Bus devices +# +# CONFIG_MHI_BUS is not set +# CONFIG_MHI_BUS_EP is not set +# end of Bus devices + +# +# Cache Drivers +# +# end of Cache Drivers + +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y + +# +# Firmware Drivers +# + +# +# ARM System Control and Management Interface Protocol +# +# end of ARM System Control and Management Interface Protocol + +# CONFIG_EDD is not set +CONFIG_FIRMWARE_MEMMAP=y +CONFIG_DMIID=y +# CONFIG_DMI_SYSFS is not set +CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y +# CONFIG_ISCSI_IBFT is not set +# CONFIG_FW_CFG_SYSFS is not set +# CONFIG_SYSFB_SIMPLEFB is not set +# CONFIG_GOOGLE_FIRMWARE is not set + +# +# EFI (Extensible Firmware Interface) Support +# +CONFIG_EFI_ESRT=y +CONFIG_EFI_DXE_MEM_ATTRIBUTES=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_TEST is not set +# CONFIG_APPLE_PROPERTIES is not set +# CONFIG_RESET_ATTACK_MITIGATION is not set +# CONFIG_EFI_RCI2_TABLE is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_CUSTOM_SSDT_OVERLAYS=y +# CONFIG_EFI_DISABLE_RUNTIME is not set +# CONFIG_EFI_COCO_SECRET is not set +# end of EFI (Extensible Firmware Interface) Support + +# +# Tegra firmware driver +# +# end of Tegra firmware driver +# end of Firmware Drivers + +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +# CONFIG_OF is not set +CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y +# CONFIG_PARPORT is not set +CONFIG_PNP=y +CONFIG_PNP_DEBUG_MESSAGES=y + +# +# Protocols +# +CONFIG_PNPACPI=y +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +# CONFIG_BLK_DEV_FD is not set +CONFIG_CDROM=y +# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_VIRTIO_BLK=y +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_BLK_DEV_UBLK is not set + +# +# NVME Support +# +# CONFIG_BLK_DEV_NVME is not set +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TCP is not set +# end of NVME Support + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_IBM_ASM is not set +# CONFIG_PHANTOM is not set +# CONFIG_TIFM_CORE is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_HP_ILO is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_SRAM is not set +# CONFIG_DW_XDATA_PCIE is not set +# CONFIG_PCI_ENDPOINT_TEST is not set +# CONFIG_XILINX_SDFEC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set +# end of EEPROM support + +# CONFIG_CB710_CORE is not set + +# +# Texas Instruments shared transport line discipline +# +# end of Texas Instruments shared transport line discipline + +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set +# CONFIG_INTEL_MEI is not set +# CONFIG_INTEL_MEI_ME is not set +# CONFIG_INTEL_MEI_TXE is not set +# CONFIG_INTEL_MEI_HDCP is not set +# CONFIG_INTEL_MEI_PXP is not set +# CONFIG_INTEL_MEI_GSC_PROXY is not set +# CONFIG_VMWARE_VMCI is not set +# CONFIG_GENWQE is not set +# CONFIG_ECHO is not set +# CONFIG_BCM_VK is not set +# CONFIG_MISC_ALCOR_PCI is not set +# CONFIG_MISC_RTSX_PCI is not set +# CONFIG_MISC_RTSX_USB is not set +# CONFIG_UACCE is not set +# CONFIG_PVPANIC is not set +# end of Misc devices + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI_COMMON=y +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +CONFIG_BLK_DEV_SR=y +CONFIG_CHR_DEV_SG=y +CONFIG_BLK_DEV_BSG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +CONFIG_SCSI_SPI_ATTRS=y +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# end of SCSI Transports + +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_SCSI_CXGB3_ISCSI is not set +# CONFIG_SCSI_CXGB4_ISCSI is not set +# CONFIG_SCSI_BNX2_ISCSI is not set +# CONFIG_BE2ISCSI is not set +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_HPSA is not set +# CONFIG_SCSI_3W_9XXX is not set +# CONFIG_SCSI_3W_SAS is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_AIC94XX is not set +# CONFIG_SCSI_MVSAS is not set +# CONFIG_SCSI_MVUMI is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_ARCMSR is not set +# CONFIG_SCSI_ESAS2R is not set +# CONFIG_MEGARAID_NEWGEN is not set +# CONFIG_MEGARAID_LEGACY is not set +# CONFIG_MEGARAID_SAS is not set +# CONFIG_SCSI_MPT3SAS is not set +# CONFIG_SCSI_MPT2SAS is not set +# CONFIG_SCSI_MPI3MR is not set +# CONFIG_SCSI_SMARTPQI is not set +# CONFIG_SCSI_HPTIOP is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_MYRB is not set +# CONFIG_SCSI_MYRS is not set +# CONFIG_VMWARE_PVSCSI is not set +# CONFIG_SCSI_SNIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_FDOMAIN_PCI is not set +# CONFIG_SCSI_ISCI is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_STEX is not set +# CONFIG_SCSI_SYM53C8XX_2 is not set +# CONFIG_SCSI_IPR is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_QLA_ISCSI is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_WD719X is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_PMCRAID is not set +# CONFIG_SCSI_PM8001 is not set +CONFIG_SCSI_VIRTIO=y +# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set +# CONFIG_SCSI_DH is not set +# end of SCSI device support + +CONFIG_ATA=y +CONFIG_SATA_HOST=y +CONFIG_PATA_TIMINGS=y +CONFIG_ATA_VERBOSE_ERROR=y +CONFIG_ATA_FORCE=y +CONFIG_ATA_ACPI=y +# CONFIG_SATA_ZPODD is not set +CONFIG_SATA_PMP=y + +# +# Controllers with non-SFF native interface +# +CONFIG_SATA_AHCI=y +CONFIG_SATA_MOBILE_LPM_POLICY=0 +# CONFIG_SATA_AHCI_PLATFORM is not set +# CONFIG_AHCI_DWC is not set +# CONFIG_SATA_INIC162X is not set +# CONFIG_SATA_ACARD_AHCI is not set +# CONFIG_SATA_SIL24 is not set +CONFIG_ATA_SFF=y + +# +# SFF controllers with custom DMA interface +# +# CONFIG_PDC_ADMA is not set +# CONFIG_SATA_QSTOR is not set +# CONFIG_SATA_SX4 is not set +CONFIG_ATA_BMDMA=y + +# +# SATA SFF controllers with BMDMA +# +CONFIG_ATA_PIIX=y +# CONFIG_SATA_DWC is not set +# CONFIG_SATA_MV is not set +# CONFIG_SATA_NV is not set +# CONFIG_SATA_PROMISE is not set +# CONFIG_SATA_SIL is not set +# CONFIG_SATA_SIS is not set +# CONFIG_SATA_SVW is not set +# CONFIG_SATA_ULI is not set +# CONFIG_SATA_VIA is not set +# CONFIG_SATA_VITESSE is not set + +# +# PATA SFF controllers with BMDMA +# +# CONFIG_PATA_ALI is not set +CONFIG_PATA_AMD=y +# CONFIG_PATA_ARTOP is not set +# CONFIG_PATA_ATIIXP is not set +# CONFIG_PATA_ATP867X is not set +# CONFIG_PATA_CMD64X is not set +# CONFIG_PATA_CYPRESS is not set +# CONFIG_PATA_EFAR is not set +# CONFIG_PATA_HPT366 is not set +# CONFIG_PATA_HPT37X is not set +# CONFIG_PATA_HPT3X2N is not set +# CONFIG_PATA_HPT3X3 is not set +# CONFIG_PATA_IT8213 is not set +# CONFIG_PATA_IT821X is not set +# CONFIG_PATA_JMICRON is not set +# CONFIG_PATA_MARVELL is not set +# CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set +# CONFIG_PATA_NS87415 is not set +CONFIG_PATA_OLDPIIX=y +# CONFIG_PATA_OPTIDMA is not set +# CONFIG_PATA_PDC2027X is not set +# CONFIG_PATA_PDC_OLD is not set +# CONFIG_PATA_RADISYS is not set +# CONFIG_PATA_RDC is not set +CONFIG_PATA_SCH=y +# CONFIG_PATA_SERVERWORKS is not set +# CONFIG_PATA_SIL680 is not set +# CONFIG_PATA_SIS is not set +# CONFIG_PATA_TOSHIBA is not set +# CONFIG_PATA_TRIFLEX is not set +# CONFIG_PATA_VIA is not set +# CONFIG_PATA_WINBOND is not set + +# +# PIO-only SFF controllers +# +# CONFIG_PATA_CMD640_PCI is not set +# CONFIG_PATA_MPIIX is not set +# CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_OPTI is not set +# CONFIG_PATA_PCMCIA is not set +# CONFIG_PATA_RZ1000 is not set + +# +# Generic fallback / legacy drivers +# +# CONFIG_PATA_ACPI is not set +# CONFIG_ATA_GENERIC is not set +# CONFIG_PATA_LEGACY is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_AUTODETECT=y +CONFIG_MD_BITMAP_FILE=y +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID10 is not set +# CONFIG_MD_RAID456 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_MD_FAULTY is not set +# CONFIG_BCACHE is not set +CONFIG_BLK_DEV_DM_BUILTIN=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +# CONFIG_DM_UNSTRIPED is not set +# CONFIG_DM_CRYPT is not set +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_THIN_PROVISIONING is not set +# CONFIG_DM_CACHE is not set +# CONFIG_DM_WRITECACHE is not set +# CONFIG_DM_EBS is not set +# CONFIG_DM_ERA is not set +# CONFIG_DM_CLONE is not set +CONFIG_DM_MIRROR=y +# CONFIG_DM_LOG_USERSPACE is not set +# CONFIG_DM_RAID is not set +CONFIG_DM_ZERO=y +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +# CONFIG_DM_DUST is not set +# CONFIG_DM_INIT is not set +# CONFIG_DM_UEVENT is not set +# CONFIG_DM_FLAKEY is not set +# CONFIG_DM_VERITY is not set +# CONFIG_DM_SWITCH is not set +# CONFIG_DM_LOG_WRITES is not set +# CONFIG_DM_INTEGRITY is not set +# CONFIG_DM_AUDIT is not set +# CONFIG_TARGET_CORE is not set +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_FIREWIRE is not set +# CONFIG_FIREWIRE_NOSY is not set +# end of IEEE 1394 (FireWire) support + +CONFIG_MACINTOSH_DRIVERS=y +CONFIG_MAC_EMUMOUSEBTN=y +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_WIREGUARD is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_FC is not set +# CONFIG_NET_TEAM is not set +# CONFIG_MACVLAN is not set +# CONFIG_IPVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_GENEVE is not set +# CONFIG_BAREUDP is not set +# CONFIG_GTP is not set +# CONFIG_AMT is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=y +# CONFIG_NETCONSOLE_EXTENDED_LOG is not set +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +# CONFIG_TUN is not set +# CONFIG_TUN_VNET_CROSS_LE is not set +# CONFIG_VETH is not set +CONFIG_VIRTIO_NET=y +# CONFIG_NLMON is not set +# CONFIG_ARCNET is not set +CONFIG_ETHERNET=y +CONFIG_NET_VENDOR_3COM=y +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_VORTEX is not set +# CONFIG_TYPHOON is not set +CONFIG_NET_VENDOR_ADAPTEC=y +# CONFIG_ADAPTEC_STARFIRE is not set +CONFIG_NET_VENDOR_AGERE=y +# CONFIG_ET131X is not set +CONFIG_NET_VENDOR_ALACRITECH=y +# CONFIG_SLICOSS is not set +CONFIG_NET_VENDOR_ALTEON=y +# CONFIG_ACENIC is not set +# CONFIG_ALTERA_TSE is not set +CONFIG_NET_VENDOR_AMAZON=y +# CONFIG_ENA_ETHERNET is not set +CONFIG_NET_VENDOR_AMD=y +# CONFIG_AMD8111_ETH is not set +# CONFIG_PCNET32 is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_AMD_XGBE is not set +# CONFIG_PDS_CORE is not set +CONFIG_NET_VENDOR_AQUANTIA=y +# CONFIG_AQTION is not set +CONFIG_NET_VENDOR_ARC=y +CONFIG_NET_VENDOR_ASIX=y +CONFIG_NET_VENDOR_ATHEROS=y +# CONFIG_ATL2 is not set +# CONFIG_ATL1 is not set +# CONFIG_ATL1E is not set +# CONFIG_ATL1C is not set +# CONFIG_ALX is not set +# CONFIG_CX_ECAT is not set +CONFIG_NET_VENDOR_BROADCOM=y +# CONFIG_B44 is not set +# CONFIG_BCMGENET is not set +# CONFIG_BNX2 is not set +# CONFIG_CNIC is not set +CONFIG_TIGON3=y +CONFIG_TIGON3_HWMON=y +# CONFIG_BNX2X is not set +# CONFIG_SYSTEMPORT is not set +# CONFIG_BNXT is not set +CONFIG_NET_VENDOR_CADENCE=y +CONFIG_NET_VENDOR_CAVIUM=y +# CONFIG_THUNDER_NIC_PF is not set +# CONFIG_THUNDER_NIC_VF is not set +# CONFIG_THUNDER_NIC_BGX is not set +# CONFIG_THUNDER_NIC_RGX is not set +# CONFIG_CAVIUM_PTP is not set +# CONFIG_LIQUIDIO is not set +# CONFIG_LIQUIDIO_VF is not set +CONFIG_NET_VENDOR_CHELSIO=y +# CONFIG_CHELSIO_T1 is not set +# CONFIG_CHELSIO_T3 is not set +# CONFIG_CHELSIO_T4 is not set +# CONFIG_CHELSIO_T4VF is not set +CONFIG_NET_VENDOR_CISCO=y +# CONFIG_ENIC is not set +CONFIG_NET_VENDOR_CORTINA=y +CONFIG_NET_VENDOR_DAVICOM=y +# CONFIG_DNET is not set +CONFIG_NET_VENDOR_DEC=y +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +# CONFIG_TULIP is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_ULI526X is not set +# CONFIG_PCMCIA_XIRCOM is not set +CONFIG_NET_VENDOR_DLINK=y +# CONFIG_DL2K is not set +# CONFIG_SUNDANCE is not set +CONFIG_NET_VENDOR_EMULEX=y +# CONFIG_BE2NET is not set +CONFIG_NET_VENDOR_ENGLEDER=y +# CONFIG_TSNEP is not set +CONFIG_NET_VENDOR_EZCHIP=y +CONFIG_NET_VENDOR_FUJITSU=y +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_NET_VENDOR_FUNGIBLE=y +# CONFIG_FUN_ETH is not set +CONFIG_NET_VENDOR_GOOGLE=y +# CONFIG_GVE is not set +CONFIG_NET_VENDOR_HUAWEI=y +# CONFIG_HINIC is not set +CONFIG_NET_VENDOR_I825XX=y +CONFIG_NET_VENDOR_INTEL=y +CONFIG_E100=y +CONFIG_E1000=y +CONFIG_E1000E=y +CONFIG_E1000E_HWTS=y +# CONFIG_IGB is not set +# CONFIG_IGBVF is not set +# CONFIG_IXGBE is not set +# CONFIG_IXGBEVF is not set +# CONFIG_I40E is not set +# CONFIG_I40EVF is not set +# CONFIG_ICE is not set +# CONFIG_FM10K is not set +# CONFIG_IGC is not set +# CONFIG_JME is not set +CONFIG_NET_VENDOR_LITEX=y +CONFIG_NET_VENDOR_MARVELL=y +# CONFIG_MVMDIO is not set +# CONFIG_SKGE is not set +CONFIG_SKY2=y +# CONFIG_SKY2_DEBUG is not set +# CONFIG_OCTEON_EP is not set +CONFIG_NET_VENDOR_MELLANOX=y +# CONFIG_MLX4_EN is not set +# CONFIG_MLX5_CORE is not set +# CONFIG_MLXSW_CORE is not set +# CONFIG_MLXFW is not set +CONFIG_NET_VENDOR_MICREL=y +# CONFIG_KS8842 is not set +# CONFIG_KS8851_MLL is not set +# CONFIG_KSZ884X_PCI is not set +CONFIG_NET_VENDOR_MICROCHIP=y +# CONFIG_LAN743X is not set +# CONFIG_VCAP is not set +CONFIG_NET_VENDOR_MICROSEMI=y +CONFIG_NET_VENDOR_MICROSOFT=y +CONFIG_NET_VENDOR_MYRI=y +# CONFIG_MYRI10GE is not set +# CONFIG_FEALNX is not set +CONFIG_NET_VENDOR_NI=y +# CONFIG_NI_XGE_MANAGEMENT_ENET is not set +CONFIG_NET_VENDOR_NATSEMI=y +# CONFIG_NATSEMI is not set +# CONFIG_NS83820 is not set +CONFIG_NET_VENDOR_NETERION=y +# CONFIG_S2IO is not set +CONFIG_NET_VENDOR_NETRONOME=y +# CONFIG_NFP is not set +CONFIG_NET_VENDOR_8390=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_PCMCIA_PCNET is not set +CONFIG_NET_VENDOR_NVIDIA=y +CONFIG_FORCEDETH=y +CONFIG_NET_VENDOR_OKI=y +# CONFIG_ETHOC is not set +CONFIG_NET_VENDOR_PACKET_ENGINES=y +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +CONFIG_NET_VENDOR_PENSANDO=y +# CONFIG_IONIC is not set +CONFIG_NET_VENDOR_QLOGIC=y +# CONFIG_QLA3XXX is not set +# CONFIG_QLCNIC is not set +# CONFIG_NETXEN_NIC is not set +# CONFIG_QED is not set +CONFIG_NET_VENDOR_BROCADE=y +# CONFIG_BNA is not set +CONFIG_NET_VENDOR_QUALCOMM=y +# CONFIG_QCOM_EMAC is not set +# CONFIG_RMNET is not set +CONFIG_NET_VENDOR_RDC=y +# CONFIG_R6040 is not set +CONFIG_NET_VENDOR_REALTEK=y +# CONFIG_8139CP is not set +CONFIG_8139TOO=y +CONFIG_8139TOO_PIO=y +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +CONFIG_R8169=y +CONFIG_NET_VENDOR_RENESAS=y +CONFIG_NET_VENDOR_ROCKER=y +CONFIG_NET_VENDOR_SAMSUNG=y +# CONFIG_SXGBE_ETH is not set +CONFIG_NET_VENDOR_SEEQ=y +CONFIG_NET_VENDOR_SILAN=y +# CONFIG_SC92031 is not set +CONFIG_NET_VENDOR_SIS=y +# CONFIG_SIS900 is not set +# CONFIG_SIS190 is not set +CONFIG_NET_VENDOR_SOLARFLARE=y +# CONFIG_SFC is not set +# CONFIG_SFC_FALCON is not set +# CONFIG_SFC_SIENA is not set +CONFIG_NET_VENDOR_SMSC=y +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SMSC911X is not set +# CONFIG_SMSC9420 is not set +CONFIG_NET_VENDOR_SOCIONEXT=y +CONFIG_NET_VENDOR_STMICRO=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NET_VENDOR_SUN=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_CASSINI is not set +# CONFIG_NIU is not set +CONFIG_NET_VENDOR_SYNOPSYS=y +# CONFIG_DWC_XLGMAC is not set +CONFIG_NET_VENDOR_TEHUTI=y +# CONFIG_TEHUTI is not set +CONFIG_NET_VENDOR_TI=y +# CONFIG_TI_CPSW_PHY_SEL is not set +# CONFIG_TLAN is not set +CONFIG_NET_VENDOR_VERTEXCOM=y +CONFIG_NET_VENDOR_VIA=y +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_VELOCITY is not set +CONFIG_NET_VENDOR_WANGXUN=y +# CONFIG_NGBE is not set +CONFIG_NET_VENDOR_WIZNET=y +# CONFIG_WIZNET_W5100 is not set +# CONFIG_WIZNET_W5300 is not set +CONFIG_NET_VENDOR_XILINX=y +# CONFIG_XILINX_EMACLITE is not set +# CONFIG_XILINX_AXI_EMAC is not set +# CONFIG_XILINX_LL_TEMAC is not set +CONFIG_NET_VENDOR_XIRCOM=y +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_NET_SB1000 is not set +CONFIG_PHYLIB=y +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set +CONFIG_FIXED_PHY=y + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_ADIN_PHY is not set +# CONFIG_ADIN1100_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_AX88796B_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_BCM54140_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM84881_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +# CONFIG_MARVELL_88Q2XXX_PHY is not set +# CONFIG_MARVELL_88X2222_PHY is not set +# CONFIG_MAXLINEAR_GPHY is not set +# CONFIG_MEDIATEK_GE_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_MICROCHIP_T1S_PHY is not set +# CONFIG_MICROCHIP_PHY is not set +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_MOTORCOMM_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_NXP_CBTX_PHY is not set +# CONFIG_NXP_C45_TJA11XX_PHY is not set +# CONFIG_NXP_TJA11XX_PHY is not set +# CONFIG_NCN26000_PHY is not set +# CONFIG_QSEMI_PHY is not set +CONFIG_REALTEK_PHY=y +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +# CONFIG_DP83869_PHY is not set +# CONFIG_DP83TD510_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_PSE_CONTROLLER is not set +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_BUS=y +CONFIG_FWNODE_MDIO=y +CONFIG_ACPI_MDIO=y +CONFIG_MDIO_DEVRES=y +# CONFIG_MDIO_BITBANG is not set +# CONFIG_MDIO_BCM_UNIMAC is not set +# CONFIG_MDIO_MVUSB is not set +# CONFIG_MDIO_THUNDER is not set + +# +# MDIO Multiplexers +# + +# +# PCS device drivers +# +# end of PCS device drivers + +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +CONFIG_USB_NET_DRIVERS=y +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_RTL8152 is not set +# CONFIG_USB_LAN78XX is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_IPHETH is not set +CONFIG_WLAN=y +CONFIG_WLAN_VENDOR_ADMTEK=y +# CONFIG_ADM8211 is not set +CONFIG_WLAN_VENDOR_ATH=y +# CONFIG_ATH_DEBUG is not set +# CONFIG_ATH5K is not set +# CONFIG_ATH5K_PCI is not set +# CONFIG_ATH9K is not set +# CONFIG_ATH9K_HTC is not set +# CONFIG_CARL9170 is not set +# CONFIG_ATH6KL is not set +# CONFIG_AR5523 is not set +# CONFIG_WIL6210 is not set +# CONFIG_ATH10K is not set +# CONFIG_WCN36XX is not set +CONFIG_WLAN_VENDOR_ATMEL=y +# CONFIG_ATMEL is not set +# CONFIG_AT76C50X_USB is not set +CONFIG_WLAN_VENDOR_BROADCOM=y +# CONFIG_B43 is not set +# CONFIG_B43LEGACY is not set +# CONFIG_BRCMSMAC is not set +# CONFIG_BRCMFMAC is not set +CONFIG_WLAN_VENDOR_CISCO=y +# CONFIG_AIRO is not set +# CONFIG_AIRO_CS is not set +CONFIG_WLAN_VENDOR_INTEL=y +# CONFIG_IPW2100 is not set +# CONFIG_IPW2200 is not set +# CONFIG_IWL4965 is not set +# CONFIG_IWL3945 is not set +# CONFIG_IWLWIFI is not set +CONFIG_WLAN_VENDOR_INTERSIL=y +# CONFIG_HOSTAP is not set +# CONFIG_HERMES is not set +# CONFIG_P54_COMMON is not set +CONFIG_WLAN_VENDOR_MARVELL=y +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_MWIFIEX is not set +# CONFIG_MWL8K is not set +CONFIG_WLAN_VENDOR_MEDIATEK=y +# CONFIG_MT7601U is not set +# CONFIG_MT76x0U is not set +# CONFIG_MT76x0E is not set +# CONFIG_MT76x2E is not set +# CONFIG_MT76x2U is not set +# CONFIG_MT7603E is not set +# CONFIG_MT7615E is not set +# CONFIG_MT7663U is not set +# CONFIG_MT7915E is not set +# CONFIG_MT7921E is not set +# CONFIG_MT7921U is not set +# CONFIG_MT7996E is not set +CONFIG_WLAN_VENDOR_MICROCHIP=y +CONFIG_WLAN_VENDOR_PURELIFI=y +# CONFIG_PLFXLC is not set +CONFIG_WLAN_VENDOR_RALINK=y +# CONFIG_RT2X00 is not set +CONFIG_WLAN_VENDOR_REALTEK=y +# CONFIG_RTL8180 is not set +# CONFIG_RTL8187 is not set +CONFIG_RTL_CARDS=y +# CONFIG_RTL8192CE is not set +# CONFIG_RTL8192SE is not set +# CONFIG_RTL8192DE is not set +# CONFIG_RTL8723AE is not set +# CONFIG_RTL8723BE is not set +# CONFIG_RTL8188EE is not set +# CONFIG_RTL8192EE is not set +# CONFIG_RTL8821AE is not set +# CONFIG_RTL8192CU is not set +# CONFIG_RTL8XXXU is not set +# CONFIG_RTW88 is not set +# CONFIG_RTW89 is not set +CONFIG_WLAN_VENDOR_RSI=y +# CONFIG_RSI_91X is not set +CONFIG_WLAN_VENDOR_SILABS=y +CONFIG_WLAN_VENDOR_ST=y +# CONFIG_CW1200 is not set +CONFIG_WLAN_VENDOR_TI=y +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +# CONFIG_WL18XX is not set +# CONFIG_WLCORE is not set +CONFIG_WLAN_VENDOR_ZYDAS=y +# CONFIG_USB_ZD1201 is not set +# CONFIG_ZD1211RW is not set +CONFIG_WLAN_VENDOR_QUANTENNA=y +# CONFIG_QTNFMAC_PCIE is not set +# CONFIG_PCMCIA_RAYCS is not set +# CONFIG_PCMCIA_WL3501 is not set +# CONFIG_USB_NET_RNDIS_WLAN is not set +# CONFIG_MAC80211_HWSIM is not set +# CONFIG_VIRT_WIFI is not set +# CONFIG_WAN is not set + +# +# Wireless WAN +# +# CONFIG_WWAN is not set +# end of Wireless WAN + +# CONFIG_VMXNET3 is not set +# CONFIG_FUJITSU_ES is not set +# CONFIG_NETDEVSIM is not set +CONFIG_NET_FAILOVER=y +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_LEDS=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_SPARSEKMAP=y +# CONFIG_INPUT_MATRIXKMAP is not set +CONFIG_INPUT_VIVALDIFMAP=y + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +CONFIG_KEYBOARD_ATKBD=y +# CONFIG_KEYBOARD_QT1050 is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_DLINK_DIR685 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_CYPRESS_SF is not set +CONFIG_INPUT_MOUSE=y +CONFIG_MOUSE_PS2=y +CONFIG_MOUSE_PS2_ALPS=y +CONFIG_MOUSE_PS2_BYD=y +CONFIG_MOUSE_PS2_LOGIPS2PP=y +CONFIG_MOUSE_PS2_SYNAPTICS=y +CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS=y +CONFIG_MOUSE_PS2_CYPRESS=y +CONFIG_MOUSE_PS2_LIFEBOOK=y +CONFIG_MOUSE_PS2_TRACKPOINT=y +# CONFIG_MOUSE_PS2_ELANTECH is not set +# CONFIG_MOUSE_PS2_SENTELIC is not set +# CONFIG_MOUSE_PS2_TOUCHKIT is not set +CONFIG_MOUSE_PS2_FOCALTECH=y +# CONFIG_MOUSE_PS2_VMMOUSE is not set +CONFIG_MOUSE_PS2_SMBUS=y +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +# CONFIG_JOYSTICK_XPAD is not set +# CONFIG_JOYSTICK_PXRC is not set +# CONFIG_JOYSTICK_QWIIC is not set +# CONFIG_JOYSTICK_FSIA6B is not set +# CONFIG_JOYSTICK_SENSEHAT is not set +CONFIG_INPUT_TABLET=y +# CONFIG_TABLET_USB_ACECAD is not set +# CONFIG_TABLET_USB_AIPTEK is not set +# CONFIG_TABLET_USB_HANWANG is not set +# CONFIG_TABLET_USB_KBTAB is not set +# CONFIG_TABLET_USB_PEGASUS is not set +# CONFIG_TABLET_SERIAL_WACOM4 is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_BU21029 is not set +# CONFIG_TOUCHSCREEN_CHIPONE_ICN8505 is not set +# CONFIG_TOUCHSCREEN_CY8CTMA140 is not set +# CONFIG_TOUCHSCREEN_CYTTSP_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set +# CONFIG_TOUCHSCREEN_CYTTSP5 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_EGALAX_SERIAL is not set +# CONFIG_TOUCHSCREEN_EXC3000 is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_HIDEEP is not set +# CONFIG_TOUCHSCREEN_HYCON_HY46XX is not set +# CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX is not set +# CONFIG_TOUCHSCREEN_ILI210X is not set +# CONFIG_TOUCHSCREEN_ILITEK is not set +# CONFIG_TOUCHSCREEN_S6SY761 is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_EKTF2127 is not set +# CONFIG_TOUCHSCREEN_ELAN is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_WACOM_I2C is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MMS114 is not set +# CONFIG_TOUCHSCREEN_MELFAS_MIP4 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS is not set +# CONFIG_TOUCHSCREEN_IMAGIS is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_EDT_FT5X06 is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_PIXCIR is not set +# CONFIG_TOUCHSCREEN_WDT87XX_I2C is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC_SERIO is not set +# CONFIG_TOUCHSCREEN_TSC2004 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_SILEAD is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_STMFTS is not set +# CONFIG_TOUCHSCREEN_SX8654 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +# CONFIG_TOUCHSCREEN_ZET6223 is not set +# CONFIG_TOUCHSCREEN_ROHM_BU21023 is not set +# CONFIG_TOUCHSCREEN_IQS5XX is not set +# CONFIG_TOUCHSCREEN_IQS7211 is not set +# CONFIG_TOUCHSCREEN_ZINITIX is not set +# CONFIG_TOUCHSCREEN_HIMAX_HX83112B is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_APANEL is not set +# CONFIG_INPUT_ATLAS_BTNS is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_DA7280_HAPTICS is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_IQS269A is not set +# CONFIG_INPUT_IQS626A is not set +# CONFIG_INPUT_IQS7222 is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_IDEAPAD_SLIDEBAR is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +# CONFIG_RMI4_CORE is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y +CONFIG_SERIO_I8042=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set +# end of Hardware I/O ports +# end of Input device support + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_LEGACY_TIOCSTI=y +CONFIG_LDISC_AUTOLOAD=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_PNP=y +# CONFIG_SERIAL_8250_16550A_VARIANTS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_DMA=y +CONFIG_SERIAL_8250_PCILIB=y +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_EXAR=y +# CONFIG_SERIAL_8250_CS is not set +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +# CONFIG_SERIAL_8250_PCI1XXXX is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_DWLIB=y +# CONFIG_SERIAL_8250_DW is not set +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_8250_LPSS=y +CONFIG_SERIAL_8250_MID=y +CONFIG_SERIAL_8250_PERICOM=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_JSM is not set +# CONFIG_SERIAL_LANTIQ is not set +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_RP2 is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_FSL_LINFLEXUART is not set +# end of Serial drivers + +CONFIG_SERIAL_NONSTANDARD=y +# CONFIG_MOXA_INTELLIO is not set +# CONFIG_MOXA_SMARTIO is not set +# CONFIG_N_HDLC is not set +# CONFIG_IPWIRELESS is not set +# CONFIG_N_GSM is not set +# CONFIG_NOZOMI is not set +# CONFIG_NULL_TTY is not set +CONFIG_HVC_DRIVER=y +# CONFIG_SERIAL_DEV_BUS is not set +CONFIG_VIRTIO_CONSOLE=y +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_BA431 is not set +CONFIG_HW_RANDOM_VIA=y +# CONFIG_HW_RANDOM_VIRTIO is not set +# CONFIG_HW_RANDOM_XIPHERA is not set +# CONFIG_APPLICOM is not set +# CONFIG_MWAVE is not set +CONFIG_DEVMEM=y +CONFIG_NVRAM=y +CONFIG_DEVPORT=y +CONFIG_HPET=y +# CONFIG_HPET_MMAP is not set +# CONFIG_HANGCHECK_TIMER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_TELCLOCK is not set +# CONFIG_XILLYBUS is not set +# CONFIG_XILLYUSB is not set +# end of Character devices + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_ACPI_I2C_OPREGION=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +# CONFIG_I2C_CHARDEV is not set +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_SMBUS=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# PC SMBus host controller drivers +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_AMD_MP2 is not set +CONFIG_I2C_I801=y +# CONFIG_I2C_ISCH is not set +# CONFIG_I2C_ISMT is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_NVIDIA_GPU is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set + +# +# ACPI drivers +# +# CONFIG_I2C_SCMI is not set + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE_PCI is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_CP2615 is not set +# CONFIG_I2C_PCI1XXXX is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_MLXCPLD is not set +# CONFIG_I2C_VIRTIO is not set +# end of I2C Hardware Bus support + +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_SLAVE is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# end of I2C support + +# CONFIG_I3C is not set +# CONFIG_SPI is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PTP_1588_CLOCK_KVM=y +# CONFIG_PTP_1588_CLOCK_IDT82P33 is not set +# CONFIG_PTP_1588_CLOCK_IDTCM is not set +# CONFIG_PTP_1588_CLOCK_MOCK is not set +# CONFIG_PTP_1588_CLOCK_VMW is not set +# end of PTP clock support + +# CONFIG_PINCTRL is not set +# CONFIG_GPIOLIB is not set +# CONFIG_W1 is not set +# CONFIG_POWER_RESET is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +CONFIG_POWER_SUPPLY_HWMON=y +# CONFIG_IP5XXX_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_BATTERY_CW2015 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_SAMSUNG_SDI is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_LTC4162L is not set +# CONFIG_CHARGER_MAX77976 is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_BATTERY_GOLDFISH is not set +# CONFIG_BATTERY_RT5033 is not set +# CONFIG_CHARGER_BD99954 is not set +# CONFIG_BATTERY_UG3105 is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM1177 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_AHT10 is not set +# CONFIG_SENSORS_AQUACOMPUTER_D5NEXT is not set +# CONFIG_SENSORS_AS370 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_AXI_FAN_CONTROL is not set +# CONFIG_SENSORS_K8TEMP is not set +# CONFIG_SENSORS_K10TEMP is not set +# CONFIG_SENSORS_FAM15H_POWER is not set +# CONFIG_SENSORS_APPLESMC is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_CORSAIR_CPRO is not set +# CONFIG_SENSORS_CORSAIR_PSU is not set +# CONFIG_SENSORS_DRIVETEMP is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_DELL_SMM is not set +# CONFIG_SENSORS_I5K_AMB is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FSCHMD is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_HS3001 is not set +# CONFIG_SENSORS_I5500 is not set +# CONFIG_SENSORS_CORETEMP is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2947_I2C is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX127 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX31730 is not set +# CONFIG_SENSORS_MAX31760 is not set +# CONFIG_MAX31827 is not set +# CONFIG_SENSORS_MAX6620 is not set +# CONFIG_SENSORS_MAX6621 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MC34VR500 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_TPS23861 is not set +# CONFIG_SENSORS_MR75203 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT6775_I2C is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_NZXT_KRAKEN2 is not set +# CONFIG_SENSORS_NZXT_SMART2 is not set +# CONFIG_SENSORS_OCC_P8_I2C is not set +# CONFIG_SENSORS_OXP is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +# CONFIG_SENSORS_SBTSI is not set +# CONFIG_SENSORS_SBRMI is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHT4x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_SIS5595 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC2305 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA238 is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP108 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_TMP464 is not set +# CONFIG_SENSORS_TMP513 is not set +# CONFIG_SENSORS_VIA_CPUTEMP is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set +# CONFIG_SENSORS_W83773G is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_XGENE is not set + +# +# ACPI drivers +# +# CONFIG_SENSORS_ACPI_POWER is not set +# CONFIG_SENSORS_ATK0110 is not set +# CONFIG_SENSORS_ASUS_WMI is not set +# CONFIG_SENSORS_ASUS_EC is not set +# CONFIG_SENSORS_HP_WMI is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_NETLINK is not set +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +CONFIG_THERMAL_GOV_USER_SPACE=y +# CONFIG_THERMAL_EMULATION is not set + +# +# Intel thermal drivers +# +# CONFIG_INTEL_POWERCLAMP is not set +CONFIG_X86_THERMAL_VECTOR=y +CONFIG_INTEL_TCC=y +CONFIG_X86_PKG_TEMP_THERMAL=m +# CONFIG_INTEL_SOC_DTS_THERMAL is not set + +# +# ACPI INT340X thermal drivers +# +# CONFIG_INT340X_THERMAL is not set +# end of ACPI INT340X thermal drivers + +# CONFIG_INTEL_PCH_THERMAL is not set +# CONFIG_INTEL_TCC_COOLING is not set +# CONFIG_INTEL_HFI_THERMAL is not set +# end of Intel thermal drivers + +CONFIG_WATCHDOG=y +# CONFIG_WATCHDOG_CORE is not set +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +CONFIG_WATCHDOG_OPEN_TIMEOUT=0 +# CONFIG_WATCHDOG_SYSFS is not set +# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set + +# +# Watchdog Pretimeout Governors +# + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_WDAT_WDT is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ADVANTECH_EC_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_EBC_C384_WDT is not set +# CONFIG_EXAR_WDT is not set +# CONFIG_F71808E_WDT is not set +# CONFIG_SP5100_TCO is not set +# CONFIG_SBC_FITPC2_WATCHDOG is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_IBMASR is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_I6300ESB_WDT is not set +# CONFIG_IE6XX_WDT is not set +# CONFIG_ITCO_WDT is not set +# CONFIG_IT8712F_WDT is not set +# CONFIG_IT87_WDT is not set +# CONFIG_HP_WATCHDOG is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_PC87413_WDT is not set +# CONFIG_NV_TCO is not set +# CONFIG_60XX_WDT is not set +# CONFIG_CPU5_WDT is not set +# CONFIG_SMSC_SCH311X_WDT is not set +# CONFIG_SMSC37B787_WDT is not set +# CONFIG_TQMX86_WDT is not set +# CONFIG_VIA_WDT is not set +# CONFIG_W83627HF_WDT is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_W83977F_WDT is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_SBC_EPX_C3_WATCHDOG is not set +# CONFIG_NI903X_WDT is not set +# CONFIG_NIC7018_WDT is not set + +# +# PCI-based Watchdog Cards +# +# CONFIG_PCIPCWATCHDOG is not set +# CONFIG_WDTPCI is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y +# CONFIG_BCMA is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_SMPRO is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +# CONFIG_MFD_CS42L43_I2C is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_MP2629 is not set +# CONFIG_LPC_ICH is not set +# CONFIG_LPC_SCH is not set +# CONFIG_MFD_INTEL_LPSS_ACPI is not set +# CONFIG_MFD_INTEL_LPSS_PCI is not set +# CONFIG_MFD_INTEL_PMC_BXT is not set +# CONFIG_MFD_IQS62X is not set +# CONFIG_MFD_JANZ_CMODIO is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77541 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MT6360 is not set +# CONFIG_MFD_MT6370 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_SY7636A is not set +# CONFIG_MFD_RDC321X is not set +# CONFIG_MFD_RT4831 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RT5120 is not set +# CONFIG_MFD_RC5T583 is not set +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SYSCON is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS6594_I2C is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_VX855 is not set +# CONFIG_MFD_ARIZONA_I2C is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_ATC260X_I2C is not set +# end of Multifunction device drivers + +# CONFIG_REGULATOR is not set +# CONFIG_RC_CORE is not set + +# +# CEC support +# +# CONFIG_MEDIA_CEC_SUPPORT is not set +# end of CEC support + +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +CONFIG_APERTURE_HELPERS=y +CONFIG_VIDEO_CMDLINE=y +CONFIG_VIDEO_NOMODESET=y +# CONFIG_AUXDISPLAY is not set +CONFIG_AGP=y +CONFIG_AGP_AMD64=y +CONFIG_AGP_INTEL=y +# CONFIG_AGP_SIS is not set +# CONFIG_AGP_VIA is not set +CONFIG_INTEL_GTT=y +# CONFIG_VGA_SWITCHEROO is not set +CONFIG_DRM=y +CONFIG_DRM_MIPI_DSI=y +# CONFIG_DRM_DEBUG_MM is not set +CONFIG_DRM_KMS_HELPER=y +# CONFIG_DRM_FBDEV_EMULATION is not set +# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set +CONFIG_DRM_DISPLAY_HELPER=y +CONFIG_DRM_DISPLAY_DP_HELPER=y +CONFIG_DRM_DISPLAY_HDCP_HELPER=y +CONFIG_DRM_DISPLAY_HDMI_HELPER=y +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DP_CEC is not set +CONFIG_DRM_TTM=y +CONFIG_DRM_BUDDY=y +CONFIG_DRM_GEM_SHMEM_HELPER=y + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set +# end of I2C encoder or helper chips + +# +# ARM devices +# +# end of ARM devices + +# CONFIG_DRM_RADEON is not set +# CONFIG_DRM_AMDGPU is not set +# CONFIG_DRM_NOUVEAU is not set +CONFIG_DRM_I915=y +CONFIG_DRM_I915_FORCE_PROBE="" +CONFIG_DRM_I915_CAPTURE_ERROR=y +CONFIG_DRM_I915_COMPRESS_ERROR=y +CONFIG_DRM_I915_USERPTR=y +CONFIG_DRM_I915_REQUEST_TIMEOUT=20000 +CONFIG_DRM_I915_FENCE_TIMEOUT=10000 +CONFIG_DRM_I915_USERFAULT_AUTOSUSPEND=250 +CONFIG_DRM_I915_HEARTBEAT_INTERVAL=2500 +CONFIG_DRM_I915_PREEMPT_TIMEOUT=640 +CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE=7500 +CONFIG_DRM_I915_MAX_REQUEST_BUSYWAIT=8000 +CONFIG_DRM_I915_STOP_TIMEOUT=100 +CONFIG_DRM_I915_TIMESLICE_DURATION=1 +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_VMWGFX is not set +# CONFIG_DRM_GMA500 is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_AST is not set +# CONFIG_DRM_MGAG200 is not set +# CONFIG_DRM_QXL is not set +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_DRM_VIRTIO_GPU_KMS=y +CONFIG_DRM_PANEL=y + +# +# Display Panels +# +# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set +# end of Display Panels + +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_PANEL_BRIDGE=y + +# +# Display Interface Bridges +# +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# end of Display Interface Bridges + +# CONFIG_DRM_LOONGSON is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_BOCHS is not set +# CONFIG_DRM_CIRRUS_QEMU is not set +# CONFIG_DRM_GM12U320 is not set +# CONFIG_DRM_SIMPLEDRM is not set +# CONFIG_DRM_VBOXVIDEO is not set +# CONFIG_DRM_GUD is not set +# CONFIG_DRM_SSD130X is not set +# CONFIG_DRM_LEGACY is not set +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y + +# +# Frame buffer Devices +# +# CONFIG_FB is not set +# end of Frame buffer Devices + +# +# Backlight & LCD device support +# +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_KTZ8866 is not set +# CONFIG_BACKLIGHT_APPLE is not set +# CONFIG_BACKLIGHT_QCOM_WLED is not set +# CONFIG_BACKLIGHT_SAHARA is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +# end of Backlight & LCD device support + +CONFIG_HDMI=y + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +# end of Console display driver support +# end of Graphics support + +# CONFIG_DRM_ACCEL is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_HWDEP=y +CONFIG_SND_SEQ_DEVICE=y +CONFIG_SND_JACK=y +CONFIG_SND_JACK_INPUT_DEV=y +# CONFIG_SND_OSSEMUL is not set +CONFIG_SND_PCM_TIMER=y +CONFIG_SND_HRTIMER=y +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_PROC_FS=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +CONFIG_SND_CTL_FAST_LOOKUP=y +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_CTL_INPUT_VALIDATION is not set +CONFIG_SND_VMASTER=y +CONFIG_SND_DMA_SGBUF=y +CONFIG_SND_SEQUENCER=y +CONFIG_SND_SEQ_DUMMY=y +CONFIG_SND_SEQ_HRTIMER_DEFAULT=y +# CONFIG_SND_SEQ_UMP is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_PCSP is not set +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_PCMTEST is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_PCI=y +# CONFIG_SND_AD1889 is not set +# CONFIG_SND_ALS300 is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_ASIHPI is not set +# CONFIG_SND_ATIIXP is not set +# CONFIG_SND_ATIIXP_MODEM is not set +# CONFIG_SND_AU8810 is not set +# CONFIG_SND_AU8820 is not set +# CONFIG_SND_AU8830 is not set +# CONFIG_SND_AW2 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CA0106 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CTXFI is not set +# CONFIG_SND_DARLA20 is not set +# CONFIG_SND_GINA20 is not set +# CONFIG_SND_LAYLA20 is not set +# CONFIG_SND_DARLA24 is not set +# CONFIG_SND_GINA24 is not set +# CONFIG_SND_LAYLA24 is not set +# CONFIG_SND_MONA is not set +# CONFIG_SND_MIA is not set +# CONFIG_SND_ECHO3G is not set +# CONFIG_SND_INDIGO is not set +# CONFIG_SND_INDIGOIO is not set +# CONFIG_SND_INDIGODJ is not set +# CONFIG_SND_INDIGOIOX is not set +# CONFIG_SND_INDIGODJX is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_EMU10K1X is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_FM801 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_HDSPM is not set +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_INTEL8X0M is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_LOLA is not set +# CONFIG_SND_LX6464ES is not set +# CONFIG_SND_MAESTRO3 is not set +# CONFIG_SND_MIXART is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_PCXHR is not set +# CONFIG_SND_RIPTIDE is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_SE6X is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set +# CONFIG_SND_VX222 is not set +# CONFIG_SND_YMFPCI is not set + +# +# HD-Audio +# +CONFIG_SND_HDA=y +CONFIG_SND_HDA_INTEL=y +CONFIG_SND_HDA_HWDEP=y +# CONFIG_SND_HDA_RECONFIG is not set +# CONFIG_SND_HDA_INPUT_BEEP is not set +# CONFIG_SND_HDA_PATCH_LOADER is not set +# CONFIG_SND_HDA_CODEC_REALTEK is not set +# CONFIG_SND_HDA_CODEC_ANALOG is not set +# CONFIG_SND_HDA_CODEC_SIGMATEL is not set +# CONFIG_SND_HDA_CODEC_VIA is not set +# CONFIG_SND_HDA_CODEC_HDMI is not set +# CONFIG_SND_HDA_CODEC_CIRRUS is not set +# CONFIG_SND_HDA_CODEC_CS8409 is not set +# CONFIG_SND_HDA_CODEC_CONEXANT is not set +# CONFIG_SND_HDA_CODEC_CA0110 is not set +# CONFIG_SND_HDA_CODEC_CA0132 is not set +# CONFIG_SND_HDA_CODEC_CMEDIA is not set +# CONFIG_SND_HDA_CODEC_SI3054 is not set +# CONFIG_SND_HDA_GENERIC is not set +CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0 +# CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM is not set +# CONFIG_SND_HDA_CTL_DEV_ID is not set +# end of HD-Audio + +CONFIG_SND_HDA_CORE=y +CONFIG_SND_HDA_COMPONENT=y +CONFIG_SND_HDA_I915=y +CONFIG_SND_HDA_PREALLOC_SIZE=0 +CONFIG_SND_INTEL_NHLT=y +CONFIG_SND_INTEL_DSP_CONFIG=y +CONFIG_SND_INTEL_SOUNDWIRE_ACPI=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_USX2Y is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_US122L is not set +# CONFIG_SND_USB_6FIRE is not set +# CONFIG_SND_USB_HIFACE is not set +# CONFIG_SND_BCD2000 is not set +# CONFIG_SND_USB_POD is not set +# CONFIG_SND_USB_PODHD is not set +# CONFIG_SND_USB_TONEPORT is not set +# CONFIG_SND_USB_VARIAX is not set +CONFIG_SND_PCMCIA=y +# CONFIG_SND_VXPOCKET is not set +# CONFIG_SND_PDAUDIOCF is not set +# CONFIG_SND_SOC is not set +CONFIG_SND_X86=y +# CONFIG_HDMI_LPE_AUDIO is not set +# CONFIG_SND_VIRTIO is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +# CONFIG_UHID is not set +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +# CONFIG_HID_ASUS is not set +# CONFIG_HID_AUREAL is not set +CONFIG_HID_BELKIN=y +# CONFIG_HID_BETOP_FF is not set +# CONFIG_HID_BIGBEN_FF is not set +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_MACALLY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CREATIVE_SB0540 is not set +CONFIG_HID_CYPRESS=y +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +# CONFIG_HID_EVISION is not set +CONFIG_HID_EZKEY=y +# CONFIG_HID_FT260 is not set +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_GLORIOUS is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_GOOGLE_STADIA_FF is not set +# CONFIG_HID_VIVALDI is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +# CONFIG_HID_VRC2 is not set +# CONFIG_HID_XIAOMI is not set +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +CONFIG_HID_ITE=y +# CONFIG_HID_JABRA is not set +# CONFIG_HID_TWINHAN is not set +CONFIG_HID_KENSINGTON=y +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +# CONFIG_HID_LENOVO is not set +# CONFIG_HID_LETSKETCH is not set +CONFIG_HID_LOGITECH=y +# CONFIG_HID_LOGITECH_DJ is not set +# CONFIG_HID_LOGITECH_HIDPP is not set +CONFIG_LOGITECH_FF=y +# CONFIG_LOGIRUMBLEPAD2_FF is not set +# CONFIG_LOGIG940_FF is not set +CONFIG_LOGIWHEELS_FF=y +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_MEGAWORLD_FF is not set +CONFIG_HID_REDRAGON=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +# CONFIG_HID_MULTITOUCH is not set +# CONFIG_HID_NINTENDO is not set +# CONFIG_HID_NTI is not set +CONFIG_HID_NTRIG=y +# CONFIG_HID_ORTEK is not set +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +# CONFIG_HID_PENMOUNT is not set +CONFIG_HID_PETALYNX=y +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PXRC is not set +# CONFIG_HID_RAZER is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +# CONFIG_HID_SEMITEK is not set +# CONFIG_HID_SIGMAMICRO is not set +CONFIG_HID_SONY=y +# CONFIG_SONY_FF is not set +# CONFIG_HID_SPEEDLINK is not set +# CONFIG_HID_STEAM is not set +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +# CONFIG_HID_RMI is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TIVO is not set +CONFIG_HID_TOPSEED=y +# CONFIG_HID_TOPRE is not set +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_U2FZERO is not set +# CONFIG_HID_WACOM is not set +# CONFIG_HID_WIIMOTE is not set +# CONFIG_HID_XINMO is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set +# CONFIG_HID_MCP2221 is not set +# end of Special HID drivers + +# +# HID-BPF support +# +# end of HID-BPF support + +# +# USB HID support +# +CONFIG_USB_HID=y +CONFIG_HID_PID=y +CONFIG_USB_HIDDEV=y +# end of USB HID support + +CONFIG_I2C_HID=y +# CONFIG_I2C_HID_ACPI is not set +# CONFIG_I2C_HID_OF is not set + +# +# Intel ISH HID support +# +# CONFIG_INTEL_ISH_HID is not set +# end of Intel ISH HID support + +# +# AMD SFH HID Support +# +# CONFIG_AMD_SFH_HID is not set +# end of AMD SFH HID Support + +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +CONFIG_USB_PCI=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_FEW_INIT_RETRIES is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set +# CONFIG_USB_OTG_PRODUCTLIST is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +CONFIG_USB_MON=y + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=y +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PCI=y +# CONFIG_USB_XHCI_PCI_RENESAS is not set +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_ROOT_HUB_TT is not set +CONFIG_USB_EHCI_TT_NEWSCHED=y +CONFIG_USB_EHCI_PCI=y +# CONFIG_USB_EHCI_FSL is not set +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PCI=y +# CONFIG_USB_OHCI_HCD_PLATFORM is not set +CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=y +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +# CONFIG_USB_UAS is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USBIP_CORE is not set + +# +# USB dual-mode controller drivers +# +# CONFIG_USB_CDNS_SUPPORT is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_APPLE_MFI_FASTCHARGE is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_CHAOSKEY is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_ISP1301 is not set +# end of USB Physical Layer drivers + +# CONFIG_USB_GADGET is not set +# CONFIG_TYPEC is not set +# CONFIG_USB_ROLE_SWITCH is not set +# CONFIG_MMC is not set +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_CLASS_MULTICOLOR is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_APU is not set +# CONFIG_LEDS_AW200XX is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3532 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_PCA995X is not set +# CONFIG_LEDS_BD2606MVV is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_INTEL_SS4200 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +# CONFIG_LEDS_MLXCPLD is not set +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set +# CONFIG_LEDS_NIC78BX is not set + +# +# Flash and Torch LED drivers +# + +# +# RGB LED drivers +# + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +# CONFIG_LEDS_TRIGGER_DISK is not set +# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +# CONFIG_LEDS_TRIGGER_CPU is not set +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_LEDS_TRIGGER_TTY is not set + +# +# Simple LED drivers +# +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_ATOMIC_SCRUB=y +CONFIG_EDAC_SUPPORT=y +CONFIG_RTC_LIB=y +CONFIG_RTC_MC146818_LIB=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV3032 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set +# CONFIG_RTC_DRV_RX6110 is not set + +# +# Platform RTC drivers +# +CONFIG_RTC_DRV_CMOS=y +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_RP5C01 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_FTRTC010 is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_RTC_DRV_GOLDFISH is not set +CONFIG_DMADEVICES=y +# CONFIG_DMADEVICES_DEBUG is not set + +# +# DMA Devices +# +CONFIG_DMA_ENGINE=y +CONFIG_DMA_VIRTUAL_CHANNELS=y +CONFIG_DMA_ACPI=y +# CONFIG_ALTERA_MSGDMA is not set +# CONFIG_INTEL_IDMA64 is not set +# CONFIG_INTEL_IDXD is not set +# CONFIG_INTEL_IDXD_COMPAT is not set +# CONFIG_INTEL_IOATDMA is not set +# CONFIG_PLX_DMA is not set +# CONFIG_XILINX_DMA is not set +# CONFIG_XILINX_XDMA is not set +# CONFIG_AMD_PTDMA is not set +# CONFIG_QCOM_HIDMA_MGMT is not set +# CONFIG_QCOM_HIDMA is not set +CONFIG_DW_DMAC_CORE=y +# CONFIG_DW_DMAC is not set +# CONFIG_DW_DMAC_PCI is not set +# CONFIG_DW_EDMA is not set +CONFIG_HSU_DMA=y +# CONFIG_SF_PDMA is not set +# CONFIG_INTEL_LDMA is not set + +# +# DMA Clients +# +# CONFIG_ASYNC_TX_DMA is not set +# CONFIG_DMATEST is not set + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +# CONFIG_UDMABUF is not set +# CONFIG_DMABUF_MOVE_NOTIFY is not set +# CONFIG_DMABUF_DEBUG is not set +# CONFIG_DMABUF_SELFTESTS is not set +# CONFIG_DMABUF_HEAPS is not set +# CONFIG_DMABUF_SYSFS_STATS is not set +# end of DMABUF options + +# CONFIG_UIO is not set +# CONFIG_VFIO is not set +CONFIG_IRQ_BYPASS_MANAGER=y +# CONFIG_VIRT_DRIVERS is not set +CONFIG_VIRTIO_ANCHOR=y +CONFIG_VIRTIO=y +CONFIG_VIRTIO_PCI_LIB=y +CONFIG_VIRTIO_PCI_LIB_LEGACY=y +CONFIG_VIRTIO_MENU=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI_LEGACY=y +# CONFIG_VIRTIO_BALLOON is not set +CONFIG_VIRTIO_INPUT=y +# CONFIG_VIRTIO_MMIO is not set +CONFIG_VIRTIO_DMA_SHARED_BUFFER=y +# CONFIG_VDPA is not set +CONFIG_VHOST_MENU=y +# CONFIG_VHOST_NET is not set +# CONFIG_VHOST_CROSS_ENDIAN_LEGACY is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_HYPERV is not set +# end of Microsoft Hyper-V guest support + +# CONFIG_GREYBUS is not set +# CONFIG_COMEDI is not set +# CONFIG_STAGING is not set +# CONFIG_CHROME_PLATFORMS is not set +# CONFIG_MELLANOX_PLATFORM is not set +CONFIG_SURFACE_PLATFORMS=y +# CONFIG_SURFACE_3_POWER_OPREGION is not set +# CONFIG_SURFACE_GPE is not set +# CONFIG_SURFACE_PRO3_BUTTON is not set +CONFIG_X86_PLATFORM_DEVICES=y +CONFIG_ACPI_WMI=y +CONFIG_WMI_BMOF=y +# CONFIG_HUAWEI_WMI is not set +# CONFIG_MXM_WMI is not set +# CONFIG_NVIDIA_WMI_EC_BACKLIGHT is not set +# CONFIG_XIAOMI_WMI is not set +# CONFIG_GIGABYTE_WMI is not set +# CONFIG_YOGABOOK is not set +# CONFIG_ACERHDF is not set +# CONFIG_ACER_WIRELESS is not set +# CONFIG_ACER_WMI is not set +# CONFIG_AMD_PMF is not set +# CONFIG_AMD_PMC is not set +# CONFIG_AMD_HSMP is not set +# CONFIG_ADV_SWBUTTON is not set +# CONFIG_APPLE_GMUX is not set +# CONFIG_ASUS_LAPTOP is not set +# CONFIG_ASUS_WIRELESS is not set +# CONFIG_ASUS_WMI is not set +CONFIG_EEEPC_LAPTOP=y +# CONFIG_X86_PLATFORM_DRIVERS_DELL is not set +# CONFIG_AMILO_RFKILL is not set +# CONFIG_FUJITSU_LAPTOP is not set +# CONFIG_FUJITSU_TABLET is not set +# CONFIG_GPD_POCKET_FAN is not set +# CONFIG_X86_PLATFORM_DRIVERS_HP is not set +# CONFIG_WIRELESS_HOTKEY is not set +# CONFIG_IBM_RTL is not set +# CONFIG_IDEAPAD_LAPTOP is not set +# CONFIG_LENOVO_YMC is not set +# CONFIG_SENSORS_HDAPS is not set +# CONFIG_THINKPAD_ACPI is not set +# CONFIG_THINKPAD_LMI is not set +# CONFIG_INTEL_ATOMISP2_PM is not set +# CONFIG_INTEL_IFS is not set +# CONFIG_INTEL_SAR_INT1092 is not set +# CONFIG_INTEL_PMC_CORE is not set + +# +# Intel Speed Select Technology interface support +# +# CONFIG_INTEL_SPEED_SELECT_INTERFACE is not set +# end of Intel Speed Select Technology interface support + +# CONFIG_INTEL_WMI_SBL_FW_UPDATE is not set +# CONFIG_INTEL_WMI_THUNDERBOLT is not set + +# +# Intel Uncore Frequency Control +# +# CONFIG_INTEL_UNCORE_FREQ_CONTROL is not set +# end of Intel Uncore Frequency Control + +# CONFIG_INTEL_HID_EVENT is not set +# CONFIG_INTEL_VBTN is not set +# CONFIG_INTEL_OAKTRAIL is not set +# CONFIG_INTEL_PUNIT_IPC is not set +# CONFIG_INTEL_RST is not set +# CONFIG_INTEL_SMARTCONNECT is not set +# CONFIG_INTEL_TURBO_MAX_3 is not set +# CONFIG_INTEL_VSEC is not set +# CONFIG_MSI_EC is not set +# CONFIG_MSI_LAPTOP is not set +# CONFIG_MSI_WMI is not set +# CONFIG_SAMSUNG_LAPTOP is not set +# CONFIG_SAMSUNG_Q10 is not set +# CONFIG_TOSHIBA_BT_RFKILL is not set +# CONFIG_TOSHIBA_HAPS is not set +# CONFIG_TOSHIBA_WMI is not set +# CONFIG_ACPI_CMPC is not set +# CONFIG_COMPAL_LAPTOP is not set +# CONFIG_LG_LAPTOP is not set +# CONFIG_PANASONIC_LAPTOP is not set +# CONFIG_SONY_LAPTOP is not set +# CONFIG_SYSTEM76_ACPI is not set +# CONFIG_TOPSTAR_LAPTOP is not set +# CONFIG_MLX_PLATFORM is not set +# CONFIG_INTEL_IPS is not set +# CONFIG_INTEL_SCU_PCI is not set +# CONFIG_INTEL_SCU_PLATFORM is not set +# CONFIG_SIEMENS_SIMATIC_IPC is not set +# CONFIG_WINMATE_FM07_KEYS is not set +CONFIG_P2SB=y +# CONFIG_COMMON_CLK is not set +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_CLKEVT_I8253=y +CONFIG_I8253_LOCK=y +CONFIG_CLKBLD_I8253=y +# end of Clock Source drivers + +CONFIG_MAILBOX=y +CONFIG_PCC=y +# CONFIG_ALTERA_MBOX is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +CONFIG_IOMMU_IO_PGTABLE=y +# end of Generic IOMMU Pagetable Support + +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set +CONFIG_IOMMU_DEFAULT_DMA_LAZY=y +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_IOMMU_DMA=y +CONFIG_AMD_IOMMU=y +# CONFIG_AMD_IOMMU_V2 is not set +CONFIG_DMAR_TABLE=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_SVM is not set +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_INTEL_IOMMU_FLOPPY_WA=y +CONFIG_INTEL_IOMMU_SCALABLE_MODE_DEFAULT_ON=y +CONFIG_INTEL_IOMMU_PERF_EVENTS=y +# CONFIG_IOMMUFD is not set +# CONFIG_IRQ_REMAP is not set +# CONFIG_VIRTIO_IOMMU is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set +# end of Remoteproc drivers + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# end of Rpmsg drivers + +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +# end of Amlogic SoC drivers + +# +# Broadcom SoC drivers +# +# end of Broadcom SoC drivers + +# +# NXP/Freescale QorIQ SoC drivers +# +# end of NXP/Freescale QorIQ SoC drivers + +# +# fujitsu SoC drivers +# +# end of fujitsu SoC drivers + +# +# i.MX SoC drivers +# +# end of i.MX SoC drivers + +# +# Enable LiteX SoC Builder specific drivers +# +# end of Enable LiteX SoC Builder specific drivers + +# CONFIG_WPCM450_SOC is not set + +# +# Qualcomm SoC drivers +# +# end of Qualcomm SoC drivers + +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# end of Xilinx SoC drivers +# end of SOC (System On Chip) specific Drivers + +# CONFIG_PM_DEVFREQ is not set +# CONFIG_EXTCON is not set +# CONFIG_MEMORY is not set +# CONFIG_IIO is not set +# CONFIG_NTB is not set +# CONFIG_PWM is not set + +# +# IRQ chip support +# +# end of IRQ chip support + +# CONFIG_IPACK_BUS is not set +# CONFIG_RESET_CONTROLLER is not set + +# +# PHY Subsystem +# +# CONFIG_GENERIC_PHY is not set +# CONFIG_USB_LGM_PHY is not set +# CONFIG_PHY_CAN_TRANSCEIVER is not set + +# +# PHY drivers for Broadcom platforms +# +# CONFIG_BCM_KONA_USB2_PHY is not set +# end of PHY drivers for Broadcom platforms + +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_INTEL_LGM_EMMC is not set +# end of PHY Subsystem + +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# end of Performance monitor support + +# CONFIG_RAS is not set +# CONFIG_USB4 is not set + +# +# Android +# +# CONFIG_ANDROID_BINDER_IPC is not set +# end of Android + +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y + +# +# Layout Types +# +# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set +# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set +# end of Layout Types + +# CONFIG_NVMEM_RMEM is not set + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# end of HW tracing support + +# CONFIG_FPGA is not set +# CONFIG_TEE is not set +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set +# CONFIG_COUNTER is not set +# CONFIG_PECI is not set +# CONFIG_HTE is not set +# end of Device Drivers + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +# CONFIG_VALIDATE_FS_PARSER is not set +CONFIG_FS_IOMAP=y +CONFIG_BUFFER_HEAD=y +CONFIG_LEGACY_DIRECT_IO=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT2=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +# CONFIG_F2FS_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +# CONFIG_FS_VERITY is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_QUOTA_DEBUG is not set +CONFIG_QUOTA_TREE=y +# CONFIG_QFMT_V1 is not set +CONFIG_QFMT_V2=y +CONFIG_QUOTACTL=y +CONFIG_AUTOFS_FS=y +# CONFIG_FUSE_FS is not set +# CONFIG_OVERLAY_FS is not set + +# +# Caches +# +CONFIG_NETFS_SUPPORT=y +# CONFIG_NETFS_STATS is not set +# CONFIG_FSCACHE is not set +# end of Caches + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +# CONFIG_UDF_FS is not set +# end of CD-ROM/DVD Filesystems + +# +# DOS/FAT/EXFAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_FAT_DEFAULT_UTF8 is not set +# CONFIG_EXFAT_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS3_FS is not set +# end of DOS/FAT/EXFAT/NT Filesystems + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_VMCORE=y +# CONFIG_PROC_VMCORE_DEVICE_DUMP is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_PROC_PID_ARCH_STATUS=y +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_TMPFS_INODE64 is not set +# CONFIG_TMPFS_QUOTA is not set +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y +# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +# CONFIG_CONFIGFS_FS is not set +CONFIG_EFIVAR_FS=m +# end of Pseudo filesystems + +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_EROFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +# CONFIG_NFS_SWAP is not set +# CONFIG_NFS_V4_1 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +CONFIG_NFS_DISABLE_UDP_SUPPORT=y +# CONFIG_NFSD is not set +CONFIG_GRACE_PERIOD=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_ACL_SUPPORT=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_RPCSEC_GSS_KRB5=y +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_SMB_SERVER is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_9P_FS=y +# CONFIG_9P_FS_POSIX_ACL is not set +# CONFIG_9P_FS_SECURITY is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_UNICODE is not set +CONFIG_IO_WQ=y +# end of File systems + +# +# Security options +# +CONFIG_KEYS=y +# CONFIG_KEYS_REQUEST_CACHE is not set +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_TRUSTED_KEYS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +CONFIG_SECURITY=y +# CONFIG_SECURITYFS is not set +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +# CONFIG_SECURITY_PATH is not set +# CONFIG_INTEL_TXT is not set +CONFIG_LSM_MMAP_MIN_ADDR=65536 +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_SECURITY_SELINUX_DEVELOP=y +CONFIG_SECURITY_SELINUX_AVC_STATS=y +CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS=9 +CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE=256 +# CONFIG_SECURITY_SELINUX_DEBUG is not set +# CONFIG_SECURITY_SMACK is not set +# CONFIG_SECURITY_TOMOYO is not set +# CONFIG_SECURITY_APPARMOR is not set +# CONFIG_SECURITY_LOADPIN is not set +# CONFIG_SECURITY_YAMA is not set +# CONFIG_SECURITY_SAFESETID is not set +# CONFIG_SECURITY_LOCKDOWN_LSM is not set +# CONFIG_SECURITY_LANDLOCK is not set +CONFIG_INTEGRITY=y +# CONFIG_INTEGRITY_SIGNATURE is not set +CONFIG_INTEGRITY_AUDIT=y +# CONFIG_IMA is not set +# CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT is not set +# CONFIG_EVM is not set +CONFIG_DEFAULT_SECURITY_SELINUX=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,selinux,smack,tomoyo,apparmor,bpf" + +# +# Kernel hardening options +# + +# +# Memory initialization +# +CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y +CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y +# CONFIG_INIT_STACK_NONE is not set +# CONFIG_INIT_STACK_ALL_PATTERN is not set +CONFIG_INIT_STACK_ALL_ZERO=y +# CONFIG_GCC_PLUGIN_STACKLEAK is not set +# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set +# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set +CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y +# CONFIG_ZERO_CALL_USED_REGS is not set +# end of Memory initialization + +# +# Hardening of kernel data structures +# +# CONFIG_LIST_HARDENED is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# end of Hardening of kernel data structures + +CONFIG_RANDSTRUCT_NONE=y +# CONFIG_RANDSTRUCT_FULL is not set +# CONFIG_RANDSTRUCT_PERFORMANCE is not set +# end of Kernel hardening options +# end of Security options + +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_SIG=y +CONFIG_CRYPTO_SIG2=y +CONFIG_CRYPTO_SKCIPHER=y +CONFIG_CRYPTO_SKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +# CONFIG_CRYPTO_PCRYPT is not set +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set +# end of Crypto core or helper + +# +# Public-key cryptography +# +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +# CONFIG_CRYPTO_ECDH is not set +# CONFIG_CRYPTO_ECDSA is not set +# CONFIG_CRYPTO_ECRDSA is not set +# CONFIG_CRYPTO_SM2 is not set +# CONFIG_CRYPTO_CURVE25519 is not set +# end of Public-key cryptography + +# +# Block ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +# CONFIG_CRYPTO_ARIA is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SM4_GENERIC is not set +# CONFIG_CRYPTO_TWOFISH is not set +# end of Block ciphers + +# +# Length-preserving ciphers and modes +# +# CONFIG_CRYPTO_ADIANTUM is not set +# CONFIG_CRYPTO_CHACHA20 is not set +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CFB is not set +CONFIG_CRYPTO_CTR=y +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_HCTR2 is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set +# end of Length-preserving ciphers and modes + +# +# AEAD (authenticated encryption with associated data) ciphers +# +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_GENIV=y +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=y +# CONFIG_CRYPTO_ESSIV is not set +# end of AEAD (authenticated encryption with associated data) ciphers + +# +# Hashes, digests, and MACs +# +# CONFIG_CRYPTO_BLAKE2B is not set +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_GHASH=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_POLY1305 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_SHA1 is not set +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_SHA3=y +# CONFIG_CRYPTO_SM3_GENERIC is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_VMAC is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_XXHASH is not set +# end of Hashes, digests, and MACs + +# +# CRCs (cyclic redundancy checks) +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_CRC32 is not set +# CONFIG_CRYPTO_CRCT10DIF is not set +# end of CRCs (cyclic redundancy checks) + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_ZSTD is not set +# end of Compression + +# +# Random number generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_JITTERENTROPY=y +# CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE is not set +# end of Random number generation + +# +# Userspace interface +# +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +# end of Userspace interface + +CONFIG_CRYPTO_HASH_INFO=y + +# +# Accelerated Cryptographic Algorithms for CPU (x86) +# +# CONFIG_CRYPTO_CURVE25519_X86 is not set +# CONFIG_CRYPTO_AES_NI_INTEL is not set +# CONFIG_CRYPTO_BLOWFISH_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_CAST5_AVX_X86_64 is not set +# CONFIG_CRYPTO_CAST6_AVX_X86_64 is not set +# CONFIG_CRYPTO_DES3_EDE_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_SSE2_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set +# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set +# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64 is not set +# CONFIG_CRYPTO_TWOFISH_X86_64_3WAY is not set +# CONFIG_CRYPTO_TWOFISH_AVX_X86_64 is not set +# CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64 is not set +# CONFIG_CRYPTO_ARIA_AESNI_AVX2_X86_64 is not set +# CONFIG_CRYPTO_ARIA_GFNI_AVX512_X86_64 is not set +# CONFIG_CRYPTO_CHACHA20_X86_64 is not set +# CONFIG_CRYPTO_AEGIS128_AESNI_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_SSE2 is not set +# CONFIG_CRYPTO_NHPOLY1305_AVX2 is not set +# CONFIG_CRYPTO_BLAKE2S_X86 is not set +# CONFIG_CRYPTO_POLYVAL_CLMUL_NI is not set +# CONFIG_CRYPTO_POLY1305_X86_64 is not set +# CONFIG_CRYPTO_SHA1_SSSE3 is not set +# CONFIG_CRYPTO_SHA256_SSSE3 is not set +# CONFIG_CRYPTO_SHA512_SSSE3 is not set +# CONFIG_CRYPTO_SM3_AVX_X86_64 is not set +# CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL is not set +# CONFIG_CRYPTO_CRC32C_INTEL is not set +# CONFIG_CRYPTO_CRC32_PCLMUL is not set +# end of Accelerated Cryptographic Algorithms for CPU (x86) + +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_PADLOCK is not set +# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set +# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_NITROX_CNN55XX is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set +# CONFIG_CRYPTO_DEV_QAT_C62X is not set +# CONFIG_CRYPTO_DEV_QAT_4XXX is not set +# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set +# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set +# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set +# CONFIG_CRYPTO_DEV_VIRTIO is not set +# CONFIG_CRYPTO_DEV_SAFEXCEL is not set +# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set +# CONFIG_FIPS_SIGNATURE_SELFTEST is not set + +# +# Certificates for signature checking +# +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set +# end of Certificates for signature checking + +CONFIG_BINARY_PRINTF=y + +# +# Library routines +# +# CONFIG_PACKING is not set +CONFIG_BITREVERSE=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +# CONFIG_CORDIC is not set +# CONFIG_PRIME_NUMBERS is not set +CONFIG_RATIONAL=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +CONFIG_ARCH_USE_SYM_ANNOTATIONS=y + +# +# Crypto library routines +# +CONFIG_CRYPTO_LIB_UTILS=y +CONFIG_CRYPTO_LIB_AES=y +CONFIG_CRYPTO_LIB_ARC4=y +CONFIG_CRYPTO_LIB_GF128MUL=y +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +# CONFIG_CRYPTO_LIB_CHACHA is not set +# CONFIG_CRYPTO_LIB_CURVE25519 is not set +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=11 +# CONFIG_CRYPTO_LIB_POLY1305 is not set +# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set +CONFIG_CRYPTO_LIB_SHA1=y +CONFIG_CRYPTO_LIB_SHA256=y +# end of Crypto library routines + +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC64_ROCKSOFT is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMMON=y +CONFIG_ZSTD_DECOMPRESS=y +CONFIG_XZ_DEC=y +CONFIG_XZ_DEC_X86=y +CONFIG_XZ_DEC_POWERPC=y +CONFIG_XZ_DEC_IA64=y +CONFIG_XZ_DEC_ARM=y +CONFIG_XZ_DEC_ARMTHUMB=y +CONFIG_XZ_DEC_SPARC=y +# CONFIG_XZ_DEC_MICROLZMA is not set +CONFIG_XZ_DEC_BCJ=y +# CONFIG_XZ_DEC_TEST is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DECOMPRESS_BZIP2=y +CONFIG_DECOMPRESS_LZMA=y +CONFIG_DECOMPRESS_XZ=y +CONFIG_DECOMPRESS_LZO=y +CONFIG_DECOMPRESS_LZ4=y +CONFIG_DECOMPRESS_ZSTD=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_INTERVAL_TREE=y +CONFIG_XARRAY_MULTI=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HAS_DMA=y +CONFIG_DMA_OPS=y +CONFIG_NEED_SG_DMA_FLAGS=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_SWIOTLB=y +# CONFIG_SWIOTLB_DYNAMIC is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_DMA_MAP_BENCHMARK is not set +CONFIG_SGL_ALLOC=y +CONFIG_CHECK_SIGNATURE=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +CONFIG_OID_REGISTRY=y +CONFIG_UCS2_STRING=y +CONFIG_HAVE_GENERIC_VDSO=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_VDSO_TIME_NS=y +CONFIG_FONT_SUPPORT=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_SG_POOL=y +CONFIG_ARCH_HAS_PMEM_API=y +CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION=y +CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y +CONFIG_ARCH_HAS_COPY_MC=y +CONFIG_ARCH_STACKWALK=y +CONFIG_STACKDEPOT=y +CONFIG_SBITMAP=y +# end of Library routines + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +# CONFIG_STACKTRACE_BUILD_ID is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +# CONFIG_DYNAMIC_DEBUG is not set +# CONFIG_DYNAMIC_DEBUG_CORE is not set +CONFIG_SYMBOLIC_ERRNAME=y +CONFIG_DEBUG_BUGVERBOSE=y +# end of printk and dmesg options + +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_MISC=y + +# +# Compile-time checks and compiler options +# +CONFIG_DEBUG_INFO=y +CONFIG_AS_HAS_NON_CONST_LEB128=y +# CONFIG_DEBUG_INFO_NONE is not set +CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y +# CONFIG_DEBUG_INFO_DWARF4 is not set +# CONFIG_DEBUG_INFO_DWARF5 is not set +# CONFIG_DEBUG_INFO_REDUCED is not set +CONFIG_DEBUG_INFO_COMPRESSED_NONE=y +# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set +# CONFIG_DEBUG_INFO_COMPRESSED_ZSTD is not set +# CONFIG_DEBUG_INFO_SPLIT is not set +CONFIG_DEBUG_INFO_BTF=y +CONFIG_PAHOLE_HAS_SPLIT_BTF=y +CONFIG_PAHOLE_HAS_LANG_EXCLUDE=y +CONFIG_DEBUG_INFO_BTF_MODULES=y +CONFIG_MODULE_ALLOW_BTF_MISMATCH=y +# CONFIG_GDB_SCRIPTS is not set +CONFIG_FRAME_WARN=2048 +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_READABLE_ASM is not set +# CONFIG_HEADERS_INSTALL is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +CONFIG_OBJTOOL=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +# end of Compile-time checks and compiler options + +# +# Generic Kernel Debugging Instruments +# +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE="" +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ALLOW_ALL=y +# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set +# CONFIG_DEBUG_FS_ALLOW_NONE is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_HAVE_ARCH_KCSAN=y +CONFIG_HAVE_KCSAN_COMPILER=y +# CONFIG_KCSAN is not set +# end of Generic Kernel Debugging Instruments + +# +# Networking Debugging +# +# CONFIG_NET_DEV_REFCNT_TRACKER is not set +# CONFIG_NET_NS_REFCNT_TRACKER is not set +# CONFIG_DEBUG_NET is not set +# end of Networking Debugging + +# +# Memory Debugging +# +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_TABLE_CHECK is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_PAGE_REF is not set +# CONFIG_DEBUG_RODATA_TEST is not set +CONFIG_ARCH_HAS_DEBUG_WX=y +CONFIG_DEBUG_WX=y +CONFIG_GENERIC_PTDUMP=y +CONFIG_PTDUMP_CORE=y +# CONFIG_PTDUMP_DEBUGFS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_PER_VMA_LOCK_STATS is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SHRINKER_DEBUG is not set +CONFIG_DEBUG_STACK_USAGE=y +# CONFIG_SCHED_STACK_END_CHECK is not set +CONFIG_ARCH_HAS_DEBUG_VM_PGTABLE=y +# CONFIG_DEBUG_VM is not set +# CONFIG_DEBUG_VM_PGTABLE is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_ARCH_SUPPORTS_KMAP_LOCAL_FORCE_MAP=y +# CONFIG_DEBUG_KMAP_LOCAL_FORCE_MAP is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_VMALLOC=y +CONFIG_CC_HAS_KASAN_GENERIC=y +CONFIG_CC_HAS_KASAN_SW_TAGS=y +CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y +# CONFIG_KASAN is not set +CONFIG_HAVE_ARCH_KFENCE=y +# CONFIG_KFENCE is not set +CONFIG_HAVE_ARCH_KMSAN=y +# end of Memory Debugging + +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Oops, Lockups and Hangs +# +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +# CONFIG_SOFTLOCKUP_DETECTOR is not set +CONFIG_HAVE_HARDLOCKUP_DETECTOR_BUDDY=y +# CONFIG_HARDLOCKUP_DETECTOR is not set +CONFIG_HARDLOCKUP_CHECK_TIMESTAMP=y +# CONFIG_DETECT_HUNG_TASK is not set +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_WQ_CPU_INTENSIVE_REPORT is not set +# CONFIG_TEST_LOCKUP is not set +# end of Debug Oops, Lockups and Hangs + +# +# Scheduler Debugging +# +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHED_INFO=y +CONFIG_SCHEDSTATS=y +# end of Scheduler Debugging + +# CONFIG_DEBUG_TIMEKEEPING is not set +# CONFIG_DEBUG_PREEMPT is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_SCF_TORTURE_TEST is not set +# CONFIG_CSD_LOCK_WAIT_DEBUG is not set +# end of Lock Debugging (spinlocks, mutexes, etc...) + +# CONFIG_NMI_CHECK_CPU is not set +# CONFIG_DEBUG_IRQFLAGS is not set +CONFIG_STACKTRACE=y +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set + +# +# Debug kernel data structures +# +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PLIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_MAPLE_TREE is not set +# end of Debug kernel data structures + +# +# RCU Debugging +# +# CONFIG_RCU_SCALE_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_RCU_REF_SCALE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0 +# CONFIG_RCU_CPU_STALL_CPUTIME is not set +CONFIG_RCU_TRACE=y +# CONFIG_RCU_EQS_DEBUG is not set +# end of RCU Debugging + +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_LATENCYTOP is not set +# CONFIG_DEBUG_CGROUP_REF is not set +CONFIG_USER_STACKTRACE_SUPPORT=y +CONFIG_NOP_TRACER=y +CONFIG_HAVE_RETHOOK=y +CONFIG_RETHOOK=y +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_NO_PATCHABLE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_FENTRY=y +CONFIG_HAVE_OBJTOOL_MCOUNT=y +CONFIG_HAVE_OBJTOOL_NOP_MCOUNT=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y +CONFIG_TRACE_CLOCK=y +CONFIG_RING_BUFFER=y +CONFIG_EVENT_TRACING=y +CONFIG_CONTEXT_SWITCH_TRACER=y +CONFIG_TRACING=y +CONFIG_GENERIC_TRACER=y +CONFIG_TRACING_SUPPORT=y +CONFIG_FTRACE=y +# CONFIG_BOOTTIME_TRACING is not set +# CONFIG_FUNCTION_TRACER is not set +# CONFIG_STACK_TRACER is not set +# CONFIG_IRQSOFF_TRACER is not set +# CONFIG_PREEMPT_TRACER is not set +# CONFIG_SCHED_TRACER is not set +# CONFIG_HWLAT_TRACER is not set +# CONFIG_OSNOISE_TRACER is not set +# CONFIG_TIMERLAT_TRACER is not set +# CONFIG_MMIOTRACE is not set +# CONFIG_FTRACE_SYSCALLS is not set +# CONFIG_TRACER_SNAPSHOT is not set +CONFIG_BRANCH_PROFILE_NONE=y +# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set +# CONFIG_PROFILE_ALL_BRANCHES is not set +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_PROBE_EVENTS_BTF_ARGS=y +CONFIG_KPROBE_EVENTS=y +CONFIG_UPROBE_EVENTS=y +CONFIG_BPF_EVENTS=y +CONFIG_DYNAMIC_EVENTS=y +CONFIG_PROBE_EVENTS=y +# CONFIG_SYNTH_EVENTS is not set +# CONFIG_USER_EVENTS is not set +# CONFIG_HIST_TRIGGERS is not set +# CONFIG_TRACE_EVENT_INJECT is not set +# CONFIG_TRACEPOINT_BENCHMARK is not set +# CONFIG_RING_BUFFER_BENCHMARK is not set +# CONFIG_TRACE_EVAL_MAP_FILE is not set +# CONFIG_FTRACE_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_STARTUP_TEST is not set +# CONFIG_RING_BUFFER_VALIDATE_TIME_DELTAS is not set +# CONFIG_PREEMPTIRQ_DELAY_TEST is not set +# CONFIG_KPROBE_EVENT_GEN_TEST is not set +# CONFIG_RV is not set +CONFIG_PROVIDE_OHCI1394_DMA_INIT=y +# CONFIG_SAMPLES is not set +CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y +CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +CONFIG_STRICT_DEVMEM=y +# CONFIG_IO_STRICT_DEVMEM is not set + +# +# x86 Debugging +# +CONFIG_EARLY_PRINTK_USB=y +CONFIG_X86_VERBOSE_BOOTUP=y +CONFIG_EARLY_PRINTK=y +CONFIG_EARLY_PRINTK_DBGP=y +# CONFIG_EARLY_PRINTK_USB_XDBC is not set +# CONFIG_EFI_PGT_DUMP is not set +# CONFIG_DEBUG_TLBFLUSH is not set +CONFIG_HAVE_MMIOTRACE_SUPPORT=y +# CONFIG_X86_DECODER_SELFTEST is not set +CONFIG_IO_DELAY_0X80=y +# CONFIG_IO_DELAY_0XED is not set +# CONFIG_IO_DELAY_UDELAY is not set +# CONFIG_IO_DELAY_NONE is not set +CONFIG_DEBUG_BOOT_PARAMS=y +# CONFIG_CPA_DEBUG is not set +# CONFIG_DEBUG_ENTRY is not set +# CONFIG_DEBUG_NMI_SELFTEST is not set +CONFIG_X86_DEBUG_FPU=y +# CONFIG_PUNIT_ATOM_DEBUG is not set +CONFIG_UNWINDER_ORC=y +# CONFIG_UNWINDER_FRAME_POINTER is not set +# end of x86 Debugging + +# +# Kernel Testing and Coverage +# +# CONFIG_KUNIT is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FUNCTION_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +CONFIG_RUNTIME_TESTING_MENU=y +# CONFIG_TEST_DHRY is not set +# CONFIG_LKDTM is not set +# CONFIG_TEST_MIN_HEAP is not set +# CONFIG_TEST_DIV64 is not set +# CONFIG_BACKTRACE_SELF_TEST is not set +# CONFIG_TEST_REF_TRACKER is not set +# CONFIG_RBTREE_TEST is not set +# CONFIG_REED_SOLOMON_TEST is not set +# CONFIG_INTERVAL_TREE_TEST is not set +# CONFIG_PERCPU_TEST is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_TEST_HEXDUMP is not set +# CONFIG_STRING_SELFTEST is not set +# CONFIG_TEST_STRING_HELPERS is not set +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_TEST_PRINTF is not set +# CONFIG_TEST_SCANF is not set +# CONFIG_TEST_BITMAP is not set +# CONFIG_TEST_UUID is not set +# CONFIG_TEST_XARRAY is not set +# CONFIG_TEST_MAPLE_TREE is not set +# CONFIG_TEST_RHASHTABLE is not set +# CONFIG_TEST_IDA is not set +# CONFIG_TEST_LKM is not set +# CONFIG_TEST_BITOPS is not set +# CONFIG_TEST_VMALLOC is not set +# CONFIG_TEST_USER_COPY is not set +# CONFIG_TEST_BPF is not set +# CONFIG_TEST_BLACKHOLE_DEV is not set +# CONFIG_FIND_BIT_BENCHMARK is not set +# CONFIG_TEST_FIRMWARE is not set +# CONFIG_TEST_SYSCTL is not set +# CONFIG_TEST_UDELAY is not set +# CONFIG_TEST_STATIC_KEYS is not set +# CONFIG_TEST_KMOD is not set +# CONFIG_TEST_MEMCAT_P is not set +# CONFIG_TEST_MEMINIT is not set +# CONFIG_TEST_FREE_PAGES is not set +# CONFIG_TEST_FPU is not set +# CONFIG_TEST_CLOCKSOURCE_WATCHDOG is not set +CONFIG_ARCH_USE_MEMTEST=y +# CONFIG_MEMTEST is not set +# end of Kernel Testing and Coverage + +# +# Rust hacking +# +# end of Rust hacking +# end of Kernel hacking diff --git a/include/linux/bpf_ir.h b/include/linux/bpf_ir.h index 2dcddc109..77ab05257 100644 --- a/include/linux/bpf_ir.h +++ b/include/linux/bpf_ir.h @@ -1,17 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _LINUX_BPF_IR_H #define _LINUX_BPF_IR_H #include "linux/bpf.h" #ifndef __KERNEL__ + #include #include #include #include -#include "list.h" #include #include - #include #include #include @@ -25,48 +25,86 @@ typedef __u32 u32; typedef __s64 s64; typedef __u64 u64; -#define SIZET_MAX SIZE_MAX +// Used to simulate kernel functions +#include "list.h" +#include "hash.h" + +#define PRINT_DBG printf + +#define CRITICAL(str) \ + { \ + printf("%s:%d <%s> %s\n", __FILE__, __LINE__, __FUNCTION__, \ + str); \ + exit(1); \ + } #else #include -#include #include +#include -#define SIZET_MAX ULONG_MAX +#define PRINT_DBG printk -#define qsort(a, b, c, d) sort(a, b, c, d, NULL) +#define CRITICAL(str) \ + { \ + panic("%s:%d <%s> %s\n", __FILE__, __LINE__, __FUNCTION__, \ + str); \ + } #endif +/** + * define BPF_IR_LOG_SIZE - Maximum size of the BPF IR log buffer + */ +#define BPF_IR_LOG_SIZE 100000 + +/** + * define BPF_IR_MAX_PASS_NAME_SIZE - Maximum length of a BPF IR pass name + */ +#define BPF_IR_MAX_PASS_NAME_SIZE 32 + +#define MAX_FUNC_ARG 5 + /* IR Env Start */ // A environment for communicating with external functions -#define BPF_IR_LOG_SIZE 100000 -#define BPF_IR_MAX_PASS_NAME_SIZE 32 - struct custom_pass_cfg; struct builtin_pass_cfg; +/** + * struct bpf_ir_opts - Options for BPF IR processing + * @force: Force the use of ePass, even if the verifier passes + * @enable_printk_log: Enable printing log messages using printk + * @enable_throw_msg: Write an error message to trace when throwing an error + * @fake_run: Run without actually modifying the bytecode + * @print_only: Print IR without performing transformations + * @max_insns: Maximum number of instructions to process + * @dotgraph: Generate a DOT graph for the interference graph + * @verbose: Verbosity level + * @disable_prog_check: Disable program checks + * @max_iteration: Maximum number of iterations allowed + * @print_mode: Printing mode for the IR (e.g., BPF, detail, dump) + * @custom_passes: Pointer to an array of custom pass configurations + * @custom_pass_num: Number of custom passes + * @builtin_pass_cfg: Pointer to an array of built-in pass configurations + * @builtin_pass_cfg_num: Number of built-in pass configurations + * + * This struct defines the set of options used during the intermediate + * representation (IR) processing of BPF programs. These options control + * transformations, output formats, logging, and optimization behavior. + */ struct bpf_ir_opts { - // Force to use ePass, even if verifier passes bool force; - - // Enable printing log to printk bool enable_printk_log; - - // Enable register coalesce optimization - bool enable_coalesce; - - // Write an error message to trace when throwing an error bool enable_throw_msg; - - // Verbose level + bool fake_run; + bool print_only; + u32 max_insns; + bool dotgraph; int verbose; - bool disable_prog_check; - u32 max_iteration; enum { @@ -83,16 +121,43 @@ struct bpf_ir_opts { size_t builtin_pass_cfg_num; }; +/** + * bpf_ir_default_opts - Get default BPF IR options + * + * Returns the default-initialized set of options for BPF IR processing. + * These defaults are used to configure the IR pipeline when no custom + * settings are provided. + * + * Return: A struct bpf_ir_opts containing default configuration values. + */ struct bpf_ir_opts bpf_ir_default_opts(void); +/** + * struct bpf_ir_env - Environment for BPF IR processing + * @err: Internal error code + * @insn_cnt: Number of BPF instructions + * @insns: Pointer to the array of BPF instructions + * @log: Log buffer for BPF IR processing output + * @log_pos: Current position in the log buffer + * @opts: Options used during BPF IR processing + * @lift_time: Time spent lifting bytecode to IR + * @run_time: Time spent running IR passes + * @cg_time: Time spent in code generation + * @executed: Whether the IR pipeline has executed (used in verifier) + * @verifier_err: Error code from the verifier + * @verifier_log_end_pos: Position in the verifier log buffer where logging ended + * @prog_type: BPF program type; may be unspecified in user space + * @venv: Pointer to the verifier environment + * @verifier_info_map: Mapping from bytecode instruction number to verifier info + * + * This struct contains the complete state and metadata for processing + * a BPF program in the intermediate representation (IR) pipeline. + * It includes instructions, options, logging buffers, stats, and + * verifier-related metadata. + */ struct bpf_ir_env { - // Internal error code int err; - - // Number of instructions size_t insn_cnt; - - // Instructions struct bpf_insn *insns; char log[BPF_IR_LOG_SIZE]; @@ -100,71 +165,79 @@ struct bpf_ir_env { struct bpf_ir_opts opts; - // Stats - u64 lift_time; u64 run_time; u64 cg_time; - // Verifier information - - // Whether executed, used in verifier bool executed; - - // Verifier error int verifier_err; - - // Verifier log end pos in ubuf u64 verifier_log_end_pos; - // Prog type - // May not be specified in user space enum bpf_prog_type prog_type; - - // Verifier env void *venv; - // Verifier information map - // Bytecode Insn number -> Verifier information (e.g. min max, type) void *verifier_info_map; }; +/** + * bpf_ir_print_to_log - Print a formatted log message to the BPF IR environment log + * @level: Log verbosity level (e.g. 0 = error, 3 = info) + * @env: Pointer to the BPF IR environment + * @fmt: Format string (printf-style) + * @...: Variable arguments for the format string + * + * Appends a formatted log message to the log buffer of the given IR environment. + * Used mostly internally. Use PRINT_LOG_INFO() and related functions to print. + */ void bpf_ir_print_to_log(int level, struct bpf_ir_env *env, char *fmt, ...); +/** + * bpf_ir_reset_env - Reset the BPF IR environment to initial state + * @env: Pointer to the BPF IR environment to reset + * + * Clears the execution state to prepare for a new IR processing run. + */ void bpf_ir_reset_env(struct bpf_ir_env *env); +/** + * PRINT_LOG_INFO - Print an informational message to the BPF IR log + */ #define PRINT_LOG_INFO(...) bpf_ir_print_to_log(3, __VA_ARGS__) -#define PRINT_LOG_DEBUG(...) bpf_ir_print_to_log(2, __VA_ARGS__) -#define PRINT_LOG_WARNING(...) bpf_ir_print_to_log(1, __VA_ARGS__) -#define PRINT_LOG_ERROR(...) bpf_ir_print_to_log(0, __VA_ARGS__) - -#ifndef __KERNEL__ - -#define PRINT_DBG printf -#else - -#define PRINT_DBG printk +/** + * PRINT_LOG_DEBUG - Print a debug message to the BPF IR log + */ +#define PRINT_LOG_DEBUG(...) bpf_ir_print_to_log(2, __VA_ARGS__) -#endif +/** + * PRINT_LOG_WARNING - Print a warning message to the BPF IR log + */ +#define PRINT_LOG_WARNING(...) bpf_ir_print_to_log(1, __VA_ARGS__) -#define CHECK_ERR(x) \ - if (env->err) { \ - return x; \ - } +/** + * PRINT_LOG_ERROR - Print an error message to the BPF IR log + */ +#define PRINT_LOG_ERROR(...) bpf_ir_print_to_log(0, __VA_ARGS__) +/** + * bpf_ir_print_log_dbg - Print the current IR log content for debugging + * @env: Pointer to the BPF IR environment + * + * Outputs the current content of the IR log buffer for debugging purposes. + * Use printf in userspace and printk in kernel + */ void bpf_ir_print_log_dbg(struct bpf_ir_env *env); /* IR Env End */ /* Array Start */ -struct array { +typedef struct array { void *data; size_t num_elem; // Current length size_t max_elem; // Maximum length size_t elem_size; -}; +} array; void bpf_ir_array_init(struct array *res, size_t size); @@ -197,27 +270,65 @@ void bpf_ir_array_clone(struct bpf_ir_env *env, struct array *res, #define INIT_ARRAY(arr, type) bpf_ir_array_init(arr, sizeof(type)) +#define INIT_PTRSET_DEF(set) bpf_ir_ptrset_init(env, set, 8) + /* Array End */ -/* DBG Macro Start */ -#ifndef __KERNEL__ +/* Ptrset Start */ -#define CRITICAL(str) \ - { \ - printf("%s:%d <%s> %s\n", __FILE__, __LINE__, __FUNCTION__, \ - str); \ - exit(1); \ - } +struct ptrset_entry { + void *key; + s8 occupy; // 0: Empty, 1: Occupied, -1: Deleted +}; -#else +struct ptrset { + struct ptrset_entry *set; + size_t size; + size_t cnt; +}; -#define CRITICAL(str) \ - { \ - panic("%s:%d <%s> %s\n", __FILE__, __LINE__, __FUNCTION__, \ - str); \ - } +void bpf_ir_ptrset_init(struct bpf_ir_env *env, struct ptrset *res, + size_t size); -#endif +void bpf_ir_ptrset_insert(struct bpf_ir_env *env, struct ptrset *set, + void *key); + +int bpf_ir_ptrset_delete(struct ptrset *set, void *key); + +bool bpf_ir_ptrset_exists(struct ptrset *set, void *key); + +void bpf_ir_ptrset_print_dbg(struct bpf_ir_env *env, struct ptrset *set, + void (*print_key)(struct bpf_ir_env *env, void *)); + +void bpf_ir_ptrset_clean(struct ptrset *set); + +void bpf_ir_ptrset_free(struct ptrset *set); + +void **bpf_ir_ptrset_next(struct ptrset *set, void **keyd); + +struct ptrset bpf_ir_ptrset_union(struct bpf_ir_env *env, struct ptrset *set1, + struct ptrset *set2); + +struct ptrset bpf_ir_ptrset_intersec(struct bpf_ir_env *env, + struct ptrset *set1, struct ptrset *set2); + +void bpf_ir_ptrset_move(struct ptrset *set1, struct ptrset *set2); + +void bpf_ir_ptrset_clone(struct bpf_ir_env *env, struct ptrset *set1, + struct ptrset *set2); + +void bpf_ir_ptrset_add(struct bpf_ir_env *env, struct ptrset *set1, + struct ptrset *set2); + +void bpf_ir_ptrset_minus(struct ptrset *set1, struct ptrset *set2); + +#define ptrset_for(pos, set) \ + for (pos = (typeof(pos))bpf_ir_ptrset_next(&(set), NULL); pos; \ + pos = (typeof(pos))bpf_ir_ptrset_next(&(set), (void **)pos)) + +/* Ptrset End */ + +/* DBG Macro Start */ #define RAISE_ERROR(str) \ { \ @@ -258,61 +369,6 @@ void bpf_ir_array_clone(struct bpf_ir_env *env, struct array *res, /* DBG Macro End */ -/* LLI Start */ - -void *malloc_proto(size_t size); - -void free_proto(void *ptr); - -int parse_int(const char *str, int *val); - -u64 get_cur_time_ns(void); - -#define SAFE_MALLOC(dst, size) \ - { \ - if (size > 10000000) { \ - CRITICAL("Incorrect Allocation"); \ - } \ - dst = malloc_proto(size); \ - if (!dst) { \ - env->err = -ENOMEM; \ - return; \ - } \ - } - -#define SAFE_MALLOC_RET_NULL(dst, size) \ - { \ - if (size > 10000000) { \ - CRITICAL("Incorrect Allocation"); \ - } \ - dst = malloc_proto(size); \ - if (!dst) { \ - env->err = -ENOMEM; \ - return NULL; \ - } \ - } - -/* LLI End */ - -#define MAX_FUNC_ARG 5 - -enum imm_type { IMM, IMM64 }; - -/* Pre-IR instructions, similar to `bpf_insn` */ -struct pre_ir_insn { - u8 opcode; - - u8 dst_reg; - u8 src_reg; - s16 off; - - enum imm_type it; - s32 imm; - s64 imm64; // Immediate constant for 64-bit immediate - - size_t pos; // Original position -}; - enum ir_alu_op_type { IR_ALU_UNKNOWN, // To prevent from not manually setting this type IR_ALU_32, @@ -328,9 +384,13 @@ enum ir_builtin_constant { enum ir_value_type { IR_VALUE_CONSTANT, // A constant value in raw operations to be added during code generation + // e.g. if the const is 10, then after CG, it will be 10 + stack shift IR_VALUE_CONSTANT_RAWOFF, + + // e.g. if the const is 10, then after CG, it will be 10 - stack shift IR_VALUE_CONSTANT_RAWOFF_REV, IR_VALUE_INSN, + IR_VALUE_FLATTEN_DST, // Used only in code generation IR_VALUE_UNDEF, }; @@ -348,6 +408,15 @@ struct ir_raw_pos { enum ir_raw_pos_type pos_t; }; +/* Actual position of a VR, used after RA in cg */ +struct ir_vr_pos { + // If this VR needs to be allocated (insn like store does not) + bool allocated; + u32 spilled_size; // Spilled + u8 alloc_reg; // Not spilled + s32 spilled; // 0 -> not spilled; X -> spilled at X +}; + /* * VALUE = CONSTANT | INSN * @@ -357,6 +426,7 @@ struct ir_value { union { s64 constant_d; struct ir_insn *insn_d; + struct ir_vr_pos vr_pos; } data; enum ir_value_type type; enum ir_alu_op_type const_type; // Used when type is a constant @@ -383,8 +453,6 @@ struct phi_value { struct ir_basic_block *bb; }; -int bpf_ir_valid_alu_type(enum ir_alu_op_type type); - /* * Virtual Register Type */ @@ -396,8 +464,6 @@ enum ir_vr_type { IR_VR_TYPE_64, }; -u32 bpf_ir_sizeof_vr_type(enum ir_vr_type type); - enum ir_loadimm_extra_type { IR_LOADIMM_IMM64 = 0, IR_LOADIMM_MAP_BY_FD, @@ -408,8 +474,6 @@ enum ir_loadimm_extra_type { IR_LOADIMM_MAP_VAL_IDX, }; -int bpf_ir_valid_vr_type(enum ir_vr_type type); - enum ir_insn_type { IR_INSN_ALLOC, IR_INSN_ALLOCARRAY, @@ -447,6 +511,8 @@ enum ir_insn_type { IR_INSN_JLT, IR_INSN_JLE, IR_INSN_JNE, + IR_INSN_JSGE, + IR_INSN_JSLE, IR_INSN_JSGT, IR_INSN_JSLT, // PHI @@ -458,40 +524,6 @@ enum ir_insn_type { IR_INSN_FUNCTIONARG, // The function argument store, not an actual instruction }; -/** - INSN = - ALLOC - | STORE - | LOAD - | ALLOCARRAY - | GETELEMPTR - | STORERAW - | LOADRAW - - | ADD , - | SUB , - | MUL , - | LSH , - | MOD , - | CALL - | RET - | JA - | JEQ , , , - | JGT , , , - | JGE , , , - | JLT , , , - | JLE , , , - | JNE , , , - | PHI - (For code gen usage) - | ASSIGN - | REG - (For special usage) - | FUNCTIONARG - - Note. must be the next basic block. - ASSIGN dst cannot be callee-saved registers - */ struct ir_insn { struct ir_value values[MAX_FUNC_ARG]; u8 value_num; @@ -544,37 +576,6 @@ struct ir_insn { u8 _visited; }; -/** - Pre-IR BB - - This includes many data structures needed to generate the IR. - */ -struct pre_ir_basic_block { - // An ID used to debug - size_t id; - - // Start position in the original insns - size_t start_pos; - - // End position in the original insns - size_t end_pos; - - // The number of instructions in this basic block (modified length) - size_t len; - - struct pre_ir_insn *pre_insns; - - struct array preds; - struct array succs; - - u8 visited; - - u8 sealed; - u8 filled; - struct ir_basic_block *ir_bb; - struct ir_insn *incompletePhis[MAX_BPF_REG]; -}; - enum ir_bb_flag { IR_BB_HAS_COUNTER = 1 << 0, }; @@ -596,52 +597,8 @@ struct ir_basic_block { size_t _id; void *user_data; - // Flag + // Flag (experimental, may be removed in the future) u32 flag; - - // Array of struct ir_insn * - struct array users; -}; - -/** - The BB value used in currentDef - */ -struct bb_val { - struct pre_ir_basic_block *bb; - struct ir_value val; -}; - -/** - BB with the raw entrance position - */ -struct bb_entrance_info { - size_t entrance; - struct pre_ir_basic_block *bb; -}; - -/** - Generated BB information - */ -struct bb_info { - struct pre_ir_basic_block *entry; - - // Array of bb_entrance_info - struct array all_bbs; -}; - -/** - The environment data for transformation - */ -struct ssa_transform_env { - // Array of bb_val (which is (BB, Value) pair) - struct array currentDef[MAX_BPF_REG]; - struct bb_info info; - - // Stack Pointer - struct ir_insn *sp; - - // Function argument - struct ir_insn *function_arg[MAX_FUNC_ARG]; }; // Helper functions @@ -651,6 +608,10 @@ struct ir_basic_block *bpf_ir_init_bb_raw(void); // Main interface void bpf_ir_autorun(struct bpf_ir_env *env); +struct ir_function *bpf_ir_lift(struct bpf_ir_env *env); + +void bpf_ir_run(struct bpf_ir_env *env, struct ir_function *fun); + void bpf_ir_print_bpf_insn(struct bpf_ir_env *env, const struct bpf_insn *insn); void bpf_ir_free_env(struct bpf_ir_env *env); @@ -660,23 +621,6 @@ struct bpf_ir_env *bpf_ir_init_env(struct bpf_ir_opts opts, /* Fun Start */ -struct code_gen_info { - // All vertex in interference graph - // Array of struct ir_insn* - struct array all_var; - - // BPF Register Virtual Instruction (used as dst) - struct ir_insn *regs[BPF_REG_10]; // Only use R0-R9 - - size_t callee_num; - - // The stack offset - s32 stack_offset; - - // Whether to spill callee saved registers - u8 spill_callee; -}; - struct ir_function { size_t arg_num; @@ -698,10 +642,7 @@ struct ir_function { // Function argument struct ir_insn *function_arg[MAX_FUNC_ARG]; - // Array of struct ir_constraint. Value constraints. - struct array value_constraints; - - struct code_gen_info cg_info; + void *user_data; }; // Find IR instruction based on raw position @@ -729,30 +670,17 @@ enum insert_position { // Return an array of struct ir_value* struct array bpf_ir_get_operands(struct bpf_ir_env *env, struct ir_insn *insn); -// Return an array of struct ir_value* -struct array bpf_ir_get_operands_and_dst(struct bpf_ir_env *env, - struct ir_insn *insn); - void bpf_ir_replace_all_usage(struct bpf_ir_env *env, struct ir_insn *insn, struct ir_value rep); -void bpf_ir_replace_all_usage_cg(struct bpf_ir_env *env, struct ir_insn *insn, - struct ir_value rep); - void bpf_ir_replace_all_usage_except(struct bpf_ir_env *env, struct ir_insn *insn, struct ir_value rep, struct ir_insn *except); void bpf_ir_erase_insn(struct bpf_ir_env *env, struct ir_insn *insn); -/* Erase an instruction during CG. Cannot erase if gen kill sets are used */ -void bpf_ir_erase_insn_cg(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn); - bool bpf_ir_is_last_insn(struct ir_insn *insn); -void bpf_ir_check_no_user(struct bpf_ir_env *env, struct ir_insn *insn); - bool bpf_ir_is_void(struct ir_insn *insn); bool bpf_ir_is_jmp(struct ir_insn *insn); @@ -797,14 +725,6 @@ struct ir_insn *bpf_ir_create_loadimmextra_insn_bb( struct bpf_ir_env *env, struct ir_basic_block *pos_bb, enum ir_loadimm_extra_type load_ty, s64 imm, enum insert_position pos); -struct ir_insn *bpf_ir_create_loadimmextra_insn_cg( - struct bpf_ir_env *env, struct ir_insn *pos_insn, - enum ir_loadimm_extra_type load_ty, s64 imm, enum insert_position pos); - -struct ir_insn *bpf_ir_create_loadimmextra_insn_bb_cg( - struct bpf_ir_env *env, struct ir_basic_block *pos_bb, - enum ir_loadimm_extra_type load_ty, s64 imm, enum insert_position pos); - struct ir_insn *bpf_ir_create_getelemptr_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_insn *alloca_insn, @@ -817,17 +737,6 @@ struct ir_insn *bpf_ir_create_getelemptr_insn_bb(struct bpf_ir_env *env, struct ir_value offset, enum insert_position pos); -struct ir_insn *bpf_ir_create_getelemptr_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - struct ir_insn *alloca_insn, - struct ir_value offset, - enum insert_position pos); - -struct ir_insn *bpf_ir_create_getelemptr_insn_bb_cg( - struct bpf_ir_env *env, struct ir_basic_block *pos_bb, - struct ir_insn *alloca_insn, struct ir_value offset, - enum insert_position pos); - struct ir_insn *bpf_ir_create_neg_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, enum ir_alu_op_type alu_type, @@ -840,18 +749,6 @@ struct ir_insn *bpf_ir_create_neg_insn_bb(struct bpf_ir_env *env, struct ir_value val, enum insert_position pos); -struct ir_insn *bpf_ir_create_neg_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_alu_op_type alu_type, - struct ir_value val, - enum insert_position pos); - -struct ir_insn *bpf_ir_create_neg_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_alu_op_type alu_type, - struct ir_value val, - enum insert_position pos); - struct ir_insn *bpf_ir_create_end_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, enum ir_insn_type ty, u32 swap_width, @@ -864,19 +761,6 @@ struct ir_insn *bpf_ir_create_end_insn_bb(struct bpf_ir_env *env, struct ir_value val, enum insert_position pos); -struct ir_insn *bpf_ir_create_end_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_insn_type ty, u32 swap_width, - struct ir_value val, - enum insert_position pos); - -struct ir_insn *bpf_ir_create_end_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_insn_type ty, - u32 swap_width, - struct ir_value val, - enum insert_position pos); - struct ir_insn *bpf_ir_create_store_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_insn *insn, @@ -911,17 +795,6 @@ bpf_ir_create_bin_insn_bb(struct bpf_ir_env *env, struct ir_basic_block *pos_bb, enum ir_insn_type ty, enum ir_alu_op_type alu_type, enum insert_position pos); -struct ir_insn * -bpf_ir_create_bin_insn_cg(struct bpf_ir_env *env, struct ir_insn *pos_insn, - struct ir_value val1, struct ir_value val2, - enum ir_insn_type ty, enum ir_alu_op_type alu_type, - enum insert_position pos); - -struct ir_insn *bpf_ir_create_bin_insn_bb_cg( - struct bpf_ir_env *env, struct ir_basic_block *pos_bb, - struct ir_value val1, struct ir_value val2, enum ir_insn_type ty, - enum ir_alu_op_type alu_type, enum insert_position pos); - struct ir_insn *bpf_ir_create_ja_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_basic_block *to_bb, @@ -985,18 +858,6 @@ struct ir_insn *bpf_ir_create_loadraw_insn_bb(struct bpf_ir_env *env, struct ir_address_value val, enum insert_position pos); -struct ir_insn *bpf_ir_create_loadraw_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_vr_type type, - struct ir_address_value val, - enum insert_position pos); - -struct ir_insn *bpf_ir_create_loadraw_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_vr_type type, - struct ir_address_value val, - enum insert_position pos); - struct ir_insn * bpf_ir_create_storeraw_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, enum ir_vr_type type, struct ir_address_value val, @@ -1009,20 +870,6 @@ struct ir_insn *bpf_ir_create_storeraw_insn_bb(struct bpf_ir_env *env, struct ir_value to_store, enum insert_position pos); -struct ir_insn *bpf_ir_create_storeraw_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_vr_type type, - struct ir_address_value val, - struct ir_value to_store, - enum insert_position pos); - -struct ir_insn *bpf_ir_create_storeraw_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_vr_type type, - struct ir_address_value val, - struct ir_value to_store, - enum insert_position pos); - struct ir_insn *bpf_ir_create_assign_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_value val, @@ -1033,16 +880,6 @@ struct ir_insn *bpf_ir_create_assign_insn_bb(struct bpf_ir_env *env, struct ir_value val, enum insert_position pos); -struct ir_insn *bpf_ir_create_assign_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - struct ir_value val, - enum insert_position pos); - -struct ir_insn *bpf_ir_create_assign_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - struct ir_value val, - enum insert_position pos); - struct ir_insn *bpf_ir_create_phi_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, enum insert_position pos); @@ -1067,10 +904,6 @@ void bpf_ir_val_remove_user(struct ir_value val, struct ir_insn *user); void bpf_ir_replace_operand(struct bpf_ir_env *env, struct ir_insn *insn, struct ir_value v1, struct ir_value v2); -struct ir_insn *bpf_ir_create_insn_base_cg(struct bpf_ir_env *env, - struct ir_basic_block *bb, - enum ir_insn_type insn_type); - struct ir_insn *bpf_ir_create_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb); @@ -1087,8 +920,6 @@ void bpf_ir_insert_at_bb(struct ir_insn *new_insn, struct ir_basic_block *bb, /// Get the number of instructions in a basic block size_t bpf_ir_bb_len(struct ir_basic_block *); -struct ir_bb_cg_extra *bpf_ir_bb_cg(struct ir_basic_block *bb); - struct ir_basic_block *bpf_ir_create_bb(struct bpf_ir_env *env, struct ir_function *fun); @@ -1126,18 +957,12 @@ void print_ir_prog(struct bpf_ir_env *env, struct ir_function *); void print_ir_prog_notag(struct bpf_ir_env *env, struct ir_function *fun); -void print_ir_prog_reachable(struct bpf_ir_env *env, struct ir_function *fun); - void print_ir_prog_advanced(struct bpf_ir_env *env, struct ir_function *, void (*)(struct bpf_ir_env *env, struct ir_basic_block *), void (*)(struct bpf_ir_env *env, struct ir_insn *), void (*)(struct bpf_ir_env *env, struct ir_insn *)); -void print_ir_dst(struct bpf_ir_env *env, struct ir_insn *insn); - -void print_ir_alloc(struct bpf_ir_env *env, struct ir_insn *insn); - void bpf_ir_clean_visited(struct ir_function *); // Tag the instruction and BB @@ -1196,12 +1021,6 @@ void bpf_ir_div_by_zero(struct bpf_ir_env *env, struct ir_function *fun, void bpf_ir_optimize_code_compaction(struct bpf_ir_env *env, struct ir_function *fun, void *param); -extern const struct builtin_pass_cfg bpf_ir_kern_insn_counter_pass; -extern const struct builtin_pass_cfg bpf_ir_kern_optimization_pass; -extern const struct builtin_pass_cfg bpf_ir_kern_msan; -extern const struct builtin_pass_cfg bpf_ir_kern_div_by_zero_pass; -extern const struct builtin_pass_cfg bpf_ir_kern_compaction_pass; - void translate_throw(struct bpf_ir_env *env, struct ir_function *fun, void *param); @@ -1213,6 +1032,12 @@ struct function_pass { char name[BPF_IR_MAX_PASS_NAME_SIZE]; }; +extern const struct function_pass *pre_passes; +extern const size_t pre_passes_cnt; + +extern const struct function_pass *post_passes; +extern const size_t post_passes_cnt; + struct custom_pass_cfg { struct function_pass pass; void *param; @@ -1240,108 +1065,43 @@ struct builtin_pass_cfg { }; #define DEF_CUSTOM_PASS(pass_def, check_applyc, param_loadc, param_unloadc) \ - { .pass = pass_def, \ - .param = NULL, \ - .param_load = param_loadc, \ - .param_unload = param_unloadc, \ - .check_apply = check_applyc } + { \ + .pass = pass_def, .param = NULL, .param_load = param_loadc, \ + .param_unload = param_unloadc, .check_apply = check_applyc \ + } #define DEF_BUILTIN_PASS_CFG(namec, param_loadc, param_unloadc) \ - { .name = namec, \ - .param = NULL, \ - .enable = false, \ - .enable_cfg = false, \ - .param_load = param_loadc, \ - .param_unload = param_unloadc } + { \ + .name = namec, .param = NULL, .enable = false, \ + .enable_cfg = false, .param_load = param_loadc, \ + .param_unload = param_unloadc \ + } #define DEF_BUILTIN_PASS_ENABLE_CFG(namec, param_loadc, param_unloadc) \ - { .name = namec, \ - .param = NULL, \ - .enable = true, \ - .enable_cfg = false, \ - .param_load = param_loadc, \ - .param_unload = param_unloadc } + { \ + .name = namec, .param = NULL, .enable = true, \ + .enable_cfg = false, .param_load = param_loadc, \ + .param_unload = param_unloadc \ + } -#define DEF_FUNC_PASS(fun, msg, en_def) \ - { .pass = fun, .name = msg, .enabled = en_def, .force_enable = false } +#define DEF_FUNC_PASS(fun, msg, en_def) \ + { \ + .pass = fun, .name = msg, .enabled = en_def, \ + .force_enable = false \ + } -#define DEF_NON_OVERRIDE_FUNC_PASS(fun, msg) \ - { .pass = fun, .name = msg, .enabled = true, .force_enable = true } +#define DEF_NON_OVERRIDE_FUNC_PASS(fun, msg) \ + { \ + .pass = fun, .name = msg, .enabled = true, \ + .force_enable = true \ + } /* Passes End */ -struct ir_function *bpf_ir_lift(struct bpf_ir_env *env, - const struct bpf_insn *insns, size_t len); - -void bpf_ir_run(struct bpf_ir_env *env, struct ir_function *fun); - /* Code Gen Start */ -void bpf_ir_init_insn_cg(struct bpf_ir_env *env, struct ir_insn *insn); - void bpf_ir_compile(struct bpf_ir_env *env, struct ir_function *fun); -void bpf_ir_free_insn_cg(struct ir_insn *insn); - -// Extra information needed for code gen -struct ir_bb_cg_extra { - // Position of the first instruction - size_t pos; -}; - -struct ir_insn_cg_extra { - // Destination (Not in SSA form anymore) - struct ir_value dst; - - // Liveness analysis - struct array in; - struct array out; - struct array gen; - struct array kill; - - // Adj list in interference graph - // Array of struct ir_insn* - struct array adj; - - // Translated pre_ir_insn - struct pre_ir_insn translated[2]; - - // Translated number - u8 translated_num; - - // Whether the VR is allocated with a real register - // If it's a pre-colored register, it's also 1 - bool allocated; - - // When allocating register, whether dst will be spilled - // 0: Not spilled - // -8: Spilled on SP-8 - // etc. - s32 spilled; - - // The size of the spilled register - u32 spilled_size; - - // Valid if spilled == 0 && allocated == 1 - // Valid number: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 - u8 alloc_reg; - - // Whether this instruction is a non-VR instruction, like a pre-colored register - bool nonvr; -}; - -enum val_type { - UNDEF, - REG, - CONST, - STACK, - STACKOFF, -}; - -#define insn_cg(insn) ((struct ir_insn_cg_extra *)(insn)->user_data) - -#define insn_dst(insn) insn_cg(insn)->dst.data.insn_d - /* Code Gen End */ /* IR Value Start */ @@ -1350,6 +1110,8 @@ bool bpf_ir_value_equal(struct ir_value a, struct ir_value b); struct ir_value bpf_ir_value_insn(struct ir_insn *); +struct ir_value bpf_ir_value_vrpos(struct ir_vr_pos pos); + struct ir_value bpf_ir_value_const32(s32 val); struct ir_value bpf_ir_value_const64(s64 val); @@ -1364,33 +1126,20 @@ struct ir_address_value bpf_ir_addr_val(struct ir_value value, s16 offset); struct ir_value bpf_ir_value_stack_ptr(struct ir_function *fun); -void bpf_ir_change_value(struct bpf_ir_env *env, struct ir_insn *insn, - struct ir_value *old, struct ir_value new); - -/* IR Value End */ +struct ir_value bpf_ir_value_r0(struct ir_function *fun); -/* IR Optimization Start */ - -void bpf_ir_optimize_ir(struct bpf_ir_env *env, struct ir_function *fun, - void *data); - -/* IR Optimization End */ - -/* CG Prepare Start */ - -void bpf_ir_cg_change_fun_arg(struct bpf_ir_env *env, struct ir_function *fun, - void *param); - -void bpf_ir_cg_change_call_pre_cg(struct bpf_ir_env *env, - struct ir_function *fun, void *param); +#define VR_POS_STACK_PTR \ + (struct ir_vr_pos) \ + { \ + .allocated = true, .alloc_reg = BPF_REG_10, .spilled = 0 \ + } -void bpf_ir_cg_add_stack_offset_pre_cg(struct bpf_ir_env *env, - struct ir_function *fun, void *param); +struct ir_value bpf_ir_value_norm_stack_ptr(void); -void bpr_ir_cg_to_cssa(struct bpf_ir_env *env, struct ir_function *fun, - void *param); +void bpf_ir_change_value(struct bpf_ir_env *env, struct ir_insn *insn, + struct ir_value *old, struct ir_value new); -/* CG Prepare End */ +/* IR Value End */ /* Kern Utils Start */ diff --git a/kernel/bpf/ir/Makefile b/kernel/bpf/ir/Makefile index 03fdb89e8..ddc72d04a 100644 --- a/kernel/bpf/ir/Makefile +++ b/kernel/bpf/ir/Makefile @@ -1,2 +1,2 @@ obj-y := kernpass/ -obj-y += array.o bpf_ir.o cg_prepare.o code_compaction.o disasm.o div_by_zero.o insn_counter_pass.o ir_bb.o ir_code_gen.o ir_helper.o ir_insn.o ir_utils.o ir_value.o jmp_complexity.o kern_utils.o lii.o msan.o optimization.o phi_pass.o prog_check.o translate_throw.o +obj-y += array.o bpf_ir.o cg_prepare.o cg_prog_check.o code_compaction.o disasm.o div_by_zero.o insn_counter_pass.o ir_bb.o ir_cg.o ir_cg_norm.o ir_helper.o ir_insn.o ir_utils.o ir_value.o jmp_complexity.o kern_utils.o lli.o msan.o optimization.o phi_pass.o prog_check.o ptrset.o translate_throw.o diff --git a/kernel/bpf/ir/array.c b/kernel/bpf/ir/array.c index a454cb1fc..04433ba2a 100644 --- a/kernel/bpf/ir/array.c +++ b/kernel/bpf/ir/array.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" void bpf_ir_array_init(struct array *res, size_t size) { @@ -74,6 +74,7 @@ void bpf_ir_array_clear(struct bpf_ir_env *env, struct array *arr) arr->num_elem = 0; } +// No need to initialize the res array void bpf_ir_array_clone(struct bpf_ir_env *env, struct array *res, struct array *arr) { diff --git a/kernel/bpf/ir/bpf_ir.c b/kernel/bpf/ir/bpf_ir.c index c0213d947..1da62e918 100644 --- a/kernel/bpf/ir/bpf_ir.c +++ b/kernel/bpf/ir/bpf_ir.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only - -#include -#include +#include "ir.h" static const s8 helper_func_arg_num[] = { [1] = 2, // map_lookup_elem @@ -217,27 +215,6 @@ static const s8 helper_func_arg_num[] = { [211] = 2, // cgrp_storage_delete }; -// All function passes -static const struct function_pass pre_passes[] = { - DEF_FUNC_PASS(remove_trivial_phi, "remove_trivial_phi", true), -}; - -static const struct function_pass post_passes[] = { - DEF_FUNC_PASS(bpf_ir_div_by_zero, "div_by_zero", false), - DEF_FUNC_PASS(msan, "msan", false), - DEF_FUNC_PASS(insn_counter, "insn_counter", false), - /* CG Preparation Passes */ - DEF_NON_OVERRIDE_FUNC_PASS(translate_throw, "translate_throw"), - DEF_FUNC_PASS(bpf_ir_optimize_code_compaction, "optimize_compaction", - false), - DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_optimize_ir, "optimize_ir"), - DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_change_fun_arg, "change_fun_arg"), - DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_change_call_pre_cg, "change_call"), - DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_add_stack_offset_pre_cg, - "add_stack_offset"), - DEF_NON_OVERRIDE_FUNC_PASS(bpr_ir_cg_to_cssa, "to_cssa"), -}; - static void write_variable(struct bpf_ir_env *env, struct ssa_transform_env *tenv, u8 reg, struct pre_ir_basic_block *bb, struct ir_value val); @@ -266,15 +243,16 @@ static int compare_num(const void *a, const void *b) return 0; } -static bool is_raw_insn_breakpoint(u8 code) +static bool is_raw_insn_breakpoint(const struct bpf_insn *insn) { + u8 code = insn->code; // exit, jmp (not call) is breakpoint if (BPF_CLASS(code) == BPF_JMP || BPF_CLASS(code) == BPF_JMP32) { - if (BPF_OP(code) != BPF_CALL) { - return true; - } else { + if (BPF_OP(code) == BPF_CALL) { // call is not a breakpoint return false; + } else { + return true; } } return false; @@ -286,13 +264,14 @@ static void add_entrance_info(struct bpf_ir_env *env, struct array *bb_entrances, size_t entrance_pos, size_t current_pos) { + // PRINT_LOG_DEBUG(env, "Add entrance %zu -> %zu\n", current_pos, + // entrance_pos); for (size_t i = 0; i < bb_entrances->num_elem; ++i) { struct bb_entrance_info *entry = ((struct bb_entrance_info *)(bb_entrances->data)) + i; if (entry->entrance == entrance_pos) { // Already has this entrance, add a pred - bpf_ir_array_push_unique(env, &entry->bb->preds, - ¤t_pos); + bpf_ir_array_push(env, &entry->bb->preds, ¤t_pos); return; } } @@ -301,8 +280,7 @@ static void add_entrance_info(struct bpf_ir_env *env, INIT_ARRAY(&preds, size_t); if (entrance_pos >= 1) { size_t last_pos = entrance_pos - 1; - u8 code = insns[last_pos].code; - if (!is_raw_insn_breakpoint(code)) { // Error! + if (!is_raw_insn_breakpoint(&insns[last_pos])) { // Error! // Breaking point // rx = ... // BB Entrance @@ -327,13 +305,20 @@ static struct pre_ir_basic_block *get_bb_parent(struct array *bb_entrance, (struct bb_entrance_info *)(bb_entrance->data); for (size_t i = 1; i < bb_entrance->num_elem; ++i) { struct bb_entrance_info *entry = bbs + i; + struct pre_ir_basic_block *bb = entry->bb; + DBGASSERT(bb->start_pos == entry->entrance); if (entry->entrance <= pos) { bb_id++; } else { break; } } - return bbs[bb_id].bb; + struct pre_ir_basic_block *bb = bbs[bb_id].bb; + if (pos >= bb->end_pos) { + return NULL; + } else { + return bb; + } } static void init_entrance_info(struct bpf_ir_env *env, @@ -378,14 +363,37 @@ static s64 to_s64(s32 imm, s32 next_imm) } static void gen_bb(struct bpf_ir_env *env, struct bb_info *ret, - const struct bpf_insn *insns, size_t len) + struct bpf_insn *insns, size_t len) { + // Remove pc+0 instructions + for (size_t i = 0; i < len; ++i) { + struct bpf_insn *insn = &insns[i]; + u8 code = insn->code; + if (BPF_CLASS(code) == BPF_JMP || + BPF_CLASS(code) == BPF_JMP32) { + if ((BPF_OP(code) >= BPF_JEQ && + BPF_OP(code) <= BPF_JSGE) || + (BPF_OP(code) >= BPF_JLT && + BPF_OP(code) <= BPF_JSLE)) { + // Conditional jump + if (insn->off == 0) { + // pc+0 + // Change to a nop (r0 = r0) + insn->code = BPF_JMP | BPF_JA; + insn->dst_reg = 0; + insn->src_reg = 0; + insn->imm = 0; + insn->off = 0; + } + } + } + } struct array bb_entrance; INIT_ARRAY(&bb_entrance, struct bb_entrance_info); // First, scan the code to find all the BB entrances for (size_t i = 0; i < len; ++i) { - struct bpf_insn insn = insns[i]; - u8 code = insn.code; + struct bpf_insn *insn = &insns[i]; + u8 code = insn->code; if (BPF_CLASS(code) == BPF_JMP || BPF_CLASS(code) == BPF_JMP32) { if (BPF_OP(code) == BPF_JA) { @@ -394,7 +402,7 @@ static void gen_bb(struct bpf_ir_env *env, struct bb_info *ret, if (BPF_CLASS(code) == BPF_JMP) { // JMP class (64 bits) // Add offset - pos = (s16)i + insn.off + 1; + pos = (s16)i + insn->off + 1; } else { // Impossible by spec RAISE_ERROR( @@ -411,7 +419,7 @@ static void gen_bb(struct bpf_ir_env *env, struct bb_info *ret, (BPF_OP(code) >= BPF_JLT && BPF_OP(code) <= BPF_JSLE)) { // Add offset - size_t pos = (s16)i + insn.off + 1; + size_t pos = (s16)i + insn->off + 1; add_entrance_info(env, insns, &bb_entrance, pos, i); CHECK_ERR(); @@ -462,9 +470,26 @@ static void gen_bb(struct bpf_ir_env *env, struct bb_info *ret, real_bb->visited = 0; real_bb->pre_insns = NULL; real_bb->start_pos = entry->entrance; - real_bb->end_pos = i + 1 < bb_entrance.num_elem ? - all_bbs[i + 1].entrance : - len; + size_t nj = i + 1 < bb_entrance.num_elem ? + all_bbs[i + 1].entrance : + len; + real_bb->end_pos = nj; + for (size_t j = entry->entrance; j < nj; ++j) { + u8 code = env->insns[j].code; + if (BPF_CLASS(code) == BPF_JMP || + BPF_CLASS(code) == BPF_JMP32) { + if (BPF_OP(code) == BPF_JA || + ((BPF_OP(code) >= BPF_JEQ && + BPF_OP(code) <= BPF_JSGE) || + (BPF_OP(code) >= BPF_JLT && + BPF_OP(code) <= BPF_JSLE)) || + (BPF_OP(code) == BPF_EXIT)) { + // end of a bb + real_bb->end_pos = j + 1; + break; + } + } + } real_bb->filled = 0; real_bb->sealed = 0; real_bb->ir_bb = NULL; @@ -504,7 +529,8 @@ static void gen_bb(struct bpf_ir_env *env, struct bb_info *ret, } for (size_t i = 0; i < bb_entrance.num_elem; ++i) { struct bb_entrance_info *entry = all_bbs + i; - + // PRINT_LOG_DEBUG(env, "entry %zu -> %zu\n", entry->entrance, + // entry->bb->start_pos); struct array preds = entry->bb->preds; struct array new_preds; INIT_ARRAY(&new_preds, struct pre_ir_basic_block *); @@ -513,10 +539,14 @@ static void gen_bb(struct bpf_ir_env *env, struct bb_info *ret, // Get the real parent BB struct pre_ir_basic_block *parent_bb = get_bb_parent(&bb_entrance, pred_pos); - // We push the address to the array - bpf_ir_array_push(env, &new_preds, &parent_bb); - // Add entry->bb to the succ of parent_bb - bpf_ir_array_push(env, &parent_bb->succs, &entry->bb); + + if (parent_bb) { + // We push the address to the array + bpf_ir_array_push(env, &new_preds, &parent_bb); + // Add entry->bb to the succ of parent_bb + bpf_ir_array_push(env, &parent_bb->succs, + &entry->bb); + } } bpf_ir_array_free(&preds); entry->bb->preds = new_preds; @@ -533,11 +563,19 @@ static void print_pre_ir_cfg(struct bpf_ir_env *env, return; } bb->visited = 1; - PRINT_LOG_DEBUG(env, "BB %ld:\n", bb->id); + PRINT_LOG_DEBUG(env, "BB %ld at [%zu, %zu):\n", bb->id, bb->start_pos, + bb->end_pos); for (size_t i = 0; i < bb->len; ++i) { struct pre_ir_insn insn = bb->pre_insns[i]; - PRINT_LOG_DEBUG(env, "%x %x %llx\n", insn.opcode, insn.imm, - insn.imm64); + struct bpf_insn binsn; + binsn.code = insn.opcode; + binsn.src_reg = insn.src_reg; + binsn.dst_reg = insn.dst_reg; + binsn.imm = insn.imm; + binsn.off = insn.off; + bpf_ir_print_bpf_insn(env, &binsn); + // PRINT_LOG_DEBUG(env, "%x %x %llx\n", insn.opcode, insn.imm, + // insn.imm64); } PRINT_LOG_DEBUG(env, "preds (%ld): ", bb->preds.num_elem); for (size_t i = 0; i < bb->preds.num_elem; ++i) { @@ -646,7 +684,6 @@ static struct ir_insn *add_phi_operands(struct bpf_ir_env *env, env, tenv, reg, (struct pre_ir_basic_block *)pred->user_data); add_user(env, insn, phi.value); - bpf_ir_array_push(env, &pred->users, &insn); bpf_ir_array_push(env, &insn->phi, &phi); } return insn; @@ -982,8 +1019,6 @@ static void create_cond_jmp(struct bpf_ir_env *env, size_t pos = insn.pos + insn.off + 1; new_insn->bb1 = get_ir_bb_from_position(tenv, insn.pos + 1); new_insn->bb2 = get_ir_bb_from_position(tenv, pos); - bpf_ir_array_push(env, &new_insn->bb1->users, &new_insn); - bpf_ir_array_push(env, &new_insn->bb2->users, &new_insn); set_insn_raw_pos(new_insn, insn.pos); set_value_raw_pos(&new_insn->values[0], insn.pos, IR_RAW_POS_DST); @@ -1018,6 +1053,12 @@ static void transform_bb(struct bpf_ir_env *env, struct ssa_transform_env *tenv, for (size_t i = 0; i < bb->len; ++i) { struct pre_ir_insn insn = bb->pre_insns[i]; u8 code = insn.opcode; + struct bpf_insn t_insn; + t_insn.code = code; + t_insn.dst_reg = insn.dst_reg; + t_insn.src_reg = insn.src_reg; + t_insn.off = insn.off; + t_insn.imm = insn.imm; if (BPF_CLASS(code) == BPF_ALU || BPF_CLASS(code) == BPF_ALU64) { // ALU class @@ -1245,8 +1286,6 @@ static void transform_bb(struct bpf_ir_env *env, struct ssa_transform_env *tenv, new_insn->bb1 = get_ir_bb_from_position(tenv, pos); set_insn_raw_pos(new_insn, insn.pos); - bpf_ir_array_push(env, &new_insn->bb1->users, - &new_insn); } else if (BPF_OP(code) == BPF_EXIT) { // Exit struct ir_insn *new_insn = @@ -1281,6 +1320,14 @@ static void transform_bb(struct bpf_ir_env *env, struct ssa_transform_env *tenv, // PC += offset if dst != src create_cond_jmp(env, tenv, bb, insn, IR_INSN_JNE, alu_ty); + } else if (BPF_OP(code) == BPF_JSGE) { + // PC += offset if dst s>= src + create_cond_jmp(env, tenv, bb, insn, + IR_INSN_JSGE, alu_ty); + } else if (BPF_OP(code) == BPF_JSLE) { + // PC += offset if dst s<= src + create_cond_jmp(env, tenv, bb, insn, + IR_INSN_JSLE, alu_ty); } else if (BPF_OP(code) == BPF_JSGT) { // PC += offset if dst s> src create_cond_jmp(env, tenv, bb, insn, @@ -1296,8 +1343,24 @@ static void transform_bb(struct bpf_ir_env *env, struct ssa_transform_env *tenv, set_insn_raw_pos(new_insn, insn.pos); new_insn->op = IR_INSN_CALL; new_insn->fid = insn.imm; + if (insn.src_reg == 1) { + // call PC+offset + PRINT_LOG_ERROR(env, "call pc+%d\n", + insn.imm); + RAISE_ERROR( + "BPF-local functions not supported"); + } + if (insn.src_reg == 2) { + // platform-specific helper function imm + RAISE_ERROR( + "Platform-specific helper function not supported"); + } if (insn.imm < 0) { new_insn->value_num = 0; + PRINT_LOG_ERROR( + env, + "Unknown helper function %d at %d\n", + insn.imm, insn.pos); RAISE_ERROR( "Not supported function call\n"); } else { @@ -1307,29 +1370,38 @@ static void transform_bb(struct bpf_ir_env *env, struct ssa_transform_env *tenv, sizeof(helper_func_arg_num) / sizeof(helper_func_arg_num [0])) { + bpf_ir_print_bpf_insn(env, + &t_insn); PRINT_LOG_ERROR( env, - "unknown helper function %d at %d\n", + "Unknown helper function %d at %d\n", insn.imm, insn.pos); RAISE_ERROR( "Unsupported helper function"); } if (helper_func_arg_num[insn.imm] < 0) { - // Variable length, infer from previous instructions - new_insn->value_num = 0; - // used[x] means whether there exists a usage of register x + 1 - for (u8 j = 0; j < MAX_FUNC_ARG; - ++j) { - if (is_variable_defined( - tenv, - j + BPF_REG_1, - bb)) { - new_insn->value_num = - j + - BPF_REG_1; - } else { - break; + if (insn.imm == 6) { + // printk instruction + // Variable length, infer from previous instructions + new_insn->value_num = 2; + // used[x] means whether there exists a usage of register x + 1 + for (u8 j = 2; + j < MAX_FUNC_ARG; + ++j) { + if (is_variable_defined( + tenv, + j + BPF_REG_1, + bb)) { + new_insn->value_num = + j + + BPF_REG_1; + } else { + break; + } } + } else { + RAISE_ERROR( + "Unknown helper function"); } } else { new_insn->value_num = @@ -1365,6 +1437,7 @@ static void transform_bb(struct bpf_ir_env *env, struct ssa_transform_env *tenv, } } else { // TODO + bpf_ir_print_bpf_insn(env, &t_insn); PRINT_LOG_ERROR(env, "Class 0x%02x not supported\n", BPF_CLASS(code)); RAISE_ERROR("Not supported"); @@ -1404,22 +1477,21 @@ struct ir_insn *bpf_ir_find_ir_insn_by_rawpos(struct ir_function *fun, void bpf_ir_free_function(struct ir_function *fun) { - for (size_t i = 0; i < fun->all_bbs.num_elem; ++i) { - struct ir_basic_block *bb = - ((struct ir_basic_block **)(fun->all_bbs.data))[i]; - + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; bpf_ir_array_free(&bb->preds); bpf_ir_array_free(&bb->succs); - bpf_ir_array_free(&bb->users); // Free the instructions - struct ir_insn *pos = NULL, *n = NULL; - list_for_each_entry_safe(pos, n, &bb->ir_insn_head, list_ptr) { - list_del(&pos->list_ptr); - bpf_ir_array_free(&pos->users); - if (pos->op == IR_INSN_PHI) { - bpf_ir_array_free(&pos->phi); + struct ir_insn *pos2 = NULL, *n = NULL; + list_for_each_entry_safe(pos2, n, &bb->ir_insn_head, list_ptr) { + list_del(&pos2->list_ptr); + bpf_ir_array_free(&pos2->users); + if (pos2->op == IR_INSN_PHI) { + bpf_ir_array_free(&pos2->phi); } - free_proto(pos); + free_proto(pos2); } free_proto(bb); } @@ -1431,15 +1503,9 @@ void bpf_ir_free_function(struct ir_function *fun) bpf_ir_array_free(&fun->sp->users); free_proto(fun->sp); } - for (u8 i = 0; i < BPF_REG_10; ++i) { - struct ir_insn *insn = fun->cg_info.regs[i]; - bpf_ir_array_free(&insn->users); - free_proto(insn); - } bpf_ir_array_free(&fun->all_bbs); bpf_ir_array_free(&fun->reachable_bbs); bpf_ir_array_free(&fun->end_bbs); - bpf_ir_array_free(&fun->cg_info.all_var); } static void init_function(struct bpf_ir_env *env, struct ir_function *fun, @@ -1454,7 +1520,6 @@ static void init_function(struct bpf_ir_env *env, struct ir_function *fun, INIT_ARRAY(&fun->all_bbs, struct ir_basic_block *); INIT_ARRAY(&fun->reachable_bbs, struct ir_basic_block *); INIT_ARRAY(&fun->end_bbs, struct ir_basic_block *); - INIT_ARRAY(&fun->cg_info.all_var, struct ir_insn *); for (size_t i = 0; i < MAX_BPF_REG; ++i) { struct array *currentDef = &tenv->currentDef[i]; bpf_ir_array_free(currentDef); @@ -1470,17 +1535,6 @@ static void init_function(struct bpf_ir_env *env, struct ir_function *fun, bpf_ir_array_push(env, &fun->all_bbs, &bb->ir_bb); free_proto(bb); } - for (u8 i = 0; i < BPF_REG_10; ++i) { - struct ir_insn *insn; - SAFE_MALLOC(fun->cg_info.regs[i], sizeof(struct ir_insn)); - // Those should be read-only - insn = fun->cg_info.regs[i]; - insn->op = IR_INSN_REG; - insn->parent_bb = NULL; - INIT_ARRAY(&insn->users, struct ir_insn *); - insn->value_num = 0; - insn->reg_id = i; - } } static void gen_bb_succ(struct bpf_ir_env *env, struct ir_function *fun) @@ -1499,6 +1553,8 @@ static void gen_bb_succ(struct bpf_ir_env *env, struct ir_function *fun) if (bb->succs.num_elem != 2) { print_ir_insn_err(env, insn, "Jump instruction"); + PRINT_LOG_ERROR(env, "Has %d succ\n", + bb->succs.num_elem); RAISE_ERROR( "Conditional jmp with != 2 successors"); } @@ -1522,71 +1578,110 @@ static void gen_bb_succ(struct bpf_ir_env *env, struct ir_function *fun) } } -static void add_reach(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_basic_block *bb) +// Find the head of the chain +static struct ir_basic_block *find_chain_head(struct ir_basic_block *bb) { - if (bb->_visited) { - return; + if (bb->preds.num_elem == 0) { + return bb; } - // bb->_visited = 1; - // bpf_ir_array_push(env, &fun->reachable_bbs, &bb); - struct array todo; - INIT_ARRAY(&todo, struct ir_basic_block *); - - // struct ir_basic_block **succ; - // bool first = false; - // array_for(succ, bb->succs) - // { - // if (!first && bb->succs.num_elem > 1) { - // first = true; - // // Check if visited - // if ((*succ)->_visited) { - // RAISE_ERROR("Loop BB detected"); - // } - // } - // add_reach(env, fun, *succ); - // } - - // First Test sanity ... TODO! - - struct ir_basic_block *cur_bb = bb; - - while (1) { - cur_bb->_visited = 1; - bpf_ir_array_push(env, &fun->reachable_bbs, &cur_bb); - if (cur_bb->succs.num_elem == 0) { - break; - } - - struct ir_basic_block **succ1 = - bpf_ir_array_get_void(&cur_bb->succs, 0); - if ((*succ1)->_visited) { - break; - } - if (cur_bb->succs.num_elem == 1) { - // Check if end with JA - struct ir_insn *lastinsn = bpf_ir_get_last_insn(cur_bb); + struct ir_basic_block *pred = NULL; + struct ir_basic_block **pos; + array_for(pos, bb->preds) + { + struct ir_basic_block *bb2 = *pos; + if (bb2->succs.num_elem == 1) { + struct ir_insn *lastinsn = bpf_ir_get_last_insn(bb2); if (lastinsn && lastinsn->op == IR_INSN_JA) { - struct ir_basic_block **succ2 = - bpf_ir_array_get_void(&cur_bb->succs, - 0); - bpf_ir_array_push(env, &todo, succ2); - break; + // Not pred + } else { + if (pred) { + // Multiple preds, error + return NULL; + } else { + pred = bb2; + } + } + } else if (bb2->succs.num_elem == 2) { + struct ir_basic_block **succ0 = + bpf_ir_array_get_void(&bb2->succs, 0); + if (*succ0 == bb) { + // This is a pred + if (pred) { + // Multiple preds, error + return NULL; + } else { + pred = bb2; + } } - } else if (cur_bb->succs.num_elem == 2) { - struct ir_basic_block **succ2 = - bpf_ir_array_get_void(&cur_bb->succs, 1); - bpf_ir_array_push(env, &todo, succ2); } else { - CRITICAL("Not possible: BB with >2 succs"); + return NULL; } - cur_bb = *succ1; } + if (pred == NULL) { + // bb is head + return bb; + } + return find_chain_head(pred); +} - struct ir_basic_block **pos; - array_for(pos, todo) - { - add_reach(env, fun, *pos); +static void add_reach(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct array todo; + INIT_ARRAY(&todo, struct ir_basic_block *); + bpf_ir_array_push(env, &todo, &fun->entry); + size_t queue_head = 0; + while (queue_head < todo.num_elem) { + struct ir_basic_block **tmp = + bpf_ir_array_get_void(&todo, queue_head); + struct ir_basic_block *bb = *tmp; + queue_head++; + if (bb->_visited) { + continue; + } + bb = find_chain_head(bb); + if (!bb) { + RAISE_ERROR("Cannot find chain, invalid CFG"); + } + // If bb has not been visited, its chain head is not visited + DBGASSERT(!bb->_visited); + + // Visit this chain + // PRINT_LOG_DEBUG(env, "Chain:"); + bool end = false; + while (!end) { + bb->_visited = 1; + // PRINT_LOG_DEBUG(env, " %d", bb->_id); + bpf_ir_array_push(env, &fun->reachable_bbs, &bb); + if (bb->succs.num_elem == 0) { + // End of the chain + end = true; + } else if (bb->succs.num_elem == 1) { + struct ir_insn *lastinsn = + bpf_ir_get_last_insn(bb); + if (lastinsn && lastinsn->op == IR_INSN_JA) { + bpf_ir_array_push(env, &todo, + &lastinsn->bb1); + end = true; + } else { + struct ir_basic_block **succ = + bpf_ir_array_get_void( + &bb->succs, 0); + bb = *succ; + } + } else if (bb->succs.num_elem == 2) { + // bb = succ0, add succ1 to todo + struct ir_basic_block **succ0 = + bpf_ir_array_get_void(&bb->succs, 0); + struct ir_basic_block **succ1 = + bpf_ir_array_get_void(&bb->succs, 1); + + bb = *succ0; + bpf_ir_array_push(env, &todo, succ1); + } else { + RAISE_ERROR(">2 successors, invalid CFG"); + } + } + // PRINT_LOG_DEBUG(env, "\n"); } bpf_ir_array_free(&todo); @@ -1595,8 +1690,14 @@ static void add_reach(struct bpf_ir_env *env, struct ir_function *fun, static void gen_reachable_bbs(struct bpf_ir_env *env, struct ir_function *fun) { bpf_ir_clean_visited(fun); + // size_t cnt = 0; + // size_t bb_cnt = 0; + // assign_id(fun->entry, &cnt, &bb_cnt); + // bpf_ir_clean_visited(fun); + bpf_ir_array_clear(env, &fun->reachable_bbs); - add_reach(env, fun, fun->entry); + add_reach(env, fun); + // bpf_ir_clean_id(fun); } static void gen_end_bbs(struct bpf_ir_env *env, struct ir_function *fun) @@ -1643,20 +1744,19 @@ static void run_single_pass(struct bpf_ir_env *env, struct ir_function *fun, CHECK_ERR(); } -void bpf_ir_run(struct bpf_ir_env *env, struct ir_function *fun) +void bpf_ir_run_passes(struct bpf_ir_env *env, struct ir_function *fun, + const struct function_pass *passes, const size_t cnt) { - u64 starttime = get_cur_time_ns(); - for (size_t i = 0; i < sizeof(pre_passes) / sizeof(pre_passes[0]); - ++i) { + for (size_t i = 0; i < cnt; ++i) { bool has_override = false; for (size_t j = 0; j < env->opts.builtin_pass_cfg_num; ++j) { if (strcmp(env->opts.builtin_pass_cfg[j].name, - pre_passes[i].name) == 0) { + passes[i].name) == 0) { has_override = true; - if (pre_passes[i].force_enable || + if (passes[i].force_enable || env->opts.builtin_pass_cfg[j].enable) { run_single_pass( - env, fun, &pre_passes[i], + env, fun, &passes[i], env->opts.builtin_pass_cfg[j] .param); } @@ -1664,13 +1764,19 @@ void bpf_ir_run(struct bpf_ir_env *env, struct ir_function *fun) } } if (!has_override) { - if (pre_passes[i].enabled) { - run_single_pass(env, fun, &pre_passes[i], NULL); + if (passes[i].enabled) { + run_single_pass(env, fun, &passes[i], NULL); } } CHECK_ERR(); } +} + +void bpf_ir_run(struct bpf_ir_env *env, struct ir_function *fun) +{ + u64 starttime = get_cur_time_ns(); + bpf_ir_run_passes(env, fun, pre_passes, pre_passes_cnt); for (size_t i = 0; i < env->opts.custom_pass_num; ++i) { if (env->opts.custom_passes[i].pass.enabled) { if (env->opts.custom_passes[i].check_apply) { @@ -1692,31 +1798,7 @@ void bpf_ir_run(struct bpf_ir_env *env, struct ir_function *fun) CHECK_ERR(); } } - for (size_t i = 0; i < sizeof(post_passes) / sizeof(post_passes[0]); - ++i) { - bool has_override = false; - for (size_t j = 0; j < env->opts.builtin_pass_cfg_num; ++j) { - if (strcmp(env->opts.builtin_pass_cfg[j].name, - post_passes[i].name) == 0) { - has_override = true; - if (post_passes[i].force_enable || - env->opts.builtin_pass_cfg[j].enable) { - run_single_pass( - env, fun, &post_passes[i], - env->opts.builtin_pass_cfg[j] - .param); - } - break; - } - } - if (!has_override) { - if (post_passes[i].enabled) { - run_single_pass(env, fun, &post_passes[i], - NULL); - } - } - CHECK_ERR(); - } + bpf_ir_run_passes(env, fun, post_passes, post_passes_cnt); env->run_time += get_cur_time_ns() - starttime; } @@ -1742,7 +1824,7 @@ static void print_bpf_prog_dump(struct bpf_ir_env *env, const struct bpf_insn *insn = &insns[i]; __u64 data; memcpy(&data, insn, sizeof(struct bpf_insn)); - PRINT_LOG_DEBUG(env, "insn[%d]: %llu\n", i, data); + PRINT_LOG_DEBUG(env, "%llu\n", data); } } @@ -1779,12 +1861,11 @@ static void print_bpf_prog(struct bpf_ir_env *env, const struct bpf_insn *insns, // Interface implementation -struct ir_function *bpf_ir_lift(struct bpf_ir_env *env, - const struct bpf_insn *insns, size_t len) +struct ir_function *bpf_ir_lift(struct bpf_ir_env *env) { u64 starttime = get_cur_time_ns(); struct bb_info info; - gen_bb(env, &info, insns, len); + gen_bb(env, &info, env->insns, env->insn_cnt); CHECK_ERR(NULL); if (env->opts.verbose > 2) { @@ -1814,9 +1895,21 @@ struct ir_function *bpf_ir_lift(struct bpf_ir_env *env, void bpf_ir_autorun(struct bpf_ir_env *env) { env->executed = true; - const struct bpf_insn *insns = env->insns; + struct bpf_insn *insns = env->insns; size_t len = env->insn_cnt; - struct ir_function *fun = bpf_ir_lift(env, insns, len); + if (env->opts.max_insns > 0 && len > env->opts.max_insns) { + PRINT_LOG_ERROR(env, "Program size: %zu\n", len); + RAISE_ERROR("Program too large"); + } + + PRINT_LOG_DEBUG(env, + "--------------------\nOriginal Program, size %zu:\n", + len); + print_bpf_prog(env, insns, len); + if (env->opts.print_only) { + return; + } + struct ir_function *fun = bpf_ir_lift(env); CHECK_ERR(); print_ir_prog(env, fun); @@ -1845,6 +1938,10 @@ void bpf_ir_autorun(struct bpf_ir_env *env) // Free the memory bpf_ir_free_function(fun); + + if (env->opts.fake_run) { + RAISE_ERROR("Fake run finished"); + } } struct bpf_ir_opts bpf_ir_default_opts(void) @@ -1853,13 +1950,16 @@ struct bpf_ir_opts bpf_ir_default_opts(void) opts.print_mode = BPF_IR_PRINT_BPF; opts.builtin_pass_cfg_num = 0; opts.custom_pass_num = 0; - opts.enable_coalesce = false; opts.force = false; opts.verbose = 1; + opts.dotgraph = false; + opts.fake_run = false; opts.max_iteration = 10; opts.disable_prog_check = false; opts.enable_throw_msg = false; opts.enable_printk_log = false; + opts.max_insns = 0; + opts.print_only = false; return opts; } diff --git a/kernel/bpf/ir/cg_prepare.c b/kernel/bpf/ir/cg_prepare.c index a5d754985..034d55ce2 100644 --- a/kernel/bpf/ir/cg_prepare.c +++ b/kernel/bpf/ir/cg_prepare.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir_cg.h" // Pre CG void bpf_ir_cg_change_fun_arg(struct bpf_ir_env *env, struct ir_function *fun, @@ -10,7 +10,7 @@ void bpf_ir_cg_change_fun_arg(struct bpf_ir_env *env, struct ir_function *fun, // Insert ASSIGN arg[i] at the beginning of the function struct ir_insn *new_insn = bpf_ir_create_assign_insn_bb( env, fun->entry, - bpf_ir_value_insn(fun->cg_info.regs[i + 1]), + bpf_ir_value_insn(cg_info(fun)->regs[i + 1]), INSERT_FRONT_AFTER_PHI); bpf_ir_replace_all_usage(env, fun->function_arg[i], bpf_ir_value_insn(new_insn)); @@ -37,7 +37,7 @@ void bpf_ir_cg_change_call_pre_cg(struct bpf_ir_env *env, bpf_ir_create_assign_insn( env, insn, bpf_ir_value_insn( - fun->cg_info.regs[0]), + cg_info(fun)->regs[0]), INSERT_BACK); bpf_ir_replace_all_usage( env, insn, bpf_ir_value_insn(new_insn)); diff --git a/kernel/bpf/ir/cg_prog_check.c b/kernel/bpf/ir/cg_prog_check.c new file mode 100644 index 000000000..7009af9c7 --- /dev/null +++ b/kernel/bpf/ir/cg_prog_check.c @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "ir.h" +#include "ir_cg.h" + +static void check_userdata(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (!insn_cg(insn)) { + print_ir_insn_err(env, insn, "No userdata"); + RAISE_ERROR("No userdata"); + } + } + } +} + +void bpf_ir_cg_prog_check(struct bpf_ir_env *env, struct ir_function *fun) +{ + tag_ir(fun); + check_userdata(env, fun); + CHECK_ERR(); +} diff --git a/kernel/bpf/ir/code_compaction.c b/kernel/bpf/ir/code_compaction.c index 9906fc909..fdd921e60 100644 --- a/kernel/bpf/ir/code_compaction.c +++ b/kernel/bpf/ir/code_compaction.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" // An optimization mentioned in MERLIN that is hard to do in LLVM diff --git a/kernel/bpf/ir/disasm.c b/kernel/bpf/ir/disasm.c index 00171f8ce..cb76bf05b 100644 --- a/kernel/bpf/ir/disasm.c +++ b/kernel/bpf/ir/disasm.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // Modified from kernel/bpf/disasm.c - -#include +#include "ir.h" static const char *const bpf_class_string[8] = { [BPF_LD] = "ld", [BPF_LDX] = "ldx", [BPF_ST] = "st", diff --git a/kernel/bpf/ir/div_by_zero.c b/kernel/bpf/ir/div_by_zero.c index f2ecf8b73..16e701b57 100644 --- a/kernel/bpf/ir/div_by_zero.c +++ b/kernel/bpf/ir/div_by_zero.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" void bpf_ir_div_by_zero(struct bpf_ir_env *env, struct ir_function *fun, void *param) diff --git a/kernel/bpf/ir/insn_counter_pass.c b/kernel/bpf/ir/insn_counter_pass.c index 151d51d90..b45f3a625 100644 --- a/kernel/bpf/ir/insn_counter_pass.c +++ b/kernel/bpf/ir/insn_counter_pass.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" static u32 en_pred_num(struct ir_function *fun, struct ir_basic_block *bb) { @@ -27,7 +27,7 @@ static void add_counter_to_bb(struct bpf_ir_env *env, struct ir_basic_block *bb, struct ir_insn *load_insn = bpf_ir_create_load_insn_bb( env, bb, bpf_ir_value_insn(alloc_insn), INSERT_BACK); struct ir_value cv = bpf_ir_value_const32(-1); - cv.builtin_const = IR_BUILTIN_BB_INSN_CRITICAL_CNT; + cv.builtin_const = IR_BUILTIN_BB_INSN_CNT; struct ir_insn *added = bpf_ir_create_bin_insn( env, load_insn, bpf_ir_value_insn(load_insn), cv, IR_INSN_ADD, IR_ALU_64, INSERT_BACK); @@ -49,7 +49,7 @@ static void add_counter_to_bb(struct bpf_ir_env *env, struct ir_basic_block *bb, struct ir_insn *load_insn = bpf_ir_create_load_insn( env, last, bpf_ir_value_insn(alloc_insn), INSERT_FRONT); struct ir_value cv = bpf_ir_value_const32(-1); - cv.builtin_const = IR_BUILTIN_BB_INSN_CRITICAL_CNT; + cv.builtin_const = IR_BUILTIN_BB_INSN_CNT; struct ir_insn *added = bpf_ir_create_bin_insn( env, load_insn, bpf_ir_value_insn(load_insn), cv, IR_INSN_ADD, IR_ALU_64, INSERT_BACK); diff --git a/kernel/bpf/ir/ir.h b/kernel/bpf/ir/ir.h new file mode 100644 index 000000000..bb4bbd1ca --- /dev/null +++ b/kernel/bpf/ir/ir.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_IR_H +#define _LINUX_IR_H + +/* +Internal functions and definitions for BPF IR. +*/ + +#include + +#ifdef __KERNEL__ + +#include +#define qsort(a, b, c, d) sort(a, b, c, d, NULL) + +#endif + +#define CHECK_ERR(x) \ + if (env->err) { \ + return x; \ + } + +/* LLI Start */ + +void *malloc_proto(size_t size); + +void free_proto(void *ptr); + +int parse_int(const char *str, int *val); + +u64 get_cur_time_ns(void); + +#define SAFE_MALLOC(dst, size) \ + { \ + dst = malloc_proto(size); \ + if (!dst) { \ + env->err = -ENOMEM; \ + return; \ + } \ + } + +#define SAFE_MALLOC_RET_NULL(dst, size) \ + { \ + dst = malloc_proto(size); \ + if (!dst) { \ + env->err = -ENOMEM; \ + return NULL; \ + } \ + } + +/* LLI End */ + +enum imm_type { IMM, IMM64 }; + +/* Pre-IR instructions, similar to `bpf_insn` */ +struct pre_ir_insn { + u8 opcode; + + u8 dst_reg; + u8 src_reg; + s16 off; + + enum imm_type it; + s32 imm; + s64 imm64; // Immediate constant for 64-bit immediate + + size_t pos; // Original position +}; + +int bpf_ir_valid_alu_type(enum ir_alu_op_type type); + +int bpf_ir_valid_vr_type(enum ir_vr_type type); + +u32 bpf_ir_sizeof_vr_type(enum ir_vr_type type); + +/** + Pre-IR BB + + This includes many data structures needed to generate the IR. + */ +struct pre_ir_basic_block { + // An ID used to debug + size_t id; + + // Start position in the original insns + size_t start_pos; + + // End position in the original insns + size_t end_pos; + + // The number of instructions in this basic block (modified length) + size_t len; + + struct pre_ir_insn *pre_insns; + + struct array preds; + struct array succs; + + u8 visited; + + u8 sealed; + u8 filled; + struct ir_basic_block *ir_bb; + struct ir_insn *incompletePhis[MAX_BPF_REG]; +}; + +/** + The BB value used in currentDef + */ +struct bb_val { + struct pre_ir_basic_block *bb; + struct ir_value val; +}; + +/** + BB with the raw entrance position + */ +struct bb_entrance_info { + size_t entrance; + struct pre_ir_basic_block *bb; +}; + +/** + Generated BB information + */ +struct bb_info { + struct pre_ir_basic_block *entry; + + // Array of bb_entrance_info + struct array all_bbs; +}; + +/** + The environment data for transformation + */ +struct ssa_transform_env { + // Array of bb_val (which is (BB, Value) pair) + struct array currentDef[MAX_BPF_REG]; + struct bb_info info; + + // Stack Pointer + struct ir_insn *sp; + + // Function argument + struct ir_insn *function_arg[MAX_FUNC_ARG]; +}; + +void bpf_ir_run_passes(struct bpf_ir_env *env, struct ir_function *fun, + const struct function_pass *passes, const size_t cnt); + +#endif diff --git a/kernel/bpf/ir/ir_bb.c b/kernel/bpf/ir/ir_bb.c index 5f051b713..28faf1de7 100644 --- a/kernel/bpf/ir/ir_bb.c +++ b/kernel/bpf/ir/ir_bb.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" size_t bpf_ir_bb_len(struct ir_basic_block *bb) { @@ -28,7 +28,6 @@ struct ir_basic_block *bpf_ir_init_bb_raw(void) new_bb->user_data = NULL; INIT_ARRAY(&new_bb->preds, struct ir_basic_block *); INIT_ARRAY(&new_bb->succs, struct ir_basic_block *); - INIT_ARRAY(&new_bb->users, struct ir_insn *); new_bb->flag = 0; return new_bb; } @@ -125,11 +124,6 @@ struct ir_insn *bpf_ir_get_first_insn(struct ir_basic_block *bb) return list_entry(bb->ir_insn_head.next, struct ir_insn, list_ptr); } -struct ir_bb_cg_extra *bpf_ir_bb_cg(struct ir_basic_block *bb) -{ - return bb->user_data; -} - void bpf_ir_bb_create_error_block(struct bpf_ir_env *env, struct ir_function *fun, struct ir_insn *insn, enum insert_position insert_pos, diff --git a/kernel/bpf/ir/ir_cg.c b/kernel/bpf/ir/ir_cg.c new file mode 100644 index 000000000..a5d8ccd9d --- /dev/null +++ b/kernel/bpf/ir/ir_cg.c @@ -0,0 +1,1404 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "ir.h" +#include "ir_cg.h" + +/* + +Using SSA-based RA and graph coloring algorithm. + +Algorithms are based on the following paper: + +Pereira, F., and Palsberg, J., "Register Allocation via the Coloring of Chordal Graphs", APLAS, pp 315-329 (2005) + +*/ + +/* CG Preparation Passes */ +static struct function_pass cg_init_passes[] = { + DEF_NON_OVERRIDE_FUNC_PASS(translate_throw, "translate_throw"), + DEF_FUNC_PASS(bpf_ir_optimize_code_compaction, "optimize_compaction", + false), + DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_optimize_ir, "optimize_ir"), + DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_add_stack_offset_pre_cg, + "add_stack_offset"), +}; + +// Erase an instruction. +// Only used in SSA Out process. +// Do not use it within RA (it doesn not maintain adj and all_var stuff properly) +static void erase_insn_cg(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *insn) +{ + if (insn->users.num_elem > 0) { + struct ir_insn **pos; + bool fail = false; + array_for(pos, insn->users) + { + if (*pos != insn) { + fail = true; + break; + } + } + if (fail) { + tag_ir(fun); + array_for(pos, insn->users) + { + print_ir_insn_err(env, *pos, "User"); + } + print_ir_insn_err(env, insn, "Has users"); + RAISE_ERROR( + "Cannot erase a instruction that has (non-self) users"); + } + } + struct array operands = bpf_ir_get_operands(env, insn); + CHECK_ERR(); + struct ir_value **pos2; + array_for(pos2, operands) + { + bpf_ir_val_remove_user((**pos2), insn); + } + bpf_ir_array_free(&operands); + list_del(&insn->list_ptr); + bpf_ir_array_free(&insn->users); + + struct ir_insn_cg_extra *extra = insn->user_data; + bpf_ir_ptrset_free(&extra->adj); + bpf_ir_ptrset_free(&extra->in); + bpf_ir_ptrset_free(&extra->out); + + free_proto(insn); +} + +static void remove_insn_dst(struct ir_insn *insn) +{ + insn_dst(insn) = NULL; +} + +static void pre_color(struct ir_function *fun, struct ir_insn *insn, u8 reg) +{ + insn_cg(insn)->finalized = true; + insn_cg(insn)->vr_pos.allocated = true; + insn_cg(insn)->vr_pos.alloc_reg = reg; + insn_cg(insn)->vr_pos.spilled = 0; +} + +void bpf_ir_init_insn_cg(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_insn_cg_extra *extra = NULL; + SAFE_MALLOC(extra, sizeof(struct ir_insn_cg_extra)); + insn->user_data = extra; + + extra->dst = bpf_ir_is_void(insn) ? NULL : insn; + extra->vr_pos.allocated = false; + extra->vr_pos.spilled = 0; + extra->vr_pos.spilled_size = 0; + extra->vr_pos.alloc_reg = 0; + extra->finalized = false; + extra->lambda = 0; + extra->w = 0; + + INIT_PTRSET_DEF(&extra->adj); + + INIT_PTRSET_DEF(&extra->in); + INIT_PTRSET_DEF(&extra->out); + extra->nonvr = false; +} + +static void init_cg(struct bpf_ir_env *env, struct ir_function *fun) +{ + // Initialize cg info + SAFE_MALLOC(fun->user_data, sizeof(struct code_gen_info)); + + INIT_ARRAY(&cg_info(fun)->seo, struct ir_insn *); + INIT_PTRSET_DEF(&cg_info(fun)->all_var); + cg_info(fun)->stack_offset = 0; + + for (u8 i = 0; i < BPF_REG_10; ++i) { + struct ir_insn *insn; + SAFE_MALLOC(cg_info(fun)->regs[i], sizeof(struct ir_insn)); + // Those should be read-only + insn = cg_info(fun)->regs[i]; + insn->op = IR_INSN_REG; + insn->parent_bb = NULL; + INIT_ARRAY(&insn->users, struct ir_insn *); + insn->value_num = 0; + insn->reg_id = i; + } + + struct ir_basic_block **pos = NULL; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_bb_cg_extra *bb_cg = NULL; + SAFE_MALLOC(bb_cg, sizeof(struct ir_bb_cg_extra)); + // Empty bb cg + bb->user_data = bb_cg; + + struct ir_insn *insn = NULL; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + bpf_ir_init_insn_cg(env, insn); + CHECK_ERR(); + } + } + + for (u8 i = 0; i < BPF_REG_10; ++i) { + struct ir_insn *insn = cg_info(fun)->regs[i]; + bpf_ir_init_insn_cg(env, insn); + CHECK_ERR(); + + struct ir_insn_cg_extra *extra = insn_cg(insn); + // Pre-colored registers are allocated + extra->vr_pos.alloc_reg = i; + extra->vr_pos.allocated = true; + extra->nonvr = true; + extra->finalized = true; + } + bpf_ir_init_insn_cg(env, fun->sp); + struct ir_insn_cg_extra *extra = insn_cg(fun->sp); + extra->vr_pos.alloc_reg = 10; + extra->vr_pos.allocated = true; + extra->nonvr = true; + extra->finalized = true; +} + +/* +Pre RA +*/ + +static void change_fun_arg(struct bpf_ir_env *env, struct ir_function *fun) +{ + for (u8 i = 0; i < MAX_FUNC_ARG; ++i) { + if (fun->function_arg[i]->users.num_elem > 0) { + // Insert ASSIGN arg[i] at the beginning of the function + struct ir_insn *new_insn = + bpf_ir_create_assign_insn_bb_cg( + env, fun->entry, + bpf_ir_value_insn( + cg_info(fun)->regs[i + 1]), + INSERT_FRONT_AFTER_PHI); + bpf_ir_replace_all_usage(env, fun->function_arg[i], + bpf_ir_value_insn(new_insn)); + } + } +} + +static void change_call(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_CALL) { + // Change function call args + for (u8 i = 0; i < insn->value_num; ++i) { + struct ir_value val = insn->values[i]; + bpf_ir_val_remove_user(val, insn); + struct ir_insn *new_insn = + bpf_ir_create_assign_insn_cg( + env, insn, val, + INSERT_FRONT); + pre_color(fun, new_insn, i + 1); + } + insn->value_num = 0; // Remove all operands + + // Change function call dst + remove_insn_dst(insn); + if (insn->users.num_elem == 0) { + continue; + } + struct ir_insn *new_insn = + bpf_ir_create_assign_insn_cg( + env, insn, + bpf_ir_value_insn( + cg_info(fun)->regs[0]), + INSERT_BACK); + bpf_ir_replace_all_usage( + env, insn, bpf_ir_value_insn(new_insn)); + } + } + } +} + +static inline s32 get_new_spill(struct ir_function *fun, u32 size) +{ + cg_info(fun)->stack_offset -= size; + return cg_info(fun)->stack_offset; +} + +static void spill_array(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn, *tmp; + list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, + list_ptr) { + if (insn->op == IR_INSN_ALLOCARRAY) { + struct ir_insn_cg_extra *extra = insn_cg(insn); + extra->vr_pos.allocated = true; + extra->finalized = true; + // Calculate the offset + u32 size = insn->array_num * + bpf_ir_sizeof_vr_type(insn->vr_type); + if (size == 0) { + RAISE_ERROR("Array size is 0"); + } + // Round up to 8 bytes + // u32 roundup_size = (((size - 1) / 8) + 1) * 8; + u32 roundup_size = (size + 7) & ~7; + extra->vr_pos.spilled = + get_new_spill(fun, roundup_size); + extra->vr_pos.spilled_size = size; + // extra->dst = NULL; + } + } + } +} + +// Spill constants based on BPF ISA +static void spill_const(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn, *tmp; + list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, + list_ptr) { + if (bpf_ir_is_bin_alu(insn) && + !bpf_ir_is_commutative_alu(insn)) { + struct ir_value *val = &insn->values[0]; + if (val->type == IR_VALUE_CONSTANT) { + // Change constant to a register + struct ir_insn *new_insn = + bpf_ir_create_assign_insn_cg( + env, insn, *val, + INSERT_FRONT); + bpf_ir_change_value( + env, insn, val, + bpf_ir_value_insn(new_insn)); + } + } + if (bpf_ir_is_cond_jmp(insn) && insn->value_num == 2) { + // jmp v0 v1, cannot be all constants + struct ir_value *v0 = &insn->values[1]; + struct ir_value *v1 = &insn->values[0]; + if (v0->type == IR_VALUE_CONSTANT && + v1->type == IR_VALUE_CONSTANT) { + // ==> + // tmp = v0 + // jmp tmp v1 + struct ir_insn *new_insn = + bpf_ir_create_assign_insn_cg( + env, insn, *v0, + INSERT_FRONT); + bpf_ir_change_value( + env, insn, v0, + bpf_ir_value_insn(new_insn)); + } + } + } + } +} + +/* +Print utils +*/ + +static void print_ir_dst(struct bpf_ir_env *env, struct ir_insn *insn) +{ + if (!insn->user_data) { + PRINT_LOG_DEBUG(env, "(?)"); + RAISE_ERROR("NULL userdata found"); + } + insn = insn_dst(insn); + if (insn) { + struct ir_vr_pos pos = insn_cg(insn)->vr_pos; + if (pos.allocated) { + // Pre-colored + if (pos.spilled) { + PRINT_LOG_DEBUG(env, "SP+%d", pos.spilled); + } else { + PRINT_LOG_DEBUG(env, "R%u", pos.alloc_reg); + } + } else { + print_insn_ptr_base(env, insn); + } + } else { + PRINT_LOG_DEBUG(env, "(NULL)"); + } +} + +static void print_ir_alloc(struct bpf_ir_env *env, struct ir_insn *insn) +{ + if (!insn->user_data) { + PRINT_LOG_DEBUG(env, "(?)"); + RAISE_ERROR("NULL userdata found"); + } + if (insn_dst(insn) == NULL) { + PRINT_LOG_DEBUG(env, "(NULL)"); + return; + } + struct ir_vr_pos pos = insn_cg(insn)->vr_pos; + DBGASSERT(pos.allocated); + if (insn_cg(insn)->finalized) { + if (pos.spilled) { + PRINT_LOG_DEBUG(env, "SP+%d", pos.spilled); + } else { + PRINT_LOG_DEBUG(env, "R%u", pos.alloc_reg); + } + } else { + if (pos.spilled) { + PRINT_LOG_DEBUG(env, "sp+%d", pos.spilled); + } else { + PRINT_LOG_DEBUG(env, "r%u", pos.alloc_reg); + } + } +} + +static void print_insn_extra(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_insn_cg_extra *insn_cg = insn->user_data; + if (insn_cg == NULL) { + CRITICAL("NULL user data"); + } + struct ir_insn **pos; + + PRINT_LOG_DEBUG(env, "\nIn:"); + ptrset_for(pos, insn_cg->in) + { + struct ir_insn *insn = *pos; + PRINT_LOG_DEBUG(env, " "); + print_insn_ptr_base(env, insn); + } + PRINT_LOG_DEBUG(env, "\nOut:"); + ptrset_for(pos, insn_cg->out) + { + struct ir_insn *insn = *pos; + PRINT_LOG_DEBUG(env, " "); + print_insn_ptr_base(env, insn); + } + PRINT_LOG_DEBUG(env, "\n-------------\n"); +} + +/* +SSA liveness analysis. +*/ + +static void live_in_at_statement(struct bpf_ir_env *env, + struct ir_function *fun, struct ptrset *M, + struct ir_insn *s, struct ir_insn *v); + +static void live_out_at_statement(struct bpf_ir_env *env, + struct ir_function *fun, struct ptrset *M, + struct ir_insn *s, struct ir_insn *v); + +static void make_conflict(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *v1, struct ir_insn *v2) +{ + DBGASSERT(v1 != v2); + struct ir_insn_cg_extra *v1e = insn_cg(v1); + struct ir_insn_cg_extra *v2e = insn_cg(v2); + struct ir_insn *r1 = v1; + struct ir_insn *r2 = v2; + if (v1e->finalized) { + DBGASSERT(v1e->vr_pos.allocated); + } + if (v1e->vr_pos.allocated) { + DBGASSERT(v1e->finalized); + if (v1e->vr_pos.spilled) { + // v1 is pre-spilled, no conflict + return; + } else { + r1 = cg_info(fun)->regs[v1e->vr_pos.alloc_reg]; + } + } + if (v2e->finalized) { + DBGASSERT(v2e->vr_pos.allocated); + } + if (v2e->vr_pos.allocated) { + DBGASSERT(v2e->finalized); + if (v2e->vr_pos.spilled) { + // v2 is pre-spilled, no conflict + return; + } else { + r2 = cg_info(fun)->regs[v2e->vr_pos.alloc_reg]; + } + } + struct ir_insn_cg_extra *r1e = insn_cg(r1); + struct ir_insn_cg_extra *r2e = insn_cg(r2); + bpf_ir_ptrset_insert(env, &r1e->adj, r2); + bpf_ir_ptrset_insert(env, &r2e->adj, r1); +} + +static void phi_conflict_at_block_no_propagate(struct bpf_ir_env *env, + struct ir_function *fun, + struct ir_basic_block *n, + struct ir_insn *v) +{ + struct ir_insn *last = bpf_ir_get_last_insn(n); + if (last) { + struct ptrset *set = NULL; + struct ir_insn_cg_extra *se = insn_cg(last); + if (bpf_ir_is_jmp(last)) { + // jmp xxx + // Conflict with its LIVE-IN + set = &se->in; + } else { + // Conflict with its LIVE-OUT + set = &se->out; + } + struct ir_insn **pos; + ptrset_for(pos, *set) + { + struct ir_insn *insn = *pos; + if (insn != v) { + make_conflict(env, fun, insn, v); + } + } + } else { + // Empty BB + struct array preds = n->preds; + struct ir_basic_block **pos; + array_for(pos, preds) + { + phi_conflict_at_block_no_propagate(env, fun, *pos, v); + } + } +} + +static void live_out_at_block(struct bpf_ir_env *env, struct ir_function *fun, + struct ptrset *M, struct ir_basic_block *n, + struct ir_insn *v) +{ + if (!bpf_ir_ptrset_exists(M, n)) { + bpf_ir_ptrset_insert(env, M, n); + struct ir_insn *last = bpf_ir_get_last_insn(n); + if (last) { + live_out_at_statement(env, fun, M, last, v); + } else { + // Empty BB + struct array preds = n->preds; + struct ir_basic_block **pos; + array_for(pos, preds) + { + live_out_at_block(env, fun, M, *pos, v); + } + } + } +} + +static void live_out_at_statement(struct bpf_ir_env *env, + struct ir_function *fun, struct ptrset *M, + struct ir_insn *s, struct ir_insn *v) +{ + // PRINT_LOG_DEBUG(env, "%%%d live out at statement %%%d\n", v->_insn_id, + // s->_insn_id); + struct ir_insn_cg_extra *se = insn_cg(s); + bpf_ir_ptrset_insert(env, &se->out, v); + if (se->dst) { + if (se->dst != v) { + make_conflict(env, fun, v, se->dst); + live_in_at_statement(env, fun, M, s, v); + } + } else { + // s has no dst (no KILL) + live_in_at_statement(env, fun, M, s, v); + } +} + +static void live_in_at_statement(struct bpf_ir_env *env, + struct ir_function *fun, struct ptrset *M, + struct ir_insn *s, struct ir_insn *v) +{ + // PRINT_LOG_DEBUG(env, "%%%d live in at statement %%%d\n", v->_insn_id, + // s->_insn_id); + bpf_ir_ptrset_insert(env, &(insn_cg(s))->in, v); + struct ir_insn *prev = bpf_ir_prev_insn(s); + if (prev == NULL) { + // First instruction + struct ir_basic_block **pos; + array_for(pos, s->parent_bb->preds) + { + live_out_at_block(env, fun, M, *pos, v); + } + } else { + live_out_at_statement(env, fun, M, prev, v); + } +} + +static void print_ir_prog_cg(struct bpf_ir_env *env, struct ir_function *fun, + char *msg) +{ + PRINT_LOG_DEBUG(env, "\x1B[32m----- CG: %s -----\x1B[0m\n", msg); + print_ir_prog_advanced(env, fun, NULL, NULL, NULL); +} + +static void print_ir_prog_cg_dst_liveness(struct bpf_ir_env *env, + struct ir_function *fun, char *msg) +{ + PRINT_LOG_DEBUG(env, "\x1B[32m----- CG: %s -----\x1B[0m\n", msg); + print_ir_prog_advanced(env, fun, NULL, print_insn_extra, print_ir_dst); +} + +static void print_ir_prog_cg_dst(struct bpf_ir_env *env, + struct ir_function *fun, char *msg) +{ + PRINT_LOG_DEBUG(env, "\x1B[32m----- CG: %s -----\x1B[0m\n", msg); + print_ir_prog_advanced(env, fun, NULL, NULL, print_ir_dst); +} + +static void print_ir_prog_cg_alloc(struct bpf_ir_env *env, + struct ir_function *fun, char *msg) +{ + PRINT_LOG_DEBUG(env, "\x1B[32m----- CG: %s -----\x1B[0m\n", msg); + print_ir_prog_advanced(env, fun, NULL, NULL, print_ir_alloc); +} + +static void print_insn_ptr_base_dot(struct bpf_ir_env *env, + struct ir_insn *insn) +{ + if (insn->op == IR_INSN_REG) { + PRINT_LOG_DEBUG(env, "R%u", insn->reg_id); + return; + } + if (insn->op == IR_INSN_FUNCTIONARG) { + PRINT_LOG_DEBUG(env, "ARG%u", insn->fun_arg_id); + return; + } + if (insn->_insn_id == (size_t)(-1)) { + PRINT_LOG_DEBUG(env, "PTR%p", insn); + return; + } + PRINT_LOG_DEBUG(env, "VR%zu", insn->_insn_id); +} + +static void print_interference_graph(struct bpf_ir_env *env, + struct ir_function *fun) +{ + PRINT_LOG_DEBUG(env, + "\x1B[32m----- CG: Interference Graph -----\x1B[0m\n"); + tag_ir(fun); + if (env->opts.dotgraph) { + PRINT_LOG_DEBUG(env, "graph {\n"); + struct ir_insn **pos2; + ptrset_for(pos2, cg_info(fun)->all_var) + { + struct ir_insn *v = *pos2; + struct ir_insn **pos3; + ptrset_for(pos3, insn_cg(v)->adj) + { + PRINT_LOG_DEBUG(env, "\t"); + print_insn_ptr_base_dot(env, v); + PRINT_LOG_DEBUG(env, " -- "); + struct ir_insn *c = *pos3; // conflict vr + print_insn_ptr_base_dot(env, c); + PRINT_LOG_DEBUG(env, ";\n"); + } + } + PRINT_LOG_DEBUG(env, "}\n"); + } else { + struct ir_insn **pos2; + ptrset_for(pos2, cg_info(fun)->all_var) + { + struct ir_insn *v = *pos2; + print_insn_ptr_base(env, v); + PRINT_LOG_DEBUG(env, ": "); + struct ir_insn **pos3; + ptrset_for(pos3, insn_cg(v)->adj) + { + struct ir_insn *c = *pos3; // conflict vr + print_insn_ptr_base(env, c); + PRINT_LOG_DEBUG(env, " "); + } + PRINT_LOG_DEBUG(env, "\n"); + } + } +} + +static void clean_cg_data_insn(struct ir_insn *insn) +{ + struct ir_insn_cg_extra *extra = insn->user_data; + DBGASSERT(extra); + bpf_ir_ptrset_clean(&extra->adj); + bpf_ir_ptrset_clean(&extra->in); + bpf_ir_ptrset_clean(&extra->out); + extra->lambda = 0; + extra->w = 0; + + if (!extra->finalized) { + // Clean register allocation + extra->vr_pos.allocated = false; + } +} + +// Clean data generated during each iteration of RA +static void clean_cg_data(struct bpf_ir_env *env, struct ir_function *fun) +{ + bpf_ir_ptrset_clean(&cg_info(fun)->all_var); + // Add all real registers to the graph + for (int i = 0; i < RA_COLORS; ++i) { + bpf_ir_ptrset_insert(env, &cg_info(fun)->all_var, + cg_info(fun)->regs[i]); + clean_cg_data_insn(cg_info(fun)->regs[i]); + } + + // Note. there should be no use of function arg anymore as they are replaced by + // %0 = R1 + // etc. + + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *v; + list_for_each_entry(v, &bb->ir_insn_head, list_ptr) { + clean_cg_data_insn(v); + } + } +} + +static void liveness_analysis(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ptrset M; + INIT_PTRSET_DEF(&M); + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *v; + list_for_each_entry(v, &bb->ir_insn_head, list_ptr) { + struct ir_insn_cg_extra *extra = insn_cg(v); + + if (extra->dst && !extra->finalized) { + DBGASSERT(extra->dst == v); + // Note. Assume pre-colored register VR has no users + // dst is a VR + bpf_ir_ptrset_insert(env, + &cg_info(fun)->all_var, v); + + bpf_ir_ptrset_clean(&M); + struct ir_insn **pos; + array_for(pos, v->users) + { + struct ir_insn *s = *pos; + if (s->op == IR_INSN_PHI) { + struct phi_value *pos2; + bool found = false; + array_for(pos2, s->phi) + { + if (pos2->value.type == + IR_VALUE_INSN && + pos2->value.data.insn_d == + v) { + found = true; + live_out_at_block( + env, + fun, &M, + pos2->bb, + v); + } + } + if (!found) { + CRITICAL( + "Not found user!"); + } + } else { + live_in_at_statement(env, fun, + &M, s, v); + } + } + } + } + } + bpf_ir_ptrset_free(&M); + + print_ir_prog_cg_dst_liveness(env, fun, "Liveness"); +} + +static void caller_constraint(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *insn) +{ + for (u8 i = BPF_REG_0; i < BPF_REG_6; ++i) { + // R0-R5 are caller saved register + make_conflict(env, fun, cg_info(fun)->regs[i], insn); + } +} + +static void conflict_analysis(struct bpf_ir_env *env, struct ir_function *fun) +{ + // Add constraints to the graph + + for (u8 i = 0; i < RA_COLORS; ++i) { + for (u8 j = i + 1; j < RA_COLORS; ++j) { + // All physical registers are conflicting + make_conflict(env, fun, cg_info(fun)->regs[i], + cg_info(fun)->regs[j]); + } + } + + struct ir_basic_block **pos; + // For each BB + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + // For each operation + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + struct ir_insn_cg_extra *insn_cg = insn->user_data; + + if (insn->op == IR_INSN_PHI) { + // v conflicts with all its predecessors' LIVEOUT + struct phi_value *pos2; + array_for(pos2, insn->phi) + { + phi_conflict_at_block_no_propagate( + env, fun, pos2->bb, insn); + } + } + + if (insn->op == IR_INSN_CALL) { + // Add caller saved register constraints + struct ir_insn **pos2; + ptrset_for(pos2, insn_cg->in) + { + struct ir_insn **pos3; + ptrset_for(pos3, insn_cg->out) + { + if (*pos2 == *pos3) { + // Live across CALL! + caller_constraint( + env, fun, + *pos2); + } + } + } + } + if (bpf_ir_is_bin_alu(insn)) { + // a = ALU b c + if (insn->values[1].type == IR_VALUE_INSN) { + make_conflict( + env, fun, insn, + insn->values[1].data.insn_d); + } + } + } + } +} + +// Maximum cardinality search +static void mcs(struct bpf_ir_env *env, struct ir_function *fun) +{ + PRINT_LOG_DEBUG(env, "SEO: "); + struct array *sigma = &cg_info(fun)->seo; + bpf_ir_array_clear(env, sigma); + struct ptrset allvar; + bpf_ir_ptrset_clone(env, &allvar, &cg_info(fun)->all_var); + for (size_t i = 0; i < cg_info(fun)->all_var.cnt; ++i) { + u32 max_l = 0; + struct ir_insn *max_i = NULL; + struct ir_insn **pos; + ptrset_for(pos, allvar) + { + struct ir_insn_cg_extra *ex = insn_cg(*pos); + if (ex->lambda >= max_l) { + max_l = ex->lambda; + max_i = *pos; + } + } + DBGASSERT(max_i != NULL); + bpf_ir_array_push(env, sigma, &max_i); + print_insn_ptr_base(env, max_i); + PRINT_LOG_DEBUG(env, " "); + + struct ir_insn_cg_extra *max_iex = insn_cg(max_i); + ptrset_for(pos, max_iex->adj) + { + if (bpf_ir_ptrset_exists(&allvar, *pos)) { + // *pos in allvar /\ N(max_i) + insn_cg(*pos)->lambda++; + } + } + + bpf_ir_ptrset_delete(&allvar, max_i); + } + + bpf_ir_ptrset_free(&allvar); + PRINT_LOG_DEBUG(env, "\n"); +} + +static struct ptrset *maxcl_need_spill(struct array *eps) +{ + struct ptrset *pos; + array_for(pos, (*eps)) + { + if (pos->cnt > RA_COLORS) { + return pos; + } + } + return NULL; +} + +struct array pre_spill(struct bpf_ir_env *env, struct ir_function *fun) +{ + // First run maximalCl + mcs(env, fun); + struct array sigma = cg_info(fun)->seo; + struct array eps; + INIT_ARRAY(&eps, struct ptrset); + PRINT_LOG_DEBUG(env, "MaxCL:\n"); + for (size_t i = 0; i < sigma.num_elem; ++i) { + PRINT_LOG_DEBUG(env, "%d: ", i); + struct ir_insn *v = *array_get(&sigma, i, struct ir_insn *); + struct ir_insn_cg_extra *vex = insn_cg(v); + struct ptrset q; + INIT_PTRSET_DEF(&q); + bpf_ir_ptrset_insert(env, &q, v); + print_insn_ptr_base(env, v); + PRINT_LOG_DEBUG(env, " "); + vex->w++; + struct ir_insn **pos; + ptrset_for(pos, vex->adj) + { + struct ir_insn *u = *pos; + + for (size_t j = 0; j < i; ++j) { + struct ir_insn *v2 = + *array_get(&sigma, j, struct ir_insn *); + if (v2 == u) { + bpf_ir_ptrset_insert(env, &q, u); + print_insn_ptr_base(env, u); + PRINT_LOG_DEBUG(env, " "); + insn_cg(u)->w++; + break; + } + } + } + PRINT_LOG_DEBUG(env, "\n"); + bpf_ir_array_push(env, &eps, &q); + } + + PRINT_LOG_DEBUG(env, "To Spill:\n"); + struct ptrset *cur; + struct array to_spill; + INIT_ARRAY(&to_spill, struct ir_insn *); + while ((cur = maxcl_need_spill(&eps))) { + // cur has more than RA_COLORS nodes + u32 max_w = 0; + struct ir_insn *max_i = NULL; + + struct ir_insn **pos; + ptrset_for(pos, (*cur)) + { + struct ir_insn *v = *pos; + struct ir_insn_cg_extra *vex = insn_cg(v); + if (vex->w >= max_w && !vex->nonvr) { + // Must be a vr to be spilled + max_w = vex->w; + max_i = v; + } + } + DBGASSERT(max_i != NULL); + // Spill max_i + bpf_ir_array_push(env, &to_spill, &max_i); + + PRINT_LOG_DEBUG(env, " "); + print_insn_ptr_base(env, max_i); + + struct ptrset *pos2; + array_for(pos2, eps) + { + bpf_ir_ptrset_delete(pos2, max_i); + } + } + + PRINT_LOG_DEBUG(env, "\n"); + struct ptrset *pos; + array_for(pos, eps) + { + bpf_ir_ptrset_free(pos); + } + bpf_ir_array_free(&eps); + return to_spill; +} + +static struct ir_insn *cgir_load_stack(struct bpf_ir_env *env, + struct ir_function *fun, + struct ir_insn *insn, + struct ir_insn *alloc_insn) +{ + DBGASSERT(alloc_insn->op == IR_INSN_ALLOC); + struct ir_insn *tmp = bpf_ir_create_load_insn_cg( + env, insn, bpf_ir_value_insn(alloc_insn), INSERT_FRONT); + tmp->vr_type = alloc_insn->vr_type; + return tmp; +} + +static struct ir_insn *cgir_load_stack_bb_end(struct bpf_ir_env *env, + struct ir_function *fun, + struct ir_basic_block *bb, + struct ir_insn *alloc_insn) +{ + DBGASSERT(alloc_insn->op == IR_INSN_ALLOC); + struct ir_insn *tmp = bpf_ir_create_load_insn_bb_cg( + env, bb, bpf_ir_value_insn(alloc_insn), INSERT_BACK_BEFORE_JMP); + tmp->vr_type = alloc_insn->vr_type; + return tmp; +} + +static void spill_insn(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *insn, struct ir_insn *alloc_insn, + struct ir_insn *v) +{ + // INSN is spilled on stack + if (insn->op == IR_INSN_STORE && + bpf_ir_value_equal(insn->values[0], bpf_ir_value_insn(insn))) { + // store INSN xxx + } else if (insn->op == IR_INSN_LOAD && + bpf_ir_value_equal(insn->values[0], + bpf_ir_value_insn(insn))) { + // load INSN + } else if (insn->op == IR_INSN_PHI) { + struct phi_value *val; + array_for(val, insn->phi) + { + if (val->value.type == IR_VALUE_INSN && + val->value.data.insn_d == v) { + // val uses v, spill it + struct ir_insn *spilled_load = + cgir_load_stack_bb_end( + env, fun, val->bb, alloc_insn); + bpf_ir_change_value( + env, insn, &val->value, + bpf_ir_value_insn(spilled_load)); + } + } + } else { + // General case + struct ir_insn *spilled_load = + cgir_load_stack(env, fun, insn, alloc_insn); + + struct array uses = bpf_ir_get_operands(env, insn); + struct ir_value **pos; + + array_for(pos, uses) + { + struct ir_value *val = *pos; + if (val->type == IR_VALUE_INSN && + val->data.insn_d == v) { + // val uses v, spill it + bpf_ir_change_value( + env, insn, val, + bpf_ir_value_insn(spilled_load)); + } + } + + bpf_ir_array_free(&uses); + } + CHECK_ERR(); +} + +static void spill(struct bpf_ir_env *env, struct ir_function *fun, + struct array *to_spill) +{ + struct ir_insn **pos; + array_for(pos, (*to_spill)) + { + struct ir_insn *v = *pos; + + // v = ... + // ==> + // %1 = alloc + // .. + // %tmp = ... + // store %1, %tmp + + struct ir_insn *alloc_insn; + + DBGASSERT(v->op != IR_INSN_CALL); + DBGASSERT(v->op != IR_INSN_ALLOCARRAY); + + // First clone a copy of users + struct array users; + bpf_ir_array_clone(env, &users, &v->users); + + if (v->op == IR_INSN_ALLOC) { + // spill load and store instruction + alloc_insn = v; + } else { + alloc_insn = bpf_ir_create_alloc_insn_bb_cg( + env, fun->entry, IR_VR_TYPE_64, + INSERT_FRONT_AFTER_PHI); + + struct ir_insn *store_insn = + bpf_ir_create_store_insn_cg( + env, v, alloc_insn, + bpf_ir_value_insn(v), INSERT_BACK); + DBGASSERT(insn_dst(store_insn) == NULL); + } + + // Finalize stack spilled value + // so that it will not change in next iteration + insn_cg(alloc_insn)->finalized = true; + insn_cg(alloc_insn)->vr_pos.allocated = true; + insn_cg(alloc_insn)->vr_pos.spilled = get_new_spill(fun, 8); + insn_cg(alloc_insn)->vr_pos.spilled_size = 8; + + // Spill every user of v (spill-everywhere algorithm) + // If v is an alloc, we do not need to spill it + // because it is already spilled + if (v->op != IR_INSN_ALLOC) { + struct ir_insn **pos2; + array_for(pos2, users) + { + spill_insn(env, fun, *pos2, alloc_insn, v); + CHECK_ERR(); + } + } + + bpf_ir_array_free(&users); + } +} + +static void coloring(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct array sigma = cg_info(fun)->seo; + struct ir_insn **pos; + + array_for(pos, sigma) + { + struct ir_insn *v = *pos; + struct ir_insn_cg_extra *vex = insn_cg(v); + if (vex->vr_pos.allocated) { + continue; + } + + bool used_reg[RA_COLORS] = { 0 }; + struct ir_insn **pos2; + ptrset_for(pos2, vex->adj) + { + struct ir_insn *insn2 = *pos2; // Adj instruction + struct ir_insn_cg_extra *extra2 = insn_cg(insn2); + if (extra2->vr_pos.allocated && + extra2->vr_pos.spilled == 0) { + used_reg[extra2->vr_pos.alloc_reg] = true; + } + } + + for (u8 i = 0; i < RA_COLORS; i++) { + if (!used_reg[i]) { + vex->vr_pos.allocated = true; + vex->vr_pos.alloc_reg = i; + break; + } + } + if (!vex->vr_pos.allocated) { + RAISE_ERROR("No register available"); + } + } +} + +// static bool has_conflict(struct ir_insn *v1, struct ir_insn *v2) +// { +// return bpf_ir_ptrset_exists(&insn_cg(v1)->adj, v2); +// } + +static void coalesce(struct ir_insn *v1, struct ir_insn *v2) +{ + struct ir_insn_cg_extra *v1e = insn_cg(v1); + struct ir_insn_cg_extra *v2e = insn_cg(v2); + if (v1e->vr_pos.spilled == 0 && v2e->vr_pos.spilled == 0 && + v2e->vr_pos.alloc_reg != v1e->vr_pos.alloc_reg) { + // Coalesce + u8 used_colors[RA_COLORS] = { 0 }; + struct ir_insn **pos2; + ptrset_for(pos2, v1e->adj) // v1's adj + { + struct ir_insn *c = *pos2; + struct ir_insn_cg_extra *cex = insn_cg(c); + DBGASSERT(cex->vr_pos.allocated); + if (cex->vr_pos.spilled == 0) { + used_colors[cex->vr_pos.alloc_reg] = true; + } + } + + ptrset_for(pos2, v2e->adj) // v2's adj + { + struct ir_insn *c = *pos2; + struct ir_insn_cg_extra *cex = insn_cg(c); + DBGASSERT(cex->vr_pos.allocated); + if (cex->vr_pos.spilled == 0) { + used_colors[cex->vr_pos.alloc_reg] = true; + } + } + + // There are three cases + // 1. Rx = %y + // 2. %x = Ry + // 3. %x = %y + + if (v1e->finalized) { + if (!used_colors[v1e->vr_pos.alloc_reg]) { + // Able to merge + v2e->vr_pos.alloc_reg = v1e->vr_pos.alloc_reg; + } + } else if (v2e->finalized) { + if (!used_colors[v2e->vr_pos.alloc_reg]) { + v1e->vr_pos.alloc_reg = v2e->vr_pos.alloc_reg; + } + } else { + bool has_unused_color = false; + u8 ureg = 0; + for (u8 i = 0; i < RA_COLORS; ++i) { + if (!used_colors[i]) { + has_unused_color = true; + ureg = i; + break; + } + } + if (has_unused_color) { + v1e->vr_pos.alloc_reg = ureg; + v2e->vr_pos.alloc_reg = ureg; + } + } + } +} + +// Best effort coalescing +static void coalescing(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *v; + list_for_each_entry(v, &bb->ir_insn_head, list_ptr) { + struct ir_insn *v1 = v; + struct ir_insn *v2 = NULL; + // v1 = v2 + if (v1->op == IR_INSN_ASSIGN) { + if (v1->values[0].type != IR_VALUE_INSN) { + continue; + } + v2 = v1->values[0].data.insn_d; + coalesce(v1, v2); + } else if (v1->op == IR_INSN_STORE) { + // store v[0], v[1] + DBGASSERT(v1->values[0].type == IR_VALUE_INSN); + DBGASSERT(v1->values[0].data.insn_d->op == + IR_INSN_ALLOC); + if (v1->values[1].type != IR_VALUE_INSN) { + continue; + } + v2 = v1->values[1].data.insn_d; + v1 = v1->values[0].data.insn_d; + coalesce(v1, v2); + } else if (v1->op == IR_INSN_LOAD) { + // v = load val[0] + DBGASSERT(v1->values[0].type == IR_VALUE_INSN); + DBGASSERT(v1->values[0].data.insn_d->op == + IR_INSN_ALLOC); + v2 = v1->values[0].data.insn_d; + coalesce(v1, v2); + } + CHECK_ERR(); + } + } +} + +static void add_stack_offset(struct bpf_ir_env *env, struct ir_function *fun, + s16 offset) +{ + struct ir_basic_block **pos; + // For each BB + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + // For each operation + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_LOADRAW || + insn->op == IR_INSN_STORERAW) { + if (insn->addr_val.offset_type == + IR_VALUE_CONSTANT_RAWOFF) { + insn->addr_val.offset += offset; + insn->addr_val.offset_type = + IR_VALUE_CONSTANT; + continue; + } else if (insn->addr_val.offset_type == + IR_VALUE_CONSTANT_RAWOFF_REV) { + insn->addr_val.offset -= offset; + insn->addr_val.offset_type = + IR_VALUE_CONSTANT; + continue; + } + } + struct array value_uses = + bpf_ir_get_operands(env, insn); + struct ir_value **pos2; + array_for(pos2, value_uses) + { + struct ir_value *val = *pos2; + if (val->type == IR_VALUE_CONSTANT_RAWOFF) { + // Stack pointer as value + val->data.constant_d += offset; + val->type = IR_VALUE_CONSTANT; + } else if (val->type == + IR_VALUE_CONSTANT_RAWOFF_REV) { + val->data.constant_d -= offset; + val->type = IR_VALUE_CONSTANT; + } + } + bpf_ir_array_free(&value_uses); + } + } +} + +// Remove PHI insn +// Move out from SSA form +static void remove_phi(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct array phi_insns; + INIT_ARRAY(&phi_insns, struct ir_insn *); + + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_PHI) { + DBGASSERT(insn_dst(insn) == insn); + // Phi cannot be spilled + DBGASSERT(insn_cg(insn)->vr_pos.spilled == 0); + bpf_ir_array_push(env, &phi_insns, &insn); + } else { + break; + } + } + } + + struct ir_insn **pos2; + array_for(pos2, phi_insns) + { + struct ir_insn *insn = *pos2; + + struct ir_vr_pos vrpos = insn_cg(insn)->vr_pos; + + struct phi_value *pos3; + array_for(pos3, insn->phi) + { + struct ir_insn *new_insn = + bpf_ir_create_assign_insn_bb_cg( + env, pos3->bb, pos3->value, + INSERT_BACK_BEFORE_JMP); + + insn_cg(new_insn)->vr_pos = vrpos; + + // Remove use + bpf_ir_val_remove_user(pos3->value, insn); + } + + bpf_ir_array_free(&insn->phi); + + bpf_ir_replace_all_usage( + env, insn, + bpf_ir_value_insn(cg_info(fun)->regs[vrpos.alloc_reg])); + erase_insn_cg(env, fun, insn); + } + + bpf_ir_array_free(&phi_insns); +} + +void bpf_ir_compile(struct bpf_ir_env *env, struct ir_function *fun) +{ + u64 starttime = get_cur_time_ns(); + + bpf_ir_run_passes(env, fun, cg_init_passes, + sizeof(cg_init_passes) / sizeof(cg_init_passes[0])); + CHECK_ERR(); + + init_cg(env, fun); + CHECK_ERR(); + + // Debugging settings + cg_info(fun)->spill_callee = 0; + + change_call(env, fun); + CHECK_ERR(); + print_ir_prog_cg(env, fun, "After Change call"); + + change_fun_arg(env, fun); + CHECK_ERR(); + print_ir_prog_cg(env, fun, "After Change fun"); + + spill_array(env, fun); + CHECK_ERR(); + print_ir_prog_cg(env, fun, "After Spill Array"); + + spill_const(env, fun); + CHECK_ERR(); + print_ir_prog_cg(env, fun, "After Spill Const"); + + bpf_ir_cg_prog_check(env, fun); + CHECK_ERR(); + + bool done = false; + u32 iteration = 0; + while (!done) { + if (iteration > 5) { + RAISE_ERROR("Too many iterations"); + } + PRINT_LOG_DEBUG( + env, + "\x1B[32m----- Register allocation iteration %d -----\x1B[0m\n", + iteration); + clean_cg_data(env, fun); + liveness_analysis(env, fun); + print_interference_graph(env, fun); + + print_ir_prog_cg_dst(env, fun, "After liveness"); + + conflict_analysis(env, fun); + print_interference_graph(env, fun); + + struct array to_spill = pre_spill(env, fun); + if (to_spill.num_elem == 0) { + // No need to spill + done = true; + } else { + // spill + spill(env, fun, &to_spill); + bpf_ir_prog_check(env, fun); + CHECK_ERR(); + print_ir_prog_cg_dst(env, fun, "After Spill"); + } + bpf_ir_array_free(&to_spill); + iteration++; + } + + PRINT_LOG_DEBUG(env, "RA finished in %u iterations\n", iteration); + + // Graph coloring + coloring(env, fun); + CHECK_ERR(); + print_ir_prog_cg_alloc(env, fun, "After Coloring"); + + // Coalesce + coalescing(env, fun); + CHECK_ERR(); + print_ir_prog_cg_alloc(env, fun, "After Coalescing"); + + add_stack_offset(env, fun, cg_info(fun)->stack_offset); + + // SSA Out + remove_phi(env, fun); + CHECK_ERR(); + print_ir_prog_cg_alloc(env, fun, "SSA Out"); + + bpf_ir_cg_norm(env, fun); + CHECK_ERR(); + env->cg_time += get_cur_time_ns() - starttime; +} diff --git a/kernel/bpf/ir/ir_cg.h b/kernel/bpf/ir/ir_cg.h new file mode 100644 index 000000000..6d015cd45 --- /dev/null +++ b/kernel/bpf/ir/ir_cg.h @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _IR_CG_H +#define _IR_CG_H + +/* +Functions and structs used internally in the code generator (CG). +*/ + +#include "ir.h" + +// Number of colors available (r0 - r9) +#define RA_COLORS 10 + +struct ir_insn *bpf_ir_create_insn_base_cg(struct bpf_ir_env *env, + struct ir_basic_block *bb, + enum ir_insn_type insn_type); + +struct ir_insn *bpf_ir_create_insn_base_norm(struct bpf_ir_env *env, + struct ir_basic_block *bb, + struct ir_vr_pos dstpos); + +void bpf_ir_erase_insn_norm(struct ir_insn *insn); + +void bpf_ir_init_insn_norm(struct bpf_ir_env *env, struct ir_insn *insn, + struct ir_vr_pos pos); + +void bpf_ir_init_insn_cg(struct bpf_ir_env *env, struct ir_insn *insn); + +void print_ir_flatten(struct bpf_ir_env *env, struct ir_insn *insn); + +struct code_gen_info { + // SEO + struct array seo; + + // All vertex in interference graph + // Set of struct ir_insn* + struct ptrset all_var; + + // BPF Register Virtual Instruction (used as dst) + struct ir_insn *regs[BPF_REG_10]; // Only use R0-R9 + + size_t callee_num; + + // The stack offset + s32 stack_offset; + + // Whether to spill callee saved registers + u8 spill_callee; +}; + +#define cg_info(fun) ((struct code_gen_info *)(fun)->user_data) + +// Extra information needed for code gen +struct ir_bb_cg_extra { + // Position of the first instruction + size_t pos; +}; + +/* Instruction data used after RA (e.g. normalization) */ +struct ir_insn_norm_extra { + struct ir_vr_pos pos; + + // Translated pre_ir_insn + struct pre_ir_insn translated[2]; + + // Translated number + u8 translated_num; +}; + +struct ir_insn_cg_extra { + struct ir_insn *dst; + + // Liveness analysis + struct ptrset in; + struct ptrset out; + + // Adj list in interference graph + struct ptrset adj; + + u32 lambda; // used in MCS + u32 w; // number of maximalCl that has this vertex. used in pre-spill + + // Whether the vr_pos is finalized (pre-colored) + // If not finalized, vr_pos will be cleaned in each iteration + // of RA + bool finalized; + + struct ir_vr_pos vr_pos; + + // Whether this instruction is a non-VR instruction, like a pre-colored register + bool nonvr; +}; + +enum val_type { + UNDEF, + REG, + CONST, + STACK, + STACKOFF, +}; + +#define insn_cg(insn) ((struct ir_insn_cg_extra *)(insn)->user_data) + +#define insn_dst(insn) insn_cg(insn)->dst + +#define insn_norm(insn) ((struct ir_insn_norm_extra *)(insn)->user_data) + +#define bb_cg(bb) ((struct ir_bb_cg_extra *)(bb)->user_data) + +void bpf_ir_cg_prog_check(struct bpf_ir_env *env, struct ir_function *fun); + +void bpf_ir_cg_norm(struct bpf_ir_env *env, struct ir_function *fun); + +void bpf_ir_optimize_ir(struct bpf_ir_env *env, struct ir_function *fun, + void *data); + +void bpf_ir_cg_change_fun_arg(struct bpf_ir_env *env, struct ir_function *fun, + void *param); + +void bpf_ir_cg_change_call_pre_cg(struct bpf_ir_env *env, + struct ir_function *fun, void *param); + +void bpf_ir_cg_add_stack_offset_pre_cg(struct bpf_ir_env *env, + struct ir_function *fun, void *param); + +void bpr_ir_cg_to_cssa(struct bpf_ir_env *env, struct ir_function *fun, + void *param); + +/* +The following functions are instruction constructors only for CG stage. +Other instruction constructors are in bpf_ir.h. +*/ + +/* Instruction Constructors */ + +struct ir_insn *bpf_ir_create_alloc_insn_cg(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + enum ir_vr_type type, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_alloc_insn_bb_cg(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + enum ir_vr_type type, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_loadimmextra_insn_norm( + struct bpf_ir_env *env, struct ir_insn *pos_insn, + struct ir_vr_pos dstpos, enum ir_loadimm_extra_type load_ty, s64 imm, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_loadimmextra_insn_bb_norm( + struct bpf_ir_env *env, struct ir_basic_block *pos_bb, + struct ir_vr_pos dstpos, enum ir_loadimm_extra_type load_ty, s64 imm, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_neg_insn_norm(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_vr_pos dstpos, + enum ir_alu_op_type alu_type, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_neg_insn_bb_norm(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_vr_pos dstpos, + enum ir_alu_op_type alu_type, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_store_insn_cg(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_insn *insn, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_store_insn_bb_cg(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_insn *insn, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_load_insn_cg(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_load_insn_bb_cg(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_value val, + enum insert_position pos); + +struct ir_insn * +bpf_ir_create_bin_insn_norm(struct bpf_ir_env *env, struct ir_insn *pos_insn, + struct ir_vr_pos dstpos, struct ir_value val1, + struct ir_value val2, enum ir_insn_type ty, + enum ir_alu_op_type alu_type, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_bin_insn_bb_norm( + struct bpf_ir_env *env, struct ir_basic_block *pos_bb, + struct ir_vr_pos dstpos, struct ir_value val1, struct ir_value val2, + enum ir_insn_type ty, enum ir_alu_op_type alu_type, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_assign_insn_norm(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_vr_pos dstpos, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_assign_insn_bb_norm(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_vr_pos dstpos, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_assign_insn_cg(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_value val, + enum insert_position pos); + +struct ir_insn *bpf_ir_create_assign_insn_bb_cg(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_value val, + enum insert_position pos); + +/* Instruction Constructors */ + +#endif diff --git a/kernel/bpf/ir/ir_cg_norm.c b/kernel/bpf/ir/ir_cg_norm.c new file mode 100644 index 000000000..d27ad5c83 --- /dev/null +++ b/kernel/bpf/ir/ir_cg_norm.c @@ -0,0 +1,1372 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "ir.h" +#include "ir_cg.h" + +// Normalization + +static void bpf_ir_free_insn_cg(struct ir_insn *insn) +{ + struct ir_insn_cg_extra *extra = insn_cg(insn); + bpf_ir_ptrset_free(&extra->adj); + bpf_ir_ptrset_free(&extra->in); + bpf_ir_ptrset_free(&extra->out); + free_proto(extra); + insn->user_data = NULL; +} + +static enum val_type vtype(struct ir_value val) +{ + if (val.type == IR_VALUE_FLATTEN_DST) { + if (val.data.vr_pos.allocated) { + if (val.data.vr_pos.spilled) { + // WARNING: cannot determine whether it's a stackoff + return STACK; + } else { + return REG; + } + } else { + return UNDEF; + } + } else if (val.type == IR_VALUE_CONSTANT || + val.type == IR_VALUE_CONSTANT_RAWOFF || + val.type == IR_VALUE_CONSTANT_RAWOFF_REV) { + return CONST; + } else { + CRITICAL("No such value type for norm!"); + } +} + +static enum val_type vtype_insn_norm(struct ir_insn *insn) +{ + struct ir_insn_norm_extra *extra = insn_norm(insn); + if (extra->pos.allocated) { + if (extra->pos.spilled) { + // WARNING: cannot determine whether it's a stackoff + return STACK; + } else { + return REG; + } + } else { + return UNDEF; + } +} + +static void remove_all_users(struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + bpf_ir_array_free(&insn->users); + } + } + for (u8 i = 0; i < MAX_FUNC_ARG; ++i) { + bpf_ir_array_free(&fun->function_arg[i]->users); + } + if (fun->sp) { + bpf_ir_array_free(&fun->sp->users); + } + for (u8 i = 0; i < BPF_REG_10; ++i) { + struct ir_insn *insn = cg_info(fun)->regs[i]; + bpf_ir_array_free(&insn->users); + } +} + +// To flatten IR, we first need to change all the values to ir_pos +static void change_all_value_to_ir_pos(struct bpf_ir_env *env, + struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_LOAD) { + struct ir_value *v = &insn->values[0]; + DBGASSERT(v->type == IR_VALUE_INSN); + DBGASSERT(v->data.insn_d->op == IR_INSN_ALLOC); + insn->vr_type = v->data.insn_d->vr_type; + } + if (insn->op == IR_INSN_STORE) { + struct ir_value *v = &insn->values[0]; + DBGASSERT(v->type == IR_VALUE_INSN); + DBGASSERT(v->data.insn_d->op == IR_INSN_ALLOC); + insn->vr_type = v->data.insn_d->vr_type; + } + struct array operands = bpf_ir_get_operands(env, insn); + struct ir_value **pos2; + array_for(pos2, operands) + { + struct ir_value *v = *pos2; + if (v->type == IR_VALUE_INSN) { + struct ir_insn *insn_d = v->data.insn_d; + struct ir_insn *dst = insn_dst(insn_d); + DBGASSERT(insn_d == dst); + struct ir_insn_cg_extra *extra = + insn_cg(dst); + v->type = IR_VALUE_FLATTEN_DST; + v->data.vr_pos = extra->vr_pos; + } + } + } + } +} + +// Free CG resources, create a new extra data for flattening +static void cg_to_flatten(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos = NULL; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn = NULL; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + struct ir_vr_pos pos; + struct ir_insn_cg_extra *insn_extra = insn_cg(insn); + if (!insn_extra->dst) { + pos.allocated = false; + } else { + struct ir_insn_cg_extra *dst_extra = + insn_cg(insn_extra->dst); + pos = dst_extra->vr_pos; + } + insn_cg(insn)->vr_pos = pos; + } + } + + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn = NULL; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + struct ir_insn_cg_extra *extra = insn_cg(insn); + struct ir_vr_pos pos = extra->vr_pos; + bpf_ir_free_insn_cg(insn); + SAFE_MALLOC(insn->user_data, + sizeof(struct ir_insn_norm_extra)); + insn_norm(insn)->pos = pos; + } + } + + for (u8 i = 0; i < BPF_REG_10; ++i) { + struct ir_insn *insn = cg_info(fun)->regs[i]; + bpf_ir_free_insn_cg(insn); + } + bpf_ir_free_insn_cg(fun->sp); +} + +static void cgir_load_stack_to_reg_norm(struct bpf_ir_env *env, + struct ir_insn *insn, + struct ir_value *val, + enum ir_vr_type vtype, + struct ir_vr_pos reg) +{ + struct ir_insn *tmp = bpf_ir_create_assign_insn_norm( + env, insn, reg, *val, INSERT_FRONT); + tmp->vr_type = vtype; + + *val = bpf_ir_value_vrpos(reg); +} + +/* Flatten IR */ +static void flatten_ir(struct bpf_ir_env *env, struct ir_function *fun) +{ + // Make sure no users + remove_all_users(fun); + change_all_value_to_ir_pos(env, fun); + CHECK_ERR(); + cg_to_flatten(env, fun); + CHECK_ERR(); +} + +/* Loading constant used in normalization */ +static struct ir_insn *normalize_load_const(struct bpf_ir_env *env, + struct ir_insn *insn, + struct ir_value *val, + struct ir_vr_pos dst) +{ + struct ir_insn *new_insn = NULL; + if (val->const_type == IR_ALU_32) { + new_insn = bpf_ir_create_assign_insn_norm(env, insn, dst, *val, + INSERT_FRONT); + new_insn->alu_op = IR_ALU_64; + } else { + new_insn = bpf_ir_create_loadimmextra_insn_norm( + env, insn, dst, IR_LOADIMM_IMM64, val->data.constant_d, + INSERT_FRONT); + new_insn->vr_type = IR_VR_TYPE_64; + } + *val = bpf_ir_value_vrpos(dst); + return new_insn; +} + +static void normalize_assign(struct ir_insn *insn) +{ + struct ir_value *v0 = &insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + struct ir_vr_pos dst_pos = insn_norm(insn)->pos; + // stack = reg + // stack = const32 + // reg = const32 + // reg = const64 + // reg = stack + // reg = reg + if (tdst == STACK) { + DBGASSERT(t0 != STACK); + // Change to STORERAW + insn->op = IR_INSN_STORERAW; + + insn->addr_val.value = bpf_ir_value_norm_stack_ptr(); + insn->addr_val.offset = dst_pos.spilled; + insn->vr_type = + IR_VR_TYPE_64; // TODO: Should be 64 before normalize + } else { + if (t0 == STACK) { + // Change to LOADRAW + insn->op = IR_INSN_LOADRAW; + insn->addr_val.value = bpf_ir_value_norm_stack_ptr(); + insn->addr_val.offset = v0->data.vr_pos.spilled; + } + if (t0 == CONST && v0->const_type == IR_ALU_64) { + // 64 imm load + insn->op = IR_INSN_LOADIMM_EXTRA; + insn->imm_extra_type = IR_LOADIMM_IMM64; + insn->imm64 = v0->data.constant_d; + } + } + if (tdst == REG && t0 == REG) { + if (dst_pos.alloc_reg == v0->data.vr_pos.alloc_reg) { + // The same, erase this instruction + bpf_ir_erase_insn_norm(insn); + } + } +} + +static void normalize_cond_jmp(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_value *v0 = &insn->values[0]; + struct ir_value *v1 = &insn->values[1]; + enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; + + if (t0 == CONST) { + // jmp const reg + if (t1 == CONST) { + if (insn->op == IR_INSN_JNE) { + if (v0->data.constant_d != + v1->data.constant_d) { + // Jump + insn->op = IR_INSN_JA; + insn->value_num = 0; + insn->bb1 = + insn->bb2; // Jump to the next + insn->bb2 = NULL; + } else { + // No jump + bpf_ir_erase_insn_norm(insn); + } + } else { + RAISE_ERROR( + "conditional jmp requires at least one variable"); + } + return; + } + if (insn->op == IR_INSN_JGT) { + insn->op = IR_INSN_JLT; + } else if (insn->op == IR_INSN_JEQ) { + } else if (insn->op == IR_INSN_JNE) { + } else if (insn->op == IR_INSN_JLT) { + insn->op = IR_INSN_JGT; + } else if (insn->op == IR_INSN_JGE) { + insn->op = IR_INSN_JLE; + } else if (insn->op == IR_INSN_JLE) { + insn->op = IR_INSN_JGE; + } else if (insn->op == IR_INSN_JSGE) { + insn->op = IR_INSN_JSLE; + } else if (insn->op == IR_INSN_JSLE) { + insn->op = IR_INSN_JSGE; + } else if (insn->op == IR_INSN_JSGT) { + insn->op = IR_INSN_JSLT; + } else if (insn->op == IR_INSN_JSLT) { + insn->op = IR_INSN_JSGT; + } else { + RAISE_ERROR("unknown conditional jmp operation"); + } + struct ir_value tmp = *v0; + *v0 = *v1; + *v1 = tmp; + } +} + +/* Normalize ALU */ +static void normalize_alu(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_value *v0 = &insn->values[0]; + struct ir_value *v1 = &insn->values[1]; + enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + DBGASSERT(tdst == REG); + struct ir_vr_pos dst_pos = insn_norm(insn)->pos; + if (t1 == REG) { + if (dst_pos.alloc_reg == v1->data.vr_pos.alloc_reg) { + if (bpf_ir_is_commutative_alu(insn)) { + // Switch + struct ir_value tmp = *v1; + *v1 = *v0; + *v0 = tmp; + enum val_type tmp2 = t1; + t1 = t0; + t0 = tmp2; + } else if (insn->op == IR_INSN_SUB) { + // reg1 = sub XX reg1 + // ==> + // reg1 = -reg1 + // reg1 = add reg1 XX + bpf_ir_create_neg_insn_norm(env, insn, dst_pos, + IR_ALU_64, *v1, + INSERT_FRONT); + insn->op = IR_INSN_ADD; + struct ir_value tmp = *v1; + *v1 = *v0; + *v0 = tmp; + enum val_type tmp2 = t1; + t1 = t0; + t0 = tmp2; + } else { + print_raw_ir_insn(env, insn); + RAISE_ERROR( + "non-commutative ALU op not supported yet"); + } + } + } + if (t0 == CONST) { + DBGASSERT(v0->const_type == IR_ALU_32); + } + if (t1 == CONST) { + DBGASSERT(v1->const_type == IR_ALU_32); + } + // Binary ALU + if (t0 == STACK && t1 == CONST) { + // reg1 = add stack const + // ==> + // reg1 = stack + // reg1 = add reg1 const + struct ir_insn *new_insn = bpf_ir_create_assign_insn_norm( + env, insn, dst_pos, *v0, INSERT_FRONT); + new_insn->vr_type = IR_VR_TYPE_64; + *v0 = bpf_ir_value_vrpos(dst_pos); + normalize_assign(new_insn); + + } else if (t0 == STACK && t1 == REG) { + // reg1 = add stack reg2 + // ==> + // reg1 = stack + // reg1 = add reg1 reg2 + struct ir_insn *new_insn = bpf_ir_create_assign_insn_norm( + env, insn, dst_pos, *v0, INSERT_FRONT); + new_insn->vr_type = IR_VR_TYPE_64; + *v0 = bpf_ir_value_vrpos(dst_pos); + normalize_assign(new_insn); + } else if (t0 == REG && t1 == REG) { + // reg1 = add reg2 reg3 + u8 reg1 = dst_pos.alloc_reg; + u8 reg2 = v0->data.vr_pos.alloc_reg; + if (reg1 != reg2) { + // reg1 = add reg2 reg3 + // ==> + // reg1 = reg2 + // reg1 = add reg1 reg3 + bpf_ir_create_assign_insn_norm(env, insn, dst_pos, *v0, + INSERT_FRONT); + // DBGASSERT(dst_insn == + // cg_info(fun)->regs[reg1]); // Fixed reg? + // TODO: Investigate here, why did I write this check? + *v0 = bpf_ir_value_vrpos(dst_pos); + } + } else if (t0 == REG && t1 == CONST) { + if (v0->data.vr_pos.alloc_reg != dst_pos.alloc_reg) { + // reg1 = add reg2 const + // ==> + // reg1 = reg2 + // reg1 = add reg1 const + bpf_ir_create_assign_insn_norm(env, insn, dst_pos, *v0, + INSERT_FRONT); + *v0 = bpf_ir_value_vrpos(dst_pos); + } + } else if (t0 == CONST && t1 == CONST) { + DBGASSERT(v1->const_type == IR_ALU_32); + normalize_load_const(env, insn, v0, dst_pos); + } else if (t0 == CONST && t1 == REG) { + // reg1 = add const reg2 + // ==> + // reg1 = const + // reg1 = add reg1 reg2 + normalize_load_const(env, insn, v0, dst_pos); + + } else { + CRITICAL_DUMP(env, "Error"); + } +} + +static void normalize_getelemptr(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_value *v0 = &insn->values[0]; + struct ir_value *v1 = &insn->values[1]; + enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; + + DBGASSERT(t1 == STACK); + struct ir_vr_pos dstpos = insn_norm(insn)->pos; + DBGASSERT(dstpos.allocated && dstpos.spilled == 0); // dst must be reg + u8 dstreg = dstpos.alloc_reg; + struct ir_vr_pos v1pos = v1->data.vr_pos; + s32 spill_pos = v1pos.spilled; + insn->op = IR_INSN_ADD; + insn->alu_op = IR_ALU_64; + if (t0 == CONST) { + // reg = getelemptr const ptr + // ==> + // reg = r10 + (const + spill_pos) + DBGASSERT(v0->const_type == IR_ALU_32); + *v0 = bpf_ir_value_norm_stack_ptr(); + s64 tmp = v0->data.constant_d + spill_pos; // Assume no overflow + *v1 = bpf_ir_value_const32(tmp); + normalize_alu(env, insn); + } + if (t0 == REG) { + u8 v0reg = v0->data.vr_pos.alloc_reg; + *v1 = bpf_ir_value_const32(spill_pos); + if (v0reg == dstreg) { + // reg = getelemptr reg ptr + // ==> + // reg += r10 + // reg += spill_pos + *v0 = bpf_ir_value_vrpos(dstpos); + bpf_ir_create_bin_insn_norm( + env, insn, dstpos, bpf_ir_value_vrpos(dstpos), + bpf_ir_value_norm_stack_ptr(), IR_INSN_ADD, + IR_ALU_64, INSERT_FRONT); + } else { + // reg1 = getelemptr reg2 ptr + // ==> + // reg1 = reg2 + // reg1 += r10 + // reg1 += spill_pos + bpf_ir_create_assign_insn_norm(env, insn, dstpos, *v0, + INSERT_FRONT); + bpf_ir_create_bin_insn_norm( + env, insn, dstpos, bpf_ir_value_vrpos(dstpos), + bpf_ir_value_norm_stack_ptr(), IR_INSN_ADD, + IR_ALU_64, INSERT_FRONT); + *v0 = bpf_ir_value_vrpos(dstpos); + } + } +} + +static void normalize_store(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_value *v0 = &insn->values[0]; + struct ir_value *v1 = &insn->values[1]; + // store v0, v1 + // ==> + // v0 = v1 + insn->op = IR_INSN_ASSIGN; + insn_norm(insn)->pos = v0->data.vr_pos; + *v0 = *v1; + insn->value_num = 1; + normalize_assign(insn); +} + +static void normalize_load(struct bpf_ir_env *env, struct ir_insn *insn) +{ + // struct ir_value *v0 = &insn->values[0]; + // enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + // enum val_type tdst = vtype_insn_norm(insn); + // reg1 = load reg2 + // ==> + // reg1 = reg2 + insn->op = IR_INSN_ASSIGN; + normalize_assign(insn); +} + +static void normalize_stackoff(struct ir_insn *insn) +{ + // Could be storeraw or loadraw + // Stack already shifted + struct ir_value addrval = insn->addr_val.value; + enum val_type addr_ty = vtype(addrval); + // storeraw STACKOFF ? + // ==> + // storeraw r10 ? + if (addr_ty == STACK) { + insn->addr_val.offset += addrval.data.vr_pos.spilled; + insn->addr_val.value = bpf_ir_value_norm_stack_ptr(); + } +} + +static void normalize_neg(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_value *v0 = &insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + DBGASSERT(tdst == REG); + struct ir_vr_pos dst_pos = insn_norm(insn)->pos; + // reg = neg reg ==> OK! + if (t0 == REG && v0->data.vr_pos.alloc_reg != dst_pos.alloc_reg) { + // reg1 = neg reg2 + // ==> + // reg1 = reg2 + // reg1 = neg reg1 + bpf_ir_create_assign_insn_norm(env, insn, dst_pos, *v0, + INSERT_FRONT); + *v0 = bpf_ir_value_vrpos(dst_pos); + } + if (t0 == CONST) { + // reg = neg const + RAISE_ERROR("Not supported"); + } else if (t0 == STACK) { + // reg = neg stack + // ==> + // reg = stack + // reg = neg reg + cgir_load_stack_to_reg_norm(env, insn, v0, IR_VR_TYPE_64, + dst_pos); + } +} + +static void normalize_end(struct bpf_ir_env *env, struct ir_insn *insn) +{ + struct ir_value *v0 = &insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + DBGASSERT(tdst == REG); + struct ir_vr_pos dst_pos = insn_norm(insn)->pos; + // reg = end reg + if (t0 == REG && v0->data.vr_pos.alloc_reg != dst_pos.alloc_reg) { + // reg1 = end reg2 + // ==> + // reg1 = reg2 + // reg1 = end reg1 + bpf_ir_create_assign_insn_norm(env, insn, dst_pos, *v0, + INSERT_FRONT); + *v0 = bpf_ir_value_vrpos(dst_pos); + } + // reg = neg const ==> Not supported + if (t0 == CONST) { + RAISE_ERROR("Not supported"); + } else if (t0 == STACK) { + // reg = end stack + // ==> + // reg = stack + // reg = end reg + cgir_load_stack_to_reg_norm(env, insn, v0, IR_VR_TYPE_64, + dst_pos); + } +} + +static void normalize_ret(struct bpf_ir_env *env, struct ir_insn *insn) +{ + if (insn->value_num == 0) { + return; + } + struct ir_value *v0 = &insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; + // ret REG + // ==> + // R0 = REG + // ret + DBGASSERT(t0 == REG || t0 == CONST); + struct ir_vr_pos pos = (struct ir_vr_pos){ .allocated = true, + .alloc_reg = BPF_REG_0, + .spilled = 0 }; + struct ir_insn *new_insn = bpf_ir_create_assign_insn_norm( + env, insn, pos, *v0, INSERT_FRONT); + new_insn->vr_type = IR_VR_TYPE_64; + insn->value_num = 0; +} + +static void normalize(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn, *tmp; + list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, + list_ptr) { + if (insn->op == IR_INSN_ALLOC) { + // OK + } else if (insn->op == IR_INSN_ALLOCARRAY) { + // OK + } else if (insn->op == IR_INSN_GETELEMPTR) { + normalize_getelemptr(env, insn); + } else if (insn->op == IR_INSN_STORE) { + normalize_store(env, insn); + } else if (insn->op == IR_INSN_LOAD) { + normalize_load(env, insn); + } else if (insn->op == IR_INSN_LOADRAW) { + normalize_stackoff(insn); + } else if (insn->op == IR_INSN_LOADIMM_EXTRA) { + // OK + } else if (insn->op == IR_INSN_STORERAW) { + normalize_stackoff(insn); + } else if (insn->op == IR_INSN_NEG) { + normalize_neg(env, insn); + } else if (insn->op == IR_INSN_HTOBE || + insn->op == IR_INSN_HTOLE) { + normalize_end(env, insn); + } else if (bpf_ir_is_bin_alu(insn)) { + normalize_alu(env, insn); + } else if (insn->op == IR_INSN_ASSIGN) { + normalize_assign(insn); + } else if (insn->op == IR_INSN_RET) { + normalize_ret(env, insn); + } else if (insn->op == IR_INSN_CALL) { + // OK + } else if (insn->op == IR_INSN_JA) { + // OK + } else if (bpf_ir_is_cond_jmp(insn)) { + // jmp reg const/reg + // or + // jmp const reg + // ==> + // jmp(REV) reg const + normalize_cond_jmp(env, insn); + } else { + RAISE_ERROR("No such instruction"); + } + CHECK_ERR(); + } + } +} + +static void print_ir_prog_cg_flatten(struct bpf_ir_env *env, + struct ir_function *fun, char *msg) +{ + PRINT_LOG_DEBUG(env, "\x1B[32m----- CG: %s -----\x1B[0m\n", msg); + print_ir_prog_advanced(env, fun, NULL, NULL, print_ir_flatten); +} + +static struct pre_ir_insn translate_reg_to_reg(u8 dst, u8 src) +{ + // MOV dst src + struct pre_ir_insn insn = { 0 }; + insn.opcode = BPF_MOV | BPF_X | BPF_ALU64; + insn.dst_reg = dst; + insn.src_reg = src; + insn.imm = 0; + return insn; +} + +static struct pre_ir_insn translate_const_to_reg(u8 dst, s64 data, + enum ir_alu_op_type type) +{ + // MOV dst imm + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + if (type == IR_ALU_32) { + insn.opcode = BPF_MOV | BPF_K | BPF_ALU; + } else { + // Default is imm64 + insn.opcode = BPF_MOV | BPF_K | BPF_ALU64; + } + insn.imm = data; + return insn; +} + +static int vr_type_to_size(enum ir_vr_type type) +{ + switch (type) { + case IR_VR_TYPE_32: + return BPF_W; + case IR_VR_TYPE_16: + return BPF_H; + case IR_VR_TYPE_8: + return BPF_B; + case IR_VR_TYPE_64: + return BPF_DW; + default: + CRITICAL("Error"); + } +} + +static struct pre_ir_insn load_addr_to_reg(u8 dst, struct ir_address_value addr, + enum ir_vr_type type) +{ + // MOV dst src + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + insn.off = addr.offset; + int size = vr_type_to_size(type); + if (addr.value.type == IR_VALUE_FLATTEN_DST) { + // Must be REG + DBGASSERT(vtype(addr.value) == REG); + // Load reg (addr) to reg + insn.src_reg = addr.value.data.vr_pos.alloc_reg; + insn.opcode = BPF_LDX | size | BPF_MEM; + } else if (addr.value.type == IR_VALUE_CONSTANT) { + // Must be U64 + insn.it = IMM64; + insn.imm64 = addr.value.data.constant_d; + insn.opcode = size; + // Simplify the opcode to reduce compiler warning, the real opcode is as follows + // (but BPF_MM and BPF_LD are all 0) + // insn.opcode = BPF_IMM | size | BPF_LD; + } else { + CRITICAL("Error"); + } + return insn; +} + +static struct pre_ir_insn store_reg_to_reg_mem(u8 dst, u8 src, s16 offset, + enum ir_vr_type type) +{ + struct pre_ir_insn insn = { 0 }; + int size = vr_type_to_size(type); + insn.src_reg = src; + insn.off = offset; + insn.opcode = BPF_STX | size | BPF_MEM; + insn.dst_reg = dst; + return insn; +} + +static struct pre_ir_insn store_const_to_reg_mem(u8 dst, s64 val, s16 offset, + enum ir_vr_type type) +{ + struct pre_ir_insn insn = { 0 }; + int size = vr_type_to_size(type); + insn.it = IMM; + insn.imm = val; + insn.off = offset; + insn.opcode = BPF_ST | size | BPF_MEM; + insn.dst_reg = dst; + return insn; +} + +static int end_code(enum ir_insn_type insn) +{ + if (insn == IR_INSN_HTOBE) { + return BPF_TO_BE; + } else if (insn == IR_INSN_HTOLE) { + return BPF_TO_LE; + } else { + CRITICAL("Error"); + } +} + +static int alu_code(enum ir_insn_type insn) +{ + switch (insn) { + case IR_INSN_NEG: + return BPF_NEG; + case IR_INSN_ADD: + return BPF_ADD; + case IR_INSN_SUB: + return BPF_SUB; + case IR_INSN_MUL: + return BPF_MUL; + case IR_INSN_DIV: + return BPF_DIV; + case IR_INSN_OR: + return BPF_OR; + case IR_INSN_AND: + return BPF_AND; + case IR_INSN_MOD: + return BPF_MOD; + case IR_INSN_XOR: + return BPF_XOR; + case IR_INSN_LSH: + return BPF_LSH; + case IR_INSN_ARSH: + return BPF_ARSH; + case IR_INSN_RSH: + return BPF_RSH; + default: + CRITICAL("Error"); + } +} + +static int jmp_code(enum ir_insn_type insn) +{ + switch (insn) { + case IR_INSN_JA: + return BPF_JA; + case IR_INSN_JEQ: + return BPF_JEQ; + case IR_INSN_JNE: + return BPF_JNE; + case IR_INSN_JLT: + return BPF_JLT; + case IR_INSN_JLE: + return BPF_JLE; + case IR_INSN_JGT: + return BPF_JGT; + case IR_INSN_JGE: + return BPF_JGE; + case IR_INSN_JSGE: + return BPF_JSGE; + case IR_INSN_JSLE: + return BPF_JSLE; + case IR_INSN_JSGT: + return BPF_JSGT; + case IR_INSN_JSLT: + return BPF_JSLT; + default: + CRITICAL("Error"); + } +} + +static struct pre_ir_insn alu_reg(u8 dst, u8 src, enum ir_alu_op_type type, + int opcode) +{ + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + insn.src_reg = src; + int alu_class = type == IR_ALU_64 ? BPF_ALU64 : BPF_ALU; + insn.opcode = opcode | BPF_X | alu_class; + return insn; +} + +static struct pre_ir_insn alu_neg(u8 dst, enum ir_alu_op_type type) +{ + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + int alu_class = type == IR_ALU_64 ? BPF_ALU64 : BPF_ALU; + insn.opcode = BPF_NEG | BPF_K | alu_class; + return insn; +} + +static struct pre_ir_insn alu_end(u8 dst, s32 swap_width, int enty) +{ + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + insn.opcode = enty | BPF_END | BPF_ALU; + insn.imm = swap_width; + return insn; +} + +static struct pre_ir_insn alu_imm(u8 dst, s64 src, enum ir_alu_op_type type, + int opcode) +{ + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + int alu_class = type == IR_ALU_64 ? BPF_ALU64 : BPF_ALU; + insn.it = IMM; + insn.imm = src; + insn.opcode = opcode | BPF_K | alu_class; + return insn; +} + +static struct pre_ir_insn cond_jmp_reg(u8 dst, u8 src, enum ir_alu_op_type type, + int opcode) +{ + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + insn.src_reg = src; + int alu_class = type == IR_ALU_64 ? BPF_JMP : BPF_JMP32; + insn.opcode = opcode | alu_class | BPF_X; + return insn; +} + +static struct pre_ir_insn cond_jmp_imm(u8 dst, s64 src, + enum ir_alu_op_type type, int opcode) +{ + struct pre_ir_insn insn = { 0 }; + insn.dst_reg = dst; + int alu_class = type == IR_ALU_64 ? BPF_JMP : BPF_JMP32; + insn.it = IMM; + insn.imm = src; + insn.opcode = opcode | alu_class | BPF_K; + return insn; +} + +static u8 get_alloc_reg(struct ir_insn *insn) +{ + return insn_norm(insn)->pos.alloc_reg; +} + +static void translate_loadraw(struct ir_insn *insn) +{ + enum val_type tdst = vtype_insn_norm(insn); + struct ir_insn_norm_extra *extra = insn_norm(insn); + DBGASSERT(tdst == REG); + extra->translated[0] = load_addr_to_reg(get_alloc_reg(insn), + insn->addr_val, insn->vr_type); +} + +static void translate_loadimm_extra(struct ir_insn *insn) +{ + enum val_type tdst = vtype_insn_norm(insn); + struct ir_insn_norm_extra *extra = insn_norm(insn); + DBGASSERT(tdst == REG); + extra->translated[0].opcode = BPF_IMM | BPF_LD | BPF_DW; + DBGASSERT(insn->imm_extra_type <= 0x6); + extra->translated[0].src_reg = insn->imm_extra_type; + extra->translated[0].dst_reg = get_alloc_reg(insn); + // 0 2 6 needs next + extra->translated[0].it = IMM64; + extra->translated[0].imm64 = insn->imm64; +} + +static void translate_storeraw(struct ir_insn *insn) +{ + struct ir_value v0 = insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; + struct ir_insn_norm_extra *extra = insn_norm(insn); + // storeraw + if (insn->addr_val.value.type == IR_VALUE_FLATTEN_DST) { + // Store value in (address in the value) + DBGASSERT(vtype(insn->addr_val.value) == REG); + // Store value in the stack + if (t0 == REG) { + extra->translated[0] = store_reg_to_reg_mem( + insn->addr_val.value.data.vr_pos.alloc_reg, + v0.data.vr_pos.alloc_reg, insn->addr_val.offset, + insn->vr_type); + } else if (t0 == CONST) { + extra->translated[0] = store_const_to_reg_mem( + insn->addr_val.value.data.vr_pos.alloc_reg, + v0.data.constant_d, insn->addr_val.offset, + insn->vr_type); + } else { + CRITICAL("Error"); + } + } else { + CRITICAL("Error"); + } +} + +static void translate_alu(struct ir_insn *insn) +{ + struct ir_value v0 = insn->values[0]; + struct ir_value v1 = insn->values[1]; + enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; + enum val_type t1 = insn->value_num >= 2 ? vtype(v1) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + struct ir_insn_norm_extra *extra = insn_norm(insn); + DBGASSERT(tdst == REG); + DBGASSERT(t0 == REG); + DBGASSERT(get_alloc_reg(insn) == v0.data.vr_pos.alloc_reg); + if (t1 == REG) { + extra->translated[0] = + alu_reg(get_alloc_reg(insn), v1.data.vr_pos.alloc_reg, + insn->alu_op, alu_code(insn->op)); + } else if (t1 == CONST) { + // Remove the instruction in some special cases + if (insn->op == IR_INSN_ADD && v1.data.constant_d == 0) { + extra->translated_num = 0; + return; + } + extra->translated[0] = alu_imm(get_alloc_reg(insn), + v1.data.constant_d, insn->alu_op, + alu_code(insn->op)); + } else { + CRITICAL("Error"); + } +} + +static void translate_assign(struct ir_insn *insn) +{ + struct ir_value v0 = insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + struct ir_insn_norm_extra *extra = insn_norm(insn); + + // reg = const (alu) + // reg = reg + if (tdst == REG && t0 == CONST) { + extra->translated[0] = translate_const_to_reg( + get_alloc_reg(insn), v0.data.constant_d, insn->alu_op); + } else if (tdst == REG && t0 == REG) { + if (get_alloc_reg(insn) == v0.data.vr_pos.alloc_reg) { + // Remove the instruction + extra->translated_num = 0; + return; + } + extra->translated[0] = translate_reg_to_reg( + get_alloc_reg(insn), v0.data.vr_pos.alloc_reg); + } else { + CRITICAL("Error"); + } +} + +static void translate_ret(struct ir_insn *insn) +{ + struct ir_insn_norm_extra *extra = insn_norm(insn); + extra->translated[0].opcode = BPF_EXIT | BPF_JMP; +} + +static void translate_call(struct ir_insn *insn) +{ + struct ir_insn_norm_extra *extra = insn_norm(insn); + // Currently only support local helper functions + extra->translated[0].opcode = BPF_CALL | BPF_JMP; + extra->translated[0].it = IMM; + extra->translated[0].imm = insn->fid; +} + +static void translate_ja(struct ir_insn *insn) +{ + struct ir_insn_norm_extra *extra = insn_norm(insn); + extra->translated[0].opcode = BPF_JMP | BPF_JA; +} + +static void translate_neg(struct ir_insn *insn) +{ + struct ir_value v0 = insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + struct ir_insn_norm_extra *extra = insn_norm(insn); + DBGASSERT(tdst == REG && t0 == REG); + DBGASSERT(get_alloc_reg(insn) == v0.data.vr_pos.alloc_reg); + extra->translated[0] = alu_neg(get_alloc_reg(insn), insn->alu_op); +} + +static void translate_end(struct ir_insn *insn) +{ + struct ir_value v0 = insn->values[0]; + enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; + enum val_type tdst = vtype_insn_norm(insn); + struct ir_insn_norm_extra *extra = insn_norm(insn); + DBGASSERT(tdst == REG); + DBGASSERT(t0 == REG); + DBGASSERT(get_alloc_reg(insn) == v0.data.vr_pos.alloc_reg); + extra->translated[0] = alu_end(get_alloc_reg(insn), insn->swap_width, + end_code(insn->op)); +} + +static void translate_cond_jmp(struct ir_insn *insn) +{ + struct ir_value v0 = insn->values[0]; + struct ir_value v1 = insn->values[1]; + enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; + enum val_type t1 = insn->value_num >= 2 ? vtype(v1) : UNDEF; + struct ir_insn_norm_extra *extra = insn_norm(insn); + DBGASSERT(t0 == REG || t1 == REG); + if (t0 == REG) { + if (t1 == REG) { + extra->translated[0] = + cond_jmp_reg(v0.data.vr_pos.alloc_reg, + v1.data.vr_pos.alloc_reg, + insn->alu_op, jmp_code(insn->op)); + } else if (t1 == CONST) { + if (v1.const_type == IR_ALU_64) { + CRITICAL("TODO"); + } + extra->translated[0] = cond_jmp_imm( + v0.data.vr_pos.alloc_reg, v1.data.constant_d, + insn->alu_op, jmp_code(insn->op)); + } else { + CRITICAL("Error"); + } + } else { + DBGASSERT(t0 == CONST); + DBGASSERT(t1 == REG); + CRITICAL("TODO"); + // Probably we could switch? + extra->translated[0] = cond_jmp_imm(v1.data.vr_pos.alloc_reg, + v0.data.constant_d, + insn->alu_op, + jmp_code(insn->op)); + } +} + +static u32 bb_insn_cnt(struct ir_basic_block *bb) +{ + u32 cnt = 0; + struct ir_insn *insn, *tmp; + list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_ALLOC || + insn->op == IR_INSN_ALLOCARRAY) { + continue; + } else { + cnt++; + } + } + return cnt; +} + +static u32 bb_insn_critical_cnt(struct ir_basic_block *bb) +{ + u32 cnt = bb_insn_cnt(bb); + while (bb->preds.num_elem <= 1) { + if (bb->preds.num_elem == 0) { + break; + } + struct ir_basic_block **tmp = + bpf_ir_array_get_void(&bb->preds, 0); + bb = *tmp; + if (bb->flag & IR_BB_HAS_COUNTER) { + break; + } + cnt += bb_insn_cnt(bb); + } + return cnt; +} + +static void replace_builtin_const(struct bpf_ir_env *env, + struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn, *tmp; + list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, + list_ptr) { + struct array operands = bpf_ir_get_operands(env, insn); + struct ir_value **val; + array_for(val, operands) + { + struct ir_value *v = *val; + if (v->type == IR_VALUE_CONSTANT) { + if (v->builtin_const == + IR_BUILTIN_BB_INSN_CNT) { + v->data.constant_d = + bb_insn_cnt(bb); + } + if (v->builtin_const == + IR_BUILTIN_BB_INSN_CRITICAL_CNT) { + v->data.constant_d = + bb_insn_critical_cnt( + bb); + } + } + } + bpf_ir_array_free(&operands); + } + } +} + +static void check_total_insn(struct bpf_ir_env *env, struct ir_function *fun) +{ + u32 cnt = 0; + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn, *tmp; + list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, + list_ptr) { + struct ir_insn_norm_extra *extra = insn_norm(insn); + cnt += extra->translated_num; + } + } + if (cnt >= 1000000) { + RAISE_ERROR("Too many instructions"); + } +} + +static void translate(struct bpf_ir_env *env, struct ir_function *fun) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn, *tmp; + list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, + list_ptr) { + struct ir_insn_norm_extra *extra = insn_norm(insn); + extra->translated_num = 1; // Default: 1 instruction + if (insn->op == IR_INSN_ALLOC) { + // Nothing to do + extra->translated_num = 0; + } else if (insn->op == IR_INSN_ALLOCARRAY) { + // Nothing to do + extra->translated_num = 0; + } else if (insn->op == IR_INSN_STORE) { + CRITICAL("Error"); + } else if (insn->op == IR_INSN_LOAD) { + CRITICAL("Error"); + } else if (insn->op == IR_INSN_GETELEMPTR) { + CRITICAL("Error"); + } else if (insn->op == IR_INSN_LOADRAW) { + translate_loadraw(insn); + } else if (insn->op == IR_INSN_LOADIMM_EXTRA) { + translate_loadimm_extra(insn); + } else if (insn->op == IR_INSN_STORERAW) { + translate_storeraw(insn); + } else if (insn->op == IR_INSN_NEG) { + translate_neg(insn); + } else if (insn->op == IR_INSN_HTOBE || + insn->op == IR_INSN_HTOLE) { + translate_end(insn); + } else if (bpf_ir_is_bin_alu(insn)) { + translate_alu(insn); + } else if (insn->op == IR_INSN_ASSIGN) { + translate_assign(insn); + } else if (insn->op == IR_INSN_RET) { + translate_ret(insn); + } else if (insn->op == IR_INSN_CALL) { + translate_call(insn); + } else if (insn->op == IR_INSN_JA) { + translate_ja(insn); + } else if (bpf_ir_is_cond_jmp(insn)) { + translate_cond_jmp(insn); + } else { + RAISE_ERROR("No such instruction"); + } + } + } +} + +// Relocate BB +static void calc_pos(struct bpf_ir_env *env, struct ir_function *fun) +{ + // Calculate the position of each instruction & BB + size_t ipos = 0; // Instruction position + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_bb_cg_extra *bb_extra = bb->user_data; + bb_extra->pos = ipos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + struct ir_insn_norm_extra *insn_extra = insn_norm(insn); + for (u8 i = 0; i < insn_extra->translated_num; ++i) { + struct pre_ir_insn *translated_insn = + &insn_extra->translated[i]; + // Pos + translated_insn->pos = ipos; + if (translated_insn->it == IMM) { + ipos += 1; + } else { + ipos += 2; + } + } + } + } + env->insn_cnt = ipos; +} + +static void relocate(struct bpf_ir_env *env, struct ir_function *fun) +{ + calc_pos(env, fun); + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + struct ir_insn_norm_extra *insn_extra = insn_norm(insn); + if (insn->op == IR_INSN_JA) { + DBGASSERT(insn_extra->translated_num == 1); + size_t target = bb_cg(insn->bb1)->pos; + insn_extra->translated[0].off = + target - insn_extra->translated[0].pos - + 1; + } + if (bpf_ir_is_cond_jmp(insn)) { + DBGASSERT(insn_extra->translated_num == 1); + size_t target = bb_cg(insn->bb2)->pos; + insn_extra->translated[0].off = + target - insn_extra->translated[0].pos - + 1; + } + } + } +} + +static void synthesize(struct bpf_ir_env *env, struct ir_function *fun) +{ + // The last step, synthesizes the program + SAFE_MALLOC(env->insns, env->insn_cnt * sizeof(struct bpf_insn)); + struct ir_basic_block **pos = NULL; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn = NULL; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + struct ir_insn_norm_extra *extra = insn_norm(insn); + for (u8 i = 0; i < extra->translated_num; ++i) { + struct pre_ir_insn translated_insn = + extra->translated[i]; + // PRINT_DBG("Writing to insn %zu\n", + // translated_insn.pos); + struct bpf_insn *real_insn = + &env->insns[translated_insn.pos]; + real_insn->code = translated_insn.opcode; + real_insn->dst_reg = translated_insn.dst_reg; + real_insn->src_reg = translated_insn.src_reg; + real_insn->off = translated_insn.off; + if (translated_insn.it == IMM) { + real_insn->imm = translated_insn.imm; + } else { + // Wide instruction + struct bpf_insn *real_insn2 = + &env->insns[translated_insn.pos + + 1]; + real_insn->imm = translated_insn.imm64 & + 0xffffffff; + real_insn2->imm = + translated_insn.imm64 >> 32; + } + } + } + } +} + +static void free_cg_final(struct ir_function *fun) +{ + // Free CG resources (after flattening) + + struct ir_basic_block **pos = NULL; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_bb_cg_extra *bb_cg = bb->user_data; + free_proto(bb_cg); + bb->user_data = NULL; + + struct ir_insn *insn = NULL; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + free_proto(insn->user_data); + insn->user_data = NULL; + } + } + for (u8 i = 0; i < BPF_REG_10; ++i) { + struct ir_insn *insn = cg_info(fun)->regs[i]; + bpf_ir_array_free(&insn->users); + free_proto(insn); + } + bpf_ir_array_free(&cg_info(fun)->seo); + bpf_ir_ptrset_free(&cg_info(fun)->all_var); + free_proto(fun->user_data); + fun->user_data = NULL; +} + +void bpf_ir_cg_norm(struct bpf_ir_env *env, struct ir_function *fun) +{ + flatten_ir(env, fun); + CHECK_ERR(); + + print_ir_prog_cg_flatten(env, fun, "Flattening"); + + normalize(env, fun); + CHECK_ERR(); + print_ir_prog_cg_flatten(env, fun, "Normalization"); + + replace_builtin_const(env, fun); + CHECK_ERR(); + + translate(env, fun); + CHECK_ERR(); + + check_total_insn(env, fun); + CHECK_ERR(); + + relocate(env, fun); + CHECK_ERR(); + + synthesize(env, fun); + CHECK_ERR(); + + // Free CG resources + free_cg_final(fun); +} diff --git a/kernel/bpf/ir/ir_code_gen.c b/kernel/bpf/ir/ir_code_gen.c deleted file mode 100644 index a40d1a10a..000000000 --- a/kernel/bpf/ir/ir_code_gen.c +++ /dev/null @@ -1,3127 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include - -static void set_insn_dst(struct bpf_ir_env *env, struct ir_insn *insn, - struct ir_insn *dst) -{ - struct ir_value v = dst ? bpf_ir_value_insn(dst) : bpf_ir_value_undef(); - if (insn_cg(insn)->dst.type == IR_VALUE_INSN) { - // Remove previous user - // Change all users to new dst (used in coalescing) - bpf_ir_replace_all_usage_cg(env, insn, v); - } else { - bpf_ir_val_add_user(env, v, insn); - } - insn_cg(insn)->dst = v; -} - -static void init_cg(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos = NULL; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_bb_cg_extra *bb_cg = NULL; - SAFE_MALLOC(bb_cg, sizeof(struct ir_bb_cg_extra)); - // Empty bb cg - bb->user_data = bb_cg; - - struct ir_insn *insn = NULL; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - bpf_ir_init_insn_cg(env, insn); - CHECK_ERR(); - } - } - - for (u8 i = 0; i < BPF_REG_10; ++i) { - struct ir_insn *insn = fun->cg_info.regs[i]; - bpf_ir_init_insn_cg(env, insn); - CHECK_ERR(); - - struct ir_insn_cg_extra *extra = insn_cg(insn); - extra->alloc_reg = i; - // Pre-colored registers are allocated - extra->allocated = true; - extra->spilled = 0; - extra->spilled_size = 0; - extra->nonvr = true; - } - bpf_ir_init_insn_cg(env, fun->sp); - struct ir_insn_cg_extra *extra = insn_cg(fun->sp); - extra->alloc_reg = 10; - extra->allocated = true; - extra->spilled = 0; - extra->spilled_size = 0; - extra->nonvr = true; -} - -void bpf_ir_free_insn_cg(struct ir_insn *insn) -{ - struct ir_insn_cg_extra *extra = insn_cg(insn); - bpf_ir_array_free(&extra->adj); - bpf_ir_array_free(&extra->gen); - bpf_ir_array_free(&extra->kill); - bpf_ir_array_free(&extra->in); - bpf_ir_array_free(&extra->out); - free_proto(extra); - insn->user_data = NULL; -} - -static void free_cg_res(struct ir_function *fun) -{ - struct ir_basic_block **pos = NULL; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_bb_cg_extra *bb_cg = bb->user_data; - free_proto(bb_cg); - bb->user_data = NULL; - struct ir_insn *insn = NULL; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - bpf_ir_free_insn_cg(insn); - } - } - - for (u8 i = 0; i < BPF_REG_10; ++i) { - struct ir_insn *insn = fun->cg_info.regs[i]; - bpf_ir_free_insn_cg(insn); - } - bpf_ir_free_insn_cg(fun->sp); -} - -static void clean_insn_cg(struct bpf_ir_env *env, struct ir_insn *insn) -{ - struct ir_insn_cg_extra *extra = insn_cg(insn); - bpf_ir_array_clear(env, &extra->adj); - bpf_ir_array_clear(env, &extra->gen); - bpf_ir_array_clear(env, &extra->kill); - bpf_ir_array_clear(env, &extra->in); - bpf_ir_array_clear(env, &extra->out); -} - -static void clean_cg(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos = NULL; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn = NULL; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - clean_insn_cg(env, insn); - struct ir_insn_cg_extra *extra = insn_cg(insn); - if (insn->op != IR_INSN_ALLOCARRAY) { - extra->allocated = false; - extra->spilled = 0; - extra->spilled_size = 0; - extra->alloc_reg = 0; - } - } - } - - for (u8 i = 0; i < BPF_REG_10; ++i) { - struct ir_insn *insn = fun->cg_info.regs[i]; - clean_insn_cg(env, insn); - } - clean_insn_cg(env, fun->sp); // But should have no effect I guess? - bpf_ir_array_clear(env, &fun->cg_info.all_var); -} - -static void print_ir_prog_cg_dst(struct bpf_ir_env *env, - struct ir_function *fun, char *msg) -{ - PRINT_LOG_DEBUG(env, "\x1B[32m----- CG: %s -----\x1B[0m\n", msg); - print_ir_prog_advanced(env, fun, NULL, NULL, print_ir_dst); -} - -static void print_ir_prog_cg_alloc(struct bpf_ir_env *env, - struct ir_function *fun, char *msg) -{ - PRINT_LOG_DEBUG(env, "\x1B[32m----- CG: %s -----\x1B[0m\n", msg); - print_ir_prog_advanced(env, fun, NULL, NULL, print_ir_alloc); -} - -static void synthesize(struct bpf_ir_env *env, struct ir_function *fun) -{ - // The last step, synthesizes the program - SAFE_MALLOC(env->insns, env->insn_cnt * sizeof(struct bpf_insn)); - struct ir_basic_block **pos = NULL; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn = NULL; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - struct ir_insn_cg_extra *extra = insn_cg(insn); - for (u8 i = 0; i < extra->translated_num; ++i) { - struct pre_ir_insn translated_insn = - extra->translated[i]; - // PRINT_DBG("Writing to insn %zu\n", - // translated_insn.pos); - struct bpf_insn *real_insn = - &env->insns[translated_insn.pos]; - real_insn->code = translated_insn.opcode; - real_insn->dst_reg = translated_insn.dst_reg; - real_insn->src_reg = translated_insn.src_reg; - real_insn->off = translated_insn.off; - if (translated_insn.it == IMM) { - real_insn->imm = translated_insn.imm; - } else { - // Wide instruction - struct bpf_insn *real_insn2 = - &env->insns[translated_insn.pos + - 1]; - real_insn->imm = translated_insn.imm64 & - 0xffffffff; - real_insn2->imm = - translated_insn.imm64 >> 32; - } - } - } - } -} - -// Remove PHI insn -static void remove_phi(struct bpf_ir_env *env, struct ir_function *fun) -{ - // dst information ready - struct array phi_insns; - INIT_ARRAY(&phi_insns, struct ir_insn *); - - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - if (insn->op == IR_INSN_PHI) { - bpf_ir_array_push(env, &phi_insns, &insn); - } else { - break; - } - } - } - - struct ir_insn **pos2; - array_for(pos2, phi_insns) - { - struct ir_insn *insn = *pos2; - struct ir_insn *repr = NULL; - struct phi_value *pos3; - array_for(pos3, insn->phi) - { - DBGASSERT(pos3->value.type == IR_VALUE_INSN); - if (!repr) { - repr = pos3->value.data.insn_d; - } else { - set_insn_dst(env, pos3->value.data.insn_d, - repr); - } - } - if (!repr) { - CRITICAL("Empty Phi not removed!"); - } - - DBGASSERT(repr == insn_dst(repr)); - - bpf_ir_replace_all_usage_cg(env, insn, bpf_ir_value_insn(repr)); - bpf_ir_erase_insn_cg(env, fun, insn); - } - - bpf_ir_array_free(&phi_insns); -} - -static bool is_insn_final(struct ir_insn *v1) -{ - return v1 == insn_dst(v1); -} - -static void build_conflict(struct bpf_ir_env *env, struct ir_insn *v1, - struct ir_insn *v2) -{ - if (!is_insn_final(v1) || !is_insn_final(v2)) { - CRITICAL("Can only build conflict on final values"); - } - if (v1 == v2) { - return; - } - bpf_ir_array_push_unique(env, &insn_cg(v1)->adj, &v2); - bpf_ir_array_push_unique(env, &insn_cg(v2)->adj, &v1); -} - -static void bpf_ir_print_interference_graph(struct bpf_ir_env *env, - struct ir_function *fun) -{ - // Tag the IR to have the actual number to print - tag_ir(fun); - struct ir_insn **pos; - array_for(pos, fun->cg_info.all_var) - { - struct ir_insn *insn = *pos; - if (insn->op == IR_INSN_REG) { - CRITICAL( - "Pre-colored register should not be in all_var"); - } - struct ir_insn_cg_extra *extra = insn_cg(insn); - if (!is_insn_final(extra->dst.data.insn_d)) { - // Not final value, give up - print_ir_insn_err_full(env, insn, "Instruction", - print_ir_dst); - RAISE_ERROR("Not Final Value!"); - } - if (extra->allocated) { - // Allocated VR - PRINT_LOG_DEBUG(env, "%%%zu(", insn->_insn_id); - if (extra->spilled) { - PRINT_LOG_DEBUG(env, "sp+%d", extra->spilled); - } else { - PRINT_LOG_DEBUG(env, "r%u", extra->alloc_reg); - } - PRINT_LOG_DEBUG(env, "):"); - } else { - // Pre-colored registers or unallocated VR - print_insn_ptr_base(env, insn); - PRINT_LOG_DEBUG(env, ":"); - } - struct ir_insn **pos2; - array_for(pos2, insn_cg(insn)->adj) - { - struct ir_insn *adj_insn = *pos2; - if (!is_insn_final(adj_insn)) { - // Not final value, give up - CRITICAL("Not Final Value!"); - } - PRINT_LOG_DEBUG(env, " "); - print_insn_ptr_base(env, adj_insn); - } - PRINT_LOG_DEBUG(env, "\n"); - } -} - -static void caller_constraint(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - for (u8 i = BPF_REG_0; i < BPF_REG_6; ++i) { - // R0-R5 are caller saved register - DBGASSERT(fun->cg_info.regs[i] == - insn_dst(fun->cg_info.regs[i])); - build_conflict(env, fun->cg_info.regs[i], insn); - } -} - -static void conflict_analysis(struct bpf_ir_env *env, struct ir_function *fun) -{ - // Basic conflict: - // For every x in KILL set, x is conflict with every element in OUT set. - - struct ir_basic_block **pos; - // For each BB - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - // For each operation - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - struct ir_insn_cg_extra *insn_cg = insn->user_data; - if (insn->op == IR_INSN_CALL) { - // Add caller saved register constraints - struct ir_insn **pos2; - array_for(pos2, insn_cg->in) - { - DBGASSERT(*pos2 == insn_dst(*pos2)); - struct ir_insn **pos3; - array_for(pos3, insn_cg->out) - { - DBGASSERT(*pos3 == - insn_dst(*pos3)); - if (*pos2 == *pos3) { - // Live across CALL! - // PRINT_LOG_DEBUG("Found a VR live across CALL!\n"); - caller_constraint( - env, fun, - *pos2); - } - } - } - } - struct ir_insn **pos2; - array_for(pos2, insn_cg->kill) - { - struct ir_insn *insn_dst = *pos2; - DBGASSERT(insn_dst == insn_dst(insn_dst)); - if (insn_dst->op != IR_INSN_REG) { - bpf_ir_array_push_unique( - env, &fun->cg_info.all_var, - &insn_dst); - } - struct ir_insn **pos3; - array_for(pos3, insn_cg->out) - { - DBGASSERT(*pos3 == insn_dst(*pos3)); - build_conflict(env, insn_dst, *pos3); - } - } - } - } -} - -static u8 allocated_reg_insn(struct ir_insn *insn) -{ - return insn_cg(insn)->alloc_reg; -} - -static u8 allocated_reg(struct ir_value val) -{ - // DBGASSERT(val.type == IR_VALUE_INSN); - return allocated_reg_insn(val.data.insn_d); -} - -static bool has_conflict(struct ir_insn *v1, struct ir_insn *v2) -{ - if (!is_insn_final(v1) || !is_insn_final(v2)) { - CRITICAL("Can only test conflict on final values"); - } - if (insn_cg(v1)->nonvr && insn_cg(v2)->nonvr) { - return false; - } - if (v1 == v2) { - return false; - } - if (insn_cg(v1)->nonvr) { - // R <-> r - struct array adj = insn_cg(v2)->adj; - struct ir_insn **pos; - array_for(pos, adj) - { - if (allocated_reg_insn(*pos) == - allocated_reg_insn(v1)) { - return true; - } - } - } else if (insn_cg(v2)->nonvr) { - // r <-> R - struct array adj = insn_cg(v1)->adj; - struct ir_insn **pos; - array_for(pos, adj) - { - if (allocated_reg_insn(*pos) == - allocated_reg_insn(v2)) { - return true; - } - } - } else { - // r <-> r - bool ok = true; - struct array adj = insn_cg(v1)->adj; - struct ir_insn **pos; - array_for(pos, adj) - { - if (allocated_reg_insn(*pos) == - allocated_reg_insn(v2)) { - ok = false; - break; - } - } - if (ok) { - // No conflict! - return false; - } - ok = true; - adj = insn_cg(v2)->adj; - array_for(pos, adj) - { - if (allocated_reg_insn(*pos) == - allocated_reg_insn(v1)) { - ok = false; - break; - } - } - if (ok) { - // No conflict! - return false; - } else { - // Both have conflict - return true; - } - } - return false; -} - -/* Optimization: Coalescing - - Returns false if no need to rerun liveness analysis - */ -static bool coalescing(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos; - // For each BB - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn, *tmp; - // For each operation - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, - list_ptr) { - struct ir_insn *insn_dst = insn_dst(insn); - if (insn->op == IR_INSN_ASSIGN) { - if (insn->values[0].type == IR_VALUE_INSN) { - struct ir_insn *src = - insn->values[0].data.insn_d; - DBGASSERT(src == insn_dst(src)); - // a = a - if (insn_cg(src)->alloc_reg == - insn_cg(insn_dst)->alloc_reg) { - // Remove - // erase_same_reg_assign(env, fun, - // insn); - // return true; - continue; - } - - // R = R - if (insn_cg(src)->nonvr && - insn_cg(insn)->nonvr) { - continue; - } - // R = r - // r = R - // Able to coalesce - - if (!has_conflict(insn_dst, src)) { - bool ret = false; - // No Conflict, could coalesce - // CRITICAL( - // "Coalescing not implemented"); - // Check if coalescing is beneficial using Briggs' conservative coalescing - u32 count = 0; - struct array merged; - bpf_ir_array_clone( - env, &merged, - &insn_cg(src)->adj); - bpf_ir_array_merge( - env, &merged, - &insn_cg(insn_dst)->adj); - struct ir_insn **pos2; - array_for(pos2, merged) - { - if (*pos2 == insn_dst || - *pos2 == src) { - continue; - } - if (insn_cg((*pos2)) - ->nonvr && - insn_cg((*pos2)) - ->spilled) { - // Pre-colored stack - continue; - } - count++; - } - - // PRINT_LOG_DEBUG(env, "Count: %u\n", count); - if (count < BPF_REG_10) { - // Coalesce - ret = true; - - PRINT_LOG_DEBUG( - env, - "Coalescing %u and %u\n", - insn_cg(src) - ->alloc_reg, - insn_cg(insn_dst) - ->alloc_reg); - if (insn_cg(insn_dst) - ->nonvr) { - // R = r - set_insn_dst( - env, - src, - insn_dst); - } else if (insn_cg(src) - ->nonvr) { - // r = R - set_insn_dst( - env, - insn_dst, - src); - } else { - // r = r - set_insn_dst( - env, - insn_dst, - src); - } - // This instruction should have no users - // bpf_ir_check_no_user( - // env, insn); - bpf_ir_erase_insn_cg( - env, fun, insn); - } - bpf_ir_array_free(&merged); - return ret; - } - } - } - } - } - return false; -} - -// CG: After init -static void change_ret(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - if (insn->op == IR_INSN_RET) { - // ret x - // ==> - // R0 = x - // ret - struct ir_insn *new_insn = - bpf_ir_create_assign_insn_cg( - env, insn, insn->values[0], - INSERT_FRONT); - new_insn->alu_op = IR_ALU_64; - set_insn_dst(env, new_insn, - fun->cg_info.regs[0]); - bpf_ir_val_remove_user(insn->values[0], insn); - insn->value_num = 0; - } - } - } -} - -// After init -static void change_call(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - if (insn->op == IR_INSN_CALL) { - for (u8 i = 0; i < insn->value_num; ++i) { - struct ir_value val = insn->values[i]; - bpf_ir_val_remove_user(val, insn); - struct ir_insn *new_insn = - bpf_ir_create_assign_insn_cg( - env, insn, val, - INSERT_FRONT); - set_insn_dst(env, new_insn, - fun->cg_info.regs[i + 1]); - } - insn->value_num = 0; // Remove all operands - set_insn_dst(env, insn, fun->cg_info.regs[0]); - } - } - } -} - -static int compare_insn(const void *a, const void *b) -{ - struct ir_insn *ap = *(struct ir_insn **)a; - struct ir_insn *bp = *(struct ir_insn **)b; - return ap->_insn_id > bp->_insn_id; -} - -static void graph_coloring(struct bpf_ir_env *env, struct ir_function *fun) -{ - // Using the Chaitin's Algorithm - // Using the simple dominance heuristic (Simple traversal of BB) - tag_ir(fun); - struct array *all_var = &fun->cg_info.all_var; - qsort(all_var->data, all_var->num_elem, all_var->elem_size, - &compare_insn); - // all_var is now PEO - struct ir_insn **pos; - array_for(pos, (*all_var)) - { - // Allocate register for *pos - struct ir_insn *insn = *pos; - if (insn->op == IR_INSN_REG) { - CRITICAL( - "Pre-colored register should not be in all_var"); - } - struct ir_insn_cg_extra *extra = insn_cg(insn); - if (extra->allocated) { - // Already allocated - continue; - } - struct ir_insn **pos2; - - int used_reg[MAX_BPF_REG] = { 0 }; - struct array used_spill; - INIT_ARRAY(&used_spill, s32); - array_for(pos2, extra->adj) - { - struct ir_insn *insn2 = *pos2; // Adj instruction - struct ir_insn_cg_extra *extra2 = insn_cg(insn2); - if (extra2->allocated) { - if (extra2->spilled) { - if (extra2->spilled_size == 0) { - RAISE_ERROR( - "Found a spilling a register that has 0 size"); - } - u32 spill_number = - (extra2->spilled_size - 1) / 8 + - 1; - for (u32 i = 0; i < spill_number; i++) { - bpf_ir_array_push_unique( - env, &used_spill, - &extra2->spilled - - i * 8); - } - } else { - used_reg[extra2->alloc_reg] = 1; - } - } - } - bool need_spill = true; - for (u8 i = 0; i < BPF_REG_10; i++) { // Wrong! - if (!used_reg[i]) { - extra->allocated = true; - PRINT_LOG_DEBUG(env, "Allocate r%u for %%%zu\n", - i, insn->_insn_id); - extra->alloc_reg = i; - need_spill = false; - break; - } - } - if (need_spill) { - s32 sp = -8; - while (1) { - bool found = true; - s32 *pos3; - array_for(pos3, used_spill) - { - if (*pos3 == sp) { - sp -= 8; - found = false; - break; - } - } - if (found) { - extra->allocated = true; - extra->spilled = sp; - extra->spilled_size = - 8; // Default size for VR - break; - } - } - } - bpf_ir_array_free(&used_spill); - } -} - -// Live variable analysis - -static void gen_kill(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos; - // For each BB - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *pos2; - // For each operation - list_for_each_entry(pos2, &bb->ir_insn_head, list_ptr) { - struct ir_insn *insn_dst = insn_dst(pos2); - struct ir_insn_cg_extra *insn_cg = pos2->user_data; - if (!bpf_ir_is_void(pos2) && insn_dst) { - bpf_ir_array_push_unique(env, &insn_cg->kill, - &insn_dst); - } - struct array value_uses = - bpf_ir_get_operands(env, pos2); - struct ir_value **pos3; - array_for(pos3, value_uses) - { - struct ir_value *val = *pos3; - if (val->type == IR_VALUE_INSN) { - struct ir_insn *insn = val->data.insn_d; - DBGASSERT(insn == insn_dst(insn)); - bpf_ir_array_push_unique( - env, &insn_cg->gen, &insn); - // array_erase_elem(&insn_cg->kill, insn); - } - } - bpf_ir_array_free(&value_uses); - } - } -} - -static bool array_contains(struct array *arr, struct ir_insn *insn) -{ - struct ir_insn **pos; - array_for(pos, (*arr)) - { - if (*pos == insn) { - return true; - } - } - return false; -} - -static struct array array_delta(struct bpf_ir_env *env, struct array *a, - struct array *b) -{ - struct array res; - INIT_ARRAY(&res, struct ir_insn *); - struct ir_insn **pos; - array_for(pos, (*a)) - { - struct ir_insn *insn = *pos; - if (!array_contains(b, insn)) { - bpf_ir_array_push(env, &res, &insn); - } - } - return res; -} - -static bool equal_set(struct array *a, struct array *b) -{ - if (a->num_elem != b->num_elem) { - return false; - } - struct ir_insn **pos; - array_for(pos, (*a)) - { - struct ir_insn *insn = *pos; - if (!array_contains(b, insn)) { - return false; - } - } - return true; -} - -static void in_out(struct bpf_ir_env *env, struct ir_function *fun) -{ - bool change = true; - // For each BB - while (change) { - change = false; - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - struct ir_insn_cg_extra *insn_cg = - insn->user_data; - struct array old_in = insn_cg->in; - bpf_ir_array_clear(env, &insn_cg->out); - CHECK_ERR(); - - if (bpf_ir_get_last_insn(bb) == insn) { - // Last instruction - struct ir_basic_block **pos2; - array_for(pos2, bb->succs) - { - struct ir_basic_block *bb2 = - *pos2; - if (bpf_ir_bb_empty(bb2)) { - CRITICAL( - "Found empty BB"); - } - struct ir_insn *first = - bpf_ir_get_first_insn( - bb2); - struct ir_insn_cg_extra - *insn2_cg = - first->user_data; - bpf_ir_array_merge( - env, &insn_cg->out, - &insn2_cg->in); - CHECK_ERR(); - } - } else { - // Not last instruction - struct ir_insn *next_insn = list_entry( - insn->list_ptr.next, - struct ir_insn, list_ptr); - struct ir_insn_cg_extra *next_insn_cg = - next_insn->user_data; - bpf_ir_array_merge(env, &insn_cg->out, - &next_insn_cg->in); - CHECK_ERR(); - } - struct array out_kill_delta = array_delta( - env, &insn_cg->out, &insn_cg->kill); - CHECK_ERR(); - bpf_ir_array_clone(env, &insn_cg->in, - &insn_cg->gen); - CHECK_ERR(); - bpf_ir_array_merge(env, &insn_cg->in, - &out_kill_delta); - CHECK_ERR(); - // Check for change - if (!equal_set(&insn_cg->in, &old_in)) { - change = true; - } - // Collect garbage - bpf_ir_array_free(&out_kill_delta); - bpf_ir_array_free(&old_in); - } - } - } -} - -static void print_insn_extra(struct bpf_ir_env *env, struct ir_insn *insn) -{ - struct ir_insn_cg_extra *insn_cg = insn->user_data; - if (insn_cg == NULL) { - CRITICAL("NULL user data"); - } - PRINT_LOG_DEBUG(env, "--\nGen:"); - struct ir_insn **pos; - array_for(pos, insn_cg->gen) - { - struct ir_insn *insn = *pos; - PRINT_LOG_DEBUG(env, " "); - print_insn_ptr_base(env, insn); - } - PRINT_LOG_DEBUG(env, "\nKill:"); - array_for(pos, insn_cg->kill) - { - struct ir_insn *insn = *pos; - PRINT_LOG_DEBUG(env, " "); - print_insn_ptr_base(env, insn); - } - PRINT_LOG_DEBUG(env, "\nIn:"); - array_for(pos, insn_cg->in) - { - struct ir_insn *insn = *pos; - PRINT_LOG_DEBUG(env, " "); - print_insn_ptr_base(env, insn); - } - PRINT_LOG_DEBUG(env, "\nOut:"); - array_for(pos, insn_cg->out) - { - struct ir_insn *insn = *pos; - PRINT_LOG_DEBUG(env, " "); - print_insn_ptr_base(env, insn); - } - PRINT_LOG_DEBUG(env, "\n-------------\n"); -} - -static void liveness_analysis(struct bpf_ir_env *env, struct ir_function *fun) -{ - // TODO: Encode Calling convention into GEN KILL - gen_kill(env, fun); - in_out(env, fun); - if (env->opts.verbose > 2) { - PRINT_LOG_DEBUG(env, "--------------\n"); - print_ir_prog_advanced(env, fun, NULL, print_insn_extra, - print_ir_dst); - print_ir_prog_advanced(env, fun, NULL, NULL, print_ir_dst); - } -} - -static enum val_type vtype_insn(struct ir_insn *insn) -{ - insn = insn_dst(insn); - if (insn == NULL) { - // Void - return UNDEF; - } - struct ir_insn_cg_extra *extra = insn_cg(insn); - if (extra->spilled) { - if (insn->op == IR_INSN_ALLOCARRAY) { - return STACKOFF; - } else { - return STACK; - } - } else { - return REG; - } -} - -static enum val_type vtype(struct ir_value val) -{ - if (val.type == IR_VALUE_INSN) { - return vtype_insn(val.data.insn_d); - } else if (val.type == IR_VALUE_CONSTANT || - val.type == IR_VALUE_CONSTANT_RAWOFF || - val.type == IR_VALUE_CONSTANT_RAWOFF_REV) { - return CONST; - } else { - CRITICAL("No such value type for dst"); - } -} - -/* Test whether an instruction is a VR instruction */ -// static bool is_vr_insn(struct ir_insn *insn) -// { -// if (insn == NULL || insn->user_data == NULL) { -// // Void -// return false; -// } -// return !insn_cg(insn)->nonvr; -// } - -/* Test whether a value is a VR instruction */ -// static bool is_vr(struct ir_value val) -// { -// if (val.type == IR_VALUE_INSN) { -// return is_vr_insn(val.data.insn_d); -// } else { -// return false; -// } -// } - -// Relocate BB -static void calc_pos(struct bpf_ir_env *env, struct ir_function *fun) -{ - // Calculate the position of each instruction & BB - size_t ipos = 0; // Instruction position - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_bb_cg_extra *bb_extra = bb->user_data; - bb_extra->pos = ipos; - struct ir_insn *insn; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - struct ir_insn_cg_extra *insn_extra = insn_cg(insn); - for (u8 i = 0; i < insn_extra->translated_num; ++i) { - struct pre_ir_insn *translated_insn = - &insn_extra->translated[i]; - // Pos - translated_insn->pos = ipos; - if (translated_insn->it == IMM) { - ipos += 1; - } else { - ipos += 2; - } - } - } - } - env->insn_cnt = ipos; -} - -static void relocate(struct bpf_ir_env *env, struct ir_function *fun) -{ - calc_pos(env, fun); - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - struct ir_insn_cg_extra *insn_extra = insn_cg(insn); - if (insn->op == IR_INSN_JA) { - DBGASSERT(insn_extra->translated_num == 1); - size_t target = bpf_ir_bb_cg(insn->bb1)->pos; - insn_extra->translated[0].off = - target - insn_extra->translated[0].pos - - 1; - } - if (bpf_ir_is_cond_jmp(insn)) { - DBGASSERT(insn_extra->translated_num == 1); - size_t target = bpf_ir_bb_cg(insn->bb2)->pos; - insn_extra->translated[0].off = - target - insn_extra->translated[0].pos - - 1; - } - } - } -} - -// Load a constant (usually 64 bits) to a register -static void cgir_load_const_to_reg(struct bpf_ir_env *env, - struct ir_function *fun, - struct ir_insn *insn, struct ir_value *val, - u8 reg) -{ - struct ir_insn *new_insn = - bpf_ir_create_assign_insn_cg(env, insn, *val, INSERT_FRONT); - new_insn->alu_op = IR_ALU_64; - set_insn_dst(env, new_insn, fun->cg_info.regs[reg]); - - bpf_ir_change_value(env, insn, val, - bpf_ir_value_insn(fun->cg_info.regs[reg])); -} - -static void cgir_load_reg_to_reg(struct bpf_ir_env *env, - struct ir_function *fun, struct ir_insn *insn, - struct ir_value *val, u8 reg) -{ - struct ir_insn *new_insn = - bpf_ir_create_assign_insn_cg(env, insn, *val, INSERT_FRONT); - new_insn->alu_op = IR_ALU_64; - set_insn_dst(env, new_insn, fun->cg_info.regs[reg]); - bpf_ir_change_value(env, insn, val, - bpf_ir_value_insn(fun->cg_info.regs[reg])); -} - -static void cgir_load_stack_to_reg(struct bpf_ir_env *env, - struct ir_function *fun, - struct ir_insn *insn, struct ir_value *val, - enum ir_vr_type vtype, u8 reg) -{ - struct ir_insn *tmp = - bpf_ir_create_assign_insn_cg(env, insn, *val, INSERT_FRONT); - tmp->vr_type = vtype; - set_insn_dst(env, tmp, fun->cg_info.regs[reg]); - - bpf_ir_change_value(env, insn, val, - bpf_ir_value_insn(fun->cg_info.regs[reg])); -} - -static void add_stack_offset_vr(struct ir_function *fun, size_t num) -{ - struct ir_insn **pos; - array_for(pos, fun->cg_info.all_var) - { - struct ir_insn_cg_extra *extra = insn_cg(*pos); - if (extra->spilled) { - extra->spilled -= num * 8; - } - } -} - -/* Spilling callee - - NOT TESTED YET - */ -static void spill_callee(struct bpf_ir_env *env, struct ir_function *fun) -{ - // Spill Callee saved registers if used - u8 reg_used[MAX_BPF_REG] = { 0 }; - - struct ir_insn **pos; - array_for(pos, fun->cg_info.all_var) - { - struct ir_insn_cg_extra *extra = insn_cg(*pos); - DBGASSERT(extra->allocated); - if (extra->spilled == 0) { - reg_used[extra->alloc_reg] = 1; - } - } - size_t off = 0; - for (u8 i = BPF_REG_6; i < BPF_REG_10; ++i) { - if (reg_used[i]) { - off++; - } - } - DBGASSERT(off == fun->cg_info.callee_num); - add_stack_offset_vr(fun, off); - off = 0; - for (u8 i = BPF_REG_6; i < BPF_REG_10; ++i) { - // All callee saved registers - if (reg_used[i]) { - off++; - // Spill at sp-off - // struct ir_insn *st = create_assign_insn_bb_cg(env, - // fun->entry, ir_value_insn(fun->cg_info.regs[i]), INSERT_FRONT); - struct ir_insn *st = bpf_ir_create_insn_base_cg( - env, fun->entry, IR_INSN_STORERAW); - bpf_ir_insert_at_bb(st, fun->entry, INSERT_FRONT); - // st->values[0] = bpf_ir_value_insn(fun->cg_info.regs[i]); - bpf_ir_val_add_user(env, st->values[0], - fun->cg_info.regs[i]); - st->value_num = 1; - st->vr_type = IR_VR_TYPE_64; - st->addr_val.value = bpf_ir_value_stack_ptr(fun); - st->addr_val.offset = -off * 8; - set_insn_dst(env, st, NULL); - - struct ir_basic_block **pos2; - array_for(pos2, fun->end_bbs) - { - struct ir_basic_block *bb = *pos2; - struct ir_insn *ld = bpf_ir_create_insn_base_cg( - env, bb, IR_INSN_LOADRAW); - bpf_ir_insert_at_bb(ld, bb, - INSERT_BACK_BEFORE_JMP); - ld->value_num = 0; - ld->vr_type = IR_VR_TYPE_64; - // ld->addr_val.value = - // bpf_ir_value_stack_ptr(fun); - bpf_ir_val_add_user(env, ld->addr_val.value, - fun->sp); - ld->addr_val.offset = -off * 8; - - set_insn_dst(env, ld, fun->cg_info.regs[i]); - } - } - } -} - -// Normalization - -/* Loading constant used in normalization */ -static struct ir_insn *normalize_load_const(struct bpf_ir_env *env, - struct ir_insn *insn, - struct ir_value *val) -{ - struct ir_insn *new_insn = NULL; - if (val->const_type == IR_ALU_32) { - new_insn = bpf_ir_create_assign_insn_cg(env, insn, *val, - INSERT_FRONT); - new_insn->alu_op = IR_ALU_64; - } else { - new_insn = bpf_ir_create_insn_base_cg(env, insn->parent_bb, - IR_INSN_LOADIMM_EXTRA); - new_insn->imm_extra_type = IR_LOADIMM_IMM64; - new_insn->imm64 = val->data.constant_d; - new_insn->vr_type = IR_VR_TYPE_64; - } - bpf_ir_change_value(env, insn, val, bpf_ir_value_insn(new_insn)); - return new_insn; -} - -static void bpf_ir_erase_insn_cg_shallow(struct ir_insn *insn) -{ - list_del(&insn->list_ptr); -} - -static void normalize_assign(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn *dst_insn = insn_dst(insn); - // stack = reg - // stack = const32 - // reg = const32 - // reg = const64 - // reg = stack - // reg = reg - if (tdst == STACK) { - DBGASSERT(t0 != STACK); - // Change to STORERAW - insn->op = IR_INSN_STORERAW; - - bpf_ir_change_value(env, insn, &insn->addr_val.value, - bpf_ir_value_stack_ptr(fun)); - insn->addr_val.offset = insn_cg(dst_insn)->spilled; - } else { - if (t0 == STACK) { - // Change to LOADRAW - insn->op = IR_INSN_LOADRAW; - bpf_ir_change_value(env, insn, &insn->addr_val.value, - bpf_ir_value_stack_ptr(fun)); - insn->addr_val.offset = - insn_cg(v0->data.insn_d)->spilled; - } - if (t0 == CONST && v0->const_type == IR_ALU_64) { - // 64 imm load - insn->op = IR_INSN_LOADIMM_EXTRA; - insn->imm_extra_type = IR_LOADIMM_IMM64; - insn->imm64 = v0->data.constant_d; - } - } - if (tdst == REG && t0 == REG) { - if (allocated_reg_insn(dst_insn) == allocated_reg(*v0)) { - // The same, erase this instruction - // erase_same_reg_assign(env, fun, insn); - // Needs garbage collection for instructions - bpf_ir_erase_insn_cg_shallow(insn); - } - } -} - -/* Normalize ALU */ -static void normalize_alu(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - struct ir_value *v1 = &insn->values[1]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - if (t1 == REG) { - // tdst != t1 - DBGASSERT(allocated_reg_insn(dst_insn) != allocated_reg(*v1)); - } - if (t0 == CONST) { - DBGASSERT(v0->const_type == IR_ALU_32); - } - if (t1 == CONST) { - DBGASSERT(v1->const_type == IR_ALU_32); - } - // Binary ALU - if (t0 == STACK && t1 == CONST) { - // reg1 = add stack const - // ==> - // reg1 = stack - // reg1 = add reg1 const - struct ir_insn *new_insn = bpf_ir_create_assign_insn_cg( - env, insn, *v0, INSERT_FRONT); - new_insn->vr_type = IR_VR_TYPE_64; - set_insn_dst(env, new_insn, dst_insn); - bpf_ir_change_value(env, insn, v0, bpf_ir_value_insn(dst_insn)); - normalize_assign(env, fun, new_insn); - } else if (t0 == STACK && t1 == REG) { - // reg1 = add stack reg2 - // ==> - // reg1 = stack - // reg1 = add reg1 reg2 - struct ir_insn *new_insn = bpf_ir_create_assign_insn_cg( - env, insn, *v0, INSERT_FRONT); - set_insn_dst(env, new_insn, dst_insn); - new_insn->vr_type = IR_VR_TYPE_64; - bpf_ir_change_value(env, insn, v0, bpf_ir_value_insn(dst_insn)); - normalize_assign(env, fun, new_insn); - } else if (t0 == REG && t1 == REG) { - // reg1 = add reg2 reg3 - u8 reg1 = insn_cg(dst_insn)->alloc_reg; - u8 reg2 = insn_cg(v0->data.insn_d)->alloc_reg; - if (reg1 != reg2) { - // reg1 = add reg2 reg3 - // ==> - // reg1 = reg2 - // reg1 = add reg1 reg3 - // PRINT_LOG_DEBUG(env, "v0:"); - // print_ir_insn(env, v0->data.insn_d); - // PRINT_LOG_DEBUG(env, "\n"); - struct ir_insn *new_insn = bpf_ir_create_assign_insn_cg( - env, insn, *v0, INSERT_FRONT); - // DBGASSERT(dst_insn == - // fun->cg_info.regs[reg1]); // Fixed reg? - // TODO: Investigate here, why did I write this check? - set_insn_dst(env, new_insn, dst_insn); - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(dst_insn)); - } - } else if (t0 == REG && t1 == CONST) { - if (allocated_reg(*v0) != allocated_reg_insn(dst_insn)) { - // reg1 = add reg2 const - // ==> - // reg1 = reg2 - // reg1 = add reg1 const - struct ir_insn *new_insn = bpf_ir_create_assign_insn_cg( - env, insn, *v0, INSERT_FRONT); - set_insn_dst(env, new_insn, dst_insn); - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(dst_insn)); - } - } else if (t0 == CONST && t1 == CONST) { - DBGASSERT(v1->const_type == IR_ALU_32); - struct ir_insn *load_const_insn = - normalize_load_const(env, insn, v0); - set_insn_dst(env, load_const_insn, dst_insn); - } else if (t0 == CONST && t1 == REG) { - // reg1 = add const reg2 - // ==> - // reg1 = const - // reg1 = add reg1 reg2 - struct ir_insn *load_const_insn = - normalize_load_const(env, insn, v0); - set_insn_dst(env, load_const_insn, dst_insn); - - } else { - CRITICAL_DUMP(env, "Error"); - } -} - -static void normalize_getelemptr(struct bpf_ir_env *env, - struct ir_function *fun, struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - struct ir_value *v1 = &insn->values[1]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - DBGASSERT(t1 == STACKOFF); - DBGASSERT(v1->type == IR_VALUE_INSN && - v1->data.insn_d->op == IR_INSN_ALLOCARRAY); - struct ir_insn_cg_extra *v1_extra = insn_cg(v1->data.insn_d); - s32 spill_pos = v1_extra->spilled; - insn->op = IR_INSN_ADD; - insn->alu_op = IR_ALU_64; - if (t0 == CONST) { - // reg = getelemptr const ptr - // ==> - // reg = r10 + (const + spill_pos) - DBGASSERT(v0->const_type == IR_ALU_32); - s64 tmp = v0->data.constant_d + spill_pos; // Assume no overflow - bpf_ir_change_value(env, insn, v0, bpf_ir_value_insn(fun->sp)); - bpf_ir_change_value(env, insn, v1, bpf_ir_value_const32(tmp)); - normalize_alu(env, fun, insn); - } - if (t0 == REG) { - bpf_ir_change_value(env, insn, v1, - bpf_ir_value_const32(spill_pos)); - if (allocated_reg(*v0) == allocated_reg_insn(dst_insn)) { - // reg = getelemptr reg ptr - // ==> - // reg += r10 - // reg += spill_pos - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(dst_insn)); - struct ir_insn *new_insn = bpf_ir_create_bin_insn_cg( - env, insn, bpf_ir_value_insn(dst_insn), - bpf_ir_value_insn(fun->sp), IR_INSN_ADD, - IR_ALU_64, INSERT_FRONT); - set_insn_dst(env, new_insn, dst_insn); - } else { - // reg1 = getelemptr reg2 ptr - // ==> - // reg1 = reg2 - // reg1 += r10 - // reg1 += spill_pos - struct ir_insn *assign_insn = - bpf_ir_create_assign_insn_cg(env, insn, *v0, - INSERT_FRONT); - set_insn_dst(env, assign_insn, dst_insn); - struct ir_insn *alu_insn = bpf_ir_create_bin_insn_cg( - env, insn, bpf_ir_value_insn(dst_insn), - bpf_ir_value_insn(fun->sp), IR_INSN_ADD, - IR_ALU_64, INSERT_FRONT); - set_insn_dst(env, alu_insn, dst_insn); - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(dst_insn)); - } - } -} - -static void normalize_stackoff(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - // Stack already shifted - struct ir_value addrval = insn->addr_val.value; - enum val_type addr_ty = vtype(addrval); - // storeraw STACKOFF ? - // ==> - // storeraw r10 ? - if (addr_ty == STACKOFF) { - insn->addr_val.offset += insn_cg(addrval.data.insn_d)->spilled; - bpf_ir_change_value(env, insn, &insn->addr_val.value, - bpf_ir_value_stack_ptr(fun)); - } -} - -static void normalize_neg(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - // reg = neg reg ==> OK! - if (t0 == REG && allocated_reg(*v0) != allocated_reg_insn(dst_insn)) { - // reg1 = neg reg2 - // ==> - // reg1 = reg2 - // reg1 = neg reg1 - struct ir_insn *new_insn = bpf_ir_create_assign_insn_cg( - env, insn, *v0, INSERT_FRONT); - set_insn_dst(env, new_insn, dst_insn); - bpf_ir_change_value(env, insn, v0, bpf_ir_value_insn(dst_insn)); - } - if (t0 == CONST) { - // reg = neg const - RAISE_ERROR("Not supported"); - } else if (t0 == STACK) { - // reg = neg stack - // ==> - // reg = stack - // reg = neg reg - cgir_load_stack_to_reg(env, fun, insn, v0, IR_VR_TYPE_64, - allocated_reg_insn(dst_insn)); - } -} - -static void normalize_end(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - // reg = end reg - if (t0 == REG && allocated_reg(*v0) != allocated_reg_insn(dst_insn)) { - // reg1 = end reg2 - // ==> - // reg1 = reg2 - // reg1 = end reg1 - struct ir_insn *new_insn = bpf_ir_create_assign_insn_cg( - env, insn, *v0, INSERT_FRONT); - set_insn_dst(env, new_insn, dst_insn); - bpf_ir_change_value(env, insn, v0, bpf_ir_value_insn(dst_insn)); - } - // reg = neg const ==> Not supported - if (t0 == CONST) { - RAISE_ERROR("Not supported"); - } else if (t0 == STACK) { - // reg = end stack - // ==> - // reg = stack - // reg = end reg - cgir_load_stack_to_reg(env, fun, insn, v0, IR_VR_TYPE_64, - allocated_reg_insn(dst_insn)); - } -} - -static void normalize(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn, *tmp; - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, - list_ptr) { - if (insn->op == IR_INSN_ALLOC) { - // OK - } else if (insn->op == IR_INSN_ALLOCARRAY) { - // OK - } else if (insn->op == IR_INSN_GETELEMPTR) { - normalize_getelemptr(env, fun, insn); - } else if (insn->op == IR_INSN_STORE) { - // Should be converted to ASSIGN - CRITICAL("Error"); - } else if (insn->op == IR_INSN_LOAD) { - CRITICAL("Error"); - } else if (insn->op == IR_INSN_LOADRAW) { - normalize_stackoff(env, fun, insn); - } else if (insn->op == IR_INSN_LOADIMM_EXTRA) { - // OK - } else if (insn->op == IR_INSN_STORERAW) { - normalize_stackoff(env, fun, insn); - } else if (insn->op == IR_INSN_NEG) { - normalize_neg(env, fun, insn); - } else if (insn->op == IR_INSN_HTOBE || - insn->op == IR_INSN_HTOLE) { - normalize_end(env, fun, insn); - } else if (bpf_ir_is_bin_alu(insn)) { - normalize_alu(env, fun, insn); - } else if (insn->op == IR_INSN_ASSIGN) { - normalize_assign(env, fun, insn); - } else if (insn->op == IR_INSN_RET) { - // OK - } else if (insn->op == IR_INSN_CALL) { - // OK - } else if (insn->op == IR_INSN_JA) { - // OK - } else if (bpf_ir_is_cond_jmp(insn)) { - // jmp reg const/reg - // or - // jmp const/reg reg - // OK - } else { - RAISE_ERROR("No such instruction"); - } - } - } -} - -/* Spill ASSIGN instruction */ -static bool spill_assign(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type tdst = vtype_insn(insn); - - // `dst = src` - - // Cases of `dst, src`: - - // - `STACK, STACK` - // - `STACK, REG` - // - `STACK, CONST` - // - `REG, CONST` - // - `REG, REG` - // - `REG, STACK` - - // Possible result: - - // REG = REG - // REG = CONST - // REG = STACK - // STACK = REG - // STACK = CONST32 - - if (tdst == STACK && t0 == STACK) { - // Both stack positions are managed by us - cgir_load_stack_to_reg(env, fun, insn, v0, IR_VR_TYPE_64, 0); - return true; - } - if (tdst == STACK && t0 == CONST) { - if (v0->const_type == IR_ALU_64) { - // First load to R0 - cgir_load_const_to_reg(env, fun, insn, v0, 0); - return true; - } - } - return false; -} - -/* Spill STORE instructions */ -static bool spill_store(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - struct ir_value *v1 = &insn->values[1]; - // store v0(dst) v1 - // Equivalent to `v0 = v1` - insn->op = IR_INSN_ASSIGN; - DBGASSERT(v0->type == - IR_VALUE_INSN); // Should be guaranteed by prog_check - DBGASSERT(v0->data.insn_d->op == IR_INSN_ALLOC); - insn->vr_type = v0->data.insn_d->vr_type; - DBGASSERT(insn_cg(insn)->dst.type == IR_VALUE_UNDEF); - DBGASSERT(insn->users.num_elem == 0); // Store has no users - bpf_ir_val_remove_user(*v0, insn); - set_insn_dst(env, insn, v0->data.insn_d); - insn->value_num = 1; - *v0 = *v1; - spill_assign(env, fun, insn); - return true; -} - -static bool spill_load(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - // stack = load stack - // stack = load reg - // reg = load reg - // reg = load stack - insn->op = IR_INSN_ASSIGN; - DBGASSERT(v0->type == - IR_VALUE_INSN); // Should be guaranteed by prog_check - DBGASSERT(v0->data.insn_d->op == IR_INSN_ALLOC); - insn->vr_type = v0->data.insn_d->vr_type; - spill_assign(env, fun, insn); - return true; -} - -static bool spill_loadraw(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - enum val_type tdst = vtype_insn(insn); - enum val_type t0 = vtype(insn->addr_val.value); - // struct ir_insn *dst_insn = insn_dst(insn); - // Load from memory - // reg = loadraw reg ==> OK - // reg = loadraw const ==> TODO - if (t0 == CONST) { - CRITICAL("Not supported"); - } - - if (tdst == STACK) { - if (t0 == REG) { - // stack = loadraw reg - // ==> - // R0 = loadraw reg - // stack = R0 - struct ir_insn *new_insn = - bpf_ir_create_loadraw_insn_cg(env, insn, - insn->vr_type, - insn->addr_val, - INSERT_FRONT); - set_insn_dst(env, new_insn, fun->cg_info.regs[0]); - insn->value_num = 1; - insn->op = IR_INSN_ASSIGN; - insn->vr_type = IR_VR_TYPE_64; - bpf_ir_val_remove_user(insn->addr_val.value, insn); - insn->values[0] = - bpf_ir_value_insn(fun->cg_info.regs[0]); - bpf_ir_val_add_user(env, insn->values[0], insn); - return true; - } - if (t0 == STACK) { - // stack = loadraw stack - // ==> - // R0 = loadraw stack - // stack = R0 - - struct ir_insn *new_insn = - bpf_ir_create_loadraw_insn_cg(env, insn, - insn->vr_type, - insn->addr_val, - INSERT_FRONT); - set_insn_dst(env, new_insn, fun->cg_info.regs[0]); - insn->value_num = 1; - insn->op = IR_INSN_ASSIGN; - bpf_ir_val_remove_user(insn->addr_val.value, insn); - insn->values[0] = - bpf_ir_value_insn(fun->cg_info.regs[0]); - bpf_ir_val_add_user(env, insn->values[0], insn); - insn->vr_type = IR_VR_TYPE_64; - - cgir_load_stack_to_reg(env, fun, new_insn, - &new_insn->addr_val.value, - IR_VR_TYPE_64, 0); - return true; - } - } - if (tdst == REG && t0 == STACK) { - cgir_load_stack_to_reg(env, fun, insn, &insn->addr_val.value, - IR_VR_TYPE_64, 0); - return true; - } - return false; -} - -static bool spill_loadrawextra(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - enum val_type tdst = vtype_insn(insn); - // struct ir_insn *dst_insn = insn_dst(insn); - // IMM64 Map instructions, must load to register - if (tdst == STACK) { - // stack = loadimm - // ==> - // R0 = loadimm - // stack = R0 - struct ir_insn *new_insn = bpf_ir_create_loadimmextra_insn_cg( - env, insn, insn->imm_extra_type, insn->imm64, - INSERT_FRONT); - set_insn_dst(env, new_insn, fun->cg_info.regs[0]); - - insn->op = IR_INSN_ASSIGN; - insn->value_num = 1; - insn->values[0] = bpf_ir_value_insn(fun->cg_info.regs[0]); - bpf_ir_val_add_user(env, insn->values[0], insn); - insn->vr_type = IR_VR_TYPE_64; - return true; - } - return false; -} - -static bool spill_storeraw(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - // Store some value to memory - // store ptr reg ==> OK - // store ptr stack - - // store stackptr stack - // ==> TODO! - enum val_type addr_ty = vtype(insn->addr_val.value); - if (addr_ty == CONST) { - CRITICAL("Not supported"); - } - if (addr_ty == STACK) { - CRITICAL("TODO!"); - } - DBGASSERT(addr_ty == REG || addr_ty == STACKOFF); - if (t0 == CONST && v0->const_type == IR_ALU_64) { - // store ptr const64 - // ==> - // r' = const64 - // store ptr r' - u8 reg = 0; - if (addr_ty == REG && - insn_cg(insn->addr_val.value.data.insn_d)->alloc_reg == 0) { - // Make sure the new register is not the same as the other register - reg = 1; - } - cgir_load_const_to_reg(env, fun, insn, v0, reg); - return true; - } - // Question: are all memory address 64 bits? - if (t0 == STACK) { - u8 reg = 0; - if (addr_ty == REG && - insn_cg(insn->addr_val.value.data.insn_d)->alloc_reg == 0) { - // Make sure the new register is not the same as the other register - reg = 1; - } - cgir_load_stack_to_reg(env, fun, insn, v0, IR_VR_TYPE_64, reg); - return true; - } - return false; -} - -static bool spill_alu(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - struct ir_value *v1 = &insn->values[1]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn *dst_insn = insn_dst(insn); - // Binary ALU - // reg = ALU reg reg - // reg = ALU reg const - // There should be NO stack - if (tdst == STACK) { - // stack = ALU ? ? - // ==> - // R0 = ALU ? ? - // stack = R0 - // Note: We should keep the tdst as stack, only change the insn type - struct ir_insn *new_alu = - bpf_ir_create_bin_insn_cg(env, insn, *v0, *v1, insn->op, - insn->alu_op, INSERT_FRONT); - set_insn_dst(env, new_alu, fun->cg_info.regs[0]); - bpf_ir_val_remove_user(*v1, insn); - insn->op = IR_INSN_ASSIGN; - insn->value_num = 1; - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(fun->cg_info.regs[0])); - insn->vr_type = IR_VR_TYPE_64; - spill_alu(env, fun, new_alu); - return true; - } - - if (t1 == REG && allocated_reg_insn(dst_insn) == allocated_reg(*v1)) { - if (t0 == REG && allocated_reg(*v1) == allocated_reg(*v0)) { - // reg = ALU reg reg - // OK, no need to change - return false; - } - if (bpf_ir_is_commutative_alu(insn)) { - // reg = ALU ? reg - // ==> - // reg = ALU reg ? - struct ir_value tmp = *v0; - *v0 = *v1; - *v1 = tmp; - return spill_alu(env, fun, insn); - } - // r0 = ALU ? r0 - // ==> - // R1 = r0 - // r0 = ALU ? R1 - u8 new_reg = allocated_reg_insn(dst_insn) == 0 ? 1 : 0; - cgir_load_reg_to_reg(env, fun, insn, v1, new_reg); - spill_alu(env, fun, insn); - return true; - } - if (t0 == REG) { - if (t1 == CONST) { - // reg = ALU reg const - if (v1->const_type == IR_ALU_64) { - // reg = ALU reg const64 - u8 new_reg = allocated_reg(*v0) == 0 ? 1 : 0; - cgir_load_const_to_reg(env, fun, insn, v1, - new_reg); - spill_alu(env, fun, insn); - return true; - } else if (v1->const_type == IR_ALU_32) { - // PASS - } else { - CRITICAL("No such const type"); - } - } - - if (t1 == STACK) { - // reg = ALU reg stack - // reg = ALU reg const64 - u8 new_reg = allocated_reg(*v0) == 0 ? 1 : 0; - cgir_load_stack_to_reg(env, fun, insn, v1, - IR_VR_TYPE_64, new_reg); - spill_alu(env, fun, insn); - return true; - } - } else { - // Convert t0 to REG - if (t0 == STACK) { - // reg = ALU stack ? - if (t1 == CONST && v1->const_type == IR_ALU_32) { - // reg = ALU stack const32 - // PASS - return false; - } - if (t1 == REG) { - // reg = ALU stack reg2 - // PASS - return false; - } - u8 new_reg = 0; - if (t1 == REG && allocated_reg(*v1) == 0) { - new_reg = 1; - } - cgir_load_stack_to_reg(env, fun, insn, v0, - IR_VR_TYPE_64, new_reg); - spill_alu(env, fun, insn); - return true; - } - if (t0 == CONST) { - if (v0->const_type == IR_ALU_64) { - if (t1 == CONST && - v1->const_type == IR_ALU_32) { - // PASS - return false; - } - u8 new_reg = 0; - if (t1 == REG && allocated_reg(*v1) == 0) { - new_reg = 1; - } - cgir_load_const_to_reg(env, fun, insn, v0, - new_reg); - spill_alu(env, fun, insn); - return true; - } else if (v0->const_type == IR_ALU_32) { - if (t1 == CONST && - v1->const_type == IR_ALU_64) { - // reg = ALU const32 const64 - cgir_load_const_to_reg(env, fun, insn, - v1, 0); - spill_alu(env, fun, insn); - return true; - } - if (t1 == STACK) { - // reg = ALU const32 stack - cgir_load_stack_to_reg(env, fun, insn, - v1, - IR_VR_TYPE_64, - 0); - spill_alu(env, fun, insn); - return true; - } - } else { - CRITICAL("IMPOSSIBLE ALU TYPE"); - } - } - } - - return false; -} - -static bool spill_cond_jump(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - struct ir_value *v1 = &insn->values[1]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; - if (t0 == REG) { - // jmp reg ? - u8 reg = 0; - if (allocated_reg(*v0) == 0) { - reg = 1; - } - if (t1 == STACK) { - cgir_load_stack_to_reg(env, fun, insn, v1, - IR_VR_TYPE_64, reg); - return true; - } - if (t1 == CONST && v1->const_type == IR_ALU_64) { - cgir_load_const_to_reg(env, fun, insn, v1, reg); - return true; - } - } else { - u8 reg = 0; - if (t1 == REG && allocated_reg(*v1) == 0) { - reg = 1; - } - if (t0 == STACK) { - // First change t0 to REG - cgir_load_stack_to_reg(env, fun, insn, v0, - IR_VR_TYPE_64, reg); - spill_cond_jump(env, fun, insn); - return true; - } else { - // CONST - PRINT_LOG_WARNING( - env, - "Warning: using const as the first operand of conditional jump may impact performance.\n"); - - cgir_load_const_to_reg(env, fun, insn, v0, reg); - spill_cond_jump(env, fun, insn); - return true; - } - } - return false; -} - -static bool spill_getelemptr(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - struct ir_value *v1 = &insn->values[1]; - enum val_type t0 = insn->value_num >= 1 ? vtype(*v0) : UNDEF; - enum val_type t1 = insn->value_num >= 2 ? vtype(*v1) : UNDEF; - enum val_type tdst = vtype_insn(insn); - // struct ir_insn *dst_insn = insn_dst(insn); - ASSERT_DUMP(v1->type == IR_VALUE_INSN, false); - ASSERT_DUMP(v1->data.insn_d->op == IR_INSN_ALLOCARRAY, false); - ASSERT_DUMP(t1 == STACKOFF, false); - if (tdst == STACK) { - // stack = getelemptr reg ptr - // ==> - // R0 = getelemptr reg ptr - // stack = R0 - - struct ir_insn *new_insn = bpf_ir_create_getelemptr_insn_cg( - env, insn, v1->data.insn_d, *v0, INSERT_FRONT); - bpf_ir_val_remove_user(*v1, insn); - - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(fun->cg_info.regs[0])); - insn->value_num = 1; - insn->op = IR_INSN_ASSIGN; - set_insn_dst(env, new_insn, fun->cg_info.regs[0]); - spill_getelemptr(env, fun, insn); - return true; - } - if (t0 == STACK) { - cgir_load_stack_to_reg(env, fun, insn, v0, IR_VR_TYPE_64, 0); - return true; - } - if (t0 == CONST && v0->const_type == IR_ALU_64) { - cgir_load_const_to_reg(env, fun, insn, v0, 0); - return true; - } - return false; -} - -static bool spill_neg(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - enum val_type tdst = vtype_insn(insn); - // dst = neg v0 - // reg = neg stack ==> OK - // reg = neg reg ==> OK - if (tdst == STACK) { - // stack = neg ? - // ==> - // R0 = neg ? - // stack = R0 - struct ir_insn *new_insn = bpf_ir_create_neg_insn_cg( - env, insn, insn->alu_op, *v0, INSERT_FRONT); - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(fun->cg_info.regs[0])); - set_insn_dst(env, new_insn, fun->cg_info.regs[0]); - return true; - } - return false; -} - -static bool spill_end(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - struct ir_value *v0 = &insn->values[0]; - enum val_type tdst = vtype_insn(insn); - // dst = end v0 - // reg = end stack ==> OK - // reg = end reg ==> OK - if (tdst == STACK) { - // stack = end ? - // ==> - // R0 = end ? - // stack = R0 - struct ir_insn *new_insn = bpf_ir_create_end_insn_cg( - env, insn, insn->op, insn->swap_width, *v0, - INSERT_FRONT); - bpf_ir_change_value(env, insn, v0, - bpf_ir_value_insn(fun->cg_info.regs[0])); - set_insn_dst(env, new_insn, fun->cg_info.regs[0]); - return true; - } - return false; -} - -static void check_insn_users_use_insn_cg(struct bpf_ir_env *env, - struct ir_insn *insn) -{ - struct ir_insn **pos; - array_for(pos, insn->users) - { - struct ir_insn *user = *pos; - // Check if the user actually uses this instruction - struct array operands = bpf_ir_get_operands_and_dst(env, user); - struct ir_value **val; - int found = 0; - array_for(val, operands) - { - struct ir_value *v = *val; - if (v->type == IR_VALUE_INSN && - v->data.insn_d == insn) { - // Found the user - found = 1; - break; - } - } - bpf_ir_array_free(&operands); - if (!found) { - // Error! - if (!insn_cg(insn)->nonvr) { - print_ir_insn_err_full(env, insn, - "The instruction", - print_ir_dst); - } else { - PRINT_LOG_DEBUG(env, - "The instruction is non-vr.\n"); - } - print_ir_insn_err_full(env, user, - "The user of that instruction", - print_ir_dst); - RAISE_ERROR("User does not use the instruction"); - } - } -} - -static void check_insn_operand_cg(struct bpf_ir_env *env, struct ir_insn *insn) -{ - struct array operands = bpf_ir_get_operands_and_dst(env, insn); - struct ir_value **val; - array_for(val, operands) - { - struct ir_value *v = *val; - if (v->type == IR_VALUE_INSN) { - // Check if the operand actually is used by this instruction - struct ir_insn **pos2; - int found = 0; - array_for(pos2, v->data.insn_d->users) - { - struct ir_insn *user = *pos2; - if (user == insn) { - // Found the user - found = 1; - break; - } - } - if (!found) { - // Error! - print_ir_insn_err_full(env, v->data.insn_d, - "Operand defined here", - print_ir_dst); - print_ir_insn_err_full( - env, insn, - "Instruction that uses the operand", - print_ir_dst); - RAISE_ERROR( - "Instruction not found in the operand's users"); - } - - // Check dst - - struct ir_insn *dst_insn = v->data.insn_d; - if (insn_dst(dst_insn) == NULL) { - print_ir_insn_err_full(env, dst_insn, - "Operand's dst is NULL", - print_ir_dst); - print_ir_insn_err_full( - env, insn, - "This instruction's operand's dst is NULL", - print_ir_dst); - RAISE_ERROR("NULL dst"); - } - if (insn_dst(dst_insn) != dst_insn) { - print_ir_insn_err_full(env, insn_dst(dst_insn), - "Operand's dst", - print_ir_dst); - print_ir_insn_err_full(env, dst_insn, "Operand", - print_ir_dst); - print_ir_insn_err_full( - env, insn, - "This instruction's operand's dst is NULL", - print_ir_dst); - RAISE_ERROR("NULL dst"); - } - } - } - bpf_ir_array_free(&operands); -} - -static void prog_check_cg(struct bpf_ir_env *env, struct ir_function *fun) -{ - if (env->opts.disable_prog_check) { - return; - } - // CG IR check - // Available to run while dst is maintained - - print_ir_err_init(fun); - - check_insn_users_use_insn_cg(env, fun->sp); - for (u8 i = 0; i < BPF_REG_10; ++i) { - check_insn_users_use_insn_cg(env, fun->cg_info.regs[i]); - } - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - // Check dst - if (insn->op == IR_INSN_PHI) { - print_ir_insn_err_full(env, insn, - "Phi instruction", - print_ir_dst); - RAISE_ERROR("Phi instruction found during CG"); - } - if (insn_cg(insn)->dst.type == IR_VALUE_INSN) { - // Check users of this instruction - check_insn_users_use_insn_cg(env, insn); - } else { - if (insn_cg(insn)->dst.type != IR_VALUE_UNDEF) { - print_ir_insn_err_full(env, insn, - "Instruction", - print_ir_dst); - RAISE_ERROR( - "Instruction's dst is incorrect value"); - } - // dst == NULL - // There should be no users! - if (insn->users.num_elem > 0) { - print_ir_insn_err_full(env, insn, - "Instruction", - print_ir_dst); - RAISE_ERROR( - "NULL dst Instruction has users"); - } - } - // Check operands of this instruction - check_insn_operand_cg(env, insn); - } - } -} - -static bool check_need_spill(struct bpf_ir_env *env, struct ir_function *fun) -{ - bool need_modify = false; // Need to modify the IR - // Check if all instruction values are OK for translating - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn, *tmp; - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, - list_ptr) { - if (insn->op == IR_INSN_ALLOC) { - // dst = alloc - // Nothing to do - } else if (insn->op == IR_INSN_ALLOCARRAY) { - // Nothing to do - } else if (insn->op == IR_INSN_GETELEMPTR) { - need_modify |= spill_getelemptr(env, fun, insn); - } else if (insn->op == IR_INSN_STORE) { - need_modify |= spill_store(env, fun, insn); - } else if (insn->op == IR_INSN_LOAD) { - need_modify |= spill_load(env, fun, insn); - } else if (insn->op == IR_INSN_LOADRAW) { - need_modify |= spill_loadraw(env, fun, insn); - } else if (insn->op == IR_INSN_LOADIMM_EXTRA) { - need_modify |= - spill_loadrawextra(env, fun, insn); - } else if (insn->op == IR_INSN_STORERAW) { - need_modify |= spill_storeraw(env, fun, insn); - } else if (insn->op == IR_INSN_NEG) { - need_modify |= spill_neg(env, fun, insn); - } else if (insn->op == IR_INSN_HTOBE || - insn->op == IR_INSN_HTOLE) { - need_modify |= spill_end(env, fun, insn); - } else if (bpf_ir_is_bin_alu(insn)) { - need_modify |= spill_alu(env, fun, insn); - } else if (insn->op == IR_INSN_ASSIGN) { - need_modify |= spill_assign(env, fun, insn); - } else if (insn->op == IR_INSN_RET) { - // ret const/reg - // Done in explicit_reg pass - DBGASSERT(insn->value_num == 0); - } else if (insn->op == IR_INSN_CALL) { - // call() - // Should have no arguments - DBGASSERT(insn->value_num == 0); - } else if (insn->op == IR_INSN_JA) { - // OK - } else if (bpf_ir_is_cond_jmp(insn)) { - need_modify |= spill_cond_jump(env, fun, insn); - } else { - RAISE_ERROR_RET("No such instruction", false); - } - CHECK_ERR(false); - } - } - return need_modify; -} - -static void calc_callee_num(struct ir_function *fun) -{ - u8 reg_used[MAX_BPF_REG] = { 0 }; - - struct ir_insn **pos; - array_for(pos, fun->cg_info.all_var) - { - struct ir_insn_cg_extra *extra = insn_cg(*pos); - reg_used[extra->alloc_reg] = 1; - } - size_t off = 0; - for (u8 i = BPF_REG_6; i < BPF_REG_10; ++i) { - if (reg_used[i]) { - off++; - } - } - fun->cg_info.callee_num = off; -} - -static void calc_stack_size(struct ir_function *fun) -{ - // Check callee - s32 off = 0; - if (fun->cg_info.spill_callee) { - off -= fun->cg_info.callee_num * 8; - } - // Check all VR - s32 max = 0; - struct ir_insn **pos; - array_for(pos, fun->cg_info.all_var) - { - struct ir_insn_cg_extra *extra = insn_cg(*pos); - if (extra->spilled) { - // Spilled! - if (extra->spilled < max) { - max = extra->spilled; - } - } - } - fun->cg_info.stack_offset = off + max; - // PRINT_DBG("Stack size: %d\n", fun->cg_info.stack_offset); -} - -static void add_stack_offset(struct bpf_ir_env *env, struct ir_function *fun, - s16 offset) -{ - struct ir_basic_block **pos; - // For each BB - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn; - // For each operation - list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { - if (insn->op == IR_INSN_LOADRAW || - insn->op == IR_INSN_STORERAW) { - if (insn->addr_val.offset_type == - IR_VALUE_CONSTANT_RAWOFF) { - insn->addr_val.offset += offset; - insn->addr_val.offset_type = - IR_VALUE_CONSTANT; - continue; - } else if (insn->addr_val.offset_type == - IR_VALUE_CONSTANT_RAWOFF_REV) { - insn->addr_val.offset -= offset; - insn->addr_val.offset_type = - IR_VALUE_CONSTANT; - continue; - } - } - struct array value_uses = - bpf_ir_get_operands(env, insn); - struct ir_value **pos2; - array_for(pos2, value_uses) - { - struct ir_value *val = *pos2; - if (val->type == IR_VALUE_CONSTANT_RAWOFF) { - // Stack pointer as value - val->data.constant_d += offset; - val->type = IR_VALUE_CONSTANT; - } else if (val->type == - IR_VALUE_CONSTANT_RAWOFF_REV) { - val->data.constant_d -= offset; - val->type = IR_VALUE_CONSTANT; - } - } - bpf_ir_array_free(&value_uses); - } - } -} - -static struct pre_ir_insn translate_reg_to_reg(u8 dst, u8 src) -{ - // MOV dst src - struct pre_ir_insn insn = { 0 }; - insn.opcode = BPF_MOV | BPF_X | BPF_ALU64; - insn.dst_reg = dst; - insn.src_reg = src; - insn.imm = 0; - return insn; -} - -static struct pre_ir_insn translate_const_to_reg(u8 dst, s64 data, - enum ir_alu_op_type type) -{ - // MOV dst imm - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - if (type == IR_ALU_32) { - insn.opcode = BPF_MOV | BPF_K | BPF_ALU; - } else { - // Default is imm64 - insn.opcode = BPF_MOV | BPF_K | BPF_ALU64; - } - insn.imm = data; - return insn; -} - -static int vr_type_to_size(enum ir_vr_type type) -{ - switch (type) { - case IR_VR_TYPE_32: - return BPF_W; - case IR_VR_TYPE_16: - return BPF_H; - case IR_VR_TYPE_8: - return BPF_B; - case IR_VR_TYPE_64: - return BPF_DW; - default: - CRITICAL("Error"); - } -} - -static struct pre_ir_insn load_addr_to_reg(u8 dst, struct ir_address_value addr, - enum ir_vr_type type) -{ - // MOV dst src - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - insn.off = addr.offset; - int size = vr_type_to_size(type); - if (addr.value.type == IR_VALUE_INSN) { - // Must be REG - DBGASSERT(vtype(addr.value) == REG); - // Load reg (addr) to reg - insn.src_reg = insn_cg(addr.value.data.insn_d)->alloc_reg; - insn.opcode = BPF_LDX | size | BPF_MEM; - } else if (addr.value.type == IR_VALUE_CONSTANT) { - // Must be U64 - insn.it = IMM64; - insn.imm64 = addr.value.data.constant_d; - insn.opcode = size; - // Simplify the opcode to reduce compiler warning, the real opcode is as follows - // (but BPF_MM and BPF_LD are all 0) - // insn.opcode = BPF_IMM | size | BPF_LD; - } else { - CRITICAL("Error"); - } - return insn; -} - -static struct pre_ir_insn store_reg_to_reg_mem(u8 dst, u8 src, s16 offset, - enum ir_vr_type type) -{ - struct pre_ir_insn insn = { 0 }; - int size = vr_type_to_size(type); - insn.src_reg = src; - insn.off = offset; - insn.opcode = BPF_STX | size | BPF_MEM; - insn.dst_reg = dst; - return insn; -} - -static struct pre_ir_insn store_const_to_reg_mem(u8 dst, s64 val, s16 offset, - enum ir_vr_type type) -{ - struct pre_ir_insn insn = { 0 }; - int size = vr_type_to_size(type); - insn.it = IMM; - insn.imm = val; - insn.off = offset; - insn.opcode = BPF_ST | size | BPF_MEM; - insn.dst_reg = dst; - return insn; -} - -static int end_code(enum ir_insn_type insn) -{ - if (insn == IR_INSN_HTOBE) { - return BPF_TO_BE; - } else if (insn == IR_INSN_HTOLE) { - return BPF_TO_LE; - } else { - CRITICAL("Error"); - } -} - -static int alu_code(enum ir_insn_type insn) -{ - switch (insn) { - case IR_INSN_NEG: - return BPF_NEG; - case IR_INSN_ADD: - return BPF_ADD; - case IR_INSN_SUB: - return BPF_SUB; - case IR_INSN_MUL: - return BPF_MUL; - case IR_INSN_DIV: - return BPF_DIV; - case IR_INSN_OR: - return BPF_OR; - case IR_INSN_AND: - return BPF_AND; - case IR_INSN_MOD: - return BPF_MOD; - case IR_INSN_XOR: - return BPF_XOR; - case IR_INSN_LSH: - return BPF_LSH; - case IR_INSN_ARSH: - return BPF_ARSH; - case IR_INSN_RSH: - return BPF_RSH; - default: - CRITICAL("Error"); - } -} - -static int jmp_code(enum ir_insn_type insn) -{ - switch (insn) { - case IR_INSN_JA: - return BPF_JA; - case IR_INSN_JEQ: - return BPF_JEQ; - case IR_INSN_JNE: - return BPF_JNE; - case IR_INSN_JLT: - return BPF_JLT; - case IR_INSN_JLE: - return BPF_JLE; - case IR_INSN_JGT: - return BPF_JGT; - case IR_INSN_JGE: - return BPF_JGE; - case IR_INSN_JSGT: - return BPF_JSGT; - case IR_INSN_JSLT: - return BPF_JSLT; - default: - CRITICAL("Error"); - } -} - -static struct pre_ir_insn alu_reg(u8 dst, u8 src, enum ir_alu_op_type type, - int opcode) -{ - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - insn.src_reg = src; - int alu_class = type == IR_ALU_64 ? BPF_ALU64 : BPF_ALU; - insn.opcode = opcode | BPF_X | alu_class; - return insn; -} - -static struct pre_ir_insn alu_neg(u8 dst, enum ir_alu_op_type type) -{ - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - int alu_class = type == IR_ALU_64 ? BPF_ALU64 : BPF_ALU; - insn.opcode = BPF_NEG | BPF_K | alu_class; - return insn; -} - -static struct pre_ir_insn alu_end(u8 dst, s32 swap_width, int enty) -{ - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - insn.opcode = enty | BPF_END | BPF_ALU; - insn.imm = swap_width; - return insn; -} - -static struct pre_ir_insn alu_imm(u8 dst, s64 src, enum ir_alu_op_type type, - int opcode) -{ - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - int alu_class = type == IR_ALU_64 ? BPF_ALU64 : BPF_ALU; - insn.it = IMM; - insn.imm = src; - insn.opcode = opcode | BPF_K | alu_class; - return insn; -} - -static struct pre_ir_insn cond_jmp_reg(u8 dst, u8 src, enum ir_alu_op_type type, - int opcode) -{ - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - insn.src_reg = src; - int alu_class = type == IR_ALU_64 ? BPF_JMP : BPF_JMP32; - insn.opcode = opcode | alu_class | BPF_X; - return insn; -} - -static struct pre_ir_insn cond_jmp_imm(u8 dst, s64 src, - enum ir_alu_op_type type, int opcode) -{ - struct pre_ir_insn insn = { 0 }; - insn.dst_reg = dst; - int alu_class = type == IR_ALU_64 ? BPF_JMP : BPF_JMP32; - insn.it = IMM; - insn.imm = src; - insn.opcode = opcode | alu_class | BPF_K; - return insn; -} - -static u8 get_alloc_reg(struct ir_insn *insn) -{ - return insn_cg(insn)->alloc_reg; -} - -static void translate_loadraw(struct ir_insn *insn) -{ - enum val_type tdst = vtype_insn(insn); - struct ir_insn_cg_extra *extra = insn_cg(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - extra->translated[0] = load_addr_to_reg(get_alloc_reg(dst_insn), - insn->addr_val, insn->vr_type); -} - -static void translate_loadimm_extra(struct ir_insn *insn) -{ - enum val_type tdst = vtype_insn(insn); - struct ir_insn_cg_extra *extra = insn_cg(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - extra->translated[0].opcode = BPF_IMM | BPF_LD | BPF_DW; - DBGASSERT(insn->imm_extra_type <= 0x6); - extra->translated[0].src_reg = insn->imm_extra_type; - extra->translated[0].dst_reg = get_alloc_reg(dst_insn); - // 0 2 6 needs next - extra->translated[0].it = IMM64; - extra->translated[0].imm64 = insn->imm64; -} - -static void translate_storeraw(struct ir_insn *insn) -{ - struct ir_value v0 = insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; - struct ir_insn_cg_extra *extra = insn_cg(insn); - // storeraw - if (insn->addr_val.value.type == IR_VALUE_INSN) { - // Store value in (address in the value) - DBGASSERT(vtype(insn->addr_val.value) == REG); - // Store value in the stack - if (t0 == REG) { - extra->translated[0] = store_reg_to_reg_mem( - get_alloc_reg(insn->addr_val.value.data.insn_d), - get_alloc_reg(v0.data.insn_d), - insn->addr_val.offset, insn->vr_type); - } else if (t0 == CONST) { - extra->translated[0] = store_const_to_reg_mem( - get_alloc_reg(insn->addr_val.value.data.insn_d), - v0.data.constant_d, insn->addr_val.offset, - insn->vr_type); - } else { - CRITICAL("Error"); - } - } else { - CRITICAL("Error"); - } -} - -static void translate_alu(struct ir_insn *insn) -{ - struct ir_value v0 = insn->values[0]; - struct ir_value v1 = insn->values[1]; - enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; - enum val_type t1 = insn->value_num >= 2 ? vtype(v1) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn_cg_extra *extra = insn_cg(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - DBGASSERT(t0 == REG); - DBGASSERT(get_alloc_reg(dst_insn) == get_alloc_reg(v0.data.insn_d)); - if (t1 == REG) { - extra->translated[0] = alu_reg(get_alloc_reg(dst_insn), - get_alloc_reg(v1.data.insn_d), - insn->alu_op, - alu_code(insn->op)); - } else if (t1 == CONST) { - // Remove the instruction in some special cases - if (insn->op == IR_INSN_ADD && v1.data.constant_d == 0) { - extra->translated_num = 0; - return; - } - extra->translated[0] = alu_imm(get_alloc_reg(dst_insn), - v1.data.constant_d, insn->alu_op, - alu_code(insn->op)); - } else { - CRITICAL("Error"); - } -} - -static void translate_assign(struct ir_insn *insn) -{ - struct ir_value v0 = insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn_cg_extra *extra = insn_cg(insn); - struct ir_insn *dst_insn = insn_dst(insn); - - // reg = const (alu) - // reg = reg - if (tdst == REG && t0 == CONST) { - extra->translated[0] = translate_const_to_reg( - get_alloc_reg(dst_insn), v0.data.constant_d, - insn->alu_op); - } else if (tdst == REG && t0 == REG) { - if (get_alloc_reg(dst_insn) == get_alloc_reg(v0.data.insn_d)) { - // Remove the instruction - extra->translated_num = 0; - return; - } - extra->translated[0] = translate_reg_to_reg( - get_alloc_reg(dst_insn), get_alloc_reg(v0.data.insn_d)); - } else { - CRITICAL("Error"); - } -} - -static void translate_ret(struct ir_insn *insn) -{ - struct ir_insn_cg_extra *extra = insn_cg(insn); - extra->translated[0].opcode = BPF_EXIT | BPF_JMP; -} - -static void translate_call(struct ir_insn *insn) -{ - struct ir_insn_cg_extra *extra = insn_cg(insn); - // Currently only support local helper functions - extra->translated[0].opcode = BPF_CALL | BPF_JMP; - extra->translated[0].it = IMM; - extra->translated[0].imm = insn->fid; -} - -static void translate_ja(struct ir_insn *insn) -{ - struct ir_insn_cg_extra *extra = insn_cg(insn); - extra->translated[0].opcode = BPF_JMP | BPF_JA; -} - -static void translate_neg(struct ir_insn *insn) -{ - struct ir_value v0 = insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn_cg_extra *extra = insn_cg(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG && t0 == REG); - DBGASSERT(get_alloc_reg(dst_insn) == get_alloc_reg(v0.data.insn_d)); - extra->translated[0] = alu_neg(get_alloc_reg(dst_insn), insn->alu_op); -} - -static void translate_end(struct ir_insn *insn) -{ - struct ir_value v0 = insn->values[0]; - enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; - enum val_type tdst = vtype_insn(insn); - struct ir_insn_cg_extra *extra = insn_cg(insn); - struct ir_insn *dst_insn = insn_dst(insn); - DBGASSERT(tdst == REG); - DBGASSERT(t0 == REG); - DBGASSERT(get_alloc_reg(dst_insn) == get_alloc_reg(v0.data.insn_d)); - extra->translated[0] = alu_end(get_alloc_reg(dst_insn), - insn->swap_width, end_code(insn->op)); -} - -static void translate_cond_jmp(struct ir_insn *insn) -{ - struct ir_value v0 = insn->values[0]; - struct ir_value v1 = insn->values[1]; - enum val_type t0 = insn->value_num >= 1 ? vtype(v0) : UNDEF; - enum val_type t1 = insn->value_num >= 2 ? vtype(v1) : UNDEF; - struct ir_insn_cg_extra *extra = insn_cg(insn); - DBGASSERT(t0 == REG || t1 == REG); - if (t0 == REG) { - if (t1 == REG) { - extra->translated[0] = - cond_jmp_reg(get_alloc_reg(v0.data.insn_d), - get_alloc_reg(v1.data.insn_d), - insn->alu_op, jmp_code(insn->op)); - } else if (t1 == CONST) { - if (v1.const_type == IR_ALU_64) { - CRITICAL("TODO"); - } - extra->translated[0] = - cond_jmp_imm(get_alloc_reg(v0.data.insn_d), - v1.data.constant_d, insn->alu_op, - jmp_code(insn->op)); - } else { - CRITICAL("Error"); - } - } else { - DBGASSERT(t0 == CONST); - DBGASSERT(t1 == REG); - CRITICAL("TODO"); - // Probably we could switch? - extra->translated[0] = cond_jmp_imm( - get_alloc_reg(v1.data.insn_d), v0.data.constant_d, - insn->alu_op, jmp_code(insn->op)); - } -} - -static u32 bb_insn_cnt(struct ir_basic_block *bb) -{ - u32 cnt = 0; - struct ir_insn *insn, *tmp; - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, list_ptr) { - if (insn->op == IR_INSN_ALLOC || - insn->op == IR_INSN_ALLOCARRAY) { - continue; - } else { - cnt++; - } - } - return cnt; -} - -static u32 bb_insn_critical_cnt(struct ir_basic_block *bb) -{ - u32 cnt = bb_insn_cnt(bb); - while (bb->preds.num_elem <= 1) { - if (bb->preds.num_elem == 0) { - break; - } - struct ir_basic_block **tmp = - bpf_ir_array_get_void(&bb->preds, 0); - bb = *tmp; - if (bb->flag & IR_BB_HAS_COUNTER) { - break; - } - cnt += bb_insn_cnt(bb); - } - return cnt; -} - -static void replace_builtin_const(struct bpf_ir_env *env, - struct ir_function *fun) -{ - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn, *tmp; - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, - list_ptr) { - struct array operands = bpf_ir_get_operands(env, insn); - struct ir_value **val; - array_for(val, operands) - { - struct ir_value *v = *val; - if (v->type == IR_VALUE_CONSTANT) { - if (v->builtin_const == - IR_BUILTIN_BB_INSN_CNT) { - v->data.constant_d = - bb_insn_cnt(bb); - } - if (v->builtin_const == - IR_BUILTIN_BB_INSN_CRITICAL_CNT) { - v->data.constant_d = - bb_insn_critical_cnt( - bb); - } - } - } - bpf_ir_array_free(&operands); - } - } -} - -static void check_total_insn(struct bpf_ir_env *env, struct ir_function *fun) -{ - u32 cnt = 0; - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn, *tmp; - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, - list_ptr) { - struct ir_insn_cg_extra *extra = insn_cg(insn); - cnt += extra->translated_num; - } - } - if (cnt >= 1000000) { - RAISE_ERROR("Too many instructions"); - } -} - -static void translate(struct bpf_ir_env *env, struct ir_function *fun) -{ - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn, *tmp; - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, - list_ptr) { - struct ir_insn_cg_extra *extra = insn_cg(insn); - extra->translated_num = 1; // Default: 1 instruction - if (insn->op == IR_INSN_ALLOC) { - // Nothing to do - extra->translated_num = 0; - } else if (insn->op == IR_INSN_ALLOCARRAY) { - // Nothing to do - extra->translated_num = 0; - } else if (insn->op == IR_INSN_STORE) { - CRITICAL("Error"); - } else if (insn->op == IR_INSN_LOAD) { - CRITICAL("Error"); - } else if (insn->op == IR_INSN_GETELEMPTR) { - CRITICAL("Error"); - } else if (insn->op == IR_INSN_LOADRAW) { - translate_loadraw(insn); - } else if (insn->op == IR_INSN_LOADIMM_EXTRA) { - translate_loadimm_extra(insn); - } else if (insn->op == IR_INSN_STORERAW) { - translate_storeraw(insn); - } else if (insn->op == IR_INSN_NEG) { - translate_neg(insn); - } else if (insn->op == IR_INSN_HTOBE || - insn->op == IR_INSN_HTOLE) { - translate_end(insn); - } else if (bpf_ir_is_bin_alu(insn)) { - translate_alu(insn); - } else if (insn->op == IR_INSN_ASSIGN) { - translate_assign(insn); - } else if (insn->op == IR_INSN_RET) { - translate_ret(insn); - } else if (insn->op == IR_INSN_CALL) { - translate_call(insn); - } else if (insn->op == IR_INSN_JA) { - translate_ja(insn); - } else if (bpf_ir_is_cond_jmp(insn)) { - translate_cond_jmp(insn); - } else { - RAISE_ERROR("No such instruction"); - } - } - } -} - -// Spill all `allocarray` instructions -static void spill_array(struct bpf_ir_env *env, struct ir_function *fun) -{ - u32 offset = 0; - struct ir_basic_block **pos; - array_for(pos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *pos; - struct ir_insn *insn, *tmp; - list_for_each_entry_safe(insn, tmp, &bb->ir_insn_head, - list_ptr) { - if (insn->op == IR_INSN_ALLOCARRAY) { - struct ir_insn_cg_extra *extra = insn_cg(insn); - DBGASSERT(extra->dst.data.insn_d == - insn); // Ensure the dst is correct - extra->allocated = true; - // Calculate the offset - u32 size = insn->array_num * - bpf_ir_sizeof_vr_type(insn->vr_type); - if (size == 0) { - RAISE_ERROR("Array size is 0"); - } - offset -= (((size - 1) / 8) + 1) * 8; - extra->spilled = offset; - extra->spilled_size = size; - extra->nonvr = true; // Array is not a VR - } - } - } -} - -// static void vreg_to_rreg(struct bpf_ir_env *env, struct ir_function *fun) -// { -// // Change all virtual registers to real registers -// // Make sure the VRs are all allocated -// // TODO -// } - -// Interface Implementation - -void bpf_ir_compile(struct bpf_ir_env *env, struct ir_function *fun) -{ - u64 starttime = get_cur_time_ns(); - // Init CG, start code generation - init_cg(env, fun); - CHECK_ERR(); - - // Debugging settings - fun->cg_info.spill_callee = 0; - - // Step 4: SSA Destruction - remove_phi(env, fun); - CHECK_ERR(); - print_ir_prog_cg_dst(env, fun, "PHI Removal"); - prog_check_cg(env, fun); - CHECK_ERR(); - - // No more users, SSA structure is destroyed - - change_ret(env, fun); - CHECK_ERR(); - print_ir_prog_cg_dst(env, fun, "Changing ret"); - prog_check_cg(env, fun); - CHECK_ERR(); - - change_call(env, fun); - CHECK_ERR(); - print_ir_prog_cg_dst(env, fun, "Changing calls"); - CHECK_ERR(); - prog_check_cg(env, fun); - CHECK_ERR(); - - spill_array(env, fun); - CHECK_ERR(); - print_ir_prog_cg_dst(env, fun, "Spilling Arrays"); - CHECK_ERR(); - prog_check_cg(env, fun); - CHECK_ERR(); - - // print_ir_prog_reachable(fun); - - bool need_spill = true; - int iterations = 0; - - while (need_spill) { - PRINT_LOG_DEBUG( - env, - "\x1B[32m----- Register allocation iteration %d -----\x1B[0m\n", - iterations); - iterations++; - // Step 5: Liveness Analysis - liveness_analysis(env, fun); - CHECK_ERR(); - - // Step 6: Conflict Analysis - conflict_analysis(env, fun); - CHECK_ERR(); - if (env->opts.verbose > 2) { - PRINT_LOG_DEBUG(env, "Conflicting graph:\n"); - bpf_ir_print_interference_graph(env, fun); - } - - // Step 7: Graph coloring - graph_coloring(env, fun); - CHECK_ERR(); - - if (env->opts.verbose > 2) { - PRINT_LOG_DEBUG( - env, "Conflicting graph (after coloring):\n"); - bpf_ir_print_interference_graph(env, fun); - } - CHECK_ERR(); - print_ir_prog_cg_alloc(env, fun, "After RA"); - - if (env->opts.enable_coalesce) { - bool need_rerun = coalescing(env, fun); - CHECK_ERR(); - if (need_rerun) { - PRINT_LOG_DEBUG(env, "Need to re-analyze...\n"); - clean_cg(env, fun); - CHECK_ERR(); - continue; - } - prog_check_cg(env, fun); - CHECK_ERR(); - print_ir_prog_cg_dst(env, fun, - "After Coalescing (dst)"); - print_ir_prog_cg_alloc(env, fun, - "After Coalescing (reg)"); - } - - // Step 8: Check if need to spill and spill - need_spill = check_need_spill(env, fun); - CHECK_ERR(); - print_ir_prog_cg_alloc(env, fun, "Spilling"); - CHECK_ERR(); - prog_check_cg(env, fun); - CHECK_ERR(); - - // print_ir_prog_cg_dst(env, fun, "After Spilling"); - if (need_spill) { - // Still need to spill - PRINT_LOG_DEBUG(env, "Need to spill...\n"); - clean_cg(env, fun); - CHECK_ERR(); - } - } - - // Register allocation finished (All registers are fixed) - PRINT_LOG_DEBUG(env, "Register allocation finished in %d iterations\n", - iterations); - print_ir_prog_cg_alloc(env, fun, "After RA & Spilling"); - // Step 9: Calculate stack size - if (fun->cg_info.spill_callee) { - calc_callee_num(fun); - } - calc_stack_size(fun); - - // Step 10: Shift raw stack operations - add_stack_offset(env, fun, fun->cg_info.stack_offset); - CHECK_ERR(); - print_ir_prog_cg_alloc(env, fun, "Shifting stack access"); - prog_check_cg(env, fun); - CHECK_ERR(); - - // Step 11: Spill callee saved registers - if (fun->cg_info.spill_callee) { - spill_callee(env, fun); - CHECK_ERR(); - print_ir_prog_cg_alloc(env, fun, "Spilling callee-saved regs"); - prog_check_cg(env, fun); - CHECK_ERR(); - } - // Step 12: Normalize - normalize(env, fun); - CHECK_ERR(); - print_ir_prog_cg_alloc(env, fun, "Normalization"); - // prog_check_cg(env, fun); - // CHECK_ERR(); - - replace_builtin_const(env, fun); - CHECK_ERR(); - - // Step 13: Direct Translation - translate(env, fun); - CHECK_ERR(); - - check_total_insn(env, fun); - CHECK_ERR(); - - // Step 14: Relocation - relocate(env, fun); - CHECK_ERR(); - - // Step 15: Synthesize - synthesize(env, fun); - CHECK_ERR(); - - // Free CG resources - free_cg_res(fun); - env->cg_time += get_cur_time_ns() - starttime; -} - -void bpf_ir_init_insn_cg(struct bpf_ir_env *env, struct ir_insn *insn) -{ - struct ir_insn_cg_extra *extra = NULL; - SAFE_MALLOC(extra, sizeof(struct ir_insn_cg_extra)); - insn->user_data = extra; - // When init, the destination is itself - extra->dst = bpf_ir_value_undef(); - if (!bpf_ir_is_void(insn)) { - set_insn_dst(env, insn, insn); - } - - INIT_ARRAY(&extra->adj, struct ir_insn *); - extra->allocated = false; - extra->spilled = 0; - extra->alloc_reg = 0; - INIT_ARRAY(&extra->gen, struct ir_insn *); - INIT_ARRAY(&extra->kill, struct ir_insn *); - INIT_ARRAY(&extra->in, struct ir_insn *); - INIT_ARRAY(&extra->out, struct ir_insn *); - extra->translated_num = 0; - extra->nonvr = false; -} diff --git a/kernel/bpf/ir/ir_helper.c b/kernel/bpf/ir/ir_helper.c index 8b7eca708..e680f57aa 100644 --- a/kernel/bpf/ir/ir_helper.c +++ b/kernel/bpf/ir/ir_helper.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" +#include "ir_cg.h" int bpf_ir_valid_alu_type(enum ir_alu_op_type type) { @@ -72,7 +73,7 @@ void print_insn_ptr_base(struct bpf_ir_env *env, struct ir_insn *insn) PRINT_LOG_DEBUG(env, "arg%u", insn->fun_arg_id); return; } - if (insn->_insn_id == SIZET_MAX) { + if (insn->_insn_id == (size_t)(-1)) { PRINT_LOG_DEBUG(env, "%p", insn); return; } @@ -152,6 +153,19 @@ static void print_ir_rawpos(struct bpf_ir_env *env, struct ir_raw_pos pos) } } +static void print_vr_pos(struct bpf_ir_env *env, struct ir_vr_pos *pos) +{ + if (pos->allocated) { + if (pos->spilled) { + PRINT_LOG_DEBUG(env, "sp+%d", pos->spilled); + } else { + PRINT_LOG_DEBUG(env, "r%u", pos->alloc_reg); + } + } else { + PRINT_LOG_DEBUG(env, "(NULL)"); + } +} + static void print_ir_value_full(struct bpf_ir_env *env, struct ir_value v, void (*print_ir)(struct bpf_ir_env *env, struct ir_insn *)) @@ -176,6 +190,9 @@ static void print_ir_value_full(struct bpf_ir_env *env, struct ir_value v, case IR_VALUE_UNDEF: PRINT_LOG_DEBUG(env, "undef"); break; + case IR_VALUE_FLATTEN_DST: + print_vr_pos(env, &v.data.vr_pos); + break; default: RAISE_ERROR("Unknown IR value type"); } @@ -309,9 +326,9 @@ static void print_cond_jmp(struct bpf_ir_env *env, struct ir_insn *insn, /** Print the IR insn */ -void print_ir_insn_full(struct bpf_ir_env *env, struct ir_insn *insn, - void (*print_ir)(struct bpf_ir_env *env, - struct ir_insn *)) +static void print_ir_insn_full(struct bpf_ir_env *env, struct ir_insn *insn, + void (*print_ir)(struct bpf_ir_env *env, + struct ir_insn *)) { switch (insn->op) { case IR_INSN_ALLOC: @@ -445,6 +462,12 @@ void print_ir_insn_full(struct bpf_ir_env *env, struct ir_insn *insn, case IR_INSN_JNE: print_cond_jmp(env, insn, print_ir, "jne"); break; + case IR_INSN_JSGE: + print_cond_jmp(env, insn, print_ir, "jsge"); + break; + case IR_INSN_JSLE: + print_cond_jmp(env, insn, print_ir, "jsle"); + break; case IR_INSN_JSGT: print_cond_jmp(env, insn, print_ir, "jsgt"); break; @@ -458,6 +481,9 @@ void print_ir_insn_full(struct bpf_ir_env *env, struct ir_insn *insn, case IR_INSN_ASSIGN: print_ir_value_full(env, insn->values[0], print_ir); break; + case IR_INSN_REG: + PRINT_LOG_DEBUG(env, "(REG)"); + break; default: PRINT_LOG_ERROR(env, "Insn code: %d\n", insn->op); CRITICAL("Unknown IR insn"); @@ -525,32 +551,19 @@ void print_ir_bb_no_rec( } } -void print_ir_bb(struct bpf_ir_env *env, struct ir_basic_block *bb, +void print_ir_bb(struct bpf_ir_env *env, struct ir_function *fun, void (*post_bb)(struct bpf_ir_env *env, struct ir_basic_block *), void (*post_insn)(struct bpf_ir_env *env, struct ir_insn *), void (*print_insn_name)(struct bpf_ir_env *env, struct ir_insn *)) -{ - if (bb->_visited) { - return; - } - bb->_visited = 1; - print_ir_bb_no_rec(env, bb, post_bb, post_insn, print_insn_name); - for (size_t i = 0; i < bb->succs.num_elem; ++i) { - struct ir_basic_block *next = - ((struct ir_basic_block **)(bb->succs.data))[i]; - print_ir_bb(env, next, post_bb, post_insn, print_insn_name); - } -} - -void print_ir_prog_reachable(struct bpf_ir_env *env, struct ir_function *fun) { struct ir_basic_block **pos; array_for(pos, fun->reachable_bbs) { struct ir_basic_block *bb = *pos; - print_ir_bb_no_rec(env, bb, NULL, NULL, NULL); + print_ir_bb_no_rec(env, bb, post_bb, post_insn, + print_insn_name); } } @@ -618,45 +631,19 @@ void print_bb_succ(struct bpf_ir_env *env, struct ir_basic_block *bb) void print_ir_prog(struct bpf_ir_env *env, struct ir_function *fun) { tag_ir(fun); - print_ir_bb(env, fun->entry, NULL, NULL, NULL); + print_ir_bb(env, fun, NULL, NULL, NULL); } void print_ir_prog_notag(struct bpf_ir_env *env, struct ir_function *fun) { - print_ir_bb(env, fun->entry, NULL, NULL, NULL); -} - -void print_ir_dst(struct bpf_ir_env *env, struct ir_insn *insn) -{ - if (!insn_cg(insn)) { - PRINT_LOG_DEBUG(env, "(?)"); - RAISE_ERROR("NULL userdata found"); - } - insn = insn_dst(insn); - if (insn) { - print_insn_ptr_base(env, insn); - } else { - PRINT_LOG_DEBUG(env, "(NULL)"); - } + print_ir_bb(env, fun, NULL, NULL, NULL); } -void print_ir_alloc(struct bpf_ir_env *env, struct ir_insn *insn) +void print_ir_flatten(struct bpf_ir_env *env, struct ir_insn *insn) { - insn = insn_dst(insn); - if (insn) { - struct ir_insn_cg_extra *extra = insn_cg(insn); - if (extra->allocated) { - if (extra->spilled) { - PRINT_LOG_DEBUG(env, "sp+%d", extra->spilled); - } else { - PRINT_LOG_DEBUG(env, "r%u", extra->alloc_reg); - } - } else { - RAISE_ERROR("Not allocated"); - } - } else { - PRINT_LOG_DEBUG(env, "(NULL)"); - } + struct ir_insn_norm_extra *norm = insn_norm(insn); + struct ir_vr_pos *pos = &norm->pos; + print_vr_pos(env, pos); } void print_ir_prog_advanced( @@ -666,7 +653,7 @@ void print_ir_prog_advanced( void (*print_insn_name)(struct bpf_ir_env *env, struct ir_insn *)) { tag_ir(fun); - print_ir_bb(env, fun->entry, post_bb, post_insn, print_insn_name); + print_ir_bb(env, fun, post_bb, post_insn, print_insn_name); } void print_ir_insn_err_full(struct bpf_ir_env *env, struct ir_insn *insn, diff --git a/kernel/bpf/ir/ir_insn.c b/kernel/bpf/ir/ir_insn.c index 1d4b42cd6..ba37099bc 100644 --- a/kernel/bpf/ir/ir_insn.c +++ b/kernel/bpf/ir/ir_insn.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" +#include "ir_cg.h" struct ir_insn *bpf_ir_create_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb) @@ -32,6 +33,34 @@ struct ir_insn *bpf_ir_create_insn_base_cg(struct bpf_ir_env *env, return new_insn; } +void bpf_ir_init_insn_norm(struct bpf_ir_env *env, struct ir_insn *insn, + struct ir_vr_pos pos) +{ + struct ir_insn_norm_extra *extra = NULL; + SAFE_MALLOC(extra, sizeof(struct ir_insn_norm_extra)); + insn->user_data = extra; + extra->pos = pos; +} + +struct ir_insn *bpf_ir_create_insn_base_norm(struct bpf_ir_env *env, + struct ir_basic_block *bb, + struct ir_vr_pos dstpos) +{ + struct ir_insn *new_insn = malloc_proto(sizeof(struct ir_insn)); + if (!new_insn) { + env->err = -ENOMEM; + PRINT_LOG_DEBUG(env, "Failed to allocate memory for ir_insn\n"); + return NULL; + } + new_insn->parent_bb = bb; + new_insn->users = bpf_ir_array_null(); // Do not allocate new users + new_insn->value_num = 0; + + bpf_ir_init_insn_norm(env, new_insn, dstpos); + CHECK_ERR(NULL); + return new_insn; +} + void bpf_ir_replace_operand(struct bpf_ir_env *env, struct ir_insn *insn, struct ir_value v1, struct ir_value v2) { @@ -70,31 +99,6 @@ void bpf_ir_replace_all_usage(struct bpf_ir_env *env, struct ir_insn *insn, bpf_ir_array_free(&users); } -void bpf_ir_replace_all_usage_cg(struct bpf_ir_env *env, struct ir_insn *insn, - struct ir_value rep) -{ - struct ir_insn **pos; - struct array users = insn->users; - INIT_ARRAY(&insn->users, struct ir_insn *); - array_for(pos, users) - { - struct ir_insn *user = *pos; - struct array operands = bpf_ir_get_operands_and_dst(env, user); - struct ir_value **pos2; - array_for(pos2, operands) - { - if ((*pos2)->type == IR_VALUE_INSN && - (*pos2)->data.insn_d == insn) { - // Match, replace - **pos2 = rep; - bpf_ir_val_add_user(env, rep, user); - } - } - bpf_ir_array_free(&operands); - } - bpf_ir_array_free(&users); -} - void bpf_ir_replace_all_usage_except(struct bpf_ir_env *env, struct ir_insn *insn, struct ir_value rep, struct ir_insn *except) @@ -125,6 +129,8 @@ void bpf_ir_replace_all_usage_except(struct bpf_ir_env *env, bpf_ir_array_free(&users); } +// Get all operands of an instruction +// Returns an array of ir_value* struct array bpf_ir_get_operands(struct bpf_ir_env *env, struct ir_insn *insn) { struct array uses; @@ -152,91 +158,11 @@ struct array bpf_ir_get_operands(struct bpf_ir_env *env, struct ir_insn *insn) return uses; } -struct array bpf_ir_get_operands_and_dst(struct bpf_ir_env *env, - struct ir_insn *insn) -{ - struct array uses = bpf_ir_get_operands(env, insn); - struct ir_value *val = &insn_cg(insn)->dst; - bpf_ir_array_push(env, &uses, &val); - return uses; -} - bool bpf_ir_is_last_insn(struct ir_insn *insn) { return insn->parent_bb->ir_insn_head.prev == &insn->list_ptr; } -void bpf_ir_check_no_user(struct bpf_ir_env *env, struct ir_insn *insn) -{ - if (insn->users.num_elem > 0) { - struct ir_insn **pos; - bool fail = false; - array_for(pos, insn->users) - { - if (*pos != insn) { - fail = true; - break; - } - } - if (fail) { - array_for(pos, insn->users) - { - print_ir_insn_err_full(env, *pos, "User", - print_ir_dst); - } - print_ir_insn_err_full(env, insn, "Has users", - print_ir_dst); - RAISE_ERROR( - "Cannot erase a instruction that has (non-self) users"); - } - } -} - -void bpf_ir_erase_insn_cg(struct bpf_ir_env *env, struct ir_function *fun, - struct ir_insn *insn) -{ - bpf_ir_check_no_user(env, insn); - CHECK_ERR(); - struct array operands = bpf_ir_get_operands_and_dst(env, insn); - CHECK_ERR(); - struct ir_value **pos; - array_for(pos, operands) - { - bpf_ir_val_remove_user((**pos), insn); - } - struct ir_insn **pos2; - array_for(pos2, insn_cg(insn)->adj) - { - struct ir_insn **pos3; - size_t idx = 0; - array_for(pos3, insn_cg(*pos2)->adj) - { - // Remove from adj - if (*pos3 == insn) { - bpf_ir_array_erase(&insn_cg(*pos2)->adj, idx); - break; - } - idx++; - } - } - struct ir_insn **pos3; - size_t idx = 0; - array_for(pos3, fun->cg_info.all_var) - { - // Remove from all var - if (*pos3 == insn) { - bpf_ir_array_erase(&fun->cg_info.all_var, idx); - break; - } - idx++; - } - bpf_ir_array_free(&operands); - bpf_ir_free_insn_cg(insn); - list_del(&insn->list_ptr); - bpf_ir_array_free(&insn->users); - free_proto(insn); -} - void bpf_ir_erase_insn(struct bpf_ir_env *env, struct ir_insn *insn) { if (insn->users.num_elem > 0) { @@ -272,9 +198,25 @@ void bpf_ir_erase_insn(struct bpf_ir_env *env, struct ir_insn *insn) free_proto(insn); } +void bpf_ir_erase_insn_norm(struct ir_insn *insn) +{ + list_del(&insn->list_ptr); + bpf_ir_array_free(&insn->users); + struct ir_insn_norm_extra *extra = insn_norm(insn); + if (extra) { + free_proto(extra); + } + free_proto(insn); +} + void bpf_ir_insert_at(struct ir_insn *new_insn, struct ir_insn *insn, enum insert_position pos) { + if (insn->op == IR_INSN_PHI && new_insn->op != IR_INSN_PHI) { + bpf_ir_insert_at_bb(new_insn, insn->parent_bb, + INSERT_FRONT_AFTER_PHI); + return; + } if (pos == INSERT_BACK) { list_add(&new_insn->list_ptr, &insn->list_ptr); } else if (pos == INSERT_FRONT) { @@ -437,6 +379,17 @@ static struct ir_insn *create_alloc_insn_base(struct bpf_ir_env *env, return new_insn; } +static struct ir_insn *create_alloc_insn_base_cg(struct bpf_ir_env *env, + struct ir_basic_block *bb, + enum ir_vr_type type) +{ + struct ir_insn *new_insn = + bpf_ir_create_insn_base_cg(env, bb, IR_INSN_ALLOC); + new_insn->vr_type = type; + new_insn->value_num = 0; + return new_insn; +} + static struct ir_insn *create_allocarray_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, enum ir_vr_type type, @@ -460,13 +413,14 @@ create_loadimmextra_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, new_insn->imm64 = imm; return new_insn; } -static struct ir_insn * -create_loadimmextra_insn_base_cg(struct bpf_ir_env *env, - struct ir_basic_block *bb, - enum ir_loadimm_extra_type load_ty, s64 imm) + +static struct ir_insn *create_loadimmextra_insn_base_norm( + struct bpf_ir_env *env, struct ir_basic_block *bb, + struct ir_vr_pos dstpos, enum ir_loadimm_extra_type load_ty, s64 imm) { struct ir_insn *new_insn = - bpf_ir_create_insn_base_cg(env, bb, IR_INSN_LOADIMM_EXTRA); + bpf_ir_create_insn_base_norm(env, bb, dstpos); + new_insn->op = IR_INSN_LOADIMM_EXTRA; new_insn->imm_extra_type = load_ty; new_insn->imm64 = imm; return new_insn; @@ -487,20 +441,6 @@ static struct ir_insn *create_getelemptr_insn_base(struct bpf_ir_env *env, return new_insn; } -static struct ir_insn *create_getelemptr_insn_base_cg( - struct bpf_ir_env *env, struct ir_basic_block *bb, - struct ir_insn *alloca_insn, struct ir_value offset) -{ - struct ir_insn *new_insn = - bpf_ir_create_insn_base_cg(env, bb, IR_INSN_GETELEMPTR); - new_insn->values[0] = offset; - new_insn->values[1] = bpf_ir_value_insn(alloca_insn); - new_insn->value_num = 2; - bpf_ir_val_add_user(env, new_insn->values[0], new_insn); - bpf_ir_val_add_user(env, new_insn->values[1], new_insn); - return new_insn; -} - static struct ir_insn *create_neg_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, enum ir_alu_op_type alu_type, @@ -515,17 +455,18 @@ static struct ir_insn *create_neg_insn_base(struct bpf_ir_env *env, return new_insn; } -static struct ir_insn *create_neg_insn_base_cg(struct bpf_ir_env *env, - struct ir_basic_block *bb, - enum ir_alu_op_type alu_type, - struct ir_value val) +static struct ir_insn *create_neg_insn_base_norm(struct bpf_ir_env *env, + struct ir_basic_block *bb, + struct ir_vr_pos dstpos, + enum ir_alu_op_type alu_type, + struct ir_value val) { struct ir_insn *new_insn = - bpf_ir_create_insn_base_cg(env, bb, IR_INSN_NEG); + bpf_ir_create_insn_base_norm(env, bb, dstpos); + new_insn->op = IR_INSN_NEG; new_insn->values[0] = val; new_insn->value_num = 1; new_insn->alu_op = alu_type; - bpf_ir_val_add_user(env, new_insn->values[0], new_insn); return new_insn; } @@ -543,20 +484,6 @@ static struct ir_insn *create_end_insn_base(struct bpf_ir_env *env, return new_insn; } -static struct ir_insn *create_end_insn_base_cg(struct bpf_ir_env *env, - struct ir_basic_block *bb, - enum ir_insn_type ty, - u32 swap_width, - struct ir_value val) -{ - struct ir_insn *new_insn = bpf_ir_create_insn_base_cg(env, bb, ty); - new_insn->values[0] = val; - new_insn->value_num = 1; - new_insn->swap_width = swap_width; - bpf_ir_val_add_user(env, new_insn->values[0], new_insn); - return new_insn; -} - static struct ir_insn *create_store_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, struct ir_insn *insn, @@ -573,6 +500,22 @@ static struct ir_insn *create_store_insn_base(struct bpf_ir_env *env, return new_insn; } +static struct ir_insn *create_store_insn_base_cg(struct bpf_ir_env *env, + struct ir_basic_block *bb, + struct ir_insn *insn, + struct ir_value val) +{ + struct ir_insn *new_insn = + bpf_ir_create_insn_base_cg(env, bb, IR_INSN_STORE); + struct ir_value nv = bpf_ir_value_insn(insn); + new_insn->values[0] = nv; + new_insn->values[1] = val; + new_insn->value_num = 2; + bpf_ir_val_add_user(env, nv, new_insn); + bpf_ir_val_add_user(env, val, new_insn); + return new_insn; +} + static struct ir_insn *create_load_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, struct ir_value val) @@ -585,6 +528,18 @@ static struct ir_insn *create_load_insn_base(struct bpf_ir_env *env, return new_insn; } +static struct ir_insn *create_load_insn_base_cg(struct bpf_ir_env *env, + struct ir_basic_block *bb, + struct ir_value val) +{ + struct ir_insn *new_insn = + bpf_ir_create_insn_base_cg(env, bb, IR_INSN_LOAD); + new_insn->values[0] = val; + bpf_ir_val_add_user(env, val, new_insn); + new_insn->value_num = 1; + return new_insn; +} + static struct ir_insn * create_bin_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, struct ir_value val1, struct ir_value val2, @@ -602,17 +557,17 @@ create_bin_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, } static struct ir_insn * -create_bin_insn_base_cg(struct bpf_ir_env *env, struct ir_basic_block *bb, - struct ir_value val1, struct ir_value val2, - enum ir_insn_type ty, enum ir_alu_op_type alu_type) +create_bin_insn_base_norm(struct bpf_ir_env *env, struct ir_basic_block *bb, + struct ir_vr_pos dstpos, struct ir_value val1, + struct ir_value val2, enum ir_insn_type ty, + enum ir_alu_op_type alu_type) { - struct ir_insn *new_insn = bpf_ir_create_insn_base_cg(env, bb, ty); + struct ir_insn *new_insn = + bpf_ir_create_insn_base_norm(env, bb, dstpos); new_insn->op = ty; new_insn->values[0] = val1; new_insn->values[1] = val2; new_insn->alu_op = alu_type; - bpf_ir_val_add_user(env, val1, new_insn); - bpf_ir_val_add_user(env, val2, new_insn); new_insn->value_num = 2; return new_insn; } @@ -624,7 +579,6 @@ static struct ir_insn *create_ja_insn_base(struct bpf_ir_env *env, struct ir_insn *new_insn = bpf_ir_create_insn_base(env, bb); new_insn->op = IR_INSN_JA; new_insn->bb1 = to_bb; - bpf_ir_array_push(env, &to_bb->users, &new_insn); return new_insn; } @@ -644,8 +598,6 @@ create_jbin_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, new_insn->alu_op = alu_type; bpf_ir_val_add_user(env, val1, new_insn); bpf_ir_val_add_user(env, val2, new_insn); - bpf_ir_array_push(env, &to_bb1->users, &new_insn); - bpf_ir_array_push(env, &to_bb2->users, &new_insn); new_insn->value_num = 2; return new_insn; } @@ -695,20 +647,6 @@ static struct ir_insn *create_loadraw_insn_base(struct bpf_ir_env *env, return new_insn; } -static struct ir_insn *create_loadraw_insn_base_cg(struct bpf_ir_env *env, - struct ir_basic_block *bb, - enum ir_vr_type type, - struct ir_address_value val) -{ - struct ir_insn *new_insn = - bpf_ir_create_insn_base_cg(env, bb, IR_INSN_LOADRAW); - new_insn->addr_val = val; - new_insn->value_num = 0; - new_insn->vr_type = type; - bpf_ir_val_add_user(env, val.value, new_insn); - return new_insn; -} - static struct ir_insn *create_storeraw_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, enum ir_vr_type type, @@ -726,23 +664,6 @@ static struct ir_insn *create_storeraw_insn_base(struct bpf_ir_env *env, return new_insn; } -static struct ir_insn *create_storeraw_insn_base_cg(struct bpf_ir_env *env, - struct ir_basic_block *bb, - enum ir_vr_type type, - struct ir_address_value val, - struct ir_value to_store) -{ - struct ir_insn *new_insn = - bpf_ir_create_insn_base_cg(env, bb, IR_INSN_STORERAW); - new_insn->addr_val = val; - new_insn->values[0] = to_store; - new_insn->value_num = 1; - new_insn->vr_type = type; - bpf_ir_val_add_user(env, val.value, new_insn); - bpf_ir_val_add_user(env, to_store, new_insn); - return new_insn; -} - static struct ir_insn *create_assign_insn_base(struct bpf_ir_env *env, struct ir_basic_block *bb, struct ir_value val) @@ -755,6 +676,21 @@ static struct ir_insn *create_assign_insn_base(struct bpf_ir_env *env, return new_insn; } +static struct ir_insn *create_assign_insn_base_norm(struct bpf_ir_env *env, + struct ir_basic_block *bb, + struct ir_vr_pos dstpos, + struct ir_value val) +{ + struct ir_insn *new_insn = + bpf_ir_create_insn_base_norm(env, bb, dstpos); + new_insn->op = IR_INSN_ASSIGN; + new_insn->values[0] = val; + new_insn->value_num = 1; + new_insn->vr_type = IR_VR_TYPE_UNKNOWN; + new_insn->alu_op = IR_ALU_UNKNOWN; + return new_insn; +} + static struct ir_insn *create_assign_insn_base_cg(struct bpf_ir_env *env, struct ir_basic_block *bb, struct ir_value val) @@ -801,6 +737,27 @@ struct ir_insn *bpf_ir_create_alloc_insn_bb(struct bpf_ir_env *env, return new_insn; } +struct ir_insn *bpf_ir_create_alloc_insn_cg(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + enum ir_vr_type type, + enum insert_position pos) +{ + struct ir_insn *new_insn = + create_alloc_insn_base_cg(env, pos_insn->parent_bb, type); + bpf_ir_insert_at(new_insn, pos_insn, pos); + return new_insn; +} + +struct ir_insn *bpf_ir_create_alloc_insn_bb_cg(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + enum ir_vr_type type, + enum insert_position pos) +{ + struct ir_insn *new_insn = create_alloc_insn_base_cg(env, pos_bb, type); + bpf_ir_insert_at_bb(new_insn, pos_bb, pos); + return new_insn; +} + struct ir_insn *bpf_ir_create_allocarray_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, enum ir_vr_type type, u32 num, @@ -843,22 +800,24 @@ struct ir_insn *bpf_ir_create_loadimmextra_insn_bb( return new_insn; } -struct ir_insn *bpf_ir_create_loadimmextra_insn_cg( +struct ir_insn *bpf_ir_create_loadimmextra_insn_norm( struct bpf_ir_env *env, struct ir_insn *pos_insn, - enum ir_loadimm_extra_type load_ty, s64 imm, enum insert_position pos) + struct ir_vr_pos dstpos, enum ir_loadimm_extra_type load_ty, s64 imm, + enum insert_position pos) { - struct ir_insn *new_insn = create_loadimmextra_insn_base_cg( - env, pos_insn->parent_bb, load_ty, imm); + struct ir_insn *new_insn = create_loadimmextra_insn_base_norm( + env, pos_insn->parent_bb, dstpos, load_ty, imm); bpf_ir_insert_at(new_insn, pos_insn, pos); return new_insn; } -struct ir_insn *bpf_ir_create_loadimmextra_insn_bb_cg( +struct ir_insn *bpf_ir_create_loadimmextra_insn_bb_norm( struct bpf_ir_env *env, struct ir_basic_block *pos_bb, - enum ir_loadimm_extra_type load_ty, s64 imm, enum insert_position pos) + struct ir_vr_pos dstpos, enum ir_loadimm_extra_type load_ty, s64 imm, + enum insert_position pos) { - struct ir_insn *new_insn = - create_loadimmextra_insn_base_cg(env, pos_bb, load_ty, imm); + struct ir_insn *new_insn = create_loadimmextra_insn_base_norm( + env, pos_bb, dstpos, load_ty, imm); bpf_ir_insert_at_bb(new_insn, pos_bb, pos); return new_insn; } @@ -887,29 +846,6 @@ struct ir_insn *bpf_ir_create_getelemptr_insn_bb(struct bpf_ir_env *env, return new_insn; } -struct ir_insn *bpf_ir_create_getelemptr_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - struct ir_insn *alloca_insn, - struct ir_value offset, - enum insert_position pos) -{ - struct ir_insn *new_insn = create_getelemptr_insn_base_cg( - env, pos_insn->parent_bb, alloca_insn, offset); - bpf_ir_insert_at(new_insn, pos_insn, pos); - return new_insn; -} - -struct ir_insn *bpf_ir_create_getelemptr_insn_bb_cg( - struct bpf_ir_env *env, struct ir_basic_block *pos_bb, - struct ir_insn *alloca_insn, struct ir_value offset, - enum insert_position pos) -{ - struct ir_insn *new_insn = create_getelemptr_insn_base_cg( - env, pos_bb, alloca_insn, offset); - bpf_ir_insert_at_bb(new_insn, pos_bb, pos); - return new_insn; -} - struct ir_insn *bpf_ir_create_neg_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, enum ir_alu_op_type alu_type, @@ -934,26 +870,28 @@ struct ir_insn *bpf_ir_create_neg_insn_bb(struct bpf_ir_env *env, return new_insn; } -struct ir_insn *bpf_ir_create_neg_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_alu_op_type alu_type, - struct ir_value val, - enum insert_position pos) +struct ir_insn *bpf_ir_create_neg_insn_norm(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_vr_pos dstpos, + enum ir_alu_op_type alu_type, + struct ir_value val, + enum insert_position pos) { - struct ir_insn *new_insn = create_neg_insn_base_cg( - env, pos_insn->parent_bb, alu_type, val); + struct ir_insn *new_insn = create_neg_insn_base_norm( + env, pos_insn->parent_bb, dstpos, alu_type, val); bpf_ir_insert_at(new_insn, pos_insn, pos); return new_insn; } -struct ir_insn *bpf_ir_create_neg_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_alu_op_type alu_type, - struct ir_value val, - enum insert_position pos) +struct ir_insn *bpf_ir_create_neg_insn_bb_norm(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_vr_pos dstpos, + enum ir_alu_op_type alu_type, + struct ir_value val, + enum insert_position pos) { struct ir_insn *new_insn = - create_neg_insn_base_cg(env, pos_bb, alu_type, val); + create_neg_insn_base_norm(env, pos_bb, dstpos, alu_type, val); bpf_ir_insert_at_bb(new_insn, pos_bb, pos); return new_insn; } @@ -982,31 +920,6 @@ struct ir_insn *bpf_ir_create_end_insn_bb(struct bpf_ir_env *env, return new_insn; } -struct ir_insn *bpf_ir_create_end_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_insn_type ty, u32 swap_width, - struct ir_value val, - enum insert_position pos) -{ - struct ir_insn *new_insn = create_end_insn_base_cg( - env, pos_insn->parent_bb, ty, swap_width, val); - bpf_ir_insert_at(new_insn, pos_insn, pos); - return new_insn; -} - -struct ir_insn *bpf_ir_create_end_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_insn_type ty, - u32 swap_width, - struct ir_value val, - enum insert_position pos) -{ - struct ir_insn *new_insn = - create_end_insn_base_cg(env, pos_bb, ty, swap_width, val); - bpf_ir_insert_at_bb(new_insn, pos_bb, pos); - return new_insn; -} - struct ir_insn *bpf_ir_create_store_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_insn *insn, @@ -1031,6 +944,30 @@ struct ir_insn *bpf_ir_create_store_insn_bb(struct bpf_ir_env *env, return new_insn; } +struct ir_insn *bpf_ir_create_store_insn_cg(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_insn *insn, + struct ir_value val, + enum insert_position pos) +{ + struct ir_insn *new_insn = + create_store_insn_base_cg(env, pos_insn->parent_bb, insn, val); + bpf_ir_insert_at(new_insn, pos_insn, pos); + return new_insn; +} + +struct ir_insn *bpf_ir_create_store_insn_bb_cg(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_insn *insn, + struct ir_value val, + enum insert_position pos) +{ + struct ir_insn *new_insn = + create_store_insn_base_cg(env, pos_bb, insn, val); + bpf_ir_insert_at_bb(new_insn, pos_bb, pos); + return new_insn; +} + struct ir_insn *bpf_ir_create_load_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_value val, @@ -1052,6 +989,27 @@ struct ir_insn *bpf_ir_create_load_insn_bb(struct bpf_ir_env *env, return new_insn; } +struct ir_insn *bpf_ir_create_load_insn_cg(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_value val, + enum insert_position pos) +{ + struct ir_insn *new_insn = + create_load_insn_base_cg(env, pos_insn->parent_bb, val); + bpf_ir_insert_at(new_insn, pos_insn, pos); + return new_insn; +} + +struct ir_insn *bpf_ir_create_load_insn_bb_cg(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_value val, + enum insert_position pos) +{ + struct ir_insn *new_insn = create_load_insn_base_cg(env, pos_bb, val); + bpf_ir_insert_at_bb(new_insn, pos_bb, pos); + return new_insn; +} + struct ir_insn * bpf_ir_create_bin_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_value val1, struct ir_value val2, @@ -1077,24 +1035,26 @@ bpf_ir_create_bin_insn_bb(struct bpf_ir_env *env, struct ir_basic_block *pos_bb, } struct ir_insn * -bpf_ir_create_bin_insn_cg(struct bpf_ir_env *env, struct ir_insn *pos_insn, - struct ir_value val1, struct ir_value val2, - enum ir_insn_type ty, enum ir_alu_op_type alu_type, - enum insert_position pos) -{ - struct ir_insn *new_insn = create_bin_insn_base_cg( - env, pos_insn->parent_bb, val1, val2, ty, alu_type); +bpf_ir_create_bin_insn_norm(struct bpf_ir_env *env, struct ir_insn *pos_insn, + struct ir_vr_pos dstpos, struct ir_value val1, + struct ir_value val2, enum ir_insn_type ty, + enum ir_alu_op_type alu_type, + enum insert_position pos) +{ + struct ir_insn *new_insn = create_bin_insn_base_norm( + env, pos_insn->parent_bb, dstpos, val1, val2, ty, alu_type); bpf_ir_insert_at(new_insn, pos_insn, pos); return new_insn; } -struct ir_insn *bpf_ir_create_bin_insn_bb_cg( +struct ir_insn *bpf_ir_create_bin_insn_bb_norm( struct bpf_ir_env *env, struct ir_basic_block *pos_bb, - struct ir_value val1, struct ir_value val2, enum ir_insn_type ty, - enum ir_alu_op_type alu_type, enum insert_position pos) + struct ir_vr_pos dstpos, struct ir_value val1, struct ir_value val2, + enum ir_insn_type ty, enum ir_alu_op_type alu_type, + enum insert_position pos) { - struct ir_insn *new_insn = - create_bin_insn_base_cg(env, pos_bb, val1, val2, ty, alu_type); + struct ir_insn *new_insn = create_bin_insn_base_norm( + env, pos_bb, dstpos, val1, val2, ty, alu_type); bpf_ir_insert_at_bb(new_insn, pos_bb, pos); return new_insn; } @@ -1231,30 +1191,6 @@ struct ir_insn *bpf_ir_create_loadraw_insn_bb(struct bpf_ir_env *env, return new_insn; } -struct ir_insn *bpf_ir_create_loadraw_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_vr_type type, - struct ir_address_value val, - enum insert_position pos) -{ - struct ir_insn *new_insn = create_loadraw_insn_base_cg( - env, pos_insn->parent_bb, type, val); - bpf_ir_insert_at(new_insn, pos_insn, pos); - return new_insn; -} - -struct ir_insn *bpf_ir_create_loadraw_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_vr_type type, - struct ir_address_value val, - enum insert_position pos) -{ - struct ir_insn *new_insn = - create_loadraw_insn_base_cg(env, pos_bb, type, val); - bpf_ir_insert_at_bb(new_insn, pos_bb, pos); - return new_insn; -} - struct ir_insn * bpf_ir_create_storeraw_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, enum ir_vr_type type, struct ir_address_value val, @@ -1279,32 +1215,6 @@ struct ir_insn *bpf_ir_create_storeraw_insn_bb(struct bpf_ir_env *env, return new_insn; } -struct ir_insn *bpf_ir_create_storeraw_insn_cg(struct bpf_ir_env *env, - struct ir_insn *pos_insn, - enum ir_vr_type type, - struct ir_address_value val, - struct ir_value to_store, - enum insert_position pos) -{ - struct ir_insn *new_insn = create_storeraw_insn_base_cg( - env, pos_insn->parent_bb, type, val, to_store); - bpf_ir_insert_at(new_insn, pos_insn, pos); - return new_insn; -} - -struct ir_insn *bpf_ir_create_storeraw_insn_bb_cg(struct bpf_ir_env *env, - struct ir_basic_block *pos_bb, - enum ir_vr_type type, - struct ir_address_value val, - struct ir_value to_store, - enum insert_position pos) -{ - struct ir_insn *new_insn = - create_storeraw_insn_base_cg(env, pos_bb, type, val, to_store); - bpf_ir_insert_at_bb(new_insn, pos_bb, pos); - return new_insn; -} - struct ir_insn *bpf_ir_create_assign_insn(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_value val, @@ -1326,6 +1236,30 @@ struct ir_insn *bpf_ir_create_assign_insn_bb(struct bpf_ir_env *env, return new_insn; } +struct ir_insn *bpf_ir_create_assign_insn_norm(struct bpf_ir_env *env, + struct ir_insn *pos_insn, + struct ir_vr_pos dstpos, + struct ir_value val, + enum insert_position pos) +{ + struct ir_insn *new_insn = create_assign_insn_base_norm( + env, pos_insn->parent_bb, dstpos, val); + bpf_ir_insert_at(new_insn, pos_insn, pos); + return new_insn; +} + +struct ir_insn *bpf_ir_create_assign_insn_bb_norm(struct bpf_ir_env *env, + struct ir_basic_block *pos_bb, + struct ir_vr_pos dstpos, + struct ir_value val, + enum insert_position pos) +{ + struct ir_insn *new_insn = + create_assign_insn_base_norm(env, pos_bb, dstpos, val); + bpf_ir_insert_at_bb(new_insn, pos_bb, pos); + return new_insn; +} + struct ir_insn *bpf_ir_create_assign_insn_cg(struct bpf_ir_env *env, struct ir_insn *pos_insn, struct ir_value val, diff --git a/kernel/bpf/ir/ir_utils.c b/kernel/bpf/ir/ir_utils.c index 430200451..de87a61ea 100644 --- a/kernel/bpf/ir/ir_utils.c +++ b/kernel/bpf/ir/ir_utils.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" // Insert some instructions to print a message void bpf_ir_printk_insns(struct bpf_ir_env *env, struct ir_insn *insn, diff --git a/kernel/bpf/ir/ir_value.c b/kernel/bpf/ir/ir_value.c index 17e2de1a6..553db9edc 100644 --- a/kernel/bpf/ir/ir_value.c +++ b/kernel/bpf/ir/ir_value.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir_cg.h" bool bpf_ir_value_equal(struct ir_value a, struct ir_value b) { @@ -16,6 +16,22 @@ bool bpf_ir_value_equal(struct ir_value a, struct ir_value b) if (a.type == IR_VALUE_INSN) { return a.data.insn_d == b.data.insn_d; } + if (a.type == IR_VALUE_FLATTEN_DST) { + if (a.data.vr_pos.allocated != b.data.vr_pos.allocated) { + return false; + } + if (a.data.vr_pos.spilled != b.data.vr_pos.spilled) { + return false; + } + if (a.data.vr_pos.spilled == 0) { + return a.data.vr_pos.alloc_reg == + b.data.vr_pos.alloc_reg; + } else { + return a.data.vr_pos.spilled_size == + b.data.vr_pos.spilled_size; + } + return true; + } CRITICAL("Error"); } @@ -37,6 +53,14 @@ struct ir_value bpf_ir_value_insn(struct ir_insn *insn) return v; } +struct ir_value bpf_ir_value_vrpos(struct ir_vr_pos pos) +{ + struct ir_value v = value_base(); + v.type = IR_VALUE_FLATTEN_DST; + v.data.vr_pos = pos; + return v; +} + struct ir_value bpf_ir_value_undef(void) { struct ir_value v = value_base(); @@ -92,6 +116,17 @@ struct ir_value bpf_ir_value_stack_ptr(struct ir_function *fun) return bpf_ir_value_insn(fun->sp); } +struct ir_value bpf_ir_value_r0(struct ir_function *fun) +{ + return bpf_ir_value_insn(cg_info(fun)->regs[0]); +} + +struct ir_value bpf_ir_value_norm_stack_ptr(void) +{ + return bpf_ir_value_vrpos(VR_POS_STACK_PTR); +} + +// Change the value of old to new in instruction insn void bpf_ir_change_value(struct bpf_ir_env *env, struct ir_insn *insn, struct ir_value *old, struct ir_value new) { diff --git a/kernel/bpf/ir/jmp_complexity.c b/kernel/bpf/ir/jmp_complexity.c index 22da538c4..9a98c1cc1 100644 --- a/kernel/bpf/ir/jmp_complexity.c +++ b/kernel/bpf/ir/jmp_complexity.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" // JMP Complexity @@ -50,4 +50,4 @@ void bpf_ir_jmp_complexity(struct bpf_ir_env *env, struct ir_function *fun, INSERT_BACK); } bpf_ir_array_free(&jmp_insns); -} \ No newline at end of file +} diff --git a/kernel/bpf/ir/kern_utils.c b/kernel/bpf/ir/kern_utils.c index 1dbeae085..d3dfe8f89 100644 --- a/kernel/bpf/ir/kern_utils.c +++ b/kernel/bpf/ir/kern_utils.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" static int apply_pass_opt(struct bpf_ir_env *env, const char *opt) { @@ -93,8 +93,6 @@ static int apply_global_opt(struct bpf_ir_env *env, const char *opt) { if (strcmp(opt, "force") == 0) { env->opts.force = true; - } else if (strcmp(opt, "enable_coalesce") == 0) { - env->opts.enable_coalesce = true; } else if (strcmp(opt, "print_bpf") == 0) { env->opts.print_mode = BPF_IR_PRINT_BPF; } else if (strcmp(opt, "print_dump") == 0) { @@ -109,6 +107,12 @@ static int apply_global_opt(struct bpf_ir_env *env, const char *opt) env->opts.enable_printk_log = true; } else if (strcmp(opt, "throw_msg") == 0) { env->opts.enable_throw_msg = true; + } else if (strcmp(opt, "printonly") == 0) { + env->opts.print_only = true; + } else if (strcmp(opt, "fakerun") == 0) { + env->opts.fake_run = true; + } else if (strcmp(opt, "dotgraph") == 0) { + env->opts.dotgraph = true; } else if (strncmp(opt, "verbose=", 8) == 0) { int res = 0; int err = parse_int(opt + 8, &res); @@ -119,6 +123,16 @@ static int apply_global_opt(struct bpf_ir_env *env, const char *opt) return -EINVAL; } env->opts.verbose = res; + } else if (strncmp(opt, "maxinsns=", 9) == 0) { + int res = 0; + int err = parse_int(opt + 9, &res); + if (err) { + return err; + } + if (res <= 0) { + return -EINVAL; + } + env->opts.max_insns = res; } else if (strncmp(opt, "maxit=", 6) == 0) { int res = 0; int err = parse_int(opt + 6, &res); @@ -176,37 +190,37 @@ bool bpf_ir_builtin_pass_enabled(struct bpf_ir_env *env, const char *pass_name) int bpf_ir_init_opts(struct bpf_ir_env *env, const char *global_opt, const char *pass_opt) { - if (!pass_opt || !global_opt) { - return -EINVAL; - } // Parse global options int err = 0; - // const char *p = global_opt; char opt[64]; - const char *src = global_opt; - while (*src) { - char *p = opt; - GET_OPT(p, src); - // PRINT_DBG("Global opt: %s\n", opt); - err = apply_global_opt(env, opt); - if (err < 0) { - return err; - } + const char *src; + if (global_opt) { + src = global_opt; + while (*src) { + char *p = opt; + GET_OPT(p, src); + // PRINT_DBG("Global opt: %s\n", opt); + err = apply_global_opt(env, opt); + if (err < 0) { + return err; + } - NEXT_OPT(src); + NEXT_OPT(src); + } } + if (pass_opt) { + src = pass_opt; + while (*src) { + char *p = opt; + GET_OPT(p, src); + // PRINT_DBG("Pass opt: %s\n", opt); + err = apply_pass_opt(env, opt); + if (err < 0) { + return err; + } - src = pass_opt; - while (*src) { - char *p = opt; - GET_OPT(p, src); - // PRINT_DBG("Pass opt: %s\n", opt); - err = apply_pass_opt(env, opt); - if (err < 0) { - return err; + NEXT_OPT(src); } - - NEXT_OPT(src); } return 0; } diff --git a/kernel/bpf/ir/kernpass/Makefile b/kernel/bpf/ir/kernpass/Makefile index ee5921a3f..b4e436818 100644 --- a/kernel/bpf/ir/kernpass/Makefile +++ b/kernel/bpf/ir/kernpass/Makefile @@ -1 +1,2 @@ -obj-y := masking.o \ No newline at end of file +obj-y := masking.o +obj-y += ptr_check.o \ No newline at end of file diff --git a/kernel/bpf/ir/kernpass/masking.c b/kernel/bpf/ir/kernpass/masking.c index 32f23d710..0fc191100 100644 --- a/kernel/bpf/ir/kernpass/masking.c +++ b/kernel/bpf/ir/kernpass/masking.c @@ -4,6 +4,7 @@ #include "linux/stddef.h" #include #include "../../ir_kern.h" +#include "../ir.h" #define CHECK_COND(cond) \ if (!(cond)) { \ @@ -64,6 +65,7 @@ static void masking_pass(struct bpf_ir_env *env, struct ir_function *fun, INSERT_BACK); struct ir_basic_block *old_bb = aluinsn->parent_bb; // Split before insn + // FIXME: bpf_ir_split_bb(..., true) error struct ir_basic_block *new_bb = bpf_ir_split_bb(env, fun, aluinsn, INSERT_FRONT); diff --git a/kernel/bpf/ir/kernpass/ptr_check.c b/kernel/bpf/ir/kernpass/ptr_check.c new file mode 100644 index 000000000..42def99d0 --- /dev/null +++ b/kernel/bpf/ir/kernpass/ptr_check.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "linux/bpf_common.h" +#include "linux/bpf_verifier.h" +#include "linux/stddef.h" +#include +#include "../../ir_kern.h" + +// 64-bit null pointer +#define NULL_PTR bpf_ir_value_const64(0) + +// TODO: move from bpf_ir.c to bpf_ir.h +static const s8 helper_func_arg_num[] = { + [1] = 2, // map_lookup_elem + [2] = 4, // map_update_elem + [3] = 2, // map_delete_elem + [4] = 3, // bpf_probe_read + [5] = 0, // ktime_get_ns + [6] = -1, // trace_printk // 5 may cause an error. May not have 5 arguments + [7] = 0, // get_prandom_u32 + [8] = 0, // get_smp_processor_id + [9] = 5, // skb_store_bytes + [10] = 5, // l3_csum_replace + [11] = 5, // l4_csum_replace + [12] = 3, // tail_call + [13] = 3, // clone_redirect + [14] = 0, // get_current_pid_tgid + [15] = 0, // get_current_uid_gid + [16] = 2, // get_current_comm + [17] = 1, // get_cgroup_classid + [18] = 3, // skb_vlan_push + [19] = 1, // skb_vlan_pop + [20] = 4, // skb_get_tunnel_key + [21] = 4, // skb_set_tunnel_key + [22] = 2, // perf_event_read + [23] = 2, // redirect + [24] = 1, // get_route_realm + [25] = 5, // perf_event_output + [26] = 4, // skb_load_bytes + [27] = 3, // get_stackid + [28] = 5, // csum_diff + [29] = 3, // skb_get_tunnel_opt + [30] = 3, // skb_set_tunnel_opt + [31] = 3, // skb_change_proto + [32] = 2, // skb_change_type + [33] = 3, // skb_under_cgroup + [34] = 1, // get_hash_recalc + [35] = 0, // get_current_task + [36] = 3, // probe_write_user + [37] = 2, // current_task_under_cgroup + [38] = 3, // skb_change_tail + [39] = 2, // skb_pull_data + [40] = 2, // csum_update + [41] = 1, // set_hash_invalid + [42] = 0, // get_numa_node_id + [43] = 3, // skb_change_head + [44] = 2, // xdp_adjust_head + [45] = 3, // bpf_probe_read_str + [46] = 1, // get_socket_cookie + [47] = 1, // get_socket_uid + [48] = 2, // set_hash + [49] = 5, // setsockopt + [50] = 4, // skb_adjust_room + [51] = 3, // bpf_redirect_map + [52] = 4, // sk_redirect_map + [53] = 4, // sock_map_update + [54] = 2, // xdp_adjust_meta + [55] = 4, // perf_event_read_value + [56] = 3, // perf_prog_read_value + [57] = 5, // getsockopt + [58] = 2, // override_return + [59] = 2, // sock_ops_cb_flags_set + [60] = 4, // msg_redirect_map + [61] = 2, // msg_apply_bytes + [62] = 2, // msg_cork_bytes + [63] = 4, // msg_pull_data + [64] = 3, // bind + [65] = 2, // xdp_adjust_tail + [66] = 5, // skb_get_xfrm_state + [67] = 4, // get_stack + [68] = 5, // skb_load_bytes_relative + [69] = 4, // fib_lookup + [70] = 4, // sock_hash_update + [71] = 4, // msg_redirect_hash + [72] = 4, // sk_redirect_hash + [73] = 4, // lwt_push_encap + [74] = 4, // lwt_seg6_store_bytes + [75] = 3, // lwt_seg6_adjust_srh + [76] = 4, // lwt_seg6_action + [77] = 1, // rc_repeat + [78] = 4, // rc_keydown + [79] = 1, // skb_cgroup_id + [80] = 0, // get_current_cgroup_id + [81] = 2, // get_local_storage + [82] = 4, // sk_select_reuseport + [83] = 2, // skb_ancestor_cgroup_id + [84] = 5, // sk_lookup_tcp + [85] = 5, // sk_lookup_udp + [86] = 1, // sk_release + [87] = 3, // map_push_elem + [88] = 2, // map_pop_elem + [89] = 2, // map_peek_elem + [90] = 4, // msg_push_data + [91] = 4, // msg_pop_data + [92] = 3, // rc_pointer_rel + [93] = 1, // spin_lock + [94] = 1, // spin_unlock + [95] = 1, // sk_fullsock + [96] = 1, // tcp_sock + [97] = 1, // skb_ecn_set_ce + [98] = 1, // get_listener_sock + [99] = 5, // skc_lookup_tcp + [100] = 5, // tcp_check_syncookie + [101] = 4, // sysctl_get_name + [102] = 3, // sysctl_get_current_value + [103] = 3, // sysctl_get_new_value + [104] = 3, // sysctl_set_new_value + [105] = 4, // strtol + [106] = 4, // strtoul + [107] = 5, // sk_storage_get + [108] = 2, // sk_storage_delete + [109] = 1, // send_signal + [110] = 5, // tcp_gen_syncookie + [111] = 5, // skb_output + [112] = 3, // probe_read_user + [113] = 3, // probe_read_kernel + [114] = 3, // probe_read_user_str + [115] = 3, // probe_read_kernel_str + [116] = 2, // tcp_send_ack + [117] = 1, // send_signal_thread + [118] = 0, // jiffies64 + [119] = 4, // read_branch_records + [120] = 4, // get_ns_current_pid_tgid + [121] = 5, // xdp_output + [122] = 1, // get_netns_cookie + [123] = 1, // get_current_ancestor_cgroup_id + [124] = 3, // sk_assign + [125] = 0, // ktime_get_boot_ns + [126] = 5, // seq_printf + [127] = 3, // seq_write + [128] = 1, // sk_cgroup_id + [129] = 2, // sk_ancestor_cgroup_id + [130] = 4, // ringbuf_output + [131] = 3, // ringbuf_reserve + [132] = 2, // ringbuf_submit + [133] = 2, // ringbuf_discard + [134] = 2, // ringbuf_query + [135] = 2, // csum_level + [136] = 1, // skc_to_tcp6_sock + [137] = 1, // skc_to_tcp_sock + [138] = 1, // skc_to_tcp_timewait_sock + [139] = 1, // skc_to_tcp_request_sock + [140] = 1, // skc_to_udp6_sock + [141] = 4, // get_task_stack + [142] = 4, // load_hdr_opt + [143] = 4, // store_hdr_opt + [144] = 3, // reserve_hdr_opt + [145] = 5, // inode_storage_get + [146] = 2, // inode_storage_delete + [147] = 3, // d_path + [148] = 3, // copy_from_user + [149] = 5, // snprintf_btf + [150] = 4, // seq_printf_btf + [151] = 1, // skb_cgroup_classid + [152] = 4, // redirect_neigh + [153] = 2, // per_cpu_ptr + [154] = 1, // this_cpu_ptr + [155] = 2, // redirect_peer + [156] = 5, // task_storage_get + [157] = 2, // task_storage_delete + [158] = 0, // get_current_task_btf + [159] = 2, // bprm_opts_set + [160] = 0, // ktime_get_coarse_ns + [161] = 3, // ima_inode_hash + [162] = 1, // sock_from_file + [163] = 5, // check_mtu + [164] = 4, // for_each_map_elem + [165] = 5, // snprintf + [166] = 3, // sys_bpf + [167] = 4, // btf_find_by_name_kind + [168] = 1, // sys_close + [169] = 3, // timer_init + [170] = 3, // timer_set_callback + [171] = 3, // timer_start + [172] = 1, // timer_cancel + [173] = 1, // get_func_ip + [174] = 1, // get_attach_cookie + [175] = 1, // task_pt_regs + [176] = 3, // get_branch_snapshot + [177] = 4, // trace_vprintk + [178] = 1, // skc_to_unix_sock + [179] = 4, // kallsyms_lookup_name + [180] = 5, // find_vma + [181] = 4, // loop + [182] = 3, // strncmp + [183] = 3, // get_func_arg + [184] = 2, // bpf_get_func_ret + [185] = 1, // bpf_get_func_arg_cnt + [186] = 0, // get_retval + [187] = 1, // set_retval + [188] = 1, // xdp_get_buff_len + [189] = 4, // xdp_load_bytes + [190] = 4, // xdp_store_bytes + [191] = 5, // copy_from_user_task + [192] = 3, // skb_set_tstamp + [193] = 3, // ima_file_hash + [194] = 2, // kptr_xchg + [195] = 3, // map_lookup_percpu_elem + [196] = 1, // skc_to_mptcp_sock + [197] = 4, // dynptr_from_mem + [198] = 4, // ringbuf_reserve_dynptr + [199] = 2, // ringbuf_submit_dynptr + [200] = 2, // ringbuf_discard_dynptr + [201] = 5, // dynptr_read + [202] = 5, // dynptr_write + [203] = 3, // dynptr_data + [204] = 3, // tcp_raw_gen_syncookie_ipv4 + [205] = 3, // tcp_raw_gen_syncookie_ipv6 + [206] = 2, // tcp_raw_check_syncookie_ipv4 + [207] = 2, // tcp_raw_check_syncookie_ipv6 + [208] = 0, // ktime_get_tai_ns + [209] = 4, // user_ringbuf_drain + [210] = 5, // cgrp_storage_get + [211] = 2, // cgrp_storage_delete +}; + +static void alu_check(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *insn) +{ + // Skipped static check for bpf_reg_state (enforced by verifier) + // - Both dst and src are pointers is not allowed + // - src is a pointer is not allowed + struct ir_insn *prev = bpf_ir_prev_insn(insn); + struct ir_basic_block *bb = insn->parent_bb; + if (!prev) { + return; + } + struct ir_basic_block *new_bb = + bpf_ir_split_bb(env, fun, prev, INSERT_BACK); + struct ir_basic_block *err_bb = + bpf_ir_create_bb(env, fun); + bpf_ir_create_throw_insn_bb(env, err_bb, INSERT_BACK); + + // *_OR_NULL pointer cannot be used in ALU + struct vi_entry *entry = get_vi_entry(env, insn->_insn_id); + struct bpf_reg_state *dst_reg = &entry->dst_reg_state; + if (dst_reg->type != SCALAR_VALUE) { + bpf_ir_create_jbin_insn( + env, prev, insn->values[0], + NULL_PTR, new_bb, err_bb, + IR_INSN_JEQ, IR_ALU_64, INSERT_BACK); + // Manually connect BBs + bpf_ir_connect_bb(env, bb, err_bb); + } +} + +static void helper_check(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *insn) +{ + struct vi_entry *entry = get_vi_entry(env, insn->_insn_id); + struct bpf_reg_state *arg_regs = entry->arg_reg_states; + + struct ir_insn *prev = bpf_ir_prev_insn(insn); + struct ir_basic_block *bb = insn->parent_bb; + if (!prev) { + return; + } + + struct ir_basic_block *new_bb = + bpf_ir_split_bb(env, fun, prev, INSERT_BACK); + struct ir_basic_block *err_bb = + bpf_ir_create_bb(env, fun); + bpf_ir_create_throw_insn_bb(env, err_bb, INSERT_BACK); + + for (int i = 0; i < helper_func_arg_num[insn->fid]; i++) { + if (arg_regs[i].type != SCALAR_VALUE) { + // val == nullptr -> err + struct ir_insn *null_check_insn = bpf_ir_create_jbin_insn(env, prev, + insn->values[i], NULL_PTR, new_bb, err_bb, + IR_INSN_JEQ, IR_ALU_64, INSERT_BACK); + // val > umax -> err + struct ir_insn *max_check_insn = bpf_ir_create_jbin_insn(env, null_check_insn, + insn->values[i], bpf_ir_value_const64(arg_regs[i].umax_value), new_bb, err_bb, + IR_INSN_JGT, IR_ALU_64, INSERT_BACK); + // val < umin -> err + prev =bpf_ir_create_jbin_insn(env, max_check_insn, + insn->values[i], bpf_ir_value_const64(arg_regs[i].umin_value), new_bb, err_bb, + IR_INSN_JLT, IR_ALU_64, INSERT_BACK); + } + } + // Manually connect BBs + bpf_ir_connect_bb(env, bb, err_bb); +} + +void pointer_check(struct bpf_ir_env *env, struct ir_function *fun, + void *param) +{ + struct bpf_verifier_env *venv = env->venv; + if (!venv) { + RAISE_ERROR("Empty verifier env"); + } + + struct array call_insns; + INIT_ARRAY(&call_insns, struct ir_insn *); + struct array alu_insns; + INIT_ARRAY(&alu_insns, struct ir_insn *); + + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_CALL) { + bpf_ir_array_push(env, &call_insns, &insn); + } else if (bpf_ir_is_bin_alu(insn)) { + bpf_ir_array_push(env, &alu_insns, &insn); + } + } + } + + struct ir_insn **pos2; + array_for(pos2, alu_insns) + { + struct ir_insn *insn = *pos2; + alu_check(env, fun, insn); + } + + array_for(pos2, call_insns) + { + struct ir_insn *insn = *pos2; + helper_check(env, fun, insn); + } + + bpf_ir_array_free(&call_insns); + bpf_ir_array_free(&alu_insns); +} + +const struct builtin_pass_cfg bpf_ir_kern_pointer_check = + DEF_BUILTIN_PASS_CFG("pointer_check", NULL, NULL); \ No newline at end of file diff --git a/kernel/bpf/ir/lii.c b/kernel/bpf/ir/lli.c similarity index 90% rename from kernel/bpf/ir/lii.c rename to kernel/bpf/ir/lli.c index 64276fd05..0526dbe8e 100644 --- a/kernel/bpf/ir/lii.c +++ b/kernel/bpf/ir/lli.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" -// Kernel-side Low-level Interface Implementation +// Low-level Interface implemented for both kernel and user-space #ifdef __KERNEL__ diff --git a/kernel/bpf/ir/msan.c b/kernel/bpf/ir/msan.c index c7eb69925..f5cff731f 100644 --- a/kernel/bpf/ir/msan.c +++ b/kernel/bpf/ir/msan.c @@ -1,5 +1,137 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" + +static void modify_storeraw(struct bpf_ir_env *env, struct ir_insn *arr, + struct ir_insn *insn) +{ + PRINT_LOG_DEBUG(env, "Found a stack pointer store at off %d\n", + insn->addr_val.offset); + // storeraw sp+offset + // ==> + // storeraw sp+offset + // storeraw sp+offset+256, -1 + struct ir_address_value v = insn->addr_val; + v.offset += 256; + bpf_ir_create_storeraw_insn(env, insn, insn->vr_type, v, + bpf_ir_value_const32(0), INSERT_BACK); +} + +static void modify_loadraw(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *arr, struct ir_insn *insn) +{ + // Non-sp memory access + // loadraw size addr(sp-32) + // ==> + // tmp = addr + 256 + // tmp2 = loadraw tmp + // if tmp2 != 0 goto err + // loadraw size addr(sp-32) + // struct ir_insn *tmp = bpf_ir_create_bin_insn(env, insn, insn->addr_val.value, + // bpf_ir_value_const32(256), + // IR_INSN_ADD, IR_ALU_64, + // INSERT_FRONT); + // struct ir_basic_block *bb = insn->parent_bb; + struct ir_address_value v = insn->addr_val; + v.offset += 256; + bpf_ir_create_loadraw_insn(env, insn, insn->vr_type, v, INSERT_BACK); + // struct ir_insn *tmp = bpf_ir_create_loadraw_insn( + // env, insn, insn->vr_type, v, INSERT_BACK); + + // struct ir_basic_block *new_bb = + // bpf_ir_split_bb(env, fun, tmp, INSERT_BACK); + + // struct ir_basic_block *err_bb = bpf_ir_create_bb(env, fun); + + // // bpf_ir_create_throw_insn_bb(env, err_bb, INSERT_BACK); + // bpf_ir_create_ret_insn_bb(env, err_bb, bpf_ir_value_const32(2), + // INSERT_BACK); + + // bpf_ir_create_jbin_insn(env, tmp, bpf_ir_value_insn(tmp), + // bpf_ir_value_const32(0), new_bb, err_bb, + // IR_INSN_JNE, IR_ALU_64, INSERT_BACK); + // // Manually connect BBs + // bpf_ir_connect_bb(env, bb, err_bb); +} + +bool is_sp_access(struct bpf_ir_env *env, struct ir_function *fun, + struct ir_insn *insn) +{ + if (insn == fun->sp) { + return true; + } + if (bpf_ir_is_bin_alu(insn)) { + if (insn->values[0].type == IR_VALUE_INSN) { + if (is_sp_access(env, fun, + insn->values[0].data.insn_d)) { + return true; + } + } + if (insn->values[1].type == IR_VALUE_INSN) { + if (is_sp_access(env, fun, + insn->values[1].data.insn_d)) { + return true; + } + } + } + return false; +} + +void msan(struct bpf_ir_env *env, struct ir_function *fun, void *param) +{ + struct array storeraw_insns; + struct array loadraw_insns; + INIT_ARRAY(&storeraw_insns, struct ir_insn *); + INIT_ARRAY(&loadraw_insns, struct ir_insn *); + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_STORERAW) { + bpf_ir_array_push(env, &storeraw_insns, &insn); + } + if (insn->op == IR_INSN_LOADRAW) { + bpf_ir_array_push(env, &loadraw_insns, &insn); + } + } + } + // Half space for shadow memory + // 32 * 8 bytes + struct ir_insn *arr = bpf_ir_create_allocarray_insn_bb( + env, fun->entry, IR_VR_TYPE_64, 32, INSERT_FRONT_AFTER_PHI); + for (int i = 0; i < 32; ++i) { + bpf_ir_create_storeraw_insn( + env, arr, IR_VR_TYPE_64, + bpf_ir_addr_val(bpf_ir_value_insn(arr), i * 8), + bpf_ir_value_const64(-1), INSERT_BACK); + } + + struct ir_insn **pos2; + array_for(pos2, storeraw_insns) + { + struct ir_insn *insn = *pos2; + if (insn->addr_val.value.type == IR_VALUE_INSN && + is_sp_access(env, fun, insn->addr_val.value.data.insn_d)) { + modify_storeraw(env, arr, insn); + } + } + array_for(pos2, loadraw_insns) + { + struct ir_insn *insn = *pos2; + if (insn->addr_val.value.type == IR_VALUE_INSN && + is_sp_access(env, fun, insn->addr_val.value.data.insn_d)) { + modify_loadraw(env, fun, arr, insn); + } + } + + bpf_ir_array_free(&storeraw_insns); + bpf_ir_array_free(&loadraw_insns); +} + +/* + +// Old MSan static u8 vr_type_to_size(enum ir_vr_type type) { @@ -141,7 +273,7 @@ static void modify_storeraw(struct bpf_ir_env *env, struct ir_insn *arr, bpf_ir_value_insn(res1), INSERT_BACK); } -void msan(struct bpf_ir_env *env, struct ir_function *fun, void *param) +void msan_old(struct bpf_ir_env *env, struct ir_function *fun, void *param) { // Add the 64B mapping space struct ir_insn *arr = bpf_ir_create_allocarray_insn_bb( @@ -200,6 +332,7 @@ void msan(struct bpf_ir_env *env, struct ir_function *fun, void *param) bpf_ir_array_free(&storeraw_insns); bpf_ir_array_free(&loadraw_insns); } +*/ const struct builtin_pass_cfg bpf_ir_kern_msan = DEF_BUILTIN_PASS_CFG("msan", NULL, NULL); diff --git a/kernel/bpf/ir/optimization.c b/kernel/bpf/ir/optimization.c index 6e1c475f5..3bbabcbe0 100644 --- a/kernel/bpf/ir/optimization.c +++ b/kernel/bpf/ir/optimization.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" static void remove_no_user_insn(struct bpf_ir_env *env, struct ir_function *fun) { diff --git a/kernel/bpf/ir/phi_pass.c b/kernel/bpf/ir/phi_pass.c index d48ca24f2..632243e8c 100644 --- a/kernel/bpf/ir/phi_pass.c +++ b/kernel/bpf/ir/phi_pass.c @@ -1,12 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" -static void try_remove_trivial_phi(struct bpf_ir_env *env, struct ir_insn *phi) +static bool try_remove_trivial_phi(struct bpf_ir_env *env, struct ir_insn *phi) { - if (phi->op != IR_INSN_PHI) { - return; - } - // print_raw_ir_insn(phi); + // Optimization: If all phi values are the same, remove this phi + // print_raw_ir_insn(env, phi); struct ir_value same; u8 same_has_value = 0; struct phi_value *pv_pos; @@ -20,34 +18,44 @@ static void try_remove_trivial_phi(struct bpf_ir_env *env, struct ir_insn *phi) continue; } if (same_has_value) { - return; + // PRINT_LOG_DEBUG(env, "failed\n"); + return false; } same = pv.value; same_has_value = 1; } + // PRINT_LOG_DEBUG(env, "success\n"); // PRINT_LOG_DEBUG("Phi to remove: "); // print_raw_ir_insn(phi); if (!same_has_value) { same.type = IR_VALUE_UNDEF; + RAISE_ERROR_RET("A phi instruction has no values", false); } bpf_ir_replace_all_usage_except(env, phi, same, phi); bpf_ir_erase_insn(env, phi); - CHECK_ERR(); + return true; } void remove_trivial_phi(struct bpf_ir_env *env, struct ir_function *fun, void *param) { - struct ir_basic_block **bpos; - array_for(bpos, fun->reachable_bbs) - { - struct ir_basic_block *bb = *bpos; - struct ir_insn *pos, *tmp; - list_for_each_entry_safe(pos, tmp, &bb->ir_insn_head, - list_ptr) { - try_remove_trivial_phi(env, pos); - CHECK_ERR(); + bool changed = true; + while (changed) { + changed = false; + struct ir_basic_block **bpos; + array_for(bpos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *bpos; + struct ir_insn *pos, *tmp; + list_for_each_entry_safe(pos, tmp, &bb->ir_insn_head, + list_ptr) { + if (pos->op == IR_INSN_PHI) { + changed |= try_remove_trivial_phi(env, + pos); + CHECK_ERR(); + } + } } } } diff --git a/kernel/bpf/ir/prog_check.c b/kernel/bpf/ir/prog_check.c index b6d0a01ed..359bdb6b3 100644 --- a/kernel/bpf/ir/prog_check.c +++ b/kernel/bpf/ir/prog_check.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" static void check_insn_users_use_insn(struct bpf_ir_env *env, struct ir_insn *insn) @@ -360,6 +360,8 @@ static void check_jumping(struct bpf_ir_env *env, struct ir_function *fun) if (bb->succs.num_elem != 1) { // Error print_ir_bb_err(env, bb); + PRINT_LOG_ERROR(env, "Succ num: %d != 1\n", + bb->succs.num_elem); RAISE_ERROR("Succ num error"); } } @@ -408,6 +410,8 @@ static void check_err_and_print(struct bpf_ir_env *env, struct ir_function *fun) // Check that the program is valid and able to be compiled void bpf_ir_prog_check(struct bpf_ir_env *env, struct ir_function *fun) { + print_ir_err_init(fun); + check_insn(env, fun); CHECK_DUMP(); diff --git a/kernel/bpf/ir/ptrset.c b/kernel/bpf/ir/ptrset.c new file mode 100644 index 000000000..a32d56aef --- /dev/null +++ b/kernel/bpf/ir/ptrset.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "ir.h" + +// An efficient pointer hashset data structure + +#define STEP 31 + +// Make sure size > 0 +void bpf_ir_ptrset_init(struct bpf_ir_env *env, struct ptrset *res, size_t size) +{ + SAFE_MALLOC(res->set, size * sizeof(struct ptrset_entry)); + res->size = size; + res->cnt = 0; +} + +static void bpf_ir_ptrset_insert_raw(struct ptrset *set, void *key) +{ + u32 index = hash32_ptr(key) % set->size; + for (u32 i = 0; i < set->size; ++i) { + if (set->set[index].occupy <= 0) { + // Found an empty slot + set->set[index].key = key; + set->set[index].occupy = 1; + set->cnt++; + return; + } else if (set->set[index].key == key) { + // Found + return; + } + index = (index + STEP) % set->size; + } + CRITICAL("Impossible"); +} + +void bpf_ir_ptrset_insert(struct bpf_ir_env *env, struct ptrset *set, void *key) +{ + if (set->cnt >= set->size) { + // Table is full, grow it + size_t new_size = set->size * 2; + struct ptrset new_table; + bpf_ir_ptrset_init(env, &new_table, new_size); + for (size_t i = 0; i < set->size; ++i) { + if (set->set[i].occupy > 0) { + bpf_ir_ptrset_insert_raw(&new_table, + set->set[i].key); + } + } + free_proto(set->set); + set->set = new_table.set; + set->size = new_table.size; + } + bpf_ir_ptrset_insert_raw(set, key); +} + +int bpf_ir_ptrset_delete(struct ptrset *set, void *key) +{ + u32 index = hash32_ptr(key) % set->size; + for (u32 i = 0; i < set->size; ++i) { + if (set->set[index].occupy == 0) { + // Already deleted + return -1; + } + if (set->set[index].occupy == 1) { + if (set->set[index].key == key) { + // Found + set->set[index].occupy = -1; + set->cnt--; + return 0; + } + } + index = (index + STEP) % set->size; + } + return -1; +} + +bool bpf_ir_ptrset_exists(struct ptrset *set, void *key) +{ + u32 index = hash32_ptr(key) % set->size; + for (u32 i = 0; i < set->size; ++i) { + if (set->set[index].occupy == 0) { + // Not found + return false; + } + if (set->set[index].occupy == 1) { + if (set->set[index].key == key) { + // Found + return true; + } + } + index = (index + STEP) % set->size; + } + return NULL; +} + +void bpf_ir_ptrset_print_dbg(struct bpf_ir_env *env, struct ptrset *set, + void (*print_key)(struct bpf_ir_env *env, void *)) +{ + for (size_t i = 0; i < set->size; ++i) { + if (set->set[i].occupy > 0) { + print_key(env, set->set[i].key); + PRINT_LOG_DEBUG(env, " "); + } + } + PRINT_LOG_DEBUG(env, "\n"); +} + +void bpf_ir_ptrset_clean(struct ptrset *set) +{ + for (size_t i = 0; i < set->size; ++i) { + set->set[i].key = NULL; + set->set[i].occupy = 0; + } + set->cnt = 0; +} + +void bpf_ir_ptrset_free(struct ptrset *set) +{ + bpf_ir_ptrset_clean(set); + if (set->set) { + free_proto(set->set); + } + set->size = 0; + set->set = NULL; +} + +void **bpf_ir_ptrset_next(struct ptrset *set, void **keyd) +{ + struct ptrset_entry *cc; + if (keyd == NULL) { + cc = set->set; + } else { + cc = container_of(keyd, struct ptrset_entry, key) + 1; + } + while ((size_t)(cc - set->set) < set->size) { + if (cc->occupy == 1) { + return &cc->key; + } + cc++; + } + return NULL; +} + +struct ptrset bpf_ir_ptrset_union(struct bpf_ir_env *env, struct ptrset *set1, + struct ptrset *set2) +{ + struct ptrset res; + bpf_ir_ptrset_init(env, &res, set1->cnt + set2->cnt); + for (size_t i = 0; i < set1->size; ++i) { + if (set1->set[i].occupy > 0) { + bpf_ir_ptrset_insert(env, &res, set1->set[i].key); + } + } + for (size_t i = 0; i < set2->size; ++i) { + if (set2->set[i].occupy > 0) { + bpf_ir_ptrset_insert(env, &res, set2->set[i].key); + } + } + return res; +} + +struct ptrset bpf_ir_ptrset_intersec(struct bpf_ir_env *env, + struct ptrset *set1, struct ptrset *set2) +{ + struct ptrset res; + bpf_ir_ptrset_init(env, &res, set1->cnt); + for (size_t i = 0; i < set1->size; ++i) { + if (set1->set[i].occupy > 0 && + bpf_ir_ptrset_exists(set2, set1->set[i].key)) { + bpf_ir_ptrset_insert(env, &res, set1->set[i].key); + } + } + return res; +} + +// Move set2 to set1 +void bpf_ir_ptrset_move(struct ptrset *set1, struct ptrset *set2) +{ + bpf_ir_ptrset_free(set1); + *set1 = *set2; + set2->set = NULL; + set2->cnt = 0; + set2->size = 0; +} + +// Clone set2 to set1 +// Make sure set1 is empty (no data) +void bpf_ir_ptrset_clone(struct bpf_ir_env *env, struct ptrset *set1, + struct ptrset *set2) +{ + bpf_ir_ptrset_init(env, set1, set2->size); + for (size_t i = 0; i < set2->size; ++i) { + if (set2->set[i].occupy > 0) { + bpf_ir_ptrset_insert(env, set1, set2->set[i].key); + } + } +} + +// set1 += set2 +void bpf_ir_ptrset_add(struct bpf_ir_env *env, struct ptrset *set1, + struct ptrset *set2) +{ + for (size_t i = 0; i < set2->size; ++i) { + if (set2->set[i].occupy > 0) { + bpf_ir_ptrset_insert(env, set1, set2->set[i].key); + } + } +} + +// set1 -= set2 +void bpf_ir_ptrset_minus(struct ptrset *set1, struct ptrset *set2) +{ + for (size_t i = 0; i < set2->size; ++i) { + if (set2->set[i].occupy > 0) { + bpf_ir_ptrset_delete(set1, set2->set[i].key); + } + } +} diff --git a/kernel/bpf/ir/translate_throw.c b/kernel/bpf/ir/translate_throw.c index aed442671..8b7c77f47 100644 --- a/kernel/bpf/ir/translate_throw.c +++ b/kernel/bpf/ir/translate_throw.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include +#include "ir.h" #define RINGBUF_RESERVE 0x83 #define RINGBUF_SUBMIT 0x84 @@ -185,8 +185,8 @@ void translate_throw_helper(struct bpf_ir_env *env, struct ir_function *fun) } } -void translate_throw(struct bpf_ir_env *env, struct ir_function *fun, - void *param) +void translate_throw_df(struct bpf_ir_env *env, struct ir_function *fun, + void *param) { // Initialize struct ir_basic_block **pos; @@ -303,3 +303,21 @@ void translate_throw(struct bpf_ir_env *env, struct ir_function *fun, CHECK_ERR(); } } + +void translate_throw(struct bpf_ir_env *env, struct ir_function *fun, + void *param) +{ + struct ir_basic_block **pos; + array_for(pos, fun->reachable_bbs) + { + struct ir_basic_block *bb = *pos; + struct ir_insn *insn; + list_for_each_entry(insn, &bb->ir_insn_head, list_ptr) { + if (insn->op == IR_INSN_THROW) { + insn->op = IR_INSN_RET; + insn->value_num = 1; + insn->values[0] = bpf_ir_value_const32(1); + } + } + } +} diff --git a/kernel/bpf/ir_kern.c b/kernel/bpf/ir_kern.c index b0327421a..607033023 100644 --- a/kernel/bpf/ir_kern.c +++ b/kernel/bpf/ir_kern.c @@ -2,9 +2,41 @@ // bpf_ir kernel functions #include "ir_kern.h" +#include "ir/ir.h" +#include "ir/ir_cg.h" #include "linux/bpf_ir.h" #include "linux/bpf.h" +// All function passes + +static const struct function_pass pre_passes_def[] = { + DEF_FUNC_PASS(remove_trivial_phi, "remove_trivial_phi", true), +}; + +static struct function_pass post_passes_def[] = { + DEF_FUNC_PASS(pointer_check, "pointer_check", false), + DEF_FUNC_PASS(bpf_ir_div_by_zero, "div_by_zero", false), + DEF_FUNC_PASS(msan, "msan", false), + DEF_FUNC_PASS(insn_counter, "insn_counter", false), + /* CG Preparation Passes */ + DEF_NON_OVERRIDE_FUNC_PASS(translate_throw, "translate_throw"), + DEF_FUNC_PASS(bpf_ir_optimize_code_compaction, "optimize_compaction", + false), + DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_optimize_ir, "optimize_ir"), + DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_change_fun_arg, "change_fun_arg"), + DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_change_call_pre_cg, "change_call"), + DEF_NON_OVERRIDE_FUNC_PASS(bpf_ir_cg_add_stack_offset_pre_cg, + "add_stack_offset"), + DEF_NON_OVERRIDE_FUNC_PASS(bpr_ir_cg_to_cssa, "to_cssa"), +}; + +const struct function_pass *pre_passes = pre_passes_def; +const struct function_pass *post_passes = post_passes_def; + +const size_t post_passes_cnt = sizeof(post_passes_def) / sizeof(post_passes_def[0]); +const size_t pre_passes_cnt = sizeof(pre_passes_def) / sizeof(pre_passes_def[0]); + + static void print_insns_log(struct bpf_insn *insns, u32 len) { printk("Program size: %d", len); @@ -125,7 +157,7 @@ int bpf_ir_kern_run(struct bpf_prog **prog_ptr, union bpf_attr *attr, struct builtin_pass_cfg builtin_pass_cfgs[] = { bpf_ir_kern_insn_counter_pass, bpf_ir_kern_optimization_pass, bpf_ir_kern_msan, bpf_ir_kern_div_by_zero_pass, - bpf_ir_kern_compaction_pass + bpf_ir_kern_compaction_pass, bpf_ir_kern_pointer_check, }; opts.builtin_pass_cfg = builtin_pass_cfgs; diff --git a/kernel/bpf/ir_kern.h b/kernel/bpf/ir_kern.h index b8dda6c43..9a51f7c49 100644 --- a/kernel/bpf/ir_kern.h +++ b/kernel/bpf/ir_kern.h @@ -15,6 +15,7 @@ struct vi_entry { bool valid; struct bpf_reg_state src_reg_state; struct bpf_reg_state dst_reg_state; + struct bpf_reg_state arg_reg_states[MAX_BPF_FUNC_REG_ARGS]; }; struct vi_entry *get_vi_entry(struct bpf_ir_env *env, u32 insn_idx); @@ -650,6 +651,15 @@ bool bpf_ir_canfix(struct bpf_ir_env *env); // Kernel passes +extern const struct builtin_pass_cfg bpf_ir_kern_insn_counter_pass; +extern const struct builtin_pass_cfg bpf_ir_kern_optimization_pass; +extern const struct builtin_pass_cfg bpf_ir_kern_msan; +extern const struct builtin_pass_cfg bpf_ir_kern_div_by_zero_pass; +extern const struct builtin_pass_cfg bpf_ir_kern_compaction_pass; +extern const struct builtin_pass_cfg bpf_ir_kern_pointer_check; extern const struct custom_pass_cfg bpf_ir_kern_masking_pass; +void pointer_check(struct bpf_ir_env *env, struct ir_function *fun, + void *param); + #endif diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 8307bab7f..2231502c7 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -2595,8 +2595,8 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) int err; char license[128]; - char epass_gopt[128]; - char epass_popt[128]; + char epass_gopt[128] = { 0 }; + char epass_popt[128] = { 0 }; if (CHECK_ATTR(BPF_PROG_LOAD)) return -EINVAL; @@ -2713,17 +2713,21 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size) /* copy epass options from user space */ if (attr->enable_epass) { - if (strncpy_from_bpfptr(epass_gopt, - make_bpfptr(attr->epass_gopt, - uattr.is_kernel), - sizeof(epass_gopt) - 1) < 0) - goto free_prog_sec; + if (attr->epass_gopt) { + if (strncpy_from_bpfptr(epass_gopt, + make_bpfptr(attr->epass_gopt, + uattr.is_kernel), + sizeof(epass_gopt) - 1) < 0) + goto free_prog_sec; + } - if (strncpy_from_bpfptr(epass_popt, - make_bpfptr(attr->epass_popt, - uattr.is_kernel), - sizeof(epass_popt) - 1) < 0) - goto free_prog_sec; + if (attr->epass_popt) { + if (strncpy_from_bpfptr(epass_popt, + make_bpfptr(attr->epass_popt, + uattr.is_kernel), + sizeof(epass_popt) - 1) < 0) + goto free_prog_sec; + } } /* eBPF programs must be GPL compatible to use GPL-ed functions */ diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index aabce635d..5648ba722 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -18066,6 +18066,9 @@ static int do_check(struct bpf_verifier_env *env) get_vi_entry(env->ir_env, env->insn_idx); entry->dst_reg_state = regs[insn->dst_reg]; entry->src_reg_state = regs[insn->src_reg]; + for (int i = 0; i < MAX_BPF_FUNC_REG_ARGS; i++) { + entry->arg_reg_states[i] = regs[BPF_REG_1 + i]; + } entry->valid = true; } diff --git a/samples/bpf/cpustat_user.c b/samples/bpf/cpustat_user.c index cfbeae844..ab90bb08a 100644 --- a/samples/bpf/cpustat_user.c +++ b/samples/bpf/cpustat_user.c @@ -208,7 +208,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/fds_example.c b/samples/bpf/fds_example.c index 2570dad0f..88a26f3ce 100644 --- a/samples/bpf/fds_example.c +++ b/samples/bpf/fds_example.c @@ -60,7 +60,7 @@ static int bpf_prog_create(const char *object) if (object) { obj = bpf_object__open_file(object, NULL); assert(!libbpf_get_error(obj)); - err = bpf_object__load(obj, 0, NULL, NULL); + err = bpf_object__load(obj); assert(!err); return bpf_program__fd(bpf_object__next_program(obj, NULL)); } else { diff --git a/samples/bpf/hbm.c b/samples/bpf/hbm.c index 300e800ff..bf6627711 100644 --- a/samples/bpf/hbm.c +++ b/samples/bpf/hbm.c @@ -128,7 +128,7 @@ static int prog_load(char *prog) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { printf("ERROR: loading BPF object file failed\n"); goto err; } diff --git a/samples/bpf/ibumad_user.c b/samples/bpf/ibumad_user.c index 4991d2e60..d074c978a 100644 --- a/samples/bpf/ibumad_user.c +++ b/samples/bpf/ibumad_user.c @@ -120,7 +120,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/lathist_user.c b/samples/bpf/lathist_user.c index da57c3e06..7d8ff2418 100644 --- a/samples/bpf/lathist_user.c +++ b/samples/bpf/lathist_user.c @@ -94,7 +94,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/map_perf_test_user.c b/samples/bpf/map_perf_test_user.c index ae2f6d51e..d2fbcf963 100644 --- a/samples/bpf/map_perf_test_user.c +++ b/samples/bpf/map_perf_test_user.c @@ -467,7 +467,7 @@ int main(int argc, char **argv) fixup_map(obj); /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/offwaketime_user.c b/samples/bpf/offwaketime_user.c index 79ac0e40f..5557b5393 100644 --- a/samples/bpf/offwaketime_user.c +++ b/samples/bpf/offwaketime_user.c @@ -114,7 +114,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/sampleip_user.c b/samples/bpf/sampleip_user.c index fae549585..9283f4784 100644 --- a/samples/bpf/sampleip_user.c +++ b/samples/bpf/sampleip_user.c @@ -199,7 +199,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/sockex1_user.c b/samples/bpf/sockex1_user.c index b72934a04..9e8d39e24 100644 --- a/samples/bpf/sockex1_user.c +++ b/samples/bpf/sockex1_user.c @@ -26,7 +26,7 @@ int main(int ac, char **argv) prog = bpf_object__next_program(obj, NULL); bpf_program__set_type(prog, BPF_PROG_TYPE_SOCKET_FILTER); - err = bpf_object__load(obj, 0, NULL, NULL); + err = bpf_object__load(obj); if (err) return 1; diff --git a/samples/bpf/sockex2_user.c b/samples/bpf/sockex2_user.c index 6feee1275..2c1847133 100644 --- a/samples/bpf/sockex2_user.c +++ b/samples/bpf/sockex2_user.c @@ -30,7 +30,7 @@ int main(int ac, char **argv) prog = bpf_object__next_program(obj, NULL); bpf_program__set_type(prog, BPF_PROG_TYPE_SOCKET_FILTER); - err = bpf_object__load(obj, 0, NULL, NULL); + err = bpf_object__load(obj); if (err) return 1; diff --git a/samples/bpf/sockex3_user.c b/samples/bpf/sockex3_user.c index 493e6bc94..56044acbd 100644 --- a/samples/bpf/sockex3_user.c +++ b/samples/bpf/sockex3_user.c @@ -39,7 +39,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/spintest_user.c b/samples/bpf/spintest_user.c index 623ab1415..55971edb1 100644 --- a/samples/bpf/spintest_user.c +++ b/samples/bpf/spintest_user.c @@ -31,7 +31,7 @@ int main(int ac, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/task_fd_query_user.c b/samples/bpf/task_fd_query_user.c index 184eb93cc..1e61f2180 100644 --- a/samples/bpf/task_fd_query_user.c +++ b/samples/bpf/task_fd_query_user.c @@ -329,7 +329,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/test_cgrp2_sock2.c b/samples/bpf/test_cgrp2_sock2.c index 502dfc146..e7060aaa2 100644 --- a/samples/bpf/test_cgrp2_sock2.c +++ b/samples/bpf/test_cgrp2_sock2.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { printf("ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/test_current_task_under_cgroup_user.c b/samples/bpf/test_current_task_under_cgroup_user.c index e7633eb04..9726ed2a8 100644 --- a/samples/bpf/test_current_task_under_cgroup_user.c +++ b/samples/bpf/test_current_task_under_cgroup_user.c @@ -35,7 +35,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/test_map_in_map_user.c b/samples/bpf/test_map_in_map_user.c index 6195a656c..55dca43f3 100644 --- a/samples/bpf/test_map_in_map_user.c +++ b/samples/bpf/test_map_in_map_user.c @@ -134,7 +134,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/test_overhead_user.c b/samples/bpf/test_overhead_user.c index 70a4a7b19..dbd86f7b1 100644 --- a/samples/bpf/test_overhead_user.c +++ b/samples/bpf/test_overhead_user.c @@ -141,7 +141,7 @@ static int load_progs(char *filename) } /* load BPF program */ - err = bpf_object__load(obj, 0, NULL, NULL); + err = bpf_object__load(obj); if (err < 0) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); return err; diff --git a/samples/bpf/test_probe_write_user_user.c b/samples/bpf/test_probe_write_user_user.c index e5b361b00..2a539aec4 100644 --- a/samples/bpf/test_probe_write_user_user.c +++ b/samples/bpf/test_probe_write_user_user.c @@ -38,7 +38,7 @@ int main(int ac, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/trace_event_user.c b/samples/bpf/trace_event_user.c index c73c29359..9664749bf 100644 --- a/samples/bpf/trace_event_user.c +++ b/samples/bpf/trace_event_user.c @@ -322,7 +322,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { printf("loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/trace_output_user.c b/samples/bpf/trace_output_user.c index 13a314922..d316fd2c8 100644 --- a/samples/bpf/trace_output_user.c +++ b/samples/bpf/trace_output_user.c @@ -59,7 +59,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/tracex1_user.c b/samples/bpf/tracex1_user.c index ff3510f13..8c3d9043a 100644 --- a/samples/bpf/tracex1_user.c +++ b/samples/bpf/tracex1_user.c @@ -26,7 +26,7 @@ int main(int ac, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/tracex2_user.c b/samples/bpf/tracex2_user.c index 84e86bb24..2131f1648 100644 --- a/samples/bpf/tracex2_user.c +++ b/samples/bpf/tracex2_user.c @@ -131,7 +131,7 @@ int main(int ac, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/tracex3_user.c b/samples/bpf/tracex3_user.c index 89ddb8e0b..1002eb032 100644 --- a/samples/bpf/tracex3_user.c +++ b/samples/bpf/tracex3_user.c @@ -133,7 +133,7 @@ int main(int ac, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/tracex4_user.c b/samples/bpf/tracex4_user.c index 737f92f17..a5145ad72 100644 --- a/samples/bpf/tracex4_user.c +++ b/samples/bpf/tracex4_user.c @@ -61,7 +61,7 @@ int main(int ac, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/tracex5_user.c b/samples/bpf/tracex5_user.c index f69a7477b..7e2d8397f 100644 --- a/samples/bpf/tracex5_user.c +++ b/samples/bpf/tracex5_user.c @@ -56,7 +56,7 @@ int main(int ac, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/tracex6_user.c b/samples/bpf/tracex6_user.c index 61ca8d956..ae811ac83 100644 --- a/samples/bpf/tracex6_user.c +++ b/samples/bpf/tracex6_user.c @@ -188,7 +188,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/tracex7_user.c b/samples/bpf/tracex7_user.c index 4f3e90e66..b10b5e03a 100644 --- a/samples/bpf/tracex7_user.c +++ b/samples/bpf/tracex7_user.c @@ -33,7 +33,7 @@ int main(int argc, char **argv) } /* load BPF program */ - if (bpf_object__load(obj, 0, NULL, NULL)) { + if (bpf_object__load(obj)) { fprintf(stderr, "ERROR: loading BPF object file failed\n"); goto cleanup; } diff --git a/samples/bpf/xdp_adjust_tail_user.c b/samples/bpf/xdp_adjust_tail_user.c index a81c648d2..e9426bd65 100644 --- a/samples/bpf/xdp_adjust_tail_user.c +++ b/samples/bpf/xdp_adjust_tail_user.c @@ -153,7 +153,7 @@ int main(int argc, char **argv) prog = bpf_object__next_program(obj, NULL); bpf_program__set_type(prog, BPF_PROG_TYPE_XDP); - err = bpf_object__load(obj, 0, NULL, NULL); + err = bpf_object__load(obj); if (err) return 1; diff --git a/samples/bpf/xdp_fwd_user.c b/samples/bpf/xdp_fwd_user.c index 41efad36c..193b3b79b 100644 --- a/samples/bpf/xdp_fwd_user.c +++ b/samples/bpf/xdp_fwd_user.c @@ -173,7 +173,7 @@ int main(int argc, char **argv) prog = bpf_object__next_program(obj, NULL); bpf_program__set_type(prog, BPF_PROG_TYPE_XDP); - err = bpf_object__load(obj, 0, NULL, NULL); + err = bpf_object__load(obj); if (err) { printf("Does kernel support devmap lookup?\n"); /* If not, the error message will be: diff --git a/samples/bpf/xdp_tx_iptunnel_user.c b/samples/bpf/xdp_tx_iptunnel_user.c index 31a9c53c4..7e4b2f710 100644 --- a/samples/bpf/xdp_tx_iptunnel_user.c +++ b/samples/bpf/xdp_tx_iptunnel_user.c @@ -264,7 +264,7 @@ int main(int argc, char **argv) prog = bpf_object__next_program(obj, NULL); bpf_program__set_type(prog, BPF_PROG_TYPE_XDP); - err = bpf_object__load(obj, 0, NULL, NULL); + err = bpf_object__load(obj); if (err) { printf("bpf_object__load(): %s\n", strerror(errno)); return 1;