Files
kernel_xiaomi_sm8250/arch/arm64/include/asm/pgtable.h
Michael Bestas bfc560ed37 Merge tag 'ASB-2024-01-05_4.19-stable' of https://android.googlesource.com/kernel/common into android13-4.19-kona
https://source.android.com/docs/security/bulletin/2024-01-01

* tag 'ASB-2024-01-05_4.19-stable' of https://android.googlesource.com/kernel/common:
  Linux 4.19.304
  block: Don't invalidate pagecache for invalid falloc modes
  dm-integrity: don't modify bio's immutable bio_vec in integrity_metadata()
  smb: client: fix OOB in smbCalcSize()
  usb: fotg210-hcd: delete an incorrect bounds test
  usb: musb: fix MUSB_QUIRK_B_DISCONNECT_99 handling
  x86/alternatives: Sync core before enabling interrupts
  net: rfkill: gpio: set GPIO direction
  net: 9p: avoid freeing uninit memory in p9pdu_vreadf
  Bluetooth: hci_event: Fix not checking if HCI_OP_INQUIRY has been sent
  USB: serial: option: add Quectel RM500Q R13 firmware support
  USB: serial: option: add Foxconn T99W265 with new baseline
  USB: serial: option: add Quectel EG912Y module support
  USB: serial: ftdi_sio: update Actisense PIDs constant names
  wifi: cfg80211: fix certs build to not depend on file order
  wifi: cfg80211: Add my certificate
  iio: common: ms_sensors: ms_sensors_i2c: fix humidity conversion time table
  scsi: bnx2fc: Fix skb double free in bnx2fc_rcv()
  scsi: bnx2fc: Remove set but not used variable 'oxid'
  Input: ipaq-micro-keys - add error handling for devm_kmemdup
  iio: imu: inv_mpu6050: fix an error code problem in inv_mpu6050_read_raw
  btrfs: do not allow non subvolume root targets for snapshot
  smb: client: fix NULL deref in asn1_ber_decoder()
  pinctrl: at91-pio4: use dedicated lock class for IRQ
  net: check dev->gso_max_size in gso_features_check()
  net: warn if gso_type isn't set for a GSO SKB
  afs: Fix the dynamic root's d_delete to always delete unused dentries
  net: check vlan filter feature in vlan_vids_add_by_dev() and vlan_vids_del_by_dev()
  net/rose: fix races in rose_kill_by_device()
  ethernet: atheros: fix a memleak in atl1e_setup_ring_resources
  net: sched: ife: fix potential use-after-free
  net/mlx5: Fix fw tracer first block check
  net/mlx5: improve some comments
  wifi: mac80211: mesh_plink: fix matches_local logic
  s390/vx: fix save/restore of fpu kernel context
  reset: Fix crash when freeing non-existent optional resets
  ARM: OMAP2+: Fix null pointer dereference and memory leak in omap_soc_device_init
  ksmbd: fix wrong name of SMB2_CREATE_ALLOCATION_SIZE
  ALSA: hda/realtek: Enable headset on Lenovo M90 Gen5
  ALSA: hda/realtek: Enable headset onLenovo M70/M90
  ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
  arm64: dts: mediatek: mt8173-evb: Fix regulator-fixed node names
  Revert "cred: switch to using atomic_long_t"
  Linux 4.19.303
  powerpc/ftrace: Fix stack teardown in ftrace_no_trace
  powerpc/ftrace: Create a dummy stackframe to fix stack unwind
  mmc: block: Be sure to wait while busy in CQE error recovery
  ring-buffer: Fix memory leak of free page
  team: Fix use-after-free when an option instance allocation fails
  arm64: mm: Always make sw-dirty PTEs hw-dirty in pte_modify
  ext4: prevent the normalized size from exceeding EXT_MAX_BLOCKS
  perf: Fix perf_event_validate_size() lockdep splat
  HID: hid-asus: add const to read-only outgoing usb buffer
  net: usb: qmi_wwan: claim interface 4 for ZTE MF290
  asm-generic: qspinlock: fix queued_spin_value_unlocked() implementation
  HID: multitouch: Add quirk for HONOR GLO-GXXX touchpad
  HID: hid-asus: reset the backlight brightness level on resume
  HID: add ALWAYS_POLL quirk for Apple kb
  platform/x86: intel_telemetry: Fix kernel doc descriptions
  bcache: avoid NULL checking to c->root in run_cache_set()
  bcache: add code comments for bch_btree_node_get() and __bch_btree_node_alloc()
  bcache: avoid oversize memory allocation by small stripe_size
  blk-throttle: fix lockdep warning of "cgroup_mutex or RCU read lock required!"
  cred: switch to using atomic_long_t
  Revert "PCI: acpiphp: Reassign resources on bridge if necessary"
  appletalk: Fix Use-After-Free in atalk_ioctl
  net: stmmac: Handle disabled MDIO busses from devicetree
  vsock/virtio: Fix unsigned integer wrap around in virtio_transport_has_space()
  sign-file: Fix incorrect return values check
  net: Remove acked SYN flag from packet in the transmit queue correctly
  qed: Fix a potential use-after-free in qed_cxt_tables_alloc
  net/rose: Fix Use-After-Free in rose_ioctl
  atm: Fix Use-After-Free in do_vcc_ioctl
  atm: solos-pci: Fix potential deadlock on &tx_queue_lock
  atm: solos-pci: Fix potential deadlock on &cli_queue_lock
  qca_spi: Fix reset behavior
  qca_debug: Fix ethtool -G iface tx behavior
  qca_debug: Prevent crash on TX ring changes
  Revert "psample: Require 'CAP_NET_ADMIN' when joining "packets" group"
  Revert "genetlink: add CAP_NET_ADMIN test for multicast bind"
  Revert "drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group"
  Revert "perf/core: Add a new read format to get a number of lost samples"
  Revert "perf: Fix perf_event_validate_size()"
  Revert "hrtimers: Push pending hrtimers away from outgoing CPU earlier"
  ANDROID: Snapshot Mainline's version of checkpatch.pl
  Linux 4.19.302
  devcoredump: Send uevent once devcd is ready
  devcoredump : Serialize devcd_del work
  IB/isert: Fix unaligned immediate-data handling
  tools headers UAPI: Sync linux/perf_event.h with the kernel sources
  drop_monitor: Require 'CAP_SYS_ADMIN' when joining "events" group
  psample: Require 'CAP_NET_ADMIN' when joining "packets" group
  genetlink: add CAP_NET_ADMIN test for multicast bind
  netlink: don't call ->netlink_bind with table lock held
  nilfs2: fix missing error check for sb_set_blocksize call
  KVM: s390/mm: Properly reset no-dat
  x86/CPU/AMD: Check vendor in the AMD microcode callback
  serial: 8250_omap: Add earlycon support for the AM654 UART controller
  serial: sc16is7xx: address RX timeout interrupt errata
  usb: typec: class: fix typec_altmode_put_partner to put plugs
  parport: Add support for Brainboxes IX/UC/PX parallel cards
  usb: gadget: f_hid: fix report descriptor allocation
  gpiolib: sysfs: Fix error handling on failed export
  perf: Fix perf_event_validate_size()
  perf/core: Add a new read format to get a number of lost samples
  tracing: Fix a possible race when disabling buffered events
  tracing: Fix incomplete locking when disabling buffered events
  tracing: Always update snapshot buffer size
  nilfs2: prevent WARNING in nilfs_sufile_set_segment_usage()
  packet: Move reference count in packet_sock to atomic_long_t
  ALSA: pcm: fix out-of-bounds in snd_pcm_state_names
  ARM: dts: imx7: Declare timers compatible with fsl,imx6dl-gpt
  ARM: dts: imx: make gpt node name generic
  ARM: imx: Check return value of devm_kasprintf in imx_mmdc_perf_init
  scsi: be2iscsi: Fix a memleak in beiscsi_init_wrb_handle()
  tracing: Fix a warning when allocating buffered events fails
  hwmon: (acpi_power_meter) Fix 4.29 MW bug
  RDMA/bnxt_re: Correct module description string
  tcp: do not accept ACK of bytes we never sent
  netfilter: xt_owner: Fix for unsafe access of sk->sk_socket
  netfilter: xt_owner: Add supplementary groups option
  net: hns: fix fake link up on xge port
  ipv4: ip_gre: Avoid skb_pull() failure in ipgre_xmit()
  arcnet: restoring support for multiple Sohard Arcnet cards
  net: arcnet: com20020 fix error handling
  net: arcnet: Fix RESET flag handling
  hv_netvsc: rndis_filter needs to select NLS
  ipv6: fix potential NULL deref in fib6_add()
  drm/amdgpu: correct chunk_ptr to a pointer to chunk.
  kconfig: fix memory leak from range properties
  tg3: Increment tx_dropped in tg3_tso_bug()
  tg3: Move the [rt]x_dropped counters to tg3_napi
  netfilter: ipset: fix race condition between swap/destroy and kernel side add/del/test
  hrtimers: Push pending hrtimers away from outgoing CPU earlier
  media: davinci: vpif_capture: fix potential double free
  spi: imx: mx51-ecspi: Move some initialisation to prepare_message hook.
  spi: imx: correct wml as the last sg length
  spi: imx: move wml setting to later than setup_transfer
  spi: imx: add a device specific prepare_message callback
  Linux 4.19.301
  mmc: block: Retry commands in CQE error recovery
  mmc: core: convert comma to semicolon
  mmc: cqhci: Fix task clearing in CQE error recovery
  mmc: cqhci: Warn of halt or task clear failure
  mmc: cqhci: Increase recovery halt timeout
  cpufreq: imx6q: Don't disable 792 Mhz OPP unnecessarily
  cpufreq: imx6q: don't warn for disabling a non-existing frequency
  ima: detect changes to the backing overlay file
  ovl: skip overlayfs superblocks at global sync
  ima: annotate iint mutex to avoid lockdep false positive warnings
  fbdev: stifb: Make the STI next font pointer a 32-bit signed offset
  mtd: cfi_cmdset_0001: Byte swap OTP info
  mtd: cfi_cmdset_0001: Support the absence of protection registers
  s390/cmma: fix detection of DAT pages
  s390/mm: fix phys vs virt confusion in mark_kernel_pXd() functions family
  smb3: fix touch -h of symlink
  net: ravb: Start TX queues after HW initialization succeeded
  ravb: Fix races between ravb_tx_timeout_work() and net related ops
  ipv4: igmp: fix refcnt uaf issue when receiving igmp query packet
  Input: xpad - add HyperX Clutch Gladiate Support
  btrfs: send: ensure send_fd is writable
  btrfs: fix off-by-one when checking chunk map includes logical address
  powerpc: Don't clobber f0/vs0 during fp|altivec register save
  bcache: revert replacing IS_ERR_OR_NULL with IS_ERR
  dm verity: don't perform FEC for failed readahead IO
  dm-verity: align struct dm_verity_fec_io properly
  ALSA: hda/realtek: Headset Mic VREF to 100%
  ALSA: hda: Disable power-save on KONTRON SinglePC
  mmc: block: Do not lose cache flush during CQE error recovery
  firewire: core: fix possible memory leak in create_units()
  pinctrl: avoid reload of p state in list iteration
  USB: dwc3: qcom: fix wakeup after probe deferral
  usb: dwc3: set the dma max_seg_size
  USB: dwc2: write HCINT with INTMASK applied
  USB: serial: option: don't claim interface 4 for ZTE MF290
  USB: serial: option: fix FM101R-GL defines
  USB: serial: option: add Fibocom L7xx modules
  bcache: prevent potential division by zero error
  bcache: check return value from btree_node_alloc_replacement()
  dm-delay: fix a race between delay_presuspend and delay_bio
  hv_netvsc: Mark VF as slave before exposing it to user-mode
  hv_netvsc: Fix race of register_netdevice_notifier and VF register
  USB: serial: option: add Luat Air72*U series products
  s390/dasd: protect device queue against concurrent access
  bcache: replace a mistaken IS_ERR() by IS_ERR_OR_NULL() in btree_gc_coalesce()
  mtd: rawnand: brcmnand: Fix ecc chunk calculation for erased page bitfips
  KVM: arm64: limit PMU version to PMUv3 for ARMv8.1
  arm64: cpufeature: Extract capped perfmon fields
  MIPS: KVM: Fix a build warning about variable set but not used
  net: axienet: Fix check for partial TX checksum
  amd-xgbe: propagate the correct speed and duplex status
  amd-xgbe: handle the corner-case during tx completion
  amd-xgbe: handle corner-case during sfp hotplug
  arm/xen: fix xen_vcpu_info allocation alignment
  net: usb: ax88179_178a: fix failed operations during ax88179_reset
  ipv4: Correct/silence an endian warning in __ip_do_redirect
  HID: fix HID device resource race between HID core and debugging support
  HID: core: store the unique system identifier in hid_device
  drm/rockchip: vop: Fix color for RGB888/BGR888 format on VOP full
  ata: pata_isapnp: Add missing error check for devm_ioport_map()
  drm/panel: simple: Fix Innolux G101ICE-L01 timings
  RDMA/irdma: Prevent zero-length STAG registration
  driver core: Release all resources during unbind before updating device links

 Conflicts:
	drivers/mmc/host/cqhci.c
	drivers/net/usb/ax88179_178a.c
	drivers/usb/dwc3/core.c
	scripts/checkpatch.pl

