Merge remote-tracking branch 'origin/tmp-441e17f' into msm-kona
* origin/tmp-441e17f: ANDROID: xt_qtaguid: Remove unnecessary null checks to device's name ANDROID: qtaguid: Fix the UAF probelm with tag_ref_tree ANDROID: netfilter: xt_qtaguid: Fix 4.14 compilation ANDROID: netfilter: xt_qtaguid: Use sk_uid to replace uid get from socket file ANDROID: netfilter: xt_qtaguid: fix handling for cases where tunnels are used. ANDROID: netfilter: xt_qtaguid: handle properly request sockets ANDROID: netfilter: xt_qtaguid: Add untag hacks to inet_release function ANDROID: netfilter: xt_qtaguid: don't check if embedded arrays are NULL ANDROID: netfilter: xt_qtaguid: fix the deadlock when enable DDEBUG ANDROID: netfilter: xt_qtaguid: Don't show empty tag stats for unprivileged uids ANDROID: netfilter: xt_qtaguid: Fix panic caused by processing non-full socket. ANDROID: netfilter: xt_qtaguid: Fix panic caused by synack processing ANDROID: netfilter: xt_qtaguid: fix a race condition in if_tag_stat_update ANDROID: netfilter: xt_qtaguid: xt_socket: build fixes ANDROID: netfilter: xt_qtaguid: Use sk_callback_lock read locks before reading sk->sk_socket ANDROID: netfilter: xt_qtaguid/xt_socket: Build fixups ANDROID: netfilter: xt_qtaguid: Fix boot panic ANDROID: netfilter: xt_qtaguid: fix bad tcp_time_wait sock handling ANDROID: netfilter: xt_qtaguid: 3.10 fixes ANDROID: netfilter: xt_qtaguid: rate limit some of the printks ANDROID: netfilter: xt_qtaguid: Allow tracking loopback ANDROID: netfilter: xt_qtaguid: extend iface stat to report protocols ANDROID: netfilter: xt_qtaguid: remove AID_* dependency for access control ANDROID: netfilter: xt_qtaguid: Don't BUG_ON if create_if_tag_stat fails ANDROID: netfilter: xt_qtaguid: fix error exit that would keep a spinlock. ANDROID: netfilter: xt_qtaguid: report only uid tags to non-privileged processes ANDROID: netfilter: xt_qtaguid: start tracking iface rx/tx at low level ANDROID: netfilter: xt_qtaguid: fix ipv6 protocol lookup ANDROID: netfilter: xt_qtaguid: add qtaguid matching module RFC: ANDROID: net: ipv6: Flip FIB entries to fib6_info RFC: ANDROID: proc/uid: switch instantiate_t to d_splice_alias() RFC: ANDROID: fs: sdcardfs: Use inode iversion helpers RFC: ANDROID: net: ipv4: sysfs_net_ipv4: Fix TCP window size controlling knobs RFC: ANDROID: net: ipv4: tcp: Namespace-ify sysctl_tcp_default_init_rwnd ANDROID: x86_64_cuttlefish_defconfig: Enable lz4 compression for zram ANDROID: x86_64_cuttlefish_defconfig: Enable zram and zstd ANDROID: AVB error handler to invalidate vbmeta partition. ANDROID: remove android config fragments ANDROID: ftrace: fix function type mismatches ANDROID: sdcardfs: Check stacked filesystem depth ANDROID: verity: really fix android-verity Kconfig x86_64_cuttlefish_defconfig: Enable android-verity x86_64_cuttlefish_defconfig: enable verity cert ANDROID: android-verity: Fix broken parameter handling. ANDROID: android-verity: Make it work with newer kernels ANDROID: android-verity: Add API to verify signature with builtin keys. ANDROID: verity: fix android-verity Kconfig dependencies ANDROID: uid_sys_stats: Replace tasklist lock with RCU in uid_cputime_show ANDROID: mnt: Fix next_descendent ANDROID: Fix massive cpufreq_times memory leaks ANDROID: Reduce use of #ifdef CONFIG_CPU_FREQ_TIMES ANDROID: sdcardfs: fix potential crash when reserved_mb is not zero ANDROID: Add kconfig to make dm-verity check_at_most_once default enabled ANDROID: add extra free kbytes tunable ANDROID: x86_64_cuttlefish_defconfig: Enable F2FS ANDROID: Update x86_64_cuttlefish_defconfig ANDROID: proc: fix undefined behavior in proc_uid_base_readdir ANDROID: x86_64_cuttlefish_defconfig: Disable ORC unwinder. ANDROID: build: cuttlefish: Upgrade clang to newer version. ANDROID: build: cuttlefish: Upgrade clang to newer version. ANDROID: build: cuttlefish: Fix path to clang. ANDROID: sdcardfs: Don't d_drop in d_revalidate ANDROID: goldfish: drop CONFIG_INPUT_KEYCHORD ANDROID: build.config: enforce trace_printk check cfi: print target address on failure ANDROID: fs: gfs2: fix filler function type ANDROID: fs: exofs: fix filler function type ANDROID: fs: afs: fix filler function type ANDROID: fs: nfs: fix filler function type ANDROID: fs: fuse: fix filler function type mismatch ANDROID: mm: fix filler function type mismatch ANDROID: arch/arm64/crypto: fix CFI in SHA CE ANDROID: arm64: kvm: disable CFI ANDROID: arm64: mark kpti_install_ng_mappings as __nocfi ANDROID: arm64: disable CFI for cpu_replace_ttbr1 ANDROID: kallsyms: strip the .cfi postfix from symbols with CONFIG_CFI_CLANG RFC: ANDROID: add support for clang Control Flow Integrity (CFI) ANDROID: sdcardfs: Set s_root to NULL after putting ANDROID: sdcardfs: d_make_root calls iput ANDROID: sdcardfs: Check for private data earlier FROMLIST: arm64: kvm: use -fno-jump-tables with clang ANDROID: Add build server config for cuttlefish. ANDROID: Add defconfig for cuttlefish. ANDROID: cpufreq: Add time_in_state to /proc/uid directories ANDROID: proc: Add /proc/uid directory ANDROID: cpufreq: times: track per-uid time in state ANDROID: cpufreq: track per-task time in state ANDROID: fuse: Add null terminator to path in canonical path to avoid issue ANDROID: sdcardfs: Fix sdcardfs to stop creating cases-sensitive duplicate entries. ANDROID: arm64: Image.gz-dtb build target depends on Image.gz ANDROID: sdcardfs: fix lock issue on 32 bit/SMP architectures ANDROID: uid_sys_stats: Copy task_struct comm field to bigger buffer ANDROID: sdcardfs: Set num in extension_details during make_item ANDROID: sdcardfs: Hold i_mutex for i_size_write ANDROID: sdcardfs: Protect set_top ANDROID: fsnotify: Notify lower fs of open ANDROID: sdcardfs: Use lower getattr times/size ANDROID: Revert "fs: unexport vfs_read and vfs_write" ANDROID: sdcardfs: port to 4.14 ANDROID: fs: Export vfs_rmdir2 ANDROID: mm: Export do_munmap ANDROID: fs: Export d_absolute_path ANDROID: fs: Export free_fs_struct and set_fs_pwd ANDROID: export security_path_chown ANDROID: sdcardfs: Add default_normal option ANDROID: Sdcardfs: Move gid derivation under flag ANDROID: sdcardfs: override credential for ioctl to lower fs ANDROID: sdcardfs: Remove unnecessary lock ANDROID: sdcardfs: use mount_nodev and fix a issue in sdcardfs_kill_sb ANDROID: sdcardfs: remove dead function open_flags_to_access_mode() ANDROID: sdcardfs: d_splice_alias can return error values ANDROID: sdcardfs: Check for NULL in revalidate ANDROID: sdcardfs: Move top to its own struct ANDROID: sdcardfs: fix sdcardfs_destroy_inode for the inode RCU approach ANDROID: sdcardfs: Don't iput if we didn't igrab ANDROID: sdcardfs: Call lower fs's revalidate ANDROID: sdcardfs: Avoid setting GIDs outside of valid ranges ANDROID: sdcardfs: Copy meta-data from lower inode ANDROID: sdcardfs: Use filesystem specific hash ANDROID: sdcardfs: Don't complain in fixup_lower_ownership ANDROID: sdcardfs: Don't do d_add for lower fs ANDROID: sdcardfs: ->iget fixes ANDROID: sdcardfs: Change cache GID value ANDROID: sdcardfs: Directly pass lower file for mmap ANDROID: sdcardfs: update module info ANDROID: sdcardfs: use d_splice_alias ANDROID: sdcardfs: add read_iter/write_iter opeations ANDROID: sdcardfs: fix ->llseek to update upper and lower offset ANDROID: sdcardfs: copy lower inode attributes in ->ioctl ANDROID: sdcardfs: remove unnecessary call to do_munmap ANDROID: sdcardfs: Fix style issues in macros ANDROID: sdcardfs: Use seq_puts over seq_printf ANDROID: sdcardfs: Use to kstrout ANDROID: sdcardfs: Use pr_[...] instead of printk ANDROID: sdcardfs: remove unneeded null check ANDROID: sdcardfs: Fix style issues with comments ANDROID: sdcardfs: Fix formatting ANDROID: sdcardfs: correct order of descriptors ANDROID: sdcardfs: Fix gid issue ANDROID: sdcardfs: Remove uninformative prints ANDROID: sdcardfs: move path_put outside of spinlock ANDROID: sdcardfs: Use case insensitive hash function ANDROID: sdcardfs: declare MODULE_ALIAS_FS ANDROID: sdcardfs: Get the blocksize from the lower fs ANDROID: sdcardfs: Use d_invalidate instead of drop_recurisve ANDROID: sdcardfs: Switch to internal case insensitive compare ANDROID: sdcardfs: Use spin_lock_nested ANDROID: sdcardfs: Replace get/put with d_lock ANDROID: sdcardfs: rate limit warning print ANDROID: sdcardfs: Fix case insensitive lookup ANDROID: sdcardfs: support direct-IO (DIO) operations ANDROID: sdcardfs: implement vm_ops->page_mkwrite ANDROID: sdcardfs: Don't bother deleting freelist ANDROID: sdcardfs: Add missing path_put ANDROID: sdcardfs: Fix incorrect hash ANDROID: sdcardfs: Switch strcasecmp for internal call ANDROID: sdcardfs: switch to full_name_hash and qstr ANDROID: sdcardfs: Add GID Derivation to sdcardfs ANDROID: sdcardfs: Remove redundant operation ANDROID: sdcardfs: add support for user permission isolation ANDROID: sdcardfs: Refactor configfs interface ANDROID: sdcardfs: Allow non-owners to touch ANDROID: sdcardfs: eliminate the offset argument to ->direct_IO ANDROID: sdcardfs: make it use new .rename i_op ANDROID: sdcardfs: Propagate dentry down to inode_change_ok() ANDROID: sdcardfs: get rid of 'parent' argument of ->d_compare() ANDROID: sdcardfs: add parent pointer into dentry name hash ANDROID: sdcardfs: use wrappers to access i_mutex ANDROID: sdcardfs: Fix locking issue with permision fix up ANDROID: sdcardfs: Switch ->d_inode to d_inode() ANDROID: sdcardfs: Change magic value ANDROID: sdcardfs: Use per mount permissions ANDROID: sdcardfs: Add gid and mask to private mount data ANDROID: sdcardfs: User new permission2 functions ANDROID: sdcardfs: Move directory unlock before touch ANDROID: sdcardfs: fix external storage exporting incorrect uid ANDROID: sdcardfs: Added top to sdcardfs_inode_info ANDROID: sdcardfs: Switch package list to RCU ANDROID: sdcardfs: Fix locking for permission fix up ANDROID: sdcardfs: Check for other cases on path lookup ANDROID: sdcardfs: override umask on mkdir and create ANDROID: sdcardfs: fix itnull.cocci warnings ANDROID: sdcardfs: Truncate packages_gid.list on overflow ANDROID: sdcardfs: remove unneeded __init and __exit ANDROID: sdcardfs: Remove unused code ANDROID: sdcardfs: remove effectless config option ANDROID: sdcardfs: Add support for d_canonical_path ANDROID: sdcardfs: Bring up to date with Android M permissions: ANDROID: Changed type-casting in packagelist management ANDROID: Port of sdcardfs to 4.4 ANDROID: xattr: Pass EOPNOTSUPP to permission2 RFC: ANDROID: vfs: Add permission2 for filesystems with per mount permissions ANDROID: vfs: Add setattr2 for filesystems with per mount permissions ANDROID: vfs: Allow filesystems to access their private mount data ANDROID: fuse: Add support for d_canonical_path ANDROID: mnt: Add filesystem private data to mount points ANDROID: vfs: add d_canonical_path for stacked filesystem support ANDROID: Included sdcardfs source code for kernel 3.0 ANDROID: Fix script to fetch android kernel config fragments for 4.14 ANDROID: uid_sys_stats: fix the comment ANDROID: initramfs: call free_initrd() when skipping init ANDROID: memory_state_time: fix undefined behavior with missing DT properties ANDROID: memory_state_time: Implement memory_state_time, used by qcom,cpubw ANDROID: uid_sys_stats: log task io with a debug flag ANDROID: uid_sys_stats: check previous uid_entry before call find_or_register_uid ANDROID: uid_sys_stats: Kconfig: add depends for UID_SYS_STATS ANDROID: uid_sys_stats: defer io stats calulation for dead tasks ANDROID: uid_sys_stats: fix access of task_uid(task) ANDROID: uid_sys_stats: reduce update_io_stats overhead ANDROID: uid_sys_stats: change to use rt_mutex ANDROID: uid_sys_stats: account for fsync syscalls ANDROID: uid_sys_stats: fix negative write bytes. ANDROID: uid_sys_stats: allow writing same state ANDROID: uid_sys_stats: rename uid_cputime.c to uid_sys_stats.c ANDROID: uid_cputime: add per-uid IO usage accounting ANDROID: uid_cputime: Check for the range while removing range of UIDs. ANDROID: uid_cputime: Iterates over all the threads instead of processes. ANDROID: uid_cputime: fix cputime overflow ANDROID: uid_cputime: Adds accounting for the cputimes per uid. CHROMIUM: usb: gadget: f_accessory: add .raw_request callback CHROMIUM: usb: gadget: f_audio_source: add .free_func callback ANDROID: usb: gadget: f_midi: set fi->f to NULL when free f_midi function ANDROID: usb: gadget: f_midi: create F_midi device ANDROID: usb: gadget: f_accessory: assign no-op request complete callbacks ANDROID: usb: gadget: f_accessory: Fix for UsbAccessory clean unbind. ANDROID: usb: gadget: f_accessory: fix false disconnect due to a signal sent to the reading process ANDROID: usb: gadget: f_accessory: Move gadget functions code ANDROID: usb: gadget: f_accessory: Migrate to USB_FUNCTION API ANDROID: usb: gadget: f_audio_source: disable the CPU C-states upon playback ANDROID: usb: gadget: f_audio_source: Move gadget functions code ANDROID: usb: gadget: f_audio_source: Move to USB_FUNCTION API ANDROID: usb: gadget: configfs: fix null ptr in android_disconnect ANDROID: usb: gadget: configfs: Add device attribute to determine gadget state ANDROID: usb: gadget: configfs: Add "state" attribute to android_device ANDROID: usb: gadget: configfs: Add function devices to the parent ANDROID: usb: gadget: configfs: Add Uevent to notify userspace ANDROID: usb: gadget: configfs: Add usb_function ptr to fi struct ANDROID: usb: gadget: f_audio_source: Fixed USB Audio Class Interface Descriptor ANDROID: usb: gadget: f_audio_source: change max ISO packet size ANDROID: usb: gadget: f_audio_source: New gadget driver for audio output ANDROID: usb: gadget: f_accessory: check for accessory device before disconnecting HIDs ANDROID: usb: gadget: f_accessory: Enabled Zero Length Packet (ZLP) for acc_write ANDROID: usb: gadget: f_accessory: move userspace interface to uapi ANDROID: usb: gadget: f_accessory: Add support for HID input devices ANDROID: usb: gadget: f_accessory: Add ACCESSORY_SET_AUDIO_MODE control request and ioctl ANDROID: usb: gadget: f_accessory: Add Android Accessory function ANDROID: trace: sched: add sched blocked tracepoint which dumps out context of sleep. ANDROID: security,perf: Allow further restriction of perf_event_open ANDROID: power: wakeup: Add the guard condition for len in pm_get_active_wakeup_sources ANDROID: power: wakeup: Add last wake up source logging for suspend abort reason. ANDROID: power: wakeup_reason: fix suspend time reporting ANDROID: power: wakeup_reason: Report suspend times from last_suspend_time ANDROID: power: wakeup_reason: Adds functionality to log the last suspend abort reason. ANDROID: power: wakeup_reason: Avoids bogus error messages for the suspend aborts. ANDROID: power: wakeup_reason: Add guard condition for maximum wakeup reasons ANDROID: power: wakeup_reason: add an API to log wakeup reasons ANDROID: power: power_supply: Add property CHARGE_COUNTER_EXT and 64-bit precision properties ANDROID: power: power_supply: add POWER_SUPPLY_PROP_CHARGE_ENABLED ANDROID: power: power_supply: add POWER_SUPPLY_PROP_USB_OTG ANDROID: power: power_supply: Add custom property for USB High Current mode ANDROID: arm64: copy CONFIG_CMDLINE_EXTEND from ARM ANDROID: of: Support CONFIG_CMDLINE_EXTEND config option ANDROID: NFC: st21nfca: Fix memory OOB and leak issues in connectivity events handler ANDROID: NFC: Fix possible memory corruption when handling SHDLC I-Frame commands ANDROID: nfc: fdp: Fix possible buffer overflow in WCS4000 NFC driver ANDROID: NFC: st21nfca: Fix out of bounds kernel access when handling ATR_REQ ANDROID: netfilter: xt_IDLETIMER: Use fullsock when querying uid ANDROID: netfilter: xt_IDLETIMER: Fix use after free condition during work ANDROID: netfilter: xt_IDLETIMER: Adds the uid field in the msg ANDROID: netfilter: xt_IDLETIMER: time-stamp and suspend/resume handling. ANDROID: netfilter: xt_IDLETIMER: Add new netlink msg type ANDROID: netfilter: xt_quota2: fixup the quota2, and enable. ANDROID: netfilter: xt_quota2: adding the original quota2 from xtables-addons ANDROID: net: xfrm: make PF_KEY SHA256 use RFC-compliant truncation. ANDROID: net: wireless: wlcore: Disable filtering in AP role ANDROID: net: wireless: Decrease scan entry expiration to avoid stall results ANDROID: net: rfkill: Introduce CONFIG_RFKILL_PM and use instead of CONFIG_PM to power down ANDROID: net: ipv6: autoconf routes into per-device tables ANDROID: net: ipv6: fix crash caused by ipv6_find_hdr() ANDROID: net: ipv4: tcp: add a sysctl to config the tcp_default_init_rwnd ANDROID: net: ipv4: sysfs_net_ipv4: Add sysfs-based knobs for controlling TCP window size ANDROID: net: ip-sysctl: Document tcp_fwmark_accept ANDROID: net: paranoid: commoncap: Begin to warn users of implicit PARANOID_NETWORK capability grants ANDROID: net: paranoid: security: Add proper checks for Android specific capability checks ANDROID: net: paranoid: Only NET_ADMIN is allowed to fully control TUN interfaces. ANDROID: net: paranoid: Replace AID_NET_RAW checks with capable(CAP_NET_RAW). ANDROID: net: paranoid: security: Add AID_NET_RAW and AID_NET_ADMIN capability check in cap_capable(). ANDROID: net: Paranoid network. ANDROID: mmc: core: Add "ignore mmc pm notify" functionality ANDROID: mm: add a field to store names for private anonymous memory ANDROID: Kbuild, LLVMLinux: allow overriding clang target triple CHROMIUM: kbuild: clang: Disable the 'duplicate-decl-specifier' warning ANDROID: kbuild: Makefile.clean: make Kbuild and Makefile optional ANDROID: kbuild: make it possible to specify the module output dir ANDROID: input: keyreset: switch to orderly_reboot ANDROID: input: keyreset: Made keyreset more robust ANDROID: input: keyreset: Changed keyreset to act as a wrapper for keycombo. ANDROID: input: keycombo: add keycombo, a general key combo driver. ANDROID: input: keyreset: Add keyreset driver. ANDROID: input: gpio_matrix: Remove wakelock.h dependencies ANDROID: input: gpio_input: convert from wakelocks to wakeup sources ANDROID: input: gpio_event: remove early suspend ANDROID: input: Generic GPIO Input devices ANDROID: initramfs: Add skip_initramfs command line option ANDROID: build: add build server configs for goldfish ANDROID: goldfish: add ranchu defconfigs ANDROID: fs: Fix for in kernel emergency remount when loop mounts are used ANDROID: fs: Refactor FS readpage/write tracepoints. ANDROID: fs: FS tracepoints to track IO. ANDROID: fs: sched: add a counter to track fsync ANDROID: fs: epoll: use freezable blocking call ANDROID: dm: verity: add minimum prefetch size ANDROID: dm: android-verity: mark dev as rw for linear target ANDROID: dm: android-verity: allow disable dm-verity for Treble VTS ANDROID: dm: android-verity: fix table_make_digest() error handling ANDROID: dm: android-verity: rebase for 4.9 ANDROID: dm: android-verity: Remove fec_header location constraint ANDROID: dm: android-verity: adopt changes made to dm callbacks ANDROID: dm: android-verity: pack the fec_header structure ANDROID: dm: android-verity: Verify header before fetching table ANDROID: dm: android-verity: allow adb disable-verity only in userdebug ANDROID: dm: android-verity: mount as linear target if eng build ANDROID: dm: android-verity: use default verity public key ANDROID: dm: android-verity: fix signature verification flag ANDROID: dm: android-verity: use name_to_dev_t ANDROID: dm: android-verity: Mounting root as linear device when verity disabled ANDROID: dm: android-verity: Add android verity target ANDROID: dm: do_mounts_dm: Update init/do_mounts_dm.c to the latest ChromiumOS version. ANDROID: dm: do_mounts_dm: fix dm_substitute_devices() ANDROID: dm: do_mounts_dm: Rebase on top of 4.9 CHROMIUM: dm: boot time specification of dm= ANDROID: dm: verity-fec: add sysfs attribute fec/corrected CHROMIUM: cgroups: relax permissions on moving tasks between cgroups ANDROID: cpuset: Make cpusets restore on hotplug ANDROID: cpu: send KOBJ_ONLINE event when enabling cpus ANDROID: cpuidle: governor: menu: don't use loadavg ANDROID: binder: fix node sched policy calculation ANDROID: binder: init desired_prio.sched_policy before use it ANDROID: binder: Add tracing for binder priority inheritance. ANDROID: binder: don't check prio permissions on restore. ANDROID: binder: add RT inheritance flag to node. ANDROID: binder: improve priority inheritance. ANDROID: binder: add min sched_policy to node. ANDROID: binder: add support for RT prio inheritance. ANDROID: kdb: support new lines without carriage returns ANDROID: arm64: Allow to choose appended kernel image ANDROID: arm64: add option to build Image-dtb ANDROID: arm64: add option to build Image.gz/dtb combo ANDROID: arm: convert build of appended dtb zImage to list of dtbs ANDROID: arm: add config option to build zImage/dtb combo ANDROID: arm: Fix dtb list when DTB_IMAGE_NAMES is empty ANDROID: add script to fetch android kernel config fragments Change-Id: Ibaa7c53d9f63499e5e96579a36e178edad19be75 [rishabhb@codeaurora.org: LLCT tree taken from: https://android-git.linaro.org/kernel/linaro-android.git/log/?h=test/amt-4.19] Signed-off-by: Rishabh Bhatnagar <rishabhb@codeaurora.org>
This commit is contained in:
commit
3bca5c7ace
3
.gitignore
vendored
3
.gitignore
vendored
@ -132,3 +132,6 @@ all.config
|
||||
|
||||
# Kdevelop4
|
||||
*.kdev4
|
||||
|
||||
# fetched Android config fragments
|
||||
kernel/configs/android-*.cfg
|
||||
|
16
Documentation/ABI/testing/sysfs-kernel-wakeup_reasons
Normal file
16
Documentation/ABI/testing/sysfs-kernel-wakeup_reasons
Normal file
@ -0,0 +1,16 @@
|
||||
What: /sys/kernel/wakeup_reasons/last_resume_reason
|
||||
Date: February 2014
|
||||
Contact: Ruchi Kandoi <kandoiruchi@google.com>
|
||||
Description:
|
||||
The /sys/kernel/wakeup_reasons/last_resume_reason is
|
||||
used to report wakeup reasons after system exited suspend.
|
||||
|
||||
What: /sys/kernel/wakeup_reasons/last_suspend_time
|
||||
Date: March 2015
|
||||
Contact: jinqian <jinqian@google.com>
|
||||
Description:
|
||||
The /sys/kernel/wakeup_reasons/last_suspend_time is
|
||||
used to report time spent in last suspend cycle. It contains
|
||||
two numbers (in seconds) separated by space. First number is
|
||||
the time spent in suspend and resume processes. Second number
|
||||
is the time spent in sleep state.
|
@ -884,6 +884,9 @@
|
||||
|
||||
dis_ucode_ldr [X86] Disable the microcode loader.
|
||||
|
||||
dm= [DM] Allows early creation of a device-mapper device.
|
||||
See Documentation/device-mapper/boot.txt.
|
||||
|
||||
dma_debug=off If the kernel is compiled with DMA_API_DEBUG support,
|
||||
this option disables the debugging code at boot.
|
||||
|
||||
|
42
Documentation/device-mapper/boot.txt
Normal file
42
Documentation/device-mapper/boot.txt
Normal file
@ -0,0 +1,42 @@
|
||||
Boot time creation of mapped devices
|
||||
===================================
|
||||
|
||||
It is possible to configure a device mapper device to act as the root
|
||||
device for your system in two ways.
|
||||
|
||||
The first is to build an initial ramdisk which boots to a minimal
|
||||
userspace which configures the device, then pivot_root(8) in to it.
|
||||
|
||||
For simple device mapper configurations, it is possible to boot directly
|
||||
using the following kernel command line:
|
||||
|
||||
dm="<name> <uuid> <ro>,table line 1,...,table line n"
|
||||
|
||||
name = the name to associate with the device
|
||||
after boot, udev, if used, will use that name to label
|
||||
the device node.
|
||||
uuid = may be 'none' or the UUID desired for the device.
|
||||
ro = may be "ro" or "rw". If "ro", the device and device table will be
|
||||
marked read-only.
|
||||
|
||||
Each table line may be as normal when using the dmsetup tool except for
|
||||
two variations:
|
||||
1. Any use of commas will be interpreted as a newline
|
||||
2. Quotation marks cannot be escaped and cannot be used without
|
||||
terminating the dm= argument.
|
||||
|
||||
Unless renamed by udev, the device node created will be dm-0 as the
|
||||
first minor number for the device-mapper is used during early creation.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
- Booting to a linear array made up of user-mode linux block devices:
|
||||
|
||||
dm="lroot none 0, 0 4096 linear 98:16 0, 4096 4096 linear 98:32 0" \
|
||||
root=/dev/dm-0
|
||||
|
||||
Will boot to a rw dm-linear target of 8192 sectors split across two
|
||||
block devices identified by their major:minor numbers. After boot, udev
|
||||
will rename this target to /dev/mapper/lroot (depending on the rules).
|
||||
No uuid was assigned.
|
@ -0,0 +1,8 @@
|
||||
Memory bandwidth and frequency state tracking
|
||||
|
||||
Required properties:
|
||||
- compatible : should be:
|
||||
"memory-state-time"
|
||||
- freq-tbl: Should contain entries with each frequency in Hz.
|
||||
- bw-buckets: Should contain upper-bound limits for each bandwidth bucket in Mbps.
|
||||
Must match the framework power_profile.xml for the device.
|
@ -398,6 +398,8 @@ is not associated with a file:
|
||||
[stack] = the stack of the main process
|
||||
[vdso] = the "virtual dynamic shared object",
|
||||
the kernel system call handler
|
||||
[anon:<name>] = an anonymous mapping that has been
|
||||
named by userspace
|
||||
|
||||
or if empty, the mapping is anonymous.
|
||||
|
||||
@ -426,6 +428,7 @@ KernelPageSize: 4 kB
|
||||
MMUPageSize: 4 kB
|
||||
Locked: 0 kB
|
||||
VmFlags: rd ex mr mw me dw
|
||||
Name: name from userspace
|
||||
|
||||
the first of these lines shows the same information as is displayed for the
|
||||
mapping in /proc/PID/maps. The remaining lines show the size of the mapping
|
||||
@ -498,6 +501,9 @@ Note that there is no guarantee that every flag and associated mnemonic will
|
||||
be present in all further kernel releases. Things get changed, the flags may
|
||||
be vanished or the reverse -- new added.
|
||||
|
||||
The "Name" field will only be present on a mapping that has been named by
|
||||
userspace, and will show the name passed in by userspace.
|
||||
|
||||
This file is only present if the CONFIG_MMU kernel configuration option is
|
||||
enabled.
|
||||
|
||||
|
@ -630,6 +630,16 @@ tcp_fastopen_blackhole_timeout_sec - INTEGER
|
||||
0 to disable the blackhole detection.
|
||||
By default, it is set to 1hr.
|
||||
|
||||
tcp_fwmark_accept - BOOLEAN
|
||||
If set, incoming connections to listening sockets that do not have a
|
||||
socket mark will set the mark of the accepting socket to the fwmark of
|
||||
the incoming SYN packet. This will cause all packets on that connection
|
||||
(starting from the first SYNACK) to be sent with that fwmark. The
|
||||
listening socket's mark is unchanged. Listening sockets that already
|
||||
have a fwmark set via setsockopt(SOL_SOCKET, SO_MARK, ...) are
|
||||
unaffected.
|
||||
Default: 0
|
||||
|
||||
tcp_syn_retries - INTEGER
|
||||
Number of times initial SYNs for an active TCP connection attempt
|
||||
will be retransmitted. Should not be higher than 127. Default value
|
||||
|
@ -693,7 +693,8 @@ allowed to execute.
|
||||
perf_event_paranoid:
|
||||
|
||||
Controls use of the performance events system by unprivileged
|
||||
users (without CAP_SYS_ADMIN). The default value is 2.
|
||||
users (without CAP_SYS_ADMIN). The default value is 3 if
|
||||
CONFIG_SECURITY_PERF_EVENTS_RESTRICT is set, or 2 otherwise.
|
||||
|
||||
-1: Allow use of (almost) all events by all users
|
||||
Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
|
||||
@ -701,6 +702,7 @@ users (without CAP_SYS_ADMIN). The default value is 2.
|
||||
Disallow raw tracepoint access by users without CAP_SYS_ADMIN
|
||||
>=1: Disallow CPU event access by users without CAP_SYS_ADMIN
|
||||
>=2: Disallow kernel profiling by users without CAP_SYS_ADMIN
|
||||
>=3: Disallow all event access by users without CAP_SYS_ADMIN
|
||||
|
||||
==============================================================
|
||||
|
||||
|
@ -31,6 +31,7 @@ Currently, these files are in /proc/sys/vm:
|
||||
- dirty_writeback_centisecs
|
||||
- drop_caches
|
||||
- extfrag_threshold
|
||||
- extra_free_kbytes
|
||||
- hugetlb_shm_group
|
||||
- laptop_mode
|
||||
- legacy_va_layout
|
||||
@ -274,6 +275,21 @@ any throttling.
|
||||
|
||||
==============================================================
|
||||
|
||||
extra_free_kbytes
|
||||
|
||||
This parameter tells the VM to keep extra free memory between the threshold
|
||||
where background reclaim (kswapd) kicks in, and the threshold where direct
|
||||
reclaim (by allocating processes) kicks in.
|
||||
|
||||
This is useful for workloads that require low latency memory allocations
|
||||
and have a bounded burstiness in memory allocations, for example a
|
||||
realtime application that receives and transmits network traffic
|
||||
(causing in-kernel memory allocations) with a maximum total message burst
|
||||
size of 200MB may need 200MB of extra free memory to avoid direct reclaim
|
||||
related latencies.
|
||||
|
||||
==============================================================
|
||||
|
||||
hugetlb_shm_group
|
||||
|
||||
hugetlb_shm_group contains group id that is allowed to create SysV
|
||||
|
34
Makefile
34
Makefile
@ -498,7 +498,8 @@ endif
|
||||
|
||||
ifeq ($(cc-name),clang)
|
||||
ifneq ($(CROSS_COMPILE),)
|
||||
CLANG_TARGET := --target=$(notdir $(CROSS_COMPILE:%-=%))
|
||||
CLANG_TRIPLE ?= $(CROSS_COMPILE)
|
||||
CLANG_TARGET := --target=$(notdir $(CLANG_TRIPLE:%-=%))
|
||||
GCC_TOOLCHAIN := $(realpath $(dir $(shell which $(LD)))/..)
|
||||
endif
|
||||
ifneq ($(GCC_TOOLCHAIN),)
|
||||
@ -722,7 +723,6 @@ KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, gnu)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, duplicate-decl-specifier)
|
||||
|
||||
KBUILD_CFLAGS += -Wno-asm-operand-widths
|
||||
KBUILD_CFLAGS += -Wno-initializer-overrides
|
||||
KBUILD_CFLAGS += -fno-builtin
|
||||
@ -821,6 +821,30 @@ KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
|
||||
LDFLAGS_vmlinux += --gc-sections
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CFI_CLANG
|
||||
cfi-clang-flags += -fsanitize=cfi
|
||||
DISABLE_CFI_CLANG := -fno-sanitize=cfi
|
||||
ifdef CONFIG_MODULES
|
||||
cfi-clang-flags += -fsanitize-cfi-cross-dso
|
||||
DISABLE_CFI_CLANG += -fno-sanitize-cfi-cross-dso
|
||||
endif
|
||||
ifdef CONFIG_CFI_PERMISSIVE
|
||||
cfi-clang-flags += -fsanitize-recover=cfi -fno-sanitize-trap=cfi
|
||||
endif
|
||||
|
||||
# allow disabling only clang CFI where needed
|
||||
export DISABLE_CFI_CLANG
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CFI
|
||||
# cfi-flags are re-tested in prepare-compiler-check
|
||||
cfi-flags := $(cfi-clang-flags)
|
||||
KBUILD_CFLAGS += $(cfi-flags)
|
||||
|
||||
DISABLE_CFI := $(DISABLE_CFI_CLANG)
|
||||
export DISABLE_CFI
|
||||
endif
|
||||
|
||||
# arch Makefile may override CC so keep this after arch Makefile is included
|
||||
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
|
||||
|
||||
@ -1144,6 +1168,12 @@ uapi-asm-generic:
|
||||
PHONY += prepare-objtool
|
||||
prepare-objtool: $(objtool_target)
|
||||
|
||||
ifdef cfi-flags
|
||||
ifeq ($(call cc-option, $(cfi-flags)),)
|
||||
@echo Cannot use CONFIG_CFI: $(cfi-flags) not supported by compiler >&2 && exit 1
|
||||
endif
|
||||
endif
|
||||
|
||||
# Generate some files
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
28
arch/Kconfig
28
arch/Kconfig
@ -474,6 +474,34 @@ config STACKPROTECTOR_STRONG
|
||||
about 20% of all kernel functions, which increases the kernel code
|
||||
size by about 2%.
|
||||
|
||||
config CFI
|
||||
bool
|
||||
|
||||
config CFI_PERMISSIVE
|
||||
bool "Use CFI in permissive mode"
|
||||
depends on CFI
|
||||
help
|
||||
When selected, Control Flow Integrity (CFI) violations result in a
|
||||
warning instead of a kernel panic. This option is useful for finding
|
||||
CFI violations in drivers during development.
|
||||
|
||||
config CFI_CLANG
|
||||
bool "Use clang Control Flow Integrity (CFI) (EXPERIMENTAL)"
|
||||
depends on LTO_CLANG
|
||||
depends on KALLSYMS
|
||||
select CFI
|
||||
help
|
||||
This option enables clang Control Flow Integrity (CFI), which adds
|
||||
runtime checking for indirect function calls.
|
||||
|
||||
config CFI_CLANG_SHADOW
|
||||
bool "Use CFI shadow to speed up cross-module checks"
|
||||
default y
|
||||
depends on CFI_CLANG
|
||||
help
|
||||
If you select this option, the kernel builds a fast look-up table of
|
||||
CFI check functions in loaded modules to reduce overhead.
|
||||
|
||||
config HAVE_ARCH_WITHIN_STACK_FRAMES
|
||||
bool
|
||||
help
|
||||
|
@ -16,6 +16,7 @@ OBJCOPYFLAGS :=-O binary -R .comment -S
|
||||
ifneq ($(MACHINE),)
|
||||
include $(MACHINE)/Makefile.boot
|
||||
endif
|
||||
include $(srctree)/arch/arm/boot/dts/Makefile
|
||||
|
||||
# Note: the following conditions must always be true:
|
||||
# ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
|
||||
|
313
arch/arm/configs/ranchu_defconfig
Normal file
313
arch/arm/configs/ranchu_defconfig
Normal file
@ -0,0 +1,313 @@
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_TASKSTATS=y
|
||||
CONFIG_TASK_DELAY_ACCT=y
|
||||
CONFIG_TASK_XACCT=y
|
||||
CONFIG_TASK_IO_ACCOUNTING=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CPUSETS=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_OPROFILE=y
|
||||
CONFIG_ARCH_MMAP_RND_BITS=16
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
# CONFIG_IOSCHED_CFQ is not set
|
||||
CONFIG_ARCH_VIRT=y
|
||||
CONFIG_ARM_KERNMEM_PERMS=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_AEABI=y
|
||||
CONFIG_HIGHMEM=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_SECCOMP=y
|
||||
CONFIG_CMDLINE="console=ttyAMA0"
|
||||
CONFIG_VFP=y
|
||||
CONFIG_NEON=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_PM_AUTOSLEEP=y
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
CONFIG_PM_WAKELOCKS_LIMIT=0
|
||||
# CONFIG_PM_WAKELOCKS_GC is not set
|
||||
CONFIG_PM_DEBUG=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_XFRM_USER=y
|
||||
CONFIG_NET_KEY=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_INET_DIAG_DESTROY=y
|
||||
CONFIG_IP_MULTICAST=y
|
||||
CONFIG_IP_ADVANCED_ROUTER=y
|
||||
CONFIG_IP_MULTIPLE_TABLES=y
|
||||
CONFIG_IP_PNP=y
|
||||
CONFIG_IP_PNP_DHCP=y
|
||||
CONFIG_IP_PNP_BOOTP=y
|
||||
CONFIG_INET_ESP=y
|
||||
# CONFIG_INET_LRO is not set
|
||||
CONFIG_IPV6_ROUTER_PREF=y
|
||||
CONFIG_IPV6_ROUTE_INFO=y
|
||||
CONFIG_IPV6_OPTIMISTIC_DAD=y
|
||||
CONFIG_INET6_AH=y
|
||||
CONFIG_INET6_ESP=y
|
||||
CONFIG_INET6_IPCOMP=y
|
||||
CONFIG_IPV6_MIP6=y
|
||||
CONFIG_IPV6_MULTIPLE_TABLES=y
|
||||
CONFIG_NETFILTER=y
|
||||
CONFIG_NF_CONNTRACK=y
|
||||
CONFIG_NF_CONNTRACK_SECMARK=y
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y
|
||||
CONFIG_NF_CT_PROTO_DCCP=y
|
||||
CONFIG_NF_CT_PROTO_SCTP=y
|
||||
CONFIG_NF_CT_PROTO_UDPLITE=y
|
||||
CONFIG_NF_CONNTRACK_AMANDA=y
|
||||
CONFIG_NF_CONNTRACK_FTP=y
|
||||
CONFIG_NF_CONNTRACK_H323=y
|
||||
CONFIG_NF_CONNTRACK_IRC=y
|
||||
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
|
||||
CONFIG_NF_CONNTRACK_PPTP=y
|
||||
CONFIG_NF_CONNTRACK_SANE=y
|
||||
CONFIG_NF_CONNTRACK_TFTP=y
|
||||
CONFIG_NF_CT_NETLINK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
|
||||
CONFIG_NETFILTER_XT_TARGET_MARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TRACE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
|
||||
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HELPER=y
|
||||
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LENGTH=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MAC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_POLICY=y
|
||||
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
|
||||
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STRING=y
|
||||
CONFIG_NETFILTER_XT_MATCH_TIME=y
|
||||
CONFIG_NETFILTER_XT_MATCH_U32=y
|
||||
CONFIG_NF_CONNTRACK_IPV4=y
|
||||
CONFIG_IP_NF_IPTABLES=y
|
||||
CONFIG_IP_NF_MATCH_AH=y
|
||||
CONFIG_IP_NF_MATCH_ECN=y
|
||||
CONFIG_IP_NF_MATCH_TTL=y
|
||||
CONFIG_IP_NF_FILTER=y
|
||||
CONFIG_IP_NF_TARGET_REJECT=y
|
||||
CONFIG_IP_NF_MANGLE=y
|
||||
CONFIG_IP_NF_RAW=y
|
||||
CONFIG_IP_NF_SECURITY=y
|
||||
CONFIG_IP_NF_ARPTABLES=y
|
||||
CONFIG_IP_NF_ARPFILTER=y
|
||||
CONFIG_IP_NF_ARP_MANGLE=y
|
||||
CONFIG_NF_CONNTRACK_IPV6=y
|
||||
CONFIG_IP6_NF_IPTABLES=y
|
||||
CONFIG_IP6_NF_FILTER=y
|
||||
CONFIG_IP6_NF_TARGET_REJECT=y
|
||||
CONFIG_IP6_NF_MANGLE=y
|
||||
CONFIG_IP6_NF_RAW=y
|
||||
CONFIG_BRIDGE=y
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_HTB=y
|
||||
CONFIG_NET_CLS_U32=y
|
||||
CONFIG_NET_EMATCH=y
|
||||
CONFIG_NET_EMATCH_U32=y
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
# CONFIG_WIRELESS is not set
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_MTD=y
|
||||
CONFIG_MTD_CMDLINE_PARTS=y
|
||||
CONFIG_MTD_BLOCK=y
|
||||
CONFIG_MTD_CFI=y
|
||||
CONFIG_MTD_CFI_INTELEXT=y
|
||||
CONFIG_MTD_CFI_AMDSTD=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=8192
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_MD=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_DM_CRYPT=y
|
||||
CONFIG_DM_UEVENT=y
|
||||
CONFIG_DM_VERITY=y
|
||||
CONFIG_DM_VERITY_FEC=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_TUN=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_SMSC911X=y
|
||||
CONFIG_PPP=y
|
||||
CONFIG_PPP_BSDCOMP=y
|
||||
CONFIG_PPP_DEFLATE=y
|
||||
CONFIG_PPP_MPPE=y
|
||||
CONFIG_USB_USBNET=y
|
||||
# CONFIG_WLAN is not set
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_INPUT_KEYRESET=y
|
||||
CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_INPUT_JOYSTICK=y
|
||||
CONFIG_JOYSTICK_XPAD=y
|
||||
CONFIG_JOYSTICK_XPAD_FF=y
|
||||
CONFIG_JOYSTICK_XPAD_LEDS=y
|
||||
CONFIG_INPUT_TABLET=y
|
||||
CONFIG_TABLET_USB_ACECAD=y
|
||||
CONFIG_TABLET_USB_AIPTEK=y
|
||||
CONFIG_TABLET_USB_GTCO=y
|
||||
CONFIG_TABLET_USB_HANWANG=y
|
||||
CONFIG_TABLET_USB_KBTAB=y
|
||||
CONFIG_INPUT_MISC=y
|
||||
CONFIG_INPUT_UINPUT=y
|
||||
CONFIG_INPUT_GPIO=y
|
||||
# CONFIG_SERIO_SERPORT is not set
|
||||
CONFIG_SERIO_AMBAKMI=y
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_DEVMEM is not set
|
||||
# CONFIG_DEVKMEM is not set
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
CONFIG_VIRTIO_CONSOLE=y
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_MEDIA_SUPPORT=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_GOLDFISH=y
|
||||
CONFIG_FB_SIMPLE=y
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
CONFIG_LOGO=y
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
CONFIG_HIDRAW=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_ACRUX=y
|
||||
CONFIG_HID_ACRUX_FF=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_PRODIKEYS=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
CONFIG_HID_DRAGONRISE=y
|
||||
CONFIG_DRAGONRISE_FF=y
|
||||
CONFIG_HID_EMS_FF=y
|
||||
CONFIG_HID_ELECOM=y
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_HOLTEK=y
|
||||
CONFIG_HID_KEYTOUCH=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_UCLOGIC=y
|
||||
CONFIG_HID_WALTOP=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_TWINHAN=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_LCPOWER=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_HID_LOGITECH_DJ=y
|
||||
CONFIG_LOGITECH_FF=y
|
||||
CONFIG_LOGIRUMBLEPAD2_FF=y
|
||||
CONFIG_LOGIG940_FF=y
|
||||
CONFIG_HID_MAGICMOUSE=y
|
||||
CONFIG_HID_MICROSOFT=y
|
||||
CONFIG_HID_MONTEREY=y
|
||||
CONFIG_HID_MULTITOUCH=y
|
||||
CONFIG_HID_NTRIG=y
|
||||
CONFIG_HID_ORTEK=y
|
||||
CONFIG_HID_PANTHERLORD=y
|
||||
CONFIG_PANTHERLORD_FF=y
|
||||
CONFIG_HID_PETALYNX=y
|
||||
CONFIG_HID_PICOLCD=y
|
||||
CONFIG_HID_PRIMAX=y
|
||||
CONFIG_HID_ROCCAT=y
|
||||
CONFIG_HID_SAITEK=y
|
||||
CONFIG_HID_SAMSUNG=y
|
||||
CONFIG_HID_SONY=y
|
||||
CONFIG_HID_SPEEDLINK=y
|
||||
CONFIG_HID_SUNPLUS=y
|
||||
CONFIG_HID_GREENASIA=y
|
||||
CONFIG_GREENASIA_FF=y
|
||||
CONFIG_HID_SMARTJOYPLUS=y
|
||||
CONFIG_SMARTJOYPLUS_FF=y
|
||||
CONFIG_HID_TIVO=y
|
||||
CONFIG_HID_TOPSEED=y
|
||||
CONFIG_HID_THRUSTMASTER=y
|
||||
CONFIG_HID_WACOM=y
|
||||
CONFIG_HID_WIIMOTE=y
|
||||
CONFIG_HID_ZEROPLUS=y
|
||||
CONFIG_HID_ZYDACRON=y
|
||||
CONFIG_USB_HIDDEV=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_OTG_WAKELOCK=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_PL031=y
|
||||
CONFIG_VIRTIO_MMIO=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_ASHMEM=y
|
||||
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
|
||||
CONFIG_SYNC=y
|
||||
CONFIG_SW_SYNC=y
|
||||
CONFIG_SW_SYNC_USER=y
|
||||
CONFIG_ION=y
|
||||
CONFIG_GOLDFISH_AUDIO=y
|
||||
CONFIG_GOLDFISH=y
|
||||
CONFIG_GOLDFISH_PIPE=y
|
||||
CONFIG_ANDROID=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_FUSE_FS=y
|
||||
CONFIG_CUSE=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_PSTORE=y
|
||||
CONFIG_PSTORE_CONSOLE=y
|
||||
CONFIG_PSTORE_RAM=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_ROOT_NFS=y
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DETECT_HUNG_TASK=y
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_TIMER_STATS=y
|
||||
CONFIG_ENABLE_DEFAULT_TRACERS=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_NETWORK=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_VIRTUALIZATION=y
|
@ -1289,6 +1289,23 @@ config CMDLINE
|
||||
entering them here. As a minimum, you should specify the the
|
||||
root device (e.g. root=/dev/nfs).
|
||||
|
||||
choice
|
||||
prompt "Kernel command line type" if CMDLINE != ""
|
||||
default CMDLINE_FROM_BOOTLOADER
|
||||
|
||||
config CMDLINE_FROM_BOOTLOADER
|
||||
bool "Use bootloader kernel arguments if available"
|
||||
help
|
||||
Uses the command-line options passed by the boot loader. If
|
||||
the boot loader doesn't provide any, the default kernel command
|
||||
string provided in CMDLINE will be used.
|
||||
|
||||
config CMDLINE_EXTEND
|
||||
bool "Extend bootloader kernel arguments"
|
||||
help
|
||||
The command-line arguments provided by the boot loader will be
|
||||
appended to the default kernel command string.
|
||||
|
||||
config CMDLINE_FORCE
|
||||
bool "Always use the default kernel command string"
|
||||
help
|
||||
@ -1296,6 +1313,7 @@ config CMDLINE_FORCE
|
||||
loader passes other arguments to the kernel.
|
||||
This is useful if you cannot or don't want to change the
|
||||
command-line options your boot loader passes to the kernel.
|
||||
endchoice
|
||||
|
||||
config EFI_STUB
|
||||
bool
|
||||
|
@ -119,7 +119,7 @@ core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
|
||||
boot := arch/arm64/boot
|
||||
|
||||
ifeq ($(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),y)
|
||||
KBUILD_IMAGE := $(boot)/$(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_KERNEL_IMAGE_NAME))
|
||||
KBUILD_IMAGE := $(boot)/$(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_KERNEL_IMAGE_NAME))
|
||||
else
|
||||
KBUILD_IMAGE := $(boot)/Image.gz
|
||||
endif
|
||||
@ -152,7 +152,10 @@ dtbs: prepare scripts
|
||||
dtbs_install:
|
||||
$(Q)$(MAKE) $(dtbinst)=$(boot)/dts
|
||||
|
||||
Image.gz-dtb: vmlinux scripts dtbs
|
||||
Image-dtb: vmlinux scripts dtbs
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
Image.gz-dtb: vmlinux scripts dtbs Image.gz
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
PHONY += vdso_install
|
||||
|
1
arch/arm64/boot/.gitignore
vendored
1
arch/arm64/boot/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
Image
|
||||
Image-dtb
|
||||
Image.gz
|
||||
Image.gz-dtb
|
||||
|
@ -34,6 +34,9 @@ $(obj)/Image: vmlinux FORCE
|
||||
$(obj)/Image.bz2: $(obj)/Image FORCE
|
||||
$(call if_changed,bzip2)
|
||||
|
||||
$(obj)/Image-dtb: $(obj)/Image $(DTB_OBJS) FORCE
|
||||
$(call if_changed,cat)
|
||||
|
||||
$(obj)/Image.gz: $(obj)/Image FORCE
|
||||
$(call if_changed,gzip)
|
||||
|
||||
|
309
arch/arm64/configs/ranchu64_defconfig
Normal file
309
arch/arm64/configs/ranchu64_defconfig
Normal file
@ -0,0 +1,309 @@
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
# CONFIG_SWAP is not set
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_BSD_PROCESS_ACCT_V3=y
|
||||
CONFIG_TASKSTATS=y
|
||||
CONFIG_TASK_DELAY_ACCT=y
|
||||
CONFIG_TASK_XACCT=y
|
||||
CONFIG_TASK_IO_ACCOUNTING=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_LOG_BUF_SHIFT=14
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_SCHED_AUTOGROUP=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_ARCH_MMAP_RND_BITS=24
|
||||
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
|
||||
# CONFIG_BLK_DEV_BSG is not set
|
||||
# CONFIG_IOSCHED_DEADLINE is not set
|
||||
CONFIG_ARCH_VEXPRESS=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_PREEMPT=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_SECCOMP=y
|
||||
CONFIG_ARMV8_DEPRECATED=y
|
||||
CONFIG_SWP_EMULATION=y
|
||||
CONFIG_CP15_BARRIER_EMULATION=y
|
||||
CONFIG_SETEND_EMULATION=y
|
||||
CONFIG_CMDLINE="console=ttyAMA0"
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_COMPAT=y
|
||||
CONFIG_PM_AUTOSLEEP=y
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
CONFIG_PM_WAKELOCKS_LIMIT=0
|
||||
# CONFIG_PM_WAKELOCKS_GC is not set
|
||||
CONFIG_PM_DEBUG=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_XFRM_USER=y
|
||||
CONFIG_NET_KEY=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_INET_DIAG_DESTROY=y
|
||||
CONFIG_IP_MULTICAST=y
|
||||
CONFIG_IP_ADVANCED_ROUTER=y
|
||||
CONFIG_IP_MULTIPLE_TABLES=y
|
||||
CONFIG_IP_PNP=y
|
||||
CONFIG_IP_PNP_DHCP=y
|
||||
CONFIG_IP_PNP_BOOTP=y
|
||||
CONFIG_INET_ESP=y
|
||||
# CONFIG_INET_LRO is not set
|
||||
CONFIG_IPV6_ROUTER_PREF=y
|
||||
CONFIG_IPV6_ROUTE_INFO=y
|
||||
CONFIG_IPV6_OPTIMISTIC_DAD=y
|
||||
CONFIG_INET6_AH=y
|
||||
CONFIG_INET6_ESP=y
|
||||
CONFIG_INET6_IPCOMP=y
|
||||
CONFIG_IPV6_MIP6=y
|
||||
CONFIG_IPV6_MULTIPLE_TABLES=y
|
||||
CONFIG_NETFILTER=y
|
||||
CONFIG_NF_CONNTRACK=y
|
||||
CONFIG_NF_CONNTRACK_SECMARK=y
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y
|
||||
CONFIG_NF_CT_PROTO_DCCP=y
|
||||
CONFIG_NF_CT_PROTO_SCTP=y
|
||||
CONFIG_NF_CT_PROTO_UDPLITE=y
|
||||
CONFIG_NF_CONNTRACK_AMANDA=y
|
||||
CONFIG_NF_CONNTRACK_FTP=y
|
||||
CONFIG_NF_CONNTRACK_H323=y
|
||||
CONFIG_NF_CONNTRACK_IRC=y
|
||||
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
|
||||
CONFIG_NF_CONNTRACK_PPTP=y
|
||||
CONFIG_NF_CONNTRACK_SANE=y
|
||||
CONFIG_NF_CONNTRACK_TFTP=y
|
||||
CONFIG_NF_CT_NETLINK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
|
||||
CONFIG_NETFILTER_XT_TARGET_MARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TRACE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
|
||||
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HELPER=y
|
||||
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LENGTH=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MAC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_POLICY=y
|
||||
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
|
||||
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STRING=y
|
||||
CONFIG_NETFILTER_XT_MATCH_TIME=y
|
||||
CONFIG_NETFILTER_XT_MATCH_U32=y
|
||||
CONFIG_NF_CONNTRACK_IPV4=y
|
||||
CONFIG_IP_NF_IPTABLES=y
|
||||
CONFIG_IP_NF_MATCH_AH=y
|
||||
CONFIG_IP_NF_MATCH_ECN=y
|
||||
CONFIG_IP_NF_MATCH_RPFILTER=y
|
||||
CONFIG_IP_NF_MATCH_TTL=y
|
||||
CONFIG_IP_NF_FILTER=y
|
||||
CONFIG_IP_NF_TARGET_REJECT=y
|
||||
CONFIG_IP_NF_MANGLE=y
|
||||
CONFIG_IP_NF_TARGET_ECN=y
|
||||
CONFIG_IP_NF_TARGET_TTL=y
|
||||
CONFIG_IP_NF_RAW=y
|
||||
CONFIG_IP_NF_SECURITY=y
|
||||
CONFIG_IP_NF_ARPTABLES=y
|
||||
CONFIG_IP_NF_ARPFILTER=y
|
||||
CONFIG_IP_NF_ARP_MANGLE=y
|
||||
CONFIG_NF_CONNTRACK_IPV6=y
|
||||
CONFIG_IP6_NF_IPTABLES=y
|
||||
CONFIG_IP6_NF_MATCH_AH=y
|
||||
CONFIG_IP6_NF_MATCH_EUI64=y
|
||||
CONFIG_IP6_NF_MATCH_FRAG=y
|
||||
CONFIG_IP6_NF_MATCH_OPTS=y
|
||||
CONFIG_IP6_NF_MATCH_HL=y
|
||||
CONFIG_IP6_NF_MATCH_IPV6HEADER=y
|
||||
CONFIG_IP6_NF_MATCH_MH=y
|
||||
CONFIG_IP6_NF_MATCH_RT=y
|
||||
CONFIG_IP6_NF_TARGET_HL=y
|
||||
CONFIG_IP6_NF_FILTER=y
|
||||
CONFIG_IP6_NF_TARGET_REJECT=y
|
||||
CONFIG_IP6_NF_MANGLE=y
|
||||
CONFIG_IP6_NF_RAW=y
|
||||
CONFIG_BRIDGE=y
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_HTB=y
|
||||
CONFIG_NET_CLS_U32=y
|
||||
CONFIG_NET_EMATCH=y
|
||||
CONFIG_NET_EMATCH_U32=y
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
# CONFIG_WIRELESS is not set
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=8192
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_PROC_FS is not set
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
CONFIG_MD=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_DM_CRYPT=y
|
||||
CONFIG_DM_UEVENT=y
|
||||
CONFIG_DM_VERITY=y
|
||||
CONFIG_DM_VERITY_FEC=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_TUN=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_SMC91X=y
|
||||
CONFIG_PPP=y
|
||||
CONFIG_PPP_BSDCOMP=y
|
||||
CONFIG_PPP_DEFLATE=y
|
||||
CONFIG_PPP_MPPE=y
|
||||
# CONFIG_WLAN is not set
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_INPUT_KEYRESET=y
|
||||
CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_INPUT_JOYSTICK=y
|
||||
CONFIG_INPUT_TABLET=y
|
||||
CONFIG_INPUT_MISC=y
|
||||
CONFIG_INPUT_UINPUT=y
|
||||
CONFIG_INPUT_GPIO=y
|
||||
# CONFIG_SERIO_SERPORT is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_DEVMEM is not set
|
||||
# CONFIG_DEVKMEM is not set
|
||||
CONFIG_SERIAL_AMBA_PL011=y
|
||||
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
|
||||
CONFIG_VIRTIO_CONSOLE=y
|
||||
# CONFIG_HW_RANDOM is not set
|
||||
CONFIG_BATTERY_GOLDFISH=y
|
||||
# CONFIG_HWMON is not set
|
||||
CONFIG_MEDIA_SUPPORT=y
|
||||
CONFIG_FB=y
|
||||
CONFIG_FB_GOLDFISH=y
|
||||
CONFIG_FB_SIMPLE=y
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
CONFIG_LOGO=y
|
||||
# CONFIG_LOGO_LINUX_MONO is not set
|
||||
# CONFIG_LOGO_LINUX_VGA16 is not set
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
CONFIG_HIDRAW=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_ACRUX=y
|
||||
CONFIG_HID_ACRUX_FF=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_PRODIKEYS=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
CONFIG_HID_DRAGONRISE=y
|
||||
CONFIG_DRAGONRISE_FF=y
|
||||
CONFIG_HID_EMS_FF=y
|
||||
CONFIG_HID_ELECOM=y
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_KEYTOUCH=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_WALTOP=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_TWINHAN=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_LCPOWER=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_HID_LOGITECH_DJ=y
|
||||
CONFIG_LOGITECH_FF=y
|
||||
CONFIG_LOGIRUMBLEPAD2_FF=y
|
||||
CONFIG_LOGIG940_FF=y
|
||||
CONFIG_HID_MAGICMOUSE=y
|
||||
CONFIG_HID_MICROSOFT=y
|
||||
CONFIG_HID_MONTEREY=y
|
||||
CONFIG_HID_MULTITOUCH=y
|
||||
CONFIG_HID_ORTEK=y
|
||||
CONFIG_HID_PANTHERLORD=y
|
||||
CONFIG_PANTHERLORD_FF=y
|
||||
CONFIG_HID_PETALYNX=y
|
||||
CONFIG_HID_PICOLCD=y
|
||||
CONFIG_HID_PRIMAX=y
|
||||
CONFIG_HID_SAITEK=y
|
||||
CONFIG_HID_SAMSUNG=y
|
||||
CONFIG_HID_SPEEDLINK=y
|
||||
CONFIG_HID_SUNPLUS=y
|
||||
CONFIG_HID_GREENASIA=y
|
||||
CONFIG_GREENASIA_FF=y
|
||||
CONFIG_HID_SMARTJOYPLUS=y
|
||||
CONFIG_SMARTJOYPLUS_FF=y
|
||||
CONFIG_HID_TIVO=y
|
||||
CONFIG_HID_TOPSEED=y
|
||||
CONFIG_HID_THRUSTMASTER=y
|
||||
CONFIG_HID_WACOM=y
|
||||
CONFIG_HID_WIIMOTE=y
|
||||
CONFIG_HID_ZEROPLUS=y
|
||||
CONFIG_HID_ZYDACRON=y
|
||||
# CONFIG_USB_SUPPORT is not set
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_VIRTIO_MMIO=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_ASHMEM=y
|
||||
CONFIG_ANDROID_TIMED_GPIO=y
|
||||
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
|
||||
CONFIG_SYNC=y
|
||||
CONFIG_SW_SYNC=y
|
||||
CONFIG_SW_SYNC_USER=y
|
||||
CONFIG_ION=y
|
||||
CONFIG_GOLDFISH_AUDIO=y
|
||||
CONFIG_GOLDFISH=y
|
||||
CONFIG_GOLDFISH_PIPE=y
|
||||
# CONFIG_IOMMU_SUPPORT is not set
|
||||
CONFIG_ANDROID=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
CONFIG_EXT2_FS=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_FUSE_FS=y
|
||||
CONFIG_CUSE=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
# CONFIG_MISC_FILESYSTEMS is not set
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_ROOT_NFS=y
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_FS=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
# CONFIG_SCHED_DEBUG is not set
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_TIMER_STATS=y
|
||||
# CONFIG_FTRACE is not set
|
||||
CONFIG_ATOMIC64_SELFTEST=y
|
||||
CONFIG_DEBUG_RODATA=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_NETWORK=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
@ -29,6 +29,14 @@ struct sha1_ce_state {
|
||||
|
||||
asmlinkage void sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src,
|
||||
int blocks);
|
||||
#ifdef CONFIG_CFI_CLANG
|
||||
static inline void __cfi_sha1_ce_transform(struct sha1_state *sst,
|
||||
u8 const *src, int blocks)
|
||||
{
|
||||
sha1_ce_transform((struct sha1_ce_state *)sst, src, blocks);
|
||||
}
|
||||
#define sha1_ce_transform __cfi_sha1_ce_transform
|
||||
#endif
|
||||
|
||||
const u32 sha1_ce_offsetof_count = offsetof(struct sha1_ce_state, sst.count);
|
||||
const u32 sha1_ce_offsetof_finalize = offsetof(struct sha1_ce_state, finalize);
|
||||
|
@ -29,6 +29,14 @@ struct sha256_ce_state {
|
||||
|
||||
asmlinkage void sha2_ce_transform(struct sha256_ce_state *sst, u8 const *src,
|
||||
int blocks);
|
||||
#ifdef CONFIG_CFI_CLANG
|
||||
static inline void __cfi_sha2_ce_transform(struct sha256_state *sst,
|
||||
u8 const *src, int blocks)
|
||||
{
|
||||
sha2_ce_transform((struct sha256_ce_state *)sst, src, blocks);
|
||||
}
|
||||
#define sha2_ce_transform __cfi_sha2_ce_transform
|
||||
#endif
|
||||
|
||||
const u32 sha256_ce_offsetof_count = offsetof(struct sha256_ce_state,
|
||||
sst.count);
|
||||
|
@ -147,7 +147,7 @@ static inline void cpu_install_idmap(void)
|
||||
* Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD,
|
||||
* avoiding the possibility of conflicting TLB entries being allocated.
|
||||
*/
|
||||
static inline void cpu_replace_ttbr1(pgd_t *pgdp)
|
||||
static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgdp)
|
||||
{
|
||||
typedef void (ttbr_replace_func)(phys_addr_t);
|
||||
extern ttbr_replace_func idmap_cpu_replace_ttbr1;
|
||||
|
@ -902,7 +902,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
|
||||
return !has_cpuid_feature(entry, scope);
|
||||
}
|
||||
|
||||
static void
|
||||
static void __nocfi
|
||||
kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
|
||||
{
|
||||
typedef void (kpti_remap_fn)(int, int, phys_addr_t);
|
||||
|
@ -4,7 +4,11 @@
|
||||
#
|
||||
|
||||
ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING \
|
||||
$(DISABLE_STACKLEAK_PLUGIN)
|
||||
$(DISABLE_STACKLEAK_PLUGIN) $(DISABLE_CFI)
|
||||
|
||||
ifeq ($(cc-name),clang)
|
||||
ccflags-y += -fno-jump-tables
|
||||
endif
|
||||
|
||||
KVM=../../../../virt/kvm
|
||||
|
||||
|
421
arch/x86/configs/i386_ranchu_defconfig
Normal file
421
arch/x86/configs/i386_ranchu_defconfig
Normal file
@ -0,0 +1,421 @@
|
||||
# CONFIG_64BIT is not set
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_TASKSTATS=y
|
||||
CONFIG_TASK_DELAY_ACCT=y
|
||||
CONFIG_TASK_XACCT=y
|
||||
CONFIG_TASK_IO_ACCOUNTING=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_SYSCTL_SYSCALL=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_ARCH_MMAP_RND_BITS=16
|
||||
CONFIG_PARTITION_ADVANCED=y
|
||||
CONFIG_OSF_PARTITION=y
|
||||
CONFIG_AMIGA_PARTITION=y
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_BSD_DISKLABEL=y
|
||||
CONFIG_MINIX_SUBPARTITION=y
|
||||
CONFIG_SOLARIS_X86_PARTITION=y
|
||||
CONFIG_UNIXWARE_DISKLABEL=y
|
||||
CONFIG_SGI_PARTITION=y
|
||||
CONFIG_SUN_PARTITION=y
|
||||
CONFIG_KARMA_PARTITION=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_X86_BIGSMP=y
|
||||
CONFIG_MCORE2=y
|
||||
CONFIG_X86_GENERIC=y
|
||||
CONFIG_HPET_TIMER=y
|
||||
CONFIG_NR_CPUS=512
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_X86_MCE is not set
|
||||
CONFIG_X86_REBOOTFIXUPS=y
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_CMA=y
|
||||
# CONFIG_MTRR_SANITIZER is not set
|
||||
CONFIG_EFI=y
|
||||
CONFIG_EFI_STUB=y
|
||||
CONFIG_HZ_100=y
|
||||
CONFIG_PHYSICAL_START=0x100000
|
||||
CONFIG_PM_AUTOSLEEP=y
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
CONFIG_PM_WAKELOCKS_LIMIT=0
|
||||
# CONFIG_PM_WAKELOCKS_GC is not set
|
||||
CONFIG_PM_DEBUG=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
# CONFIG_PCIEASPM is not set
|
||||
CONFIG_PCCARD=y
|
||||
CONFIG_YENTA=y
|
||||
CONFIG_HOTPLUG_PCI=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_BINFMT_MISC=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_XFRM_USER=y
|
||||
CONFIG_NET_KEY=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IP_MULTICAST=y
|
||||
CONFIG_IP_ADVANCED_ROUTER=y
|
||||
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_IP_MROUTE=y
|
||||
CONFIG_IP_PIMSM_V1=y
|
||||
CONFIG_IP_PIMSM_V2=y
|
||||
CONFIG_SYN_COOKIES=y
|
||||
CONFIG_INET_ESP=y
|
||||
# CONFIG_INET_XFRM_MODE_BEET is not set
|
||||
# CONFIG_INET_LRO is not set
|
||||
CONFIG_INET_DIAG_DESTROY=y
|
||||
CONFIG_IPV6_ROUTER_PREF=y
|
||||
CONFIG_IPV6_ROUTE_INFO=y
|
||||
CONFIG_IPV6_OPTIMISTIC_DAD=y
|
||||
CONFIG_INET6_AH=y
|
||||
CONFIG_INET6_ESP=y
|
||||
CONFIG_INET6_IPCOMP=y
|
||||
CONFIG_IPV6_MIP6=y
|
||||
CONFIG_IPV6_MULTIPLE_TABLES=y
|
||||
CONFIG_NETLABEL=y
|
||||
CONFIG_NETFILTER=y
|
||||
CONFIG_NF_CONNTRACK=y
|
||||
CONFIG_NF_CONNTRACK_SECMARK=y
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y
|
||||
CONFIG_NF_CT_PROTO_DCCP=y
|
||||
CONFIG_NF_CT_PROTO_SCTP=y
|
||||
CONFIG_NF_CT_PROTO_UDPLITE=y
|
||||
CONFIG_NF_CONNTRACK_AMANDA=y
|
||||
CONFIG_NF_CONNTRACK_FTP=y
|
||||
CONFIG_NF_CONNTRACK_H323=y
|
||||
CONFIG_NF_CONNTRACK_IRC=y
|
||||
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
|
||||
CONFIG_NF_CONNTRACK_PPTP=y
|
||||
CONFIG_NF_CONNTRACK_SANE=y
|
||||
CONFIG_NF_CONNTRACK_TFTP=y
|
||||
CONFIG_NF_CT_NETLINK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
|
||||
CONFIG_NETFILTER_XT_TARGET_MARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TRACE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
|
||||
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HELPER=y
|
||||
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LENGTH=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MAC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_POLICY=y
|
||||
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
|
||||
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STRING=y
|
||||
CONFIG_NETFILTER_XT_MATCH_TIME=y
|
||||
CONFIG_NETFILTER_XT_MATCH_U32=y
|
||||
CONFIG_NF_CONNTRACK_IPV4=y
|
||||
CONFIG_IP_NF_IPTABLES=y
|
||||
CONFIG_IP_NF_MATCH_AH=y
|
||||
CONFIG_IP_NF_MATCH_ECN=y
|
||||
CONFIG_IP_NF_MATCH_TTL=y
|
||||
CONFIG_IP_NF_FILTER=y
|
||||
CONFIG_IP_NF_TARGET_REJECT=y
|
||||
CONFIG_IP_NF_MANGLE=y
|
||||
CONFIG_IP_NF_RAW=y
|
||||
CONFIG_IP_NF_SECURITY=y
|
||||
CONFIG_IP_NF_ARPTABLES=y
|
||||
CONFIG_IP_NF_ARPFILTER=y
|
||||
CONFIG_IP_NF_ARP_MANGLE=y
|
||||
CONFIG_NF_CONNTRACK_IPV6=y
|
||||
CONFIG_IP6_NF_IPTABLES=y
|
||||
CONFIG_IP6_NF_FILTER=y
|
||||
CONFIG_IP6_NF_TARGET_REJECT=y
|
||||
CONFIG_IP6_NF_MANGLE=y
|
||||
CONFIG_IP6_NF_RAW=y
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_HTB=y
|
||||
CONFIG_NET_CLS_U32=y
|
||||
CONFIG_NET_EMATCH=y
|
||||
CONFIG_NET_EMATCH_U32=y
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
CONFIG_CFG80211=y
|
||||
CONFIG_MAC80211=y
|
||||
CONFIG_MAC80211_LEDS=y
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_CMA_SIZE_MBYTES=16
|
||||
CONFIG_CONNECTOR=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=8192
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BLK_DEV_SR=y
|
||||
CONFIG_BLK_DEV_SR_VENDOR=y
|
||||
CONFIG_CHR_DEV_SG=y
|
||||
CONFIG_SCSI_CONSTANTS=y
|
||||
CONFIG_SCSI_SPI_ATTRS=y
|
||||
CONFIG_SCSI_ISCSI_ATTRS=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
CONFIG_ATA=y
|
||||
CONFIG_SATA_AHCI=y
|
||||
CONFIG_ATA_PIIX=y
|
||||
CONFIG_PATA_AMD=y
|
||||
CONFIG_PATA_OLDPIIX=y
|
||||
CONFIG_PATA_SCH=y
|
||||
CONFIG_PATA_MPIIX=y
|
||||
CONFIG_ATA_GENERIC=y
|
||||
CONFIG_MD=y
|
||||
CONFIG_BLK_DEV_MD=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_DM_DEBUG=y
|
||||
CONFIG_DM_CRYPT=y
|
||||
CONFIG_DM_MIRROR=y
|
||||
CONFIG_DM_ZERO=y
|
||||
CONFIG_DM_UEVENT=y
|
||||
CONFIG_DM_VERITY=y
|
||||
CONFIG_DM_VERITY_FEC=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_NETCONSOLE=y
|
||||
CONFIG_TUN=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_BNX2=y
|
||||
CONFIG_TIGON3=y
|
||||
CONFIG_NET_TULIP=y
|
||||
CONFIG_E100=y
|
||||
CONFIG_E1000=y
|
||||
CONFIG_E1000E=y
|
||||
CONFIG_SKY2=y
|
||||
CONFIG_NE2K_PCI=y
|
||||
CONFIG_FORCEDETH=y
|
||||
CONFIG_8139TOO=y
|
||||
# CONFIG_8139TOO_PIO is not set
|
||||
CONFIG_R8169=y
|
||||
CONFIG_FDDI=y
|
||||
CONFIG_PPP=y
|
||||
CONFIG_PPP_BSDCOMP=y
|
||||
CONFIG_PPP_DEFLATE=y
|
||||
CONFIG_PPP_MPPE=y
|
||||
CONFIG_USB_USBNET=y
|
||||
CONFIG_INPUT_POLLDEV=y
|
||||
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_INPUT_KEYRESET=y
|
||||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_INPUT_JOYSTICK=y
|
||||
CONFIG_JOYSTICK_XPAD=y
|
||||
CONFIG_JOYSTICK_XPAD_FF=y
|
||||
CONFIG_JOYSTICK_XPAD_LEDS=y
|
||||
CONFIG_INPUT_TABLET=y
|
||||
CONFIG_TABLET_USB_ACECAD=y
|
||||
CONFIG_TABLET_USB_AIPTEK=y
|
||||
CONFIG_TABLET_USB_GTCO=y
|
||||
CONFIG_TABLET_USB_HANWANG=y
|
||||
CONFIG_TABLET_USB_KBTAB=y
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
CONFIG_INPUT_MISC=y
|
||||
CONFIG_INPUT_UINPUT=y
|
||||
CONFIG_INPUT_GPIO=y
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
CONFIG_SERIAL_NONSTANDARD=y
|
||||
# CONFIG_DEVMEM is not set
|
||||
# CONFIG_DEVKMEM is not set
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_VIRTIO_CONSOLE=y
|
||||
CONFIG_NVRAM=y
|
||||
CONFIG_I2C_I801=y
|
||||
CONFIG_BATTERY_GOLDFISH=y
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_MEDIA_SUPPORT=y
|
||||
CONFIG_AGP=y
|
||||
CONFIG_AGP_AMD64=y
|
||||
CONFIG_AGP_INTEL=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_FB_MODE_HELPERS=y
|
||||
CONFIG_FB_TILEBLITTING=y
|
||||
CONFIG_FB_EFI=y
|
||||
CONFIG_FB_GOLDFISH=y
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
# CONFIG_LCD_CLASS_DEVICE is not set
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
CONFIG_HIDRAW=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_ACRUX=y
|
||||
CONFIG_HID_ACRUX_FF=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_PRODIKEYS=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
CONFIG_HID_DRAGONRISE=y
|
||||
CONFIG_DRAGONRISE_FF=y
|
||||
CONFIG_HID_EMS_FF=y
|
||||
CONFIG_HID_ELECOM=y
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_HOLTEK=y
|
||||
CONFIG_HID_KEYTOUCH=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_UCLOGIC=y
|
||||
CONFIG_HID_WALTOP=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_TWINHAN=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_LCPOWER=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_HID_LOGITECH_DJ=y
|
||||
CONFIG_LOGITECH_FF=y
|
||||
CONFIG_LOGIRUMBLEPAD2_FF=y
|
||||
CONFIG_LOGIG940_FF=y
|
||||
CONFIG_HID_MAGICMOUSE=y
|
||||
CONFIG_HID_MICROSOFT=y
|
||||
CONFIG_HID_MONTEREY=y
|
||||
CONFIG_HID_MULTITOUCH=y
|
||||
CONFIG_HID_NTRIG=y
|
||||
CONFIG_HID_ORTEK=y
|
||||
CONFIG_HID_PANTHERLORD=y
|
||||
CONFIG_PANTHERLORD_FF=y
|
||||
CONFIG_HID_PETALYNX=y
|
||||
CONFIG_HID_PICOLCD=y
|
||||
CONFIG_HID_PRIMAX=y
|
||||
CONFIG_HID_ROCCAT=y
|
||||
CONFIG_HID_SAITEK=y
|
||||
CONFIG_HID_SAMSUNG=y
|
||||
CONFIG_HID_SONY=y
|
||||
CONFIG_HID_SPEEDLINK=y
|
||||
CONFIG_HID_SUNPLUS=y
|
||||
CONFIG_HID_GREENASIA=y
|
||||
CONFIG_GREENASIA_FF=y
|
||||
CONFIG_HID_SMARTJOYPLUS=y
|
||||
CONFIG_SMARTJOYPLUS_FF=y
|
||||
CONFIG_HID_TIVO=y
|
||||
CONFIG_HID_TOPSEED=y
|
||||
CONFIG_HID_THRUSTMASTER=y
|
||||
CONFIG_HID_WACOM=y
|
||||
CONFIG_HID_WIIMOTE=y
|
||||
CONFIG_HID_ZEROPLUS=y
|
||||
CONFIG_HID_ZYDACRON=y
|
||||
CONFIG_HID_PID=y
|
||||
CONFIG_USB_HIDDEV=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_MON=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
|
||||
CONFIG_USB_OHCI_HCD=y
|
||||
CONFIG_USB_UHCI_HCD=y
|
||||
CONFIG_USB_PRINTER=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_OTG_WAKELOCK=y
|
||||
CONFIG_EDAC=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
# CONFIG_RTC_HCTOSYS is not set
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_ASHMEM=y
|
||||
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
|
||||
CONFIG_SYNC=y
|
||||
CONFIG_SW_SYNC=y
|
||||
CONFIG_SYNC_FILE=y
|
||||
CONFIG_ION=y
|
||||
CONFIG_GOLDFISH_AUDIO=y
|
||||
CONFIG_SND_HDA_INTEL=y
|
||||
CONFIG_GOLDFISH=y
|
||||
CONFIG_GOLDFISH_PIPE=y
|
||||
CONFIG_GOLDFISH_SYNC=y
|
||||
CONFIG_ANDROID=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
CONFIG_ISCSI_IBFT_FIND=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_QUOTA_NETLINK_INTERFACE=y
|
||||
# CONFIG_PRINT_QUOTA_WARNING is not set
|
||||
CONFIG_FUSE_FS=y
|
||||
CONFIG_ISO9660_FS=y
|
||||
CONFIG_JOLIET=y
|
||||
CONFIG_ZISOFS=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_PROC_KCORE=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_HUGETLBFS=y
|
||||
CONFIG_PSTORE=y
|
||||
CONFIG_PSTORE_CONSOLE=y
|
||||
CONFIG_PSTORE_RAM=y
|
||||
# CONFIG_NETWORK_FILESYSTEMS is not set
|
||||
CONFIG_NLS_DEFAULT="utf8"
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_NLS_UTF8=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_FRAME_WARN=2048
|
||||
# CONFIG_UNUSED_SYMBOLS is not set
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_TIMER_STATS=y
|
||||
CONFIG_SCHED_TRACER=y
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_NETWORK=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_CRYPTO_AES_586=y
|
||||
CONFIG_CRYPTO_TWOFISH=y
|
||||
CONFIG_ASYMMETRIC_KEY_TYPE=y
|
||||
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
|
||||
CONFIG_X509_CERTIFICATE_PARSER=y
|
||||
CONFIG_PKCS7_MESSAGE_PARSER=y
|
||||
CONFIG_PKCS7_TEST_KEY=y
|
||||
# CONFIG_VIRTUALIZATION is not set
|
||||
CONFIG_CRC_T10DIF=y
|
464
arch/x86/configs/x86_64_cuttlefish_defconfig
Normal file
464
arch/x86/configs/x86_64_cuttlefish_defconfig
Normal file
@ -0,0 +1,464 @@
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
# CONFIG_FHANDLE is not set
|
||||
# CONFIG_USELIB is not set
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_TASKSTATS=y
|
||||
CONFIG_TASK_DELAY_ACCT=y
|
||||
CONFIG_TASK_XACCT=y
|
||||
CONFIG_TASK_IO_ACCOUNTING=y
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_MEMCG=y
|
||||
CONFIG_MEMCG_SWAP=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_BPF=y
|
||||
CONFIG_NAMESPACES=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
# CONFIG_RD_LZ4 is not set
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
# CONFIG_PCSPKR_PLATFORM is not set
|
||||
CONFIG_BPF_SYSCALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_PROFILING=y
|
||||
CONFIG_OPROFILE=y
|
||||
CONFIG_KPROBES=y
|
||||
CONFIG_JUMP_LABEL=y
|
||||
CONFIG_CC_STACKPROTECTOR_STRONG=y
|
||||
CONFIG_REFCOUNT_FULL=y
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODVERSIONS=y
|
||||
CONFIG_PARTITION_ADVANCED=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_HYPERVISOR_GUEST=y
|
||||
CONFIG_PARAVIRT=y
|
||||
CONFIG_PARAVIRT_SPINLOCKS=y
|
||||
CONFIG_MCORE2=y
|
||||
CONFIG_PROCESSOR_SELECT=y
|
||||
# CONFIG_CPU_SUP_CENTAUR is not set
|
||||
CONFIG_NR_CPUS=8
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_MICROCODE is not set
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
|
||||
CONFIG_TRANSPARENT_HUGEPAGE=y
|
||||
CONFIG_ZSMALLOC=y
|
||||
# CONFIG_MTRR is not set
|
||||
CONFIG_HZ_100=y
|
||||
CONFIG_KEXEC=y
|
||||
CONFIG_CRASH_DUMP=y
|
||||
CONFIG_PHYSICAL_START=0x200000
|
||||
CONFIG_PHYSICAL_ALIGN=0x1000000
|
||||
CONFIG_CMDLINE_BOOL=y
|
||||
CONFIG_CMDLINE="console=ttyS0 reboot=p"
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
CONFIG_PM_WAKELOCKS_LIMIT=0
|
||||
# CONFIG_PM_WAKELOCKS_GC is not set
|
||||
CONFIG_PM_DEBUG=y
|
||||
CONFIG_ACPI_PROCFS_POWER=y
|
||||
# CONFIG_ACPI_FAN is not set
|
||||
# CONFIG_ACPI_THERMAL is not set
|
||||
# CONFIG_X86_PM_TIMER is not set
|
||||
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
||||
CONFIG_X86_ACPI_CPUFREQ=y
|
||||
CONFIG_PCI_MMCONFIG=y
|
||||
CONFIG_PCI_MSI=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_BINFMT_MISC=y
|
||||
CONFIG_IA32_EMULATION=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_XFRM_USER=y
|
||||
CONFIG_NET_KEY=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IP_MULTICAST=y
|
||||
CONFIG_IP_ADVANCED_ROUTER=y
|
||||
CONFIG_IP_MULTIPLE_TABLES=y
|
||||
CONFIG_IP_ROUTE_MULTIPATH=y
|
||||
CONFIG_IP_ROUTE_VERBOSE=y
|
||||
CONFIG_IP_MROUTE=y
|
||||
CONFIG_IP_PIMSM_V1=y
|
||||
CONFIG_IP_PIMSM_V2=y
|
||||
CONFIG_SYN_COOKIES=y
|
||||
CONFIG_NET_IPVTI=y
|
||||
CONFIG_INET_ESP=y
|
||||
# CONFIG_INET_XFRM_MODE_BEET is not set
|
||||
CONFIG_INET_DIAG_DESTROY=y
|
||||
CONFIG_TCP_CONG_ADVANCED=y
|
||||
# CONFIG_TCP_CONG_BIC is not set
|
||||
# CONFIG_TCP_CONG_WESTWOOD is not set
|
||||
# CONFIG_TCP_CONG_HTCP is not set
|
||||
CONFIG_TCP_MD5SIG=y
|
||||
CONFIG_IPV6_ROUTER_PREF=y
|
||||
CONFIG_IPV6_ROUTE_INFO=y
|
||||
CONFIG_IPV6_OPTIMISTIC_DAD=y
|
||||
CONFIG_INET6_AH=y
|
||||
CONFIG_INET6_ESP=y
|
||||
CONFIG_INET6_IPCOMP=y
|
||||
CONFIG_IPV6_MIP6=y
|
||||
CONFIG_IPV6_VTI=y
|
||||
CONFIG_IPV6_MULTIPLE_TABLES=y
|
||||
CONFIG_NETLABEL=y
|
||||
CONFIG_NETFILTER=y
|
||||
CONFIG_NF_CONNTRACK=y
|
||||
CONFIG_NF_CONNTRACK_SECMARK=y
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y
|
||||
CONFIG_NF_CONNTRACK_AMANDA=y
|
||||
CONFIG_NF_CONNTRACK_FTP=y
|
||||
CONFIG_NF_CONNTRACK_H323=y
|
||||
CONFIG_NF_CONNTRACK_IRC=y
|
||||
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
|
||||
CONFIG_NF_CONNTRACK_PPTP=y
|
||||
CONFIG_NF_CONNTRACK_SANE=y
|
||||
CONFIG_NF_CONNTRACK_TFTP=y
|
||||
CONFIG_NF_CT_NETLINK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
|
||||
CONFIG_NETFILTER_XT_TARGET_MARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TRACE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
|
||||
CONFIG_NETFILTER_XT_MATCH_BPF=y
|
||||
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HELPER=y
|
||||
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LENGTH=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MAC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_POLICY=y
|
||||
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
|
||||
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STRING=y
|
||||
CONFIG_NETFILTER_XT_MATCH_TIME=y
|
||||
CONFIG_NETFILTER_XT_MATCH_U32=y
|
||||
CONFIG_NF_CONNTRACK_IPV4=y
|
||||
CONFIG_NF_SOCKET_IPV4=y
|
||||
CONFIG_IP_NF_IPTABLES=y
|
||||
CONFIG_IP_NF_MATCH_AH=y
|
||||
CONFIG_IP_NF_MATCH_ECN=y
|
||||
CONFIG_IP_NF_MATCH_TTL=y
|
||||
CONFIG_IP_NF_FILTER=y
|
||||
CONFIG_IP_NF_TARGET_REJECT=y
|
||||
CONFIG_IP_NF_NAT=y
|
||||
CONFIG_IP_NF_TARGET_MASQUERADE=y
|
||||
CONFIG_IP_NF_TARGET_NETMAP=y
|
||||
CONFIG_IP_NF_TARGET_REDIRECT=y
|
||||
CONFIG_IP_NF_MANGLE=y
|
||||
CONFIG_IP_NF_RAW=y
|
||||
CONFIG_IP_NF_SECURITY=y
|
||||
CONFIG_IP_NF_ARPTABLES=y
|
||||
CONFIG_IP_NF_ARPFILTER=y
|
||||
CONFIG_IP_NF_ARP_MANGLE=y
|
||||
CONFIG_NF_CONNTRACK_IPV6=y
|
||||
CONFIG_NF_SOCKET_IPV6=y
|
||||
CONFIG_IP6_NF_IPTABLES=y
|
||||
CONFIG_IP6_NF_MATCH_IPV6HEADER=y
|
||||
CONFIG_IP6_NF_MATCH_RPFILTER=y
|
||||
CONFIG_IP6_NF_FILTER=y
|
||||
CONFIG_IP6_NF_TARGET_REJECT=y
|
||||
CONFIG_IP6_NF_MANGLE=y
|
||||
CONFIG_IP6_NF_RAW=y
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_HTB=y
|
||||
CONFIG_NET_CLS_U32=y
|
||||
CONFIG_NET_EMATCH=y
|
||||
CONFIG_NET_EMATCH_U32=y
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
CONFIG_CFG80211=y
|
||||
CONFIG_MAC80211=y
|
||||
CONFIG_RFKILL=y
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEBUG_DEVRES=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_UNITTEST=y
|
||||
# CONFIG_PNP_DEBUG_MESSAGES is not set
|
||||
CONFIG_ZRAM=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=8192
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_UID_SYS_STATS=y
|
||||
CONFIG_MEMORY_STATE_TIME=y
|
||||
CONFIG_SCSI=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BLK_DEV_SR=y
|
||||
CONFIG_BLK_DEV_SR_VENDOR=y
|
||||
CONFIG_CHR_DEV_SG=y
|
||||
CONFIG_SCSI_CONSTANTS=y
|
||||
CONFIG_SCSI_SPI_ATTRS=y
|
||||
CONFIG_SCSI_VIRTIO=y
|
||||
CONFIG_MD=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_DM_CRYPT=y
|
||||
CONFIG_DM_MIRROR=y
|
||||
CONFIG_DM_ZERO=y
|
||||
CONFIG_DM_UEVENT=y
|
||||
CONFIG_DM_VERITY=y
|
||||
CONFIG_DM_VERITY_HASH_PREFETCH_MIN_SIZE=1
|
||||
CONFIG_DM_VERITY_FEC=y
|
||||
CONFIG_DM_ANDROID_VERITY=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_NETCONSOLE=y
|
||||
CONFIG_NETCONSOLE_DYNAMIC=y
|
||||
CONFIG_TUN=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
# CONFIG_ETHERNET is not set
|
||||
CONFIG_PPP=y
|
||||
CONFIG_PPP_BSDCOMP=y
|
||||
CONFIG_PPP_DEFLATE=y
|
||||
CONFIG_PPP_MPPE=y
|
||||
CONFIG_USB_USBNET=y
|
||||
# CONFIG_USB_NET_AX8817X is not set
|
||||
# CONFIG_USB_NET_AX88179_178A is not set
|
||||
# CONFIG_USB_NET_CDCETHER is not set
|
||||
# CONFIG_USB_NET_CDC_NCM is not set
|
||||
# CONFIG_USB_NET_NET1080 is not set
|
||||
# CONFIG_USB_NET_CDC_SUBSET is not set
|
||||
# CONFIG_USB_NET_ZAURUS is not set
|
||||
# CONFIG_WLAN_VENDOR_ADMTEK is not set
|
||||
# CONFIG_WLAN_VENDOR_ATH is not set
|
||||
# CONFIG_WLAN_VENDOR_ATMEL is not set
|
||||
# CONFIG_WLAN_VENDOR_BROADCOM is not set
|
||||
# CONFIG_WLAN_VENDOR_CISCO is not set
|
||||
# CONFIG_WLAN_VENDOR_INTEL is not set
|
||||
# CONFIG_WLAN_VENDOR_INTERSIL is not set
|
||||
# CONFIG_WLAN_VENDOR_MARVELL is not set
|
||||
# CONFIG_WLAN_VENDOR_MEDIATEK is not set
|
||||
# CONFIG_WLAN_VENDOR_RALINK is not set
|
||||
# CONFIG_WLAN_VENDOR_REALTEK is not set
|
||||
# CONFIG_WLAN_VENDOR_RSI is not set
|
||||
# CONFIG_WLAN_VENDOR_ST is not set
|
||||
# CONFIG_WLAN_VENDOR_TI is not set
|
||||
# CONFIG_WLAN_VENDOR_ZYDAS is not set
|
||||
# CONFIG_WLAN_VENDOR_QUANTENNA is not set
|
||||
CONFIG_MAC80211_HWSIM=y
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_INPUT_KEYRESET=y
|
||||
# CONFIG_INPUT_KEYBOARD is not set
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_INPUT_JOYSTICK=y
|
||||
CONFIG_JOYSTICK_XPAD=y
|
||||
CONFIG_JOYSTICK_XPAD_FF=y
|
||||
CONFIG_JOYSTICK_XPAD_LEDS=y
|
||||
CONFIG_INPUT_TABLET=y
|
||||
CONFIG_TABLET_USB_ACECAD=y
|
||||
CONFIG_TABLET_USB_AIPTEK=y
|
||||
CONFIG_TABLET_USB_GTCO=y
|
||||
CONFIG_TABLET_USB_HANWANG=y
|
||||
CONFIG_TABLET_USB_KBTAB=y
|
||||
CONFIG_INPUT_MISC=y
|
||||
CONFIG_INPUT_KEYCHORD=y
|
||||
CONFIG_INPUT_UINPUT=y
|
||||
CONFIG_INPUT_GPIO=y
|
||||
# CONFIG_SERIO_I8042 is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_DEVMEM is not set
|
||||
CONFIG_SERIAL_8250=y
|
||||
# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
# CONFIG_SERIAL_8250_EXAR is not set
|
||||
CONFIG_SERIAL_8250_NR_UARTS=48
|
||||
CONFIG_SERIAL_8250_EXTENDED=y
|
||||
CONFIG_SERIAL_8250_MANY_PORTS=y
|
||||
CONFIG_SERIAL_8250_SHARE_IRQ=y
|
||||
CONFIG_VIRTIO_CONSOLE=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
# CONFIG_HW_RANDOM_INTEL is not set
|
||||
# CONFIG_HW_RANDOM_AMD is not set
|
||||
# CONFIG_HW_RANDOM_VIA is not set
|
||||
CONFIG_HW_RANDOM_VIRTIO=y
|
||||
CONFIG_HPET=y
|
||||
# CONFIG_HPET_MMAP_DEFAULT is not set
|
||||
# CONFIG_DEVPORT is not set
|
||||
# CONFIG_ACPI_I2C_OPREGION is not set
|
||||
# CONFIG_I2C_COMPAT is not set
|
||||
# CONFIG_I2C_HELPER_AUTO is not set
|
||||
CONFIG_PTP_1588_CLOCK=y
|
||||
# CONFIG_HWMON is not set
|
||||
# CONFIG_X86_PKG_TEMP_THERMAL is not set
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_SOFT_WATCHDOG=y
|
||||
CONFIG_MEDIA_SUPPORT=y
|
||||
# CONFIG_VGA_ARB is not set
|
||||
CONFIG_DRM=y
|
||||
# CONFIG_DRM_FBDEV_EMULATION is not set
|
||||
CONFIG_DRM_VIRTIO_GPU=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
CONFIG_HIDRAW=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_ACRUX=y
|
||||
CONFIG_HID_ACRUX_FF=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_PRODIKEYS=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
CONFIG_HID_DRAGONRISE=y
|
||||
CONFIG_DRAGONRISE_FF=y
|
||||
CONFIG_HID_EMS_FF=y
|
||||
CONFIG_HID_ELECOM=y
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_HOLTEK=y
|
||||
CONFIG_HID_KEYTOUCH=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_UCLOGIC=y
|
||||
CONFIG_HID_WALTOP=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_TWINHAN=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_LCPOWER=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_HID_LOGITECH_DJ=y
|
||||
CONFIG_LOGITECH_FF=y
|
||||
CONFIG_LOGIRUMBLEPAD2_FF=y
|
||||
CONFIG_LOGIG940_FF=y
|
||||
CONFIG_HID_MAGICMOUSE=y
|
||||
CONFIG_HID_MICROSOFT=y
|
||||
CONFIG_HID_MONTEREY=y
|
||||
CONFIG_HID_MULTITOUCH=y
|
||||
CONFIG_HID_NTRIG=y
|
||||
CONFIG_HID_ORTEK=y
|
||||
CONFIG_HID_PANTHERLORD=y
|
||||
CONFIG_PANTHERLORD_FF=y
|
||||
CONFIG_HID_PETALYNX=y
|
||||
CONFIG_HID_PICOLCD=y
|
||||
CONFIG_HID_PRIMAX=y
|
||||
CONFIG_HID_ROCCAT=y
|
||||
CONFIG_HID_SAITEK=y
|
||||
CONFIG_HID_SAMSUNG=y
|
||||
CONFIG_HID_SONY=y
|
||||
CONFIG_HID_SPEEDLINK=y
|
||||
CONFIG_HID_SUNPLUS=y
|
||||
CONFIG_HID_GREENASIA=y
|
||||
CONFIG_GREENASIA_FF=y
|
||||
CONFIG_HID_SMARTJOYPLUS=y
|
||||
CONFIG_SMARTJOYPLUS_FF=y
|
||||
CONFIG_HID_TIVO=y
|
||||
CONFIG_HID_TOPSEED=y
|
||||
CONFIG_HID_THRUSTMASTER=y
|
||||
CONFIG_HID_WACOM=y
|
||||
CONFIG_HID_WIIMOTE=y
|
||||
CONFIG_HID_ZEROPLUS=y
|
||||
CONFIG_HID_ZYDACRON=y
|
||||
CONFIG_USB_HIDDEV=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
CONFIG_USB_GADGET=y
|
||||
CONFIG_USB_DUMMY_HCD=y
|
||||
CONFIG_USB_CONFIGFS=y
|
||||
CONFIG_USB_CONFIGFS_F_FS=y
|
||||
CONFIG_USB_CONFIGFS_F_ACC=y
|
||||
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
|
||||
CONFIG_USB_CONFIGFS_UEVENT=y
|
||||
CONFIG_USB_CONFIGFS_F_MIDI=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
# CONFIG_RTC_HCTOSYS is not set
|
||||
CONFIG_SW_SYNC=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO_BALLOON=y
|
||||
CONFIG_VIRTIO_MMIO=y
|
||||
CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_ASHMEM=y
|
||||
CONFIG_ANDROID_VSOC=y
|
||||
CONFIG_ION=y
|
||||
# CONFIG_X86_PLATFORM_DEVICES is not set
|
||||
# CONFIG_IOMMU_SUPPORT is not set
|
||||
CONFIG_ANDROID=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
# CONFIG_FIRMWARE_MEMMAP is not set
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_POSIX_ACL=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
CONFIG_EXT4_ENCRYPTION=y
|
||||
CONFIG_F2FS_FS=y
|
||||
CONFIG_F2FS_FS_SECURITY=y
|
||||
CONFIG_F2FS_FS_ENCRYPTION=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_QUOTA_NETLINK_INTERFACE=y
|
||||
# CONFIG_PRINT_QUOTA_WARNING is not set
|
||||
CONFIG_QFMT_V2=y
|
||||
CONFIG_AUTOFS4_FS=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_PROC_KCORE=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_HUGETLBFS=y
|
||||
CONFIG_SDCARD_FS=y
|
||||
CONFIG_PSTORE=y
|
||||
CONFIG_PSTORE_CONSOLE=y
|
||||
CONFIG_PSTORE_RAM=y
|
||||
CONFIG_NLS_DEFAULT="utf8"
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_NLS_UTF8=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
CONFIG_FRAME_WARN=1024
|
||||
# CONFIG_UNUSED_SYMBOLS is not set
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DEBUG_STACK_USAGE=y
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_DEBUG_STACKOVERFLOW=y
|
||||
CONFIG_HARDLOCKUP_DETECTOR=y
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_RCU_CPU_STALL_TIMEOUT=60
|
||||
CONFIG_ENABLE_DEFAULT_TRACERS=y
|
||||
CONFIG_IO_DELAY_NONE=y
|
||||
CONFIG_DEBUG_BOOT_PARAMS=y
|
||||
CONFIG_OPTIMIZE_INLINING=y
|
||||
CONFIG_UNWINDER_FRAME_POINTER=y
|
||||
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_NETWORK=y
|
||||
CONFIG_SECURITY_PATH=y
|
||||
CONFIG_HARDENED_USERCOPY=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
|
||||
CONFIG_CRYPTO_RSA=y
|
||||
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_LZ4=y
|
||||
CONFIG_CRYPTO_ZSTD=y
|
||||
CONFIG_CRYPTO_DEV_VIRTIO=y
|
||||
CONFIG_ASYMMETRIC_KEY_TYPE=y
|
||||
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
|
||||
CONFIG_X509_CERTIFICATE_PARSER=y
|
||||
CONFIG_SYSTEM_TRUSTED_KEYRING=y
|
||||
CONFIG_SYSTEM_TRUSTED_KEYS="verity_dev_keys.x509"
|
416
arch/x86/configs/x86_64_ranchu_defconfig
Normal file
416
arch/x86/configs/x86_64_ranchu_defconfig
Normal file
@ -0,0 +1,416 @@
|
||||
# CONFIG_LOCALVERSION_AUTO is not set
|
||||
CONFIG_POSIX_MQUEUE=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_HIGH_RES_TIMERS=y
|
||||
CONFIG_BSD_PROCESS_ACCT=y
|
||||
CONFIG_TASKSTATS=y
|
||||
CONFIG_TASK_DELAY_ACCT=y
|
||||
CONFIG_TASK_XACCT=y
|
||||
CONFIG_TASK_IO_ACCOUNTING=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_DEBUG=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||
CONFIG_SYSCTL_SYSCALL=y
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_EMBEDDED=y
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
CONFIG_ARCH_MMAP_RND_BITS=32
|
||||
CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16
|
||||
CONFIG_PARTITION_ADVANCED=y
|
||||
CONFIG_OSF_PARTITION=y
|
||||
CONFIG_AMIGA_PARTITION=y
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_BSD_DISKLABEL=y
|
||||
CONFIG_MINIX_SUBPARTITION=y
|
||||
CONFIG_SOLARIS_X86_PARTITION=y
|
||||
CONFIG_UNIXWARE_DISKLABEL=y
|
||||
CONFIG_SGI_PARTITION=y
|
||||
CONFIG_SUN_PARTITION=y
|
||||
CONFIG_KARMA_PARTITION=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_MCORE2=y
|
||||
CONFIG_MAXSMP=y
|
||||
CONFIG_PREEMPT=y
|
||||
# CONFIG_X86_MCE is not set
|
||||
CONFIG_X86_MSR=y
|
||||
CONFIG_X86_CPUID=y
|
||||
CONFIG_KSM=y
|
||||
CONFIG_CMA=y
|
||||
# CONFIG_MTRR_SANITIZER is not set
|
||||
CONFIG_EFI=y
|
||||
CONFIG_EFI_STUB=y
|
||||
CONFIG_HZ_100=y
|
||||
CONFIG_PHYSICAL_START=0x100000
|
||||
CONFIG_PM_AUTOSLEEP=y
|
||||
CONFIG_PM_WAKELOCKS=y
|
||||
CONFIG_PM_WAKELOCKS_LIMIT=0
|
||||
# CONFIG_PM_WAKELOCKS_GC is not set
|
||||
CONFIG_PM_DEBUG=y
|
||||
CONFIG_CPU_FREQ=y
|
||||
# CONFIG_CPU_FREQ_STAT is not set
|
||||
CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
||||
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
||||
CONFIG_PCI_MMCONFIG=y
|
||||
CONFIG_PCIEPORTBUS=y
|
||||
# CONFIG_PCIEASPM is not set
|
||||
CONFIG_PCCARD=y
|
||||
CONFIG_YENTA=y
|
||||
CONFIG_HOTPLUG_PCI=y
|
||||
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
||||
CONFIG_BINFMT_MISC=y
|
||||
CONFIG_IA32_EMULATION=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
CONFIG_UNIX=y
|
||||
CONFIG_XFRM_USER=y
|
||||
CONFIG_NET_KEY=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_IP_MULTICAST=y
|
||||
CONFIG_IP_ADVANCED_ROUTER=y
|
||||
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_IP_MROUTE=y
|
||||
CONFIG_IP_PIMSM_V1=y
|
||||
CONFIG_IP_PIMSM_V2=y
|
||||
CONFIG_SYN_COOKIES=y
|
||||
CONFIG_INET_ESP=y
|
||||
# CONFIG_INET_XFRM_MODE_BEET is not set
|
||||
# CONFIG_INET_LRO is not set
|
||||
CONFIG_INET_DIAG_DESTROY=y
|
||||
CONFIG_IPV6_ROUTER_PREF=y
|
||||
CONFIG_IPV6_ROUTE_INFO=y
|
||||
CONFIG_IPV6_OPTIMISTIC_DAD=y
|
||||
CONFIG_INET6_AH=y
|
||||
CONFIG_INET6_ESP=y
|
||||
CONFIG_INET6_IPCOMP=y
|
||||
CONFIG_IPV6_MIP6=y
|
||||
CONFIG_IPV6_MULTIPLE_TABLES=y
|
||||
CONFIG_NETLABEL=y
|
||||
CONFIG_NETFILTER=y
|
||||
CONFIG_NF_CONNTRACK=y
|
||||
CONFIG_NF_CONNTRACK_SECMARK=y
|
||||
CONFIG_NF_CONNTRACK_EVENTS=y
|
||||
CONFIG_NF_CT_PROTO_DCCP=y
|
||||
CONFIG_NF_CT_PROTO_SCTP=y
|
||||
CONFIG_NF_CT_PROTO_UDPLITE=y
|
||||
CONFIG_NF_CONNTRACK_AMANDA=y
|
||||
CONFIG_NF_CONNTRACK_FTP=y
|
||||
CONFIG_NF_CONNTRACK_H323=y
|
||||
CONFIG_NF_CONNTRACK_IRC=y
|
||||
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
|
||||
CONFIG_NF_CONNTRACK_PPTP=y
|
||||
CONFIG_NF_CONNTRACK_SANE=y
|
||||
CONFIG_NF_CONNTRACK_TFTP=y
|
||||
CONFIG_NF_CT_NETLINK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
|
||||
CONFIG_NETFILTER_XT_TARGET_MARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TRACE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
|
||||
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_HELPER=y
|
||||
CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LENGTH=y
|
||||
CONFIG_NETFILTER_XT_MATCH_LIMIT=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MAC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_MARK=y
|
||||
CONFIG_NETFILTER_XT_MATCH_POLICY=y
|
||||
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
|
||||
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
|
||||
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATE=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
|
||||
CONFIG_NETFILTER_XT_MATCH_STRING=y
|
||||
CONFIG_NETFILTER_XT_MATCH_TIME=y
|
||||
CONFIG_NETFILTER_XT_MATCH_U32=y
|
||||
CONFIG_NF_CONNTRACK_IPV4=y
|
||||
CONFIG_IP_NF_IPTABLES=y
|
||||
CONFIG_IP_NF_MATCH_AH=y
|
||||
CONFIG_IP_NF_MATCH_ECN=y
|
||||
CONFIG_IP_NF_MATCH_TTL=y
|
||||
CONFIG_IP_NF_FILTER=y
|
||||
CONFIG_IP_NF_TARGET_REJECT=y
|
||||
CONFIG_IP_NF_MANGLE=y
|
||||
CONFIG_IP_NF_RAW=y
|
||||
CONFIG_IP_NF_SECURITY=y
|
||||
CONFIG_IP_NF_ARPTABLES=y
|
||||
CONFIG_IP_NF_ARPFILTER=y
|
||||
CONFIG_IP_NF_ARP_MANGLE=y
|
||||
CONFIG_NF_CONNTRACK_IPV6=y
|
||||
CONFIG_IP6_NF_IPTABLES=y
|
||||
CONFIG_IP6_NF_FILTER=y
|
||||
CONFIG_IP6_NF_TARGET_REJECT=y
|
||||
CONFIG_IP6_NF_MANGLE=y
|
||||
CONFIG_IP6_NF_RAW=y
|
||||
CONFIG_NET_SCHED=y
|
||||
CONFIG_NET_SCH_HTB=y
|
||||
CONFIG_NET_CLS_U32=y
|
||||
CONFIG_NET_EMATCH=y
|
||||
CONFIG_NET_EMATCH_U32=y
|
||||
CONFIG_NET_CLS_ACT=y
|
||||
CONFIG_CFG80211=y
|
||||
CONFIG_MAC80211=y
|
||||
CONFIG_MAC80211_LEDS=y
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_DMA_CMA=y
|
||||
CONFIG_CONNECTOR=y
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_RAM=y
|
||||
CONFIG_BLK_DEV_RAM_SIZE=8192
|
||||
CONFIG_VIRTIO_BLK=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BLK_DEV_SR=y
|
||||
CONFIG_BLK_DEV_SR_VENDOR=y
|
||||
CONFIG_CHR_DEV_SG=y
|
||||
CONFIG_SCSI_CONSTANTS=y
|
||||
CONFIG_SCSI_SPI_ATTRS=y
|
||||
CONFIG_SCSI_ISCSI_ATTRS=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
CONFIG_ATA=y
|
||||
CONFIG_SATA_AHCI=y
|
||||
CONFIG_ATA_PIIX=y
|
||||
CONFIG_PATA_AMD=y
|
||||
CONFIG_PATA_OLDPIIX=y
|
||||
CONFIG_PATA_SCH=y
|
||||
CONFIG_PATA_MPIIX=y
|
||||
CONFIG_ATA_GENERIC=y
|
||||
CONFIG_MD=y
|
||||
CONFIG_BLK_DEV_MD=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_DM_DEBUG=y
|
||||
CONFIG_DM_CRYPT=y
|
||||
CONFIG_DM_MIRROR=y
|
||||
CONFIG_DM_ZERO=y
|
||||
CONFIG_DM_UEVENT=y
|
||||
CONFIG_DM_VERITY=y
|
||||
CONFIG_DM_VERITY_FEC=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_NETCONSOLE=y
|
||||
CONFIG_TUN=y
|
||||
CONFIG_VIRTIO_NET=y
|
||||
CONFIG_BNX2=y
|
||||
CONFIG_TIGON3=y
|
||||
CONFIG_NET_TULIP=y
|
||||
CONFIG_E100=y
|
||||
CONFIG_E1000=y
|
||||
CONFIG_E1000E=y
|
||||
CONFIG_SKY2=y
|
||||
CONFIG_NE2K_PCI=y
|
||||
CONFIG_FORCEDETH=y
|
||||
CONFIG_8139TOO=y
|
||||
# CONFIG_8139TOO_PIO is not set
|
||||
CONFIG_R8169=y
|
||||
CONFIG_FDDI=y
|
||||
CONFIG_PPP=y
|
||||
CONFIG_PPP_BSDCOMP=y
|
||||
CONFIG_PPP_DEFLATE=y
|
||||
CONFIG_PPP_MPPE=y
|
||||
CONFIG_USB_USBNET=y
|
||||
CONFIG_INPUT_POLLDEV=y
|
||||
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_INPUT_KEYRESET=y
|
||||
# CONFIG_KEYBOARD_ATKBD is not set
|
||||
CONFIG_KEYBOARD_GOLDFISH_EVENTS=y
|
||||
# CONFIG_INPUT_MOUSE is not set
|
||||
CONFIG_INPUT_JOYSTICK=y
|
||||
CONFIG_JOYSTICK_XPAD=y
|
||||
CONFIG_JOYSTICK_XPAD_FF=y
|
||||
CONFIG_JOYSTICK_XPAD_LEDS=y
|
||||
CONFIG_INPUT_TABLET=y
|
||||
CONFIG_TABLET_USB_ACECAD=y
|
||||
CONFIG_TABLET_USB_AIPTEK=y
|
||||
CONFIG_TABLET_USB_GTCO=y
|
||||
CONFIG_TABLET_USB_HANWANG=y
|
||||
CONFIG_TABLET_USB_KBTAB=y
|
||||
CONFIG_INPUT_TOUCHSCREEN=y
|
||||
CONFIG_INPUT_MISC=y
|
||||
CONFIG_INPUT_UINPUT=y
|
||||
CONFIG_INPUT_GPIO=y
|
||||
# CONFIG_SERIO is not set
|
||||
# CONFIG_VT is not set
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
CONFIG_SERIAL_NONSTANDARD=y
|
||||
# CONFIG_DEVMEM is not set
|
||||
# CONFIG_DEVKMEM is not set
|
||||
CONFIG_SERIAL_8250=y
|
||||
CONFIG_SERIAL_8250_CONSOLE=y
|
||||
CONFIG_VIRTIO_CONSOLE=y
|
||||
CONFIG_NVRAM=y
|
||||
CONFIG_I2C_I801=y
|
||||
CONFIG_BATTERY_GOLDFISH=y
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_MEDIA_SUPPORT=y
|
||||
CONFIG_AGP=y
|
||||
CONFIG_AGP_AMD64=y
|
||||
CONFIG_AGP_INTEL=y
|
||||
CONFIG_DRM=y
|
||||
CONFIG_FB_MODE_HELPERS=y
|
||||
CONFIG_FB_TILEBLITTING=y
|
||||
CONFIG_FB_EFI=y
|
||||
CONFIG_FB_GOLDFISH=y
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
# CONFIG_LCD_CLASS_DEVICE is not set
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_SND=y
|
||||
CONFIG_HIDRAW=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HID_A4TECH=y
|
||||
CONFIG_HID_ACRUX=y
|
||||
CONFIG_HID_ACRUX_FF=y
|
||||
CONFIG_HID_APPLE=y
|
||||
CONFIG_HID_BELKIN=y
|
||||
CONFIG_HID_CHERRY=y
|
||||
CONFIG_HID_CHICONY=y
|
||||
CONFIG_HID_PRODIKEYS=y
|
||||
CONFIG_HID_CYPRESS=y
|
||||
CONFIG_HID_DRAGONRISE=y
|
||||
CONFIG_DRAGONRISE_FF=y
|
||||
CONFIG_HID_EMS_FF=y
|
||||
CONFIG_HID_ELECOM=y
|
||||
CONFIG_HID_EZKEY=y
|
||||
CONFIG_HID_HOLTEK=y
|
||||
CONFIG_HID_KEYTOUCH=y
|
||||
CONFIG_HID_KYE=y
|
||||
CONFIG_HID_UCLOGIC=y
|
||||
CONFIG_HID_WALTOP=y
|
||||
CONFIG_HID_GYRATION=y
|
||||
CONFIG_HID_TWINHAN=y
|
||||
CONFIG_HID_KENSINGTON=y
|
||||
CONFIG_HID_LCPOWER=y
|
||||
CONFIG_HID_LOGITECH=y
|
||||
CONFIG_HID_LOGITECH_DJ=y
|
||||
CONFIG_LOGITECH_FF=y
|
||||
CONFIG_LOGIRUMBLEPAD2_FF=y
|
||||
CONFIG_LOGIG940_FF=y
|
||||
CONFIG_HID_MAGICMOUSE=y
|
||||
CONFIG_HID_MICROSOFT=y
|
||||
CONFIG_HID_MONTEREY=y
|
||||
CONFIG_HID_MULTITOUCH=y
|
||||
CONFIG_HID_NTRIG=y
|
||||
CONFIG_HID_ORTEK=y
|
||||
CONFIG_HID_PANTHERLORD=y
|
||||
CONFIG_PANTHERLORD_FF=y
|
||||
CONFIG_HID_PETALYNX=y
|
||||
CONFIG_HID_PICOLCD=y
|
||||
CONFIG_HID_PRIMAX=y
|
||||
CONFIG_HID_ROCCAT=y
|
||||
CONFIG_HID_SAITEK=y
|
||||
CONFIG_HID_SAMSUNG=y
|
||||
CONFIG_HID_SONY=y
|
||||
CONFIG_HID_SPEEDLINK=y
|
||||
CONFIG_HID_SUNPLUS=y
|
||||
CONFIG_HID_GREENASIA=y
|
||||
CONFIG_GREENASIA_FF=y
|
||||
CONFIG_HID_SMARTJOYPLUS=y
|
||||
CONFIG_SMARTJOYPLUS_FF=y
|
||||
CONFIG_HID_TIVO=y
|
||||
CONFIG_HID_TOPSEED=y
|
||||
CONFIG_HID_THRUSTMASTER=y
|
||||
CONFIG_HID_WACOM=y
|
||||
CONFIG_HID_WIIMOTE=y
|
||||
CONFIG_HID_ZEROPLUS=y
|
||||
CONFIG_HID_ZYDACRON=y
|
||||
CONFIG_HID_PID=y
|
||||
CONFIG_USB_HIDDEV=y
|
||||
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
|
||||
CONFIG_USB_MON=y
|
||||
CONFIG_USB_EHCI_HCD=y
|
||||
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
|
||||
CONFIG_USB_OHCI_HCD=y
|
||||
CONFIG_USB_UHCI_HCD=y
|
||||
CONFIG_USB_PRINTER=y
|
||||
CONFIG_USB_STORAGE=y
|
||||
CONFIG_USB_OTG_WAKELOCK=y
|
||||
CONFIG_EDAC=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
# CONFIG_RTC_HCTOSYS is not set
|
||||
CONFIG_DMADEVICES=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_ASHMEM=y
|
||||
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
|
||||
CONFIG_SYNC=y
|
||||
CONFIG_SW_SYNC=y
|
||||
CONFIG_SYNC_FILE=y
|
||||
CONFIG_ION=y
|
||||
CONFIG_GOLDFISH_AUDIO=y
|
||||
CONFIG_SND_HDA_INTEL=y
|
||||
CONFIG_GOLDFISH=y
|
||||
CONFIG_GOLDFISH_PIPE=y
|
||||
CONFIG_GOLDFISH_SYNC=y
|
||||
CONFIG_ANDROID=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
CONFIG_ISCSI_IBFT_FIND=y
|
||||
CONFIG_EXT4_FS=y
|
||||
CONFIG_EXT4_FS_SECURITY=y
|
||||
CONFIG_QUOTA=y
|
||||
CONFIG_QUOTA_NETLINK_INTERFACE=y
|
||||
# CONFIG_PRINT_QUOTA_WARNING is not set
|
||||
CONFIG_FUSE_FS=y
|
||||
CONFIG_ISO9660_FS=y
|
||||
CONFIG_JOLIET=y
|
||||
CONFIG_ZISOFS=y
|
||||
CONFIG_MSDOS_FS=y
|
||||
CONFIG_VFAT_FS=y
|
||||
CONFIG_PROC_KCORE=y
|
||||
CONFIG_TMPFS=y
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_HUGETLBFS=y
|
||||
CONFIG_PSTORE=y
|
||||
CONFIG_PSTORE_CONSOLE=y
|
||||
CONFIG_PSTORE_RAM=y
|
||||
# CONFIG_NETWORK_FILESYSTEMS is not set
|
||||
CONFIG_NLS_DEFAULT="utf8"
|
||||
CONFIG_NLS_CODEPAGE_437=y
|
||||
CONFIG_NLS_ASCII=y
|
||||
CONFIG_NLS_ISO8859_1=y
|
||||
CONFIG_NLS_UTF8=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
# CONFIG_ENABLE_WARN_DEPRECATED is not set
|
||||
# CONFIG_ENABLE_MUST_CHECK is not set
|
||||
# CONFIG_UNUSED_SYMBOLS is not set
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_DEBUG_MEMORY_INIT=y
|
||||
CONFIG_PANIC_TIMEOUT=5
|
||||
CONFIG_SCHEDSTATS=y
|
||||
CONFIG_TIMER_STATS=y
|
||||
CONFIG_SCHED_TRACER=y
|
||||
CONFIG_BLK_DEV_IO_TRACE=y
|
||||
CONFIG_PROVIDE_OHCI1394_DMA_INIT=y
|
||||
CONFIG_KEYS=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_NETWORK=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_CRYPTO_TWOFISH=y
|
||||
CONFIG_ASYMMETRIC_KEY_TYPE=y
|
||||
CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y
|
||||
CONFIG_X509_CERTIFICATE_PARSER=y
|
||||
CONFIG_PKCS7_MESSAGE_PARSER=y
|
||||
CONFIG_PKCS7_TEST_KEY=y
|
||||
# CONFIG_VIRTUALIZATION is not set
|
||||
CONFIG_CRC_T10DIF=y
|
16
build.config.cuttlefish.x86_64
Normal file
16
build.config.cuttlefish.x86_64
Normal file
@ -0,0 +1,16 @@
|
||||
ARCH=x86_64
|
||||
BRANCH=android-4.14
|
||||
CLANG_TRIPLE=x86_64-linux-gnu-
|
||||
CROSS_COMPILE=x86_64-linux-androidkernel-
|
||||
DEFCONFIG=x86_64_cuttlefish_defconfig
|
||||
EXTRA_CMDS=''
|
||||
KERNEL_DIR=common
|
||||
POST_DEFCONFIG_CMDS="check_defconfig"
|
||||
CLANG_PREBUILT_BIN=prebuilts-master/clang/host/linux-x86/clang-r328903/bin
|
||||
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin
|
||||
FILES="
|
||||
arch/x86/boot/bzImage
|
||||
vmlinux
|
||||
System.map
|
||||
"
|
||||
STOP_SHIP_TRACEPRINTK=1
|
13
build.config.goldfish.arm
Normal file
13
build.config.goldfish.arm
Normal file
@ -0,0 +1,13 @@
|
||||
ARCH=arm
|
||||
BRANCH=android-4.4
|
||||
CROSS_COMPILE=arm-linux-androidkernel-
|
||||
DEFCONFIG=ranchu_defconfig
|
||||
EXTRA_CMDS=''
|
||||
KERNEL_DIR=common
|
||||
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin
|
||||
FILES="
|
||||
arch/arm/boot/zImage
|
||||
vmlinux
|
||||
System.map
|
||||
"
|
||||
STOP_SHIP_TRACEPRINTK=1
|
13
build.config.goldfish.arm64
Normal file
13
build.config.goldfish.arm64
Normal file
@ -0,0 +1,13 @@
|
||||
ARCH=arm64
|
||||
BRANCH=android-4.4
|
||||
CROSS_COMPILE=aarch64-linux-android-
|
||||
DEFCONFIG=ranchu64_defconfig
|
||||
EXTRA_CMDS=''
|
||||
KERNEL_DIR=common
|
||||
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/bin
|
||||
FILES="
|
||||
arch/arm64/boot/Image
|
||||
vmlinux
|
||||
System.map
|
||||
"
|
||||
STOP_SHIP_TRACEPRINTK=1
|
12
build.config.goldfish.mips
Normal file
12
build.config.goldfish.mips
Normal file
@ -0,0 +1,12 @@
|
||||
ARCH=mips
|
||||
BRANCH=android-4.4
|
||||
CROSS_COMPILE=mips64el-linux-android-
|
||||
DEFCONFIG=ranchu_defconfig
|
||||
EXTRA_CMDS=''
|
||||
KERNEL_DIR=common
|
||||
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9/bin
|
||||
FILES="
|
||||
vmlinux
|
||||
System.map
|
||||
"
|
||||
STOP_SHIP_TRACEPRINTK=1
|
12
build.config.goldfish.mips64
Normal file
12
build.config.goldfish.mips64
Normal file
@ -0,0 +1,12 @@
|
||||
ARCH=mips
|
||||
BRANCH=android-4.4
|
||||
CROSS_COMPILE=mips64el-linux-android-
|
||||
DEFCONFIG=ranchu64_defconfig
|
||||
EXTRA_CMDS=''
|
||||
KERNEL_DIR=common
|
||||
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/mips/mips64el-linux-android-4.9/bin
|
||||
FILES="
|
||||
vmlinux
|
||||
System.map
|
||||
"
|
||||
STOP_SHIP_TRACEPRINTK=1
|
13
build.config.goldfish.x86
Normal file
13
build.config.goldfish.x86
Normal file
@ -0,0 +1,13 @@
|
||||
ARCH=x86
|
||||
BRANCH=android-4.4
|
||||
CROSS_COMPILE=x86_64-linux-android-
|
||||
DEFCONFIG=i386_ranchu_defconfig
|
||||
EXTRA_CMDS=''
|
||||
KERNEL_DIR=common
|
||||
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin
|
||||
FILES="
|
||||
arch/x86/boot/bzImage
|
||||
vmlinux
|
||||
System.map
|
||||
"
|
||||
STOP_SHIP_TRACEPRINTK=1
|
13
build.config.goldfish.x86_64
Normal file
13
build.config.goldfish.x86_64
Normal file
@ -0,0 +1,13 @@
|
||||
ARCH=x86_64
|
||||
BRANCH=android-4.4
|
||||
CROSS_COMPILE=x86_64-linux-android-
|
||||
DEFCONFIG=x86_64_ranchu_defconfig
|
||||
EXTRA_CMDS=''
|
||||
KERNEL_DIR=common
|
||||
LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin
|
||||
FILES="
|
||||
arch/x86/boot/bzImage
|
||||
vmlinux
|
||||
System.map
|
||||
"
|
||||
STOP_SHIP_TRACEPRINTK=1
|
@ -264,5 +264,46 @@ error:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
|
||||
|
||||
#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
|
||||
|
||||
/**
|
||||
* verify_signature_one - Verify a signature with keys from given keyring
|
||||
* @sig: The signature to be verified
|
||||
* @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
|
||||
* (void *)1UL for all trusted keys).
|
||||
* @keyid: key description (not partial)
|
||||
*/
|
||||
int verify_signature_one(const struct public_key_signature *sig,
|
||||
struct key *trusted_keys, const char *keyid)
|
||||
{
|
||||
key_ref_t ref;
|
||||
struct key *key;
|
||||
int ret;
|
||||
|
||||
if (!sig)
|
||||
return -EBADMSG;
|
||||
if (!trusted_keys) {
|
||||
trusted_keys = builtin_trusted_keys;
|
||||
} else if (trusted_keys == (void *)1UL) {
|
||||
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
|
||||
trusted_keys = secondary_trusted_keys;
|
||||
#else
|
||||
trusted_keys = builtin_trusted_keys;
|
||||
#endif
|
||||
}
|
||||
|
||||
ref = keyring_search(make_key_ref(trusted_keys, 1),
|
||||
&key_type_asymmetric, keyid);
|
||||
if (IS_ERR(ref)) {
|
||||
pr_err("Asymmetric key (%s) not found in keyring(%s)\n",
|
||||
keyid, trusted_keys->description);
|
||||
return -ENOKEY;
|
||||
}
|
||||
|
||||
key = key_ref_to_ptr(ref);
|
||||
ret = verify_signature(key, sig);
|
||||
key_put(key);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(verify_signature_one);
|
||||
|
||||
|
@ -73,6 +73,7 @@
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#include <uapi/linux/android/binder.h>
|
||||
#include <uapi/linux/sched/types.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
@ -350,10 +351,14 @@ struct binder_error {
|
||||
* and by @lock)
|
||||
* @has_async_transaction: async transaction to node in progress
|
||||
* (protected by @lock)
|
||||
* @sched_policy: minimum scheduling policy for node
|
||||
* (invariant after initialized)
|
||||
* @accept_fds: file descriptor operations supported for node
|
||||
* (invariant after initialized)
|
||||
* @min_priority: minimum scheduling priority
|
||||
* (invariant after initialized)
|
||||
* @inherit_rt: inherit RT scheduling policy from caller
|
||||
* (invariant after initialized)
|
||||
* @async_todo: list of async work items
|
||||
* (protected by @proc->inner_lock)
|
||||
*
|
||||
@ -389,6 +394,8 @@ struct binder_node {
|
||||
/*
|
||||
* invariant after initialization
|
||||
*/
|
||||
u8 sched_policy:2;
|
||||
u8 inherit_rt:1;
|
||||
u8 accept_fds:1;
|
||||
u8 min_priority;
|
||||
};
|
||||
@ -462,6 +469,22 @@ enum binder_deferred_state {
|
||||
BINDER_DEFERRED_RELEASE = 0x04,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct binder_priority - scheduler policy and priority
|
||||
* @sched_policy scheduler policy
|
||||
* @prio [100..139] for SCHED_NORMAL, [0..99] for FIFO/RT
|
||||
*
|
||||
* The binder driver supports inheriting the following scheduler policies:
|
||||
* SCHED_NORMAL
|
||||
* SCHED_BATCH
|
||||
* SCHED_FIFO
|
||||
* SCHED_RR
|
||||
*/
|
||||
struct binder_priority {
|
||||
unsigned int sched_policy;
|
||||
int prio;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct binder_proc - binder process bookkeeping
|
||||
* @proc_node: element for binder_procs list
|
||||
@ -540,7 +563,7 @@ struct binder_proc {
|
||||
int requested_threads;
|
||||
int requested_threads_started;
|
||||
int tmp_ref;
|
||||
long default_priority;
|
||||
struct binder_priority default_priority;
|
||||
struct dentry *debugfs_entry;
|
||||
struct binder_alloc alloc;
|
||||
struct binder_context *context;
|
||||
@ -590,6 +613,7 @@ enum {
|
||||
* @is_dead: thread is dead and awaiting free
|
||||
* when outstanding transactions are cleaned up
|
||||
* (protected by @proc->inner_lock)
|
||||
* @task: struct task_struct for this thread
|
||||
*
|
||||
* Bookkeeping structure for binder threads.
|
||||
*/
|
||||
@ -609,6 +633,7 @@ struct binder_thread {
|
||||
struct binder_stats stats;
|
||||
atomic_t tmp_ref;
|
||||
bool is_dead;
|
||||
struct task_struct *task;
|
||||
};
|
||||
|
||||
struct binder_transaction {
|
||||
@ -625,8 +650,9 @@ struct binder_transaction {
|
||||
struct binder_buffer *buffer;
|
||||
unsigned int code;
|
||||
unsigned int flags;
|
||||
long priority;
|
||||
long saved_priority;
|
||||
struct binder_priority priority;
|
||||
struct binder_priority saved_priority;
|
||||
bool set_priority_called;
|
||||
kuid_t sender_euid;
|
||||
/**
|
||||
* @lock: protects @from, @to_proc, and @to_thread
|
||||
@ -1107,22 +1133,145 @@ static void binder_wakeup_proc_ilocked(struct binder_proc *proc)
|
||||
binder_wakeup_thread_ilocked(proc, thread, /* sync = */false);
|
||||
}
|
||||
|
||||
static void binder_set_nice(long nice)
|
||||
static bool is_rt_policy(int policy)
|
||||
{
|
||||
long min_nice;
|
||||
return policy == SCHED_FIFO || policy == SCHED_RR;
|
||||
}
|
||||
|
||||
if (can_nice(current, nice)) {
|
||||
set_user_nice(current, nice);
|
||||
static bool is_fair_policy(int policy)
|
||||
{
|
||||
return policy == SCHED_NORMAL || policy == SCHED_BATCH;
|
||||
}
|
||||
|
||||
static bool binder_supported_policy(int policy)
|
||||
{
|
||||
return is_fair_policy(policy) || is_rt_policy(policy);
|
||||
}
|
||||
|
||||
static int to_userspace_prio(int policy, int kernel_priority)
|
||||
{
|
||||
if (is_fair_policy(policy))
|
||||
return PRIO_TO_NICE(kernel_priority);
|
||||
else
|
||||
return MAX_USER_RT_PRIO - 1 - kernel_priority;
|
||||
}
|
||||
|
||||
static int to_kernel_prio(int policy, int user_priority)
|
||||
{
|
||||
if (is_fair_policy(policy))
|
||||
return NICE_TO_PRIO(user_priority);
|
||||
else
|
||||
return MAX_USER_RT_PRIO - 1 - user_priority;
|
||||
}
|
||||
|
||||
static void binder_do_set_priority(struct task_struct *task,
|
||||
struct binder_priority desired,
|
||||
bool verify)
|
||||
{
|
||||
int priority; /* user-space prio value */
|
||||
bool has_cap_nice;
|
||||
unsigned int policy = desired.sched_policy;
|
||||
|
||||
if (task->policy == policy && task->normal_prio == desired.prio)
|
||||
return;
|
||||
|
||||
has_cap_nice = has_capability_noaudit(task, CAP_SYS_NICE);
|
||||
|
||||
priority = to_userspace_prio(policy, desired.prio);
|
||||
|
||||
if (verify && is_rt_policy(policy) && !has_cap_nice) {
|
||||
long max_rtprio = task_rlimit(task, RLIMIT_RTPRIO);
|
||||
|
||||
if (max_rtprio == 0) {
|
||||
policy = SCHED_NORMAL;
|
||||
priority = MIN_NICE;
|
||||
} else if (priority > max_rtprio) {
|
||||
priority = max_rtprio;
|
||||
}
|
||||
}
|
||||
min_nice = rlimit_to_nice(rlimit(RLIMIT_NICE));
|
||||
binder_debug(BINDER_DEBUG_PRIORITY_CAP,
|
||||
"%d: nice value %ld not allowed use %ld instead\n",
|
||||
current->pid, nice, min_nice);
|
||||
set_user_nice(current, min_nice);
|
||||
if (min_nice <= MAX_NICE)
|
||||
|
||||
if (verify && is_fair_policy(policy) && !has_cap_nice) {
|
||||
long min_nice = rlimit_to_nice(task_rlimit(task, RLIMIT_NICE));
|
||||
|
||||
if (min_nice > MAX_NICE) {
|
||||
binder_user_error("%d RLIMIT_NICE not set\n",
|
||||
task->pid);
|
||||
return;
|
||||
} else if (priority < min_nice) {
|
||||
priority = min_nice;
|
||||
}
|
||||
}
|
||||
|
||||
if (policy != desired.sched_policy ||
|
||||
to_kernel_prio(policy, priority) != desired.prio)
|
||||
binder_debug(BINDER_DEBUG_PRIORITY_CAP,
|
||||
"%d: priority %d not allowed, using %d instead\n",
|
||||
task->pid, desired.prio,
|
||||
to_kernel_prio(policy, priority));
|
||||
|
||||
trace_binder_set_priority(task->tgid, task->pid, task->normal_prio,
|
||||
to_kernel_prio(policy, priority),
|
||||
desired.prio);
|
||||
|
||||
/* Set the actual priority */
|
||||
if (task->policy != policy || is_rt_policy(policy)) {
|
||||
struct sched_param params;
|
||||
|
||||
params.sched_priority = is_rt_policy(policy) ? priority : 0;
|
||||
|
||||
sched_setscheduler_nocheck(task,
|
||||
policy | SCHED_RESET_ON_FORK,
|
||||
¶ms);
|
||||
}
|
||||
if (is_fair_policy(policy))
|
||||
set_user_nice(task, priority);
|
||||
}
|
||||
|
||||
static void binder_set_priority(struct task_struct *task,
|
||||
struct binder_priority desired)
|
||||
{
|
||||
binder_do_set_priority(task, desired, /* verify = */ true);
|
||||
}
|
||||
|
||||
static void binder_restore_priority(struct task_struct *task,
|
||||
struct binder_priority desired)
|
||||
{
|
||||
binder_do_set_priority(task, desired, /* verify = */ false);
|
||||
}
|
||||
|
||||
static void binder_transaction_priority(struct task_struct *task,
|
||||
struct binder_transaction *t,
|
||||
struct binder_priority node_prio,
|
||||
bool inherit_rt)
|
||||
{
|
||||
struct binder_priority desired_prio = t->priority;
|
||||
|
||||
if (t->set_priority_called)
|
||||
return;
|
||||
binder_user_error("%d RLIMIT_NICE not set\n", current->pid);
|
||||
|
||||
t->set_priority_called = true;
|
||||
t->saved_priority.sched_policy = task->policy;
|
||||
t->saved_priority.prio = task->normal_prio;
|
||||
|
||||
if (!inherit_rt && is_rt_policy(desired_prio.sched_policy)) {
|
||||
desired_prio.prio = NICE_TO_PRIO(0);
|
||||
desired_prio.sched_policy = SCHED_NORMAL;
|
||||
}
|
||||
|
||||
if (node_prio.prio < t->priority.prio ||
|
||||
(node_prio.prio == t->priority.prio &&
|
||||
node_prio.sched_policy == SCHED_FIFO)) {
|
||||
/*
|
||||
* In case the minimum priority on the node is
|
||||
* higher (lower value), use that priority. If
|
||||
* the priority is the same, but the node uses
|
||||
* SCHED_FIFO, prefer SCHED_FIFO, since it can
|
||||
* run unbounded, unlike SCHED_RR.
|
||||
*/
|
||||
desired_prio = node_prio;
|
||||
}
|
||||
|
||||
binder_set_priority(task, desired_prio);
|
||||
}
|
||||
|
||||
static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc,
|
||||
@ -1175,6 +1324,7 @@ static struct binder_node *binder_init_node_ilocked(
|
||||
binder_uintptr_t ptr = fp ? fp->binder : 0;
|
||||
binder_uintptr_t cookie = fp ? fp->cookie : 0;
|
||||
__u32 flags = fp ? fp->flags : 0;
|
||||
s8 priority;
|
||||
|
||||
assert_spin_locked(&proc->inner_lock);
|
||||
|
||||
@ -1207,8 +1357,12 @@ static struct binder_node *binder_init_node_ilocked(
|
||||
node->ptr = ptr;
|
||||
node->cookie = cookie;
|
||||
node->work.type = BINDER_WORK_NODE;
|
||||
node->min_priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
|
||||
priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
|
||||
node->sched_policy = (flags & FLAT_BINDER_FLAG_SCHED_POLICY_MASK) >>
|
||||
FLAT_BINDER_FLAG_SCHED_POLICY_SHIFT;
|
||||
node->min_priority = to_kernel_prio(node->sched_policy, priority);
|
||||
node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
|
||||
node->inherit_rt = !!(flags & FLAT_BINDER_FLAG_INHERIT_RT);
|
||||
spin_lock_init(&node->lock);
|
||||
INIT_LIST_HEAD(&node->work.entry);
|
||||
INIT_LIST_HEAD(&node->async_todo);
|
||||
@ -2633,11 +2787,15 @@ static bool binder_proc_transaction(struct binder_transaction *t,
|
||||
struct binder_thread *thread)
|
||||
{
|
||||
struct binder_node *node = t->buffer->target_node;
|
||||
struct binder_priority node_prio;
|
||||
bool oneway = !!(t->flags & TF_ONE_WAY);
|
||||
bool pending_async = false;
|
||||
|
||||
BUG_ON(!node);
|
||||
binder_node_lock(node);
|
||||
node_prio.prio = node->min_priority;
|
||||
node_prio.sched_policy = node->sched_policy;
|
||||
|
||||
if (oneway) {
|
||||
BUG_ON(thread);
|
||||
if (node->has_async_transaction) {
|
||||
@ -2658,12 +2816,15 @@ static bool binder_proc_transaction(struct binder_transaction *t,
|
||||
if (!thread && !pending_async)
|
||||
thread = binder_select_thread_ilocked(proc);
|
||||
|
||||
if (thread)
|
||||
if (thread) {
|
||||
binder_transaction_priority(thread->task, t, node_prio,
|
||||
node->inherit_rt);
|
||||
binder_enqueue_thread_work_ilocked(thread, &t->work);
|
||||
else if (!pending_async)
|
||||
} else if (!pending_async) {
|
||||
binder_enqueue_work_ilocked(&t->work, &proc->todo);
|
||||
else
|
||||
} else {
|
||||
binder_enqueue_work_ilocked(&t->work, &node->async_todo);
|
||||
}
|
||||
|
||||
if (!pending_async)
|
||||
binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);
|
||||
@ -2780,7 +2941,6 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
}
|
||||
thread->transaction_stack = in_reply_to->to_parent;
|
||||
binder_inner_proc_unlock(proc);
|
||||
binder_set_nice(in_reply_to->saved_priority);
|
||||
target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
|
||||
if (target_thread == NULL) {
|
||||
return_error = BR_DEAD_REPLY;
|
||||
@ -2953,7 +3113,15 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
t->to_thread = target_thread;
|
||||
t->code = tr->code;
|
||||
t->flags = tr->flags;
|
||||
t->priority = task_nice(current);
|
||||
if (!(t->flags & TF_ONE_WAY) &&
|
||||
binder_supported_policy(current->policy)) {
|
||||
/* Inherit supported policies for synchronous transactions */
|
||||
t->priority.sched_policy = current->policy;
|
||||
t->priority.prio = current->normal_prio;
|
||||
} else {
|
||||
/* Otherwise, fall back to the default priority */
|
||||
t->priority = target_proc->default_priority;
|
||||
}
|
||||
|
||||
trace_binder_transaction(reply, t, target_node);
|
||||
|
||||
@ -3182,6 +3350,7 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
binder_enqueue_thread_work_ilocked(target_thread, &t->work);
|
||||
binder_inner_proc_unlock(target_proc);
|
||||
wake_up_interruptible_sync(&target_thread->wait);
|
||||
binder_restore_priority(current, in_reply_to->saved_priority);
|
||||
binder_free_transaction(in_reply_to);
|
||||
} else if (!(t->flags & TF_ONE_WAY)) {
|
||||
BUG_ON(t->buffer->async_transaction != 0);
|
||||
@ -3285,6 +3454,7 @@ err_invalid_target_handle:
|
||||
|
||||
BUG_ON(thread->return_error.cmd != BR_OK);
|
||||
if (in_reply_to) {
|
||||
binder_restore_priority(current, in_reply_to->saved_priority);
|
||||
thread->return_error.cmd = BR_TRANSACTION_COMPLETE;
|
||||
binder_enqueue_thread_work(thread, &thread->return_error.work);
|
||||
binder_send_failed_reply(in_reply_to, return_error);
|
||||
@ -3865,7 +4035,7 @@ retry:
|
||||
wait_event_interruptible(binder_user_error_wait,
|
||||
binder_stop_on_user_error < 2);
|
||||
}
|
||||
binder_set_nice(proc->default_priority);
|
||||
binder_restore_priority(current, proc->default_priority);
|
||||
}
|
||||
|
||||
if (non_block) {
|
||||
@ -4080,16 +4250,14 @@ retry:
|
||||
BUG_ON(t->buffer == NULL);
|
||||
if (t->buffer->target_node) {
|
||||
struct binder_node *target_node = t->buffer->target_node;
|
||||
struct binder_priority node_prio;
|
||||
|
||||
tr.target.ptr = target_node->ptr;
|
||||
tr.cookie = target_node->cookie;
|
||||
t->saved_priority = task_nice(current);
|
||||
if (t->priority < target_node->min_priority &&
|
||||
!(t->flags & TF_ONE_WAY))
|
||||
binder_set_nice(t->priority);
|
||||
else if (!(t->flags & TF_ONE_WAY) ||
|
||||
t->saved_priority > target_node->min_priority)
|
||||
binder_set_nice(target_node->min_priority);
|
||||
node_prio.sched_policy = target_node->sched_policy;
|
||||
node_prio.prio = target_node->min_priority;
|
||||
binder_transaction_priority(current, t, node_prio,
|
||||
target_node->inherit_rt);
|
||||
cmd = BR_TRANSACTION;
|
||||
} else {
|
||||
tr.target.ptr = 0;
|
||||
@ -4267,6 +4435,8 @@ static struct binder_thread *binder_get_thread_ilocked(
|
||||
binder_stats_created(BINDER_STAT_THREAD);
|
||||
thread->proc = proc;
|
||||
thread->pid = current->pid;
|
||||
get_task_struct(current);
|
||||
thread->task = current;
|
||||
atomic_set(&thread->tmp_ref, 0);
|
||||
init_waitqueue_head(&thread->wait);
|
||||
INIT_LIST_HEAD(&thread->todo);
|
||||
@ -4317,6 +4487,7 @@ static void binder_free_thread(struct binder_thread *thread)
|
||||
BUG_ON(!list_empty(&thread->todo));
|
||||
binder_stats_deleted(BINDER_STAT_THREAD);
|
||||
binder_proc_dec_tmpref(thread->proc);
|
||||
put_task_struct(thread->task);
|
||||
kfree(thread);
|
||||
}
|
||||
|
||||
@ -4767,7 +4938,14 @@ static int binder_open(struct inode *nodp, struct file *filp)
|
||||
proc->tsk = current->group_leader;
|
||||
mutex_init(&proc->files_lock);
|
||||
INIT_LIST_HEAD(&proc->todo);
|
||||
proc->default_priority = task_nice(current);
|
||||
if (binder_supported_policy(current->policy)) {
|
||||
proc->default_priority.sched_policy = current->policy;
|
||||
proc->default_priority.prio = current->normal_prio;
|
||||
} else {
|
||||
proc->default_priority.sched_policy = SCHED_NORMAL;
|
||||
proc->default_priority.prio = NICE_TO_PRIO(0);
|
||||
}
|
||||
|
||||
binder_dev = container_of(filp->private_data, struct binder_device,
|
||||
miscdev);
|
||||
proc->context = &binder_dev->context;
|
||||
@ -5061,13 +5239,14 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
|
||||
spin_lock(&t->lock);
|
||||
to_proc = t->to_proc;
|
||||
seq_printf(m,
|
||||
"%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d",
|
||||
"%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %d:%d r%d",
|
||||
prefix, t->debug_id, t,
|
||||
t->from ? t->from->proc->pid : 0,
|
||||
t->from ? t->from->pid : 0,
|
||||
to_proc ? to_proc->pid : 0,
|
||||
t->to_thread ? t->to_thread->pid : 0,
|
||||
t->code, t->flags, t->priority, t->need_reply);
|
||||
t->code, t->flags, t->priority.sched_policy,
|
||||
t->priority.prio, t->need_reply);
|
||||
spin_unlock(&t->lock);
|
||||
|
||||
if (proc != to_proc) {
|
||||
@ -5185,8 +5364,9 @@ static void print_binder_node_nilocked(struct seq_file *m,
|
||||
hlist_for_each_entry(ref, &node->refs, node_entry)
|
||||
count++;
|
||||
|
||||
seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d tr %d",
|
||||
seq_printf(m, " node %d: u%016llx c%016llx pri %d:%d hs %d hw %d ls %d lw %d is %d iw %d tr %d",
|
||||
node->debug_id, (u64)node->ptr, (u64)node->cookie,
|
||||
node->sched_policy, node->min_priority,
|
||||
node->has_strong_ref, node->has_weak_ref,
|
||||
node->local_strong_refs, node->local_weak_refs,
|
||||
node->internal_strong_refs, count, node->tmp_refs);
|
||||
|
@ -85,6 +85,30 @@ DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_ioctl_done);
|
||||
DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_write_done);
|
||||
DEFINE_BINDER_FUNCTION_RETURN_EVENT(binder_read_done);
|
||||
|
||||
TRACE_EVENT(binder_set_priority,
|
||||
TP_PROTO(int proc, int thread, unsigned int old_prio,
|
||||
unsigned int desired_prio, unsigned int new_prio),
|
||||
TP_ARGS(proc, thread, old_prio, new_prio, desired_prio),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, proc)
|
||||
__field(int, thread)
|
||||
__field(unsigned int, old_prio)
|
||||
__field(unsigned int, new_prio)
|
||||
__field(unsigned int, desired_prio)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->proc = proc;
|
||||
__entry->thread = thread;
|
||||
__entry->old_prio = old_prio;
|
||||
__entry->new_prio = new_prio;
|
||||
__entry->desired_prio = desired_prio;
|
||||
),
|
||||
TP_printk("proc=%d thread=%d old=%d => new=%d desired=%d",
|
||||
__entry->proc, __entry->thread, __entry->old_prio,
|
||||
__entry->new_prio, __entry->desired_prio)
|
||||
);
|
||||
|
||||
TRACE_EVENT(binder_wait_for_work,
|
||||
TP_PROTO(bool proc_work, bool transaction_stack, bool thread_todo),
|
||||
TP_ARGS(proc_work, transaction_stack, thread_todo),
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
|
||||
#include "../base.h"
|
||||
#include "power.h"
|
||||
@ -1706,6 +1707,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
pm_callback_t callback = NULL;
|
||||
const char *info = NULL;
|
||||
int error = 0;
|
||||
char suspend_abort[MAX_SUSPEND_ABORT_LEN];
|
||||
DECLARE_DPM_WATCHDOG_ON_STACK(wd);
|
||||
|
||||
TRACE_DEVICE(dev);
|
||||
@ -1726,6 +1728,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
|
||||
pm_wakeup_event(dev, 0);
|
||||
|
||||
if (pm_wakeup_pending()) {
|
||||
pm_get_active_wakeup_sources(suspend_abort,
|
||||
MAX_SUSPEND_ABORT_LEN);
|
||||
log_suspend_abort_reason(suspend_abort);
|
||||
async_error = -EBUSY;
|
||||
goto Complete;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/types.h>
|
||||
#include <trace/events/power.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
@ -806,6 +807,37 @@ void pm_wakeup_dev_event(struct device *dev, unsigned int msec, bool hard)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_wakeup_dev_event);
|
||||
|
||||
void pm_get_active_wakeup_sources(char *pending_wakeup_source, size_t max)
|
||||
{
|
||||
struct wakeup_source *ws, *last_active_ws = NULL;
|
||||
int len = 0;
|
||||
bool active = false;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
if (ws->active && len < max) {
|
||||
if (!active)
|
||||
len += scnprintf(pending_wakeup_source, max,
|
||||
"Pending Wakeup Sources: ");
|
||||
len += scnprintf(pending_wakeup_source + len, max - len,
|
||||
"%s ", ws->name);
|
||||
active = true;
|
||||
} else if (!active &&
|
||||
(!last_active_ws ||
|
||||
ktime_to_ns(ws->last_time) >
|
||||
ktime_to_ns(last_active_ws->last_time))) {
|
||||
last_active_ws = ws;
|
||||
}
|
||||
}
|
||||
if (!active && last_active_ws) {
|
||||
scnprintf(pending_wakeup_source, max,
|
||||
"Last active Wakeup Source: %s",
|
||||
last_active_ws->name);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm_get_active_wakeup_sources);
|
||||
|
||||
void pm_print_active_wakeup_sources(void)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <trace/events/power.h>
|
||||
#include <linux/wakeup_reason.h>
|
||||
|
||||
static LIST_HEAD(syscore_ops_list);
|
||||
static DEFINE_MUTEX(syscore_ops_lock);
|
||||
@ -74,6 +75,8 @@ int syscore_suspend(void)
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
log_suspend_abort_reason("System core suspend callback %pF failed",
|
||||
ops->suspend);
|
||||
pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend);
|
||||
|
||||
list_for_each_entry_continue(ops, &syscore_ops_list, node)
|
||||
|
@ -37,6 +37,13 @@ config CPU_FREQ_STAT
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config CPU_FREQ_TIMES
|
||||
bool "CPU frequency time-in-state statistics"
|
||||
help
|
||||
Export CPU time-in-state information through procfs.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
choice
|
||||
prompt "Default CPUFreq governor"
|
||||
default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
|
||||
|
@ -5,6 +5,9 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o
|
||||
# CPUfreq stats
|
||||
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
|
||||
|
||||
# CPUfreq times
|
||||
obj-$(CONFIG_CPU_FREQ_TIMES) += cpufreq_times.o
|
||||
|
||||
# CPUfreq governors
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpufreq_times.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
@ -349,6 +350,7 @@ static void cpufreq_notify_transition(struct cpufreq_policy *policy,
|
||||
}
|
||||
|
||||
cpufreq_stats_record_transition(policy, freqs->new);
|
||||
cpufreq_times_record_transition(freqs);
|
||||
policy->cur = freqs->new;
|
||||
}
|
||||
}
|
||||
@ -1295,6 +1297,7 @@ static int cpufreq_online(unsigned int cpu)
|
||||
goto out_destroy_policy;
|
||||
|
||||
cpufreq_stats_create_table(policy);
|
||||
cpufreq_times_create_policy(policy);
|
||||
|
||||
write_lock_irqsave(&cpufreq_driver_lock, flags);
|
||||
list_add(&policy->policy_list, &cpufreq_policy_list);
|
||||
|
464
drivers/cpufreq/cpufreq_times.c
Normal file
464
drivers/cpufreq/cpufreq_times.c
Normal file
@ -0,0 +1,464 @@
|
||||
/* drivers/cpufreq/cpufreq_times.c
|
||||
*
|
||||
* Copyright (C) 2018 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpufreq_times.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/threads.h>
|
||||
|
||||
#define UID_HASH_BITS 10
|
||||
|
||||
static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS);
|
||||
|
||||
static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */
|
||||
static DEFINE_SPINLOCK(uid_lock); /* uid_hash_table */
|
||||
|
||||
struct uid_entry {
|
||||
uid_t uid;
|
||||
unsigned int max_state;
|
||||
struct hlist_node hash;
|
||||
struct rcu_head rcu;
|
||||
u64 time_in_state[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cpu_freqs - per-cpu frequency information
|
||||
* @offset: start of these freqs' stats in task time_in_state array
|
||||
* @max_state: number of entries in freq_table
|
||||
* @last_index: index in freq_table of last frequency switched to
|
||||
* @freq_table: list of available frequencies
|
||||
*/
|
||||
struct cpu_freqs {
|
||||
unsigned int offset;
|
||||
unsigned int max_state;
|
||||
unsigned int last_index;
|
||||
unsigned int freq_table[0];
|
||||
};
|
||||
|
||||
static struct cpu_freqs *all_freqs[NR_CPUS];
|
||||
|
||||
static unsigned int next_offset;
|
||||
|
||||
|
||||
/* Caller must hold rcu_read_lock() */
|
||||
static struct uid_entry *find_uid_entry_rcu(uid_t uid)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
|
||||
hash_for_each_possible_rcu(uid_hash_table, uid_entry, hash, uid) {
|
||||
if (uid_entry->uid == uid)
|
||||
return uid_entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Caller must hold uid lock */
|
||||
static struct uid_entry *find_uid_entry_locked(uid_t uid)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
|
||||
hash_for_each_possible(uid_hash_table, uid_entry, hash, uid) {
|
||||
if (uid_entry->uid == uid)
|
||||
return uid_entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Caller must hold uid lock */
|
||||
static struct uid_entry *find_or_register_uid_locked(uid_t uid)
|
||||
{
|
||||
struct uid_entry *uid_entry, *temp;
|
||||
unsigned int max_state = READ_ONCE(next_offset);
|
||||
size_t alloc_size = sizeof(*uid_entry) + max_state *
|
||||
sizeof(uid_entry->time_in_state[0]);
|
||||
|
||||
uid_entry = find_uid_entry_locked(uid);
|
||||
if (uid_entry) {
|
||||
if (uid_entry->max_state == max_state)
|
||||
return uid_entry;
|
||||
/* uid_entry->time_in_state is too small to track all freqs, so
|
||||
* expand it.
|
||||
*/
|
||||
temp = __krealloc(uid_entry, alloc_size, GFP_ATOMIC);
|
||||
if (!temp)
|
||||
return uid_entry;
|
||||
temp->max_state = max_state;
|
||||
memset(temp->time_in_state + uid_entry->max_state, 0,
|
||||
(max_state - uid_entry->max_state) *
|
||||
sizeof(uid_entry->time_in_state[0]));
|
||||
if (temp != uid_entry) {
|
||||
hlist_replace_rcu(&uid_entry->hash, &temp->hash);
|
||||
kfree_rcu(uid_entry, rcu);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
uid_entry = kzalloc(alloc_size, GFP_ATOMIC);
|
||||
if (!uid_entry)
|
||||
return NULL;
|
||||
|
||||
uid_entry->uid = uid;
|
||||
uid_entry->max_state = max_state;
|
||||
|
||||
hash_add_rcu(uid_hash_table, &uid_entry->hash, uid);
|
||||
|
||||
return uid_entry;
|
||||
}
|
||||
|
||||
static bool freq_index_invalid(unsigned int index)
|
||||
{
|
||||
unsigned int cpu;
|
||||
struct cpu_freqs *freqs;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
freqs = all_freqs[cpu];
|
||||
if (!freqs || index < freqs->offset ||
|
||||
freqs->offset + freqs->max_state <= index)
|
||||
continue;
|
||||
return freqs->freq_table[index - freqs->offset] ==
|
||||
CPUFREQ_ENTRY_INVALID;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int single_uid_time_in_state_show(struct seq_file *m, void *ptr)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
unsigned int i;
|
||||
u64 time;
|
||||
uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private);
|
||||
|
||||
if (uid == overflowuid)
|
||||
return -EINVAL;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
uid_entry = find_uid_entry_rcu(uid);
|
||||
if (!uid_entry) {
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < uid_entry->max_state; ++i) {
|
||||
if (freq_index_invalid(i))
|
||||
continue;
|
||||
time = nsec_to_clock_t(uid_entry->time_in_state[i]);
|
||||
seq_write(m, &time, sizeof(time));
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *uid_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
if (*pos >= HASH_SIZE(uid_hash_table))
|
||||
return NULL;
|
||||
|
||||
return &uid_hash_table[*pos];
|
||||
}
|
||||
|
||||
static void *uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
(*pos)++;
|
||||
|
||||
if (*pos >= HASH_SIZE(uid_hash_table))
|
||||
return NULL;
|
||||
|
||||
return &uid_hash_table[*pos];
|
||||
}
|
||||
|
||||
static void uid_seq_stop(struct seq_file *seq, void *v) { }
|
||||
|
||||
static int uid_time_in_state_seq_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
struct cpu_freqs *freqs, *last_freqs = NULL;
|
||||
int i, cpu;
|
||||
|
||||
if (v == uid_hash_table) {
|
||||
seq_puts(m, "uid:");
|
||||
for_each_possible_cpu(cpu) {
|
||||
freqs = all_freqs[cpu];
|
||||
if (!freqs || freqs == last_freqs)
|
||||
continue;
|
||||
last_freqs = freqs;
|
||||
for (i = 0; i < freqs->max_state; i++) {
|
||||
if (freqs->freq_table[i] ==
|
||||
CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
seq_printf(m, " %d", freqs->freq_table[i]);
|
||||
}
|
||||
}
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) {
|
||||
if (uid_entry->max_state)
|
||||
seq_printf(m, "%d:", uid_entry->uid);
|
||||
for (i = 0; i < uid_entry->max_state; ++i) {
|
||||
if (freq_index_invalid(i))
|
||||
continue;
|
||||
seq_printf(m, " %lu", (unsigned long)nsec_to_clock_t(
|
||||
uid_entry->time_in_state[i]));
|
||||
}
|
||||
if (uid_entry->max_state)
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpufreq_task_times_init(struct task_struct *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&task_time_in_state_lock, flags);
|
||||
p->time_in_state = NULL;
|
||||
spin_unlock_irqrestore(&task_time_in_state_lock, flags);
|
||||
p->max_state = 0;
|
||||
}
|
||||
|
||||
void cpufreq_task_times_alloc(struct task_struct *p)
|
||||
{
|
||||
void *temp;
|
||||
unsigned long flags;
|
||||
unsigned int max_state = READ_ONCE(next_offset);
|
||||
|
||||
/* We use one array to avoid multiple allocs per task */
|
||||
temp = kcalloc(max_state, sizeof(p->time_in_state[0]), GFP_ATOMIC);
|
||||
if (!temp)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&task_time_in_state_lock, flags);
|
||||
p->time_in_state = temp;
|
||||
spin_unlock_irqrestore(&task_time_in_state_lock, flags);
|
||||
p->max_state = max_state;
|
||||
}
|
||||
|
||||
/* Caller must hold task_time_in_state_lock */
|
||||
static int cpufreq_task_times_realloc_locked(struct task_struct *p)
|
||||
{
|
||||
void *temp;
|
||||
unsigned int max_state = READ_ONCE(next_offset);
|
||||
|
||||
temp = krealloc(p->time_in_state, max_state * sizeof(u64), GFP_ATOMIC);
|
||||
if (!temp)
|
||||
return -ENOMEM;
|
||||
p->time_in_state = temp;
|
||||
memset(p->time_in_state + p->max_state, 0,
|
||||
(max_state - p->max_state) * sizeof(u64));
|
||||
p->max_state = max_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpufreq_task_times_exit(struct task_struct *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
void *temp;
|
||||
|
||||
if (!p->time_in_state)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&task_time_in_state_lock, flags);
|
||||
temp = p->time_in_state;
|
||||
p->time_in_state = NULL;
|
||||
spin_unlock_irqrestore(&task_time_in_state_lock, flags);
|
||||
kfree(temp);
|
||||
}
|
||||
|
||||
int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns,
|
||||
struct pid *pid, struct task_struct *p)
|
||||
{
|
||||
unsigned int cpu, i;
|
||||
u64 cputime;
|
||||
unsigned long flags;
|
||||
struct cpu_freqs *freqs;
|
||||
struct cpu_freqs *last_freqs = NULL;
|
||||
|
||||
spin_lock_irqsave(&task_time_in_state_lock, flags);
|
||||
for_each_possible_cpu(cpu) {
|
||||
freqs = all_freqs[cpu];
|
||||
if (!freqs || freqs == last_freqs)
|
||||
continue;
|
||||
last_freqs = freqs;
|
||||
|
||||
seq_printf(m, "cpu%u\n", cpu);
|
||||
for (i = 0; i < freqs->max_state; i++) {
|
||||
if (freqs->freq_table[i] == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
cputime = 0;
|
||||
if (freqs->offset + i < p->max_state &&
|
||||
p->time_in_state)
|
||||
cputime = p->time_in_state[freqs->offset + i];
|
||||
seq_printf(m, "%u %lu\n", freqs->freq_table[i],
|
||||
(unsigned long)nsec_to_clock_t(cputime));
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&task_time_in_state_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpufreq_acct_update_power(struct task_struct *p, u64 cputime)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int state;
|
||||
struct uid_entry *uid_entry;
|
||||
struct cpu_freqs *freqs = all_freqs[task_cpu(p)];
|
||||
uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
|
||||
|
||||
if (!freqs || p->flags & PF_EXITING)
|
||||
return;
|
||||
|
||||
state = freqs->offset + READ_ONCE(freqs->last_index);
|
||||
|
||||
spin_lock_irqsave(&task_time_in_state_lock, flags);
|
||||
if ((state < p->max_state || !cpufreq_task_times_realloc_locked(p)) &&
|
||||
p->time_in_state)
|
||||
p->time_in_state[state] += cputime;
|
||||
spin_unlock_irqrestore(&task_time_in_state_lock, flags);
|
||||
|
||||
spin_lock_irqsave(&uid_lock, flags);
|
||||
uid_entry = find_or_register_uid_locked(uid);
|
||||
if (uid_entry && state < uid_entry->max_state)
|
||||
uid_entry->time_in_state[state] += cputime;
|
||||
spin_unlock_irqrestore(&uid_lock, flags);
|
||||
}
|
||||
|
||||
void cpufreq_times_create_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
int cpu, index;
|
||||
unsigned int count = 0;
|
||||
struct cpufreq_frequency_table *pos, *table;
|
||||
struct cpu_freqs *freqs;
|
||||
void *tmp;
|
||||
|
||||
if (all_freqs[policy->cpu])
|
||||
return;
|
||||
|
||||
table = policy->freq_table;
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
cpufreq_for_each_entry(pos, table)
|
||||
count++;
|
||||
|
||||
tmp = kzalloc(sizeof(*freqs) + sizeof(freqs->freq_table[0]) * count,
|
||||
GFP_KERNEL);
|
||||
if (!tmp)
|
||||
return;
|
||||
|
||||
freqs = tmp;
|
||||
freqs->max_state = count;
|
||||
|
||||
index = cpufreq_frequency_table_get_index(policy, policy->cur);
|
||||
if (index >= 0)
|
||||
WRITE_ONCE(freqs->last_index, index);
|
||||
|
||||
cpufreq_for_each_entry(pos, table)
|
||||
freqs->freq_table[pos - table] = pos->frequency;
|
||||
|
||||
freqs->offset = next_offset;
|
||||
WRITE_ONCE(next_offset, freqs->offset + count);
|
||||
for_each_cpu(cpu, policy->related_cpus)
|
||||
all_freqs[cpu] = freqs;
|
||||
}
|
||||
|
||||
void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
struct hlist_node *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&uid_lock, flags);
|
||||
|
||||
for (; uid_start <= uid_end; uid_start++) {
|
||||
hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp,
|
||||
hash, uid_start) {
|
||||
if (uid_start == uid_entry->uid) {
|
||||
hash_del_rcu(&uid_entry->hash);
|
||||
kfree_rcu(uid_entry, rcu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&uid_lock, flags);
|
||||
}
|
||||
|
||||
void cpufreq_times_record_transition(struct cpufreq_freqs *freq)
|
||||
{
|
||||
int index;
|
||||
struct cpu_freqs *freqs = all_freqs[freq->cpu];
|
||||
struct cpufreq_policy *policy;
|
||||
|
||||
if (!freqs)
|
||||
return;
|
||||
|
||||
policy = cpufreq_cpu_get(freq->cpu);
|
||||
if (!policy)
|
||||
return;
|
||||
|
||||
index = cpufreq_frequency_table_get_index(policy, freq->new);
|
||||
if (index >= 0)
|
||||
WRITE_ONCE(freqs->last_index, index);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
static const struct seq_operations uid_time_in_state_seq_ops = {
|
||||
.start = uid_seq_start,
|
||||
.next = uid_seq_next,
|
||||
.stop = uid_seq_stop,
|
||||
.show = uid_time_in_state_seq_show,
|
||||
};
|
||||
|
||||
static int uid_time_in_state_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &uid_time_in_state_seq_ops);
|
||||
}
|
||||
|
||||
int single_uid_time_in_state_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, single_uid_time_in_state_show,
|
||||
&(inode->i_uid));
|
||||
}
|
||||
|
||||
static const struct file_operations uid_time_in_state_fops = {
|
||||
.open = uid_time_in_state_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static int __init cpufreq_times_init(void)
|
||||
{
|
||||
proc_create_data("uid_time_in_state", 0444, NULL,
|
||||
&uid_time_in_state_fops, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_initcall(cpufreq_times_init);
|
@ -179,7 +179,12 @@ static inline int performance_multiplier(unsigned long nr_iowaiters, unsigned lo
|
||||
|
||||
/* for higher loadavg, we are more reluctant */
|
||||
|
||||
mult += 2 * get_loadavg(load);
|
||||
/*
|
||||
* this doesn't work as intended - it is almost always 0, but can
|
||||
* sometimes, depending on workload, spike very high into the hundreds
|
||||
* even when the average cpu load is under 10%.
|
||||
*/
|
||||
/* mult += 2 * get_loadavg(); */
|
||||
|
||||
/* for IO wait tasks (per cpu!) we add 5x each */
|
||||
mult += 10 * nr_iowaiters;
|
||||
|
@ -184,6 +184,19 @@ config INPUT_APMPOWER
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called apm-power.
|
||||
|
||||
config INPUT_KEYRESET
|
||||
bool "Reset key"
|
||||
depends on INPUT
|
||||
select INPUT_KEYCOMBO
|
||||
---help---
|
||||
Say Y here if you want to reboot when some keys are pressed;
|
||||
|
||||
config INPUT_KEYCOMBO
|
||||
bool "Key combo"
|
||||
depends on INPUT
|
||||
---help---
|
||||
Say Y here if you want to take action when some keys are pressed;
|
||||
|
||||
comment "Input Device Drivers"
|
||||
|
||||
source "drivers/input/keyboard/Kconfig"
|
||||
|
@ -27,5 +27,7 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
|
||||
obj-$(CONFIG_INPUT_MISC) += misc/
|
||||
|
||||
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
|
||||
obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o
|
||||
obj-$(CONFIG_INPUT_KEYCOMBO) += keycombo.o
|
||||
|
||||
obj-$(CONFIG_RMI4_CORE) += rmi4/
|
||||
|
261
drivers/input/keycombo.c
Normal file
261
drivers/input/keycombo.c
Normal file
@ -0,0 +1,261 @@
|
||||
/* drivers/input/keycombo.c
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/keycombo.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct keycombo_state {
|
||||
struct input_handler input_handler;
|
||||
unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
|
||||
unsigned long upbit[BITS_TO_LONGS(KEY_CNT)];
|
||||
unsigned long key[BITS_TO_LONGS(KEY_CNT)];
|
||||
spinlock_t lock;
|
||||
struct workqueue_struct *wq;
|
||||
int key_down_target;
|
||||
int key_down;
|
||||
int key_up;
|
||||
struct delayed_work key_down_work;
|
||||
int delay;
|
||||
struct work_struct key_up_work;
|
||||
void (*key_up_fn)(void *);
|
||||
void (*key_down_fn)(void *);
|
||||
void *priv;
|
||||
int key_is_down;
|
||||
struct wakeup_source combo_held_wake_source;
|
||||
struct wakeup_source combo_up_wake_source;
|
||||
};
|
||||
|
||||
static void do_key_down(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork = container_of(work, struct delayed_work,
|
||||
work);
|
||||
struct keycombo_state *state = container_of(dwork,
|
||||
struct keycombo_state, key_down_work);
|
||||
if (state->key_down_fn)
|
||||
state->key_down_fn(state->priv);
|
||||
}
|
||||
|
||||
static void do_key_up(struct work_struct *work)
|
||||
{
|
||||
struct keycombo_state *state = container_of(work, struct keycombo_state,
|
||||
key_up_work);
|
||||
if (state->key_up_fn)
|
||||
state->key_up_fn(state->priv);
|
||||
__pm_relax(&state->combo_up_wake_source);
|
||||
}
|
||||
|
||||
static void keycombo_event(struct input_handle *handle, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct keycombo_state *state = handle->private;
|
||||
|
||||
if (type != EV_KEY)
|
||||
return;
|
||||
|
||||
if (code >= KEY_MAX)
|
||||
return;
|
||||
|
||||
if (!test_bit(code, state->keybit))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&state->lock, flags);
|
||||
if (!test_bit(code, state->key) == !value)
|
||||
goto done;
|
||||
__change_bit(code, state->key);
|
||||
if (test_bit(code, state->upbit)) {
|
||||
if (value)
|
||||
state->key_up++;
|
||||
else
|
||||
state->key_up--;
|
||||
} else {
|
||||
if (value)
|
||||
state->key_down++;
|
||||
else
|
||||
state->key_down--;
|
||||
}
|
||||
if (state->key_down == state->key_down_target && state->key_up == 0) {
|
||||
__pm_stay_awake(&state->combo_held_wake_source);
|
||||
state->key_is_down = 1;
|
||||
if (queue_delayed_work(state->wq, &state->key_down_work,
|
||||
state->delay))
|
||||
pr_debug("Key down work already queued!");
|
||||
} else if (state->key_is_down) {
|
||||
if (!cancel_delayed_work(&state->key_down_work)) {
|
||||
__pm_stay_awake(&state->combo_up_wake_source);
|
||||
queue_work(state->wq, &state->key_up_work);
|
||||
}
|
||||
__pm_relax(&state->combo_held_wake_source);
|
||||
state->key_is_down = 0;
|
||||
}
|
||||
done:
|
||||
spin_unlock_irqrestore(&state->lock, flags);
|
||||
}
|
||||
|
||||
static int keycombo_connect(struct input_handler *handler,
|
||||
struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct input_handle *handle;
|
||||
struct keycombo_state *state =
|
||||
container_of(handler, struct keycombo_state, input_handler);
|
||||
for (i = 0; i < KEY_MAX; i++) {
|
||||
if (test_bit(i, state->keybit) && test_bit(i, dev->keybit))
|
||||
break;
|
||||
}
|
||||
if (i == KEY_MAX)
|
||||
return -ENODEV;
|
||||
|
||||
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
|
||||
if (!handle)
|
||||
return -ENOMEM;
|
||||
|
||||
handle->dev = dev;
|
||||
handle->handler = handler;
|
||||
handle->name = KEYCOMBO_NAME;
|
||||
handle->private = state;
|
||||
|
||||
ret = input_register_handle(handle);
|
||||
if (ret)
|
||||
goto err_input_register_handle;
|
||||
|
||||
ret = input_open_device(handle);
|
||||
if (ret)
|
||||
goto err_input_open_device;
|
||||
|
||||
return 0;
|
||||
|
||||
err_input_open_device:
|
||||
input_unregister_handle(handle);
|
||||
err_input_register_handle:
|
||||
kfree(handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void keycombo_disconnect(struct input_handle *handle)
|
||||
{
|
||||
input_close_device(handle);
|
||||
input_unregister_handle(handle);
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
static const struct input_device_id keycombo_ids[] = {
|
||||
{
|
||||
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
||||
.evbit = { BIT_MASK(EV_KEY) },
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(input, keycombo_ids);
|
||||
|
||||
static int keycombo_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
int key, *keyp;
|
||||
struct keycombo_state *state;
|
||||
struct keycombo_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&state->lock);
|
||||
keyp = pdata->keys_down;
|
||||
while ((key = *keyp++)) {
|
||||
if (key >= KEY_MAX)
|
||||
continue;
|
||||
state->key_down_target++;
|
||||
__set_bit(key, state->keybit);
|
||||
}
|
||||
if (pdata->keys_up) {
|
||||
keyp = pdata->keys_up;
|
||||
while ((key = *keyp++)) {
|
||||
if (key >= KEY_MAX)
|
||||
continue;
|
||||
__set_bit(key, state->keybit);
|
||||
__set_bit(key, state->upbit);
|
||||
}
|
||||
}
|
||||
|
||||
state->wq = alloc_ordered_workqueue("keycombo", 0);
|
||||
if (!state->wq)
|
||||
return -ENOMEM;
|
||||
|
||||
state->priv = pdata->priv;
|
||||
|
||||
if (pdata->key_down_fn)
|
||||
state->key_down_fn = pdata->key_down_fn;
|
||||
INIT_DELAYED_WORK(&state->key_down_work, do_key_down);
|
||||
|
||||
if (pdata->key_up_fn)
|
||||
state->key_up_fn = pdata->key_up_fn;
|
||||
INIT_WORK(&state->key_up_work, do_key_up);
|
||||
|
||||
wakeup_source_init(&state->combo_held_wake_source, "key combo");
|
||||
wakeup_source_init(&state->combo_up_wake_source, "key combo up");
|
||||
state->delay = msecs_to_jiffies(pdata->key_down_delay);
|
||||
|
||||
state->input_handler.event = keycombo_event;
|
||||
state->input_handler.connect = keycombo_connect;
|
||||
state->input_handler.disconnect = keycombo_disconnect;
|
||||
state->input_handler.name = KEYCOMBO_NAME;
|
||||
state->input_handler.id_table = keycombo_ids;
|
||||
ret = input_register_handler(&state->input_handler);
|
||||
if (ret) {
|
||||
kfree(state);
|
||||
return ret;
|
||||
}
|
||||
platform_set_drvdata(pdev, state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int keycombo_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct keycombo_state *state = platform_get_drvdata(pdev);
|
||||
input_unregister_handler(&state->input_handler);
|
||||
destroy_workqueue(state->wq);
|
||||
kfree(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct platform_driver keycombo_driver = {
|
||||
.driver.name = KEYCOMBO_NAME,
|
||||
.probe = keycombo_probe,
|
||||
.remove = keycombo_remove,
|
||||
};
|
||||
|
||||
static int __init keycombo_init(void)
|
||||
{
|
||||
return platform_driver_register(&keycombo_driver);
|
||||
}
|
||||
|
||||
static void __exit keycombo_exit(void)
|
||||
{
|
||||
return platform_driver_unregister(&keycombo_driver);
|
||||
}
|
||||
|
||||
module_init(keycombo_init);
|
||||
module_exit(keycombo_exit);
|
144
drivers/input/keyreset.c
Normal file
144
drivers/input/keyreset.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* drivers/input/keyreset.c
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/keyreset.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/keycombo.h>
|
||||
|
||||
struct keyreset_state {
|
||||
int restart_requested;
|
||||
int (*reset_fn)(void);
|
||||
struct platform_device *pdev_child;
|
||||
struct work_struct restart_work;
|
||||
};
|
||||
|
||||
static void do_restart(struct work_struct *unused)
|
||||
{
|
||||
orderly_reboot();
|
||||
}
|
||||
|
||||
static void do_reset_fn(void *priv)
|
||||
{
|
||||
struct keyreset_state *state = priv;
|
||||
if (state->restart_requested)
|
||||
panic("keyboard reset failed, %d", state->restart_requested);
|
||||
if (state->reset_fn) {
|
||||
state->restart_requested = state->reset_fn();
|
||||
} else {
|
||||
pr_info("keyboard reset\n");
|
||||
schedule_work(&state->restart_work);
|
||||
state->restart_requested = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int keyreset_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
struct keycombo_platform_data *pdata_child;
|
||||
struct keyreset_platform_data *pdata = pdev->dev.platform_data;
|
||||
int up_size = 0, down_size = 0, size;
|
||||
int key, *keyp;
|
||||
struct keyreset_state *state;
|
||||
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
|
||||
state->pdev_child = platform_device_alloc(KEYCOMBO_NAME,
|
||||
PLATFORM_DEVID_AUTO);
|
||||
if (!state->pdev_child)
|
||||
return -ENOMEM;
|
||||
state->pdev_child->dev.parent = &pdev->dev;
|
||||
INIT_WORK(&state->restart_work, do_restart);
|
||||
|
||||
keyp = pdata->keys_down;
|
||||
while ((key = *keyp++)) {
|
||||
if (key >= KEY_MAX)
|
||||
continue;
|
||||
down_size++;
|
||||
}
|
||||
if (pdata->keys_up) {
|
||||
keyp = pdata->keys_up;
|
||||
while ((key = *keyp++)) {
|
||||
if (key >= KEY_MAX)
|
||||
continue;
|
||||
up_size++;
|
||||
}
|
||||
}
|
||||
size = sizeof(struct keycombo_platform_data)
|
||||
+ sizeof(int) * (down_size + 1);
|
||||
pdata_child = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
|
||||
if (!pdata_child)
|
||||
goto error;
|
||||
memcpy(pdata_child->keys_down, pdata->keys_down,
|
||||
sizeof(int) * down_size);
|
||||
if (up_size > 0) {
|
||||
pdata_child->keys_up = devm_kzalloc(&pdev->dev, up_size + 1,
|
||||
GFP_KERNEL);
|
||||
if (!pdata_child->keys_up)
|
||||
goto error;
|
||||
memcpy(pdata_child->keys_up, pdata->keys_up,
|
||||
sizeof(int) * up_size);
|
||||
if (!pdata_child->keys_up)
|
||||
goto error;
|
||||
}
|
||||
state->reset_fn = pdata->reset_fn;
|
||||
pdata_child->key_down_fn = do_reset_fn;
|
||||
pdata_child->priv = state;
|
||||
pdata_child->key_down_delay = pdata->key_down_delay;
|
||||
ret = platform_device_add_data(state->pdev_child, pdata_child, size);
|
||||
if (ret)
|
||||
goto error;
|
||||
platform_set_drvdata(pdev, state);
|
||||
return platform_device_add(state->pdev_child);
|
||||
error:
|
||||
platform_device_put(state->pdev_child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int keyreset_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct keyreset_state *state = platform_get_drvdata(pdev);
|
||||
platform_device_put(state->pdev_child);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct platform_driver keyreset_driver = {
|
||||
.driver.name = KEYRESET_NAME,
|
||||
.probe = keyreset_probe,
|
||||
.remove = keyreset_remove,
|
||||
};
|
||||
|
||||
static int __init keyreset_init(void)
|
||||
{
|
||||
return platform_driver_register(&keyreset_driver);
|
||||
}
|
||||
|
||||
static void __exit keyreset_exit(void)
|
||||
{
|
||||
return platform_driver_unregister(&keyreset_driver);
|
||||
}
|
||||
|
||||
module_init(keyreset_init);
|
||||
module_exit(keyreset_exit);
|
@ -521,6 +521,11 @@ config INPUT_SGI_BTNS
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called sgi_btns.
|
||||
|
||||
config INPUT_GPIO
|
||||
tristate "GPIO driver support"
|
||||
help
|
||||
Say Y here if you want to support gpio based keys, wheels etc...
|
||||
|
||||
config HP_SDC_RTC
|
||||
tristate "HP SDC Real Time Clock"
|
||||
depends on (GSC || HP300) && SERIO
|
||||
|
@ -36,6 +36,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
|
||||
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
|
||||
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
|
||||
obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o
|
||||
obj-$(CONFIG_INPUT_GPIO) += gpio_event.o gpio_matrix.o gpio_input.o gpio_output.o gpio_axis.o
|
||||
obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o
|
||||
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
|
||||
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
|
||||
|
192
drivers/input/misc/gpio_axis.c
Normal file
192
drivers/input/misc/gpio_axis.c
Normal file
@ -0,0 +1,192 @@
|
||||
/* drivers/input/misc/gpio_axis.c
|
||||
*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_event.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct gpio_axis_state {
|
||||
struct gpio_event_input_devs *input_devs;
|
||||
struct gpio_event_axis_info *info;
|
||||
uint32_t pos;
|
||||
};
|
||||
|
||||
uint16_t gpio_axis_4bit_gray_map_table[] = {
|
||||
[0x0] = 0x0, [0x1] = 0x1, /* 0000 0001 */
|
||||
[0x3] = 0x2, [0x2] = 0x3, /* 0011 0010 */
|
||||
[0x6] = 0x4, [0x7] = 0x5, /* 0110 0111 */
|
||||
[0x5] = 0x6, [0x4] = 0x7, /* 0101 0100 */
|
||||
[0xc] = 0x8, [0xd] = 0x9, /* 1100 1101 */
|
||||
[0xf] = 0xa, [0xe] = 0xb, /* 1111 1110 */
|
||||
[0xa] = 0xc, [0xb] = 0xd, /* 1010 1011 */
|
||||
[0x9] = 0xe, [0x8] = 0xf, /* 1001 1000 */
|
||||
};
|
||||
uint16_t gpio_axis_4bit_gray_map(struct gpio_event_axis_info *info, uint16_t in)
|
||||
{
|
||||
return gpio_axis_4bit_gray_map_table[in];
|
||||
}
|
||||
|
||||
uint16_t gpio_axis_5bit_singletrack_map_table[] = {
|
||||
[0x10] = 0x00, [0x14] = 0x01, [0x1c] = 0x02, /* 10000 10100 11100 */
|
||||
[0x1e] = 0x03, [0x1a] = 0x04, [0x18] = 0x05, /* 11110 11010 11000 */
|
||||
[0x08] = 0x06, [0x0a] = 0x07, [0x0e] = 0x08, /* 01000 01010 01110 */
|
||||
[0x0f] = 0x09, [0x0d] = 0x0a, [0x0c] = 0x0b, /* 01111 01101 01100 */
|
||||
[0x04] = 0x0c, [0x05] = 0x0d, [0x07] = 0x0e, /* 00100 00101 00111 */
|
||||
[0x17] = 0x0f, [0x16] = 0x10, [0x06] = 0x11, /* 10111 10110 00110 */
|
||||
[0x02] = 0x12, [0x12] = 0x13, [0x13] = 0x14, /* 00010 10010 10011 */
|
||||
[0x1b] = 0x15, [0x0b] = 0x16, [0x03] = 0x17, /* 11011 01011 00011 */
|
||||
[0x01] = 0x18, [0x09] = 0x19, [0x19] = 0x1a, /* 00001 01001 11001 */
|
||||
[0x1d] = 0x1b, [0x15] = 0x1c, [0x11] = 0x1d, /* 11101 10101 10001 */
|
||||
};
|
||||
uint16_t gpio_axis_5bit_singletrack_map(
|
||||
struct gpio_event_axis_info *info, uint16_t in)
|
||||
{
|
||||
return gpio_axis_5bit_singletrack_map_table[in];
|
||||
}
|
||||
|
||||
static void gpio_event_update_axis(struct gpio_axis_state *as, int report)
|
||||
{
|
||||
struct gpio_event_axis_info *ai = as->info;
|
||||
int i;
|
||||
int change;
|
||||
uint16_t state = 0;
|
||||
uint16_t pos;
|
||||
uint16_t old_pos = as->pos;
|
||||
for (i = ai->count - 1; i >= 0; i--)
|
||||
state = (state << 1) | gpio_get_value(ai->gpio[i]);
|
||||
pos = ai->map(ai, state);
|
||||
if (ai->flags & GPIOEAF_PRINT_RAW)
|
||||
pr_info("axis %d-%d raw %x, pos %d -> %d\n",
|
||||
ai->type, ai->code, state, old_pos, pos);
|
||||
if (report && pos != old_pos) {
|
||||
if (ai->type == EV_REL) {
|
||||
change = (ai->decoded_size + pos - old_pos) %
|
||||
ai->decoded_size;
|
||||
if (change > ai->decoded_size / 2)
|
||||
change -= ai->decoded_size;
|
||||
if (change == ai->decoded_size / 2) {
|
||||
if (ai->flags & GPIOEAF_PRINT_EVENT)
|
||||
pr_info("axis %d-%d unknown direction, "
|
||||
"pos %d -> %d\n", ai->type,
|
||||
ai->code, old_pos, pos);
|
||||
change = 0; /* no closest direction */
|
||||
}
|
||||
if (ai->flags & GPIOEAF_PRINT_EVENT)
|
||||
pr_info("axis %d-%d change %d\n",
|
||||
ai->type, ai->code, change);
|
||||
input_report_rel(as->input_devs->dev[ai->dev],
|
||||
ai->code, change);
|
||||
} else {
|
||||
if (ai->flags & GPIOEAF_PRINT_EVENT)
|
||||
pr_info("axis %d-%d now %d\n",
|
||||
ai->type, ai->code, pos);
|
||||
input_event(as->input_devs->dev[ai->dev],
|
||||
ai->type, ai->code, pos);
|
||||
}
|
||||
input_sync(as->input_devs->dev[ai->dev]);
|
||||
}
|
||||
as->pos = pos;
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_axis_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct gpio_axis_state *as = dev_id;
|
||||
gpio_event_update_axis(as, 1);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int gpio_event_axis_func(struct gpio_event_input_devs *input_devs,
|
||||
struct gpio_event_info *info, void **data, int func)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int irq;
|
||||
struct gpio_event_axis_info *ai;
|
||||
struct gpio_axis_state *as;
|
||||
|
||||
ai = container_of(info, struct gpio_event_axis_info, info);
|
||||
if (func == GPIO_EVENT_FUNC_SUSPEND) {
|
||||
for (i = 0; i < ai->count; i++)
|
||||
disable_irq(gpio_to_irq(ai->gpio[i]));
|
||||
return 0;
|
||||
}
|
||||
if (func == GPIO_EVENT_FUNC_RESUME) {
|
||||
for (i = 0; i < ai->count; i++)
|
||||
enable_irq(gpio_to_irq(ai->gpio[i]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (func == GPIO_EVENT_FUNC_INIT) {
|
||||
*data = as = kmalloc(sizeof(*as), GFP_KERNEL);
|
||||
if (as == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_axis_state_failed;
|
||||
}
|
||||
as->input_devs = input_devs;
|
||||
as->info = ai;
|
||||
if (ai->dev >= input_devs->count) {
|
||||
pr_err("gpio_event_axis: bad device index %d >= %d "
|
||||
"for %d:%d\n", ai->dev, input_devs->count,
|
||||
ai->type, ai->code);
|
||||
ret = -EINVAL;
|
||||
goto err_bad_device_index;
|
||||
}
|
||||
|
||||
input_set_capability(input_devs->dev[ai->dev],
|
||||
ai->type, ai->code);
|
||||
if (ai->type == EV_ABS) {
|
||||
input_set_abs_params(input_devs->dev[ai->dev], ai->code,
|
||||
0, ai->decoded_size - 1, 0, 0);
|
||||
}
|
||||
for (i = 0; i < ai->count; i++) {
|
||||
ret = gpio_request(ai->gpio[i], "gpio_event_axis");
|
||||
if (ret < 0)
|
||||
goto err_request_gpio_failed;
|
||||
ret = gpio_direction_input(ai->gpio[i]);
|
||||
if (ret < 0)
|
||||
goto err_gpio_direction_input_failed;
|
||||
ret = irq = gpio_to_irq(ai->gpio[i]);
|
||||
if (ret < 0)
|
||||
goto err_get_irq_num_failed;
|
||||
ret = request_irq(irq, gpio_axis_irq_handler,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
"gpio_event_axis", as);
|
||||
if (ret < 0)
|
||||
goto err_request_irq_failed;
|
||||
}
|
||||
gpio_event_update_axis(as, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
as = *data;
|
||||
for (i = ai->count - 1; i >= 0; i--) {
|
||||
free_irq(gpio_to_irq(ai->gpio[i]), as);
|
||||
err_request_irq_failed:
|
||||
err_get_irq_num_failed:
|
||||
err_gpio_direction_input_failed:
|
||||
gpio_free(ai->gpio[i]);
|
||||
err_request_gpio_failed:
|
||||
;
|
||||
}
|
||||
err_bad_device_index:
|
||||
kfree(as);
|
||||
*data = NULL;
|
||||
err_alloc_axis_state_failed:
|
||||
return ret;
|
||||
}
|
228
drivers/input/misc/gpio_event.c
Normal file
228
drivers/input/misc/gpio_event.c
Normal file
@ -0,0 +1,228 @@
|
||||
/* drivers/input/misc/gpio_event.c
|
||||
*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio_event.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct gpio_event {
|
||||
struct gpio_event_input_devs *input_devs;
|
||||
const struct gpio_event_platform_data *info;
|
||||
void *state[0];
|
||||
};
|
||||
|
||||
static int gpio_input_event(
|
||||
struct input_dev *dev, unsigned int type, unsigned int code, int value)
|
||||
{
|
||||
int i;
|
||||
int devnr;
|
||||
int ret = 0;
|
||||
int tmp_ret;
|
||||
struct gpio_event_info **ii;
|
||||
struct gpio_event *ip = input_get_drvdata(dev);
|
||||
|
||||
for (devnr = 0; devnr < ip->input_devs->count; devnr++)
|
||||
if (ip->input_devs->dev[devnr] == dev)
|
||||
break;
|
||||
if (devnr == ip->input_devs->count) {
|
||||
pr_err("gpio_input_event: unknown device %p\n", dev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
for (i = 0, ii = ip->info->info; i < ip->info->info_count; i++, ii++) {
|
||||
if ((*ii)->event) {
|
||||
tmp_ret = (*ii)->event(ip->input_devs, *ii,
|
||||
&ip->state[i],
|
||||
devnr, type, code, value);
|
||||
if (tmp_ret)
|
||||
ret = tmp_ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gpio_event_call_all_func(struct gpio_event *ip, int func)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct gpio_event_info **ii;
|
||||
|
||||
if (func == GPIO_EVENT_FUNC_INIT || func == GPIO_EVENT_FUNC_RESUME) {
|
||||
ii = ip->info->info;
|
||||
for (i = 0; i < ip->info->info_count; i++, ii++) {
|
||||
if ((*ii)->func == NULL) {
|
||||
ret = -ENODEV;
|
||||
pr_err("gpio_event_probe: Incomplete pdata, "
|
||||
"no function\n");
|
||||
goto err_no_func;
|
||||
}
|
||||
if (func == GPIO_EVENT_FUNC_RESUME && (*ii)->no_suspend)
|
||||
continue;
|
||||
ret = (*ii)->func(ip->input_devs, *ii, &ip->state[i],
|
||||
func);
|
||||
if (ret) {
|
||||
pr_err("gpio_event_probe: function failed\n");
|
||||
goto err_func_failed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
i = ip->info->info_count;
|
||||
ii = ip->info->info + i;
|
||||
while (i > 0) {
|
||||
i--;
|
||||
ii--;
|
||||
if ((func & ~1) == GPIO_EVENT_FUNC_SUSPEND && (*ii)->no_suspend)
|
||||
continue;
|
||||
(*ii)->func(ip->input_devs, *ii, &ip->state[i], func & ~1);
|
||||
err_func_failed:
|
||||
err_no_func:
|
||||
;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __maybe_unused gpio_event_suspend(struct gpio_event *ip)
|
||||
{
|
||||
gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_SUSPEND);
|
||||
if (ip->info->power)
|
||||
ip->info->power(ip->info, 0);
|
||||
}
|
||||
|
||||
static void __maybe_unused gpio_event_resume(struct gpio_event *ip)
|
||||
{
|
||||
if (ip->info->power)
|
||||
ip->info->power(ip->info, 1);
|
||||
gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_RESUME);
|
||||
}
|
||||
|
||||
static int gpio_event_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct gpio_event *ip;
|
||||
struct gpio_event_platform_data *event_info;
|
||||
int dev_count = 1;
|
||||
int i;
|
||||
int registered = 0;
|
||||
|
||||
event_info = pdev->dev.platform_data;
|
||||
if (event_info == NULL) {
|
||||
pr_err("gpio_event_probe: No pdata\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if ((!event_info->name && !event_info->names[0]) ||
|
||||
!event_info->info || !event_info->info_count) {
|
||||
pr_err("gpio_event_probe: Incomplete pdata\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!event_info->name)
|
||||
while (event_info->names[dev_count])
|
||||
dev_count++;
|
||||
ip = kzalloc(sizeof(*ip) +
|
||||
sizeof(ip->state[0]) * event_info->info_count +
|
||||
sizeof(*ip->input_devs) +
|
||||
sizeof(ip->input_devs->dev[0]) * dev_count, GFP_KERNEL);
|
||||
if (ip == NULL) {
|
||||
err = -ENOMEM;
|
||||
pr_err("gpio_event_probe: Failed to allocate private data\n");
|
||||
goto err_kp_alloc_failed;
|
||||
}
|
||||
ip->input_devs = (void*)&ip->state[event_info->info_count];
|
||||
platform_set_drvdata(pdev, ip);
|
||||
|
||||
for (i = 0; i < dev_count; i++) {
|
||||
struct input_dev *input_dev = input_allocate_device();
|
||||
if (input_dev == NULL) {
|
||||
err = -ENOMEM;
|
||||
pr_err("gpio_event_probe: "
|
||||
"Failed to allocate input device\n");
|
||||
goto err_input_dev_alloc_failed;
|
||||
}
|
||||
input_set_drvdata(input_dev, ip);
|
||||
input_dev->name = event_info->name ?
|
||||
event_info->name : event_info->names[i];
|
||||
input_dev->event = gpio_input_event;
|
||||
ip->input_devs->dev[i] = input_dev;
|
||||
}
|
||||
ip->input_devs->count = dev_count;
|
||||
ip->info = event_info;
|
||||
if (event_info->power)
|
||||
ip->info->power(ip->info, 1);
|
||||
|
||||
err = gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_INIT);
|
||||
if (err)
|
||||
goto err_call_all_func_failed;
|
||||
|
||||
for (i = 0; i < dev_count; i++) {
|
||||
err = input_register_device(ip->input_devs->dev[i]);
|
||||
if (err) {
|
||||
pr_err("gpio_event_probe: Unable to register %s "
|
||||
"input device\n", ip->input_devs->dev[i]->name);
|
||||
goto err_input_register_device_failed;
|
||||
}
|
||||
registered++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_input_register_device_failed:
|
||||
gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
|
||||
err_call_all_func_failed:
|
||||
if (event_info->power)
|
||||
ip->info->power(ip->info, 0);
|
||||
for (i = 0; i < registered; i++)
|
||||
input_unregister_device(ip->input_devs->dev[i]);
|
||||
for (i = dev_count - 1; i >= registered; i--) {
|
||||
input_free_device(ip->input_devs->dev[i]);
|
||||
err_input_dev_alloc_failed:
|
||||
;
|
||||
}
|
||||
kfree(ip);
|
||||
err_kp_alloc_failed:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int gpio_event_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_event *ip = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
gpio_event_call_all_func(ip, GPIO_EVENT_FUNC_UNINIT);
|
||||
if (ip->info->power)
|
||||
ip->info->power(ip->info, 0);
|
||||
for (i = 0; i < ip->input_devs->count; i++)
|
||||
input_unregister_device(ip->input_devs->dev[i]);
|
||||
kfree(ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver gpio_event_driver = {
|
||||
.probe = gpio_event_probe,
|
||||
.remove = gpio_event_remove,
|
||||
.driver = {
|
||||
.name = GPIO_EVENT_DEV_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(gpio_event_driver);
|
||||
|
||||
MODULE_DESCRIPTION("GPIO Event Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
390
drivers/input/misc/gpio_input.c
Normal file
390
drivers/input/misc/gpio_input.c
Normal file
@ -0,0 +1,390 @@
|
||||
/* drivers/input/misc/gpio_input.c
|
||||
*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_event.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_wakeup.h>
|
||||
|
||||
enum {
|
||||
DEBOUNCE_UNSTABLE = BIT(0), /* Got irq, while debouncing */
|
||||
DEBOUNCE_PRESSED = BIT(1),
|
||||
DEBOUNCE_NOTPRESSED = BIT(2),
|
||||
DEBOUNCE_WAIT_IRQ = BIT(3), /* Stable irq state */
|
||||
DEBOUNCE_POLL = BIT(4), /* Stable polling state */
|
||||
|
||||
DEBOUNCE_UNKNOWN =
|
||||
DEBOUNCE_PRESSED | DEBOUNCE_NOTPRESSED,
|
||||
};
|
||||
|
||||
struct gpio_key_state {
|
||||
struct gpio_input_state *ds;
|
||||
uint8_t debounce;
|
||||
};
|
||||
|
||||
struct gpio_input_state {
|
||||
struct gpio_event_input_devs *input_devs;
|
||||
const struct gpio_event_input_info *info;
|
||||
struct hrtimer timer;
|
||||
int use_irq;
|
||||
int debounce_count;
|
||||
spinlock_t irq_lock;
|
||||
struct wakeup_source *ws;
|
||||
struct gpio_key_state key_state[0];
|
||||
};
|
||||
|
||||
static enum hrtimer_restart gpio_event_input_timer_func(struct hrtimer *timer)
|
||||
{
|
||||
int i;
|
||||
int pressed;
|
||||
struct gpio_input_state *ds =
|
||||
container_of(timer, struct gpio_input_state, timer);
|
||||
unsigned gpio_flags = ds->info->flags;
|
||||
unsigned npolarity;
|
||||
int nkeys = ds->info->keymap_size;
|
||||
const struct gpio_event_direct_entry *key_entry;
|
||||
struct gpio_key_state *key_state;
|
||||
unsigned long irqflags;
|
||||
uint8_t debounce;
|
||||
bool sync_needed;
|
||||
|
||||
#if 0
|
||||
key_entry = kp->keys_info->keymap;
|
||||
key_state = kp->key_state;
|
||||
for (i = 0; i < nkeys; i++, key_entry++, key_state++)
|
||||
pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio,
|
||||
gpio_read_detect_status(key_entry->gpio));
|
||||
#endif
|
||||
key_entry = ds->info->keymap;
|
||||
key_state = ds->key_state;
|
||||
sync_needed = false;
|
||||
spin_lock_irqsave(&ds->irq_lock, irqflags);
|
||||
for (i = 0; i < nkeys; i++, key_entry++, key_state++) {
|
||||
debounce = key_state->debounce;
|
||||
if (debounce & DEBOUNCE_WAIT_IRQ)
|
||||
continue;
|
||||
if (key_state->debounce & DEBOUNCE_UNSTABLE) {
|
||||
debounce = key_state->debounce = DEBOUNCE_UNKNOWN;
|
||||
enable_irq(gpio_to_irq(key_entry->gpio));
|
||||
if (gpio_flags & GPIOEDF_PRINT_KEY_UNSTABLE)
|
||||
pr_info("gpio_keys_scan_keys: key %x-%x, %d "
|
||||
"(%d) continue debounce\n",
|
||||
ds->info->type, key_entry->code,
|
||||
i, key_entry->gpio);
|
||||
}
|
||||
npolarity = !(gpio_flags & GPIOEDF_ACTIVE_HIGH);
|
||||
pressed = gpio_get_value(key_entry->gpio) ^ npolarity;
|
||||
if (debounce & DEBOUNCE_POLL) {
|
||||
if (pressed == !(debounce & DEBOUNCE_PRESSED)) {
|
||||
ds->debounce_count++;
|
||||
key_state->debounce = DEBOUNCE_UNKNOWN;
|
||||
if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
|
||||
pr_info("gpio_keys_scan_keys: key %x-"
|
||||
"%x, %d (%d) start debounce\n",
|
||||
ds->info->type, key_entry->code,
|
||||
i, key_entry->gpio);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (pressed && (debounce & DEBOUNCE_NOTPRESSED)) {
|
||||
if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
|
||||
pr_info("gpio_keys_scan_keys: key %x-%x, %d "
|
||||
"(%d) debounce pressed 1\n",
|
||||
ds->info->type, key_entry->code,
|
||||
i, key_entry->gpio);
|
||||
key_state->debounce = DEBOUNCE_PRESSED;
|
||||
continue;
|
||||
}
|
||||
if (!pressed && (debounce & DEBOUNCE_PRESSED)) {
|
||||
if (gpio_flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
|
||||
pr_info("gpio_keys_scan_keys: key %x-%x, %d "
|
||||
"(%d) debounce pressed 0\n",
|
||||
ds->info->type, key_entry->code,
|
||||
i, key_entry->gpio);
|
||||
key_state->debounce = DEBOUNCE_NOTPRESSED;
|
||||
continue;
|
||||
}
|
||||
/* key is stable */
|
||||
ds->debounce_count--;
|
||||
if (ds->use_irq)
|
||||
key_state->debounce |= DEBOUNCE_WAIT_IRQ;
|
||||
else
|
||||
key_state->debounce |= DEBOUNCE_POLL;
|
||||
if (gpio_flags & GPIOEDF_PRINT_KEYS)
|
||||
pr_info("gpio_keys_scan_keys: key %x-%x, %d (%d) "
|
||||
"changed to %d\n", ds->info->type,
|
||||
key_entry->code, i, key_entry->gpio, pressed);
|
||||
input_event(ds->input_devs->dev[key_entry->dev], ds->info->type,
|
||||
key_entry->code, pressed);
|
||||
sync_needed = true;
|
||||
}
|
||||
if (sync_needed) {
|
||||
for (i = 0; i < ds->input_devs->count; i++)
|
||||
input_sync(ds->input_devs->dev[i]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
key_entry = kp->keys_info->keymap;
|
||||
key_state = kp->key_state;
|
||||
for (i = 0; i < nkeys; i++, key_entry++, key_state++) {
|
||||
pr_info("gpio_read_detect_status %d %d\n", key_entry->gpio,
|
||||
gpio_read_detect_status(key_entry->gpio));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ds->debounce_count)
|
||||
hrtimer_start(timer, ds->info->debounce_time, HRTIMER_MODE_REL);
|
||||
else if (!ds->use_irq)
|
||||
hrtimer_start(timer, ds->info->poll_time, HRTIMER_MODE_REL);
|
||||
else
|
||||
__pm_relax(ds->ws);
|
||||
|
||||
spin_unlock_irqrestore(&ds->irq_lock, irqflags);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_event_input_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct gpio_key_state *ks = dev_id;
|
||||
struct gpio_input_state *ds = ks->ds;
|
||||
int keymap_index = ks - ds->key_state;
|
||||
const struct gpio_event_direct_entry *key_entry;
|
||||
unsigned long irqflags;
|
||||
int pressed;
|
||||
|
||||
if (!ds->use_irq)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
key_entry = &ds->info->keymap[keymap_index];
|
||||
|
||||
if (ds->info->debounce_time) {
|
||||
spin_lock_irqsave(&ds->irq_lock, irqflags);
|
||||
if (ks->debounce & DEBOUNCE_WAIT_IRQ) {
|
||||
ks->debounce = DEBOUNCE_UNKNOWN;
|
||||
if (ds->debounce_count++ == 0) {
|
||||
__pm_stay_awake(ds->ws);
|
||||
hrtimer_start(
|
||||
&ds->timer, ds->info->debounce_time,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
if (ds->info->flags & GPIOEDF_PRINT_KEY_DEBOUNCE)
|
||||
pr_info("gpio_event_input_irq_handler: "
|
||||
"key %x-%x, %d (%d) start debounce\n",
|
||||
ds->info->type, key_entry->code,
|
||||
keymap_index, key_entry->gpio);
|
||||
} else {
|
||||
disable_irq_nosync(irq);
|
||||
ks->debounce = DEBOUNCE_UNSTABLE;
|
||||
}
|
||||
spin_unlock_irqrestore(&ds->irq_lock, irqflags);
|
||||
} else {
|
||||
pressed = gpio_get_value(key_entry->gpio) ^
|
||||
!(ds->info->flags & GPIOEDF_ACTIVE_HIGH);
|
||||
if (ds->info->flags & GPIOEDF_PRINT_KEYS)
|
||||
pr_info("gpio_event_input_irq_handler: key %x-%x, %d "
|
||||
"(%d) changed to %d\n",
|
||||
ds->info->type, key_entry->code, keymap_index,
|
||||
key_entry->gpio, pressed);
|
||||
input_event(ds->input_devs->dev[key_entry->dev], ds->info->type,
|
||||
key_entry->code, pressed);
|
||||
input_sync(ds->input_devs->dev[key_entry->dev]);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int gpio_event_input_request_irqs(struct gpio_input_state *ds)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
unsigned int irq;
|
||||
unsigned long req_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
|
||||
|
||||
for (i = 0; i < ds->info->keymap_size; i++) {
|
||||
err = irq = gpio_to_irq(ds->info->keymap[i].gpio);
|
||||
if (err < 0)
|
||||
goto err_gpio_get_irq_num_failed;
|
||||
err = request_irq(irq, gpio_event_input_irq_handler,
|
||||
req_flags, "gpio_keys", &ds->key_state[i]);
|
||||
if (err) {
|
||||
pr_err("gpio_event_input_request_irqs: request_irq "
|
||||
"failed for input %d, irq %d\n",
|
||||
ds->info->keymap[i].gpio, irq);
|
||||
goto err_request_irq_failed;
|
||||
}
|
||||
if (ds->info->info.no_suspend) {
|
||||
err = enable_irq_wake(irq);
|
||||
if (err) {
|
||||
pr_err("gpio_event_input_request_irqs: "
|
||||
"enable_irq_wake failed for input %d, "
|
||||
"irq %d\n",
|
||||
ds->info->keymap[i].gpio, irq);
|
||||
goto err_enable_irq_wake_failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
for (i = ds->info->keymap_size - 1; i >= 0; i--) {
|
||||
irq = gpio_to_irq(ds->info->keymap[i].gpio);
|
||||
if (ds->info->info.no_suspend)
|
||||
disable_irq_wake(irq);
|
||||
err_enable_irq_wake_failed:
|
||||
free_irq(irq, &ds->key_state[i]);
|
||||
err_request_irq_failed:
|
||||
err_gpio_get_irq_num_failed:
|
||||
;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int gpio_event_input_func(struct gpio_event_input_devs *input_devs,
|
||||
struct gpio_event_info *info, void **data, int func)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
unsigned long irqflags;
|
||||
struct gpio_event_input_info *di;
|
||||
struct gpio_input_state *ds = *data;
|
||||
char *wlname;
|
||||
|
||||
di = container_of(info, struct gpio_event_input_info, info);
|
||||
|
||||
if (func == GPIO_EVENT_FUNC_SUSPEND) {
|
||||
if (ds->use_irq)
|
||||
for (i = 0; i < di->keymap_size; i++)
|
||||
disable_irq(gpio_to_irq(di->keymap[i].gpio));
|
||||
hrtimer_cancel(&ds->timer);
|
||||
return 0;
|
||||
}
|
||||
if (func == GPIO_EVENT_FUNC_RESUME) {
|
||||
spin_lock_irqsave(&ds->irq_lock, irqflags);
|
||||
if (ds->use_irq)
|
||||
for (i = 0; i < di->keymap_size; i++)
|
||||
enable_irq(gpio_to_irq(di->keymap[i].gpio));
|
||||
hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
|
||||
spin_unlock_irqrestore(&ds->irq_lock, irqflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (func == GPIO_EVENT_FUNC_INIT) {
|
||||
if (ktime_to_ns(di->poll_time) <= 0)
|
||||
di->poll_time = ktime_set(0, 20 * NSEC_PER_MSEC);
|
||||
|
||||
*data = ds = kzalloc(sizeof(*ds) + sizeof(ds->key_state[0]) *
|
||||
di->keymap_size, GFP_KERNEL);
|
||||
if (ds == NULL) {
|
||||
ret = -ENOMEM;
|
||||
pr_err("gpio_event_input_func: "
|
||||
"Failed to allocate private data\n");
|
||||
goto err_ds_alloc_failed;
|
||||
}
|
||||
ds->debounce_count = di->keymap_size;
|
||||
ds->input_devs = input_devs;
|
||||
ds->info = di;
|
||||
wlname = kasprintf(GFP_KERNEL, "gpio_input:%s%s",
|
||||
input_devs->dev[0]->name,
|
||||
(input_devs->count > 1) ? "..." : "");
|
||||
|
||||
ds->ws = wakeup_source_register(wlname);
|
||||
kfree(wlname);
|
||||
if (!ds->ws) {
|
||||
ret = -ENOMEM;
|
||||
pr_err("gpio_event_input_func: "
|
||||
"Failed to allocate wakeup source\n");
|
||||
goto err_ws_failed;
|
||||
}
|
||||
|
||||
spin_lock_init(&ds->irq_lock);
|
||||
|
||||
for (i = 0; i < di->keymap_size; i++) {
|
||||
int dev = di->keymap[i].dev;
|
||||
if (dev >= input_devs->count) {
|
||||
pr_err("gpio_event_input_func: bad device "
|
||||
"index %d >= %d for key code %d\n",
|
||||
dev, input_devs->count,
|
||||
di->keymap[i].code);
|
||||
ret = -EINVAL;
|
||||
goto err_bad_keymap;
|
||||
}
|
||||
input_set_capability(input_devs->dev[dev], di->type,
|
||||
di->keymap[i].code);
|
||||
ds->key_state[i].ds = ds;
|
||||
ds->key_state[i].debounce = DEBOUNCE_UNKNOWN;
|
||||
}
|
||||
|
||||
for (i = 0; i < di->keymap_size; i++) {
|
||||
ret = gpio_request(di->keymap[i].gpio, "gpio_kp_in");
|
||||
if (ret) {
|
||||
pr_err("gpio_event_input_func: gpio_request "
|
||||
"failed for %d\n", di->keymap[i].gpio);
|
||||
goto err_gpio_request_failed;
|
||||
}
|
||||
ret = gpio_direction_input(di->keymap[i].gpio);
|
||||
if (ret) {
|
||||
pr_err("gpio_event_input_func: "
|
||||
"gpio_direction_input failed for %d\n",
|
||||
di->keymap[i].gpio);
|
||||
goto err_gpio_configure_failed;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpio_event_input_request_irqs(ds);
|
||||
|
||||
spin_lock_irqsave(&ds->irq_lock, irqflags);
|
||||
ds->use_irq = ret == 0;
|
||||
|
||||
pr_info("GPIO Input Driver: Start gpio inputs for %s%s in %s "
|
||||
"mode\n", input_devs->dev[0]->name,
|
||||
(input_devs->count > 1) ? "..." : "",
|
||||
ret == 0 ? "interrupt" : "polling");
|
||||
|
||||
hrtimer_init(&ds->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
ds->timer.function = gpio_event_input_timer_func;
|
||||
hrtimer_start(&ds->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
|
||||
spin_unlock_irqrestore(&ds->irq_lock, irqflags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
spin_lock_irqsave(&ds->irq_lock, irqflags);
|
||||
hrtimer_cancel(&ds->timer);
|
||||
if (ds->use_irq) {
|
||||
for (i = di->keymap_size - 1; i >= 0; i--) {
|
||||
int irq = gpio_to_irq(di->keymap[i].gpio);
|
||||
if (ds->info->info.no_suspend)
|
||||
disable_irq_wake(irq);
|
||||
free_irq(irq, &ds->key_state[i]);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&ds->irq_lock, irqflags);
|
||||
|
||||
for (i = di->keymap_size - 1; i >= 0; i--) {
|
||||
err_gpio_configure_failed:
|
||||
gpio_free(di->keymap[i].gpio);
|
||||
err_gpio_request_failed:
|
||||
;
|
||||
}
|
||||
err_bad_keymap:
|
||||
wakeup_source_unregister(ds->ws);
|
||||
err_ws_failed:
|
||||
kfree(ds);
|
||||
err_ds_alloc_failed:
|
||||
return ret;
|
||||
}
|
440
drivers/input/misc/gpio_matrix.c
Normal file
440
drivers/input/misc/gpio_matrix.c
Normal file
@ -0,0 +1,440 @@
|
||||
/* drivers/input/misc/gpio_matrix.c
|
||||
*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_event.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct gpio_kp {
|
||||
struct gpio_event_input_devs *input_devs;
|
||||
struct gpio_event_matrix_info *keypad_info;
|
||||
struct hrtimer timer;
|
||||
struct wakeup_source wake_src;
|
||||
int current_output;
|
||||
unsigned int use_irq:1;
|
||||
unsigned int key_state_changed:1;
|
||||
unsigned int last_key_state_changed:1;
|
||||
unsigned int some_keys_pressed:2;
|
||||
unsigned int disabled_irq:1;
|
||||
unsigned long keys_pressed[0];
|
||||
};
|
||||
|
||||
static void clear_phantom_key(struct gpio_kp *kp, int out, int in)
|
||||
{
|
||||
struct gpio_event_matrix_info *mi = kp->keypad_info;
|
||||
int key_index = out * mi->ninputs + in;
|
||||
unsigned short keyentry = mi->keymap[key_index];
|
||||
unsigned short keycode = keyentry & MATRIX_KEY_MASK;
|
||||
unsigned short dev = keyentry >> MATRIX_CODE_BITS;
|
||||
|
||||
if (!test_bit(keycode, kp->input_devs->dev[dev]->key)) {
|
||||
if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
|
||||
pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
|
||||
"cleared\n", keycode, out, in,
|
||||
mi->output_gpios[out], mi->input_gpios[in]);
|
||||
__clear_bit(key_index, kp->keys_pressed);
|
||||
} else {
|
||||
if (mi->flags & GPIOKPF_PRINT_PHANTOM_KEYS)
|
||||
pr_info("gpiomatrix: phantom key %x, %d-%d (%d-%d) "
|
||||
"not cleared\n", keycode, out, in,
|
||||
mi->output_gpios[out], mi->input_gpios[in]);
|
||||
}
|
||||
}
|
||||
|
||||
static int restore_keys_for_input(struct gpio_kp *kp, int out, int in)
|
||||
{
|
||||
int rv = 0;
|
||||
int key_index;
|
||||
|
||||
key_index = out * kp->keypad_info->ninputs + in;
|
||||
while (out < kp->keypad_info->noutputs) {
|
||||
if (test_bit(key_index, kp->keys_pressed)) {
|
||||
rv = 1;
|
||||
clear_phantom_key(kp, out, in);
|
||||
}
|
||||
key_index += kp->keypad_info->ninputs;
|
||||
out++;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void remove_phantom_keys(struct gpio_kp *kp)
|
||||
{
|
||||
int out, in, inp;
|
||||
int key_index;
|
||||
|
||||
if (kp->some_keys_pressed < 3)
|
||||
return;
|
||||
|
||||
for (out = 0; out < kp->keypad_info->noutputs; out++) {
|
||||
inp = -1;
|
||||
key_index = out * kp->keypad_info->ninputs;
|
||||
for (in = 0; in < kp->keypad_info->ninputs; in++, key_index++) {
|
||||
if (test_bit(key_index, kp->keys_pressed)) {
|
||||
if (inp == -1) {
|
||||
inp = in;
|
||||
continue;
|
||||
}
|
||||
if (inp >= 0) {
|
||||
if (!restore_keys_for_input(kp, out + 1,
|
||||
inp))
|
||||
break;
|
||||
clear_phantom_key(kp, out, inp);
|
||||
inp = -2;
|
||||
}
|
||||
restore_keys_for_input(kp, out, in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void report_key(struct gpio_kp *kp, int key_index, int out, int in)
|
||||
{
|
||||
struct gpio_event_matrix_info *mi = kp->keypad_info;
|
||||
int pressed = test_bit(key_index, kp->keys_pressed);
|
||||
unsigned short keyentry = mi->keymap[key_index];
|
||||
unsigned short keycode = keyentry & MATRIX_KEY_MASK;
|
||||
unsigned short dev = keyentry >> MATRIX_CODE_BITS;
|
||||
|
||||
if (pressed != test_bit(keycode, kp->input_devs->dev[dev]->key)) {
|
||||
if (keycode == KEY_RESERVED) {
|
||||
if (mi->flags & GPIOKPF_PRINT_UNMAPPED_KEYS)
|
||||
pr_info("gpiomatrix: unmapped key, %d-%d "
|
||||
"(%d-%d) changed to %d\n",
|
||||
out, in, mi->output_gpios[out],
|
||||
mi->input_gpios[in], pressed);
|
||||
} else {
|
||||
if (mi->flags & GPIOKPF_PRINT_MAPPED_KEYS)
|
||||
pr_info("gpiomatrix: key %x, %d-%d (%d-%d) "
|
||||
"changed to %d\n", keycode,
|
||||
out, in, mi->output_gpios[out],
|
||||
mi->input_gpios[in], pressed);
|
||||
input_report_key(kp->input_devs->dev[dev], keycode, pressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void report_sync(struct gpio_kp *kp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < kp->input_devs->count; i++)
|
||||
input_sync(kp->input_devs->dev[i]);
|
||||
}
|
||||
|
||||
static enum hrtimer_restart gpio_keypad_timer_func(struct hrtimer *timer)
|
||||
{
|
||||
int out, in;
|
||||
int key_index;
|
||||
int gpio;
|
||||
struct gpio_kp *kp = container_of(timer, struct gpio_kp, timer);
|
||||
struct gpio_event_matrix_info *mi = kp->keypad_info;
|
||||
unsigned gpio_keypad_flags = mi->flags;
|
||||
unsigned polarity = !!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH);
|
||||
|
||||
out = kp->current_output;
|
||||
if (out == mi->noutputs) {
|
||||
out = 0;
|
||||
kp->last_key_state_changed = kp->key_state_changed;
|
||||
kp->key_state_changed = 0;
|
||||
kp->some_keys_pressed = 0;
|
||||
} else {
|
||||
key_index = out * mi->ninputs;
|
||||
for (in = 0; in < mi->ninputs; in++, key_index++) {
|
||||
gpio = mi->input_gpios[in];
|
||||
if (gpio_get_value(gpio) ^ !polarity) {
|
||||
if (kp->some_keys_pressed < 3)
|
||||
kp->some_keys_pressed++;
|
||||
kp->key_state_changed |= !__test_and_set_bit(
|
||||
key_index, kp->keys_pressed);
|
||||
} else
|
||||
kp->key_state_changed |= __test_and_clear_bit(
|
||||
key_index, kp->keys_pressed);
|
||||
}
|
||||
gpio = mi->output_gpios[out];
|
||||
if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
|
||||
gpio_set_value(gpio, !polarity);
|
||||
else
|
||||
gpio_direction_input(gpio);
|
||||
out++;
|
||||
}
|
||||
kp->current_output = out;
|
||||
if (out < mi->noutputs) {
|
||||
gpio = mi->output_gpios[out];
|
||||
if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
|
||||
gpio_set_value(gpio, polarity);
|
||||
else
|
||||
gpio_direction_output(gpio, polarity);
|
||||
hrtimer_start(timer, mi->settle_time, HRTIMER_MODE_REL);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
if (gpio_keypad_flags & GPIOKPF_DEBOUNCE) {
|
||||
if (kp->key_state_changed) {
|
||||
hrtimer_start(&kp->timer, mi->debounce_delay,
|
||||
HRTIMER_MODE_REL);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
kp->key_state_changed = kp->last_key_state_changed;
|
||||
}
|
||||
if (kp->key_state_changed) {
|
||||
if (gpio_keypad_flags & GPIOKPF_REMOVE_SOME_PHANTOM_KEYS)
|
||||
remove_phantom_keys(kp);
|
||||
key_index = 0;
|
||||
for (out = 0; out < mi->noutputs; out++)
|
||||
for (in = 0; in < mi->ninputs; in++, key_index++)
|
||||
report_key(kp, key_index, out, in);
|
||||
report_sync(kp);
|
||||
}
|
||||
if (!kp->use_irq || kp->some_keys_pressed) {
|
||||
hrtimer_start(timer, mi->poll_time, HRTIMER_MODE_REL);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
/* No keys are pressed, reenable interrupt */
|
||||
for (out = 0; out < mi->noutputs; out++) {
|
||||
if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
|
||||
gpio_set_value(mi->output_gpios[out], polarity);
|
||||
else
|
||||
gpio_direction_output(mi->output_gpios[out], polarity);
|
||||
}
|
||||
for (in = 0; in < mi->ninputs; in++)
|
||||
enable_irq(gpio_to_irq(mi->input_gpios[in]));
|
||||
__pm_relax(&kp->wake_src);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static irqreturn_t gpio_keypad_irq_handler(int irq_in, void *dev_id)
|
||||
{
|
||||
int i;
|
||||
struct gpio_kp *kp = dev_id;
|
||||
struct gpio_event_matrix_info *mi = kp->keypad_info;
|
||||
unsigned gpio_keypad_flags = mi->flags;
|
||||
|
||||
if (!kp->use_irq) {
|
||||
/* ignore interrupt while registering the handler */
|
||||
kp->disabled_irq = 1;
|
||||
disable_irq_nosync(irq_in);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
for (i = 0; i < mi->ninputs; i++)
|
||||
disable_irq_nosync(gpio_to_irq(mi->input_gpios[i]));
|
||||
for (i = 0; i < mi->noutputs; i++) {
|
||||
if (gpio_keypad_flags & GPIOKPF_DRIVE_INACTIVE)
|
||||
gpio_set_value(mi->output_gpios[i],
|
||||
!(gpio_keypad_flags & GPIOKPF_ACTIVE_HIGH));
|
||||
else
|
||||
gpio_direction_input(mi->output_gpios[i]);
|
||||
}
|
||||
__pm_stay_awake(&kp->wake_src);
|
||||
hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int gpio_keypad_request_irqs(struct gpio_kp *kp)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
unsigned int irq;
|
||||
unsigned long request_flags;
|
||||
struct gpio_event_matrix_info *mi = kp->keypad_info;
|
||||
|
||||
switch (mi->flags & (GPIOKPF_ACTIVE_HIGH|GPIOKPF_LEVEL_TRIGGERED_IRQ)) {
|
||||
default:
|
||||
request_flags = IRQF_TRIGGER_FALLING;
|
||||
break;
|
||||
case GPIOKPF_ACTIVE_HIGH:
|
||||
request_flags = IRQF_TRIGGER_RISING;
|
||||
break;
|
||||
case GPIOKPF_LEVEL_TRIGGERED_IRQ:
|
||||
request_flags = IRQF_TRIGGER_LOW;
|
||||
break;
|
||||
case GPIOKPF_LEVEL_TRIGGERED_IRQ | GPIOKPF_ACTIVE_HIGH:
|
||||
request_flags = IRQF_TRIGGER_HIGH;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < mi->ninputs; i++) {
|
||||
err = irq = gpio_to_irq(mi->input_gpios[i]);
|
||||
if (err < 0)
|
||||
goto err_gpio_get_irq_num_failed;
|
||||
err = request_irq(irq, gpio_keypad_irq_handler, request_flags,
|
||||
"gpio_kp", kp);
|
||||
if (err) {
|
||||
pr_err("gpiomatrix: request_irq failed for input %d, "
|
||||
"irq %d\n", mi->input_gpios[i], irq);
|
||||
goto err_request_irq_failed;
|
||||
}
|
||||
err = enable_irq_wake(irq);
|
||||
if (err) {
|
||||
pr_err("gpiomatrix: set_irq_wake failed for input %d, "
|
||||
"irq %d\n", mi->input_gpios[i], irq);
|
||||
}
|
||||
disable_irq(irq);
|
||||
if (kp->disabled_irq) {
|
||||
kp->disabled_irq = 0;
|
||||
enable_irq(irq);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
for (i = mi->noutputs - 1; i >= 0; i--) {
|
||||
free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
|
||||
err_request_irq_failed:
|
||||
err_gpio_get_irq_num_failed:
|
||||
;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int gpio_event_matrix_func(struct gpio_event_input_devs *input_devs,
|
||||
struct gpio_event_info *info, void **data, int func)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
int key_count;
|
||||
struct gpio_kp *kp;
|
||||
struct gpio_event_matrix_info *mi;
|
||||
|
||||
mi = container_of(info, struct gpio_event_matrix_info, info);
|
||||
if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) {
|
||||
/* TODO: disable scanning */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (func == GPIO_EVENT_FUNC_INIT) {
|
||||
if (mi->keymap == NULL ||
|
||||
mi->input_gpios == NULL ||
|
||||
mi->output_gpios == NULL) {
|
||||
err = -ENODEV;
|
||||
pr_err("gpiomatrix: Incomplete pdata\n");
|
||||
goto err_invalid_platform_data;
|
||||
}
|
||||
key_count = mi->ninputs * mi->noutputs;
|
||||
|
||||
*data = kp = kzalloc(sizeof(*kp) + sizeof(kp->keys_pressed[0]) *
|
||||
BITS_TO_LONGS(key_count), GFP_KERNEL);
|
||||
if (kp == NULL) {
|
||||
err = -ENOMEM;
|
||||
pr_err("gpiomatrix: Failed to allocate private data\n");
|
||||
goto err_kp_alloc_failed;
|
||||
}
|
||||
kp->input_devs = input_devs;
|
||||
kp->keypad_info = mi;
|
||||
for (i = 0; i < key_count; i++) {
|
||||
unsigned short keyentry = mi->keymap[i];
|
||||
unsigned short keycode = keyentry & MATRIX_KEY_MASK;
|
||||
unsigned short dev = keyentry >> MATRIX_CODE_BITS;
|
||||
if (dev >= input_devs->count) {
|
||||
pr_err("gpiomatrix: bad device index %d >= "
|
||||
"%d for key code %d\n",
|
||||
dev, input_devs->count, keycode);
|
||||
err = -EINVAL;
|
||||
goto err_bad_keymap;
|
||||
}
|
||||
if (keycode && keycode <= KEY_MAX)
|
||||
input_set_capability(input_devs->dev[dev],
|
||||
EV_KEY, keycode);
|
||||
}
|
||||
|
||||
for (i = 0; i < mi->noutputs; i++) {
|
||||
err = gpio_request(mi->output_gpios[i], "gpio_kp_out");
|
||||
if (err) {
|
||||
pr_err("gpiomatrix: gpio_request failed for "
|
||||
"output %d\n", mi->output_gpios[i]);
|
||||
goto err_request_output_gpio_failed;
|
||||
}
|
||||
if (gpio_cansleep(mi->output_gpios[i])) {
|
||||
pr_err("gpiomatrix: unsupported output gpio %d,"
|
||||
" can sleep\n", mi->output_gpios[i]);
|
||||
err = -EINVAL;
|
||||
goto err_output_gpio_configure_failed;
|
||||
}
|
||||
if (mi->flags & GPIOKPF_DRIVE_INACTIVE)
|
||||
err = gpio_direction_output(mi->output_gpios[i],
|
||||
!(mi->flags & GPIOKPF_ACTIVE_HIGH));
|
||||
else
|
||||
err = gpio_direction_input(mi->output_gpios[i]);
|
||||
if (err) {
|
||||
pr_err("gpiomatrix: gpio_configure failed for "
|
||||
"output %d\n", mi->output_gpios[i]);
|
||||
goto err_output_gpio_configure_failed;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < mi->ninputs; i++) {
|
||||
err = gpio_request(mi->input_gpios[i], "gpio_kp_in");
|
||||
if (err) {
|
||||
pr_err("gpiomatrix: gpio_request failed for "
|
||||
"input %d\n", mi->input_gpios[i]);
|
||||
goto err_request_input_gpio_failed;
|
||||
}
|
||||
err = gpio_direction_input(mi->input_gpios[i]);
|
||||
if (err) {
|
||||
pr_err("gpiomatrix: gpio_direction_input failed"
|
||||
" for input %d\n", mi->input_gpios[i]);
|
||||
goto err_gpio_direction_input_failed;
|
||||
}
|
||||
}
|
||||
kp->current_output = mi->noutputs;
|
||||
kp->key_state_changed = 1;
|
||||
|
||||
hrtimer_init(&kp->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
kp->timer.function = gpio_keypad_timer_func;
|
||||
wakeup_source_init(&kp->wake_src, "gpio_kp");
|
||||
err = gpio_keypad_request_irqs(kp);
|
||||
kp->use_irq = err == 0;
|
||||
|
||||
pr_info("GPIO Matrix Keypad Driver: Start keypad matrix for "
|
||||
"%s%s in %s mode\n", input_devs->dev[0]->name,
|
||||
(input_devs->count > 1) ? "..." : "",
|
||||
kp->use_irq ? "interrupt" : "polling");
|
||||
|
||||
if (kp->use_irq)
|
||||
__pm_stay_awake(&kp->wake_src);
|
||||
hrtimer_start(&kp->timer, ktime_set(0, 0), HRTIMER_MODE_REL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
kp = *data;
|
||||
|
||||
if (kp->use_irq)
|
||||
for (i = mi->noutputs - 1; i >= 0; i--)
|
||||
free_irq(gpio_to_irq(mi->input_gpios[i]), kp);
|
||||
|
||||
hrtimer_cancel(&kp->timer);
|
||||
wakeup_source_trash(&kp->wake_src);
|
||||
for (i = mi->noutputs - 1; i >= 0; i--) {
|
||||
err_gpio_direction_input_failed:
|
||||
gpio_free(mi->input_gpios[i]);
|
||||
err_request_input_gpio_failed:
|
||||
;
|
||||
}
|
||||
for (i = mi->noutputs - 1; i >= 0; i--) {
|
||||
err_output_gpio_configure_failed:
|
||||
gpio_free(mi->output_gpios[i]);
|
||||
err_request_output_gpio_failed:
|
||||
;
|
||||
}
|
||||
err_bad_keymap:
|
||||
kfree(kp);
|
||||
err_kp_alloc_failed:
|
||||
err_invalid_platform_data:
|
||||
return err;
|
||||
}
|
97
drivers/input/misc/gpio_output.c
Normal file
97
drivers/input/misc/gpio_output.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* drivers/input/misc/gpio_output.c
|
||||
*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio_event.h>
|
||||
|
||||
int gpio_event_output_event(
|
||||
struct gpio_event_input_devs *input_devs, struct gpio_event_info *info,
|
||||
void **data, unsigned int dev, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
int i;
|
||||
struct gpio_event_output_info *oi;
|
||||
oi = container_of(info, struct gpio_event_output_info, info);
|
||||
if (type != oi->type)
|
||||
return 0;
|
||||
if (!(oi->flags & GPIOEDF_ACTIVE_HIGH))
|
||||
value = !value;
|
||||
for (i = 0; i < oi->keymap_size; i++)
|
||||
if (dev == oi->keymap[i].dev && code == oi->keymap[i].code)
|
||||
gpio_set_value(oi->keymap[i].gpio, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_event_output_func(
|
||||
struct gpio_event_input_devs *input_devs, struct gpio_event_info *info,
|
||||
void **data, int func)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct gpio_event_output_info *oi;
|
||||
oi = container_of(info, struct gpio_event_output_info, info);
|
||||
|
||||
if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME)
|
||||
return 0;
|
||||
|
||||
if (func == GPIO_EVENT_FUNC_INIT) {
|
||||
int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH);
|
||||
|
||||
for (i = 0; i < oi->keymap_size; i++) {
|
||||
int dev = oi->keymap[i].dev;
|
||||
if (dev >= input_devs->count) {
|
||||
pr_err("gpio_event_output_func: bad device "
|
||||
"index %d >= %d for key code %d\n",
|
||||
dev, input_devs->count,
|
||||
oi->keymap[i].code);
|
||||
ret = -EINVAL;
|
||||
goto err_bad_keymap;
|
||||
}
|
||||
input_set_capability(input_devs->dev[dev], oi->type,
|
||||
oi->keymap[i].code);
|
||||
}
|
||||
|
||||
for (i = 0; i < oi->keymap_size; i++) {
|
||||
ret = gpio_request(oi->keymap[i].gpio,
|
||||
"gpio_event_output");
|
||||
if (ret) {
|
||||
pr_err("gpio_event_output_func: gpio_request "
|
||||
"failed for %d\n", oi->keymap[i].gpio);
|
||||
goto err_gpio_request_failed;
|
||||
}
|
||||
ret = gpio_direction_output(oi->keymap[i].gpio,
|
||||
output_level);
|
||||
if (ret) {
|
||||
pr_err("gpio_event_output_func: "
|
||||
"gpio_direction_output failed for %d\n",
|
||||
oi->keymap[i].gpio);
|
||||
goto err_gpio_direction_output_failed;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
for (i = oi->keymap_size - 1; i >= 0; i--) {
|
||||
err_gpio_direction_output_failed:
|
||||
gpio_free(oi->keymap[i].gpio);
|
||||
err_gpio_request_failed:
|
||||
;
|
||||
}
|
||||
err_bad_keymap:
|
||||
return ret;
|
||||
}
|
||||
|
@ -479,6 +479,21 @@ config DM_VERITY
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config DM_VERITY_HASH_PREFETCH_MIN_SIZE_128
|
||||
bool "Prefetch size 128"
|
||||
|
||||
config DM_VERITY_HASH_PREFETCH_MIN_SIZE
|
||||
int "Verity hash prefetch minimum size"
|
||||
depends on DM_VERITY
|
||||
range 1 4096
|
||||
default 128 if DM_VERITY_HASH_PREFETCH_MIN_SIZE_128
|
||||
default 1
|
||||
---help---
|
||||
This sets minimum number of hash blocks to prefetch for dm-verity.
|
||||
For devices like eMMC, having larger prefetch size like 128 can improve
|
||||
performance with increased memory consumption for keeping more hashes
|
||||
in RAM.
|
||||
|
||||
config DM_VERITY_FEC
|
||||
bool "Verity forward error correction support"
|
||||
depends on DM_VERITY
|
||||
@ -559,4 +574,51 @@ config DM_ZONED
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config DM_VERITY_AVB
|
||||
tristate "Support AVB specific verity error behavior"
|
||||
depends on DM_VERITY
|
||||
---help---
|
||||
Enables Android Verified Boot platform-specific error
|
||||
behavior. In particular, it will modify the vbmeta partition
|
||||
specified on the kernel command-line when non-transient error
|
||||
occurs (followed by a panic).
|
||||
|
||||
config DM_ANDROID_VERITY
|
||||
bool "Android verity target support"
|
||||
depends on BLK_DEV_DM=y
|
||||
depends on DM_VERITY=y
|
||||
depends on X509_CERTIFICATE_PARSER
|
||||
depends on SYSTEM_TRUSTED_KEYRING
|
||||
depends on CRYPTO_RSA
|
||||
depends on KEYS
|
||||
depends on ASYMMETRIC_KEY_TYPE
|
||||
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
select DM_VERITY_HASH_PREFETCH_MIN_SIZE_128
|
||||
---help---
|
||||
This device-mapper target is virtually a VERITY target. This
|
||||
target is setup by reading the metadata contents piggybacked
|
||||
to the actual data blocks in the block device. The signature
|
||||
of the metadata contents are verified against the key included
|
||||
in the system keyring. Upon success, the underlying verity
|
||||
target is setup.
|
||||
|
||||
config DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED
|
||||
bool "Verity will validate blocks at most once"
|
||||
depends on DM_VERITY
|
||||
---help---
|
||||
Default enables at_most_once option for dm-verity
|
||||
|
||||
Verify data blocks only the first time they are read from the
|
||||
data device, rather than every time. This reduces the overhead
|
||||
of dm-verity so that it can be used on systems that are memory
|
||||
and/or CPU constrained. However, it provides a reduced level
|
||||
of security because only offline tampering of the data device's
|
||||
content will be detected, not online tampering.
|
||||
|
||||
Hash blocks are still verified each time they are read from the
|
||||
hash device, since verification of hash blocks is less performance
|
||||
critical than data blocks, and a hash block will not be verified
|
||||
any more after all the data blocks it covers have been verified anyway.
|
||||
|
||||
If unsure, say N.
|
||||
endif # MD
|
||||
|
@ -76,3 +76,11 @@ endif
|
||||
ifeq ($(CONFIG_DM_VERITY_FEC),y)
|
||||
dm-verity-objs += dm-verity-fec.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DM_VERITY_AVB),y)
|
||||
dm-verity-objs += dm-verity-avb.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DM_ANDROID_VERITY),y)
|
||||
dm-verity-objs += dm-android-verity.o
|
||||
endif
|
||||
|
925
drivers/md/dm-android-verity.c
Normal file
925
drivers/md/dm-android-verity.c
Normal file
@ -0,0 +1,925 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/device-mapper.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/key.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/hash_info.h>
|
||||
#include <crypto/public_key.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include <keys/system_keyring.h>
|
||||
|
||||
#include "dm-verity.h"
|
||||
#include "dm-android-verity.h"
|
||||
|
||||
static char verifiedbootstate[VERITY_COMMANDLINE_PARAM_LENGTH];
|
||||
static char veritymode[VERITY_COMMANDLINE_PARAM_LENGTH];
|
||||
static char veritykeyid[VERITY_DEFAULT_KEY_ID_LENGTH];
|
||||
static char buildvariant[BUILD_VARIANT];
|
||||
|
||||
static bool target_added;
|
||||
static bool verity_enabled = true;
|
||||
struct dentry *debug_dir;
|
||||
static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv);
|
||||
|
||||
static struct target_type android_verity_target = {
|
||||
.name = "android-verity",
|
||||
.version = {1, 0, 0},
|
||||
.module = THIS_MODULE,
|
||||
.ctr = android_verity_ctr,
|
||||
.dtr = verity_dtr,
|
||||
.map = verity_map,
|
||||
.status = verity_status,
|
||||
.prepare_ioctl = verity_prepare_ioctl,
|
||||
.iterate_devices = verity_iterate_devices,
|
||||
.io_hints = verity_io_hints,
|
||||
};
|
||||
|
||||
static int __init verified_boot_state_param(char *line)
|
||||
{
|
||||
strlcpy(verifiedbootstate, line, sizeof(verifiedbootstate));
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("androidboot.verifiedbootstate=", verified_boot_state_param);
|
||||
|
||||
static int __init verity_mode_param(char *line)
|
||||
{
|
||||
strlcpy(veritymode, line, sizeof(veritymode));
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("androidboot.veritymode=", verity_mode_param);
|
||||
|
||||
static int __init verity_keyid_param(char *line)
|
||||
{
|
||||
strlcpy(veritykeyid, line, sizeof(veritykeyid));
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("veritykeyid=", verity_keyid_param);
|
||||
|
||||
static int __init verity_buildvariant(char *line)
|
||||
{
|
||||
strlcpy(buildvariant, line, sizeof(buildvariant));
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup("buildvariant=", verity_buildvariant);
|
||||
|
||||
static inline bool default_verity_key_id(void)
|
||||
{
|
||||
return veritykeyid[0] != '\0';
|
||||
}
|
||||
|
||||
static inline bool is_eng(void)
|
||||
{
|
||||
static const char typeeng[] = "eng";
|
||||
|
||||
return !strncmp(buildvariant, typeeng, sizeof(typeeng));
|
||||
}
|
||||
|
||||
static inline bool is_userdebug(void)
|
||||
{
|
||||
static const char typeuserdebug[] = "userdebug";
|
||||
|
||||
return !strncmp(buildvariant, typeuserdebug, sizeof(typeuserdebug));
|
||||
}
|
||||
|
||||
static inline bool is_unlocked(void)
|
||||
{
|
||||
static const char unlocked[] = "orange";
|
||||
|
||||
return !strncmp(verifiedbootstate, unlocked, sizeof(unlocked));
|
||||
}
|
||||
|
||||
static int read_block_dev(struct bio_read *payload, struct block_device *bdev,
|
||||
sector_t offset, int length)
|
||||
{
|
||||
struct bio *bio;
|
||||
int err = 0, i;
|
||||
|
||||
payload->number_of_pages = DIV_ROUND_UP(length, PAGE_SIZE);
|
||||
|
||||
bio = bio_alloc(GFP_KERNEL, payload->number_of_pages);
|
||||
if (!bio) {
|
||||
DMERR("Error while allocating bio");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bio_set_dev(bio, bdev);
|
||||
bio->bi_iter.bi_sector = offset;
|
||||
bio_set_op_attrs(bio, REQ_OP_READ, 0);
|
||||
|
||||
payload->page_io = kzalloc(sizeof(struct page *) *
|
||||
payload->number_of_pages, GFP_KERNEL);
|
||||
if (!payload->page_io) {
|
||||
DMERR("page_io array alloc failed");
|
||||
err = -ENOMEM;
|
||||
goto free_bio;
|
||||
}
|
||||
|
||||
for (i = 0; i < payload->number_of_pages; i++) {
|
||||
payload->page_io[i] = alloc_page(GFP_KERNEL);
|
||||
if (!payload->page_io[i]) {
|
||||
DMERR("alloc_page failed");
|
||||
err = -ENOMEM;
|
||||
goto free_pages;
|
||||
}
|
||||
if (!bio_add_page(bio, payload->page_io[i], PAGE_SIZE, 0)) {
|
||||
DMERR("bio_add_page error");
|
||||
err = -EIO;
|
||||
goto free_pages;
|
||||
}
|
||||
}
|
||||
|
||||
if (!submit_bio_wait(bio))
|
||||
/* success */
|
||||
goto free_bio;
|
||||
DMERR("bio read failed");
|
||||
err = -EIO;
|
||||
|
||||
free_pages:
|
||||
for (i = 0; i < payload->number_of_pages; i++)
|
||||
if (payload->page_io[i])
|
||||
__free_page(payload->page_io[i]);
|
||||
kfree(payload->page_io);
|
||||
free_bio:
|
||||
bio_put(bio);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline u64 fec_div_round_up(u64 x, u64 y)
|
||||
{
|
||||
u64 remainder;
|
||||
|
||||
return div64_u64_rem(x, y, &remainder) +
|
||||
(remainder > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
static inline void populate_fec_metadata(struct fec_header *header,
|
||||
struct fec_ecc_metadata *ecc)
|
||||
{
|
||||
ecc->blocks = fec_div_round_up(le64_to_cpu(header->inp_size),
|
||||
FEC_BLOCK_SIZE);
|
||||
ecc->roots = le32_to_cpu(header->roots);
|
||||
ecc->start = le64_to_cpu(header->inp_size);
|
||||
}
|
||||
|
||||
static inline int validate_fec_header(struct fec_header *header, u64 offset)
|
||||
{
|
||||
/* move offset to make the sanity check work for backup header
|
||||
* as well. */
|
||||
offset -= offset % FEC_BLOCK_SIZE;
|
||||
if (le32_to_cpu(header->magic) != FEC_MAGIC ||
|
||||
le32_to_cpu(header->version) != FEC_VERSION ||
|
||||
le32_to_cpu(header->size) != sizeof(struct fec_header) ||
|
||||
le32_to_cpu(header->roots) == 0 ||
|
||||
le32_to_cpu(header->roots) >= FEC_RSM)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extract_fec_header(dev_t dev, struct fec_header *fec,
|
||||
struct fec_ecc_metadata *ecc)
|
||||
{
|
||||
u64 device_size;
|
||||
struct bio_read payload;
|
||||
int i, err = 0;
|
||||
struct block_device *bdev;
|
||||
|
||||
bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
|
||||
|
||||
if (IS_ERR_OR_NULL(bdev)) {
|
||||
DMERR("bdev get error");
|
||||
return PTR_ERR(bdev);
|
||||
}
|
||||
|
||||
device_size = i_size_read(bdev->bd_inode);
|
||||
|
||||
/* fec metadata size is a power of 2 and PAGE_SIZE
|
||||
* is a power of 2 as well.
|
||||
*/
|
||||
BUG_ON(FEC_BLOCK_SIZE > PAGE_SIZE);
|
||||
/* 512 byte sector alignment */
|
||||
BUG_ON(((device_size - FEC_BLOCK_SIZE) % (1 << SECTOR_SHIFT)) != 0);
|
||||
|
||||
err = read_block_dev(&payload, bdev, (device_size -
|
||||
FEC_BLOCK_SIZE) / (1 << SECTOR_SHIFT), FEC_BLOCK_SIZE);
|
||||
if (err) {
|
||||
DMERR("Error while reading verity metadata");
|
||||
goto error;
|
||||
}
|
||||
|
||||
BUG_ON(sizeof(struct fec_header) > PAGE_SIZE);
|
||||
memcpy(fec, page_address(payload.page_io[0]),
|
||||
sizeof(*fec));
|
||||
|
||||
ecc->valid = true;
|
||||
if (validate_fec_header(fec, device_size - FEC_BLOCK_SIZE)) {
|
||||
/* Try the backup header */
|
||||
memcpy(fec, page_address(payload.page_io[0]) + FEC_BLOCK_SIZE
|
||||
- sizeof(*fec) ,
|
||||
sizeof(*fec));
|
||||
if (validate_fec_header(fec, device_size -
|
||||
sizeof(struct fec_header)))
|
||||
ecc->valid = false;
|
||||
}
|
||||
|
||||
if (ecc->valid)
|
||||
populate_fec_metadata(fec, ecc);
|
||||
|
||||
for (i = 0; i < payload.number_of_pages; i++)
|
||||
__free_page(payload.page_io[i]);
|
||||
kfree(payload.page_io);
|
||||
|
||||
error:
|
||||
blkdev_put(bdev, FMODE_READ);
|
||||
return err;
|
||||
}
|
||||
static void find_metadata_offset(struct fec_header *fec,
|
||||
struct block_device *bdev, u64 *metadata_offset)
|
||||
{
|
||||
u64 device_size;
|
||||
|
||||
device_size = i_size_read(bdev->bd_inode);
|
||||
|
||||
if (le32_to_cpu(fec->magic) == FEC_MAGIC)
|
||||
*metadata_offset = le64_to_cpu(fec->inp_size) -
|
||||
VERITY_METADATA_SIZE;
|
||||
else
|
||||
*metadata_offset = device_size - VERITY_METADATA_SIZE;
|
||||
}
|
||||
|
||||
static int find_size(dev_t dev, u64 *device_size)
|
||||
{
|
||||
struct block_device *bdev;
|
||||
|
||||
bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
|
||||
if (IS_ERR_OR_NULL(bdev)) {
|
||||
DMERR("blkdev_get_by_dev failed");
|
||||
return PTR_ERR(bdev);
|
||||
}
|
||||
|
||||
*device_size = i_size_read(bdev->bd_inode);
|
||||
*device_size >>= SECTOR_SHIFT;
|
||||
|
||||
DMINFO("blkdev size in sectors: %llu", *device_size);
|
||||
blkdev_put(bdev, FMODE_READ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_header(struct android_metadata_header *header)
|
||||
{
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (is_userdebug() && le32_to_cpu(header->magic_number) ==
|
||||
VERITY_METADATA_MAGIC_DISABLE)
|
||||
return VERITY_STATE_DISABLE;
|
||||
|
||||
if (!(le32_to_cpu(header->magic_number) ==
|
||||
VERITY_METADATA_MAGIC_NUMBER) ||
|
||||
(le32_to_cpu(header->magic_number) ==
|
||||
VERITY_METADATA_MAGIC_DISABLE)) {
|
||||
DMERR("Incorrect magic number");
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(header->protocol_version) !=
|
||||
VERITY_METADATA_VERSION) {
|
||||
DMERR("Unsupported version %u",
|
||||
le32_to_cpu(header->protocol_version));
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extract_metadata(dev_t dev, struct fec_header *fec,
|
||||
struct android_metadata **metadata,
|
||||
bool *verity_enabled)
|
||||
{
|
||||
struct block_device *bdev;
|
||||
struct android_metadata_header *header;
|
||||
int i;
|
||||
u32 table_length, copy_length, offset;
|
||||
u64 metadata_offset;
|
||||
struct bio_read payload;
|
||||
int err = 0;
|
||||
|
||||
bdev = blkdev_get_by_dev(dev, FMODE_READ, NULL);
|
||||
|
||||
if (IS_ERR_OR_NULL(bdev)) {
|
||||
DMERR("blkdev_get_by_dev failed");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
find_metadata_offset(fec, bdev, &metadata_offset);
|
||||
|
||||
/* Verity metadata size is a power of 2 and PAGE_SIZE
|
||||
* is a power of 2 as well.
|
||||
* PAGE_SIZE is also a multiple of 512 bytes.
|
||||
*/
|
||||
if (VERITY_METADATA_SIZE > PAGE_SIZE)
|
||||
BUG_ON(VERITY_METADATA_SIZE % PAGE_SIZE != 0);
|
||||
/* 512 byte sector alignment */
|
||||
BUG_ON(metadata_offset % (1 << SECTOR_SHIFT) != 0);
|
||||
|
||||
err = read_block_dev(&payload, bdev, metadata_offset /
|
||||
(1 << SECTOR_SHIFT), VERITY_METADATA_SIZE);
|
||||
if (err) {
|
||||
DMERR("Error while reading verity metadata");
|
||||
goto blkdev_release;
|
||||
}
|
||||
|
||||
header = kzalloc(sizeof(*header), GFP_KERNEL);
|
||||
if (!header) {
|
||||
DMERR("kzalloc failed for header");
|
||||
err = -ENOMEM;
|
||||
goto free_payload;
|
||||
}
|
||||
|
||||
memcpy(header, page_address(payload.page_io[0]),
|
||||
sizeof(*header));
|
||||
|
||||
DMINFO("bio magic_number:%u protocol_version:%d table_length:%u",
|
||||
le32_to_cpu(header->magic_number),
|
||||
le32_to_cpu(header->protocol_version),
|
||||
le32_to_cpu(header->table_length));
|
||||
|
||||
err = verify_header(header);
|
||||
|
||||
if (err == VERITY_STATE_DISABLE) {
|
||||
DMERR("Mounting root with verity disabled");
|
||||
*verity_enabled = false;
|
||||
/* we would still have to read the metadata to figure out
|
||||
* the data blocks size. Or may be could map the entire
|
||||
* partition similar to mounting the device.
|
||||
*
|
||||
* Reset error as well as the verity_enabled flag is changed.
|
||||
*/
|
||||
err = 0;
|
||||
} else if (err)
|
||||
goto free_header;
|
||||
|
||||
*metadata = kzalloc(sizeof(**metadata), GFP_KERNEL);
|
||||
if (!*metadata) {
|
||||
DMERR("kzalloc for metadata failed");
|
||||
err = -ENOMEM;
|
||||
goto free_header;
|
||||
}
|
||||
|
||||
(*metadata)->header = header;
|
||||
table_length = le32_to_cpu(header->table_length);
|
||||
|
||||
if (table_length == 0 ||
|
||||
table_length > (VERITY_METADATA_SIZE -
|
||||
sizeof(struct android_metadata_header))) {
|
||||
DMERR("table_length too long");
|
||||
err = -EINVAL;
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
(*metadata)->verity_table = kzalloc(table_length + 1, GFP_KERNEL);
|
||||
|
||||
if (!(*metadata)->verity_table) {
|
||||
DMERR("kzalloc verity_table failed");
|
||||
err = -ENOMEM;
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
if (sizeof(struct android_metadata_header) +
|
||||
table_length <= PAGE_SIZE) {
|
||||
memcpy((*metadata)->verity_table,
|
||||
page_address(payload.page_io[0])
|
||||
+ sizeof(struct android_metadata_header),
|
||||
table_length);
|
||||
} else {
|
||||
copy_length = PAGE_SIZE -
|
||||
sizeof(struct android_metadata_header);
|
||||
memcpy((*metadata)->verity_table,
|
||||
page_address(payload.page_io[0])
|
||||
+ sizeof(struct android_metadata_header),
|
||||
copy_length);
|
||||
table_length -= copy_length;
|
||||
offset = copy_length;
|
||||
i = 1;
|
||||
while (table_length != 0) {
|
||||
if (table_length > PAGE_SIZE) {
|
||||
memcpy((*metadata)->verity_table + offset,
|
||||
page_address(payload.page_io[i]),
|
||||
PAGE_SIZE);
|
||||
offset += PAGE_SIZE;
|
||||
table_length -= PAGE_SIZE;
|
||||
} else {
|
||||
memcpy((*metadata)->verity_table + offset,
|
||||
page_address(payload.page_io[i]),
|
||||
table_length);
|
||||
table_length = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
(*metadata)->verity_table[table_length] = '\0';
|
||||
|
||||
DMINFO("verity_table: %s", (*metadata)->verity_table);
|
||||
goto free_payload;
|
||||
|
||||
free_metadata:
|
||||
kfree(*metadata);
|
||||
free_header:
|
||||
kfree(header);
|
||||
free_payload:
|
||||
for (i = 0; i < payload.number_of_pages; i++)
|
||||
if (payload.page_io[i])
|
||||
__free_page(payload.page_io[i]);
|
||||
kfree(payload.page_io);
|
||||
blkdev_release:
|
||||
blkdev_put(bdev, FMODE_READ);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* helper functions to extract properties from dts */
|
||||
const char *find_dt_value(const char *name)
|
||||
{
|
||||
struct device_node *firmware;
|
||||
const char *value;
|
||||
|
||||
firmware = of_find_node_by_path("/firmware/android");
|
||||
if (!firmware)
|
||||
return NULL;
|
||||
value = of_get_property(firmware, name, NULL);
|
||||
of_node_put(firmware);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int verity_mode(void)
|
||||
{
|
||||
static const char enforcing[] = "enforcing";
|
||||
static const char verified_mode_prop[] = "veritymode";
|
||||
const char *value;
|
||||
|
||||
value = find_dt_value(verified_mode_prop);
|
||||
if (!value)
|
||||
value = veritymode;
|
||||
if (!strncmp(value, enforcing, sizeof(enforcing) - 1))
|
||||
return DM_VERITY_MODE_RESTART;
|
||||
|
||||
return DM_VERITY_MODE_EIO;
|
||||
}
|
||||
|
||||
static void handle_error(void)
|
||||
{
|
||||
int mode = verity_mode();
|
||||
if (mode == DM_VERITY_MODE_RESTART) {
|
||||
DMERR("triggering restart");
|
||||
kernel_restart("dm-verity device corrupted");
|
||||
} else {
|
||||
DMERR("Mounting verity root failed");
|
||||
}
|
||||
}
|
||||
|
||||
static struct public_key_signature *table_make_digest(
|
||||
enum hash_algo hash,
|
||||
const void *table,
|
||||
unsigned long table_len)
|
||||
{
|
||||
struct public_key_signature *pks = NULL;
|
||||
struct crypto_shash *tfm;
|
||||
struct shash_desc *desc;
|
||||
size_t digest_size, desc_size;
|
||||
int ret;
|
||||
|
||||
/* Allocate the hashing algorithm we're going to need and find out how
|
||||
* big the hash operational data will be.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return ERR_CAST(tfm);
|
||||
|
||||
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
|
||||
digest_size = crypto_shash_digestsize(tfm);
|
||||
|
||||
/* We allocate the hash operational data storage on the end of out
|
||||
* context data and the digest output buffer on the end of that.
|
||||
*/
|
||||
ret = -ENOMEM;
|
||||
pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
|
||||
if (!pks)
|
||||
goto error;
|
||||
|
||||
pks->pkey_algo = "rsa";
|
||||
pks->hash_algo = hash_algo_name[hash];
|
||||
pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
|
||||
pks->digest_size = digest_size;
|
||||
|
||||
desc = (struct shash_desc *)(pks + 1);
|
||||
desc->tfm = tfm;
|
||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = crypto_shash_finup(desc, table, table_len, pks->digest);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
crypto_free_shash(tfm);
|
||||
return pks;
|
||||
|
||||
error:
|
||||
kfree(pks);
|
||||
crypto_free_shash(tfm);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
||||
static int verify_verity_signature(char *key_id,
|
||||
struct android_metadata *metadata)
|
||||
{
|
||||
struct public_key_signature *pks = NULL;
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (!key_id)
|
||||
goto error;
|
||||
|
||||
pks = table_make_digest(HASH_ALGO_SHA256,
|
||||
(const void *)metadata->verity_table,
|
||||
le32_to_cpu(metadata->header->table_length));
|
||||
if (IS_ERR(pks)) {
|
||||
DMERR("hashing failed");
|
||||
retval = PTR_ERR(pks);
|
||||
pks = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pks->s = kmemdup(&metadata->header->signature[0], RSANUMBYTES, GFP_KERNEL);
|
||||
if (!pks->s) {
|
||||
DMERR("Error allocating memory for signature");
|
||||
goto error;
|
||||
}
|
||||
pks->s_size = RSANUMBYTES;
|
||||
|
||||
retval = verify_signature_one(pks, NULL, key_id);
|
||||
kfree(pks->s);
|
||||
error:
|
||||
kfree(pks);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static inline bool test_mult_overflow(sector_t a, u32 b)
|
||||
{
|
||||
sector_t r = (sector_t)~0ULL;
|
||||
|
||||
sector_div(r, b);
|
||||
return a > r;
|
||||
}
|
||||
|
||||
static int add_as_linear_device(struct dm_target *ti, char *dev)
|
||||
{
|
||||
/*Move to linear mapping defines*/
|
||||
char *linear_table_args[DM_LINEAR_ARGS] = {dev,
|
||||
DM_LINEAR_TARGET_OFFSET};
|
||||
int err = 0;
|
||||
|
||||
android_verity_target.dtr = dm_linear_dtr,
|
||||
android_verity_target.map = dm_linear_map,
|
||||
android_verity_target.status = dm_linear_status,
|
||||
android_verity_target.end_io = dm_linear_end_io,
|
||||
android_verity_target.prepare_ioctl = dm_linear_prepare_ioctl,
|
||||
android_verity_target.iterate_devices = dm_linear_iterate_devices,
|
||||
android_verity_target.direct_access = dm_linear_dax_direct_access,
|
||||
android_verity_target.dax_copy_from_iter = dm_linear_dax_copy_from_iter,
|
||||
android_verity_target.io_hints = NULL;
|
||||
|
||||
set_disk_ro(dm_disk(dm_table_get_md(ti->table)), 0);
|
||||
|
||||
err = dm_linear_ctr(ti, DM_LINEAR_ARGS, linear_table_args);
|
||||
|
||||
if (!err) {
|
||||
DMINFO("Added android-verity as a linear target");
|
||||
target_added = true;
|
||||
} else
|
||||
DMERR("Failed to add android-verity as linear target");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int create_linear_device(struct dm_target *ti, dev_t dev,
|
||||
char *target_device)
|
||||
{
|
||||
u64 device_size = 0;
|
||||
int err = find_size(dev, &device_size);
|
||||
|
||||
if (err) {
|
||||
DMERR("error finding bdev size");
|
||||
handle_error();
|
||||
return err;
|
||||
}
|
||||
|
||||
ti->len = device_size;
|
||||
err = add_as_linear_device(ti, target_device);
|
||||
if (err) {
|
||||
handle_error();
|
||||
return err;
|
||||
}
|
||||
verity_enabled = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Target parameters:
|
||||
* <key id> Key id of the public key in the system keyring.
|
||||
* Verity metadata's signature would be verified against
|
||||
* this. If the key id contains spaces, replace them
|
||||
* with '#'.
|
||||
* <block device> The block device for which dm-verity is being setup.
|
||||
*/
|
||||
static int android_verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
||||
{
|
||||
dev_t uninitialized_var(dev);
|
||||
struct android_metadata *metadata = NULL;
|
||||
int err = 0, i, mode;
|
||||
char *key_id = NULL, *table_ptr, dummy, *target_device;
|
||||
char *verity_table_args[VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS];
|
||||
/* One for specifying number of opt args and one for mode */
|
||||
sector_t data_sectors;
|
||||
u32 data_block_size;
|
||||
unsigned int no_of_args = VERITY_TABLE_ARGS + 2 + VERITY_TABLE_OPT_FEC_ARGS;
|
||||
struct fec_header uninitialized_var(fec);
|
||||
struct fec_ecc_metadata uninitialized_var(ecc);
|
||||
char buf[FEC_ARG_LENGTH], *buf_ptr;
|
||||
unsigned long long tmpll;
|
||||
|
||||
if (argc == 1) {
|
||||
/* Use the default keyid */
|
||||
if (default_verity_key_id())
|
||||
key_id = veritykeyid;
|
||||
else if (!is_eng()) {
|
||||
DMERR("veritykeyid= is not set");
|
||||
handle_error();
|
||||
return -EINVAL;
|
||||
}
|
||||
target_device = argv[0];
|
||||
} else if (argc == 2) {
|
||||
key_id = argv[0];
|
||||
target_device = argv[1];
|
||||
} else {
|
||||
DMERR("Incorrect number of arguments");
|
||||
handle_error();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev = name_to_dev_t(target_device);
|
||||
if (!dev) {
|
||||
DMERR("no dev found for %s", target_device);
|
||||
handle_error();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (is_eng())
|
||||
return create_linear_device(ti, dev, target_device);
|
||||
|
||||
strreplace(key_id, '#', ' ');
|
||||
|
||||
DMINFO("key:%s dev:%s", key_id, target_device);
|
||||
|
||||
if (extract_fec_header(dev, &fec, &ecc)) {
|
||||
DMERR("Error while extracting fec header");
|
||||
handle_error();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = extract_metadata(dev, &fec, &metadata, &verity_enabled);
|
||||
|
||||
if (err) {
|
||||
/* Allow invalid metadata when the device is unlocked */
|
||||
if (is_unlocked()) {
|
||||
DMWARN("Allow invalid metadata when unlocked");
|
||||
return create_linear_device(ti, dev, target_device);
|
||||
}
|
||||
DMERR("Error while extracting metadata");
|
||||
handle_error();
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
if (verity_enabled) {
|
||||
err = verify_verity_signature(key_id, metadata);
|
||||
|
||||
if (err) {
|
||||
DMERR("Signature verification failed");
|
||||
handle_error();
|
||||
goto free_metadata;
|
||||
} else
|
||||
DMINFO("Signature verification success");
|
||||
}
|
||||
|
||||
table_ptr = metadata->verity_table;
|
||||
|
||||
for (i = 0; i < VERITY_TABLE_ARGS; i++) {
|
||||
verity_table_args[i] = strsep(&table_ptr, " ");
|
||||
if (verity_table_args[i] == NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != VERITY_TABLE_ARGS) {
|
||||
DMERR("Verity table not in the expected format");
|
||||
err = -EINVAL;
|
||||
handle_error();
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
if (sscanf(verity_table_args[5], "%llu%c", &tmpll, &dummy)
|
||||
!= 1) {
|
||||
DMERR("Verity table not in the expected format");
|
||||
handle_error();
|
||||
err = -EINVAL;
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
if (tmpll > ULONG_MAX) {
|
||||
DMERR("<num_data_blocks> too large. Forgot to turn on CONFIG_LBDAF?");
|
||||
handle_error();
|
||||
err = -EINVAL;
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
data_sectors = tmpll;
|
||||
|
||||
if (sscanf(verity_table_args[3], "%u%c", &data_block_size, &dummy)
|
||||
!= 1) {
|
||||
DMERR("Verity table not in the expected format");
|
||||
handle_error();
|
||||
err = -EINVAL;
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
if (test_mult_overflow(data_sectors, data_block_size >>
|
||||
SECTOR_SHIFT)) {
|
||||
DMERR("data_sectors too large");
|
||||
handle_error();
|
||||
err = -EOVERFLOW;
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
data_sectors *= data_block_size >> SECTOR_SHIFT;
|
||||
DMINFO("Data sectors %llu", (unsigned long long)data_sectors);
|
||||
|
||||
/* update target length */
|
||||
ti->len = data_sectors;
|
||||
|
||||
/* Setup linear target and free */
|
||||
if (!verity_enabled) {
|
||||
err = add_as_linear_device(ti, target_device);
|
||||
goto free_metadata;
|
||||
}
|
||||
|
||||
/*substitute data_dev and hash_dev*/
|
||||
verity_table_args[1] = target_device;
|
||||
verity_table_args[2] = target_device;
|
||||
|
||||
mode = verity_mode();
|
||||
|
||||
if (ecc.valid && IS_BUILTIN(CONFIG_DM_VERITY_FEC)) {
|
||||
if (mode) {
|
||||
err = snprintf(buf, FEC_ARG_LENGTH,
|
||||
"%u %s " VERITY_TABLE_OPT_FEC_FORMAT,
|
||||
1 + VERITY_TABLE_OPT_FEC_ARGS,
|
||||
mode == DM_VERITY_MODE_RESTART ?
|
||||
VERITY_TABLE_OPT_RESTART :
|
||||
VERITY_TABLE_OPT_LOGGING,
|
||||
target_device,
|
||||
ecc.start / FEC_BLOCK_SIZE, ecc.blocks,
|
||||
ecc.roots);
|
||||
} else {
|
||||
err = snprintf(buf, FEC_ARG_LENGTH,
|
||||
"%u " VERITY_TABLE_OPT_FEC_FORMAT,
|
||||
VERITY_TABLE_OPT_FEC_ARGS, target_device,
|
||||
ecc.start / FEC_BLOCK_SIZE, ecc.blocks,
|
||||
ecc.roots);
|
||||
}
|
||||
} else if (mode) {
|
||||
err = snprintf(buf, FEC_ARG_LENGTH,
|
||||
"2 " VERITY_TABLE_OPT_IGNZERO " %s",
|
||||
mode == DM_VERITY_MODE_RESTART ?
|
||||
VERITY_TABLE_OPT_RESTART : VERITY_TABLE_OPT_LOGGING);
|
||||
} else {
|
||||
err = snprintf(buf, FEC_ARG_LENGTH, "1 %s",
|
||||
"ignore_zero_blocks");
|
||||
}
|
||||
|
||||
if (err < 0 || err >= FEC_ARG_LENGTH)
|
||||
goto free_metadata;
|
||||
|
||||
buf_ptr = buf;
|
||||
|
||||
for (i = VERITY_TABLE_ARGS; i < (VERITY_TABLE_ARGS +
|
||||
VERITY_TABLE_OPT_FEC_ARGS + 2); i++) {
|
||||
verity_table_args[i] = strsep(&buf_ptr, " ");
|
||||
if (verity_table_args[i] == NULL) {
|
||||
no_of_args = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
err = verity_ctr(ti, no_of_args, verity_table_args);
|
||||
if (err) {
|
||||
DMERR("android-verity failed to create a verity target");
|
||||
} else {
|
||||
target_added = true;
|
||||
DMINFO("android-verity created as verity target");
|
||||
}
|
||||
|
||||
free_metadata:
|
||||
if (metadata) {
|
||||
kfree(metadata->header);
|
||||
kfree(metadata->verity_table);
|
||||
}
|
||||
kfree(metadata);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init dm_android_verity_init(void)
|
||||
{
|
||||
int r;
|
||||
struct dentry *file;
|
||||
|
||||
r = dm_register_target(&android_verity_target);
|
||||
if (r < 0)
|
||||
DMERR("register failed %d", r);
|
||||
|
||||
/* Tracks the status of the last added target */
|
||||
debug_dir = debugfs_create_dir("android_verity", NULL);
|
||||
|
||||
if (IS_ERR_OR_NULL(debug_dir)) {
|
||||
DMERR("Cannot create android_verity debugfs directory: %ld",
|
||||
PTR_ERR(debug_dir));
|
||||
goto end;
|
||||
}
|
||||
|
||||
file = debugfs_create_bool("target_added", S_IRUGO, debug_dir,
|
||||
&target_added);
|
||||
|
||||
if (IS_ERR_OR_NULL(file)) {
|
||||
DMERR("Cannot create android_verity debugfs directory: %ld",
|
||||
PTR_ERR(debug_dir));
|
||||
debugfs_remove_recursive(debug_dir);
|
||||
goto end;
|
||||
}
|
||||
|
||||
file = debugfs_create_bool("verity_enabled", S_IRUGO, debug_dir,
|
||||
&verity_enabled);
|
||||
|
||||
if (IS_ERR_OR_NULL(file)) {
|
||||
DMERR("Cannot create android_verity debugfs directory: %ld",
|
||||
PTR_ERR(debug_dir));
|
||||
debugfs_remove_recursive(debug_dir);
|
||||
}
|
||||
|
||||
end:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit dm_android_verity_exit(void)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(debug_dir))
|
||||
debugfs_remove_recursive(debug_dir);
|
||||
|
||||
dm_unregister_target(&android_verity_target);
|
||||
}
|
||||
|
||||
module_init(dm_android_verity_init);
|
||||
module_exit(dm_android_verity_exit);
|
132
drivers/md/dm-android-verity.h
Normal file
132
drivers/md/dm-android-verity.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DM_ANDROID_VERITY_H
|
||||
#define DM_ANDROID_VERITY_H
|
||||
|
||||
#include <crypto/sha.h>
|
||||
|
||||
#define RSANUMBYTES 256
|
||||
#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
|
||||
#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56
|
||||
#define VERITY_METADATA_VERSION 0
|
||||
#define VERITY_STATE_DISABLE 1
|
||||
#define DATA_BLOCK_SIZE (4 * 1024)
|
||||
#define VERITY_METADATA_SIZE (8 * DATA_BLOCK_SIZE)
|
||||
#define VERITY_TABLE_ARGS 10
|
||||
#define VERITY_COMMANDLINE_PARAM_LENGTH 20
|
||||
#define BUILD_VARIANT 20
|
||||
|
||||
/*
|
||||
* <subject>:<sha1-id> is the format for the identifier.
|
||||
* subject can either be the Common Name(CN) + Organization Name(O) or
|
||||
* just the CN if the it is prefixed with O
|
||||
* From https://tools.ietf.org/html/rfc5280#appendix-A
|
||||
* ub-organization-name-length INTEGER ::= 64
|
||||
* ub-common-name-length INTEGER ::= 64
|
||||
*
|
||||
* http://lxr.free-electrons.com/source/crypto/asymmetric_keys/x509_cert_parser.c?v=3.9#L278
|
||||
* ctx->o_size + 2 + ctx->cn_size + 1
|
||||
* + 41 characters for ":" and sha1 id
|
||||
* 64 + 2 + 64 + 1 + 1 + 40 (172)
|
||||
* setting VERITY_DEFAULT_KEY_ID_LENGTH to 200 characters.
|
||||
*/
|
||||
#define VERITY_DEFAULT_KEY_ID_LENGTH 200
|
||||
|
||||
#define FEC_MAGIC 0xFECFECFE
|
||||
#define FEC_BLOCK_SIZE (4 * 1024)
|
||||
#define FEC_VERSION 0
|
||||
#define FEC_RSM 255
|
||||
#define FEC_ARG_LENGTH 300
|
||||
|
||||
#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
|
||||
#define VERITY_TABLE_OPT_LOGGING "ignore_corruption"
|
||||
#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
|
||||
|
||||
#define VERITY_TABLE_OPT_FEC_FORMAT \
|
||||
"use_fec_from_device %s fec_start %llu fec_blocks %llu fec_roots %u ignore_zero_blocks"
|
||||
#define VERITY_TABLE_OPT_FEC_ARGS 9
|
||||
|
||||
#define VERITY_DEBUG 0
|
||||
|
||||
#define DM_MSG_PREFIX "android-verity"
|
||||
|
||||
#define DM_LINEAR_ARGS 2
|
||||
#define DM_LINEAR_TARGET_OFFSET "0"
|
||||
|
||||
/*
|
||||
* There can be two formats.
|
||||
* if fec is present
|
||||
* <data_blocks> <verity_tree> <verity_metdata_32K><fec_data><fec_data_4K>
|
||||
* if fec is not present
|
||||
* <data_blocks> <verity_tree> <verity_metdata_32K>
|
||||
*/
|
||||
struct fec_header {
|
||||
__le32 magic;
|
||||
__le32 version;
|
||||
__le32 size;
|
||||
__le32 roots;
|
||||
__le32 fec_size;
|
||||
__le64 inp_size;
|
||||
u8 hash[SHA256_DIGEST_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct android_metadata_header {
|
||||
__le32 magic_number;
|
||||
__le32 protocol_version;
|
||||
char signature[RSANUMBYTES];
|
||||
__le32 table_length;
|
||||
};
|
||||
|
||||
struct android_metadata {
|
||||
struct android_metadata_header *header;
|
||||
char *verity_table;
|
||||
};
|
||||
|
||||
struct fec_ecc_metadata {
|
||||
bool valid;
|
||||
u32 roots;
|
||||
u64 blocks;
|
||||
u64 rounds;
|
||||
u64 start;
|
||||
};
|
||||
|
||||
struct bio_read {
|
||||
struct page **page_io;
|
||||
int number_of_pages;
|
||||
};
|
||||
|
||||
extern struct target_type linear_target;
|
||||
|
||||
extern void dm_linear_dtr(struct dm_target *ti);
|
||||
extern int dm_linear_map(struct dm_target *ti, struct bio *bio);
|
||||
extern int dm_linear_end_io(struct dm_target *ti, struct bio *bio,
|
||||
blk_status_t *error);
|
||||
extern void dm_linear_status(struct dm_target *ti, status_type_t type,
|
||||
unsigned status_flags, char *result, unsigned maxlen);
|
||||
extern int dm_linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev);
|
||||
extern int dm_linear_iterate_devices(struct dm_target *ti,
|
||||
iterate_devices_callout_fn fn, void *data);
|
||||
extern int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv);
|
||||
#if IS_ENABLED(CONFIG_DAX_DRIVER)
|
||||
extern long dm_linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
|
||||
long nr_pages, void **kaddr,
|
||||
pfn_t *pfn);
|
||||
extern size_t dm_linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff,
|
||||
void *addr, size_t bytes, struct iov_iter *i);
|
||||
#else
|
||||
#define dm_linear_dax_direct_access NULL
|
||||
#define dm_linear_dax_copy_from_iter NULL
|
||||
#endif
|
||||
#endif /* DM_ANDROID_VERITY_H */
|
@ -1993,6 +1993,45 @@ void dm_interface_exit(void)
|
||||
dm_hash_exit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dm_ioctl_export - Permanently export a mapped device via the ioctl interface
|
||||
* @md: Pointer to mapped_device
|
||||
* @name: Buffer (size DM_NAME_LEN) for name
|
||||
* @uuid: Buffer (size DM_UUID_LEN) for uuid or NULL if not desired
|
||||
*/
|
||||
int dm_ioctl_export(struct mapped_device *md, const char *name,
|
||||
const char *uuid)
|
||||
{
|
||||
int r = 0;
|
||||
struct hash_cell *hc;
|
||||
|
||||
if (!md) {
|
||||
r = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* The name and uuid can only be set once. */
|
||||
mutex_lock(&dm_hash_cells_mutex);
|
||||
hc = dm_get_mdptr(md);
|
||||
mutex_unlock(&dm_hash_cells_mutex);
|
||||
if (hc) {
|
||||
DMERR("%s: already exported", dm_device_name(md));
|
||||
r = -ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = dm_hash_insert(name, uuid, md);
|
||||
if (r) {
|
||||
DMERR("%s: could not bind to '%s'", dm_device_name(md), name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Let udev know we've changed. */
|
||||
dm_kobject_uevent(md, KOBJ_CHANGE, dm_get_event_nr(md));
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
/**
|
||||
* dm_copy_name_and_uuid - Copy mapped device name & uuid into supplied buffers
|
||||
* @md: Pointer to mapped_device
|
||||
|
@ -26,7 +26,7 @@ struct linear_c {
|
||||
/*
|
||||
* Construct a linear mapping: <dev_path> <offset>
|
||||
*/
|
||||
static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
int dm_linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
{
|
||||
struct linear_c *lc;
|
||||
unsigned long long tmp;
|
||||
@ -70,7 +70,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void linear_dtr(struct dm_target *ti)
|
||||
void dm_linear_dtr(struct dm_target *ti)
|
||||
{
|
||||
struct linear_c *lc = (struct linear_c *) ti->private;
|
||||
|
||||
@ -95,14 +95,14 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio)
|
||||
linear_map_sector(ti, bio->bi_iter.bi_sector);
|
||||
}
|
||||
|
||||
static int linear_map(struct dm_target *ti, struct bio *bio)
|
||||
int dm_linear_map(struct dm_target *ti, struct bio *bio)
|
||||
{
|
||||
linear_map_bio(ti, bio);
|
||||
|
||||
return DM_MAPIO_REMAPPED;
|
||||
}
|
||||
|
||||
static int linear_end_io(struct dm_target *ti, struct bio *bio,
|
||||
int dm_linear_end_io(struct dm_target *ti, struct bio *bio,
|
||||
blk_status_t *error)
|
||||
{
|
||||
struct linear_c *lc = ti->private;
|
||||
@ -112,8 +112,9 @@ static int linear_end_io(struct dm_target *ti, struct bio *bio,
|
||||
|
||||
return DM_ENDIO_DONE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dm_linear_end_io);
|
||||
|
||||
static void linear_status(struct dm_target *ti, status_type_t type,
|
||||
void dm_linear_status(struct dm_target *ti, status_type_t type,
|
||||
unsigned status_flags, char *result, unsigned maxlen)
|
||||
{
|
||||
struct linear_c *lc = (struct linear_c *) ti->private;
|
||||
@ -130,7 +131,7 @@ static void linear_status(struct dm_target *ti, status_type_t type,
|
||||
}
|
||||
}
|
||||
|
||||
static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
int dm_linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
{
|
||||
struct linear_c *lc = (struct linear_c *) ti->private;
|
||||
struct dm_dev *dev = lc->dev;
|
||||
@ -146,7 +147,7 @@ static int linear_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int linear_iterate_devices(struct dm_target *ti,
|
||||
int dm_linear_iterate_devices(struct dm_target *ti,
|
||||
iterate_devices_callout_fn fn, void *data)
|
||||
{
|
||||
struct linear_c *lc = ti->private;
|
||||
@ -155,7 +156,7 @@ static int linear_iterate_devices(struct dm_target *ti,
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_DAX_DRIVER)
|
||||
static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
|
||||
long dm_linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
|
||||
long nr_pages, void **kaddr, pfn_t *pfn)
|
||||
{
|
||||
long ret;
|
||||
@ -170,8 +171,9 @@ static long linear_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
|
||||
return ret;
|
||||
return dax_direct_access(dax_dev, pgoff, nr_pages, kaddr, pfn);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dm_linear_dax_direct_access);
|
||||
|
||||
static size_t linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff,
|
||||
size_t dm_linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff,
|
||||
void *addr, size_t bytes, struct iov_iter *i)
|
||||
{
|
||||
struct linear_c *lc = ti->private;
|
||||
@ -184,8 +186,9 @@ static size_t linear_dax_copy_from_iter(struct dm_target *ti, pgoff_t pgoff,
|
||||
return 0;
|
||||
return dax_copy_from_iter(dax_dev, pgoff, addr, bytes, i);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dm_linear_dax_copy_from_iter);
|
||||
|
||||
static size_t linear_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
|
||||
static size_t dm_linear_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
|
||||
void *addr, size_t bytes, struct iov_iter *i)
|
||||
{
|
||||
struct linear_c *lc = ti->private;
|
||||
@ -200,9 +203,9 @@ static size_t linear_dax_copy_to_iter(struct dm_target *ti, pgoff_t pgoff,
|
||||
}
|
||||
|
||||
#else
|
||||
#define linear_dax_direct_access NULL
|
||||
#define linear_dax_copy_from_iter NULL
|
||||
#define linear_dax_copy_to_iter NULL
|
||||
#define dm_linear_dax_direct_access NULL
|
||||
#define dm_linear_dax_copy_from_iter NULL
|
||||
#define dm_linear_dax_copy_to_iter NULL
|
||||
#endif
|
||||
|
||||
static struct target_type linear_target = {
|
||||
@ -210,16 +213,16 @@ static struct target_type linear_target = {
|
||||
.version = {1, 4, 0},
|
||||
.features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_ZONED_HM,
|
||||
.module = THIS_MODULE,
|
||||
.ctr = linear_ctr,
|
||||
.dtr = linear_dtr,
|
||||
.map = linear_map,
|
||||
.end_io = linear_end_io,
|
||||
.status = linear_status,
|
||||
.prepare_ioctl = linear_prepare_ioctl,
|
||||
.iterate_devices = linear_iterate_devices,
|
||||
.direct_access = linear_dax_direct_access,
|
||||
.dax_copy_from_iter = linear_dax_copy_from_iter,
|
||||
.dax_copy_to_iter = linear_dax_copy_to_iter,
|
||||
.ctr = dm_linear_ctr,
|
||||
.dtr = dm_linear_dtr,
|
||||
.map = dm_linear_map,
|
||||
.status = dm_linear_status,
|
||||
.end_io = dm_linear_end_io,
|
||||
.prepare_ioctl = dm_linear_prepare_ioctl,
|
||||
.iterate_devices = dm_linear_iterate_devices,
|
||||
.direct_access = dm_linear_dax_direct_access,
|
||||
.dax_copy_from_iter = dm_linear_dax_copy_from_iter,
|
||||
.dax_copy_to_iter = dm_linear_dax_copy_to_iter,
|
||||
};
|
||||
|
||||
int __init dm_linear_init(void)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
229
drivers/md/dm-verity-avb.c
Normal file
229
drivers/md/dm-verity-avb.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Google.
|
||||
*
|
||||
* This file is released under the GPLv2.
|
||||
*
|
||||
* Based on drivers/md/dm-verity-chromeos.c
|
||||
*/
|
||||
|
||||
#include <linux/device-mapper.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mount.h>
|
||||
|
||||
#define DM_MSG_PREFIX "verity-avb"
|
||||
|
||||
/* Set via module parameters. */
|
||||
static char avb_vbmeta_device[64];
|
||||
static char avb_invalidate_on_error[4];
|
||||
|
||||
static void invalidate_vbmeta_endio(struct bio *bio)
|
||||
{
|
||||
if (bio->bi_status)
|
||||
DMERR("invalidate_vbmeta_endio: error %d", bio->bi_status);
|
||||
complete(bio->bi_private);
|
||||
}
|
||||
|
||||
static int invalidate_vbmeta_submit(struct bio *bio,
|
||||
struct block_device *bdev,
|
||||
int op, int access_last_sector,
|
||||
struct page *page)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(wait);
|
||||
|
||||
bio->bi_private = &wait;
|
||||
bio->bi_end_io = invalidate_vbmeta_endio;
|
||||
bio_set_dev(bio, bdev);
|
||||
bio_set_op_attrs(bio, op, REQ_SYNC);
|
||||
|
||||
bio->bi_iter.bi_sector = 0;
|
||||
if (access_last_sector) {
|
||||
sector_t last_sector;
|
||||
|
||||
last_sector = (i_size_read(bdev->bd_inode)>>SECTOR_SHIFT) - 1;
|
||||
bio->bi_iter.bi_sector = last_sector;
|
||||
}
|
||||
if (!bio_add_page(bio, page, PAGE_SIZE, 0)) {
|
||||
DMERR("invalidate_vbmeta_submit: bio_add_page error");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
submit_bio(bio);
|
||||
/* Wait up to 2 seconds for completion or fail. */
|
||||
if (!wait_for_completion_timeout(&wait, msecs_to_jiffies(2000)))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int invalidate_vbmeta(dev_t vbmeta_devt)
|
||||
{
|
||||
int ret = 0;
|
||||
struct block_device *bdev;
|
||||
struct bio *bio;
|
||||
struct page *page;
|
||||
fmode_t dev_mode;
|
||||
/* Ensure we do synchronous unblocked I/O. We may also need
|
||||
* sync_bdev() on completion, but it really shouldn't.
|
||||
*/
|
||||
int access_last_sector = 0;
|
||||
|
||||
DMINFO("invalidate_vbmeta: acting on device %d:%d",
|
||||
MAJOR(vbmeta_devt), MINOR(vbmeta_devt));
|
||||
|
||||
/* First we open the device for reading. */
|
||||
dev_mode = FMODE_READ | FMODE_EXCL;
|
||||
bdev = blkdev_get_by_dev(vbmeta_devt, dev_mode,
|
||||
invalidate_vbmeta);
|
||||
if (IS_ERR(bdev)) {
|
||||
DMERR("invalidate_kernel: could not open device for reading");
|
||||
dev_mode = 0;
|
||||
ret = -ENOENT;
|
||||
goto failed_to_read;
|
||||
}
|
||||
|
||||
bio = bio_alloc(GFP_NOIO, 1);
|
||||
if (!bio) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_bio_alloc;
|
||||
}
|
||||
|
||||
page = alloc_page(GFP_NOIO);
|
||||
if (!page) {
|
||||
ret = -ENOMEM;
|
||||
goto failed_to_alloc_page;
|
||||
}
|
||||
|
||||
access_last_sector = 0;
|
||||
ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_READ,
|
||||
access_last_sector, page);
|
||||
if (ret) {
|
||||
DMERR("invalidate_vbmeta: error reading");
|
||||
goto failed_to_submit_read;
|
||||
}
|
||||
|
||||
/* We have a page. Let's make sure it looks right. */
|
||||
if (memcmp("AVB0", page_address(page), 4) == 0) {
|
||||
/* Stamp it. */
|
||||
memcpy(page_address(page), "AVE0", 4);
|
||||
DMINFO("invalidate_vbmeta: found vbmeta partition");
|
||||
} else {
|
||||
/* Could be this is on a AVB footer, check. Also, since the
|
||||
* AVB footer is in the last 64 bytes, adjust for the fact that
|
||||
* we're dealing with 512-byte sectors.
|
||||
*/
|
||||
size_t offset = (1<<SECTOR_SHIFT) - 64;
|
||||
|
||||
access_last_sector = 1;
|
||||
ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_READ,
|
||||
access_last_sector, page);
|
||||
if (ret) {
|
||||
DMERR("invalidate_vbmeta: error reading");
|
||||
goto failed_to_submit_read;
|
||||
}
|
||||
if (memcmp("AVBf", page_address(page) + offset, 4) != 0) {
|
||||
DMERR("invalidate_vbmeta on non-vbmeta partition");
|
||||
ret = -EINVAL;
|
||||
goto invalid_header;
|
||||
}
|
||||
/* Stamp it. */
|
||||
memcpy(page_address(page) + offset, "AVE0", 4);
|
||||
DMINFO("invalidate_vbmeta: found vbmeta footer partition");
|
||||
}
|
||||
|
||||
/* Now rewrite the changed page - the block dev was being
|
||||
* changed on read. Let's reopen here.
|
||||
*/
|
||||
blkdev_put(bdev, dev_mode);
|
||||
dev_mode = FMODE_WRITE | FMODE_EXCL;
|
||||
bdev = blkdev_get_by_dev(vbmeta_devt, dev_mode,
|
||||
invalidate_vbmeta);
|
||||
if (IS_ERR(bdev)) {
|
||||
DMERR("invalidate_vbmeta: could not open device for writing");
|
||||
dev_mode = 0;
|
||||
ret = -ENOENT;
|
||||
goto failed_to_write;
|
||||
}
|
||||
|
||||
/* We re-use the same bio to do the write after the read. Need to reset
|
||||
* it to initialize bio->bi_remaining.
|
||||
*/
|
||||
bio_reset(bio);
|
||||
|
||||
ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_WRITE,
|
||||
access_last_sector, page);
|
||||
if (ret) {
|
||||
DMERR("invalidate_vbmeta: error writing");
|
||||
goto failed_to_submit_write;
|
||||
}
|
||||
|
||||
DMERR("invalidate_vbmeta: completed.");
|
||||
ret = 0;
|
||||
failed_to_submit_write:
|
||||
failed_to_write:
|
||||
invalid_header:
|
||||
__free_page(page);
|
||||
failed_to_submit_read:
|
||||
/* Technically, we'll leak a page with the pending bio, but
|
||||
* we're about to reboot anyway.
|
||||
*/
|
||||
failed_to_alloc_page:
|
||||
bio_put(bio);
|
||||
failed_bio_alloc:
|
||||
if (dev_mode)
|
||||
blkdev_put(bdev, dev_mode);
|
||||
failed_to_read:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dm_verity_avb_error_handler(void)
|
||||
{
|
||||
dev_t dev;
|
||||
|
||||
DMINFO("AVB error handler called for %s", avb_vbmeta_device);
|
||||
|
||||
if (strcmp(avb_invalidate_on_error, "yes") != 0) {
|
||||
DMINFO("Not configured to invalidate");
|
||||
return;
|
||||
}
|
||||
|
||||
if (avb_vbmeta_device[0] == '\0') {
|
||||
DMERR("avb_vbmeta_device parameter not set");
|
||||
goto fail_no_dev;
|
||||
}
|
||||
|
||||
dev = name_to_dev_t(avb_vbmeta_device);
|
||||
if (!dev) {
|
||||
DMERR("No matching partition for device: %s",
|
||||
avb_vbmeta_device);
|
||||
goto fail_no_dev;
|
||||
}
|
||||
|
||||
invalidate_vbmeta(dev);
|
||||
|
||||
fail_no_dev:
|
||||
;
|
||||
}
|
||||
|
||||
static int __init dm_verity_avb_init(void)
|
||||
{
|
||||
DMINFO("AVB error handler initialized with vbmeta device: %s",
|
||||
avb_vbmeta_device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dm_verity_avb_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(dm_verity_avb_init);
|
||||
module_exit(dm_verity_avb_exit);
|
||||
|
||||
MODULE_AUTHOR("David Zeuthen <zeuthen@google.com>");
|
||||
MODULE_DESCRIPTION("AVB-specific error handler for dm-verity");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Declare parameter with no module prefix */
|
||||
#undef MODULE_PARAM_PREFIX
|
||||
#define MODULE_PARAM_PREFIX "androidboot.vbmeta."
|
||||
module_param_string(device, avb_vbmeta_device, sizeof(avb_vbmeta_device), 0);
|
||||
module_param_string(invalidate_on_error, avb_invalidate_on_error,
|
||||
sizeof(avb_invalidate_on_error), 0);
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "dm-verity-fec.h"
|
||||
#include <linux/math64.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#define DM_MSG_PREFIX "verity-fec"
|
||||
|
||||
@ -175,9 +176,11 @@ error:
|
||||
if (r < 0 && neras)
|
||||
DMERR_LIMIT("%s: FEC %llu: failed to correct: %d",
|
||||
v->data_dev->name, (unsigned long long)rsb, r);
|
||||
else if (r > 0)
|
||||
else if (r > 0) {
|
||||
DMWARN_LIMIT("%s: FEC %llu: corrected %d errors",
|
||||
v->data_dev->name, (unsigned long long)rsb, r);
|
||||
atomic_add_unless(&v->fec->corrected, 1, INT_MAX);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -545,6 +548,7 @@ unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
|
||||
void verity_fec_dtr(struct dm_verity *v)
|
||||
{
|
||||
struct dm_verity_fec *f = v->fec;
|
||||
struct kobject *kobj = &f->kobj_holder.kobj;
|
||||
|
||||
if (!verity_fec_is_enabled(v))
|
||||
goto out;
|
||||
@ -561,6 +565,12 @@ void verity_fec_dtr(struct dm_verity *v)
|
||||
|
||||
if (f->dev)
|
||||
dm_put_device(v->ti, f->dev);
|
||||
|
||||
if (kobj->state_initialized) {
|
||||
kobject_put(kobj);
|
||||
wait_for_completion(dm_get_completion_from_kobject(kobj));
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(f);
|
||||
v->fec = NULL;
|
||||
@ -649,6 +659,28 @@ int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t corrected_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct dm_verity_fec *f = container_of(kobj, struct dm_verity_fec,
|
||||
kobj_holder.kobj);
|
||||
|
||||
return sprintf(buf, "%d\n", atomic_read(&f->corrected));
|
||||
}
|
||||
|
||||
static struct kobj_attribute attr_corrected = __ATTR_RO(corrected);
|
||||
|
||||
static struct attribute *fec_attrs[] = {
|
||||
&attr_corrected.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct kobj_type fec_ktype = {
|
||||
.sysfs_ops = &kobj_sysfs_ops,
|
||||
.default_attrs = fec_attrs,
|
||||
.release = dm_kobject_release
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocate dm_verity_fec for v->fec. Must be called before verity_fec_ctr.
|
||||
*/
|
||||
@ -672,8 +704,10 @@ int verity_fec_ctr_alloc(struct dm_verity *v)
|
||||
*/
|
||||
int verity_fec_ctr(struct dm_verity *v)
|
||||
{
|
||||
int r;
|
||||
struct dm_verity_fec *f = v->fec;
|
||||
struct dm_target *ti = v->ti;
|
||||
struct mapped_device *md = dm_table_get_md(ti->table);
|
||||
u64 hash_blocks;
|
||||
int ret;
|
||||
|
||||
@ -682,6 +716,16 @@ int verity_fec_ctr(struct dm_verity *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a kobject and sysfs attributes */
|
||||
init_completion(&f->kobj_holder.completion);
|
||||
|
||||
r = kobject_init_and_add(&f->kobj_holder.kobj, &fec_ktype,
|
||||
&disk_to_dev(dm_disk(md))->kobj, "%s", "fec");
|
||||
if (r) {
|
||||
ti->error = "Cannot create kobject";
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* FEC is computed over data blocks, possible metadata, and
|
||||
* hash blocks. In other words, FEC covers total of fec_blocks
|
||||
|
@ -12,6 +12,8 @@
|
||||
#ifndef DM_VERITY_FEC_H
|
||||
#define DM_VERITY_FEC_H
|
||||
|
||||
#include "dm.h"
|
||||
#include "dm-core.h"
|
||||
#include "dm-verity.h"
|
||||
#include <linux/rslib.h>
|
||||
|
||||
@ -51,6 +53,8 @@ struct dm_verity_fec {
|
||||
mempool_t extra_pool; /* mempool for extra buffers */
|
||||
mempool_t output_pool; /* mempool for output */
|
||||
struct kmem_cache *cache; /* cache for buffers */
|
||||
atomic_t corrected; /* corrected errors */
|
||||
struct dm_kobject_holder kobj_holder; /* for sysfs attributes */
|
||||
};
|
||||
|
||||
/* per-bio data */
|
||||
|
@ -235,8 +235,12 @@ out:
|
||||
if (v->mode == DM_VERITY_MODE_LOGGING)
|
||||
return 0;
|
||||
|
||||
if (v->mode == DM_VERITY_MODE_RESTART)
|
||||
if (v->mode == DM_VERITY_MODE_RESTART) {
|
||||
#ifdef CONFIG_DM_VERITY_AVB
|
||||
dm_verity_avb_error_handler();
|
||||
#endif
|
||||
kernel_restart("dm-verity device corrupted");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -564,6 +568,7 @@ static void verity_prefetch_io(struct work_struct *work)
|
||||
container_of(work, struct dm_verity_prefetch_work, work);
|
||||
struct dm_verity *v = pw->v;
|
||||
int i;
|
||||
sector_t prefetch_size;
|
||||
|
||||
for (i = v->levels - 2; i >= 0; i--) {
|
||||
sector_t hash_block_start;
|
||||
@ -586,8 +591,14 @@ static void verity_prefetch_io(struct work_struct *work)
|
||||
hash_block_end = v->hash_blocks - 1;
|
||||
}
|
||||
no_prefetch_cluster:
|
||||
// for emmc, it is more efficient to send bigger read
|
||||
prefetch_size = max((sector_t)CONFIG_DM_VERITY_HASH_PREFETCH_MIN_SIZE,
|
||||
hash_block_end - hash_block_start + 1);
|
||||
if ((hash_block_start + prefetch_size) >= (v->hash_start + v->hash_blocks)) {
|
||||
prefetch_size = hash_block_end - hash_block_start + 1;
|
||||
}
|
||||
dm_bufio_prefetch(v->bufio, hash_block_start,
|
||||
hash_block_end - hash_block_start + 1);
|
||||
prefetch_size);
|
||||
}
|
||||
|
||||
kfree(pw);
|
||||
@ -614,7 +625,7 @@ static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io)
|
||||
* Bio map function. It allocates dm_verity_io structure and bio vector and
|
||||
* fills them. Then it issues prefetches and the I/O.
|
||||
*/
|
||||
static int verity_map(struct dm_target *ti, struct bio *bio)
|
||||
int verity_map(struct dm_target *ti, struct bio *bio)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
struct dm_verity_io *io;
|
||||
@ -659,7 +670,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
|
||||
/*
|
||||
* Status: V (valid) or C (corruption found)
|
||||
*/
|
||||
static void verity_status(struct dm_target *ti, status_type_t type,
|
||||
void verity_status(struct dm_target *ti, status_type_t type,
|
||||
unsigned status_flags, char *result, unsigned maxlen)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
@ -723,7 +734,7 @@ static void verity_status(struct dm_target *ti, status_type_t type,
|
||||
}
|
||||
}
|
||||
|
||||
static int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
|
||||
@ -735,7 +746,7 @@ static int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verity_iterate_devices(struct dm_target *ti,
|
||||
int verity_iterate_devices(struct dm_target *ti,
|
||||
iterate_devices_callout_fn fn, void *data)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
@ -743,7 +754,7 @@ static int verity_iterate_devices(struct dm_target *ti,
|
||||
return fn(ti, v->data_dev, v->data_start, ti->len, data);
|
||||
}
|
||||
|
||||
static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
|
||||
void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
|
||||
@ -756,7 +767,7 @@ static void verity_io_hints(struct dm_target *ti, struct queue_limits *limits)
|
||||
blk_limits_io_min(limits, limits->logical_block_size);
|
||||
}
|
||||
|
||||
static void verity_dtr(struct dm_target *ti)
|
||||
void verity_dtr(struct dm_target *ti)
|
||||
{
|
||||
struct dm_verity *v = ti->private;
|
||||
|
||||
@ -911,7 +922,7 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
|
||||
* <digest>
|
||||
* <salt> Hex string or "-" if no salt.
|
||||
*/
|
||||
static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
||||
int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
||||
{
|
||||
struct dm_verity *v;
|
||||
struct dm_arg_set as;
|
||||
@ -1075,6 +1086,14 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED
|
||||
if (!v->validated_blocks) {
|
||||
r = verity_alloc_most_once(v);
|
||||
if (r)
|
||||
goto bad;
|
||||
}
|
||||
#endif
|
||||
|
||||
v->hash_per_block_bits =
|
||||
__fls((1 << v->hash_dev_block_bits) / v->digest_size);
|
||||
|
||||
|
@ -127,4 +127,14 @@ extern int verity_hash(struct dm_verity *v, struct ahash_request *req,
|
||||
extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
|
||||
sector_t block, u8 *digest, bool *is_zero);
|
||||
|
||||
extern void verity_status(struct dm_target *ti, status_type_t type,
|
||||
unsigned status_flags, char *result, unsigned maxlen);
|
||||
extern int verity_prepare_ioctl(struct dm_target *ti, struct block_device **bdev);
|
||||
extern int verity_iterate_devices(struct dm_target *ti,
|
||||
iterate_devices_callout_fn fn, void *data);
|
||||
extern void verity_io_hints(struct dm_target *ti, struct queue_limits *limits);
|
||||
extern void verity_dtr(struct dm_target *ti);
|
||||
extern int verity_ctr(struct dm_target *ti, unsigned argc, char **argv);
|
||||
extern int verity_map(struct dm_target *ti, struct bio *bio);
|
||||
extern void dm_verity_avb_error_handler(void);
|
||||
#endif /* DM_VERITY_H */
|
||||
|
@ -80,8 +80,6 @@ void dm_set_md_type(struct mapped_device *md, enum dm_queue_mode type);
|
||||
enum dm_queue_mode dm_get_md_type(struct mapped_device *md);
|
||||
struct target_type *dm_get_immutable_target_type(struct mapped_device *md);
|
||||
|
||||
int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t);
|
||||
|
||||
/*
|
||||
* To check the return value from dm_table_find_target().
|
||||
*/
|
||||
|
@ -513,6 +513,27 @@ config MISC_RTSX
|
||||
tristate
|
||||
default MISC_RTSX_PCI || MISC_RTSX_USB
|
||||
|
||||
config UID_SYS_STATS
|
||||
bool "Per-UID statistics"
|
||||
depends on PROFILING && TASK_XACCT && TASK_IO_ACCOUNTING
|
||||
help
|
||||
Per UID based cpu time statistics exported to /proc/uid_cputime
|
||||
Per UID based io statistics exported to /proc/uid_io
|
||||
Per UID based procstat control in /proc/uid_procstat
|
||||
|
||||
config UID_SYS_STATS_DEBUG
|
||||
bool "Per-TASK statistics"
|
||||
depends on UID_SYS_STATS
|
||||
default n
|
||||
help
|
||||
Per TASK based io statistics exported to /proc/uid_io
|
||||
|
||||
config MEMORY_STATE_TIME
|
||||
tristate "Memory freq/bandwidth time statistics"
|
||||
depends on PROFILING
|
||||
help
|
||||
Memory time statistics exported to /sys/kernel/memory_state_time
|
||||
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
source "drivers/misc/cb710/Kconfig"
|
||||
|
@ -58,3 +58,5 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
|
||||
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
|
||||
obj-$(CONFIG_OCXL) += ocxl/
|
||||
obj-$(CONFIG_MISC_RTSX) += cardreader/
|
||||
obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o
|
||||
obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o
|
||||
|
462
drivers/misc/memory_state_time.c
Normal file
462
drivers/misc/memory_state_time.c
Normal file
@ -0,0 +1,462 @@
|
||||
/* drivers/misc/memory_state_time.c
|
||||
*
|
||||
* Copyright (C) 2016 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/memory-state-time.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timekeeping.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define KERNEL_ATTR_RO(_name) \
|
||||
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
|
||||
|
||||
#define KERNEL_ATTR_RW(_name) \
|
||||
static struct kobj_attribute _name##_attr = \
|
||||
__ATTR(_name, 0644, _name##_show, _name##_store)
|
||||
|
||||
#define FREQ_HASH_BITS 4
|
||||
DECLARE_HASHTABLE(freq_hash_table, FREQ_HASH_BITS);
|
||||
|
||||
static DEFINE_MUTEX(mem_lock);
|
||||
|
||||
#define TAG "memory_state_time"
|
||||
#define BW_NODE "/soc/memory-state-time"
|
||||
#define FREQ_TBL "freq-tbl"
|
||||
#define BW_TBL "bw-buckets"
|
||||
#define NUM_SOURCES "num-sources"
|
||||
|
||||
#define LOWEST_FREQ 2
|
||||
|
||||
static int curr_bw;
|
||||
static int curr_freq;
|
||||
static u32 *bw_buckets;
|
||||
static u32 *freq_buckets;
|
||||
static int num_freqs;
|
||||
static int num_buckets;
|
||||
static int registered_bw_sources;
|
||||
static u64 last_update;
|
||||
static bool init_success;
|
||||
static struct workqueue_struct *memory_wq;
|
||||
static u32 num_sources = 10;
|
||||
static int *bandwidths;
|
||||
|
||||
struct freq_entry {
|
||||
int freq;
|
||||
u64 *buckets; /* Bandwidth buckets. */
|
||||
struct hlist_node hash;
|
||||
};
|
||||
|
||||
struct queue_container {
|
||||
struct work_struct update_state;
|
||||
int value;
|
||||
u64 time_now;
|
||||
int id;
|
||||
struct mutex *lock;
|
||||
};
|
||||
|
||||
static int find_bucket(int bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (bw_buckets != NULL) {
|
||||
for (i = 0; i < num_buckets; i++) {
|
||||
if (bw_buckets[i] > bw) {
|
||||
pr_debug("Found bucket %d for bandwidth %d\n",
|
||||
i, bw);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return num_buckets - 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 get_time_diff(u64 time_now)
|
||||
{
|
||||
u64 ms;
|
||||
|
||||
ms = time_now - last_update;
|
||||
last_update = time_now;
|
||||
return ms;
|
||||
}
|
||||
|
||||
static ssize_t show_stat_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int i, j;
|
||||
int len = 0;
|
||||
struct freq_entry *freq_entry;
|
||||
|
||||
for (i = 0; i < num_freqs; i++) {
|
||||
hash_for_each_possible(freq_hash_table, freq_entry, hash,
|
||||
freq_buckets[i]) {
|
||||
if (freq_entry->freq == freq_buckets[i]) {
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"%d ", freq_buckets[i]);
|
||||
if (len >= PAGE_SIZE)
|
||||
break;
|
||||
for (j = 0; j < num_buckets; j++) {
|
||||
len += scnprintf(buf + len,
|
||||
PAGE_SIZE - len,
|
||||
"%llu ",
|
||||
freq_entry->buckets[j]);
|
||||
}
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len,
|
||||
"\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
pr_debug("Current Time: %llu\n", ktime_get_boot_ns());
|
||||
return len;
|
||||
}
|
||||
KERNEL_ATTR_RO(show_stat);
|
||||
|
||||
static void update_table(u64 time_now)
|
||||
{
|
||||
struct freq_entry *freq_entry;
|
||||
|
||||
pr_debug("Last known bw %d freq %d\n", curr_bw, curr_freq);
|
||||
hash_for_each_possible(freq_hash_table, freq_entry, hash, curr_freq) {
|
||||
if (curr_freq == freq_entry->freq) {
|
||||
freq_entry->buckets[find_bucket(curr_bw)]
|
||||
+= get_time_diff(time_now);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool freq_exists(int freq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_freqs; i++) {
|
||||
if (freq == freq_buckets[i])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int calculate_total_bw(int bw, int index)
|
||||
{
|
||||
int i;
|
||||
int total_bw = 0;
|
||||
|
||||
pr_debug("memory_state_time New bw %d for id %d\n", bw, index);
|
||||
bandwidths[index] = bw;
|
||||
for (i = 0; i < registered_bw_sources; i++)
|
||||
total_bw += bandwidths[i];
|
||||
return total_bw;
|
||||
}
|
||||
|
||||
static void freq_update_do_work(struct work_struct *work)
|
||||
{
|
||||
struct queue_container *freq_state_update
|
||||
= container_of(work, struct queue_container,
|
||||
update_state);
|
||||
if (freq_state_update) {
|
||||
mutex_lock(&mem_lock);
|
||||
update_table(freq_state_update->time_now);
|
||||
curr_freq = freq_state_update->value;
|
||||
mutex_unlock(&mem_lock);
|
||||
kfree(freq_state_update);
|
||||
}
|
||||
}
|
||||
|
||||
static void bw_update_do_work(struct work_struct *work)
|
||||
{
|
||||
struct queue_container *bw_state_update
|
||||
= container_of(work, struct queue_container,
|
||||
update_state);
|
||||
if (bw_state_update) {
|
||||
mutex_lock(&mem_lock);
|
||||
update_table(bw_state_update->time_now);
|
||||
curr_bw = calculate_total_bw(bw_state_update->value,
|
||||
bw_state_update->id);
|
||||
mutex_unlock(&mem_lock);
|
||||
kfree(bw_state_update);
|
||||
}
|
||||
}
|
||||
|
||||
static void memory_state_freq_update(struct memory_state_update_block *ub,
|
||||
int value)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
|
||||
if (freq_exists(value) && init_success) {
|
||||
struct queue_container *freq_container
|
||||
= kmalloc(sizeof(struct queue_container),
|
||||
GFP_KERNEL);
|
||||
if (!freq_container)
|
||||
return;
|
||||
INIT_WORK(&freq_container->update_state,
|
||||
freq_update_do_work);
|
||||
freq_container->time_now = ktime_get_boot_ns();
|
||||
freq_container->value = value;
|
||||
pr_debug("Scheduling freq update in work queue\n");
|
||||
queue_work(memory_wq, &freq_container->update_state);
|
||||
} else {
|
||||
pr_debug("Freq does not exist.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void memory_state_bw_update(struct memory_state_update_block *ub,
|
||||
int value)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
|
||||
if (init_success) {
|
||||
struct queue_container *bw_container
|
||||
= kmalloc(sizeof(struct queue_container),
|
||||
GFP_KERNEL);
|
||||
if (!bw_container)
|
||||
return;
|
||||
INIT_WORK(&bw_container->update_state,
|
||||
bw_update_do_work);
|
||||
bw_container->time_now = ktime_get_boot_ns();
|
||||
bw_container->value = value;
|
||||
bw_container->id = ub->id;
|
||||
pr_debug("Scheduling bandwidth update in work queue\n");
|
||||
queue_work(memory_wq, &bw_container->update_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct memory_state_update_block *memory_state_register_frequency_source(void)
|
||||
{
|
||||
struct memory_state_update_block *block;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
|
||||
pr_debug("Allocating frequency source\n");
|
||||
block = kmalloc(sizeof(struct memory_state_update_block),
|
||||
GFP_KERNEL);
|
||||
if (!block)
|
||||
return NULL;
|
||||
block->update_call = memory_state_freq_update;
|
||||
return block;
|
||||
}
|
||||
pr_err("Config option disabled.\n");
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(memory_state_register_frequency_source);
|
||||
|
||||
struct memory_state_update_block *memory_state_register_bandwidth_source(void)
|
||||
{
|
||||
struct memory_state_update_block *block;
|
||||
|
||||
if (IS_ENABLED(CONFIG_MEMORY_STATE_TIME)) {
|
||||
pr_debug("Allocating bandwidth source %d\n",
|
||||
registered_bw_sources);
|
||||
block = kmalloc(sizeof(struct memory_state_update_block),
|
||||
GFP_KERNEL);
|
||||
if (!block)
|
||||
return NULL;
|
||||
block->update_call = memory_state_bw_update;
|
||||
if (registered_bw_sources < num_sources) {
|
||||
block->id = registered_bw_sources++;
|
||||
} else {
|
||||
pr_err("Unable to allocate source; max number reached\n");
|
||||
kfree(block);
|
||||
return NULL;
|
||||
}
|
||||
return block;
|
||||
}
|
||||
pr_err("Config option disabled.\n");
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(memory_state_register_bandwidth_source);
|
||||
|
||||
/* Buckets are designated by their maximum.
|
||||
* Returns the buckets decided by the capability of the device.
|
||||
*/
|
||||
static int get_bw_buckets(struct device *dev)
|
||||
{
|
||||
int ret, lenb;
|
||||
struct device_node *node = dev->of_node;
|
||||
|
||||
of_property_read_u32(node, NUM_SOURCES, &num_sources);
|
||||
if (!of_find_property(node, BW_TBL, &lenb)) {
|
||||
pr_err("Missing %s property\n", BW_TBL);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
bandwidths = devm_kzalloc(dev,
|
||||
sizeof(*bandwidths) * num_sources, GFP_KERNEL);
|
||||
if (!bandwidths)
|
||||
return -ENOMEM;
|
||||
lenb /= sizeof(*bw_buckets);
|
||||
bw_buckets = devm_kzalloc(dev, lenb * sizeof(*bw_buckets),
|
||||
GFP_KERNEL);
|
||||
if (!bw_buckets) {
|
||||
devm_kfree(dev, bandwidths);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = of_property_read_u32_array(node, BW_TBL, bw_buckets,
|
||||
lenb);
|
||||
if (ret < 0) {
|
||||
devm_kfree(dev, bandwidths);
|
||||
devm_kfree(dev, bw_buckets);
|
||||
pr_err("Unable to read bandwidth table from device tree.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
curr_bw = 0;
|
||||
num_buckets = lenb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Adds struct freq_entry nodes to the hashtable for each compatible frequency.
|
||||
* Returns the supported number of frequencies.
|
||||
*/
|
||||
static int freq_buckets_init(struct device *dev)
|
||||
{
|
||||
struct freq_entry *freq_entry;
|
||||
int i;
|
||||
int ret, lenf;
|
||||
struct device_node *node = dev->of_node;
|
||||
|
||||
if (!of_find_property(node, FREQ_TBL, &lenf)) {
|
||||
pr_err("Missing %s property\n", FREQ_TBL);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
lenf /= sizeof(*freq_buckets);
|
||||
freq_buckets = devm_kzalloc(dev, lenf * sizeof(*freq_buckets),
|
||||
GFP_KERNEL);
|
||||
if (!freq_buckets)
|
||||
return -ENOMEM;
|
||||
pr_debug("freqs found len %d\n", lenf);
|
||||
ret = of_property_read_u32_array(node, FREQ_TBL, freq_buckets,
|
||||
lenf);
|
||||
if (ret < 0) {
|
||||
devm_kfree(dev, freq_buckets);
|
||||
pr_err("Unable to read frequency table from device tree.\n");
|
||||
return ret;
|
||||
}
|
||||
pr_debug("ret freq %d\n", ret);
|
||||
|
||||
num_freqs = lenf;
|
||||
curr_freq = freq_buckets[LOWEST_FREQ];
|
||||
|
||||
for (i = 0; i < num_freqs; i++) {
|
||||
freq_entry = devm_kzalloc(dev, sizeof(struct freq_entry),
|
||||
GFP_KERNEL);
|
||||
if (!freq_entry)
|
||||
return -ENOMEM;
|
||||
freq_entry->buckets = devm_kzalloc(dev, sizeof(u64)*num_buckets,
|
||||
GFP_KERNEL);
|
||||
if (!freq_entry->buckets) {
|
||||
devm_kfree(dev, freq_entry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
pr_debug("memory_state_time Adding freq to ht %d\n",
|
||||
freq_buckets[i]);
|
||||
freq_entry->freq = freq_buckets[i];
|
||||
hash_add(freq_hash_table, &freq_entry->hash, freq_buckets[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct kobject *memory_kobj;
|
||||
EXPORT_SYMBOL_GPL(memory_kobj);
|
||||
|
||||
static struct attribute *memory_attrs[] = {
|
||||
&show_stat_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group memory_attr_group = {
|
||||
.attrs = memory_attrs,
|
||||
};
|
||||
|
||||
static int memory_state_time_probe(struct platform_device *pdev)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = get_bw_buckets(&pdev->dev);
|
||||
if (error)
|
||||
return error;
|
||||
error = freq_buckets_init(&pdev->dev);
|
||||
if (error)
|
||||
return error;
|
||||
last_update = ktime_get_boot_ns();
|
||||
init_success = true;
|
||||
|
||||
pr_debug("memory_state_time initialized with num_freqs %d\n",
|
||||
num_freqs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id match_table[] = {
|
||||
{ .compatible = "memory-state-time" },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver memory_state_time_driver = {
|
||||
.probe = memory_state_time_probe,
|
||||
.driver = {
|
||||
.name = "memory-state-time",
|
||||
.of_match_table = match_table,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init memory_state_time_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
hash_init(freq_hash_table);
|
||||
memory_wq = create_singlethread_workqueue("memory_wq");
|
||||
if (!memory_wq) {
|
||||
pr_err("Unable to create workqueue.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* Create sys/kernel directory for memory_state_time.
|
||||
*/
|
||||
memory_kobj = kobject_create_and_add(TAG, kernel_kobj);
|
||||
if (!memory_kobj) {
|
||||
pr_err("Unable to allocate memory_kobj for sysfs directory.\n");
|
||||
error = -ENOMEM;
|
||||
goto wq;
|
||||
}
|
||||
error = sysfs_create_group(memory_kobj, &memory_attr_group);
|
||||
if (error) {
|
||||
pr_err("Unable to create sysfs folder.\n");
|
||||
goto kobj;
|
||||
}
|
||||
|
||||
error = platform_driver_register(&memory_state_time_driver);
|
||||
if (error) {
|
||||
pr_err("Unable to register memory_state_time platform driver.\n");
|
||||
goto group;
|
||||
}
|
||||
return 0;
|
||||
|
||||
group: sysfs_remove_group(memory_kobj, &memory_attr_group);
|
||||
kobj: kobject_put(memory_kobj);
|
||||
wq: destroy_workqueue(memory_wq);
|
||||
return error;
|
||||
}
|
||||
module_init(memory_state_time_init);
|
703
drivers/misc/uid_sys_stats.c
Normal file
703
drivers/misc/uid_sys_stats.c
Normal file
@ -0,0 +1,703 @@
|
||||
/* drivers/misc/uid_sys_stats.c
|
||||
*
|
||||
* Copyright (C) 2014 - 2015 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/cpufreq_times.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/rtmutex.h>
|
||||
#include <linux/sched/cputime.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
|
||||
#define UID_HASH_BITS 10
|
||||
DECLARE_HASHTABLE(hash_table, UID_HASH_BITS);
|
||||
|
||||
static DEFINE_RT_MUTEX(uid_lock);
|
||||
static struct proc_dir_entry *cpu_parent;
|
||||
static struct proc_dir_entry *io_parent;
|
||||
static struct proc_dir_entry *proc_parent;
|
||||
|
||||
struct io_stats {
|
||||
u64 read_bytes;
|
||||
u64 write_bytes;
|
||||
u64 rchar;
|
||||
u64 wchar;
|
||||
u64 fsync;
|
||||
};
|
||||
|
||||
#define UID_STATE_FOREGROUND 0
|
||||
#define UID_STATE_BACKGROUND 1
|
||||
#define UID_STATE_BUCKET_SIZE 2
|
||||
|
||||
#define UID_STATE_TOTAL_CURR 2
|
||||
#define UID_STATE_TOTAL_LAST 3
|
||||
#define UID_STATE_DEAD_TASKS 4
|
||||
#define UID_STATE_SIZE 5
|
||||
|
||||
#define MAX_TASK_COMM_LEN 256
|
||||
|
||||
struct task_entry {
|
||||
char comm[MAX_TASK_COMM_LEN];
|
||||
pid_t pid;
|
||||
struct io_stats io[UID_STATE_SIZE];
|
||||
struct hlist_node hash;
|
||||
};
|
||||
|
||||
struct uid_entry {
|
||||
uid_t uid;
|
||||
u64 utime;
|
||||
u64 stime;
|
||||
u64 active_utime;
|
||||
u64 active_stime;
|
||||
int state;
|
||||
struct io_stats io[UID_STATE_SIZE];
|
||||
struct hlist_node hash;
|
||||
#ifdef CONFIG_UID_SYS_STATS_DEBUG
|
||||
DECLARE_HASHTABLE(task_entries, UID_HASH_BITS);
|
||||
#endif
|
||||
};
|
||||
|
||||
static u64 compute_write_bytes(struct task_struct *task)
|
||||
{
|
||||
if (task->ioac.write_bytes <= task->ioac.cancelled_write_bytes)
|
||||
return 0;
|
||||
|
||||
return task->ioac.write_bytes - task->ioac.cancelled_write_bytes;
|
||||
}
|
||||
|
||||
static void compute_io_bucket_stats(struct io_stats *io_bucket,
|
||||
struct io_stats *io_curr,
|
||||
struct io_stats *io_last,
|
||||
struct io_stats *io_dead)
|
||||
{
|
||||
/* tasks could switch to another uid group, but its io_last in the
|
||||
* previous uid group could still be positive.
|
||||
* therefore before each update, do an overflow check first
|
||||
*/
|
||||
int64_t delta;
|
||||
|
||||
delta = io_curr->read_bytes + io_dead->read_bytes -
|
||||
io_last->read_bytes;
|
||||
io_bucket->read_bytes += delta > 0 ? delta : 0;
|
||||
delta = io_curr->write_bytes + io_dead->write_bytes -
|
||||
io_last->write_bytes;
|
||||
io_bucket->write_bytes += delta > 0 ? delta : 0;
|
||||
delta = io_curr->rchar + io_dead->rchar - io_last->rchar;
|
||||
io_bucket->rchar += delta > 0 ? delta : 0;
|
||||
delta = io_curr->wchar + io_dead->wchar - io_last->wchar;
|
||||
io_bucket->wchar += delta > 0 ? delta : 0;
|
||||
delta = io_curr->fsync + io_dead->fsync - io_last->fsync;
|
||||
io_bucket->fsync += delta > 0 ? delta : 0;
|
||||
|
||||
io_last->read_bytes = io_curr->read_bytes;
|
||||
io_last->write_bytes = io_curr->write_bytes;
|
||||
io_last->rchar = io_curr->rchar;
|
||||
io_last->wchar = io_curr->wchar;
|
||||
io_last->fsync = io_curr->fsync;
|
||||
|
||||
memset(io_dead, 0, sizeof(struct io_stats));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UID_SYS_STATS_DEBUG
|
||||
static void get_full_task_comm(struct task_entry *task_entry,
|
||||
struct task_struct *task)
|
||||
{
|
||||
int i = 0, offset = 0, len = 0;
|
||||
/* save one byte for terminating null character */
|
||||
int unused_len = MAX_TASK_COMM_LEN - TASK_COMM_LEN - 1;
|
||||
char buf[unused_len];
|
||||
struct mm_struct *mm = task->mm;
|
||||
|
||||
/* fill the first TASK_COMM_LEN bytes with thread name */
|
||||
__get_task_comm(task_entry->comm, TASK_COMM_LEN, task);
|
||||
i = strlen(task_entry->comm);
|
||||
while (i < TASK_COMM_LEN)
|
||||
task_entry->comm[i++] = ' ';
|
||||
|
||||
/* next the executable file name */
|
||||
if (mm) {
|
||||
down_read(&mm->mmap_sem);
|
||||
if (mm->exe_file) {
|
||||
char *pathname = d_path(&mm->exe_file->f_path, buf,
|
||||
unused_len);
|
||||
|
||||
if (!IS_ERR(pathname)) {
|
||||
len = strlcpy(task_entry->comm + i, pathname,
|
||||
unused_len);
|
||||
i += len;
|
||||
task_entry->comm[i++] = ' ';
|
||||
unused_len--;
|
||||
}
|
||||
}
|
||||
up_read(&mm->mmap_sem);
|
||||
}
|
||||
unused_len -= len;
|
||||
|
||||
/* fill the rest with command line argument
|
||||
* replace each null or new line character
|
||||
* between args in argv with whitespace */
|
||||
len = get_cmdline(task, buf, unused_len);
|
||||
while (offset < len) {
|
||||
if (buf[offset] != '\0' && buf[offset] != '\n')
|
||||
task_entry->comm[i++] = buf[offset];
|
||||
else
|
||||
task_entry->comm[i++] = ' ';
|
||||
offset++;
|
||||
}
|
||||
|
||||
/* get rid of trailing whitespaces in case when arg is memset to
|
||||
* zero before being reset in userspace
|
||||
*/
|
||||
while (task_entry->comm[i-1] == ' ')
|
||||
i--;
|
||||
task_entry->comm[i] = '\0';
|
||||
}
|
||||
|
||||
static struct task_entry *find_task_entry(struct uid_entry *uid_entry,
|
||||
struct task_struct *task)
|
||||
{
|
||||
struct task_entry *task_entry;
|
||||
|
||||
hash_for_each_possible(uid_entry->task_entries, task_entry, hash,
|
||||
task->pid) {
|
||||
if (task->pid == task_entry->pid) {
|
||||
/* if thread name changed, update the entire command */
|
||||
int len = strnchr(task_entry->comm, ' ', TASK_COMM_LEN)
|
||||
- task_entry->comm;
|
||||
|
||||
if (strncmp(task_entry->comm, task->comm, len))
|
||||
get_full_task_comm(task_entry, task);
|
||||
return task_entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct task_entry *find_or_register_task(struct uid_entry *uid_entry,
|
||||
struct task_struct *task)
|
||||
{
|
||||
struct task_entry *task_entry;
|
||||
pid_t pid = task->pid;
|
||||
|
||||
task_entry = find_task_entry(uid_entry, task);
|
||||
if (task_entry)
|
||||
return task_entry;
|
||||
|
||||
task_entry = kzalloc(sizeof(struct task_entry), GFP_ATOMIC);
|
||||
if (!task_entry)
|
||||
return NULL;
|
||||
|
||||
get_full_task_comm(task_entry, task);
|
||||
|
||||
task_entry->pid = pid;
|
||||
hash_add(uid_entry->task_entries, &task_entry->hash, (unsigned int)pid);
|
||||
|
||||
return task_entry;
|
||||
}
|
||||
|
||||
static void remove_uid_tasks(struct uid_entry *uid_entry)
|
||||
{
|
||||
struct task_entry *task_entry;
|
||||
unsigned long bkt_task;
|
||||
struct hlist_node *tmp_task;
|
||||
|
||||
hash_for_each_safe(uid_entry->task_entries, bkt_task,
|
||||
tmp_task, task_entry, hash) {
|
||||
hash_del(&task_entry->hash);
|
||||
kfree(task_entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_io_uid_tasks_zero(struct uid_entry *uid_entry)
|
||||
{
|
||||
struct task_entry *task_entry;
|
||||
unsigned long bkt_task;
|
||||
|
||||
hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
|
||||
memset(&task_entry->io[UID_STATE_TOTAL_CURR], 0,
|
||||
sizeof(struct io_stats));
|
||||
}
|
||||
}
|
||||
|
||||
static void add_uid_tasks_io_stats(struct uid_entry *uid_entry,
|
||||
struct task_struct *task, int slot)
|
||||
{
|
||||
struct task_entry *task_entry = find_or_register_task(uid_entry, task);
|
||||
struct io_stats *task_io_slot = &task_entry->io[slot];
|
||||
|
||||
task_io_slot->read_bytes += task->ioac.read_bytes;
|
||||
task_io_slot->write_bytes += compute_write_bytes(task);
|
||||
task_io_slot->rchar += task->ioac.rchar;
|
||||
task_io_slot->wchar += task->ioac.wchar;
|
||||
task_io_slot->fsync += task->ioac.syscfs;
|
||||
}
|
||||
|
||||
static void compute_io_uid_tasks(struct uid_entry *uid_entry)
|
||||
{
|
||||
struct task_entry *task_entry;
|
||||
unsigned long bkt_task;
|
||||
|
||||
hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
|
||||
compute_io_bucket_stats(&task_entry->io[uid_entry->state],
|
||||
&task_entry->io[UID_STATE_TOTAL_CURR],
|
||||
&task_entry->io[UID_STATE_TOTAL_LAST],
|
||||
&task_entry->io[UID_STATE_DEAD_TASKS]);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_io_uid_tasks(struct seq_file *m, struct uid_entry *uid_entry)
|
||||
{
|
||||
struct task_entry *task_entry;
|
||||
unsigned long bkt_task;
|
||||
|
||||
hash_for_each(uid_entry->task_entries, bkt_task, task_entry, hash) {
|
||||
/* Separated by comma because space exists in task comm */
|
||||
seq_printf(m, "task,%s,%lu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu\n",
|
||||
task_entry->comm,
|
||||
(unsigned long)task_entry->pid,
|
||||
task_entry->io[UID_STATE_FOREGROUND].rchar,
|
||||
task_entry->io[UID_STATE_FOREGROUND].wchar,
|
||||
task_entry->io[UID_STATE_FOREGROUND].read_bytes,
|
||||
task_entry->io[UID_STATE_FOREGROUND].write_bytes,
|
||||
task_entry->io[UID_STATE_BACKGROUND].rchar,
|
||||
task_entry->io[UID_STATE_BACKGROUND].wchar,
|
||||
task_entry->io[UID_STATE_BACKGROUND].read_bytes,
|
||||
task_entry->io[UID_STATE_BACKGROUND].write_bytes,
|
||||
task_entry->io[UID_STATE_FOREGROUND].fsync,
|
||||
task_entry->io[UID_STATE_BACKGROUND].fsync);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void remove_uid_tasks(struct uid_entry *uid_entry) {};
|
||||
static void set_io_uid_tasks_zero(struct uid_entry *uid_entry) {};
|
||||
static void add_uid_tasks_io_stats(struct uid_entry *uid_entry,
|
||||
struct task_struct *task, int slot) {};
|
||||
static void compute_io_uid_tasks(struct uid_entry *uid_entry) {};
|
||||
static void show_io_uid_tasks(struct seq_file *m,
|
||||
struct uid_entry *uid_entry) {}
|
||||
#endif
|
||||
|
||||
static struct uid_entry *find_uid_entry(uid_t uid)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
hash_for_each_possible(hash_table, uid_entry, hash, uid) {
|
||||
if (uid_entry->uid == uid)
|
||||
return uid_entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct uid_entry *find_or_register_uid(uid_t uid)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
|
||||
uid_entry = find_uid_entry(uid);
|
||||
if (uid_entry)
|
||||
return uid_entry;
|
||||
|
||||
uid_entry = kzalloc(sizeof(struct uid_entry), GFP_ATOMIC);
|
||||
if (!uid_entry)
|
||||
return NULL;
|
||||
|
||||
uid_entry->uid = uid;
|
||||
#ifdef CONFIG_UID_SYS_STATS_DEBUG
|
||||
hash_init(uid_entry->task_entries);
|
||||
#endif
|
||||
hash_add(hash_table, &uid_entry->hash, uid);
|
||||
|
||||
return uid_entry;
|
||||
}
|
||||
|
||||
static int uid_cputime_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct uid_entry *uid_entry = NULL;
|
||||
struct task_struct *task, *temp;
|
||||
struct user_namespace *user_ns = current_user_ns();
|
||||
u64 utime;
|
||||
u64 stime;
|
||||
unsigned long bkt;
|
||||
uid_t uid;
|
||||
|
||||
rt_mutex_lock(&uid_lock);
|
||||
|
||||
hash_for_each(hash_table, bkt, uid_entry, hash) {
|
||||
uid_entry->active_stime = 0;
|
||||
uid_entry->active_utime = 0;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
do_each_thread(temp, task) {
|
||||
uid = from_kuid_munged(user_ns, task_uid(task));
|
||||
if (!uid_entry || uid_entry->uid != uid)
|
||||
uid_entry = find_or_register_uid(uid);
|
||||
if (!uid_entry) {
|
||||
rcu_read_unlock();
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
pr_err("%s: failed to find the uid_entry for uid %d\n",
|
||||
__func__, uid);
|
||||
return -ENOMEM;
|
||||
}
|
||||
task_cputime_adjusted(task, &utime, &stime);
|
||||
uid_entry->active_utime += utime;
|
||||
uid_entry->active_stime += stime;
|
||||
} while_each_thread(temp, task);
|
||||
rcu_read_unlock();
|
||||
|
||||
hash_for_each(hash_table, bkt, uid_entry, hash) {
|
||||
u64 total_utime = uid_entry->utime +
|
||||
uid_entry->active_utime;
|
||||
u64 total_stime = uid_entry->stime +
|
||||
uid_entry->active_stime;
|
||||
seq_printf(m, "%d: %llu %llu\n", uid_entry->uid,
|
||||
ktime_to_ms(total_utime), ktime_to_ms(total_stime));
|
||||
}
|
||||
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uid_cputime_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, uid_cputime_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations uid_cputime_fops = {
|
||||
.open = uid_cputime_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int uid_remove_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, NULL, NULL);
|
||||
}
|
||||
|
||||
static ssize_t uid_remove_write(struct file *file,
|
||||
const char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
struct hlist_node *tmp;
|
||||
char uids[128];
|
||||
char *start_uid, *end_uid = NULL;
|
||||
long int uid_start = 0, uid_end = 0;
|
||||
|
||||
if (count >= sizeof(uids))
|
||||
count = sizeof(uids) - 1;
|
||||
|
||||
if (copy_from_user(uids, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
uids[count] = '\0';
|
||||
end_uid = uids;
|
||||
start_uid = strsep(&end_uid, "-");
|
||||
|
||||
if (!start_uid || !end_uid)
|
||||
return -EINVAL;
|
||||
|
||||
if (kstrtol(start_uid, 10, &uid_start) != 0 ||
|
||||
kstrtol(end_uid, 10, &uid_end) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Also remove uids from /proc/uid_time_in_state */
|
||||
cpufreq_task_times_remove_uids(uid_start, uid_end);
|
||||
|
||||
rt_mutex_lock(&uid_lock);
|
||||
|
||||
for (; uid_start <= uid_end; uid_start++) {
|
||||
hash_for_each_possible_safe(hash_table, uid_entry, tmp,
|
||||
hash, (uid_t)uid_start) {
|
||||
if (uid_start == uid_entry->uid) {
|
||||
remove_uid_tasks(uid_entry);
|
||||
hash_del(&uid_entry->hash);
|
||||
kfree(uid_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations uid_remove_fops = {
|
||||
.open = uid_remove_open,
|
||||
.release = single_release,
|
||||
.write = uid_remove_write,
|
||||
};
|
||||
|
||||
|
||||
static void add_uid_io_stats(struct uid_entry *uid_entry,
|
||||
struct task_struct *task, int slot)
|
||||
{
|
||||
struct io_stats *io_slot = &uid_entry->io[slot];
|
||||
|
||||
io_slot->read_bytes += task->ioac.read_bytes;
|
||||
io_slot->write_bytes += compute_write_bytes(task);
|
||||
io_slot->rchar += task->ioac.rchar;
|
||||
io_slot->wchar += task->ioac.wchar;
|
||||
io_slot->fsync += task->ioac.syscfs;
|
||||
|
||||
add_uid_tasks_io_stats(uid_entry, task, slot);
|
||||
}
|
||||
|
||||
static void update_io_stats_all_locked(void)
|
||||
{
|
||||
struct uid_entry *uid_entry = NULL;
|
||||
struct task_struct *task, *temp;
|
||||
struct user_namespace *user_ns = current_user_ns();
|
||||
unsigned long bkt;
|
||||
uid_t uid;
|
||||
|
||||
hash_for_each(hash_table, bkt, uid_entry, hash) {
|
||||
memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
|
||||
sizeof(struct io_stats));
|
||||
set_io_uid_tasks_zero(uid_entry);
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
do_each_thread(temp, task) {
|
||||
uid = from_kuid_munged(user_ns, task_uid(task));
|
||||
if (!uid_entry || uid_entry->uid != uid)
|
||||
uid_entry = find_or_register_uid(uid);
|
||||
if (!uid_entry)
|
||||
continue;
|
||||
add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR);
|
||||
} while_each_thread(temp, task);
|
||||
rcu_read_unlock();
|
||||
|
||||
hash_for_each(hash_table, bkt, uid_entry, hash) {
|
||||
compute_io_bucket_stats(&uid_entry->io[uid_entry->state],
|
||||
&uid_entry->io[UID_STATE_TOTAL_CURR],
|
||||
&uid_entry->io[UID_STATE_TOTAL_LAST],
|
||||
&uid_entry->io[UID_STATE_DEAD_TASKS]);
|
||||
compute_io_uid_tasks(uid_entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_io_stats_uid_locked(struct uid_entry *uid_entry)
|
||||
{
|
||||
struct task_struct *task, *temp;
|
||||
struct user_namespace *user_ns = current_user_ns();
|
||||
|
||||
memset(&uid_entry->io[UID_STATE_TOTAL_CURR], 0,
|
||||
sizeof(struct io_stats));
|
||||
set_io_uid_tasks_zero(uid_entry);
|
||||
|
||||
rcu_read_lock();
|
||||
do_each_thread(temp, task) {
|
||||
if (from_kuid_munged(user_ns, task_uid(task)) != uid_entry->uid)
|
||||
continue;
|
||||
add_uid_io_stats(uid_entry, task, UID_STATE_TOTAL_CURR);
|
||||
} while_each_thread(temp, task);
|
||||
rcu_read_unlock();
|
||||
|
||||
compute_io_bucket_stats(&uid_entry->io[uid_entry->state],
|
||||
&uid_entry->io[UID_STATE_TOTAL_CURR],
|
||||
&uid_entry->io[UID_STATE_TOTAL_LAST],
|
||||
&uid_entry->io[UID_STATE_DEAD_TASKS]);
|
||||
compute_io_uid_tasks(uid_entry);
|
||||
}
|
||||
|
||||
|
||||
static int uid_io_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
unsigned long bkt;
|
||||
|
||||
rt_mutex_lock(&uid_lock);
|
||||
|
||||
update_io_stats_all_locked();
|
||||
|
||||
hash_for_each(hash_table, bkt, uid_entry, hash) {
|
||||
seq_printf(m, "%d %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n",
|
||||
uid_entry->uid,
|
||||
uid_entry->io[UID_STATE_FOREGROUND].rchar,
|
||||
uid_entry->io[UID_STATE_FOREGROUND].wchar,
|
||||
uid_entry->io[UID_STATE_FOREGROUND].read_bytes,
|
||||
uid_entry->io[UID_STATE_FOREGROUND].write_bytes,
|
||||
uid_entry->io[UID_STATE_BACKGROUND].rchar,
|
||||
uid_entry->io[UID_STATE_BACKGROUND].wchar,
|
||||
uid_entry->io[UID_STATE_BACKGROUND].read_bytes,
|
||||
uid_entry->io[UID_STATE_BACKGROUND].write_bytes,
|
||||
uid_entry->io[UID_STATE_FOREGROUND].fsync,
|
||||
uid_entry->io[UID_STATE_BACKGROUND].fsync);
|
||||
|
||||
show_io_uid_tasks(m, uid_entry);
|
||||
}
|
||||
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uid_io_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, uid_io_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations uid_io_fops = {
|
||||
.open = uid_io_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int uid_procstat_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, NULL, NULL);
|
||||
}
|
||||
|
||||
static ssize_t uid_procstat_write(struct file *file,
|
||||
const char __user *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct uid_entry *uid_entry;
|
||||
uid_t uid;
|
||||
int argc, state;
|
||||
char input[128];
|
||||
|
||||
if (count >= sizeof(input))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(input, buffer, count))
|
||||
return -EFAULT;
|
||||
|
||||
input[count] = '\0';
|
||||
|
||||
argc = sscanf(input, "%u %d", &uid, &state);
|
||||
if (argc != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (state != UID_STATE_BACKGROUND && state != UID_STATE_FOREGROUND)
|
||||
return -EINVAL;
|
||||
|
||||
rt_mutex_lock(&uid_lock);
|
||||
|
||||
uid_entry = find_or_register_uid(uid);
|
||||
if (!uid_entry) {
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uid_entry->state == state) {
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
update_io_stats_uid_locked(uid_entry);
|
||||
|
||||
uid_entry->state = state;
|
||||
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations uid_procstat_fops = {
|
||||
.open = uid_procstat_open,
|
||||
.release = single_release,
|
||||
.write = uid_procstat_write,
|
||||
};
|
||||
|
||||
static int process_notifier(struct notifier_block *self,
|
||||
unsigned long cmd, void *v)
|
||||
{
|
||||
struct task_struct *task = v;
|
||||
struct uid_entry *uid_entry;
|
||||
u64 utime, stime;
|
||||
uid_t uid;
|
||||
|
||||
if (!task)
|
||||
return NOTIFY_OK;
|
||||
|
||||
rt_mutex_lock(&uid_lock);
|
||||
uid = from_kuid_munged(current_user_ns(), task_uid(task));
|
||||
uid_entry = find_or_register_uid(uid);
|
||||
if (!uid_entry) {
|
||||
pr_err("%s: failed to find uid %d\n", __func__, uid);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
task_cputime_adjusted(task, &utime, &stime);
|
||||
uid_entry->utime += utime;
|
||||
uid_entry->stime += stime;
|
||||
|
||||
add_uid_io_stats(uid_entry, task, UID_STATE_DEAD_TASKS);
|
||||
|
||||
exit:
|
||||
rt_mutex_unlock(&uid_lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block process_notifier_block = {
|
||||
.notifier_call = process_notifier,
|
||||
};
|
||||
|
||||
static int __init proc_uid_sys_stats_init(void)
|
||||
{
|
||||
hash_init(hash_table);
|
||||
|
||||
cpu_parent = proc_mkdir("uid_cputime", NULL);
|
||||
if (!cpu_parent) {
|
||||
pr_err("%s: failed to create uid_cputime proc entry\n",
|
||||
__func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
proc_create_data("remove_uid_range", 0222, cpu_parent,
|
||||
&uid_remove_fops, NULL);
|
||||
proc_create_data("show_uid_stat", 0444, cpu_parent,
|
||||
&uid_cputime_fops, NULL);
|
||||
|
||||
io_parent = proc_mkdir("uid_io", NULL);
|
||||
if (!io_parent) {
|
||||
pr_err("%s: failed to create uid_io proc entry\n",
|
||||
__func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
proc_create_data("stats", 0444, io_parent,
|
||||
&uid_io_fops, NULL);
|
||||
|
||||
proc_parent = proc_mkdir("uid_procstat", NULL);
|
||||
if (!proc_parent) {
|
||||
pr_err("%s: failed to create uid_procstat proc entry\n",
|
||||
__func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
proc_create_data("set", 0222, proc_parent,
|
||||
&uid_procstat_fops, NULL);
|
||||
|
||||
profile_event_register(PROFILE_TASK_EXIT, &process_notifier_block);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
remove_proc_subtree("uid_cputime", NULL);
|
||||
remove_proc_subtree("uid_io", NULL);
|
||||
remove_proc_subtree("uid_procstat", NULL);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
early_initcall(proc_uid_sys_stats_init);
|
@ -441,7 +441,8 @@ int mmc_add_host(struct mmc_host *host)
|
||||
#endif
|
||||
|
||||
mmc_start_host(host);
|
||||
mmc_register_pm_notifier(host);
|
||||
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
|
||||
mmc_register_pm_notifier(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -458,7 +459,8 @@ EXPORT_SYMBOL(mmc_add_host);
|
||||
*/
|
||||
void mmc_remove_host(struct mmc_host *host)
|
||||
{
|
||||
mmc_unregister_pm_notifier(host);
|
||||
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
|
||||
mmc_unregister_pm_notifier(host);
|
||||
mmc_stop_host(host);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
@ -2879,6 +2879,12 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
|
||||
int ret;
|
||||
bool do_notify = false;
|
||||
|
||||
#ifdef CONFIG_ANDROID_PARANOID_NETWORK
|
||||
if (cmd != TUNGETIFF && !capable(CAP_NET_ADMIN)) {
|
||||
return -EPERM;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cmd == TUNSETIFF || cmd == TUNSETQUEUE ||
|
||||
(_IOC_TYPE(cmd) == SOCK_IOC_TYPE && cmd != SIOCGSKNS)) {
|
||||
if (copy_from_user(&ifr, argp, ifreq_len))
|
||||
|
@ -549,6 +549,11 @@ static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Disable filtering */
|
||||
ret = wl1271_acx_group_address_tbl(wl, wlvif, false, NULL, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -176,6 +176,16 @@ static int fdp_nci_i2c_read(struct fdp_i2c_phy *phy, struct sk_buff **skb)
|
||||
/* Packet that contains a length */
|
||||
if (tmp[0] == 0 && tmp[1] == 0) {
|
||||
phy->next_read_size = (tmp[2] << 8) + tmp[3] + 3;
|
||||
/*
|
||||
* Ensure next_read_size does not exceed sizeof(tmp)
|
||||
* for reading that many bytes during next iteration
|
||||
*/
|
||||
if (phy->next_read_size > FDP_NCI_I2C_MAX_PAYLOAD) {
|
||||
dev_dbg(&client->dev, "%s: corrupted packet\n",
|
||||
__func__);
|
||||
phy->next_read_size = 5;
|
||||
goto flush;
|
||||
}
|
||||
} else {
|
||||
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
|
||||
|
||||
|
@ -217,7 +217,8 @@ static int st21nfca_tm_recv_atr_req(struct nfc_hci_dev *hdev,
|
||||
|
||||
atr_req = (struct st21nfca_atr_req *)skb->data;
|
||||
|
||||
if (atr_req->length < sizeof(struct st21nfca_atr_req)) {
|
||||
if (atr_req->length < sizeof(struct st21nfca_atr_req) ||
|
||||
atr_req->length > skb->len) {
|
||||
r = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -322,23 +322,33 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
|
||||
* AID 81 5 to 16
|
||||
* PARAMETERS 82 0 to 255
|
||||
*/
|
||||
if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
|
||||
if (skb->len < NFC_MIN_AID_LENGTH + 2 ||
|
||||
skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
|
||||
return -EPROTO;
|
||||
|
||||
/*
|
||||
* Buffer should have enough space for at least
|
||||
* two tag fields + two length fields + aid_len (skb->data[1])
|
||||
*/
|
||||
if (skb->len < skb->data[1] + 4)
|
||||
return -EPROTO;
|
||||
|
||||
transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
|
||||
skb->len - 2, GFP_KERNEL);
|
||||
|
||||
transaction->aid_len = skb->data[1];
|
||||
memcpy(transaction->aid, &skb->data[2],
|
||||
transaction->aid_len);
|
||||
|
||||
/* Check next byte is PARAMETERS tag (82) */
|
||||
if (skb->data[transaction->aid_len + 2] !=
|
||||
NFC_EVT_TRANSACTION_PARAMS_TAG)
|
||||
return -EPROTO;
|
||||
|
||||
transaction->params_len = skb->data[transaction->aid_len + 3];
|
||||
|
||||
/* Check next byte is PARAMETERS tag (82) and the length field */
|
||||
if (skb->data[transaction->aid_len + 2] !=
|
||||
NFC_EVT_TRANSACTION_PARAMS_TAG ||
|
||||
skb->len < transaction->aid_len + transaction->params_len + 4) {
|
||||
devm_kfree(dev, transaction);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
memcpy(transaction->params, skb->data +
|
||||
transaction->aid_len + 4, transaction->params_len);
|
||||
|
||||
|
@ -1072,42 +1072,66 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert configs to something easy to use in C code
|
||||
*/
|
||||
#if defined(CONFIG_CMDLINE_FORCE)
|
||||
static const int overwrite_incoming_cmdline = 1;
|
||||
static const int read_dt_cmdline;
|
||||
static const int concat_cmdline;
|
||||
#elif defined(CONFIG_CMDLINE_EXTEND)
|
||||
static const int overwrite_incoming_cmdline;
|
||||
static const int read_dt_cmdline = 1;
|
||||
static const int concat_cmdline = 1;
|
||||
#else /* CMDLINE_FROM_BOOTLOADER */
|
||||
static const int overwrite_incoming_cmdline;
|
||||
static const int read_dt_cmdline = 1;
|
||||
static const int concat_cmdline;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CMDLINE
|
||||
static const char *config_cmdline = CONFIG_CMDLINE;
|
||||
#else
|
||||
static const char *config_cmdline = "";
|
||||
#endif
|
||||
|
||||
int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
|
||||
int depth, void *data)
|
||||
{
|
||||
int l;
|
||||
const char *p;
|
||||
int l = 0;
|
||||
const char *p = NULL;
|
||||
char *cmdline = data;
|
||||
|
||||
pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
|
||||
|
||||
if (depth != 1 || !data ||
|
||||
if (depth != 1 || !cmdline ||
|
||||
(strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
|
||||
return 0;
|
||||
|
||||
early_init_dt_check_for_initrd(node);
|
||||
|
||||
/* Retrieve command line */
|
||||
p = of_get_flat_dt_prop(node, "bootargs", &l);
|
||||
if (p != NULL && l > 0)
|
||||
strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
|
||||
/* Put CONFIG_CMDLINE in if forced or if data had nothing in it to start */
|
||||
if (overwrite_incoming_cmdline || !cmdline[0])
|
||||
strlcpy(cmdline, config_cmdline, COMMAND_LINE_SIZE);
|
||||
|
||||
/*
|
||||
* CONFIG_CMDLINE is meant to be a default in case nothing else
|
||||
* managed to set the command line, unless CONFIG_CMDLINE_FORCE
|
||||
* is set in which case we override whatever was found earlier.
|
||||
*/
|
||||
#ifdef CONFIG_CMDLINE
|
||||
#if defined(CONFIG_CMDLINE_EXTEND)
|
||||
strlcat(data, " ", COMMAND_LINE_SIZE);
|
||||
strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
|
||||
#elif defined(CONFIG_CMDLINE_FORCE)
|
||||
strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
|
||||
#else
|
||||
/* No arguments from boot loader, use kernel's cmdl*/
|
||||
if (!((char *)data)[0])
|
||||
strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
|
||||
#endif
|
||||
#endif /* CONFIG_CMDLINE */
|
||||
/* Retrieve command line unless forcing */
|
||||
if (read_dt_cmdline)
|
||||
p = of_get_flat_dt_prop(node, "bootargs", &l);
|
||||
|
||||
if (p != NULL && l > 0) {
|
||||
if (concat_cmdline) {
|
||||
int cmdline_len;
|
||||
int copy_len;
|
||||
strlcat(cmdline, " ", COMMAND_LINE_SIZE);
|
||||
cmdline_len = strlen(cmdline);
|
||||
copy_len = COMMAND_LINE_SIZE - cmdline_len - 1;
|
||||
copy_len = min((int)l, copy_len);
|
||||
strncpy(cmdline + cmdline_len, p, copy_len);
|
||||
cmdline[cmdline_len + copy_len] = '\0';
|
||||
} else {
|
||||
strlcpy(cmdline, p, min((int)l, COMMAND_LINE_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("Command line is: %s\n", (char*)data);
|
||||
|
||||
|
@ -171,6 +171,9 @@ static ssize_t power_supply_show_property(struct device *dev,
|
||||
ret = sprintf(buf, "%s\n",
|
||||
power_supply_scope_text[value.intval]);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT:
|
||||
ret = sprintf(buf, "%lld\n", value.int64val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME ... POWER_SUPPLY_PROP_SERIAL_NUMBER:
|
||||
ret = sprintf(buf, "%s\n", value.strval);
|
||||
break;
|
||||
@ -302,6 +305,12 @@ static struct device_attribute power_supply_attrs[] = {
|
||||
POWER_SUPPLY_ATTR(precharge_current),
|
||||
POWER_SUPPLY_ATTR(charge_term_current),
|
||||
POWER_SUPPLY_ATTR(calibrate),
|
||||
/* Local extensions */
|
||||
POWER_SUPPLY_ATTR(usb_hc),
|
||||
POWER_SUPPLY_ATTR(usb_otg),
|
||||
POWER_SUPPLY_ATTR(charge_enabled),
|
||||
/* Local extensions of type int64_t */
|
||||
POWER_SUPPLY_ATTR(charge_counter_ext),
|
||||
/* Properties of type `const char *' */
|
||||
POWER_SUPPLY_ATTR(model_name),
|
||||
POWER_SUPPLY_ATTR(manufacturer),
|
||||
|
@ -226,6 +226,12 @@ config USB_F_CDEV
|
||||
config USB_F_CCID
|
||||
tristate
|
||||
|
||||
config USB_F_AUDIO_SRC
|
||||
tristate
|
||||
|
||||
config USB_F_ACC
|
||||
tristate
|
||||
|
||||
# this first set of drivers all depend on bulk-capable hardware.
|
||||
|
||||
config USB_CONFIGFS
|
||||
@ -379,6 +385,30 @@ config USB_CONFIGFS_F_FS
|
||||
implemented in kernel space (for instance Ethernet, serial or
|
||||
mass storage) and other are implemented in user space.
|
||||
|
||||
config USB_CONFIGFS_F_ACC
|
||||
bool "Accessory gadget"
|
||||
depends on USB_CONFIGFS
|
||||
select USB_F_ACC
|
||||
help
|
||||
USB gadget Accessory support
|
||||
|
||||
config USB_CONFIGFS_F_AUDIO_SRC
|
||||
bool "Audio Source gadget"
|
||||
depends on USB_CONFIGFS && USB_CONFIGFS_F_ACC
|
||||
depends on SND
|
||||
select SND_PCM
|
||||
select USB_F_AUDIO_SRC
|
||||
help
|
||||
USB gadget Audio Source support
|
||||
|
||||
config USB_CONFIGFS_UEVENT
|
||||
bool "Uevent notification of Gadget state"
|
||||
depends on USB_CONFIGFS
|
||||
help
|
||||
Enable uevent notifications to userspace when the gadget
|
||||
state changes. The gadget can be in any of the following
|
||||
three states: "CONNECTED/DISCONNECTED/CONFIGURED"
|
||||
|
||||
config USB_CONFIGFS_F_UAC1
|
||||
bool "Audio Class 1.0"
|
||||
depends on USB_CONFIGFS
|
||||
|
@ -10,6 +10,31 @@
|
||||
#include "u_f.h"
|
||||
#include "u_os_desc.h"
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_F_ACC
|
||||
extern int acc_ctrlrequest(struct usb_composite_dev *cdev,
|
||||
const struct usb_ctrlrequest *ctrl);
|
||||
void acc_disconnect(void);
|
||||
#endif
|
||||
static struct class *android_class;
|
||||
static struct device *android_device;
|
||||
static int index;
|
||||
|
||||
struct device *create_function_device(char *name)
|
||||
{
|
||||
if (android_device && !IS_ERR(android_device))
|
||||
return device_create(android_class, android_device,
|
||||
MKDEV(0, index++), NULL, name);
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(create_function_device);
|
||||
#endif
|
||||
|
||||
int check_user_usb_string(const char *name,
|
||||
struct usb_gadget_strings *stringtab_dev)
|
||||
{
|
||||
@ -61,6 +86,12 @@ struct gadget_info {
|
||||
bool use_os_desc;
|
||||
char b_vendor_code;
|
||||
char qw_sign[OS_STRING_QW_SIGN_LEN];
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
bool connected;
|
||||
bool sw_connected;
|
||||
struct work_struct work;
|
||||
struct device *dev;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct gadget_info *to_gadget_info(struct config_item *item)
|
||||
@ -266,7 +297,7 @@ static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
|
||||
|
||||
mutex_lock(&gi->lock);
|
||||
|
||||
if (!strlen(name)) {
|
||||
if (!strlen(name) || strcmp(name, "none") == 0) {
|
||||
ret = unregister_gadget(gi);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -1372,6 +1403,60 @@ err_comp_cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
static void android_work(struct work_struct *data)
|
||||
{
|
||||
struct gadget_info *gi = container_of(data, struct gadget_info, work);
|
||||
struct usb_composite_dev *cdev = &gi->cdev;
|
||||
char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
|
||||
char *connected[2] = { "USB_STATE=CONNECTED", NULL };
|
||||
char *configured[2] = { "USB_STATE=CONFIGURED", NULL };
|
||||
/* 0-connected 1-configured 2-disconnected*/
|
||||
bool status[3] = { false, false, false };
|
||||
unsigned long flags;
|
||||
bool uevent_sent = false;
|
||||
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
if (cdev->config)
|
||||
status[1] = true;
|
||||
|
||||
if (gi->connected != gi->sw_connected) {
|
||||
if (gi->connected)
|
||||
status[0] = true;
|
||||
else
|
||||
status[2] = true;
|
||||
gi->sw_connected = gi->connected;
|
||||
}
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
|
||||
if (status[0]) {
|
||||
kobject_uevent_env(&android_device->kobj,
|
||||
KOBJ_CHANGE, connected);
|
||||
pr_info("%s: sent uevent %s\n", __func__, connected[0]);
|
||||
uevent_sent = true;
|
||||
}
|
||||
|
||||
if (status[1]) {
|
||||
kobject_uevent_env(&android_device->kobj,
|
||||
KOBJ_CHANGE, configured);
|
||||
pr_info("%s: sent uevent %s\n", __func__, configured[0]);
|
||||
uevent_sent = true;
|
||||
}
|
||||
|
||||
if (status[2]) {
|
||||
kobject_uevent_env(&android_device->kobj,
|
||||
KOBJ_CHANGE, disconnected);
|
||||
pr_info("%s: sent uevent %s\n", __func__, disconnected[0]);
|
||||
uevent_sent = true;
|
||||
}
|
||||
|
||||
if (!uevent_sent) {
|
||||
pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
|
||||
gi->connected, gi->sw_connected, cdev->config);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void configfs_composite_unbind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev;
|
||||
@ -1391,14 +1476,91 @@ static void configfs_composite_unbind(struct usb_gadget *gadget)
|
||||
set_gadget_data(gadget, NULL);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
static int android_setup(struct usb_gadget *gadget,
|
||||
const struct usb_ctrlrequest *c)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
unsigned long flags;
|
||||
struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
|
||||
int value = -EOPNOTSUPP;
|
||||
struct usb_function_instance *fi;
|
||||
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
if (!gi->connected) {
|
||||
gi->connected = 1;
|
||||
schedule_work(&gi->work);
|
||||
}
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
list_for_each_entry(fi, &gi->available_func, cfs_list) {
|
||||
if (fi != NULL && fi->f != NULL && fi->f->setup != NULL) {
|
||||
value = fi->f->setup(fi->f, c);
|
||||
if (value >= 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_F_ACC
|
||||
if (value < 0)
|
||||
value = acc_ctrlrequest(cdev, c);
|
||||
#endif
|
||||
|
||||
if (value < 0)
|
||||
value = composite_setup(gadget, c);
|
||||
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
|
||||
cdev->config) {
|
||||
schedule_work(&gi->work);
|
||||
}
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void android_disconnect(struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_composite_dev *cdev = get_gadget_data(gadget);
|
||||
struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
|
||||
|
||||
/* FIXME: There's a race between usb_gadget_udc_stop() which is likely
|
||||
* to set the gadget driver to NULL in the udc driver and this drivers
|
||||
* gadget disconnect fn which likely checks for the gadget driver to
|
||||
* be a null ptr. It happens that unbind (doing set_gadget_data(NULL))
|
||||
* is called before the gadget driver is set to NULL and the udc driver
|
||||
* calls disconnect fn which results in cdev being a null ptr.
|
||||
*/
|
||||
if (cdev == NULL) {
|
||||
WARN(1, "%s: gadget driver already disconnected\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* accessory HID support can be active while the
|
||||
accessory function is not actually enabled,
|
||||
so we need to inform it when we are disconnected.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_F_ACC
|
||||
acc_disconnect();
|
||||
#endif
|
||||
gi->connected = 0;
|
||||
schedule_work(&gi->work);
|
||||
composite_disconnect(gadget);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct usb_gadget_driver configfs_driver_template = {
|
||||
.bind = configfs_composite_bind,
|
||||
.unbind = configfs_composite_unbind,
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
.setup = android_setup,
|
||||
.reset = android_disconnect,
|
||||
.disconnect = android_disconnect,
|
||||
#else
|
||||
.setup = composite_setup,
|
||||
.reset = composite_disconnect,
|
||||
.disconnect = composite_disconnect,
|
||||
|
||||
#endif
|
||||
.suspend = composite_suspend,
|
||||
.resume = composite_resume,
|
||||
|
||||
@ -1410,6 +1572,89 @@ static const struct usb_gadget_driver configfs_driver_template = {
|
||||
.match_existing_only = 1,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct gadget_info *dev = dev_get_drvdata(pdev);
|
||||
struct usb_composite_dev *cdev;
|
||||
char *state = "DISCONNECTED";
|
||||
unsigned long flags;
|
||||
|
||||
if (!dev)
|
||||
goto out;
|
||||
|
||||
cdev = &dev->cdev;
|
||||
|
||||
if (!cdev)
|
||||
goto out;
|
||||
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
if (cdev->config)
|
||||
state = "CONFIGURED";
|
||||
else if (dev->connected)
|
||||
state = "CONNECTED";
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
out:
|
||||
return sprintf(buf, "%s\n", state);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
|
||||
|
||||
static struct device_attribute *android_usb_attributes[] = {
|
||||
&dev_attr_state,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int android_device_create(struct gadget_info *gi)
|
||||
{
|
||||
struct device_attribute **attrs;
|
||||
struct device_attribute *attr;
|
||||
|
||||
INIT_WORK(&gi->work, android_work);
|
||||
android_device = device_create(android_class, NULL,
|
||||
MKDEV(0, 0), NULL, "android0");
|
||||
if (IS_ERR(android_device))
|
||||
return PTR_ERR(android_device);
|
||||
|
||||
dev_set_drvdata(android_device, gi);
|
||||
|
||||
attrs = android_usb_attributes;
|
||||
while ((attr = *attrs++)) {
|
||||
int err;
|
||||
|
||||
err = device_create_file(android_device, attr);
|
||||
if (err) {
|
||||
device_destroy(android_device->class,
|
||||
android_device->devt);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void android_device_destroy(void)
|
||||
{
|
||||
struct device_attribute **attrs;
|
||||
struct device_attribute *attr;
|
||||
|
||||
attrs = android_usb_attributes;
|
||||
while ((attr = *attrs++))
|
||||
device_remove_file(android_device, attr);
|
||||
device_destroy(android_device->class, android_device->devt);
|
||||
}
|
||||
#else
|
||||
static inline int android_device_create(struct gadget_info *gi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void android_device_destroy(void)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct config_group *gadgets_make(
|
||||
struct config_group *group,
|
||||
const char *name)
|
||||
@ -1461,7 +1706,11 @@ static struct config_group *gadgets_make(
|
||||
if (!gi->composite.gadget_driver.function)
|
||||
goto err;
|
||||
|
||||
if (android_device_create(gi) < 0)
|
||||
goto err;
|
||||
|
||||
return &gi->group;
|
||||
|
||||
err:
|
||||
kfree(gi);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@ -1470,6 +1719,7 @@ err:
|
||||
static void gadgets_drop(struct config_group *group, struct config_item *item)
|
||||
{
|
||||
config_item_put(item);
|
||||
android_device_destroy();
|
||||
}
|
||||
|
||||
static struct configfs_group_operations gadgets_ops = {
|
||||
@ -1509,6 +1759,13 @@ static int __init gadget_cfs_init(void)
|
||||
config_group_init(&gadget_subsys.su_group);
|
||||
|
||||
ret = configfs_register_subsystem(&gadget_subsys);
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
android_class = class_create(THIS_MODULE, "android_usb");
|
||||
if (IS_ERR(android_class))
|
||||
return PTR_ERR(android_class);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(gadget_cfs_init);
|
||||
@ -1516,5 +1773,10 @@ module_init(gadget_cfs_init);
|
||||
static void __exit gadget_cfs_exit(void)
|
||||
{
|
||||
configfs_unregister_subsystem(&gadget_subsys);
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
if (!IS_ERR(android_class))
|
||||
class_destroy(android_class);
|
||||
#endif
|
||||
|
||||
}
|
||||
module_exit(gadget_cfs_exit);
|
||||
|
@ -56,3 +56,7 @@ usb_f_cdev-y := f_cdev.o
|
||||
obj-$(CONFIG_USB_F_CDEV) += usb_f_cdev.o
|
||||
usb_f_ccid-y := f_ccid.o
|
||||
obj-$(CONFIG_USB_F_CCID) += usb_f_ccid.o
|
||||
usb_f_audio_source-y := f_audio_source.o
|
||||
obj-$(CONFIG_USB_F_AUDIO_SRC) += usb_f_audio_source.o
|
||||
usb_f_accessory-y := f_accessory.o
|
||||
obj-$(CONFIG_USB_F_ACC) += usb_f_accessory.o
|
||||
|
1352
drivers/usb/gadget/function/f_accessory.c
Normal file
1352
drivers/usb/gadget/function/f_accessory.c
Normal file
File diff suppressed because it is too large
Load Diff
1071
drivers/usb/gadget/function/f_audio_source.c
Normal file
1071
drivers/usb/gadget/function/f_audio_source.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1216,6 +1216,65 @@ static void f_midi_free_inst(struct usb_function_instance *f)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_CONFIGFS_UEVENT
|
||||
extern struct device *create_function_device(char *name);
|
||||
static ssize_t alsa_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_function_instance *fi_midi = dev_get_drvdata(dev);
|
||||
struct f_midi *midi;
|
||||
|
||||
if (!fi_midi->f)
|
||||
dev_warn(dev, "f_midi: function not set\n");
|
||||
|
||||
if (fi_midi && fi_midi->f) {
|
||||
midi = func_to_midi(fi_midi->f);
|
||||
if (midi->rmidi && midi->rmidi->card)
|
||||
return sprintf(buf, "%d %d\n",
|
||||
midi->rmidi->card->number, midi->rmidi->device);
|
||||
}
|
||||
|
||||
/* print PCM card and device numbers */
|
||||
return sprintf(buf, "%d %d\n", -1, -1);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(alsa, S_IRUGO, alsa_show, NULL);
|
||||
|
||||
static struct device_attribute *alsa_function_attributes[] = {
|
||||
&dev_attr_alsa,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int create_alsa_device(struct usb_function_instance *fi)
|
||||
{
|
||||
struct device *dev;
|
||||
struct device_attribute **attrs;
|
||||
struct device_attribute *attr;
|
||||
int err = 0;
|
||||
|
||||
dev = create_function_device("f_midi");
|
||||
if (IS_ERR(dev))
|
||||
return PTR_ERR(dev);
|
||||
|
||||
attrs = alsa_function_attributes;
|
||||
if (attrs) {
|
||||
while ((attr = *attrs++) && !err)
|
||||
err = device_create_file(dev, attr);
|
||||
if (err) {
|
||||
device_destroy(dev->class, dev->devt);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
dev_set_drvdata(dev, fi);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int create_alsa_device(struct usb_function_instance *fi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct usb_function_instance *f_midi_alloc_inst(void)
|
||||
{
|
||||
struct f_midi_opts *opts;
|
||||
@ -1234,6 +1293,11 @@ static struct usb_function_instance *f_midi_alloc_inst(void)
|
||||
opts->out_ports = 1;
|
||||
opts->refcnt = 1;
|
||||
|
||||
if (create_alsa_device(&opts->func_inst)) {
|
||||
kfree(opts);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
config_group_init_type_name(&opts->func_inst.group, "",
|
||||
&midi_func_type);
|
||||
|
||||
@ -1254,6 +1318,7 @@ static void f_midi_free(struct usb_function *f)
|
||||
kfifo_free(&midi->in_req_fifo);
|
||||
kfree(midi);
|
||||
free = true;
|
||||
opts->func_inst.f = NULL;
|
||||
}
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
@ -1341,6 +1406,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)
|
||||
midi->func.disable = f_midi_disable;
|
||||
midi->func.free_func = f_midi_free;
|
||||
|
||||
fi->f = &midi->func;
|
||||
return &midi->func;
|
||||
|
||||
setup_fail:
|
||||
|
@ -234,6 +234,7 @@ source "fs/orangefs/Kconfig"
|
||||
source "fs/adfs/Kconfig"
|
||||
source "fs/affs/Kconfig"
|
||||
source "fs/ecryptfs/Kconfig"
|
||||
source "fs/sdcardfs/Kconfig"
|
||||
source "fs/hfs/Kconfig"
|
||||
source "fs/hfsplus/Kconfig"
|
||||
source "fs/befs/Kconfig"
|
||||
|
@ -84,6 +84,7 @@ obj-$(CONFIG_ISO9660_FS) += isofs/
|
||||
obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+
|
||||
obj-$(CONFIG_HFS_FS) += hfs/
|
||||
obj-$(CONFIG_ECRYPT_FS) += ecryptfs/
|
||||
obj-$(CONFIG_SDCARD_FS) += sdcardfs/
|
||||
obj-$(CONFIG_VXFS_FS) += freevxfs/
|
||||
obj-$(CONFIG_NFS_FS) += nfs/
|
||||
obj-$(CONFIG_EXPORTFS) += exportfs/
|
||||
|
@ -260,12 +260,11 @@ int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *de
|
||||
/*
|
||||
* read page from file, directory or symlink, given a key to use
|
||||
*/
|
||||
int afs_page_filler(void *data, struct page *page)
|
||||
static int __afs_page_filler(struct key *key, struct page *page)
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||
struct afs_read *req;
|
||||
struct key *key = data;
|
||||
int ret;
|
||||
|
||||
_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
|
||||
@ -372,6 +371,13 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int afs_page_filler(struct file *data, struct page *page)
|
||||
{
|
||||
struct key *key = (struct key *)data;
|
||||
|
||||
return __afs_page_filler(key, page);
|
||||
}
|
||||
|
||||
/*
|
||||
* read page from file, directory or symlink, given a file to nominate the key
|
||||
* to be used
|
||||
@ -384,14 +390,14 @@ static int afs_readpage(struct file *file, struct page *page)
|
||||
if (file) {
|
||||
key = afs_file_key(file);
|
||||
ASSERT(key != NULL);
|
||||
ret = afs_page_filler(key, page);
|
||||
ret = __afs_page_filler(key, page);
|
||||
} else {
|
||||
struct inode *inode = page->mapping->host;
|
||||
key = afs_request_key(AFS_FS_S(inode->i_sb)->cell);
|
||||
if (IS_ERR(key)) {
|
||||
ret = PTR_ERR(key);
|
||||
} else {
|
||||
ret = afs_page_filler(key, page);
|
||||
ret = __afs_page_filler(key, page);
|
||||
key_put(key);
|
||||
}
|
||||
}
|
||||
|
@ -752,7 +752,7 @@ extern void afs_put_wb_key(struct afs_wb_key *);
|
||||
extern int afs_open(struct inode *, struct file *);
|
||||
extern int afs_release(struct inode *, struct file *);
|
||||
extern int afs_fetch_data(struct afs_vnode *, struct key *, struct afs_read *);
|
||||
extern int afs_page_filler(void *, struct page *);
|
||||
extern int afs_page_filler(struct file *, struct page *);
|
||||
extern void afs_put_read(struct afs_read *);
|
||||
|
||||
/*
|
||||
|
14
fs/attr.c
14
fs/attr.c
@ -223,7 +223,7 @@ EXPORT_SYMBOL(setattr_copy);
|
||||
* the file open for write, as there can be no conflicting delegation in
|
||||
* that case.
|
||||
*/
|
||||
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
|
||||
int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
umode_t mode = inode->i_mode;
|
||||
@ -247,7 +247,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
||||
return -EPERM;
|
||||
|
||||
if (!inode_owner_or_capable(inode)) {
|
||||
error = inode_permission(inode, MAY_WRITE);
|
||||
error = inode_permission2(mnt, inode, MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
@ -330,7 +330,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (inode->i_op->setattr)
|
||||
if (mnt && inode->i_op->setattr2)
|
||||
error = inode->i_op->setattr2(mnt, dentry, attr);
|
||||
else if (inode->i_op->setattr)
|
||||
error = inode->i_op->setattr(dentry, attr);
|
||||
else
|
||||
error = simple_setattr(dentry, attr);
|
||||
@ -343,4 +345,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
|
||||
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(notify_change2);
|
||||
|
||||
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
|
||||
{
|
||||
return notify_change2(NULL, dentry, attr, delegated_inode);
|
||||
}
|
||||
EXPORT_SYMBOL(notify_change);
|
||||
|
@ -742,7 +742,7 @@ void do_coredump(const siginfo_t *siginfo)
|
||||
goto close_fail;
|
||||
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
|
||||
goto close_fail;
|
||||
if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
|
||||
if (do_truncate2(cprm.file->f_path.mnt, cprm.file->f_path.dentry, 0, 0, cprm.file))
|
||||
goto close_fail;
|
||||
}
|
||||
|
||||
|
@ -204,6 +204,7 @@ char *d_absolute_path(const struct path *path,
|
||||
return ERR_PTR(error);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(d_absolute_path);
|
||||
|
||||
/*
|
||||
* same as __d_path but appends "(deleted)" for unlinked files.
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mman.h>
|
||||
@ -1816,7 +1817,8 @@ fetch_events:
|
||||
}
|
||||
|
||||
spin_unlock_irq(&ep->wq.lock);
|
||||
if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS))
|
||||
if (!freezable_schedule_hrtimeout_range(to, slack,
|
||||
HRTIMER_MODE_ABS))
|
||||
timed_out = 1;
|
||||
|
||||
spin_lock_irq(&ep->wq.lock);
|
||||
|
@ -1308,7 +1308,7 @@ EXPORT_SYMBOL(flush_old_exec);
|
||||
void would_dump(struct linux_binprm *bprm, struct file *file)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
if (inode_permission(inode, MAY_READ) < 0) {
|
||||
if (inode_permission2(file->f_path.mnt, inode, MAY_READ) < 0) {
|
||||
struct user_namespace *old, *user_ns;
|
||||
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
|
||||
|
||||
|
@ -377,9 +377,8 @@ err:
|
||||
* and will start a new collection. Eventually caller must submit the last
|
||||
* segment if present.
|
||||
*/
|
||||
static int readpage_strip(void *data, struct page *page)
|
||||
static int __readpage_strip(struct page_collect *pcol, struct page *page)
|
||||
{
|
||||
struct page_collect *pcol = data;
|
||||
struct inode *inode = pcol->inode;
|
||||
struct exofs_i_info *oi = exofs_i(inode);
|
||||
loff_t i_size = i_size_read(inode);
|
||||
@ -470,6 +469,13 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int readpage_strip(struct file *data, struct page *page)
|
||||
{
|
||||
struct page_collect *pcol = (struct page_collect *)data;
|
||||
|
||||
return __readpage_strip(pcol, page);
|
||||
}
|
||||
|
||||
static int exofs_readpages(struct file *file, struct address_space *mapping,
|
||||
struct list_head *pages, unsigned nr_pages)
|
||||
{
|
||||
@ -499,7 +505,7 @@ static int _readpage(struct page *page, bool read_4_write)
|
||||
_pcol_init(&pcol, 1, page->mapping->host);
|
||||
|
||||
pcol.read_4_write = read_4_write;
|
||||
ret = readpage_strip(&pcol, page);
|
||||
ret = __readpage_strip(&pcol, page);
|
||||
if (ret) {
|
||||
EXOFS_ERR("_readpage => %d\n", ret);
|
||||
return ret;
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "ext4.h"
|
||||
#include "xattr.h"
|
||||
#include "truncate.h"
|
||||
#include <trace/events/android_fs.h>
|
||||
|
||||
#define EXT4_XATTR_SYSTEM_DATA "data"
|
||||
#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
|
||||
@ -505,6 +506,17 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (trace_android_fs_dataread_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_dataread_start(inode, page_offset(page),
|
||||
PAGE_SIZE, current->pid,
|
||||
path, current->comm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Current inline data can only exist in the 1st page,
|
||||
* So for all the other pages, just set them uptodate.
|
||||
@ -516,6 +528,8 @@ int ext4_readpage_inline(struct inode *inode, struct page *page)
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
|
||||
trace_android_fs_dataread_end(inode, page_offset(page), PAGE_SIZE);
|
||||
|
||||
up_read(&EXT4_I(inode)->xattr_sem);
|
||||
|
||||
unlock_page(page);
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "truncate.h"
|
||||
|
||||
#include <trace/events/ext4.h>
|
||||
#include <trace/events/android_fs.h>
|
||||
|
||||
#define MPAGE_DA_EXTENT_TAIL 0x01
|
||||
|
||||
@ -1253,6 +1254,16 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
|
||||
if (unlikely(ext4_forced_shutdown(EXT4_SB(inode->i_sb))))
|
||||
return -EIO;
|
||||
|
||||
if (trace_android_fs_datawrite_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_datawrite_start(inode, pos, len,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
trace_ext4_write_begin(inode, pos, len, flags);
|
||||
/*
|
||||
* Reserve one block more for addition to orphan list in case
|
||||
@ -1391,6 +1402,7 @@ static int ext4_write_end(struct file *file,
|
||||
int i_size_changed = 0;
|
||||
int inline_data = ext4_has_inline_data(inode);
|
||||
|
||||
trace_android_fs_datawrite_end(inode, pos, len);
|
||||
trace_ext4_write_end(inode, pos, len, copied);
|
||||
if (inline_data) {
|
||||
ret = ext4_write_inline_data_end(inode, pos, len,
|
||||
@ -1496,6 +1508,7 @@ static int ext4_journalled_write_end(struct file *file,
|
||||
int size_changed = 0;
|
||||
int inline_data = ext4_has_inline_data(inode);
|
||||
|
||||
trace_android_fs_datawrite_end(inode, pos, len);
|
||||
trace_ext4_journalled_write_end(inode, pos, len, copied);
|
||||
from = pos & (PAGE_SIZE - 1);
|
||||
to = from + len;
|
||||
@ -3024,6 +3037,16 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
|
||||
len, flags, pagep, fsdata);
|
||||
}
|
||||
*fsdata = (void *)0;
|
||||
if (trace_android_fs_datawrite_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_datawrite_start(inode, pos, len,
|
||||
current->pid,
|
||||
path, current->comm);
|
||||
}
|
||||
trace_ext4_da_write_begin(inode, pos, len, flags);
|
||||
|
||||
if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) {
|
||||
@ -3142,6 +3165,7 @@ static int ext4_da_write_end(struct file *file,
|
||||
return ext4_write_end(file, mapping, pos,
|
||||
len, copied, page, fsdata);
|
||||
|
||||
trace_android_fs_datawrite_end(inode, pos, len);
|
||||
trace_ext4_da_write_end(inode, pos, len, copied);
|
||||
start = pos & (PAGE_SIZE - 1);
|
||||
end = start + copied - 1;
|
||||
@ -3843,6 +3867,7 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
size_t count = iov_iter_count(iter);
|
||||
loff_t offset = iocb->ki_pos;
|
||||
ssize_t ret;
|
||||
int rw = iov_iter_rw(iter);
|
||||
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
|
||||
@ -3859,12 +3884,42 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
if (ext4_has_inline_data(inode))
|
||||
return 0;
|
||||
|
||||
if (trace_android_fs_dataread_start_enabled() &&
|
||||
(rw == READ)) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_dataread_start(inode, offset, count,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
if (trace_android_fs_datawrite_start_enabled() &&
|
||||
(rw == WRITE)) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_datawrite_start(inode, offset, count,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter));
|
||||
if (iov_iter_rw(iter) == READ)
|
||||
ret = ext4_direct_IO_read(iocb, iter);
|
||||
else
|
||||
ret = ext4_direct_IO_write(iocb, iter);
|
||||
trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret);
|
||||
|
||||
if (trace_android_fs_dataread_start_enabled() &&
|
||||
(rw == READ))
|
||||
trace_android_fs_dataread_end(inode, offset, count);
|
||||
if (trace_android_fs_datawrite_start_enabled() &&
|
||||
(rw == WRITE))
|
||||
trace_android_fs_datawrite_end(inode, offset, count);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <linux/cleancache.h>
|
||||
|
||||
#include "ext4.h"
|
||||
#include <trace/events/android_fs.h>
|
||||
|
||||
static inline bool ext4_bio_encrypted(struct bio *bio)
|
||||
{
|
||||
@ -56,6 +57,17 @@ static inline bool ext4_bio_encrypted(struct bio *bio)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ext4_trace_read_completion(struct bio *bio)
|
||||
{
|
||||
struct page *first_page = bio->bi_io_vec[0].bv_page;
|
||||
|
||||
if (first_page != NULL)
|
||||
trace_android_fs_dataread_end(first_page->mapping->host,
|
||||
page_offset(first_page),
|
||||
bio->bi_iter.bi_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O completion handler for multipage BIOs.
|
||||
*
|
||||
@ -73,6 +85,9 @@ static void mpage_end_io(struct bio *bio)
|
||||
struct bio_vec *bv;
|
||||
int i;
|
||||
|
||||
if (trace_android_fs_dataread_start_enabled())
|
||||
ext4_trace_read_completion(bio);
|
||||
|
||||
if (ext4_bio_encrypted(bio)) {
|
||||
if (bio->bi_status) {
|
||||
fscrypt_release_ctx(bio->bi_private);
|
||||
@ -96,6 +111,30 @@ static void mpage_end_io(struct bio *bio)
|
||||
bio_put(bio);
|
||||
}
|
||||
|
||||
static void
|
||||
ext4_submit_bio_read(struct bio *bio)
|
||||
{
|
||||
if (trace_android_fs_dataread_start_enabled()) {
|
||||
struct page *first_page = bio->bi_io_vec[0].bv_page;
|
||||
|
||||
if (first_page != NULL) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
first_page->mapping->host);
|
||||
trace_android_fs_dataread_start(
|
||||
first_page->mapping->host,
|
||||
page_offset(first_page),
|
||||
bio->bi_iter.bi_size,
|
||||
current->pid,
|
||||
path,
|
||||
current->comm);
|
||||
}
|
||||
}
|
||||
submit_bio(bio);
|
||||
}
|
||||
|
||||
int ext4_mpage_readpages(struct address_space *mapping,
|
||||
struct list_head *pages, struct page *page,
|
||||
unsigned nr_pages, bool is_readahead)
|
||||
@ -236,7 +275,7 @@ int ext4_mpage_readpages(struct address_space *mapping,
|
||||
*/
|
||||
if (bio && (last_block_in_bio != blocks[0] - 1)) {
|
||||
submit_and_realloc:
|
||||
submit_bio(bio);
|
||||
ext4_submit_bio_read(bio);
|
||||
bio = NULL;
|
||||
}
|
||||
if (bio == NULL) {
|
||||
@ -270,14 +309,14 @@ int ext4_mpage_readpages(struct address_space *mapping,
|
||||
if (((map.m_flags & EXT4_MAP_BOUNDARY) &&
|
||||
(relative_block == map.m_len)) ||
|
||||
(first_hole != blocks_per_page)) {
|
||||
submit_bio(bio);
|
||||
ext4_submit_bio_read(bio);
|
||||
bio = NULL;
|
||||
} else
|
||||
last_block_in_bio = blocks[blocks_per_page - 1];
|
||||
goto next_page;
|
||||
confused:
|
||||
if (bio) {
|
||||
submit_bio(bio);
|
||||
ext4_submit_bio_read(bio);
|
||||
bio = NULL;
|
||||
}
|
||||
if (!PageUptodate(page))
|
||||
@ -290,6 +329,6 @@ int ext4_mpage_readpages(struct address_space *mapping,
|
||||
}
|
||||
BUG_ON(pages && !list_empty(pages));
|
||||
if (bio)
|
||||
submit_bio(bio);
|
||||
ext4_submit_bio_read(bio);
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "segment.h"
|
||||
#include "trace.h"
|
||||
#include <trace/events/f2fs.h>
|
||||
#include <trace/events/android_fs.h>
|
||||
|
||||
#define NUM_PREALLOC_POST_READ_CTXS 128
|
||||
|
||||
@ -2330,6 +2331,16 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
block_t blkaddr = NULL_ADDR;
|
||||
int err = 0;
|
||||
|
||||
if (trace_android_fs_datawrite_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_datawrite_start(inode, pos, len,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
trace_f2fs_write_begin(inode, pos, len, flags);
|
||||
|
||||
if ((f2fs_is_atomic_file(inode) &&
|
||||
@ -2429,6 +2440,7 @@ static int f2fs_write_end(struct file *file,
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
|
||||
trace_android_fs_datawrite_end(inode, pos, len);
|
||||
trace_f2fs_write_end(inode, pos, len, copied);
|
||||
|
||||
/*
|
||||
@ -2496,6 +2508,29 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
|
||||
trace_f2fs_direct_IO_enter(inode, offset, count, rw);
|
||||
|
||||
if (trace_android_fs_dataread_start_enabled() &&
|
||||
(rw == READ)) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_dataread_start(inode, offset,
|
||||
count, current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
if (trace_android_fs_datawrite_start_enabled() &&
|
||||
(rw == WRITE)) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
path = android_fstrace_get_pathname(pathbuf,
|
||||
MAX_TRACE_PATHBUF_LEN,
|
||||
inode);
|
||||
trace_android_fs_datawrite_start(inode, offset, count,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
|
||||
if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
|
||||
iocb->ki_hint = WRITE_LIFE_NOT_SET;
|
||||
|
||||
@ -2524,6 +2559,13 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
}
|
||||
|
||||
out:
|
||||
if (trace_android_fs_dataread_start_enabled() &&
|
||||
(rw == READ))
|
||||
trace_android_fs_dataread_end(inode, offset, count);
|
||||
if (trace_android_fs_datawrite_start_enabled() &&
|
||||
(rw == WRITE))
|
||||
trace_android_fs_datawrite_end(inode, offset, count);
|
||||
|
||||
trace_f2fs_direct_IO_exit(inode, offset, count, rw, err);
|
||||
|
||||
return err;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user