* refs/heads/tmp-d6bbe8b Linux 4.4.127 Revert "ip6_vti: adjust vti mtu according to mtu of lower device" net: cavium: liquidio: fix up "Avoid dma_unmap_single on uninitialized ndata" spi: davinci: fix up dma_mapping_error() incorrect patch Revert "mtip32xx: use runtime tag to initialize command header" Revert "cpufreq: Fix governor module removal race" Revert "ARM: dts: omap3-n900: Fix the audio CODEC's reset pin" Revert "ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin" Revert "PCI/MSI: Stop disabling MSI/MSI-X in pci_device_shutdown()" nospec: Kill array_index_nospec_mask_check() nospec: Move array_index_nospec() parameter checking into separate macro net: hns: Fix ethtool private flags md/raid10: reset the 'first' at the end of loop ARM: dts: am57xx-beagle-x15-common: Add overide powerhold property ARM: dts: dra7: Add power hold and power controller properties to palmas Documentation: pinctrl: palmas: Add ti,palmas-powerhold-override property definition vt: change SGR 21 to follow the standards Input: i8042 - enable MUX on Sony VAIO VGN-CS series to fix touchpad Input: i8042 - add Lenovo ThinkPad L460 to i8042 reset list staging: comedi: ni_mio_common: ack ai fifo error interrupts. fs/proc: Stop trying to report thread stacks crypto: x86/cast5-avx - fix ECB encryption when long sg follows short one crypto: ahash - Fix early termination in hash walk parport_pc: Add support for WCH CH382L PCI-E single parallel port card. media: usbtv: prevent double free in error case mei: remove dev_err message on an unsupported ioctl USB: serial: cp210x: add ELDAT Easywave RX09 id USB: serial: ftdi_sio: add support for Harman FirmwareHubEmulator USB: serial: ftdi_sio: add RT Systems VX-8 cable usb: dwc2: Improve gadget state disconnection handling scsi: virtio_scsi: always read VPD pages for multiqueue too llist: clang: introduce member_address_is_nonnull() Bluetooth: Fix missing encryption refresh on Security Request netfilter: x_tables: add and use xt_check_proc_name netfilter: bridge: ebt_among: add more missing match size checks xfrm: Refuse to insert 32 bit userspace socket policies on 64 bit systems net: xfrm: use preempt-safe this_cpu_read() in ipcomp_alloc_tfms() RDMA/ucma: Introduce safer rdma_addr_size() variants RDMA/ucma: Don't allow join attempts for unsupported AF family RDMA/ucma: Check that device exists prior to accessing it RDMA/ucma: Check that device is connected prior to access it RDMA/ucma: Ensure that CM_ID exists prior to access it RDMA/ucma: Fix use-after-free access in ucma_close RDMA/ucma: Check AF family prior resolving address xfrm_user: uncoditionally validate esn replay attribute struct arm64: avoid overflow in VA_START and PAGE_OFFSET selinux: Remove redundant check for unknown labeling behavior netfilter: ctnetlink: Make some parameters integer to avoid enum mismatch tty: provide tty_name() even without CONFIG_TTY audit: add tty field to LOGIN event frv: declare jiffies to be located in the .data section jiffies.h: declare jiffies and jiffies_64 with ____cacheline_aligned_in_smp fs: compat: Remove warning from COMPATIBLE_IOCTL selinux: Remove unnecessary check of array base in selinux_set_mapping() cpumask: Add helper cpumask_available() genirq: Use cpumask_available() for check of cpumask variable netfilter: nf_nat_h323: fix logical-not-parentheses warning Input: mousedev - fix implicit conversion warning dm ioctl: remove double parentheses PCI: Make PCI_ROM_ADDRESS_MASK a 32-bit constant writeback: fix the wrong congested state variable definition ACPI, PCI, irq: remove redundant check for null string pointer kprobes/x86: Fix to set RWX bits correctly before releasing trampoline usb: gadget: f_hid: fix: Prevent accessing released memory usb: gadget: align buffer size when allocating for OUT endpoint usb: gadget: fix usb_ep_align_maybe endianness and new usb_ep_align usb: gadget: change len to size_t on alloc_ep_req() usb: gadget: define free_ep_req as universal function partitions/msdos: Unable to mount UFS 44bsd partitions perf/hwbp: Simplify the perf-hwbp code, fix documentation ALSA: pcm: potential uninitialized return values ALSA: pcm: Use dma_bytes as size parameter in dma_mmap_coherent() mtd: jedec_probe: Fix crash in jedec_read_mfr() Replace #define with enum for better compilation errors. Add missing include to drivers/tty/goldfish.c Fix whitespace in drivers/tty/goldfish.c 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: add missing include to pdev_bus ANDROID: pdev_bus: replace writel with gf_write_ptr ANDROID: Cleanup type casting in goldfish.h ANDROID: Include missing headers in goldfish.h ANDROID: cpufreq: times: skip printing invalid frequencies ANDROID: xt_qtaguid: Remove unnecessary null checks to device's name ANDROID: xt_qtaguid: Remove unnecessary null checks to ifa_label ANDROID: cpufreq: times: allocate enough space for a uid_entry Linux 4.4.126 net: systemport: Rewrite __bcm_sysport_tx_reclaim() net: fec: Fix unbalanced PM runtime calls ieee802154: 6lowpan: fix possible NULL deref in lowpan_device_event() s390/qeth: on channel error, reject further cmd requests s390/qeth: lock read device while queueing next buffer s390/qeth: when thread completes, wake up all waiters s390/qeth: free netdevice when removing a card team: Fix double free in error path skbuff: Fix not waking applications when errors are enqueued net: Only honor ifindex in IP_PKTINFO if non-0 netlink: avoid a double skb free in genlmsg_mcast() net/iucv: Free memory obtained by kzalloc net: ethernet: ti: cpsw: add check for in-band mode setting with RGMII PHY interface net: ethernet: arc: Fix a potential memory leak if an optional regulator is deferred l2tp: do not accept arbitrary sockets ipv6: fix access to non-linear packet in ndisc_fill_redirect_hdr_option() dccp: check sk for closed state in dccp_sendmsg() net: Fix hlist corruptions in inet_evict_bucket() Revert "genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs" scsi: sg: don't return bogus Sg_requests Revert "genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs" UPSTREAM: drm: virtio-gpu: set atomic flag UPSTREAM: drm: virtio-gpu: transfer dumb buffers to host on plane update UPSTREAM: drm: virtio-gpu: ensure plane is flushed to host on atomic update UPSTREAM: drm: virtio-gpu: get the fb from the plane state for atomic updates Linux 4.4.125 bpf, x64: increase number of passes bpf: skip unnecessary capability check kbuild: disable clang's default use of -fmerge-all-constants staging: lustre: ptlrpc: kfree used instead of kvfree perf/x86/intel: Don't accidentally clear high bits in bdw_limit_period() x86/entry/64: Don't use IST entry for #BP stack x86/boot/64: Verify alignment of the LOAD segment x86/build/64: Force the linker to use 2MB page size kvm/x86: fix icebp instruction handling tty: vt: fix up tabstops properly can: cc770: Fix use after free in cc770_tx_interrupt() can: cc770: Fix queue stall & dropped RTR reply can: cc770: Fix stalls on rt-linux, remove redundant IRQ ack staging: ncpfs: memory corruption in ncp_read_kernel() mtd: nand: fsl_ifc: Fix nand waitfunc return value tracing: probeevent: Fix to support minus offset from symbol rtlwifi: rtl8723be: Fix loss of signal brcmfmac: fix P2P_DEVICE ethernet address generation acpi, numa: fix pxm to online numa node associations drm: udl: Properly check framebuffer mmap offsets drm/radeon: Don't turn off DP sink when disconnected drm/vmwgfx: Fix a destoy-while-held mutex problem. x86/mm: implement free pmd/pte page interfaces mm/vmalloc: add interfaces to free unmapped page table libata: Modify quirks for MX100 to limit NCQ_TRIM quirk to MU01 version libata: Make Crucial BX100 500GB LPM quirk apply to all firmware versions libata: Apply NOLPM quirk to Crucial M500 480 and 960GB SSDs libata: Enable queued TRIM for Samsung SSD 860 libata: disable LPM for Crucial BX100 SSD 500GB drive libata: Apply NOLPM quirk to Crucial MX100 512GB SSDs libata: remove WARN() for DMA or PIO command without data libata: fix length validation of ATAPI-relayed SCSI commands Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174 clk: bcm2835: Protect sections updating shared registers ahci: Add PCI-id for the Highpoint Rocketraid 644L card PCI: Add function 1 DMA alias quirk for Highpoint RocketRAID 644L mmc: dw_mmc: fix falling from idmac to PIO mode when dw_mci_reset occurs ALSA: hda/realtek - Always immediately update mute LED with pin VREF ALSA: aloop: Fix access to not-yet-ready substream via cable ALSA: aloop: Sync stale timer before release ALSA: usb-audio: Fix parsing descriptor of UAC2 processing unit iio: st_pressure: st_accel: pass correct platform data to init MIPS: ralink: Remove ralink_halt() ANDROID: cpufreq: times: fix proc_time_in_state_show dtc: turn off dtc unit address warnings by default Linux 4.4.124 RDMA/ucma: Fix access to non-initialized CM_ID object dmaengine: ti-dma-crossbar: Fix event mapping for TPCC_EVT_MUX_60_63 clk: si5351: Rename internal plls to avoid name collisions nfsd4: permit layoutget of executable-only files RDMA/ocrdma: Fix permissions for OCRDMA_RESET_STATS ip6_vti: adjust vti mtu according to mtu of lower device iommu/vt-d: clean up pr_irq if request_threaded_irq fails pinctrl: Really force states during suspend/resume coresight: Fix disabling of CoreSight TPIU pty: cancel pty slave port buf's work in tty_release drm/omap: DMM: Check for DMM readiness after successful transaction commit vgacon: Set VGA struct resource types IB/umem: Fix use of npages/nmap fields RDMA/cma: Use correct size when writing netlink stats IB/ipoib: Avoid memory leak if the SA returns a different DGID mmc: avoid removing non-removable hosts during suspend platform/chrome: Use proper protocol transfer function cros_ec: fix nul-termination for firmware build info media: [RESEND] media: dvb-frontends: Add delay to Si2168 restart media: bt8xx: Fix err 'bt878_probe()' rtlwifi: rtl_pci: Fix the bug when inactiveps is enabled. RDMA/iwpm: Fix uninitialized error code in iwpm_send_mapinfo() drm/msm: fix leak in failed get_pages media: c8sectpfe: fix potential NULL pointer dereference in c8sectpfe_timer_interrupt Bluetooth: hci_qca: Avoid setup failure on missing rampatch perf tests kmod-path: Don't fail if compressed modules aren't supported rtc: ds1374: wdt: Fix stop/start ioctl always returning -EINVAL rtc: ds1374: wdt: Fix issue with timeout scaling from secs to wdt ticks cifs: small underflow in cnvrtDosUnixTm() net: hns: fix ethtool_get_strings overflow in hns driver sm501fb: don't return zero on failure path in sm501fb_start() video: fbdev: udlfb: Fix buffer on stack tcm_fileio: Prevent information leak for short reads ia64: fix module loading for gcc-5.4 md/raid10: skip spare disk as 'first' disk Input: twl4030-pwrbutton - use correct device for irq request power: supply: pda_power: move from timer to delayed_work bnx2x: Align RX buffers drm/nouveau/kms: Increase max retries in scanout position queries. ACPI / PMIC: xpower: Fix power_table addresses ipmi/watchdog: fix wdog hang on panic waiting for ipmi response ARM: DRA7: clockdomain: Change the CLKTRCTRL of CM_PCIE_CLKSTCTRL to SW_WKUP mmc: sdhci-of-esdhc: limit SD clock for ls1012a/ls1046a staging: wilc1000: fix unchecked return value staging: unisys: visorhba: fix s-Par to boot with option CONFIG_VMAP_STACK set to y mtip32xx: use runtime tag to initialize command header mfd: palmas: Reset the POWERHOLD mux during power off mac80211: don't parse encrypted management frames in ieee80211_frame_acked Btrfs: send, fix file hole not being preserved due to inline extent rndis_wlan: add return value validation mt7601u: check return value of alloc_skb iio: st_pressure: st_accel: Initialise sensor platform data properly NFS: don't try to cross a mountpount when there isn't one there. infiniband/uverbs: Fix integer overflows scsi: mac_esp: Replace bogus memory barrier with spinlock qlcnic: fix unchecked return value wan: pc300too: abort path on failure mmc: host: omap_hsmmc: checking for NULL instead of IS_ERR() openvswitch: Delete conntrack entry clashing with an expectation. netfilter: xt_CT: fix refcnt leak on error path Fix driver usage of 128B WQEs when WQ_CREATE is V1. ASoC: Intel: Skylake: Uninitialized variable in probe_codec() IB/mlx4: Change vma from shared to private IB/mlx4: Take write semaphore when changing the vma struct HSI: ssi_protocol: double free in ssip_pn_xmit() IB/ipoib: Update broadcast object if PKey value was changed in index 0 IB/ipoib: Fix deadlock between ipoib_stop and mcast join flow ALSA: hda - Fix headset microphone detection for ASUS N551 and N751 e1000e: fix timing for 82579 Gigabit Ethernet controller tcp: remove poll() flakes with FastOpen NFS: Fix missing pg_cleanup after nfs_pageio_cond_complete() md/raid10: wait up frozen array in handle_write_completed iommu/omap: Register driver before setting IOMMU ops ARM: 8668/1: ftrace: Fix dynamic ftrace with DEBUG_RODATA and !FRAME_POINTER KVM: PPC: Book3S PR: Exit KVM on failed mapping scsi: virtio_scsi: Always try to read VPD pages clk: ns2: Correct SDIO bits ath: Fix updating radar flags for coutry code India spi: dw: Disable clock after unregistering the host media/dvb-core: Race condition when writing to CAM net: ipv6: send unsolicited NA on admin up i2c: i2c-scmi: add a MS HID genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs cpufreq/sh: Replace racy task affinity logic ACPI/processor: Replace racy task affinity logic ACPI/processor: Fix error handling in __acpi_processor_start() time: Change posix clocks ops interfaces to use timespec64 Input: ar1021_i2c - fix too long name in driver's device table rtc: cmos: Do not assume irq 8 for rtc when there are no legacy irqs x86: i8259: export legacy_pic symbol regulator: anatop: set default voltage selector for pcie platform/x86: asus-nb-wmi: Add wapf4 quirk for the X302UA staging: android: ashmem: Fix possible deadlock in ashmem_ioctl CIFS: Enable encryption during session setup phase SMB3: Validate negotiate request must always be signed tpm_tis: fix potential buffer overruns caused by bit glitches on the bus tpm: fix potential buffer overruns caused by bit glitches on the bus BACKPORT, FROMLIST: crypto: arm64/speck - add NEON-accelerated implementation of Speck-XTS Linux 4.4.123 bpf: fix incorrect sign extension in check_alu_op() usb: gadget: bdc: 64-bit pointer capability check USB: gadget: udc: Add missing platform_device_put() on error in bdc_pci_probe() btrfs: Fix use-after-free when cleaning up fs_devs with a single stale device btrfs: alloc_chunk: fix DUP stripe size handling ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux scsi: sg: only check for dxfer_len greater than 256M scsi: sg: fix static checker warning in sg_is_valid_dxfer scsi: sg: fix SG_DXFER_FROM_DEV transfers irqchip/gic-v3-its: Ensure nr_ites >= nr_lpis fs/aio: Use RCU accessors for kioctx_table->table[] fs/aio: Add explicit RCU grace period when freeing kioctx lock_parent() needs to recheck if dentry got __dentry_kill'ed under it fs: Teach path_connected to handle nfs filesystems with multiple roots. drm/amdgpu/dce: Don't turn off DP sink when disconnected ALSA: seq: Clear client entry before deleting else at closing ALSA: seq: Fix possible UAF in snd_seq_check_queue() ALSA: hda - Revert power_save option default value ALSA: pcm: Fix UAF in snd_pcm_oss_get_formats() x86/mm: Fix vmalloc_fault to use pXd_large x86/vm86/32: Fix POPF emulation selftests/x86/entry_from_vm86: Add test cases for POPF selftests/x86: Add tests for the STR and SLDT instructions selftests/x86: Add tests for User-Mode Instruction Prevention selftests/x86/entry_from_vm86: Exit with 1 if we fail ima: relax requiring a file signature for new files with zero length rcutorture/configinit: Fix build directory error message ipvlan: add L2 check for packets arriving via virtual devices ASoC: nuc900: Fix a loop timeout test mac80211: remove BUG() when interface type is invalid mac80211_hwsim: enforce PS_MANUAL_POLL to be set after PS_ENABLED agp/intel: Flush all chipset writes after updating the GGTT drm/amdkfd: Fix memory leaks in kfd topology veth: set peer GSO values media: cpia2: Fix a couple off by one bugs scsi: dh: add new rdac devices scsi: devinfo: apply to HP XP the same flags as Hitachi VSP scsi: core: scsi_get_device_flags_keyed(): Always return device flags spi: sun6i: disable/unprepare clocks on remove tools/usbip: fixes build with musl libc toolchain ath10k: fix invalid STS_CAP_OFFSET_MASK clk: qcom: msm8916: fix mnd_width for codec_digcodec cpufreq: Fix governor module removal race ath10k: update tdls teardown state to target ARM: dts: omap3-n900: Fix the audio CODEC's reset pin ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin mtd: nand: fix interpretation of NAND_CMD_NONE in nand_command[_lp]() net: xfrm: allow clearing socket xfrm policies. test_firmware: fix setting old custom fw path back on exit sched: Stop resched_cpu() from sending IPIs to offline CPUs sched: Stop switched_to_rt() from sending IPIs to offline CPUs ARM: dts: exynos: Correct Trats2 panel reset line HID: elo: clear BTN_LEFT mapping video/hdmi: Allow "empty" HDMI infoframes drm/edid: set ELD connector type in drm_edid_to_eld() wil6210: fix memory access violation in wil_memcpy_from/toio_32 pwm: tegra: Increase precision in PWM rate calculation kprobes/x86: Set kprobes pages read-only kprobes/x86: Fix kprobe-booster not to boost far call instructions scsi: sg: close race condition in sg_remove_sfp_usercontext() scsi: sg: check for valid direction before starting the request perf session: Don't rely on evlist in pipe mode perf inject: Copy events when reordering events in pipe mode drivers/perf: arm_pmu: handle no platform_device usb: gadget: dummy_hcd: Fix wrong power status bit clear/reset in dummy_hub_control() usb: dwc2: Make sure we disconnect the gadget state md/raid6: Fix anomily when recovering a single device in RAID6. regulator: isl9305: fix array size MIPS: r2-on-r6-emu: Clear BLTZALL and BGEZALL debugfs counters MIPS: r2-on-r6-emu: Fix BLEZL and BGTZL identification MIPS: BPF: Fix multiple problems in JIT skb access helpers. MIPS: BPF: Quit clobbering callee saved registers in JIT code. coresight: Fixes coresight DT parse to get correct output port ID. drm/amdgpu: Fail fb creation from imported dma-bufs. (v2) drm/radeon: Fail fb creation from imported dma-bufs. video: ARM CLCD: fix dma allocation size iommu/iova: Fix underflow bug in __alloc_and_insert_iova_range apparmor: Make path_max parameter readonly scsi: ses: don't get power status of SES device slot on probe fm10k: correctly check if interface is removed ALSA: firewire-digi00x: handle all MIDI messages on streaming packets reiserfs: Make cancel_old_flush() reliable ARM: dts: koelsch: Correct clock frequency of X2 DU clock input net/faraday: Add missing include of of.h powerpc: Avoid taking a data miss on every userspace instruction miss ARM: dts: r8a7791: Correct parent of SSI[0-9] clocks ARM: dts: r8a7790: Correct parent of SSI[0-9] clocks NFC: nfcmrvl: double free on error path NFC: nfcmrvl: Include unaligned.h instead of access_ok.h vxlan: vxlan dev should inherit lowerdev's gso_max_size drm/vmwgfx: Fixes to vmwgfx_fb braille-console: Fix value returned by _braille_console_setup bonding: refine bond_fold_stats() wrap detection f2fs: relax node version check for victim data in gc blk-throttle: make sure expire time isn't too big mm: Fix false-positive VM_BUG_ON() in page_cache_{get,add}_speculative() driver: (adm1275) set the m,b and R coefficients correctly for power dmaengine: imx-sdma: add 1ms delay to ensure SDMA channel is stopped tcp: sysctl: Fix a race to avoid unexpected 0 window from space spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer ASoC: rcar: ssi: don't set SSICR.CKDV = 000 with SSIWSR.CONT sched: act_csum: don't mangle TCP and UDP GSO packets Input: qt1070 - add OF device ID table sysrq: Reset the watchdog timers while displaying high-resolution timers timers, sched_clock: Update timeout for clock wrap media: i2c/soc_camera: fix ov6650 sensor getting wrong clock scsi: ipr: Fix missed EH wakeup solo6x10: release vb2 buffers in solo_stop_streaming() of: fix of_device_get_modalias returned length when truncating buffers batman-adv: handle race condition for claims between gateways ARM: dts: Adjust moxart IRQ controller and flags net/8021q: create device with all possible features in wanted_features HID: clamp input to logical range if no null state perf probe: Return errno when not hitting any event ath10k: disallow DFS simulation if DFS channel is not enabled drm: Defer disabling the vblank IRQ until the next interrupt (for instant-off) drivers: net: xgene: Fix hardware checksum setting perf tools: Make perf_event__synthesize_mmap_events() scale i40e: fix ethtool to get EEPROM data from X722 interface i40e: Acquire NVM lock before reads on all devices perf sort: Fix segfault with basic block 'cycles' sort dimension selinux: check for address length in selinux_socket_bind() PCI/MSI: Stop disabling MSI/MSI-X in pci_device_shutdown() ath10k: fix a warning during channel switch with multiple vaps drm: qxl: Don't alloc fbdev if emulation is not supported HID: reject input outside logical range only if null state is set staging: wilc1000: add check for kmalloc allocation failure. staging: speakup: Replace BUG_ON() with WARN_ON(). Input: tsc2007 - check for presence and power down tsc2007 during probe blkcg: fix double free of new_blkg in blkcg_init_queue ANDROID: cpufreq: times: avoid prematurely freeing uid_entry ANDROID: Use standard logging functions in goldfish_pipe ANDROID: Fix whitespace in goldfish staging: android: ashmem: Fix possible deadlock in ashmem_ioctl llist: clang: introduce member_address_is_nonnull() Linux 4.4.122 fixup: sctp: verify size of a new chunk in _sctp_make_chunk() serial: 8250_pci: Add Brainboxes UC-260 4 port serial device usb: gadget: f_fs: Fix use-after-free in ffs_fs_kill_sb() usb: usbmon: Read text within supplied buffer size USB: usbmon: remove assignment from IS_ERR argument usb: quirks: add control message delay for 1b1c:1b20 USB: storage: Add JMicron bridge 152d:2567 to unusual_devs.h staging: android: ashmem: Fix lockdep issue during llseek staging: comedi: fix comedi_nsamples_left. uas: fix comparison for error code tty/serial: atmel: add new version check for usart serial: sh-sci: prevent lockup on full TTY buffers x86: Treat R_X86_64_PLT32 as R_X86_64_PC32 x86/module: Detect and skip invalid relocations Revert "ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux" NFS: Fix an incorrect type in struct nfs_direct_req scsi: qla2xxx: Replace fcport alloc with qla2x00_alloc_fcport ubi: Fix race condition between ubi volume creation and udev ext4: inplace xattr block update fails to deduplicate blocks netfilter: x_tables: pack percpu counter allocations netfilter: x_tables: pass xt_counters struct to counter allocator netfilter: x_tables: pass xt_counters struct instead of packet counter netfilter: use skb_to_full_sk in ip_route_me_harder netfilter: ipv6: fix use-after-free Write in nf_nat_ipv6_manip_pkt netfilter: bridge: ebt_among: add missing match size checks netfilter: ebtables: CONFIG_COMPAT: don't trust userland offsets netfilter: IDLETIMER: be syzkaller friendly netfilter: nat: cope with negative port range netfilter: x_tables: fix missing timer initialization in xt_LED netfilter: add back stackpointer size checks tc358743: fix register i2c_rd/wr function fix Input: tca8418_keypad - remove double read of key event register ARM: omap2: hide omap3_save_secure_ram on non-OMAP3 builds netfilter: nfnetlink_queue: fix timestamp attribute watchdog: hpwdt: fix unused variable warning watchdog: hpwdt: Check source of NMI watchdog: hpwdt: SMBIOS check nospec: Include <asm/barrier.h> dependency ALSA: hda: add dock and led support for HP ProBook 640 G2 ALSA: hda: add dock and led support for HP EliteBook 820 G3 ALSA: seq: More protection for concurrent write and ioctl races ALSA: seq: Don't allow resizing pool in use ALSA: hda/realtek - Fix dock line-out volume on Dell Precision 7520 x86/MCE: Serialize sysfs changes bcache: don't attach backing with duplicate UUID kbuild: Handle builtin dtb file names containing hyphens loop: Fix lost writes caused by missing flag Input: matrix_keypad - fix race when disabling interrupts MIPS: OCTEON: irq: Check for null return on kzalloc allocation MIPS: ath25: Check for kzalloc allocation failure MIPS: BMIPS: Do not mask IPIs during suspend drm/amdgpu: fix KV harvesting drm/radeon: fix KV harvesting drm/amdgpu: Notify sbios device ready before send request drm/amdgpu: Fix deadlock on runtime suspend drm/radeon: Fix deadlock on runtime suspend drm/nouveau: Fix deadlock on runtime suspend drm: Allow determining if current task is output poll worker workqueue: Allow retrieval of current task's work struct scsi: qla2xxx: Fix NULL pointer crash due to active timer for ABTS RDMA/mlx5: Fix integer overflow while resizing CQ RDMA/ucma: Check that user doesn't overflow QP state RDMA/ucma: Limit possible option size ANDROID: ranchu: 32 bit framebuffer support ANDROID: Address checkpatch warnings in goldfishfb ANDROID: Address checkpatch.pl warnings in goldfish_pipe ANDROID: sdcardfs: fix lock issue on 32 bit/SMP architectures ANDROID: goldfish: Fix typo in goldfish_cmd_locked() call ANDROID: Address checkpatch.pl warnings in goldfish_pipe_v2 FROMLIST: f2fs: don't put dentry page in pagecache into highmem Linux 4.4.121 btrfs: preserve i_mode if __btrfs_set_acl() fails bpf, x64: implement retpoline for tail call dm io: fix duplicate bio completion due to missing ref count mpls, nospec: Sanitize array index in mpls_label_ok() net: mpls: Pull common label check into helper sctp: verify size of a new chunk in _sctp_make_chunk() s390/qeth: fix IPA command submission race s390/qeth: fix SETIP command handling sctp: fix dst refcnt leak in sctp_v6_get_dst() sctp: fix dst refcnt leak in sctp_v4_get_dst udplite: fix partial checksum initialization ppp: prevent unregistered channels from connecting to PPP units netlink: ensure to loop over all netns in genlmsg_multicast_allns() net: ipv4: don't allow setting net.ipv4.route.min_pmtu below 68 net: fix race on decreasing number of TX queues ipv6 sit: work around bogus gcc-8 -Wrestrict warning hdlc_ppp: carrier detect ok, don't turn off negotiation fib_semantics: Don't match route with mismatching tclassid bridge: check brport attr show in brport_show Revert "led: core: Fix brightness setting when setting delay_off=0" x86/spectre: Fix an error message leds: do not overflow sysfs buffer in led_trigger_show x86/apic/vector: Handle legacy irq data correctly ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux btrfs: Don't clear SGID when inheriting ACLs x86/syscall: Sanitize syscall table de-references under speculation fix KVM: mmu: Fix overlap between public and private memslots ARM: mvebu: Fix broken PL310_ERRATA_753970 selects nospec: Allow index argument to have const-qualified type media: m88ds3103: don't call a non-initalized function cpufreq: s3c24xx: Fix broken s3c_cpufreq_init() ALSA: hda: Add a power_save blacklist ALSA: usb-audio: Add a quirck for B&W PX headphones tpm_i2c_nuvoton: fix potential buffer overruns caused by bit glitches on the bus tpm_i2c_infineon: fix potential buffer overruns caused by bit glitches on the bus tpm: st33zp24: fix potential buffer overruns caused by bit glitches on the bus ANDROID: Delete the goldfish_nand driver. ANDROID: Add input support for Android Wear. ANDROID: proc: fix config & includes for /proc/uid FROMLIST: ARM: amba: Don't read past the end of sysfs "driver_override" buffer UPSTREAM: ANDROID: binder: remove WARN() for redundant txn error ANDROID: cpufreq: times: Add missing includes 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 Conflicts: drivers/gpu/drm/msm/msm_gem.c drivers/net/wireless/ath/regd.c kernel/sched/core.c Change-Id: I9bb7b5a062415da6925a5a56a34e6eb066a53320 Signed-off-by: Srinivasarao P <spathi@codeaurora.org>
1369 lines
34 KiB
C
1369 lines
34 KiB
C
/*
|
|
* Based on arch/arm/mm/mmu.c
|
|
*
|
|
* Copyright (C) 1995-2005 Russell King
|
|
* Copyright (C) 2012 ARM Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <linux/export.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/init.h>
|
|
#include <linux/libfdt.h>
|
|
#include <linux/mman.h>
|
|
#include <linux/nodemask.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/io.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/stop_machine.h>
|
|
#include <linux/dma-contiguous.h>
|
|
#include <linux/cma.h>
|
|
#include <linux/mm.h>
|
|
|
|
#include <asm/barrier.h>
|
|
#include <asm/cputype.h>
|
|
#include <asm/fixmap.h>
|
|
#include <asm/kasan.h>
|
|
#include <asm/kernel-pgtable.h>
|
|
#include <asm/sections.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/sizes.h>
|
|
#include <asm/tlb.h>
|
|
#include <asm/memblock.h>
|
|
#include <asm/mmu_context.h>
|
|
|
|
#include "mm.h"
|
|
|
|
u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
|
|
|
|
u64 kimage_voffset __read_mostly;
|
|
EXPORT_SYMBOL(kimage_voffset);
|
|
|
|
/*
|
|
* Empty_zero_page is a special page that is used for zero-initialized data
|
|
* and COW.
|
|
*/
|
|
unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
|
|
EXPORT_SYMBOL(empty_zero_page);
|
|
|
|
static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
|
|
static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
|
|
static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
|
|
|
|
static bool dma_overlap(phys_addr_t start, phys_addr_t end);
|
|
|
|
pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
|
|
unsigned long size, pgprot_t vma_prot)
|
|
{
|
|
if (!pfn_valid(pfn))
|
|
return pgprot_noncached(vma_prot);
|
|
else if (file->f_flags & O_SYNC)
|
|
return pgprot_writecombine(vma_prot);
|
|
return vma_prot;
|
|
}
|
|
EXPORT_SYMBOL(phys_mem_access_prot);
|
|
|
|
static phys_addr_t __init early_pgtable_alloc(void)
|
|
{
|
|
phys_addr_t phys;
|
|
void *ptr;
|
|
|
|
phys = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
|
|
BUG_ON(!phys);
|
|
|
|
/*
|
|
* The FIX_{PGD,PUD,PMD} slots may be in active use, but the FIX_PTE
|
|
* slot will be free, so we can (ab)use the FIX_PTE slot to initialise
|
|
* any level of table.
|
|
*/
|
|
ptr = pte_set_fixmap(phys);
|
|
|
|
memset(ptr, 0, PAGE_SIZE);
|
|
|
|
/*
|
|
* Implicit barriers also ensure the zeroed page is visible to the page
|
|
* table walker
|
|
*/
|
|
pte_clear_fixmap();
|
|
|
|
return phys;
|
|
}
|
|
|
|
/*
|
|
* remap a PMD into pages
|
|
*/
|
|
static void split_pmd(pmd_t *pmd, pte_t *pte)
|
|
{
|
|
unsigned long pfn = pmd_pfn(*pmd);
|
|
int i = 0;
|
|
|
|
do {
|
|
/*
|
|
* Need to have the least restrictive permissions available
|
|
* permissions will be fixed up later
|
|
*/
|
|
set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
|
|
pfn++;
|
|
} while (pte++, i++, i < PTRS_PER_PTE);
|
|
}
|
|
|
|
static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
|
|
unsigned long end, unsigned long pfn,
|
|
pgprot_t prot,
|
|
phys_addr_t (*pgtable_alloc)(void))
|
|
{
|
|
pte_t *pte;
|
|
|
|
if (pmd_none(*pmd) || pmd_sect(*pmd)) {
|
|
phys_addr_t pte_phys;
|
|
BUG_ON(!pgtable_alloc);
|
|
pte_phys = pgtable_alloc();
|
|
pte = pte_set_fixmap(pte_phys);
|
|
if (pmd_sect(*pmd))
|
|
split_pmd(pmd, pte);
|
|
__pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE);
|
|
flush_tlb_all();
|
|
pte_clear_fixmap();
|
|
}
|
|
BUG_ON(pmd_bad(*pmd));
|
|
|
|
pte = pte_set_fixmap_offset(pmd, addr);
|
|
do {
|
|
set_pte(pte, pfn_pte(pfn, prot));
|
|
pfn++;
|
|
} while (pte++, addr += PAGE_SIZE, addr != end);
|
|
|
|
pte_clear_fixmap();
|
|
}
|
|
|
|
static void split_pud(pud_t *old_pud, pmd_t *pmd)
|
|
{
|
|
unsigned long addr = pud_pfn(*old_pud) << PAGE_SHIFT;
|
|
pgprot_t prot = __pgprot(pud_val(*old_pud) ^ addr);
|
|
int i = 0;
|
|
|
|
do {
|
|
set_pmd(pmd, __pmd(addr | pgprot_val(prot)));
|
|
addr += PMD_SIZE;
|
|
} while (pmd++, i++, i < PTRS_PER_PMD);
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_PAGEALLOC
|
|
static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
|
|
{
|
|
|
|
/*
|
|
* If debug_page_alloc is enabled we must map the linear map
|
|
* using pages. However, other mappings created by
|
|
* create_mapping_noalloc must use sections in some cases. Allow
|
|
* sections to be used in those cases, where no pgtable_alloc
|
|
* function is provided.
|
|
*/
|
|
return !pgtable_alloc || !debug_pagealloc_enabled();
|
|
}
|
|
#else
|
|
static bool block_mappings_allowed(phys_addr_t (*pgtable_alloc)(void))
|
|
{
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
static void alloc_init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
|
|
phys_addr_t phys, pgprot_t prot,
|
|
phys_addr_t (*pgtable_alloc)(void))
|
|
{
|
|
pmd_t *pmd;
|
|
unsigned long next;
|
|
|
|
/*
|
|
* Check for initial section mappings in the pgd/pud and remove them.
|
|
*/
|
|
if (pud_none(*pud) || pud_sect(*pud)) {
|
|
phys_addr_t pmd_phys;
|
|
BUG_ON(!pgtable_alloc);
|
|
pmd_phys = pgtable_alloc();
|
|
pmd = pmd_set_fixmap(pmd_phys);
|
|
if (pud_sect(*pud)) {
|
|
/*
|
|
* need to have the 1G of mappings continue to be
|
|
* present
|
|
*/
|
|
split_pud(pud, pmd);
|
|
}
|
|
__pud_populate(pud, pmd_phys, PUD_TYPE_TABLE);
|
|
flush_tlb_all();
|
|
pmd_clear_fixmap();
|
|
}
|
|
BUG_ON(pud_bad(*pud));
|
|
|
|
pmd = pmd_set_fixmap_offset(pud, addr);
|
|
do {
|
|
next = pmd_addr_end(addr, end);
|
|
/* try section mapping first */
|
|
if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
|
|
block_mappings_allowed(pgtable_alloc) &&
|
|
!dma_overlap(phys, phys + next - addr)) {
|
|
pmd_t old_pmd =*pmd;
|
|
pmd_set_huge(pmd, phys, prot);
|
|
/*
|
|
* Check for previous table entries created during
|
|
* boot (__create_page_tables) and flush them.
|
|
*/
|
|
if (!pmd_none(old_pmd)) {
|
|
flush_tlb_all();
|
|
if (pmd_table(old_pmd)) {
|
|
phys_addr_t table = pmd_page_paddr(old_pmd);
|
|
if (!WARN_ON_ONCE(slab_is_available()))
|
|
memblock_free(table, PAGE_SIZE);
|
|
}
|
|
}
|
|
} else {
|
|
alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
|
|
prot, pgtable_alloc);
|
|
}
|
|
phys += next - addr;
|
|
} while (pmd++, addr = next, addr != end);
|
|
|
|
pmd_clear_fixmap();
|
|
}
|
|
|
|
static inline bool use_1G_block(unsigned long addr, unsigned long next,
|
|
unsigned long phys)
|
|
{
|
|
if (PAGE_SHIFT != 12)
|
|
return false;
|
|
|
|
if (((addr | next | phys) & ~PUD_MASK) != 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
|
|
phys_addr_t phys, pgprot_t prot,
|
|
phys_addr_t (*pgtable_alloc)(void))
|
|
{
|
|
pud_t *pud;
|
|
unsigned long next;
|
|
|
|
if (pgd_none(*pgd)) {
|
|
phys_addr_t pud_phys;
|
|
BUG_ON(!pgtable_alloc);
|
|
pud_phys = pgtable_alloc();
|
|
__pgd_populate(pgd, pud_phys, PUD_TYPE_TABLE);
|
|
}
|
|
BUG_ON(pgd_bad(*pgd));
|
|
|
|
pud = pud_set_fixmap_offset(pgd, addr);
|
|
do {
|
|
next = pud_addr_end(addr, end);
|
|
|
|
/*
|
|
* For 4K granule only, attempt to put down a 1GB block
|
|
*/
|
|
if (use_1G_block(addr, next, phys) &&
|
|
block_mappings_allowed(pgtable_alloc) &&
|
|
!dma_overlap(phys, phys + next - addr)) {
|
|
pud_t old_pud = *pud;
|
|
pud_set_huge(pud, phys, prot);
|
|
|
|
/*
|
|
* If we have an old value for a pud, it will
|
|
* be pointing to a pmd table that we no longer
|
|
* need (from swapper_pg_dir).
|
|
*
|
|
* Look up the old pmd table and free it.
|
|
*/
|
|
if (!pud_none(old_pud)) {
|
|
flush_tlb_all();
|
|
if (pud_table(old_pud)) {
|
|
phys_addr_t table = pud_page_paddr(old_pud);
|
|
if (!WARN_ON_ONCE(slab_is_available()))
|
|
memblock_free(table, PAGE_SIZE);
|
|
}
|
|
}
|
|
} else {
|
|
alloc_init_pmd(pud, addr, next, phys, prot,
|
|
pgtable_alloc);
|
|
}
|
|
phys += next - addr;
|
|
} while (pud++, addr = next, addr != end);
|
|
|
|
pud_clear_fixmap();
|
|
}
|
|
|
|
/*
|
|
* Create the page directory entries and any necessary page tables for the
|
|
* mapping specified by 'md'.
|
|
*/
|
|
static void init_pgd(pgd_t *pgd, phys_addr_t phys, unsigned long virt,
|
|
phys_addr_t size, pgprot_t prot,
|
|
phys_addr_t (*pgtable_alloc)(void))
|
|
{
|
|
unsigned long addr, length, end, next;
|
|
|
|
/*
|
|
* If the virtual and physical address don't have the same offset
|
|
* within a page, we cannot map the region as the caller expects.
|
|
*/
|
|
if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
|
|
return;
|
|
|
|
phys &= PAGE_MASK;
|
|
addr = virt & PAGE_MASK;
|
|
length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
|
|
|
|
end = addr + length;
|
|
do {
|
|
next = pgd_addr_end(addr, end);
|
|
alloc_init_pud(pgd, addr, next, phys, prot, pgtable_alloc);
|
|
phys += next - addr;
|
|
} while (pgd++, addr = next, addr != end);
|
|
}
|
|
|
|
static phys_addr_t late_pgtable_alloc(void)
|
|
{
|
|
void *ptr = (void *)__get_free_page(PGALLOC_GFP);
|
|
BUG_ON(!ptr);
|
|
|
|
/* Ensure the zeroed page is visible to the page table walker */
|
|
dsb(ishst);
|
|
return __pa(ptr);
|
|
}
|
|
|
|
static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
|
|
unsigned long virt, phys_addr_t size,
|
|
pgprot_t prot,
|
|
phys_addr_t (*alloc)(void))
|
|
{
|
|
init_pgd(pgd_offset_raw(pgdir, virt), phys, virt, size, prot, alloc);
|
|
}
|
|
|
|
/*
|
|
* This function can only be used to modify existing table entries,
|
|
* without allocating new levels of table. Note that this permits the
|
|
* creation of new section or page entries.
|
|
*/
|
|
static void __init create_mapping_noalloc(phys_addr_t phys, unsigned long virt,
|
|
phys_addr_t size, pgprot_t prot)
|
|
{
|
|
if (virt < VMALLOC_START) {
|
|
pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
|
|
&phys, virt);
|
|
return;
|
|
}
|
|
__create_pgd_mapping(init_mm.pgd, phys, virt, size, prot,
|
|
NULL);
|
|
}
|
|
|
|
void __init create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
|
|
unsigned long virt, phys_addr_t size,
|
|
pgprot_t prot)
|
|
{
|
|
__create_pgd_mapping(mm->pgd, phys, virt, size, prot,
|
|
late_pgtable_alloc);
|
|
}
|
|
|
|
static void create_mapping_late(phys_addr_t phys, unsigned long virt,
|
|
phys_addr_t size, pgprot_t prot)
|
|
{
|
|
if (virt < VMALLOC_START) {
|
|
pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
|
|
&phys, virt);
|
|
return;
|
|
}
|
|
|
|
__create_pgd_mapping(init_mm.pgd, phys, virt, size, prot,
|
|
late_pgtable_alloc);
|
|
}
|
|
|
|
static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
|
|
{
|
|
unsigned long kernel_start = __pa_symbol(_text);
|
|
unsigned long kernel_end = __pa_symbol(__init_begin);
|
|
|
|
/*
|
|
* Take care not to create a writable alias for the
|
|
* read-only text and rodata sections of the kernel image.
|
|
*/
|
|
|
|
/* No overlap with the kernel text/rodata */
|
|
if (end < kernel_start || start >= kernel_end) {
|
|
__create_pgd_mapping(pgd, start, __phys_to_virt(start),
|
|
end - start, PAGE_KERNEL,
|
|
early_pgtable_alloc);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This block overlaps the kernel text/rodata mappings.
|
|
* Map the portion(s) which don't overlap.
|
|
*/
|
|
if (start < kernel_start)
|
|
__create_pgd_mapping(pgd, start,
|
|
__phys_to_virt(start),
|
|
kernel_start - start, PAGE_KERNEL,
|
|
early_pgtable_alloc);
|
|
if (kernel_end < end)
|
|
__create_pgd_mapping(pgd, kernel_end,
|
|
__phys_to_virt(kernel_end),
|
|
end - kernel_end, PAGE_KERNEL,
|
|
early_pgtable_alloc);
|
|
|
|
/*
|
|
* Map the linear alias of the [_text, __init_begin) interval as
|
|
* read-only/non-executable. This makes the contents of the
|
|
* region accessible to subsystems such as hibernate, but
|
|
* protects it from inadvertent modification or execution.
|
|
*/
|
|
__create_pgd_mapping(pgd, kernel_start, __phys_to_virt(kernel_start),
|
|
kernel_end - kernel_start, PAGE_KERNEL_RO,
|
|
early_pgtable_alloc);
|
|
}
|
|
|
|
static void __init map_mem(pgd_t *pgd)
|
|
{
|
|
struct memblock_region *reg;
|
|
|
|
/* map all the memory banks */
|
|
for_each_memblock(memory, reg) {
|
|
phys_addr_t start = reg->base;
|
|
phys_addr_t end = start + reg->size;
|
|
|
|
if (start >= end)
|
|
break;
|
|
if (memblock_is_nomap(reg))
|
|
continue;
|
|
|
|
__map_memblock(pgd, start, end);
|
|
}
|
|
}
|
|
|
|
void mark_rodata_ro(void)
|
|
{
|
|
unsigned long section_size;
|
|
|
|
section_size = (unsigned long)_etext - (unsigned long)_text;
|
|
create_mapping_late(__pa_symbol(_text), (unsigned long)_text,
|
|
section_size, PAGE_KERNEL_ROX);
|
|
/*
|
|
* mark .rodata as read only. Use __init_begin rather than __end_rodata
|
|
* to cover NOTES and EXCEPTION_TABLE.
|
|
*/
|
|
section_size = (unsigned long)__init_begin - (unsigned long)__start_rodata;
|
|
create_mapping_late(__pa_symbol(__start_rodata),
|
|
(unsigned long)__start_rodata,
|
|
section_size, PAGE_KERNEL_RO);
|
|
}
|
|
|
|
void fixup_init(void)
|
|
{
|
|
/*
|
|
* Unmap the __init region but leave the VM area in place. This
|
|
* prevents the region from being reused for kernel modules, which
|
|
* is not supported by kallsyms.
|
|
*/
|
|
unmap_kernel_range((u64)__init_begin, (u64)(__init_end - __init_begin));
|
|
}
|
|
|
|
static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
|
|
pgprot_t prot, struct vm_struct *vma)
|
|
{
|
|
phys_addr_t pa_start = __pa_symbol(va_start);
|
|
unsigned long size = va_end - va_start;
|
|
|
|
BUG_ON(!PAGE_ALIGNED(pa_start));
|
|
BUG_ON(!PAGE_ALIGNED(size));
|
|
|
|
__create_pgd_mapping(pgd, pa_start, (unsigned long)va_start, size, prot,
|
|
early_pgtable_alloc);
|
|
|
|
vma->addr = va_start;
|
|
vma->phys_addr = pa_start;
|
|
vma->size = size;
|
|
vma->flags = VM_MAP;
|
|
vma->caller = __builtin_return_address(0);
|
|
|
|
vm_area_add_early(vma);
|
|
}
|
|
|
|
#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
|
|
static int __init map_entry_trampoline(void)
|
|
{
|
|
extern char __entry_tramp_text_start[];
|
|
|
|
pgprot_t prot = PAGE_KERNEL_EXEC;
|
|
phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
|
|
|
|
/* The trampoline is always mapped and can therefore be global */
|
|
pgprot_val(prot) &= ~PTE_NG;
|
|
|
|
/* Map only the text into the trampoline page table */
|
|
memset(tramp_pg_dir, 0, PGD_SIZE);
|
|
__create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
|
|
prot, late_pgtable_alloc);
|
|
|
|
/* Map both the text and data into the kernel page table */
|
|
__set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
|
|
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
|
extern char __entry_tramp_data_start[];
|
|
|
|
__set_fixmap(FIX_ENTRY_TRAMP_DATA,
|
|
__pa_symbol(__entry_tramp_data_start),
|
|
PAGE_KERNEL_RO);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
core_initcall(map_entry_trampoline);
|
|
#endif
|
|
|
|
/*
|
|
* Create fine-grained mappings for the kernel.
|
|
*/
|
|
static void __init map_kernel(pgd_t *pgd)
|
|
{
|
|
static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_init, vmlinux_data;
|
|
|
|
map_kernel_segment(pgd, _text, _etext, PAGE_KERNEL_EXEC, &vmlinux_text);
|
|
map_kernel_segment(pgd, __start_rodata, __init_begin, PAGE_KERNEL, &vmlinux_rodata);
|
|
map_kernel_segment(pgd, __init_begin, __init_end, PAGE_KERNEL_EXEC,
|
|
&vmlinux_init);
|
|
map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data);
|
|
|
|
if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) {
|
|
/*
|
|
* The fixmap falls in a separate pgd to the kernel, and doesn't
|
|
* live in the carveout for the swapper_pg_dir. We can simply
|
|
* re-use the existing dir for the fixmap.
|
|
*/
|
|
set_pgd(pgd_offset_raw(pgd, FIXADDR_START),
|
|
*pgd_offset_k(FIXADDR_START));
|
|
} else if (CONFIG_PGTABLE_LEVELS > 3) {
|
|
/*
|
|
* The fixmap shares its top level pgd entry with the kernel
|
|
* mapping. This can really only occur when we are running
|
|
* with 16k/4 levels, so we can simply reuse the pud level
|
|
* entry instead.
|
|
*/
|
|
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
|
|
set_pud(pud_set_fixmap_offset(pgd, FIXADDR_START),
|
|
__pud(__pa_symbol(bm_pmd) | PUD_TYPE_TABLE));
|
|
pud_clear_fixmap();
|
|
} else {
|
|
BUG();
|
|
}
|
|
|
|
kasan_copy_shadow(pgd);
|
|
}
|
|
|
|
struct dma_contig_early_reserve {
|
|
phys_addr_t base;
|
|
unsigned long size;
|
|
};
|
|
|
|
static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS];
|
|
|
|
static int dma_mmu_remap_num;
|
|
|
|
void __init dma_contiguous_early_fixup(phys_addr_t base, unsigned long size)
|
|
{
|
|
dma_mmu_remap[dma_mmu_remap_num].base = base;
|
|
dma_mmu_remap[dma_mmu_remap_num].size = size;
|
|
dma_mmu_remap_num++;
|
|
}
|
|
|
|
static bool dma_overlap(phys_addr_t start, phys_addr_t end)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < dma_mmu_remap_num; i++) {
|
|
phys_addr_t dma_base = dma_mmu_remap[i].base;
|
|
phys_addr_t dma_end = dma_mmu_remap[i].base +
|
|
dma_mmu_remap[i].size;
|
|
|
|
if ((dma_base < end) && (dma_end > start))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* paging_init() sets up the page tables, initialises the zone memory
|
|
* maps and sets up the zero page.
|
|
*/
|
|
void __init paging_init(void)
|
|
{
|
|
phys_addr_t pgd_phys = early_pgtable_alloc();
|
|
pgd_t *pgd = pgd_set_fixmap(pgd_phys);
|
|
|
|
map_kernel(pgd);
|
|
map_mem(pgd);
|
|
|
|
/*
|
|
* We want to reuse the original swapper_pg_dir so we don't have to
|
|
* communicate the new address to non-coherent secondaries in
|
|
* secondary_entry, and so cpu_switch_mm can generate the address with
|
|
* adrp+add rather than a load from some global variable.
|
|
*
|
|
* To do this we need to go via a temporary pgd.
|
|
*/
|
|
cpu_replace_ttbr1(__va(pgd_phys));
|
|
memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
|
|
cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
|
|
|
|
pgd_clear_fixmap();
|
|
memblock_free(pgd_phys, PAGE_SIZE);
|
|
|
|
/*
|
|
* We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
|
|
* allocated with it.
|
|
*/
|
|
memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
|
|
SWAPPER_DIR_SIZE - PAGE_SIZE);
|
|
|
|
bootmem_init();
|
|
}
|
|
|
|
#ifdef CONFIG_MEMORY_HOTPLUG
|
|
static phys_addr_t pgd_pgtable_alloc(void)
|
|
{
|
|
void *ptr = (void *)__get_free_page(PGALLOC_GFP);
|
|
if (!ptr || !pgtable_page_ctor(virt_to_page(ptr)))
|
|
BUG();
|
|
|
|
/* Ensure the zeroed page is visible to the page table walker */
|
|
dsb(ishst);
|
|
return __pa(ptr);
|
|
}
|
|
|
|
/*
|
|
* hotplug_paging() is used by memory hotplug to build new page tables
|
|
* for hot added memory.
|
|
*/
|
|
void hotplug_paging(phys_addr_t start, phys_addr_t size)
|
|
{
|
|
|
|
struct page *pg;
|
|
phys_addr_t pgd_phys = pgd_pgtable_alloc();
|
|
pgd_t *pgd = pgd_set_fixmap(pgd_phys);
|
|
|
|
memcpy(pgd, swapper_pg_dir, PAGE_SIZE);
|
|
|
|
__create_pgd_mapping(pgd, start, __phys_to_virt(start), size,
|
|
PAGE_KERNEL, pgd_pgtable_alloc);
|
|
|
|
cpu_replace_ttbr1(__va(pgd_phys));
|
|
memcpy(swapper_pg_dir, pgd, PAGE_SIZE);
|
|
cpu_replace_ttbr1(swapper_pg_dir);
|
|
|
|
pgd_clear_fixmap();
|
|
|
|
pg = phys_to_page(pgd_phys);
|
|
pgtable_page_dtor(pg);
|
|
__free_pages(pg, 0);
|
|
}
|
|
|
|
#ifdef CONFIG_MEMORY_HOTREMOVE
|
|
#define PAGE_INUSE 0xFD
|
|
|
|
static void free_pagetable(struct page *page, int order, bool direct)
|
|
{
|
|
unsigned long magic;
|
|
unsigned int nr_pages = 1 << order;
|
|
|
|
/* bootmem page has reserved flag */
|
|
if (PageReserved(page)) {
|
|
__ClearPageReserved(page);
|
|
|
|
magic = (unsigned long)page->lru.next;
|
|
if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) {
|
|
while (nr_pages--)
|
|
put_page_bootmem(page++);
|
|
} else {
|
|
while (nr_pages--)
|
|
free_reserved_page(page++);
|
|
}
|
|
} else {
|
|
/*
|
|
* Only direct pagetable allocation (those allocated via
|
|
* hotplug) call the pgtable_page_ctor; vmemmap pgtable
|
|
* allocations don't.
|
|
*/
|
|
if (direct)
|
|
pgtable_page_dtor(page);
|
|
|
|
free_pages((unsigned long)page_address(page), order);
|
|
}
|
|
}
|
|
|
|
static void free_pte_table(pmd_t *pmd, bool direct)
|
|
{
|
|
pte_t *pte_start, *pte;
|
|
struct page *page;
|
|
int i;
|
|
|
|
pte_start = (pte_t *) pmd_page_vaddr(*pmd);
|
|
/* Check if there is no valid entry in the PMD */
|
|
for (i = 0; i < PTRS_PER_PTE; i++) {
|
|
pte = pte_start + i;
|
|
if (!pte_none(*pte))
|
|
return;
|
|
}
|
|
|
|
page = pmd_page(*pmd);
|
|
|
|
free_pagetable(page, 0, direct);
|
|
|
|
/*
|
|
* This spin lock could be only taken in _pte_aloc_kernel
|
|
* in mm/memory.c and nowhere else (for arm64). Not sure if
|
|
* the function above can be called concurrently. In doubt,
|
|
* I am living it here for now, but it probably can be removed
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pmd_clear(pmd);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
}
|
|
|
|
static void free_pmd_table(pud_t *pud, bool direct)
|
|
{
|
|
pmd_t *pmd_start, *pmd;
|
|
struct page *page;
|
|
int i;
|
|
|
|
pmd_start = (pmd_t *) pud_page_vaddr(*pud);
|
|
/* Check if there is no valid entry in the PMD */
|
|
for (i = 0; i < PTRS_PER_PMD; i++) {
|
|
pmd = pmd_start + i;
|
|
if (!pmd_none(*pmd))
|
|
return;
|
|
}
|
|
|
|
page = pud_page(*pud);
|
|
|
|
free_pagetable(page, 0, direct);
|
|
|
|
/*
|
|
* This spin lock could be only taken in _pte_aloc_kernel
|
|
* in mm/memory.c and nowhere else (for arm64). Not sure if
|
|
* the function above can be called concurrently. In doubt,
|
|
* I am living it here for now, but it probably can be removed
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pud_clear(pud);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
}
|
|
|
|
/*
|
|
* When the PUD is folded on the PGD (three levels of paging),
|
|
* there's no need to free PUDs
|
|
*/
|
|
#if CONFIG_PGTABLE_LEVELS > 3
|
|
static void free_pud_table(pgd_t *pgd, bool direct)
|
|
{
|
|
pud_t *pud_start, *pud;
|
|
struct page *page;
|
|
int i;
|
|
|
|
pud_start = (pud_t *) pgd_page_vaddr(*pgd);
|
|
/* Check if there is no valid entry in the PUD */
|
|
for (i = 0; i < PTRS_PER_PUD; i++) {
|
|
pud = pud_start + i;
|
|
if (!pud_none(*pud))
|
|
return;
|
|
}
|
|
|
|
page = pgd_page(*pgd);
|
|
|
|
free_pagetable(page, 0, direct);
|
|
|
|
/*
|
|
* This spin lock could be only
|
|
* taken in _pte_aloc_kernel in
|
|
* mm/memory.c and nowhere else
|
|
* (for arm64). Not sure if the
|
|
* function above can be called
|
|
* concurrently. In doubt,
|
|
* I am living it here for now,
|
|
* but it probably can be removed.
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pgd_clear(pgd);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
}
|
|
#endif
|
|
|
|
static void remove_pte_table(pte_t *pte, unsigned long addr,
|
|
unsigned long end, bool direct)
|
|
{
|
|
unsigned long next;
|
|
void *page_addr;
|
|
|
|
for (; addr < end; addr = next, pte++) {
|
|
next = (addr + PAGE_SIZE) & PAGE_MASK;
|
|
if (next > end)
|
|
next = end;
|
|
|
|
if (!pte_present(*pte))
|
|
continue;
|
|
|
|
if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) {
|
|
/*
|
|
* Do not free direct mapping pages since they were
|
|
* freed when offlining, or simplely not in use.
|
|
*/
|
|
if (!direct)
|
|
free_pagetable(pte_page(*pte), 0, direct);
|
|
|
|
/*
|
|
* This spin lock could be only
|
|
* taken in _pte_aloc_kernel in
|
|
* mm/memory.c and nowhere else
|
|
* (for arm64). Not sure if the
|
|
* function above can be called
|
|
* concurrently. In doubt,
|
|
* I am living it here for now,
|
|
* but it probably can be removed.
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pte_clear(&init_mm, addr, pte);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
} else {
|
|
/*
|
|
* If we are here, we are freeing vmemmap pages since
|
|
* direct mapped memory ranges to be freed are aligned.
|
|
*
|
|
* If we are not removing the whole page, it means
|
|
* other page structs in this page are being used and
|
|
* we canot remove them. So fill the unused page_structs
|
|
* with 0xFD, and remove the page when it is wholly
|
|
* filled with 0xFD.
|
|
*/
|
|
memset((void *)addr, PAGE_INUSE, next - addr);
|
|
|
|
page_addr = page_address(pte_page(*pte));
|
|
if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) {
|
|
free_pagetable(pte_page(*pte), 0, direct);
|
|
|
|
/*
|
|
* This spin lock could be only
|
|
* taken in _pte_aloc_kernel in
|
|
* mm/memory.c and nowhere else
|
|
* (for arm64). Not sure if the
|
|
* function above can be called
|
|
* concurrently. In doubt,
|
|
* I am living it here for now,
|
|
* but it probably can be removed.
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pte_clear(&init_mm, addr, pte);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
}
|
|
}
|
|
}
|
|
|
|
// I am adding this flush here in simmetry to the x86 code.
|
|
// Why do I need to call it here and not in remove_p[mu]d
|
|
flush_tlb_all();
|
|
}
|
|
|
|
static void remove_pmd_table(pmd_t *pmd, unsigned long addr,
|
|
unsigned long end, bool direct)
|
|
{
|
|
unsigned long next;
|
|
void *page_addr;
|
|
pte_t *pte;
|
|
|
|
for (; addr < end; addr = next, pmd++) {
|
|
next = pmd_addr_end(addr, end);
|
|
|
|
if (!pmd_present(*pmd))
|
|
continue;
|
|
|
|
// check if we are using 2MB section mappings
|
|
if (pmd_sect(*pmd)) {
|
|
if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) {
|
|
if (!direct) {
|
|
free_pagetable(pmd_page(*pmd),
|
|
get_order(PMD_SIZE), direct);
|
|
}
|
|
/*
|
|
* This spin lock could be only
|
|
* taken in _pte_aloc_kernel in
|
|
* mm/memory.c and nowhere else
|
|
* (for arm64). Not sure if the
|
|
* function above can be called
|
|
* concurrently. In doubt,
|
|
* I am living it here for now,
|
|
* but it probably can be removed.
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pmd_clear(pmd);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
} else {
|
|
/* If here, we are freeing vmemmap pages. */
|
|
memset((void *)addr, PAGE_INUSE, next - addr);
|
|
|
|
page_addr = page_address(pmd_page(*pmd));
|
|
if (!memchr_inv(page_addr, PAGE_INUSE,
|
|
PMD_SIZE)) {
|
|
free_pagetable(pmd_page(*pmd),
|
|
get_order(PMD_SIZE), direct);
|
|
|
|
/*
|
|
* This spin lock could be only
|
|
* taken in _pte_aloc_kernel in
|
|
* mm/memory.c and nowhere else
|
|
* (for arm64). Not sure if the
|
|
* function above can be called
|
|
* concurrently. In doubt,
|
|
* I am living it here for now,
|
|
* but it probably can be removed.
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pmd_clear(pmd);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
BUG_ON(!pmd_table(*pmd));
|
|
|
|
pte = pte_offset_map(pmd, addr);
|
|
remove_pte_table(pte, addr, next, direct);
|
|
free_pte_table(pmd, direct);
|
|
}
|
|
}
|
|
|
|
static void remove_pud_table(pud_t *pud, unsigned long addr,
|
|
unsigned long end, bool direct)
|
|
{
|
|
unsigned long next;
|
|
pmd_t *pmd;
|
|
void *page_addr;
|
|
|
|
for (; addr < end; addr = next, pud++) {
|
|
next = pud_addr_end(addr, end);
|
|
if (!pud_present(*pud))
|
|
continue;
|
|
/*
|
|
* If we are using 4K granules, check if we are using
|
|
* 1GB section mapping.
|
|
*/
|
|
if (pud_sect(*pud)) {
|
|
if (PAGE_ALIGNED(addr) && PAGE_ALIGNED(next)) {
|
|
if (!direct) {
|
|
free_pagetable(pud_page(*pud),
|
|
get_order(PUD_SIZE), direct);
|
|
}
|
|
|
|
/*
|
|
* This spin lock could be only
|
|
* taken in _pte_aloc_kernel in
|
|
* mm/memory.c and nowhere else
|
|
* (for arm64). Not sure if the
|
|
* function above can be called
|
|
* concurrently. In doubt,
|
|
* I am living it here for now,
|
|
* but it probably can be removed.
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pud_clear(pud);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
} else {
|
|
/* If here, we are freeing vmemmap pages. */
|
|
memset((void *)addr, PAGE_INUSE, next - addr);
|
|
|
|
page_addr = page_address(pud_page(*pud));
|
|
if (!memchr_inv(page_addr, PAGE_INUSE,
|
|
PUD_SIZE)) {
|
|
|
|
free_pagetable(pud_page(*pud),
|
|
get_order(PUD_SIZE), direct);
|
|
|
|
/*
|
|
* This spin lock could be only
|
|
* taken in _pte_aloc_kernel in
|
|
* mm/memory.c and nowhere else
|
|
* (for arm64). Not sure if the
|
|
* function above can be called
|
|
* concurrently. In doubt,
|
|
* I am living it here for now,
|
|
* but it probably can be removed.
|
|
*/
|
|
spin_lock(&init_mm.page_table_lock);
|
|
pud_clear(pud);
|
|
spin_unlock(&init_mm.page_table_lock);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
BUG_ON(!pud_table(*pud));
|
|
|
|
pmd = pmd_offset(pud, addr);
|
|
remove_pmd_table(pmd, addr, next, direct);
|
|
free_pmd_table(pud, direct);
|
|
}
|
|
}
|
|
|
|
void remove_pagetable(unsigned long start, unsigned long end, bool direct)
|
|
{
|
|
unsigned long next;
|
|
unsigned long addr;
|
|
pgd_t *pgd;
|
|
pud_t *pud;
|
|
|
|
for (addr = start; addr < end; addr = next) {
|
|
next = pgd_addr_end(addr, end);
|
|
|
|
pgd = pgd_offset_k(addr);
|
|
if (pgd_none(*pgd))
|
|
continue;
|
|
|
|
pud = pud_offset(pgd, addr);
|
|
remove_pud_table(pud, addr, next, direct);
|
|
/*
|
|
* When the PUD is folded on the PGD (three levels of paging),
|
|
* I did already clear the PMD page in free_pmd_table,
|
|
* and reset the corresponding PGD==PUD entry.
|
|
*/
|
|
#if CONFIG_PGTABLE_LEVELS > 3
|
|
free_pud_table(pgd, direct);
|
|
#endif
|
|
}
|
|
|
|
flush_tlb_all();
|
|
}
|
|
|
|
|
|
#endif /* CONFIG_MEMORY_HOTREMOVE */
|
|
#endif /* CONFIG_MEMORY_HOTPLUG */
|
|
|
|
/*
|
|
* Check whether a kernel address is valid (derived from arch/x86/).
|
|
*/
|
|
int kern_addr_valid(unsigned long addr)
|
|
{
|
|
pgd_t *pgd;
|
|
pud_t *pud;
|
|
pmd_t *pmd;
|
|
pte_t *pte;
|
|
|
|
if ((((long)addr) >> VA_BITS) != -1UL)
|
|
return 0;
|
|
|
|
pgd = pgd_offset_k(addr);
|
|
if (pgd_none(*pgd))
|
|
return 0;
|
|
|
|
pud = pud_offset(pgd, addr);
|
|
if (pud_none(*pud))
|
|
return 0;
|
|
|
|
if (pud_sect(*pud))
|
|
return pfn_valid(pud_pfn(*pud));
|
|
|
|
pmd = pmd_offset(pud, addr);
|
|
if (pmd_none(*pmd))
|
|
return 0;
|
|
|
|
if (pmd_sect(*pmd))
|
|
return pfn_valid(pmd_pfn(*pmd));
|
|
|
|
pte = pte_offset_kernel(pmd, addr);
|
|
if (pte_none(*pte))
|
|
return 0;
|
|
|
|
return pfn_valid(pte_pfn(*pte));
|
|
}
|
|
#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
|
#if !ARM64_SWAPPER_USES_SECTION_MAPS
|
|
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
|
|
{
|
|
return vmemmap_populate_basepages(start, end, node);
|
|
}
|
|
#else /* !ARM64_SWAPPER_USES_SECTION_MAPS */
|
|
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
|
|
{
|
|
unsigned long addr = start;
|
|
unsigned long next;
|
|
pgd_t *pgd;
|
|
pud_t *pud;
|
|
pmd_t *pmd;
|
|
int ret = 0;
|
|
|
|
do {
|
|
next = pmd_addr_end(addr, end);
|
|
|
|
pgd = vmemmap_pgd_populate(addr, node);
|
|
if (!pgd)
|
|
return -ENOMEM;
|
|
|
|
pud = vmemmap_pud_populate(pgd, addr, node);
|
|
if (!pud)
|
|
return -ENOMEM;
|
|
|
|
pmd = pmd_offset(pud, addr);
|
|
if (pmd_none(*pmd)) {
|
|
void *p = NULL;
|
|
|
|
p = vmemmap_alloc_block_buf(PMD_SIZE, node);
|
|
if (!p) {
|
|
#ifdef CONFIG_MEMORY_HOTPLUG
|
|
vmemmap_free(start, end);
|
|
#endif
|
|
ret = -ENOMEM;
|
|
break;
|
|
}
|
|
|
|
set_pmd(pmd, __pmd(__pa(p) | PROT_SECT_NORMAL));
|
|
} else
|
|
vmemmap_verify((pte_t *)pmd, node, addr, next);
|
|
} while (addr = next, addr != end);
|
|
|
|
if (ret)
|
|
return vmemmap_populate_basepages(start, end, node);
|
|
else
|
|
return ret;
|
|
}
|
|
#endif /* CONFIG_ARM64_64K_PAGES */
|
|
void vmemmap_free(unsigned long start, unsigned long end)
|
|
{
|
|
#ifdef CONFIG_MEMORY_HOTREMOVE
|
|
remove_pagetable(start, end, false);
|
|
#endif
|
|
}
|
|
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
|
|
|
|
static inline pud_t * fixmap_pud(unsigned long addr)
|
|
{
|
|
pgd_t *pgd = pgd_offset_k(addr);
|
|
|
|
BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
|
|
|
|
return pud_offset_kimg(pgd, addr);
|
|
}
|
|
|
|
static inline pmd_t * fixmap_pmd(unsigned long addr)
|
|
{
|
|
pud_t *pud = fixmap_pud(addr);
|
|
|
|
BUG_ON(pud_none(*pud) || pud_bad(*pud));
|
|
|
|
return pmd_offset_kimg(pud, addr);
|
|
}
|
|
|
|
static inline pte_t * fixmap_pte(unsigned long addr)
|
|
{
|
|
return &bm_pte[pte_index(addr)];
|
|
}
|
|
|
|
/*
|
|
* The p*d_populate functions call virt_to_phys implicitly so they can't be used
|
|
* directly on kernel symbols (bm_p*d). This function is called too early to use
|
|
* lm_alias so __p*d_populate functions must be used to populate with the
|
|
* physical address from __pa_symbol.
|
|
*/
|
|
void __init early_fixmap_init(void)
|
|
{
|
|
pgd_t *pgd;
|
|
pud_t *pud;
|
|
pmd_t *pmd;
|
|
unsigned long addr = FIXADDR_START;
|
|
|
|
pgd = pgd_offset_k(addr);
|
|
if (CONFIG_PGTABLE_LEVELS > 3 &&
|
|
!(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa_symbol(bm_pud))) {
|
|
/*
|
|
* We only end up here if the kernel mapping and the fixmap
|
|
* share the top level pgd entry, which should only happen on
|
|
* 16k/4 levels configurations.
|
|
*/
|
|
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
|
|
pud = pud_offset_kimg(pgd, addr);
|
|
} else {
|
|
if (pgd_none(*pgd))
|
|
__pgd_populate(pgd, __pa_symbol(bm_pud),
|
|
PUD_TYPE_TABLE);
|
|
pud = fixmap_pud(addr);
|
|
}
|
|
if (pud_none(*pud))
|
|
__pud_populate(pud, __pa_symbol(bm_pmd), PMD_TYPE_TABLE);
|
|
pmd = fixmap_pmd(addr);
|
|
__pmd_populate(pmd, __pa_symbol(bm_pte), PMD_TYPE_TABLE);
|
|
|
|
/*
|
|
* The boot-ioremap range spans multiple pmds, for which
|
|
* we are not prepared:
|
|
*/
|
|
BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
|
|
!= (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
|
|
|
|
if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
|
|
|| pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
|
|
WARN_ON(1);
|
|
pr_warn("pmd %p != %p, %p\n",
|
|
pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
|
|
fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
|
|
pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
|
|
fix_to_virt(FIX_BTMAP_BEGIN));
|
|
pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
|
|
fix_to_virt(FIX_BTMAP_END));
|
|
|
|
pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
|
|
pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN);
|
|
}
|
|
}
|
|
|
|
void __set_fixmap(enum fixed_addresses idx,
|
|
phys_addr_t phys, pgprot_t flags)
|
|
{
|
|
unsigned long addr = __fix_to_virt(idx);
|
|
pte_t *pte;
|
|
|
|
BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
|
|
|
|
pte = fixmap_pte(addr);
|
|
|
|
if (pgprot_val(flags)) {
|
|
set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
|
|
} else {
|
|
pte_clear(&init_mm, addr, pte);
|
|
flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
|
|
}
|
|
}
|
|
|
|
void *__init __fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot)
|
|
{
|
|
const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
|
|
int offset;
|
|
void *dt_virt;
|
|
|
|
/*
|
|
* Check whether the physical FDT address is set and meets the minimum
|
|
* alignment requirement. Since we are relying on MIN_FDT_ALIGN to be
|
|
* at least 8 bytes so that we can always access the magic and size
|
|
* fields of the FDT header after mapping the first chunk, double check
|
|
* here if that is indeed the case.
|
|
*/
|
|
BUILD_BUG_ON(MIN_FDT_ALIGN < 8);
|
|
if (!dt_phys || dt_phys % MIN_FDT_ALIGN)
|
|
return NULL;
|
|
|
|
/*
|
|
* Make sure that the FDT region can be mapped without the need to
|
|
* allocate additional translation table pages, so that it is safe
|
|
* to call create_mapping_noalloc() this early.
|
|
*
|
|
* On 64k pages, the FDT will be mapped using PTEs, so we need to
|
|
* be in the same PMD as the rest of the fixmap.
|
|
* On 4k pages, we'll use section mappings for the FDT so we only
|
|
* have to be in the same PUD.
|
|
*/
|
|
BUILD_BUG_ON(dt_virt_base % SZ_2M);
|
|
|
|
BUILD_BUG_ON(__fix_to_virt(FIX_FDT_END) >> SWAPPER_TABLE_SHIFT !=
|
|
__fix_to_virt(FIX_BTMAP_BEGIN) >> SWAPPER_TABLE_SHIFT);
|
|
|
|
offset = dt_phys % SWAPPER_BLOCK_SIZE;
|
|
dt_virt = (void *)dt_virt_base + offset;
|
|
|
|
/* map the first chunk so we can read the size from the header */
|
|
create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE),
|
|
dt_virt_base, SWAPPER_BLOCK_SIZE, prot);
|
|
|
|
if (fdt_magic(dt_virt) != FDT_MAGIC)
|
|
return NULL;
|
|
|
|
*size = fdt_totalsize(dt_virt);
|
|
if (*size > MAX_FDT_SIZE)
|
|
return NULL;
|
|
|
|
if (offset + *size > SWAPPER_BLOCK_SIZE)
|
|
create_mapping_noalloc(round_down(dt_phys, SWAPPER_BLOCK_SIZE), dt_virt_base,
|
|
round_up(offset + *size, SWAPPER_BLOCK_SIZE), prot);
|
|
|
|
return dt_virt;
|
|
}
|
|
|
|
void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
|
|
{
|
|
void *dt_virt;
|
|
int size;
|
|
|
|
dt_virt = __fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO);
|
|
if (!dt_virt)
|
|
return NULL;
|
|
|
|
memblock_reserve(dt_phys, size);
|
|
return dt_virt;
|
|
}
|
|
|
|
int __init arch_ioremap_pud_supported(void)
|
|
{
|
|
/* only 4k granule supports level 1 block mappings */
|
|
return IS_ENABLED(CONFIG_ARM64_4K_PAGES);
|
|
}
|
|
|
|
int __init arch_ioremap_pmd_supported(void)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot)
|
|
{
|
|
BUG_ON(phys & ~PUD_MASK);
|
|
set_pud(pud, __pud(phys | PUD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
|
|
return 1;
|
|
}
|
|
|
|
int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot)
|
|
{
|
|
BUG_ON(phys & ~PMD_MASK);
|
|
set_pmd(pmd, __pmd(phys | PMD_TYPE_SECT | pgprot_val(mk_sect_prot(prot))));
|
|
return 1;
|
|
}
|
|
|
|
int pud_clear_huge(pud_t *pud)
|
|
{
|
|
if (!pud_sect(*pud))
|
|
return 0;
|
|
pud_clear(pud);
|
|
return 1;
|
|
}
|
|
|
|
int pmd_clear_huge(pmd_t *pmd)
|
|
{
|
|
if (!pmd_sect(*pmd))
|
|
return 0;
|
|
pmd_clear(pmd);
|
|
return 1;
|
|
}
|
|
|
|
#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
|
|
int pud_free_pmd_page(pud_t *pud)
|
|
{
|
|
return pud_none(*pud);
|
|
}
|
|
|
|
int pmd_free_pte_page(pmd_t *pmd)
|
|
{
|
|
return pmd_none(*pmd);
|
|
}
|
|
#endif
|