Change-Id: I571c71df4f4c1c612d4101c9b9c2b901b4408103
2024-01-13 21:09:02 +02:00

823 lines
24 KiB
C

/*
* 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/>.
*/
#ifndef __ASM_PGTABLE_H
#define __ASM_PGTABLE_H
#include <asm/bug.h>
#include <asm/proc-fns.h>
#include <asm/bug.h>
#include <asm/memory.h>
#include <asm/pgtable-hwdef.h>
#include <asm/pgtable-prot.h>
/*
* VMALLOC range.
*
* VMALLOC_START: beginning of the kernel vmalloc space
* VMALLOC_END: extends to the available space below vmmemmap, PCI I/O space
* and fixed mappings
*/
#define VMALLOC_START (MODULES_END)
#define VMALLOC_END (PAGE_OFFSET - PUD_SIZE - VMEMMAP_SIZE - SZ_64K)
#define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
#define FIRST_USER_ADDRESS 0UL
#ifndef __ASSEMBLY__
#include <asm/cmpxchg.h>
#include <asm/fixmap.h>
#include <linux/mmdebug.h>
#include <linux/mm_types.h>
#include <linux/sched.h>
extern void __pte_error(const char *file, int line, unsigned long val);
extern void __pmd_error(const char *file, int line, unsigned long val);
extern void __pud_error(const char *file, int line, unsigned long val);
extern void __pgd_error(const char *file, int line, unsigned long val);
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define ZERO_PAGE(vaddr) phys_to_page(__pa_symbol(empty_zero_page))
#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte))
/*
* Macros to convert between a physical address and its placement in a
* page table entry, taking care of 52-bit addresses.
*/
#ifdef CONFIG_ARM64_PA_BITS_52
static inline phys_addr_t __pte_to_phys(pte_t pte)
{
return (pte_val(pte) & PTE_ADDR_LOW) |
((pte_val(pte) & PTE_ADDR_HIGH) << 36);
}
static inline pteval_t __phys_to_pte_val(phys_addr_t phys)
{
return (phys | (phys >> 36)) & PTE_ADDR_MASK;
}
#else
#define __pte_to_phys(pte) (pte_val(pte) & PTE_ADDR_MASK)
#define __phys_to_pte_val(phys) (phys)
#endif
#define pte_pfn(pte) (__pte_to_phys(pte) >> PAGE_SHIFT)
#define pfn_pte(pfn,prot) \
__pte(__phys_to_pte_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define pte_none(pte) (!pte_val(pte))
#define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0))
#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
/*
* The following only work if pte_present(). Undefined behaviour otherwise.
*/
#define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)))
#define pte_young(pte) (!!(pte_val(pte) & PTE_AF))
#define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL))
#define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE))
#define pte_user_exec(pte) (!(pte_val(pte) & PTE_UXN))
#define pte_cont(pte) (!!(pte_val(pte) & PTE_CONT))
#define pte_cont_addr_end(addr, end) \
({ unsigned long __boundary = ((addr) + CONT_PTE_SIZE) & CONT_PTE_MASK; \
(__boundary - 1 < (end) - 1) ? __boundary : (end); \
})
#define pmd_cont_addr_end(addr, end) \
({ unsigned long __boundary = ((addr) + CONT_PMD_SIZE) & CONT_PMD_MASK; \
(__boundary - 1 < (end) - 1) ? __boundary : (end); \
})
#define pte_hw_dirty(pte) (pte_write(pte) && !(pte_val(pte) & PTE_RDONLY))
#define pte_sw_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY))
#define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte))
#define pte_valid(pte) (!!(pte_val(pte) & PTE_VALID))
#define pte_valid_not_user(pte) \
((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
#define pte_valid_user(pte) \
((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
/*
* Could the pte be present in the TLB? We must check mm_tlb_flush_pending
* so that we don't erroneously return false for pages that have been
* remapped as PROT_NONE but are yet to be flushed from the TLB.
* Note that we can't make any assumptions based on the state of the access
* flag, since ptep_clear_flush_young() elides a DSB when invalidating the
* TLB.
*/
#define pte_accessible(mm, pte) \
(mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid(pte))
/*
* p??_access_permitted() is true for valid user mappings (subject to the
* write permission check). PROT_NONE mappings do not have the PTE_VALID bit
* set.
*/
#define pte_access_permitted(pte, write) \
(pte_valid_user(pte) && (!(write) || pte_write(pte)))
#define pmd_access_permitted(pmd, write) \
(pte_access_permitted(pmd_pte(pmd), (write)))
#define pud_access_permitted(pud, write) \
(pte_access_permitted(pud_pte(pud), (write)))
static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
{
pte_val(pte) &= ~pgprot_val(prot);
return pte;
}
static inline pte_t set_pte_bit(pte_t pte, pgprot_t prot)
{
pte_val(pte) |= pgprot_val(prot);
return pte;
}
static inline pte_t pte_mkwrite(pte_t pte)
{
pte = set_pte_bit(pte, __pgprot(PTE_WRITE));
pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
return pte;
}
static inline pte_t pte_mkclean(pte_t pte)
{
pte = clear_pte_bit(pte, __pgprot(PTE_DIRTY));
pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
return pte;
}
static inline pte_t pte_mkdirty(pte_t pte)
{
pte = set_pte_bit(pte, __pgprot(PTE_DIRTY));
if (pte_write(pte))
pte = clear_pte_bit(pte, __pgprot(PTE_RDONLY));
return pte;
}
static inline pte_t pte_wrprotect(pte_t pte)
{
/*
* If hardware-dirty (PTE_WRITE/DBM bit set and PTE_RDONLY
* clear), set the PTE_DIRTY bit.
*/
if (pte_hw_dirty(pte))
pte = pte_mkdirty(pte);
pte = clear_pte_bit(pte, __pgprot(PTE_WRITE));
pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
return pte;
}
static inline pte_t pte_mkold(pte_t pte)
{
return clear_pte_bit(pte, __pgprot(PTE_AF));
}
static inline pte_t pte_mkyoung(pte_t pte)
{
return set_pte_bit(pte, __pgprot(PTE_AF));
}
static inline pte_t pte_mkspecial(pte_t pte)
{
return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
}
static inline pte_t pte_mkcont(pte_t pte)
{
pte = set_pte_bit(pte, __pgprot(PTE_CONT));
return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE));
}
static inline pte_t pte_mknoncont(pte_t pte)
{
return clear_pte_bit(pte, __pgprot(PTE_CONT));
}
static inline pte_t pte_mkpresent(pte_t pte)
{
return set_pte_bit(pte, __pgprot(PTE_VALID));
}
static inline pmd_t pmd_mkcont(pmd_t pmd)
{
return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
}
static inline void set_pte(pte_t *ptep, pte_t pte)
{
#ifdef CONFIG_ARM64_STRICT_BREAK_BEFORE_MAKE
pteval_t old = pte_val(*ptep);
pteval_t new = pte_val(pte);
/* Only problematic if valid -> valid */
if (!(old & new & PTE_VALID))
goto pte_ok;
/* Changing attributes should go via an invalid entry */
if (WARN_ON((old & PTE_ATTRINDX_MASK) != (new & PTE_ATTRINDX_MASK)))
goto pte_bad;
/* Change of OA is only an issue if one mapping is writable */
if (!(old & new & PTE_RDONLY) &&
WARN_ON(pte_pfn(*ptep) != pte_pfn(pte)))
goto pte_bad;
goto pte_ok;
pte_bad:
*ptep = __pte(0);
dsb(ishst);
asm("tlbi vmalle1is");
dsb(ish);
isb();
pte_ok:
#endif
WRITE_ONCE(*ptep, pte);
/*
* Only if the new pte is valid and kernel, otherwise TLB maintenance
* or update_mmu_cache() have the necessary barriers.
*/
if (pte_valid_not_user(pte)) {
dsb(ishst);
isb();
}
}
extern void __sync_icache_dcache(pte_t pteval);
/*
* PTE bits configuration in the presence of hardware Dirty Bit Management
* (PTE_WRITE == PTE_DBM):
*
* Dirty Writable | PTE_RDONLY PTE_WRITE PTE_DIRTY (sw)
* 0 0 | 1 0 0
* 0 1 | 1 1 0
* 1 0 | 1 0 1
* 1 1 | 0 1 x
*
* When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via
* the page fault mechanism. Checking the dirty status of a pte becomes:
*
* PTE_DIRTY || (PTE_WRITE && !PTE_RDONLY)
*/
static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
pte_t old_pte;
if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
__sync_icache_dcache(pte);
/*
* If the existing pte is valid, check for potential race with
* hardware updates of the pte (ptep_set_access_flags safely changes
* valid ptes without going through an invalid entry).
*/
old_pte = READ_ONCE(*ptep);
if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(old_pte) && pte_valid(pte) &&
(mm == current->active_mm || atomic_read(&mm->mm_users) > 1)) {
VM_WARN_ONCE(!pte_young(pte),
"%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
"%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(old_pte), pte_val(pte));
}
set_pte(ptep, pte);
}
/*
* Huge pte definitions.
*/
#define pte_huge(pte) (!(pte_val(pte) & PTE_TABLE_BIT))
#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
/*
* Hugetlb definitions.
*/
#define HUGE_MAX_HSTATE 4
#define HPAGE_SHIFT PMD_SHIFT
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
static inline pte_t pgd_pte(pgd_t pgd)
{
return __pte(pgd_val(pgd));
}
static inline pte_t pud_pte(pud_t pud)
{
return __pte(pud_val(pud));
}
static inline pmd_t pud_pmd(pud_t pud)
{
return __pmd(pud_val(pud));
}
static inline pte_t pmd_pte(pmd_t pmd)
{
return __pte(pmd_val(pmd));
}
static inline pmd_t pte_pmd(pte_t pte)
{
return __pmd(pte_val(pte));
}
static inline pgprot_t mk_sect_prot(pgprot_t prot)
{
return __pgprot(pgprot_val(prot) & ~PTE_TABLE_BIT);
}
#ifdef CONFIG_NUMA_BALANCING
/*
* See the comment in include/asm-generic/pgtable.h
*/
static inline int pte_protnone(pte_t pte)
{
return (pte_val(pte) & (PTE_VALID | PTE_PROT_NONE)) == PTE_PROT_NONE;
}
static inline int pmd_protnone(pmd_t pmd)
{
return pte_protnone(pmd_pte(pmd));
}
#endif
/*
* THP definitions.
*/
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#define pmd_present(pmd) pte_present(pmd_pte(pmd))
#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_SECT_VALID))
#define pmd_thp_or_huge(pmd) (pmd_huge(pmd) || pmd_trans_huge(pmd))
#define pmd_write(pmd) pte_write(pmd_pte(pmd))
#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
#define __pmd_to_phys(pmd) __pte_to_phys(pmd_pte(pmd))
#define __phys_to_pmd_val(phys) __phys_to_pte_val(phys)
#define pmd_pfn(pmd) ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT)
#define pfn_pmd(pfn,prot) __pmd(__phys_to_pmd_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
#define pud_write(pud) pte_write(pud_pte(pud))
#define __pud_to_phys(pud) __pte_to_phys(pud_pte(pud))
#define __phys_to_pud_val(phys) __phys_to_pte_val(phys)
#define pud_pfn(pud) ((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT)
#define pfn_pud(pfn,prot) __pud(__phys_to_pud_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))
#define __pgd_to_phys(pgd) __pte_to_phys(pgd_pte(pgd))
#define __phys_to_pgd_val(phys) __phys_to_pte_val(phys)
#define __pgprot_modify(prot,mask,bits) \
__pgprot((pgprot_val(prot) & ~(mask)) | (bits))
/*
* Mark the prot value as uncacheable and unbufferable.
*/
#define pgprot_noncached(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
#define pgprot_device(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
#define __HAVE_PHYS_MEM_ACCESS_PROT
struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot);
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (!(pmd_val(pmd) & PMD_TABLE_BIT))
#define pmd_table(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \
PMD_TYPE_TABLE)
#define pmd_sect(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \
PMD_TYPE_SECT)
#if defined(CONFIG_ARM64_64K_PAGES) || CONFIG_PGTABLE_LEVELS < 3
static inline bool pud_sect(pud_t pud) { return false; }
static inline bool pud_table(pud_t pud) { return true; }
#else
#define pud_sect(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \
PUD_TYPE_SECT)
#define pud_table(pud) ((pud_val(pud) & PUD_TYPE_MASK) == \
PUD_TYPE_TABLE)
#endif
static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{
WRITE_ONCE(*pmdp, pmd);
dsb(ishst);
isb();
}
static inline void pmd_clear(pmd_t *pmdp)
{
set_pmd(pmdp, __pmd(0));
}
static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
{
return __pmd_to_phys(pmd);
}
static inline unsigned long pmd_page_vaddr(pmd_t pmd)
{
return (unsigned long) __va(pmd_page_paddr(pmd));
}
static inline void pte_unmap(pte_t *pte) { }
/* Find an entry in the third-level page table. */
#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define pte_offset_phys(dir,addr) (pmd_page_paddr(READ_ONCE(*(dir))) + pte_index(addr) * sizeof(pte_t))
#define pte_offset_kernel(dir,addr) ((pte_t *)__va(pte_offset_phys((dir), (addr))))
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
#define pte_unmap_nested(pte) do { } while (0)
#define pte_set_fixmap(addr) ((pte_t *)set_fixmap_offset(FIX_PTE, addr))
#define pte_set_fixmap_offset(pmd, addr) pte_set_fixmap(pte_offset_phys(pmd, addr))
#define pte_clear_fixmap() clear_fixmap(FIX_PTE)
#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(__pmd_to_phys(pmd)))
/* use ONLY for statically allocated translation tables */
#define pte_offset_kimg(dir,addr) ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot)
#if CONFIG_PGTABLE_LEVELS > 2
#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd))
#define pud_none(pud) (!pud_val(pud))
#define pud_bad(pud) (!(pud_val(pud) & PUD_TABLE_BIT))
#define pud_present(pud) pte_present(pud_pte(pud))
static inline void set_pud(pud_t *pudp, pud_t pud)
{
WRITE_ONCE(*pudp, pud);
dsb(ishst);
isb();
}
static inline void pud_clear(pud_t *pudp)
{
set_pud(pudp, __pud(0));
}
static inline phys_addr_t pud_page_paddr(pud_t pud)
{
return __pud_to_phys(pud);
}
static inline unsigned long pud_page_vaddr(pud_t pud)
{
return (unsigned long) __va(pud_page_paddr(pud));
}
/* Find an entry in the second-level page table. */
#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
#define pmd_offset_phys(dir, addr) (pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t))
#define pmd_offset(dir, addr) ((pmd_t *)__va(pmd_offset_phys((dir), (addr))))
#define pmd_set_fixmap(addr) ((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
#define pmd_set_fixmap_offset(pud, addr) pmd_set_fixmap(pmd_offset_phys(pud, addr))
#define pmd_clear_fixmap() clear_fixmap(FIX_PMD)
#define pud_page(pud) pfn_to_page(__phys_to_pfn(__pud_to_phys(pud)))
/* use ONLY for statically allocated translation tables */
#define pmd_offset_kimg(dir,addr) ((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
#else
#define pud_page_paddr(pud) ({ BUILD_BUG(); 0; })
/* Match pmd_offset folding in <asm/generic/pgtable-nopmd.h> */
#define pmd_set_fixmap(addr) NULL
#define pmd_set_fixmap_offset(pudp, addr) ((pmd_t *)pudp)
#define pmd_clear_fixmap()
#define pmd_offset_kimg(dir,addr) ((pmd_t *)dir)
#endif /* CONFIG_PGTABLE_LEVELS > 2 */
#if CONFIG_PGTABLE_LEVELS > 3
#define pud_ERROR(pud) __pud_error(__FILE__, __LINE__, pud_val(pud))
#define pgd_none(pgd) (!pgd_val(pgd))
#define pgd_bad(pgd) (!(pgd_val(pgd) & 2))
#define pgd_present(pgd) (pgd_val(pgd))
static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
{
WRITE_ONCE(*pgdp, pgd);
dsb(ishst);
}
static inline void pgd_clear(pgd_t *pgdp)
{
set_pgd(pgdp, __pgd(0));
}
static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
{
return __pgd_to_phys(pgd);
}
static inline unsigned long pgd_page_vaddr(pgd_t pgd)
{
return (unsigned long) __va(pgd_page_paddr(pgd));
}
/* Find an entry in the frst-level page table. */
#define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
#define pud_offset_phys(dir, addr) (pgd_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
#define pud_offset(dir, addr) ((pud_t *)__va(pud_offset_phys((dir), (addr))))
#define pud_set_fixmap(addr) ((pud_t *)set_fixmap_offset(FIX_PUD, addr))
#define pud_set_fixmap_offset(pgd, addr) pud_set_fixmap(pud_offset_phys(pgd, addr))
#define pud_clear_fixmap() clear_fixmap(FIX_PUD)
#define pgd_page(pgd) pfn_to_page(__phys_to_pfn(__pgd_to_phys(pgd)))
/* use ONLY for statically allocated translation tables */
#define pud_offset_kimg(dir,addr) ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
#else
#define pgd_page_paddr(pgd) ({ BUILD_BUG(); 0;})
/* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
#define pud_set_fixmap(addr) NULL
#define pud_set_fixmap_offset(pgdp, addr) ((pud_t *)pgdp)
#define pud_clear_fixmap()
#define pud_offset_kimg(dir,addr) ((pud_t *)dir)
#endif /* CONFIG_PGTABLE_LEVELS > 3 */
#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
/* to find an entry in a page-table-directory */
#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
#define pgd_offset_raw(pgd, addr) ((pgd) + pgd_index(addr))
#define pgd_offset(mm, addr) (pgd_offset_raw((mm)->pgd, (addr)))
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
#define pgd_set_fixmap(addr) ((pgd_t *)set_fixmap_offset(FIX_PGD, addr))
#define pgd_clear_fixmap() clear_fixmap(FIX_PGD)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
/* preserve the hardware dirty information */
if (pte_hw_dirty(pte))
pte = pte_mkdirty(pte);
pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
/*
* If we end up clearing hw dirtiness for a sw-dirty PTE, set hardware
* dirtiness again.
*/
if (pte_sw_dirty(pte))
pte = pte_mkdirty(pte);
return pte;
}
static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
{
return pte_pmd(pte_modify(pmd_pte(pmd), newprot));
}
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
extern int ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep,
pte_t entry, int dirty);
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
static inline int pmdp_set_access_flags(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp,
pmd_t entry, int dirty)
{
return ptep_set_access_flags(vma, address, (pte_t *)pmdp, pmd_pte(entry), dirty);
}
#endif
/*
* Atomic pte/pmd modifications.
*/
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
static inline int __ptep_test_and_clear_young(pte_t *ptep)
{
pte_t old_pte, pte;
pte = READ_ONCE(*ptep);
do {
old_pte = pte;
pte = pte_mkold(pte);
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
pte_val(old_pte), pte_val(pte));
} while (pte_val(pte) != pte_val(old_pte));
return pte_young(pte);
}
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long address,
pte_t *ptep)
{
return __ptep_test_and_clear_young(ptep);
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
unsigned long address,
pmd_t *pmdp)
{
return ptep_test_and_clear_young(vma, address, (pte_t *)pmdp);
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long address, pte_t *ptep)
{
return __pte(xchg_relaxed(&pte_val(*ptep), 0));
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
unsigned long address, pmd_t *pmdp)
{
return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp));
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
/*
* ptep_set_wrprotect - mark read-only while trasferring potential hardware
* dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit.
*/
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep)
{
pte_t old_pte, pte;
pte = READ_ONCE(*ptep);
do {
old_pte = pte;
pte = pte_wrprotect(pte);
pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep),
pte_val(old_pte), pte_val(pte));
} while (pte_val(pte) != pte_val(old_pte));
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define __HAVE_ARCH_PMDP_SET_WRPROTECT
static inline void pmdp_set_wrprotect(struct mm_struct *mm,
unsigned long address, pmd_t *pmdp)
{
ptep_set_wrprotect(mm, address, (pte_t *)pmdp);
}
#define pmdp_establish pmdp_establish
static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
unsigned long address, pmd_t *pmdp, pmd_t pmd)
{
return __pmd(xchg_relaxed(&pmd_val(*pmdp), pmd_val(pmd)));
}
#endif
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pgd_t swapper_pg_end[];
extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
extern pgd_t tramp_pg_dir[PTRS_PER_PGD];
/*
* Encode and decode a swap entry:
* bits 0-1: present (must be zero)
* bits 2-7: swap type
* bits 8-57: swap offset
* bit 58: PTE_PROT_NONE (must be zero)
*/
#define __SWP_TYPE_SHIFT 2
#define __SWP_TYPE_BITS 6
#define __SWP_OFFSET_BITS 50
#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
#define __SWP_OFFSET_MASK ((1UL << __SWP_OFFSET_BITS) - 1)
#define __swp_type(x) (((x).val >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
#define __swp_offset(x) (((x).val >> __SWP_OFFSET_SHIFT) & __SWP_OFFSET_MASK)
#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << __SWP_TYPE_SHIFT) | ((offset) << __SWP_OFFSET_SHIFT) })
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val })
/*
* Ensure that there are not more swap files than can be encoded in the kernel
* PTEs.
*/
#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > __SWP_TYPE_BITS)
extern int kern_addr_valid(unsigned long addr);
#include <asm-generic/pgtable.h>
void pgd_cache_init(void);
#define pgtable_cache_init pgd_cache_init
/*
* On AArch64, the cache coherency is handled via the set_pte_at() function.
*/
static inline void update_mmu_cache(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
/*
* We don't do anything here, so there's a very small chance of
* us retaking a user fault which we just fixed up. The alternative
* is doing a dsb(ishst), but that penalises the fastpath.
*/
}
#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
#define kc_vaddr_to_offset(v) ((v) & ~VA_START)
#define kc_offset_to_vaddr(o) ((o) | VA_START)
#ifdef CONFIG_ARM64_PA_BITS_52
#define phys_to_ttbr(addr) (((addr) | ((addr) >> 46)) & TTBR_BADDR_MASK_52)
#else
#define phys_to_ttbr(addr) (addr)
#endif
#endif /* !__ASSEMBLY__ */
#endif /* __ASM_PGTABLE_H */