mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 updates from Will Deacon:
"Although there isn't tonnes of code in terms of line count, there are
a fair few headline features which I've noted both in the tag and also
in the merge commits when I pulled everything together.
The part I'm most pleased with is that we had 35 contributors this
time around, which feels like a big jump from the usual small group of
core arm64 arch developers. Hopefully they all enjoyed it so much that
they'll continue to contribute, but we'll see.
It's probably worth highlighting that we've pulled in a branch from
the risc-v folks which moves our CPU topology code out to where it can
be shared with others.
Summary:
- 52-bit virtual addressing in the kernel
- New ABI to allow tagged user pointers to be dereferenced by
syscalls
- Early RNG seeding by the bootloader
- Improve robustness of SMP boot
- Fix TLB invalidation in light of recent architectural
clarifications
- Support for i.MX8 DDR PMU
- Remove direct LSE instruction patching in favour of static keys
- Function error injection using kprobes
- Support for the PPTT "thread" flag introduced by ACPI 6.3
- Move PSCI idle code into proper cpuidle driver
- Relaxation of implicit I/O memory barriers
- Build with RELR relocations when toolchain supports them
- Numerous cleanups and non-critical fixes"
* tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (114 commits)
arm64: remove __iounmap
arm64: atomics: Use K constraint when toolchain appears to support it
arm64: atomics: Undefine internal macros after use
arm64: lse: Make ARM64_LSE_ATOMICS depend on JUMP_LABEL
arm64: asm: Kill 'asm/atomic_arch.h'
arm64: lse: Remove unused 'alt_lse' assembly macro
arm64: atomics: Remove atomic_ll_sc compilation unit
arm64: avoid using hard-coded registers for LSE atomics
arm64: atomics: avoid out-of-line ll/sc atomics
arm64: Use correct ll/sc atomic constraints
jump_label: Don't warn on __exit jump entries
docs/perf: Add documentation for the i.MX8 DDR PMU
perf/imx_ddr: Add support for AXI ID filtering
arm64: kpti: ensure patched kernel text is fetched from PoU
arm64: fix fixmap copy for 16K pages and 48-bit VA
perf/smmuv3: Validate groups for global filtering
perf/smmuv3: Validate group size
arm64: Relax Documentation/arm64/tagged-pointers.rst
arm64: kvm: Replace hardcoded '1' with SYS_PAR_EL1_F
arm64: mm: Ignore spurious translation faults taken from the kernel
...
This commit is contained in:
commit
e77fafe9af
137 files changed
+2686
-1640
No files matched your search
@@ -0,0 +1,52 @@
|
||||
=====================================================
|
||||
Freescale i.MX8 DDR Performance Monitoring Unit (PMU)
|
||||
=====================================================
|
||||
|
||||
There are no performance counters inside the DRAM controller, so performance
|
||||
signals are brought out to the edge of the controller where a set of 4 x 32 bit
|
||||
counters is implemented. This is controlled by the CSV modes programed in counter
|
||||
control register which causes a large number of PERF signals to be generated.
|
||||
|
||||
Selection of the value for each counter is done via the config registers. There
|
||||
is one register for each counter. Counter 0 is special in that it always counts
|
||||
“time” and when expired causes a lock on itself and the other counters and an
|
||||
interrupt is raised. If any other counter overflows, it continues counting, and
|
||||
no interrupt is raised.
|
||||
|
||||
The "format" directory describes format of the config (event ID) and config1
|
||||
(AXI filtering) fields of the perf_event_attr structure, see /sys/bus/event_source/
|
||||
devices/imx8_ddr0/format/. The "events" directory describes the events types
|
||||
hardware supported that can be used with perf tool, see /sys/bus/event_source/
|
||||
devices/imx8_ddr0/events/.
|
||||
e.g.::
|
||||
perf stat -a -e imx8_ddr0/cycles/ cmd
|
||||
perf stat -a -e imx8_ddr0/read/,imx8_ddr0/write/ cmd
|
||||
|
||||
AXI filtering is only used by CSV modes 0x41 (axid-read) and 0x42 (axid-write)
|
||||
to count reading or writing matches filter setting. Filter setting is various
|
||||
from different DRAM controller implementations, which is distinguished by quirks
|
||||
in the driver.
|
||||
|
||||
* With DDR_CAP_AXI_ID_FILTER quirk.
|
||||
Filter is defined with two configuration parts:
|
||||
--AXI_ID defines AxID matching value.
|
||||
--AXI_MASKING defines which bits of AxID are meaningful for the matching.
|
||||
0:corresponding bit is masked.
|
||||
1: corresponding bit is not masked, i.e. used to do the matching.
|
||||
|
||||
AXI_ID and AXI_MASKING are mapped on DPCR1 register in performance counter.
|
||||
When non-masked bits are matching corresponding AXI_ID bits then counter is
|
||||
incremented. Perf counter is incremented if
|
||||
AxID && AXI_MASKING == AXI_ID && AXI_MASKING
|
||||
|
||||
This filter doesn't support filter different AXI ID for axid-read and axid-write
|
||||
event at the same time as this filter is shared between counters.
|
||||
e.g.::
|
||||
perf stat -a -e imx8_ddr0/axid-read,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
|
||||
perf stat -a -e imx8_ddr0/axid-write,axi_mask=0xMMMM,axi_id=0xDDDD/ cmd
|
||||
|
||||
NOTE: axi_mask is inverted in userspace(i.e. set bits are bits to mask), and
|
||||
it will be reverted in driver automatically. so that the user can just specify
|
||||
axi_id to monitor a specific id, rather than having to specify axi_mask.
|
||||
e.g.::
|
||||
perf stat -a -e imx8_ddr0/axid-read,axi_id=0x12/ cmd, which will monitor ARID=0x12
|
||||
@@ -16,6 +16,7 @@ ARM64 Architecture
|
||||
pointer-authentication
|
||||
silicon-errata
|
||||
sve
|
||||
tagged-address-abi
|
||||
tagged-pointers
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Print out the KASAN_SHADOW_OFFSETS required to place the KASAN SHADOW
|
||||
# start address at the mid-point of the kernel VA space
|
||||
|
||||
print_kasan_offset () {
|
||||
printf "%02d\t" $1
|
||||
printf "0x%08x00000000\n" $(( (0xffffffff & (-1 << ($1 - 1 - 32))) \
|
||||
+ (1 << ($1 - 32 - $2)) \
|
||||
- (1 << (64 - 32 - $2)) ))
|
||||
}
|
||||
|
||||
echo KASAN_SHADOW_SCALE_SHIFT = 3
|
||||
printf "VABITS\tKASAN_SHADOW_OFFSET\n"
|
||||
print_kasan_offset 48 3
|
||||
print_kasan_offset 47 3
|
||||
print_kasan_offset 42 3
|
||||
print_kasan_offset 39 3
|
||||
print_kasan_offset 36 3
|
||||
echo
|
||||
echo KASAN_SHADOW_SCALE_SHIFT = 4
|
||||
printf "VABITS\tKASAN_SHADOW_OFFSET\n"
|
||||
print_kasan_offset 48 4
|
||||
print_kasan_offset 47 4
|
||||
print_kasan_offset 42 4
|
||||
print_kasan_offset 39 4
|
||||
print_kasan_offset 36 4
|
||||
@@ -14,6 +14,10 @@ with the 4KB page configuration, allowing 39-bit (512GB) or 48-bit
|
||||
64KB pages, only 2 levels of translation tables, allowing 42-bit (4TB)
|
||||
virtual address, are used but the memory layout is the same.
|
||||
|
||||
ARMv8.2 adds optional support for Large Virtual Address space. This is
|
||||
only available when running with a 64KB page size and expands the
|
||||
number of descriptors in the first level of translation.
|
||||
|
||||
User addresses have bits 63:48 set to 0 while the kernel addresses have
|
||||
the same bits set to 1. TTBRx selection is given by bit 63 of the
|
||||
virtual address. The swapper_pg_dir contains only kernel (global)
|
||||
@@ -22,40 +26,43 @@ The swapper_pg_dir address is written to TTBR1 and never written to
|
||||
TTBR0.
|
||||
|
||||
|
||||
AArch64 Linux memory layout with 4KB pages + 3 levels::
|
||||
|
||||
Start End Size Use
|
||||
-----------------------------------------------------------------------
|
||||
0000000000000000 0000007fffffffff 512GB user
|
||||
ffffff8000000000 ffffffffffffffff 512GB kernel
|
||||
|
||||
|
||||
AArch64 Linux memory layout with 4KB pages + 4 levels::
|
||||
AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::
|
||||
|
||||
Start End Size Use
|
||||
-----------------------------------------------------------------------
|
||||
0000000000000000 0000ffffffffffff 256TB user
|
||||
ffff000000000000 ffffffffffffffff 256TB kernel
|
||||
ffff000000000000 ffff7fffffffffff 128TB kernel logical memory map
|
||||
ffff800000000000 ffff9fffffffffff 32TB kasan shadow region
|
||||
ffffa00000000000 ffffa00007ffffff 128MB bpf jit region
|
||||
ffffa00008000000 ffffa0000fffffff 128MB modules
|
||||
ffffa00010000000 fffffdffbffeffff ~93TB vmalloc
|
||||
fffffdffbfff0000 fffffdfffe5f8fff ~998MB [guard region]
|
||||
fffffdfffe5f9000 fffffdfffe9fffff 4124KB fixed mappings
|
||||
fffffdfffea00000 fffffdfffebfffff 2MB [guard region]
|
||||
fffffdfffec00000 fffffdffffbfffff 16MB PCI I/O space
|
||||
fffffdffffc00000 fffffdffffdfffff 2MB [guard region]
|
||||
fffffdffffe00000 ffffffffffdfffff 2TB vmemmap
|
||||
ffffffffffe00000 ffffffffffffffff 2MB [guard region]
|
||||
|
||||
|
||||
AArch64 Linux memory layout with 64KB pages + 2 levels::
|
||||
AArch64 Linux memory layout with 64KB pages + 3 levels (52-bit with HW support)::
|
||||
|
||||
Start End Size Use
|
||||
-----------------------------------------------------------------------
|
||||
0000000000000000 000003ffffffffff 4TB user
|
||||
fffffc0000000000 ffffffffffffffff 4TB kernel
|
||||
|
||||
|
||||
AArch64 Linux memory layout with 64KB pages + 3 levels::
|
||||
|
||||
Start End Size Use
|
||||
-----------------------------------------------------------------------
|
||||
0000000000000000 0000ffffffffffff 256TB user
|
||||
ffff000000000000 ffffffffffffffff 256TB kernel
|
||||
|
||||
|
||||
For details of the virtual kernel memory layout please see the kernel
|
||||
booting log.
|
||||
0000000000000000 000fffffffffffff 4PB user
|
||||
fff0000000000000 fff7ffffffffffff 2PB kernel logical memory map
|
||||
fff8000000000000 fffd9fffffffffff 1440TB [gap]
|
||||
fffda00000000000 ffff9fffffffffff 512TB kasan shadow region
|
||||
ffffa00000000000 ffffa00007ffffff 128MB bpf jit region
|
||||
ffffa00008000000 ffffa0000fffffff 128MB modules
|
||||
ffffa00010000000 fffff81ffffeffff ~88TB vmalloc
|
||||
fffff81fffff0000 fffffc1ffe58ffff ~3TB [guard region]
|
||||
fffffc1ffe590000 fffffc1ffe9fffff 4544KB fixed mappings
|
||||
fffffc1ffea00000 fffffc1ffebfffff 2MB [guard region]
|
||||
fffffc1ffec00000 fffffc1fffbfffff 16MB PCI I/O space
|
||||
fffffc1fffc00000 fffffc1fffdfffff 2MB [guard region]
|
||||
fffffc1fffe00000 ffffffffffdfffff 3968GB vmemmap
|
||||
ffffffffffe00000 ffffffffffffffff 2MB [guard region]
|
||||
|
||||
|
||||
Translation table lookup with 4KB pages::
|
||||
@@ -83,7 +90,8 @@ Translation table lookup with 64KB pages::
|
||||
| | | | [15:0] in-page offset
|
||||
| | | +----------> [28:16] L3 index
|
||||
| | +--------------------------> [41:29] L2 index
|
||||
| +-------------------------------> [47:42] L1 index
|
||||
| +-------------------------------> [47:42] L1 index (48-bit)
|
||||
| [51:42] L1 index (52-bit)
|
||||
+-------------------------------------------------> [63] TTBR0/1
|
||||
|
||||
|
||||
@@ -96,3 +104,62 @@ ARM64_HARDEN_EL2_VECTORS is selected for particular CPUs.
|
||||
|
||||
When using KVM with the Virtualization Host Extensions, no additional
|
||||
mappings are created, since the host kernel runs directly in EL2.
|
||||
|
||||
52-bit VA support in the kernel
|
||||
-------------------------------
|
||||
If the ARMv8.2-LVA optional feature is present, and we are running
|
||||
with a 64KB page size; then it is possible to use 52-bits of address
|
||||
space for both userspace and kernel addresses. However, any kernel
|
||||
binary that supports 52-bit must also be able to fall back to 48-bit
|
||||
at early boot time if the hardware feature is not present.
|
||||
|
||||
This fallback mechanism necessitates the kernel .text to be in the
|
||||
higher addresses such that they are invariant to 48/52-bit VAs. Due
|
||||
to the kasan shadow being a fraction of the entire kernel VA space,
|
||||
the end of the kasan shadow must also be in the higher half of the
|
||||
kernel VA space for both 48/52-bit. (Switching from 48-bit to 52-bit,
|
||||
the end of the kasan shadow is invariant and dependent on ~0UL,
|
||||
whilst the start address will "grow" towards the lower addresses).
|
||||
|
||||
In order to optimise phys_to_virt and virt_to_phys, the PAGE_OFFSET
|
||||
is kept constant at 0xFFF0000000000000 (corresponding to 52-bit),
|
||||
this obviates the need for an extra variable read. The physvirt
|
||||
offset and vmemmap offsets are computed at early boot to enable
|
||||
this logic.
|
||||
|
||||
As a single binary will need to support both 48-bit and 52-bit VA
|
||||
spaces, the VMEMMAP must be sized large enough for 52-bit VAs and
|
||||
also must be sized large enought to accommodate a fixed PAGE_OFFSET.
|
||||
|
||||
Most code in the kernel should not need to consider the VA_BITS, for
|
||||
code that does need to know the VA size the variables are
|
||||
defined as follows:
|
||||
|
||||
VA_BITS constant the *maximum* VA space size
|
||||
|
||||
VA_BITS_MIN constant the *minimum* VA space size
|
||||
|
||||
vabits_actual variable the *actual* VA space size
|
||||
|
||||
|
||||
Maximum and minimum sizes can be useful to ensure that buffers are
|
||||
sized large enough or that addresses are positioned close enough for
|
||||
the "worst" case.
|
||||
|
||||
52-bit userspace VAs
|
||||
--------------------
|
||||
To maintain compatibility with software that relies on the ARMv8.0
|
||||
VA space maximum size of 48-bits, the kernel will, by default,
|
||||
return virtual addresses to userspace from a 48-bit range.
|
||||
|
||||
Software can "opt-in" to receiving VAs from a 52-bit space by
|
||||
specifying an mmap hint parameter that is larger than 48-bit.
|
||||
For example:
|
||||
maybe_high_address = mmap(~0UL, size, prot, flags,...);
|
||||
|
||||
It is also possible to build a debug kernel that returns addresses
|
||||
from a 52-bit space by enabling the following kernel config options:
|
||||
CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y
|
||||
|
||||
Note that this option is only intended for debugging applications
|
||||
and should not be used in production.
|
||||
@@ -0,0 +1,156 @@
|
||||
==========================
|
||||
AArch64 TAGGED ADDRESS ABI
|
||||
==========================
|
||||
|
||||
Authors: Vincenzo Frascino <vincenzo.frascino@arm.com>
|
||||
Catalin Marinas <catalin.marinas@arm.com>
|
||||
|
||||
Date: 21 August 2019
|
||||
|
||||
This document describes the usage and semantics of the Tagged Address
|
||||
ABI on AArch64 Linux.
|
||||
|
||||
1. Introduction
|
||||
---------------
|
||||
|
||||
On AArch64 the ``TCR_EL1.TBI0`` bit is set by default, allowing
|
||||
userspace (EL0) to perform memory accesses through 64-bit pointers with
|
||||
a non-zero top byte. This document describes the relaxation of the
|
||||
syscall ABI that allows userspace to pass certain tagged pointers to
|
||||
kernel syscalls.
|
||||
|
||||
2. AArch64 Tagged Address ABI
|
||||
-----------------------------
|
||||
|
||||
From the kernel syscall interface perspective and for the purposes of
|
||||
this document, a "valid tagged pointer" is a pointer with a potentially
|
||||
non-zero top-byte that references an address in the user process address
|
||||
space obtained in one of the following ways:
|
||||
|
||||
- ``mmap()`` syscall where either:
|
||||
|
||||
- flags have the ``MAP_ANONYMOUS`` bit set or
|
||||
- the file descriptor refers to a regular file (including those
|
||||
returned by ``memfd_create()``) or ``/dev/zero``
|
||||
|
||||
- ``brk()`` syscall (i.e. the heap area between the initial location of
|
||||
the program break at process creation and its current location).
|
||||
|
||||
- any memory mapped by the kernel in the address space of the process
|
||||
during creation and with the same restrictions as for ``mmap()`` above
|
||||
(e.g. data, bss, stack).
|
||||
|
||||
The AArch64 Tagged Address ABI has two stages of relaxation depending
|
||||
how the user addresses are used by the kernel:
|
||||
|
||||
1. User addresses not accessed by the kernel but used for address space
|
||||
management (e.g. ``mmap()``, ``mprotect()``, ``madvise()``). The use
|
||||
of valid tagged pointers in this context is always allowed.
|
||||
|
||||
2. User addresses accessed by the kernel (e.g. ``write()``). This ABI
|
||||
relaxation is disabled by default and the application thread needs to
|
||||
explicitly enable it via ``prctl()`` as follows:
|
||||
|
||||
- ``PR_SET_TAGGED_ADDR_CTRL``: enable or disable the AArch64 Tagged
|
||||
Address ABI for the calling thread.
|
||||
|
||||
The ``(unsigned int) arg2`` argument is a bit mask describing the
|
||||
control mode used:
|
||||
|
||||
- ``PR_TAGGED_ADDR_ENABLE``: enable AArch64 Tagged Address ABI.
|
||||
Default status is disabled.
|
||||
|
||||
Arguments ``arg3``, ``arg4``, and ``arg5`` must be 0.
|
||||
|
||||
- ``PR_GET_TAGGED_ADDR_CTRL``: get the status of the AArch64 Tagged
|
||||
Address ABI for the calling thread.
|
||||
|
||||
Arguments ``arg2``, ``arg3``, ``arg4``, and ``arg5`` must be 0.
|
||||
|
||||
The ABI properties described above are thread-scoped, inherited on
|
||||
clone() and fork() and cleared on exec().
|
||||
|
||||
Calling ``prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0)``
|
||||
returns ``-EINVAL`` if the AArch64 Tagged Address ABI is globally
|
||||
disabled by ``sysctl abi.tagged_addr_disabled=1``. The default
|
||||
``sysctl abi.tagged_addr_disabled`` configuration is 0.
|
||||
|
||||
When the AArch64 Tagged Address ABI is enabled for a thread, the
|
||||
following behaviours are guaranteed:
|
||||
|
||||
- All syscalls except the cases mentioned in section 3 can accept any
|
||||
valid tagged pointer.
|
||||
|
||||
- The syscall behaviour is undefined for invalid tagged pointers: it may
|
||||
result in an error code being returned, a (fatal) signal being raised,
|
||||
or other modes of failure.
|
||||
|
||||
- The syscall behaviour for a valid tagged pointer is the same as for
|
||||
the corresponding untagged pointer.
|
||||
|
||||
|
||||
A definition of the meaning of tagged pointers on AArch64 can be found
|
||||
in Documentation/arm64/tagged-pointers.rst.
|
||||
|
||||
3. AArch64 Tagged Address ABI Exceptions
|
||||
-----------------------------------------
|
||||
|
||||
The following system call parameters must be untagged regardless of the
|
||||
ABI relaxation:
|
||||
|
||||
- ``prctl()`` other than pointers to user data either passed directly or
|
||||
indirectly as arguments to be accessed by the kernel.
|
||||
|
||||
- ``ioctl()`` other than pointers to user data either passed directly or
|
||||
indirectly as arguments to be accessed by the kernel.
|
||||
|
||||
- ``shmat()`` and ``shmdt()``.
|
||||
|
||||
Any attempt to use non-zero tagged pointers may result in an error code
|
||||
being returned, a (fatal) signal being raised, or other modes of
|
||||
failure.
|
||||
|
||||
4. Example of correct usage
|
||||
---------------------------
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#define PR_SET_TAGGED_ADDR_CTRL 55
|
||||
#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
|
||||
|
||||
#define TAG_SHIFT 56
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int tbi_enabled = 0;
|
||||
unsigned long tag = 0;
|
||||
char *ptr;
|
||||
|
||||
/* check/enable the tagged address ABI */
|
||||
if (!prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0))
|
||||
tbi_enabled = 1;
|
||||
|
||||
/* memory allocation */
|
||||
ptr = mmap(NULL, sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (ptr == MAP_FAILED)
|
||||
return 1;
|
||||
|
||||
/* set a non-zero tag if the ABI is available */
|
||||
if (tbi_enabled)
|
||||
tag = rand() & 0xff;
|
||||
ptr = (char *)((unsigned long)ptr | (tag << TAG_SHIFT));
|
||||
|
||||
/* memory access to a tagged address */
|
||||
strcpy(ptr, "tagged pointer\n");
|
||||
|
||||
/* syscall with a tagged pointer */
|
||||
write(1, ptr, strlen(ptr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -20,7 +20,9 @@ Passing tagged addresses to the kernel
|
||||
--------------------------------------
|
||||
|
||||
All interpretation of userspace memory addresses by the kernel assumes
|
||||
an address tag of 0x00.
|
||||
an address tag of 0x00, unless the application enables the AArch64
|
||||
Tagged Address ABI explicitly
|
||||
(Documentation/arm64/tagged-address-abi.rst).
|
||||
|
||||
This includes, but is not limited to, addresses found in:
|
||||
|
||||
@@ -33,13 +35,15 @@ This includes, but is not limited to, addresses found in:
|
||||
- the frame pointer (x29) and frame records, e.g. when interpreting
|
||||
them to generate a backtrace or call graph.
|
||||
|
||||
Using non-zero address tags in any of these locations may result in an
|
||||
error code being returned, a (fatal) signal being raised, or other modes
|
||||
of failure.
|
||||
Using non-zero address tags in any of these locations when the
|
||||
userspace application did not enable the AArch64 Tagged Address ABI may
|
||||
result in an error code being returned, a (fatal) signal being raised,
|
||||
or other modes of failure.
|
||||
|
||||
For these reasons, passing non-zero address tags to the kernel via
|
||||
system calls is forbidden, and using a non-zero address tag for sp is
|
||||
strongly discouraged.
|
||||
For these reasons, when the AArch64 Tagged Address ABI is disabled,
|
||||
passing non-zero address tags to the kernel via system calls is
|
||||
forbidden, and using a non-zero address tag for sp is strongly
|
||||
discouraged.
|
||||
|
||||
Programs maintaining a frame pointer and frame records that use non-zero
|
||||
address tags may suffer impaired or inaccurate debug and profiling
|
||||
@@ -59,6 +63,9 @@ be preserved.
|
||||
The architecture prevents the use of a tagged PC, so the upper byte will
|
||||
be set to a sign-extension of bit 55 on exception return.
|
||||
|
||||
This behaviour is maintained when the AArch64 Tagged Address ABI is
|
||||
enabled.
|
||||
|
||||
|
||||
Other considerations
|
||||
--------------------
|
||||
|
||||
+168
-90
@@ -1,21 +1,19 @@
|
||||
===========================================
|
||||
ARM topology binding description
|
||||
CPU topology binding description
|
||||
===========================================
|
||||
|
||||
===========================================
|
||||
1 - Introduction
|
||||
===========================================
|
||||
|
||||
In an ARM system, the hierarchy of CPUs is defined through three entities that
|
||||
In a SMP system, the hierarchy of CPUs is defined through three entities that
|
||||
are used to describe the layout of physical CPUs in the system:
|
||||
|
||||
- socket
|
||||
- cluster
|
||||
- core
|
||||
- thread
|
||||
|
||||
The cpu nodes (bindings defined in [1]) represent the devices that
|
||||
correspond to physical CPUs and are to be mapped to the hierarchy levels.
|
||||
|
||||
The bottom hierarchy level sits at core or thread level depending on whether
|
||||
symmetric multi-threading (SMT) is supported or not.
|
||||
|
||||
@@ -24,33 +22,31 @@ threads existing in the system and map to the hierarchy level "thread" above.
|
||||
In systems where SMT is not supported "cpu" nodes represent all cores present
|
||||
in the system and map to the hierarchy level "core" above.
|
||||
|
||||
ARM topology bindings allow one to associate cpu nodes with hierarchical groups
|
||||
CPU topology bindings allow one to associate cpu nodes with hierarchical groups
|
||||
corresponding to the system hierarchy; syntactically they are defined as device
|
||||
tree nodes.
|
||||
|
||||
The remainder of this document provides the topology bindings for ARM, based
|
||||
on the Devicetree Specification, available from:
|
||||
Currently, only ARM/RISC-V intend to use this cpu topology binding but it may be
|
||||
used for any other architecture as well.
|
||||
|
||||
https://www.devicetree.org/specifications/
|
||||
The cpu nodes, as per bindings defined in [4], represent the devices that
|
||||
correspond to physical CPUs and are to be mapped to the hierarchy levels.
|
||||
|
||||
If not stated otherwise, whenever a reference to a cpu node phandle is made its
|
||||
value must point to a cpu node compliant with the cpu node bindings as
|
||||
documented in [1].
|
||||
A topology description containing phandles to cpu nodes that are not compliant
|
||||
with bindings standardized in [1] is therefore considered invalid.
|
||||
with bindings standardized in [4] is therefore considered invalid.
|
||||
|
||||
===========================================
|
||||
2 - cpu-map node
|
||||
===========================================
|
||||
|
||||
The ARM CPU topology is defined within the cpu-map node, which is a direct
|
||||
The ARM/RISC-V CPU topology is defined within the cpu-map node, which is a direct
|
||||
child of the cpus node and provides a container where the actual topology
|
||||
nodes are listed.
|
||||
|
||||
- cpu-map node
|
||||
|
||||
Usage: Optional - On ARM SMP systems provide CPUs topology to the OS.
|
||||
ARM uniprocessor systems do not require a topology
|
||||
Usage: Optional - On SMP systems provide CPUs topology to the OS.
|
||||
Uniprocessor systems do not require a topology
|
||||
description and therefore should not define a
|
||||
cpu-map node.
|
||||
|
||||
@@ -63,21 +59,23 @@ nodes are listed.
|
||||
|
||||
The cpu-map node's child nodes can be:
|
||||
|
||||
- one or more cluster nodes
|
||||
- one or more cluster nodes or
|
||||
- one or more socket nodes in a multi-socket system
|
||||
|
||||
Any other configuration is considered invalid.
|
||||
|
||||
The cpu-map node can only contain three types of child nodes:
|
||||
The cpu-map node can only contain 4 types of child nodes:
|
||||
|
||||
- socket node
|
||||
- cluster node
|
||||
- core node
|
||||
- thread node
|
||||
|
||||
whose bindings are described in paragraph 3.
|
||||
|
||||
The nodes describing the CPU topology (cluster/core/thread) can only
|
||||
be defined within the cpu-map node and every core/thread in the system
|
||||
must be defined within the topology. Any other configuration is
|
||||
The nodes describing the CPU topology (socket/cluster/core/thread) can
|
||||
only be defined within the cpu-map node and every core/thread in the
|
||||
system must be defined within the topology. Any other configuration is
|
||||
invalid and therefore must be ignored.
|
||||
|
||||
===========================================
|
||||
@@ -85,26 +83,44 @@ invalid and therefore must be ignored.
|
||||
===========================================
|
||||
|
||||
cpu-map child nodes must follow a naming convention where the node name
|
||||
must be "clusterN", "coreN", "threadN" depending on the node type (ie
|
||||
cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes which
|
||||
are siblings within a single common parent node must be given a unique and
|
||||
must be "socketN", "clusterN", "coreN", "threadN" depending on the node type
|
||||
(ie socket/cluster/core/thread) (where N = {0, 1, ...} is the node number; nodes
|
||||
which are siblings within a single common parent node must be given a unique and
|
||||
sequential N value, starting from 0).
|
||||
cpu-map child nodes which do not share a common parent node can have the same
|
||||
name (ie same number N as other cpu-map child nodes at different device tree
|
||||
levels) since name uniqueness will be guaranteed by the device tree hierarchy.
|
||||
|
||||
===========================================
|
||||
3 - cluster/core/thread node bindings
|
||||
3 - socket/cluster/core/thread node bindings
|
||||
===========================================
|
||||
|
||||
Bindings for cluster/cpu/thread nodes are defined as follows:
|
||||
Bindings for socket/cluster/cpu/thread nodes are defined as follows:
|
||||
|
||||
- socket node
|
||||
|
||||
Description: must be declared within a cpu-map node, one node
|
||||
per physical socket in the system. A system can
|
||||
contain single or multiple physical socket.
|
||||
The association of sockets and NUMA nodes is beyond
|
||||
the scope of this bindings, please refer [2] for
|
||||
NUMA bindings.
|
||||
|
||||
This node is optional for a single socket system.
|
||||
|
||||
The socket node name must be "socketN" as described in 2.1 above.
|
||||
A socket node can not be a leaf node.
|
||||
|
||||
A socket node's child nodes must be one or more cluster nodes.
|
||||
|
||||
Any other configuration is considered invalid.
|
||||
|
||||
- cluster node
|
||||
|
||||
Description: must be declared within a cpu-map node, one node
|
||||
per cluster. A system can contain several layers of
|
||||
clustering and cluster nodes can be contained in parent
|
||||
cluster nodes.
|
||||
clustering within a single physical socket and cluster
|
||||
nodes can be contained in parent cluster nodes.
|
||||
|
||||
The cluster node name must be "clusterN" as described in 2.1 above.
|
||||
A cluster node can not be a leaf node.
|
||||
@@ -164,90 +180,93 @@ Bindings for cluster/cpu/thread nodes are defined as follows:
|
||||
4 - Example dts
|
||||
===========================================
|
||||
|
||||
Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters):
|
||||
Example 1 (ARM 64-bit, 16-cpu system, two clusters of clusters in a single
|
||||
physical socket):
|
||||
|
||||
cpus {
|
||||
#size-cells = <0>;
|
||||
#address-cells = <2>;
|
||||
|
||||
cpu-map {
|
||||
cluster0 {
|
||||
socket0 {
|
||||
cluster0 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU0>;
|
||||
cluster0 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU0>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU1>;
|
||||
};
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU1>;
|
||||
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU2>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU2>;
|
||||
cluster1 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU4>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU5>;
|
||||
};
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU3>;
|
||||
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU6>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU7>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cluster1 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU4>;
|
||||
cluster0 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU8>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU9>;
|
||||
};
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU5>;
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU10>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU11>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU6>;
|
||||
cluster1 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU12>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU13>;
|
||||
};
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU7>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cluster1 {
|
||||
cluster0 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU8>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU9>;
|
||||
};
|
||||
};
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU10>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU11>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
cluster1 {
|
||||
core0 {
|
||||
thread0 {
|
||||
cpu = <&CPU12>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU13>;
|
||||
};
|
||||
};
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU14>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU15>;
|
||||
core1 {
|
||||
thread0 {
|
||||
cpu = <&CPU14>;
|
||||
};
|
||||
thread1 {
|
||||
cpu = <&CPU15>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -470,6 +489,65 @@ cpus {
|
||||
};
|
||||
};
|
||||
|
||||
Example 3: HiFive Unleashed (RISC-V 64 bit, 4 core system)
|
||||
|
||||
{
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
compatible = "sifive,fu540g", "sifive,fu500";
|
||||
model = "sifive,hifive-unleashed-a00";
|
||||
|
||||
...
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
cpu-map {
|
||||
socket0 {
|
||||
cluster0 {
|
||||
core0 {
|
||||
cpu = <&CPU1>;
|
||||
};
|
||||
core1 {
|
||||
cpu = <&CPU2>;
|
||||
};
|
||||
core2 {
|
||||
cpu0 = <&CPU2>;
|
||||
};
|
||||
core3 {
|
||||
cpu0 = <&CPU3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
CPU1: cpu@1 {
|
||||
device_type = "cpu";
|
||||
compatible = "sifive,rocket0", "riscv";
|
||||
reg = <0x1>;
|
||||
}
|
||||
|
||||
CPU2: cpu@2 {
|
||||
device_type = "cpu";
|
||||
compatible = "sifive,rocket0", "riscv";
|
||||
reg = <0x2>;
|
||||
}
|
||||
CPU3: cpu@3 {
|
||||
device_type = "cpu";
|
||||
compatible = "sifive,rocket0", "riscv";
|
||||
reg = <0x3>;
|
||||
}
|
||||
CPU4: cpu@4 {
|
||||
device_type = "cpu";
|
||||
compatible = "sifive,rocket0", "riscv";
|
||||
reg = <0x4>;
|
||||
}
|
||||
}
|
||||
};
|
||||
===============================================================================
|
||||
[1] ARM Linux kernel documentation
|
||||
Documentation/devicetree/bindings/arm/cpus.yaml
|
||||
[2] Devicetree NUMA binding description
|
||||
Documentation/devicetree/bindings/numa.txt
|
||||
[3] RISC-V Linux kernel documentation
|
||||
Documentation/devicetree/bindings/riscv/cpus.txt
|
||||
[4] https://www.devicetree.org/specifications/
|
||||
+16
@@ -4281,6 +4281,14 @@ S: Supported
|
||||
F: drivers/cpuidle/cpuidle-exynos.c
|
||||
F: arch/arm/mach-exynos/pm.c
|
||||
|
||||
CPUIDLE DRIVER - ARM PSCI
|
||||
M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
|
||||
M: Sudeep Holla <sudeep.holla@arm.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
L: linux-arm-kernel@lists.infradead.org
|
||||
S: Supported
|
||||
F: drivers/cpuidle/cpuidle-psci.c
|
||||
|
||||
CPU IDLE TIME MANAGEMENT FRAMEWORK
|
||||
M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
|
||||
M: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
@@ -6427,6 +6435,7 @@ M: Frank Li <Frank.li@nxp.com>
|
||||
L: linux-arm-kernel@lists.infradead.org
|
||||
S: Maintained
|
||||
F: drivers/perf/fsl_imx8_ddr_perf.c
|
||||
F: Documentation/admin-guide/perf/imx-ddr.rst
|
||||
F: Documentation/devicetree/bindings/perf/fsl-imx-ddr.txt
|
||||
|
||||
FREESCALE IMX I2C DRIVER
|
||||
@@ -6720,6 +6729,13 @@ W: https://linuxtv.org
|
||||
S: Maintained
|
||||
F: drivers/media/radio/radio-gemtek*
|
||||
|
||||
GENERIC ARCHITECTURE TOPOLOGY
|
||||
M: Sudeep Holla <sudeep.holla@arm.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/base/arch_topology.c
|
||||
F: include/linux/arch_topology.h
|
||||
|
||||
GENERIC GPIO I2C DRIVER
|
||||
M: Wolfram Sang <wsa+renesas@sang-engineering.com>
|
||||
S: Supported
|
||||
|
||||
@@ -913,6 +913,10 @@ ifeq ($(CONFIG_STRIP_ASM_SYMS),y)
|
||||
LDFLAGS_vmlinux += $(call ld-option, -X,)
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RELR),y)
|
||||
LDFLAGS_vmlinux += --pack-dyn-relocs=relr
|
||||
endif
|
||||
|
||||
# insure the checker run with the right endianness
|
||||
CHECKFLAGS += $(if $(CONFIG_CPU_BIG_ENDIAN),-mbig-endian,-mlittle-endian)
|
||||
|
||||
|
||||
@@ -925,6 +925,20 @@ config LOCK_EVENT_COUNTS
|
||||
the chance of application behavior change because of timing
|
||||
differences. The counts are reported via debugfs.
|
||||
|
||||
# Select if the architecture has support for applying RELR relocations.
|
||||
config ARCH_HAS_RELR
|
||||
bool
|
||||
|
||||
config RELR
|
||||
bool "Use RELR relocation packing"
|
||||
depends on ARCH_HAS_RELR && TOOLS_SUPPORT_RELR
|
||||
default y
|
||||
help
|
||||
Store the kernel's dynamic relocations in the RELR relocation packing
|
||||
format. Requires a compatible linker (LLD supports this feature), as
|
||||
well as compatible NM and OBJCOPY utilities (llvm-nm and llvm-objcopy
|
||||
are compatible).
|
||||
|
||||
source "kernel/gcov/Kconfig"
|
||||
|
||||
source "scripts/gcc-plugins/Kconfig"
|
||||
|
||||
@@ -5,26 +5,6 @@
|
||||
#ifdef CONFIG_ARM_CPU_TOPOLOGY
|
||||
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
struct cputopo_arm {
|
||||
int thread_id;
|
||||
int core_id;
|
||||
int socket_id;
|
||||
cpumask_t thread_sibling;
|
||||
cpumask_t core_sibling;
|
||||
};
|
||||
|
||||
extern struct cputopo_arm cpu_topology[NR_CPUS];
|
||||
|
||||
#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
|
||||
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
|
||||
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling)
|
||||
#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling)
|
||||
|
||||
void init_cpu_topology(void);
|
||||
void store_cpu_topology(unsigned int cpuid);
|
||||
const struct cpumask *cpu_coregroup_mask(int cpu);
|
||||
|
||||
#include <linux/arch_topology.h>
|
||||
|
||||
/* Replace task scheduler's default frequency-invariant accounting */
|
||||
|
||||
@@ -177,17 +177,6 @@ static inline void parse_dt_topology(void) {}
|
||||
static inline void update_cpu_capacity(unsigned int cpuid) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* cpu topology table
|
||||
*/
|
||||
struct cputopo_arm cpu_topology[NR_CPUS];
|
||||
EXPORT_SYMBOL_GPL(cpu_topology);
|
||||
|
||||
const struct cpumask *cpu_coregroup_mask(int cpu)
|
||||
{
|
||||
return &cpu_topology[cpu].core_sibling;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current assumption is that we can power gate each core independently.
|
||||
* This will be superseded by DT binding once available.
|
||||
@@ -197,32 +186,6 @@ const struct cpumask *cpu_corepower_mask(int cpu)
|
||||
return &cpu_topology[cpu].thread_sibling;
|
||||
}
|
||||
|
||||
static void update_siblings_masks(unsigned int cpuid)
|
||||
{
|
||||
struct cputopo_arm *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
|
||||
int cpu;
|
||||
|
||||
/* update core and thread sibling masks */
|
||||
for_each_possible_cpu(cpu) {
|
||||
cpu_topo = &cpu_topology[cpu];
|
||||
|
||||
if (cpuid_topo->socket_id != cpu_topo->socket_id)
|
||||
continue;
|
||||
|
||||
cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
|
||||
if (cpu != cpuid)
|
||||
cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
|
||||
|
||||
if (cpuid_topo->core_id != cpu_topo->core_id)
|
||||
continue;
|
||||
|
||||
cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling);
|
||||
if (cpu != cpuid)
|
||||
cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling);
|
||||
}
|
||||
smp_wmb();
|
||||
}
|
||||
|
||||
/*
|
||||
* store_cpu_topology is called at boot when only one cpu is running
|
||||
* and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
|
||||
@@ -230,7 +193,7 @@ static void update_siblings_masks(unsigned int cpuid)
|
||||
*/
|
||||
void store_cpu_topology(unsigned int cpuid)
|
||||
{
|
||||
struct cputopo_arm *cpuid_topo = &cpu_topology[cpuid];
|
||||
struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
|
||||
unsigned int mpidr;
|
||||
|
||||
/* If the cpu topology has been already set, just return */
|
||||
@@ -250,12 +213,12 @@ void store_cpu_topology(unsigned int cpuid)
|
||||
/* core performance interdependency */
|
||||
cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
|
||||
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
|
||||
cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
|
||||
cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
|
||||
} else {
|
||||
/* largely independent cores */
|
||||
cpuid_topo->thread_id = -1;
|
||||
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
|
||||
cpuid_topo->socket_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
|
||||
cpuid_topo->package_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@@ -265,7 +228,7 @@ void store_cpu_topology(unsigned int cpuid)
|
||||
*/
|
||||
cpuid_topo->thread_id = -1;
|
||||
cpuid_topo->core_id = 0;
|
||||
cpuid_topo->socket_id = -1;
|
||||
cpuid_topo->package_id = -1;
|
||||
}
|
||||
|
||||
update_siblings_masks(cpuid);
|
||||
@@ -275,7 +238,7 @@ void store_cpu_topology(unsigned int cpuid)
|
||||
pr_info("CPU%u: thread %d, cpu %d, socket %d, mpidr %x\n",
|
||||
cpuid, cpu_topology[cpuid].thread_id,
|
||||
cpu_topology[cpuid].core_id,
|
||||
cpu_topology[cpuid].socket_id, mpidr);
|
||||
cpu_topology[cpuid].package_id, mpidr);
|
||||
}
|
||||
|
||||
static inline int cpu_corepower_flags(void)
|
||||
@@ -298,18 +261,7 @@ static struct sched_domain_topology_level arm_topology[] = {
|
||||
*/
|
||||
void __init init_cpu_topology(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* init core mask and capacity */
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
|
||||
|
||||
cpu_topo->thread_id = -1;
|
||||
cpu_topo->core_id = -1;
|
||||
cpu_topo->socket_id = -1;
|
||||
cpumask_clear(&cpu_topo->core_sibling);
|
||||
cpumask_clear(&cpu_topo->thread_sibling);
|
||||
}
|
||||
reset_cpu_topology();
|
||||
smp_wmb();
|
||||
|
||||
parse_dt_topology();
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y += kernel/ mm/
|
||||
obj-$(CONFIG_NET) += net/
|
||||
obj-$(CONFIG_KVM) += kvm/
|
||||
obj-$(CONFIG_XEN) += xen/
|
||||
obj-$(CONFIG_CRYPTO) += crypto/
|
||||
+36
-7
@@ -148,6 +148,7 @@ config ARM64
|
||||
select HAVE_FAST_GUP
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_FUNCTION_ERROR_INJECTION
|
||||
select HAVE_FUNCTION_GRAPH_TRACER
|
||||
select HAVE_GCC_PLUGINS
|
||||
select HAVE_HW_BREAKPOINT if PERF_EVENTS
|
||||
@@ -286,7 +287,7 @@ config PGTABLE_LEVELS
|
||||
int
|
||||
default 2 if ARM64_16K_PAGES && ARM64_VA_BITS_36
|
||||
default 2 if ARM64_64K_PAGES && ARM64_VA_BITS_42
|
||||
default 3 if ARM64_64K_PAGES && (ARM64_VA_BITS_48 || ARM64_USER_VA_BITS_52)
|
||||
default 3 if ARM64_64K_PAGES && (ARM64_VA_BITS_48 || ARM64_VA_BITS_52)
|
||||
default 3 if ARM64_4K_PAGES && ARM64_VA_BITS_39
|
||||
default 3 if ARM64_16K_PAGES && ARM64_VA_BITS_47
|
||||
default 4 if !ARM64_64K_PAGES && ARM64_VA_BITS_48
|
||||
@@ -297,6 +298,21 @@ config ARCH_SUPPORTS_UPROBES
|
||||
config ARCH_PROC_KCORE_TEXT
|
||||
def_bool y
|
||||
|
||||
config KASAN_SHADOW_OFFSET
|
||||
hex
|
||||
depends on KASAN
|
||||
default 0xdfffa00000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && !KASAN_SW_TAGS
|
||||
default 0xdfffd00000000000 if ARM64_VA_BITS_47 && !KASAN_SW_TAGS
|
||||
default 0xdffffe8000000000 if ARM64_VA_BITS_42 && !KASAN_SW_TAGS
|
||||
default 0xdfffffd000000000 if ARM64_VA_BITS_39 && !KASAN_SW_TAGS
|
||||
default 0xdffffffa00000000 if ARM64_VA_BITS_36 && !KASAN_SW_TAGS
|
||||
default 0xefff900000000000 if (ARM64_VA_BITS_48 || ARM64_VA_BITS_52) && KASAN_SW_TAGS
|
||||
default 0xefffc80000000000 if ARM64_VA_BITS_47 && KASAN_SW_TAGS
|
||||
default 0xeffffe4000000000 if ARM64_VA_BITS_42 && KASAN_SW_TAGS
|
||||
default 0xefffffc800000000 if ARM64_VA_BITS_39 && KASAN_SW_TAGS
|
||||
default 0xeffffff900000000 if ARM64_VA_BITS_36 && KASAN_SW_TAGS
|
||||
default 0xffffffffffffffff
|
||||
|
||||
source "arch/arm64/Kconfig.platforms"
|
||||
|
||||
menu "Kernel Features"
|
||||
@@ -744,13 +760,14 @@ config ARM64_VA_BITS_47
|
||||
config ARM64_VA_BITS_48
|
||||
bool "48-bit"
|
||||
|
||||
config ARM64_USER_VA_BITS_52
|
||||
bool "52-bit (user)"
|
||||
config ARM64_VA_BITS_52
|
||||
bool "52-bit"
|
||||
depends on ARM64_64K_PAGES && (ARM64_PAN || !ARM64_SW_TTBR0_PAN)
|
||||
help
|
||||
Enable 52-bit virtual addressing for userspace when explicitly
|
||||
requested via a hint to mmap(). The kernel will continue to
|
||||
use 48-bit virtual addresses for its own mappings.
|
||||
requested via a hint to mmap(). The kernel will also use 52-bit
|
||||
virtual addresses for its own mappings (provided HW support for
|
||||
this feature is available, otherwise it reverts to 48-bit).
|
||||
|
||||
NOTE: Enabling 52-bit virtual addressing in conjunction with
|
||||
ARMv8.3 Pointer Authentication will result in the PAC being
|
||||
@@ -763,7 +780,7 @@ endchoice
|
||||
|
||||
config ARM64_FORCE_52BIT
|
||||
bool "Force 52-bit virtual addresses for userspace"
|
||||
depends on ARM64_USER_VA_BITS_52 && EXPERT
|
||||
depends on ARM64_VA_BITS_52 && EXPERT
|
||||
help
|
||||
For systems with 52-bit userspace VAs enabled, the kernel will attempt
|
||||
to maintain compatibility with older software by providing 48-bit VAs
|
||||
@@ -780,7 +797,8 @@ config ARM64_VA_BITS
|
||||
default 39 if ARM64_VA_BITS_39
|
||||
default 42 if ARM64_VA_BITS_42
|
||||
default 47 if ARM64_VA_BITS_47
|
||||
default 48 if ARM64_VA_BITS_48 || ARM64_USER_VA_BITS_52
|
||||
default 48 if ARM64_VA_BITS_48
|
||||
default 52 if ARM64_VA_BITS_52
|
||||
|
||||
choice
|
||||
prompt "Physical address space size"
|
||||
@@ -1110,6 +1128,15 @@ config ARM64_SW_TTBR0_PAN
|
||||
zeroed area and reserved ASID. The user access routines
|
||||
restore the valid TTBR0_EL1 temporarily.
|
||||
|
||||
config ARM64_TAGGED_ADDR_ABI
|
||||
bool "Enable the tagged user addresses syscall ABI"
|
||||
default y
|
||||
help
|
||||
When this option is enabled, user applications can opt in to a
|
||||
relaxed ABI via prctl() allowing tagged addresses to be passed
|
||||
to system calls as pointer arguments. For details, see
|
||||
Documentation/arm64/tagged-address-abi.txt.
|
||||
|
||||
menuconfig COMPAT
|
||||
bool "Kernel support for 32-bit EL0"
|
||||
depends on ARM64_4K_PAGES || EXPERT
|
||||
@@ -1263,6 +1290,7 @@ config ARM64_PAN
|
||||
|
||||
config ARM64_LSE_ATOMICS
|
||||
bool "Atomic instructions"
|
||||
depends on JUMP_LABEL
|
||||
default y
|
||||
help
|
||||
As part of the Large System Extensions, ARMv8.1 introduces new
|
||||
@@ -1467,6 +1495,7 @@ endif
|
||||
|
||||
config RELOCATABLE
|
||||
bool
|
||||
select ARCH_HAS_RELR
|
||||
help
|
||||
This builds the kernel as a Position Independent Executable (PIE),
|
||||
which retains all relocation metadata required to relocate the
|
||||
|
||||
+9
-14
@@ -39,6 +39,12 @@ $(warning LSE atomics not supported by binutils)
|
||||
endif
|
||||
endif
|
||||
|
||||
cc_has_k_constraint := $(call try-run,echo \
|
||||
'int main(void) { \
|
||||
asm volatile("and w0, w0, %w0" :: "K" (4294967295)); \
|
||||
return 0; \
|
||||
}' | $(CC) -S -x c -o "$$TMP" -,,-DCONFIG_CC_HAS_K_CONSTRAINT=1)
|
||||
|
||||
ifeq ($(CONFIG_ARM64), y)
|
||||
brokengasinst := $(call as-instr,1:\n.inst 0\n.rept . - 1b\n\nnop\n.endr\n,,-DCONFIG_BROKEN_GAS_INST=1)
|
||||
|
||||
@@ -63,7 +69,8 @@ ifeq ($(CONFIG_GENERIC_COMPAT_VDSO), y)
|
||||
endif
|
||||
endif
|
||||
|
||||
KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst) $(compat_vdso)
|
||||
KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) $(brokengasinst) \
|
||||
$(compat_vdso) $(cc_has_k_constraint)
|
||||
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, psabi)
|
||||
KBUILD_AFLAGS += $(lseinstr) $(brokengasinst) $(compat_vdso)
|
||||
@@ -126,21 +133,9 @@ KBUILD_CFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
|
||||
KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
|
||||
KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT)
|
||||
|
||||
# KASAN_SHADOW_OFFSET = VA_START + (1 << (VA_BITS - KASAN_SHADOW_SCALE_SHIFT))
|
||||
# - (1 << (64 - KASAN_SHADOW_SCALE_SHIFT))
|
||||
# in 32-bit arithmetic
|
||||
KASAN_SHADOW_OFFSET := $(shell printf "0x%08x00000000\n" $$(( \
|
||||
(0xffffffff & (-1 << ($(CONFIG_ARM64_VA_BITS) - 32))) \
|
||||
+ (1 << ($(CONFIG_ARM64_VA_BITS) - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) \
|
||||
- (1 << (64 - 32 - $(KASAN_SHADOW_SCALE_SHIFT))) )) )
|
||||
|
||||
export TEXT_OFFSET GZFLAGS
|
||||
|
||||
core-y += arch/arm64/kernel/ arch/arm64/mm/
|
||||
core-$(CONFIG_NET) += arch/arm64/net/
|
||||
core-$(CONFIG_KVM) += arch/arm64/kvm/
|
||||
core-$(CONFIG_XEN) += arch/arm64/xen/
|
||||
core-$(CONFIG_CRYPTO) += arch/arm64/crypto/
|
||||
core-y += arch/arm64/
|
||||
libs-y := arch/arm64/lib/ $(libs-y)
|
||||
core-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
|
||||
|
||||
|
||||
@@ -123,17 +123,6 @@ alternative_else
|
||||
alternative_endif
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Sanitise a 64-bit bounded index wrt speculation, returning zero if out
|
||||
* of bounds.
|
||||
*/
|
||||
.macro mask_nospec64, idx, limit, tmp
|
||||
sub \tmp, \idx, \limit
|
||||
bic \tmp, \tmp, \idx
|
||||
and \idx, \idx, \tmp, asr #63
|
||||
csdb
|
||||
.endm
|
||||
|
||||
/*
|
||||
* NOP sequence
|
||||
*/
|
||||
@@ -349,6 +338,13 @@ alternative_endif
|
||||
bfi \valreg, \t0sz, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
|
||||
.endm
|
||||
|
||||
/*
|
||||
* tcr_set_t1sz - update TCR.T1SZ
|
||||
*/
|
||||
.macro tcr_set_t1sz, valreg, t1sz
|
||||
bfi \valreg, \t1sz, #TCR_T1SZ_OFFSET, #TCR_TxSZ_WIDTH
|
||||
.endm
|
||||
|
||||
/*
|
||||
* tcr_compute_pa_size - set TCR.(I)PS to the highest supported
|
||||
* ID_AA64MMFR0_EL1.PARange value
|
||||
@@ -538,9 +534,13 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
|
||||
* In future this may be nop'ed out when dealing with 52-bit kernel VAs.
|
||||
* ttbr: Value of ttbr to set, modified.
|
||||
*/
|
||||
.macro offset_ttbr1, ttbr
|
||||
#ifdef CONFIG_ARM64_USER_VA_BITS_52
|
||||
.macro offset_ttbr1, ttbr, tmp
|
||||
#ifdef CONFIG_ARM64_VA_BITS_52
|
||||
mrs_s \tmp, SYS_ID_AA64MMFR2_EL1
|
||||
and \tmp, \tmp, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
|
||||
cbnz \tmp, .Lskipoffs_\@
|
||||
orr \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
|
||||
.Lskipoffs_\@ :
|
||||
#endif
|
||||
.endm
|
||||
|
||||
@@ -550,7 +550,7 @@ USER(\label, ic ivau, \tmp2) // invalidate I line PoU
|
||||
* to be nop'ed out when dealing with 52-bit kernel VAs.
|
||||
*/
|
||||
.macro restore_ttbr1, ttbr
|
||||
#ifdef CONFIG_ARM64_USER_VA_BITS_52
|
||||
#ifdef CONFIG_ARM64_VA_BITS_52
|
||||
bic \ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
|
||||
#endif
|
||||
.endm
|
||||
|
||||
@@ -13,21 +13,91 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/barrier.h>
|
||||
#include <asm/cmpxchg.h>
|
||||
#include <asm/lse.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define ATOMIC_OP(op) \
|
||||
static inline void arch_##op(int i, atomic_t *v) \
|
||||
{ \
|
||||
__lse_ll_sc_body(op, i, v); \
|
||||
}
|
||||
|
||||
#define __ARM64_IN_ATOMIC_IMPL
|
||||
ATOMIC_OP(atomic_andnot)
|
||||
ATOMIC_OP(atomic_or)
|
||||
ATOMIC_OP(atomic_xor)
|
||||
ATOMIC_OP(atomic_add)
|
||||
ATOMIC_OP(atomic_and)
|
||||
ATOMIC_OP(atomic_sub)
|
||||
|
||||
#if defined(CONFIG_ARM64_LSE_ATOMICS) && defined(CONFIG_AS_LSE)
|
||||
#include <asm/atomic_lse.h>
|
||||
#else
|
||||
#include <asm/atomic_ll_sc.h>
|
||||
#endif
|
||||
#undef ATOMIC_OP
|
||||
|
||||
#undef __ARM64_IN_ATOMIC_IMPL
|
||||
#define ATOMIC_FETCH_OP(name, op) \
|
||||
static inline int arch_##op##name(int i, atomic_t *v) \
|
||||
{ \
|
||||
return __lse_ll_sc_body(op##name, i, v); \
|
||||
}
|
||||
|
||||
#include <asm/cmpxchg.h>
|
||||
#define ATOMIC_FETCH_OPS(op) \
|
||||
ATOMIC_FETCH_OP(_relaxed, op) \
|
||||
ATOMIC_FETCH_OP(_acquire, op) \
|
||||
ATOMIC_FETCH_OP(_release, op) \
|
||||
ATOMIC_FETCH_OP( , op)
|
||||
|
||||
ATOMIC_FETCH_OPS(atomic_fetch_andnot)
|
||||
ATOMIC_FETCH_OPS(atomic_fetch_or)
|
||||
ATOMIC_FETCH_OPS(atomic_fetch_xor)
|
||||
ATOMIC_FETCH_OPS(atomic_fetch_add)
|
||||
ATOMIC_FETCH_OPS(atomic_fetch_and)
|
||||
ATOMIC_FETCH_OPS(atomic_fetch_sub)
|
||||
ATOMIC_FETCH_OPS(atomic_add_return)
|
||||
ATOMIC_FETCH_OPS(atomic_sub_return)
|
||||
|
||||
#undef ATOMIC_FETCH_OP
|
||||
#undef ATOMIC_FETCH_OPS
|
||||
|
||||
#define ATOMIC64_OP(op) \
|
||||
static inline void arch_##op(long i, atomic64_t *v) \
|
||||
{ \
|
||||
__lse_ll_sc_body(op, i, v); \
|
||||
}
|
||||
|
||||
ATOMIC64_OP(atomic64_andnot)
|
||||
ATOMIC64_OP(atomic64_or)
|
||||
ATOMIC64_OP(atomic64_xor)
|
||||
ATOMIC64_OP(atomic64_add)
|
||||
ATOMIC64_OP(atomic64_and)
|
||||
ATOMIC64_OP(atomic64_sub)
|
||||
|
||||
#undef ATOMIC64_OP
|
||||
|
||||
#define ATOMIC64_FETCH_OP(name, op) \
|
||||
static inline long arch_##op##name(long i, atomic64_t *v) \
|
||||
{ \
|
||||
return __lse_ll_sc_body(op##name, i, v); \
|
||||
}
|
||||
|
||||
#define ATOMIC64_FETCH_OPS(op) \
|
||||
ATOMIC64_FETCH_OP(_relaxed, op) \
|
||||
ATOMIC64_FETCH_OP(_acquire, op) \
|
||||
ATOMIC64_FETCH_OP(_release, op) \
|
||||
ATOMIC64_FETCH_OP( , op)
|
||||
|
||||
ATOMIC64_FETCH_OPS(atomic64_fetch_andnot)
|
||||
ATOMIC64_FETCH_OPS(atomic64_fetch_or)
|
||||
ATOMIC64_FETCH_OPS(atomic64_fetch_xor)
|
||||
ATOMIC64_FETCH_OPS(atomic64_fetch_add)
|
||||
ATOMIC64_FETCH_OPS(atomic64_fetch_and)
|
||||
ATOMIC64_FETCH_OPS(atomic64_fetch_sub)
|
||||
ATOMIC64_FETCH_OPS(atomic64_add_return)
|
||||
ATOMIC64_FETCH_OPS(atomic64_sub_return)
|
||||
|
||||
#undef ATOMIC64_FETCH_OP
|
||||
#undef ATOMIC64_FETCH_OPS
|
||||
|
||||
static inline long arch_atomic64_dec_if_positive(atomic64_t *v)
|
||||
{
|
||||
return __lse_ll_sc_body(atomic64_dec_if_positive, v);
|
||||
}
|
||||
|
||||
#define ATOMIC_INIT(i) { (i) }
|
||||
|
||||
@@ -157,5 +227,4 @@
|
||||
|
||||
#include <asm-generic/atomic-instrumented.h>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif /* __ASM_ATOMIC_H */
|
||||
@@ -10,83 +10,92 @@
|
||||
#ifndef __ASM_ATOMIC_LL_SC_H
|
||||
#define __ASM_ATOMIC_LL_SC_H
|
||||
|
||||
#ifndef __ARM64_IN_ATOMIC_IMPL
|
||||
#error "please don't include this file directly"
|
||||
#include <linux/stringify.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS) && IS_ENABLED(CONFIG_AS_LSE)
|
||||
#define __LL_SC_FALLBACK(asm_ops) \
|
||||
" b 3f\n" \
|
||||
" .subsection 1\n" \
|
||||
"3:\n" \
|
||||
asm_ops "\n" \
|
||||
" b 4f\n" \
|
||||
" .previous\n" \
|
||||
"4:\n"
|
||||
#else
|
||||
#define __LL_SC_FALLBACK(asm_ops) asm_ops
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_CC_HAS_K_CONSTRAINT
|
||||
#define K
|
||||
#endif
|
||||
|
||||
/*
|
||||
* AArch64 UP and SMP safe atomic ops. We use load exclusive and
|
||||
* store exclusive to ensure that these are atomic. We may loop
|
||||
* to ensure that the update happens.
|
||||
*
|
||||
* NOTE: these functions do *not* follow the PCS and must explicitly
|
||||
* save any clobbered registers other than x0 (regardless of return
|
||||
* value). This is achieved through -fcall-saved-* compiler flags for
|
||||
* this file, which unfortunately don't work on a per-function basis
|
||||
* (the optimize attribute silently ignores these options).
|
||||
*/
|
||||
|
||||
#define ATOMIC_OP(op, asm_op) \
|
||||
__LL_SC_INLINE void \
|
||||
__LL_SC_PREFIX(arch_atomic_##op(int i, atomic_t *v)) \
|
||||
#define ATOMIC_OP(op, asm_op, constraint) \
|
||||
static inline void \
|
||||
__ll_sc_atomic_##op(int i, atomic_t *v) \
|
||||
{ \
|
||||
unsigned long tmp; \
|
||||
int result; \
|
||||
\
|
||||
asm volatile("// atomic_" #op "\n" \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %2\n" \
|
||||
"1: ldxr %w0, %2\n" \
|
||||
" " #asm_op " %w0, %w0, %w3\n" \
|
||||
" stxr %w1, %w0, %2\n" \
|
||||
" cbnz %w1, 1b" \
|
||||
" cbnz %w1, 1b\n") \
|
||||
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \
|
||||
: "Ir" (i)); \
|
||||
} \
|
||||
__LL_SC_EXPORT(arch_atomic_##op);
|
||||
: __stringify(constraint) "r" (i)); \
|
||||
}
|
||||
|
||||
#define ATOMIC_OP_RETURN(name, mb, acq, rel, cl, op, asm_op) \
|
||||
__LL_SC_INLINE int \
|
||||
__LL_SC_PREFIX(arch_atomic_##op##_return##name(int i, atomic_t *v)) \
|
||||
#define ATOMIC_OP_RETURN(name, mb, acq, rel, cl, op, asm_op, constraint)\
|
||||
static inline int \
|
||||
__ll_sc_atomic_##op##_return##name(int i, atomic_t *v) \
|
||||
{ \
|
||||
unsigned long tmp; \
|
||||
int result; \
|
||||
\
|
||||
asm volatile("// atomic_" #op "_return" #name "\n" \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %2\n" \
|
||||
"1: ld" #acq "xr %w0, %2\n" \
|
||||
" " #asm_op " %w0, %w0, %w3\n" \
|
||||
" st" #rel "xr %w1, %w0, %2\n" \
|
||||
" cbnz %w1, 1b\n" \
|
||||
" " #mb \
|
||||
" " #mb ) \
|
||||
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \
|
||||
: "Ir" (i) \
|
||||
: __stringify(constraint) "r" (i) \
|
||||
: cl); \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
__LL_SC_EXPORT(arch_atomic_##op##_return##name);
|
||||
}
|
||||
|
||||
#define ATOMIC_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \
|
||||
__LL_SC_INLINE int \
|
||||
__LL_SC_PREFIX(arch_atomic_fetch_##op##name(int i, atomic_t *v)) \
|
||||
#define ATOMIC_FETCH_OP(name, mb, acq, rel, cl, op, asm_op, constraint) \
|
||||
static inline int \
|
||||
__ll_sc_atomic_fetch_##op##name(int i, atomic_t *v) \
|
||||
{ \
|
||||
unsigned long tmp; \
|
||||
int val, result; \
|
||||
\
|
||||
asm volatile("// atomic_fetch_" #op #name "\n" \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %3\n" \
|
||||
"1: ld" #acq "xr %w0, %3\n" \
|
||||
" " #asm_op " %w1, %w0, %w4\n" \
|
||||
" st" #rel "xr %w2, %w1, %3\n" \
|
||||
" cbnz %w2, 1b\n" \
|
||||
" " #mb \
|
||||
" " #mb ) \
|
||||
: "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter) \
|
||||
: "Ir" (i) \
|
||||
: __stringify(constraint) "r" (i) \
|
||||
: cl); \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
__LL_SC_EXPORT(arch_atomic_fetch_##op##name);
|
||||
}
|
||||
|
||||
#define ATOMIC_OPS(...) \
|
||||
ATOMIC_OP(__VA_ARGS__) \
|
||||
@@ -99,8 +108,8 @@ __LL_SC_EXPORT(arch_atomic_fetch_##op##name);
|
||||
ATOMIC_FETCH_OP (_acquire, , a, , "memory", __VA_ARGS__)\
|
||||
ATOMIC_FETCH_OP (_release, , , l, "memory", __VA_ARGS__)
|
||||
|
||||
ATOMIC_OPS(add, add)
|
||||
ATOMIC_OPS(sub, sub)
|
||||
ATOMIC_OPS(add, add, I)
|
||||
ATOMIC_OPS(sub, sub, J)
|
||||
|
||||
#undef ATOMIC_OPS
|
||||
#define ATOMIC_OPS(...) \
|
||||
@@ -110,77 +119,82 @@ ATOMIC_OPS(sub, sub)
|
||||
ATOMIC_FETCH_OP (_acquire, , a, , "memory", __VA_ARGS__)\
|
||||
ATOMIC_FETCH_OP (_release, , , l, "memory", __VA_ARGS__)
|
||||
|
||||
ATOMIC_OPS(and, and)
|
||||
ATOMIC_OPS(andnot, bic)
|
||||
ATOMIC_OPS(or, orr)
|
||||
ATOMIC_OPS(xor, eor)
|
||||
ATOMIC_OPS(and, and, K)
|
||||
ATOMIC_OPS(or, orr, K)
|
||||
ATOMIC_OPS(xor, eor, K)
|
||||
/*
|
||||
* GAS converts the mysterious and undocumented BIC (immediate) alias to
|
||||
* an AND (immediate) instruction with the immediate inverted. We don't
|
||||
* have a constraint for this, so fall back to register.
|
||||
*/
|
||||
ATOMIC_OPS(andnot, bic, )
|
||||
|
||||
#undef ATOMIC_OPS
|
||||
#undef ATOMIC_FETCH_OP
|
||||
#undef ATOMIC_OP_RETURN
|
||||
#undef ATOMIC_OP
|
||||
|
||||
#define ATOMIC64_OP(op, asm_op) \
|
||||
__LL_SC_INLINE void \
|
||||
__LL_SC_PREFIX(arch_atomic64_##op(s64 i, atomic64_t *v)) \
|
||||
#define ATOMIC64_OP(op, asm_op, constraint) \
|
||||
static inline void \
|
||||
__ll_sc_atomic64_##op(s64 i, atomic64_t *v) \
|
||||
{ \
|
||||
s64 result; \
|
||||
unsigned long tmp; \
|
||||
\
|
||||
asm volatile("// atomic64_" #op "\n" \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %2\n" \
|
||||
"1: ldxr %0, %2\n" \
|
||||
" " #asm_op " %0, %0, %3\n" \
|
||||
" stxr %w1, %0, %2\n" \
|
||||
" cbnz %w1, 1b" \
|
||||
" cbnz %w1, 1b") \
|
||||
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \
|
||||
: "Ir" (i)); \
|
||||
} \
|
||||
__LL_SC_EXPORT(arch_atomic64_##op);
|
||||
: __stringify(constraint) "r" (i)); \
|
||||
}
|
||||
|
||||
#define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op) \
|
||||
__LL_SC_INLINE s64 \
|
||||
__LL_SC_PREFIX(arch_atomic64_##op##_return##name(s64 i, atomic64_t *v))\
|
||||
#define ATOMIC64_OP_RETURN(name, mb, acq, rel, cl, op, asm_op, constraint)\
|
||||
static inline long \
|
||||
__ll_sc_atomic64_##op##_return##name(s64 i, atomic64_t *v) \
|
||||
{ \
|
||||
s64 result; \
|
||||
unsigned long tmp; \
|
||||
\
|
||||
asm volatile("// atomic64_" #op "_return" #name "\n" \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %2\n" \
|
||||
"1: ld" #acq "xr %0, %2\n" \
|
||||
" " #asm_op " %0, %0, %3\n" \
|
||||
" st" #rel "xr %w1, %0, %2\n" \
|
||||
" cbnz %w1, 1b\n" \
|
||||
" " #mb \
|
||||
" " #mb ) \
|
||||
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \
|
||||
: "Ir" (i) \
|
||||
: __stringify(constraint) "r" (i) \
|
||||
: cl); \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
__LL_SC_EXPORT(arch_atomic64_##op##_return##name);
|
||||
}
|
||||
|
||||
#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op) \
|
||||
__LL_SC_INLINE s64 \
|
||||
__LL_SC_PREFIX(arch_atomic64_fetch_##op##name(s64 i, atomic64_t *v)) \
|
||||
#define ATOMIC64_FETCH_OP(name, mb, acq, rel, cl, op, asm_op, constraint)\
|
||||
static inline long \
|
||||
__ll_sc_atomic64_fetch_##op##name(s64 i, atomic64_t *v) \
|
||||
{ \
|
||||
s64 result, val; \
|
||||
unsigned long tmp; \
|
||||
\
|
||||
asm volatile("// atomic64_fetch_" #op #name "\n" \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %3\n" \
|
||||
"1: ld" #acq "xr %0, %3\n" \
|
||||
" " #asm_op " %1, %0, %4\n" \
|
||||
" st" #rel "xr %w2, %1, %3\n" \
|
||||
" cbnz %w2, 1b\n" \
|
||||
" " #mb \
|
||||
" " #mb ) \
|
||||
: "=&r" (result), "=&r" (val), "=&r" (tmp), "+Q" (v->counter) \
|
||||
: "Ir" (i) \
|
||||
: __stringify(constraint) "r" (i) \
|
||||
: cl); \
|
||||
\
|
||||
return result; \
|
||||
} \
|
||||
__LL_SC_EXPORT(arch_atomic64_fetch_##op##name);
|
||||
}
|
||||
|
||||
#define ATOMIC64_OPS(...) \
|
||||
ATOMIC64_OP(__VA_ARGS__) \
|
||||
@@ -193,8 +207,8 @@ __LL_SC_EXPORT(arch_atomic64_fetch_##op##name);
|
||||
ATOMIC64_FETCH_OP (_acquire,, a, , "memory", __VA_ARGS__) \
|
||||
ATOMIC64_FETCH_OP (_release,, , l, "memory", __VA_ARGS__)
|
||||
|
||||
ATOMIC64_OPS(add, add)
|
||||
ATOMIC64_OPS(sub, sub)
|
||||
ATOMIC64_OPS(add, add, I)
|
||||
ATOMIC64_OPS(sub, sub, J)
|
||||
|
||||
#undef ATOMIC64_OPS
|
||||
#define ATOMIC64_OPS(...) \
|
||||
@@ -204,23 +218,29 @@ ATOMIC64_OPS(sub, sub)
|
||||
ATOMIC64_FETCH_OP (_acquire,, a, , "memory", __VA_ARGS__) \
|
||||
ATOMIC64_FETCH_OP (_release,, , l, "memory", __VA_ARGS__)
|
||||
|
||||
ATOMIC64_OPS(and, and)
|
||||
ATOMIC64_OPS(andnot, bic)
|
||||
ATOMIC64_OPS(or, orr)
|
||||
ATOMIC64_OPS(xor, eor)
|
||||
ATOMIC64_OPS(and, and, L)
|
||||
ATOMIC64_OPS(or, orr, L)
|
||||
ATOMIC64_OPS(xor, eor, L)
|
||||
/*
|
||||
* GAS converts the mysterious and undocumented BIC (immediate) alias to
|
||||
* an AND (immediate) instruction with the immediate inverted. We don't
|
||||
* have a constraint for this, so fall back to register.
|
||||
*/
|
||||
ATOMIC64_OPS(andnot, bic, )
|
||||
|
||||
#undef ATOMIC64_OPS
|
||||
#undef ATOMIC64_FETCH_OP
|
||||
#undef ATOMIC64_OP_RETURN
|
||||
#undef ATOMIC64_OP
|
||||
|
||||
__LL_SC_INLINE s64
|
||||
__LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v))
|
||||
static inline s64
|
||||
__ll_sc_atomic64_dec_if_positive(atomic64_t *v)
|
||||
{
|
||||
s64 result;
|
||||
unsigned long tmp;
|
||||
|
||||
asm volatile("// atomic64_dec_if_positive\n"
|
||||
__LL_SC_FALLBACK(
|
||||
" prfm pstl1strm, %2\n"
|
||||
"1: ldxr %0, %2\n"
|
||||
" subs %0, %0, #1\n"
|
||||
@@ -228,20 +248,19 @@ __LL_SC_PREFIX(arch_atomic64_dec_if_positive(atomic64_t *v))
|
||||
" stlxr %w1, %0, %2\n"
|
||||
" cbnz %w1, 1b\n"
|
||||
" dmb ish\n"
|
||||
"2:"
|
||||
"2:")
|
||||
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
|
||||
:
|
||||
: "cc", "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
__LL_SC_EXPORT(arch_atomic64_dec_if_positive);
|
||||
|
||||
#define __CMPXCHG_CASE(w, sfx, name, sz, mb, acq, rel, cl) \
|
||||
__LL_SC_INLINE u##sz \
|
||||
__LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr, \
|
||||
#define __CMPXCHG_CASE(w, sfx, name, sz, mb, acq, rel, cl, constraint) \
|
||||
static inline u##sz \
|
||||
__ll_sc__cmpxchg_case_##name##sz(volatile void *ptr, \
|
||||
unsigned long old, \
|
||||
u##sz new)) \
|
||||
u##sz new) \
|
||||
{ \
|
||||
unsigned long tmp; \
|
||||
u##sz oldval; \
|
||||
@@ -255,6 +274,7 @@ __LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr, \
|
||||
old = (u##sz)old; \
|
||||
\
|
||||
asm volatile( \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %[v]\n" \
|
||||
"1: ld" #acq "xr" #sfx "\t%" #w "[oldval], %[v]\n" \
|
||||
" eor %" #w "[tmp], %" #w "[oldval], %" #w "[old]\n" \
|
||||
@@ -262,46 +282,51 @@ __LL_SC_PREFIX(__cmpxchg_case_##name##sz(volatile void *ptr, \
|
||||
" st" #rel "xr" #sfx "\t%w[tmp], %" #w "[new], %[v]\n" \
|
||||
" cbnz %w[tmp], 1b\n" \
|
||||
" " #mb "\n" \
|
||||
"2:" \
|
||||
"2:") \
|
||||
: [tmp] "=&r" (tmp), [oldval] "=&r" (oldval), \
|
||||
[v] "+Q" (*(u##sz *)ptr) \
|
||||
: [old] "Kr" (old), [new] "r" (new) \
|
||||
: [old] __stringify(constraint) "r" (old), [new] "r" (new) \
|
||||
: cl); \
|
||||
\
|
||||
return oldval; \
|
||||
} \
|
||||
__LL_SC_EXPORT(__cmpxchg_case_##name##sz);
|
||||
}
|
||||
|
||||
__CMPXCHG_CASE(w, b, , 8, , , , )
|
||||
__CMPXCHG_CASE(w, h, , 16, , , , )
|
||||
__CMPXCHG_CASE(w, , , 32, , , , )
|
||||
__CMPXCHG_CASE( , , , 64, , , , )
|
||||
__CMPXCHG_CASE(w, b, acq_, 8, , a, , "memory")
|
||||
__CMPXCHG_CASE(w, h, acq_, 16, , a, , "memory")
|
||||
__CMPXCHG_CASE(w, , acq_, 32, , a, , "memory")
|
||||
__CMPXCHG_CASE( , , acq_, 64, , a, , "memory")
|
||||
__CMPXCHG_CASE(w, b, rel_, 8, , , l, "memory")
|
||||
__CMPXCHG_CASE(w, h, rel_, 16, , , l, "memory")
|
||||
__CMPXCHG_CASE(w, , rel_, 32, , , l, "memory")
|
||||
__CMPXCHG_CASE( , , rel_, 64, , , l, "memory")
|
||||
__CMPXCHG_CASE(w, b, mb_, 8, dmb ish, , l, "memory")
|
||||
__CMPXCHG_CASE(w, h, mb_, 16, dmb ish, , l, "memory")
|
||||
__CMPXCHG_CASE(w, , mb_, 32, dmb ish, , l, "memory")
|
||||
__CMPXCHG_CASE( , , mb_, 64, dmb ish, , l, "memory")
|
||||
/*
|
||||
* Earlier versions of GCC (no later than 8.1.0) appear to incorrectly
|
||||
* handle the 'K' constraint for the value 4294967295 - thus we use no
|
||||
* constraint for 32 bit operations.
|
||||
*/
|
||||
__CMPXCHG_CASE(w, b, , 8, , , , , K)
|
||||
__CMPXCHG_CASE(w, h, , 16, , , , , K)
|
||||
__CMPXCHG_CASE(w, , , 32, , , , , K)
|
||||
__CMPXCHG_CASE( , , , 64, , , , , L)
|
||||
__CMPXCHG_CASE(w, b, acq_, 8, , a, , "memory", K)
|
||||
__CMPXCHG_CASE(w, h, acq_, 16, , a, , "memory", K)
|
||||
__CMPXCHG_CASE(w, , acq_, 32, , a, , "memory", K)
|
||||
__CMPXCHG_CASE( , , acq_, 64, , a, , "memory", L)
|
||||
__CMPXCHG_CASE(w, b, rel_, 8, , , l, "memory", K)
|
||||
__CMPXCHG_CASE(w, h, rel_, 16, , , l, "memory", K)
|
||||
__CMPXCHG_CASE(w, , rel_, 32, , , l, "memory", K)
|
||||
__CMPXCHG_CASE( , , rel_, 64, , , l, "memory", L)
|
||||
__CMPXCHG_CASE(w, b, mb_, 8, dmb ish, , l, "memory", K)
|
||||
__CMPXCHG_CASE(w, h, mb_, 16, dmb ish, , l, "memory", K)
|
||||
__CMPXCHG_CASE(w, , mb_, 32, dmb ish, , l, "memory", K)
|
||||
__CMPXCHG_CASE( , , mb_, 64, dmb ish, , l, "memory", L)
|
||||
|
||||
#undef __CMPXCHG_CASE
|
||||
|
||||
#define __CMPXCHG_DBL(name, mb, rel, cl) \
|
||||
__LL_SC_INLINE long \
|
||||
__LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \
|
||||
static inline long \
|
||||
__ll_sc__cmpxchg_double##name(unsigned long old1, \
|
||||
unsigned long old2, \
|
||||
unsigned long new1, \
|
||||
unsigned long new2, \
|
||||
volatile void *ptr)) \
|
||||
volatile void *ptr) \
|
||||
{ \
|
||||
unsigned long tmp, ret; \
|
||||
\
|
||||
asm volatile("// __cmpxchg_double" #name "\n" \
|
||||
__LL_SC_FALLBACK( \
|
||||
" prfm pstl1strm, %2\n" \
|
||||
"1: ldxp %0, %1, %2\n" \
|
||||
" eor %0, %0, %3\n" \
|
||||
@@ -311,18 +336,18 @@ __LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \
|
||||
" st" #rel "xp %w0, %5, %6, %2\n" \
|
||||
" cbnz %w0, 1b\n" \
|
||||
" " #mb "\n" \
|
||||
"2:" \
|
||||
"2:") \
|
||||
: "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr) \
|
||||
: "r" (old1), "r" (old2), "r" (new1), "r" (new2) \
|
||||
: cl); \
|
||||
\
|
||||
return ret; \
|
||||
} \
|
||||
__LL_SC_EXPORT(__cmpxchg_double##name);
|
||||
}
|
||||
|
||||
__CMPXCHG_DBL( , , , )
|
||||
__CMPXCHG_DBL(_mb, dmb ish, l, "memory")
|
||||
|
||||
#undef __CMPXCHG_DBL
|
||||
#undef K
|
||||
|
||||
#endif /* __ASM_ATOMIC_LL_SC_H */
|
||||
+134
-259
File diff suppressed because it is too large.
Load diff
@@ -78,7 +78,7 @@ static inline u32 cache_type_cwg(void)
|
||||
return (read_cpuid_cachetype() >> CTR_CWG_SHIFT) & CTR_CWG_MASK;
|
||||
}
|
||||
|
||||
#define __read_mostly __attribute__((__section__(".data..read_mostly")))
|
||||
#define __read_mostly __section(.data..read_mostly)
|
||||
|
||||
static inline int cache_line_size_of_cpu(void)
|
||||
{
|
||||
|
||||
Loaded 20 of 137 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user