mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-06 05:06:29 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Documentation/bpf/bpf_devel_QA.rstb7abcd9c65
("bpf, doc: Link to submitting-patches.rst for general patch submission info")d56b0c461d
("bpf, docs: Fix link to netdev-FAQ target") https://lore.kernel.org/all/20230307095812.236eb1be@canb.auug.org.au/ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
d0ddf5065f
@ -226,7 +226,6 @@ ForEachMacros:
|
|||||||
- 'for_each_console_srcu'
|
- 'for_each_console_srcu'
|
||||||
- 'for_each_cpu'
|
- 'for_each_cpu'
|
||||||
- 'for_each_cpu_and'
|
- 'for_each_cpu_and'
|
||||||
- 'for_each_cpu_not'
|
|
||||||
- 'for_each_cpu_wrap'
|
- 'for_each_cpu_wrap'
|
||||||
- 'for_each_dapm_widgets'
|
- 'for_each_dapm_widgets'
|
||||||
- 'for_each_dedup_cand'
|
- 'for_each_dedup_cand'
|
||||||
|
10
.mailmap
10
.mailmap
@ -121,6 +121,7 @@ Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@gmail.com>
|
|||||||
Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@imgtec.com>
|
Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@imgtec.com>
|
||||||
Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@mips.com>
|
Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@mips.com>
|
||||||
<dev.kurt@vandijck-laurijssen.be> <kurt.van.dijck@eia.be>
|
<dev.kurt@vandijck-laurijssen.be> <kurt.van.dijck@eia.be>
|
||||||
|
Dikshita Agarwal <dikshita@qti.qualcomm.com> <dikshita@codeaurora.org>
|
||||||
Dmitry Baryshkov <dbaryshkov@gmail.com>
|
Dmitry Baryshkov <dbaryshkov@gmail.com>
|
||||||
Dmitry Baryshkov <dbaryshkov@gmail.com> <[dbaryshkov@gmail.com]>
|
Dmitry Baryshkov <dbaryshkov@gmail.com> <[dbaryshkov@gmail.com]>
|
||||||
Dmitry Baryshkov <dbaryshkov@gmail.com> <dmitry_baryshkov@mentor.com>
|
Dmitry Baryshkov <dbaryshkov@gmail.com> <dmitry_baryshkov@mentor.com>
|
||||||
@ -150,6 +151,7 @@ Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com>
|
|||||||
Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
|
Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
|
||||||
Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
|
Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
|
||||||
Gao Xiang <xiang@kernel.org> <hsiangkao@redhat.com>
|
Gao Xiang <xiang@kernel.org> <hsiangkao@redhat.com>
|
||||||
|
Georgi Djakov <djakov@kernel.org> <georgi.djakov@linaro.org>
|
||||||
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@de.ibm.com>
|
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@de.ibm.com>
|
||||||
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <gerald.schaefer@de.ibm.com>
|
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <gerald.schaefer@de.ibm.com>
|
||||||
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@linux.vnet.ibm.com>
|
Gerald Schaefer <gerald.schaefer@linux.ibm.com> <geraldsc@linux.vnet.ibm.com>
|
||||||
@ -304,6 +306,8 @@ Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@osg.samsung.com>
|
|||||||
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@redhat.com>
|
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@redhat.com>
|
||||||
Mauro Carvalho Chehab <mchehab@kernel.org> <m.chehab@samsung.com>
|
Mauro Carvalho Chehab <mchehab@kernel.org> <m.chehab@samsung.com>
|
||||||
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@s-opensource.com>
|
Mauro Carvalho Chehab <mchehab@kernel.org> <mchehab@s-opensource.com>
|
||||||
|
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@mellanox.com>
|
||||||
|
Maxim Mikityanskiy <maxtram95@gmail.com> <maximmi@nvidia.com>
|
||||||
Maxime Ripard <mripard@kernel.org> <maxime.ripard@bootlin.com>
|
Maxime Ripard <mripard@kernel.org> <maxime.ripard@bootlin.com>
|
||||||
Maxime Ripard <mripard@kernel.org> <maxime.ripard@free-electrons.com>
|
Maxime Ripard <mripard@kernel.org> <maxime.ripard@free-electrons.com>
|
||||||
Mayuresh Janorkar <mayur@ti.com>
|
Mayuresh Janorkar <mayur@ti.com>
|
||||||
@ -409,7 +413,10 @@ Shuah Khan <shuah@kernel.org> <shuah.kh@samsung.com>
|
|||||||
Simon Arlott <simon@octiron.net> <simon@fire.lp0.eu>
|
Simon Arlott <simon@octiron.net> <simon@fire.lp0.eu>
|
||||||
Simon Kelley <simon@thekelleys.org.uk>
|
Simon Kelley <simon@thekelleys.org.uk>
|
||||||
Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
|
Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
|
||||||
Stephen Hemminger <shemminger@osdl.org>
|
Stephen Hemminger <stephen@networkplumber.org> <shemminger@linux-foundation.org>
|
||||||
|
Stephen Hemminger <stephen@networkplumber.org> <shemminger@osdl.org>
|
||||||
|
Stephen Hemminger <stephen@networkplumber.org> <sthemmin@microsoft.com>
|
||||||
|
Stephen Hemminger <stephen@networkplumber.org> <sthemmin@vyatta.com>
|
||||||
Steve Wise <larrystevenwise@gmail.com> <swise@chelsio.com>
|
Steve Wise <larrystevenwise@gmail.com> <swise@chelsio.com>
|
||||||
Steve Wise <larrystevenwise@gmail.com> <swise@opengridcomputing.com>
|
Steve Wise <larrystevenwise@gmail.com> <swise@opengridcomputing.com>
|
||||||
Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
|
Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
|
||||||
@ -441,6 +448,7 @@ Vasily Averin <vasily.averin@linux.dev> <vvs@openvz.org>
|
|||||||
Vasily Averin <vasily.averin@linux.dev> <vvs@parallels.com>
|
Vasily Averin <vasily.averin@linux.dev> <vvs@parallels.com>
|
||||||
Vasily Averin <vasily.averin@linux.dev> <vvs@sw.ru>
|
Vasily Averin <vasily.averin@linux.dev> <vvs@sw.ru>
|
||||||
Valentin Schneider <vschneid@redhat.com> <valentin.schneider@arm.com>
|
Valentin Schneider <vschneid@redhat.com> <valentin.schneider@arm.com>
|
||||||
|
Vikash Garodia <quic_vgarodia@quicinc.com> <vgarodia@codeaurora.org>
|
||||||
Vinod Koul <vkoul@kernel.org> <vinod.koul@intel.com>
|
Vinod Koul <vkoul@kernel.org> <vinod.koul@intel.com>
|
||||||
Vinod Koul <vkoul@kernel.org> <vinod.koul@linux.intel.com>
|
Vinod Koul <vkoul@kernel.org> <vinod.koul@linux.intel.com>
|
||||||
Vinod Koul <vkoul@kernel.org> <vkoul@infradead.org>
|
Vinod Koul <vkoul@kernel.org> <vkoul@infradead.org>
|
||||||
|
@ -437,7 +437,8 @@ What: /sys/class/power_supply/<supply_name>/present
|
|||||||
Date: May 2007
|
Date: May 2007
|
||||||
Contact: linux-pm@vger.kernel.org
|
Contact: linux-pm@vger.kernel.org
|
||||||
Description:
|
Description:
|
||||||
Reports whether a battery is present or not in the system.
|
Reports whether a battery is present or not in the system. If the
|
||||||
|
property does not exist, the battery is considered to be present.
|
||||||
|
|
||||||
Access: Read
|
Access: Read
|
||||||
|
|
||||||
|
@ -6,6 +6,19 @@ Description:
|
|||||||
device at boot. It is equivalent to WDIOC_GETBOOTSTATUS of
|
device at boot. It is equivalent to WDIOC_GETBOOTSTATUS of
|
||||||
ioctl interface.
|
ioctl interface.
|
||||||
|
|
||||||
|
What: /sys/class/watchdog/watchdogn/options
|
||||||
|
Date: April 2023
|
||||||
|
Contact: Thomas Weißschuh
|
||||||
|
Description:
|
||||||
|
It is a read only file. It contains options of watchdog device.
|
||||||
|
|
||||||
|
What: /sys/class/watchdog/watchdogn/fw_version
|
||||||
|
Date: April 2023
|
||||||
|
Contact: Thomas Weißschuh
|
||||||
|
Description:
|
||||||
|
It is a read only file. It contains firmware version of
|
||||||
|
watchdog device.
|
||||||
|
|
||||||
What: /sys/class/watchdog/watchdogn/identity
|
What: /sys/class/watchdog/watchdogn/identity
|
||||||
Date: August 2015
|
Date: August 2015
|
||||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||||
|
@ -49,16 +49,23 @@ Contact: "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
|
|||||||
Description: Controls the in-place-update policy.
|
Description: Controls the in-place-update policy.
|
||||||
updates in f2fs. User can set:
|
updates in f2fs. User can set:
|
||||||
|
|
||||||
==== =================
|
===== =============== ===================================================
|
||||||
0x01 F2FS_IPU_FORCE
|
value policy description
|
||||||
0x02 F2FS_IPU_SSR
|
0x00 DISABLE disable IPU(=default option in LFS mode)
|
||||||
0x04 F2FS_IPU_UTIL
|
0x01 FORCE all the time
|
||||||
0x08 F2FS_IPU_SSR_UTIL
|
0x02 SSR if SSR mode is activated
|
||||||
0x10 F2FS_IPU_FSYNC
|
0x04 UTIL if FS utilization is over threashold
|
||||||
0x20 F2FS_IPU_ASYNC
|
0x08 SSR_UTIL if SSR mode is activated and FS utilization is over
|
||||||
0x40 F2FS_IPU_NOCACHE
|
threashold
|
||||||
0x80 F2FS_IPU_HONOR_OPU_WRITE
|
0x10 FSYNC activated in fsync path only for high performance
|
||||||
==== =================
|
flash storages. IPU will be triggered only if the
|
||||||
|
# of dirty pages over min_fsync_blocks.
|
||||||
|
(=default option)
|
||||||
|
0x20 ASYNC do IPU given by asynchronous write requests
|
||||||
|
0x40 NOCACHE disable IPU bio cache
|
||||||
|
0x80 HONOR_OPU_WRITE use OPU write prior to IPU write if inode has
|
||||||
|
FI_OPU_WRITE flag
|
||||||
|
===== =============== ===================================================
|
||||||
|
|
||||||
Refer segment.h for details.
|
Refer segment.h for details.
|
||||||
|
|
||||||
@ -669,3 +676,56 @@ Contact: "Ping Xiong" <xiongping1@xiaomi.com>
|
|||||||
Description: When DATA SEPARATION is on, it controls the age threshold to indicate
|
Description: When DATA SEPARATION is on, it controls the age threshold to indicate
|
||||||
the data blocks as warm. By default it was initialized as 2621440 blocks
|
the data blocks as warm. By default it was initialized as 2621440 blocks
|
||||||
(equals to 10GB).
|
(equals to 10GB).
|
||||||
|
|
||||||
|
What: /sys/fs/f2fs/<disk>/fault_rate
|
||||||
|
Date: May 2016
|
||||||
|
Contact: "Sheng Yong" <shengyong@oppo.com>
|
||||||
|
Contact: "Chao Yu" <chao@kernel.org>
|
||||||
|
Description: Enable fault injection in all supported types with
|
||||||
|
specified injection rate.
|
||||||
|
|
||||||
|
What: /sys/fs/f2fs/<disk>/fault_type
|
||||||
|
Date: May 2016
|
||||||
|
Contact: "Sheng Yong" <shengyong@oppo.com>
|
||||||
|
Contact: "Chao Yu" <chao@kernel.org>
|
||||||
|
Description: Support configuring fault injection type, should be
|
||||||
|
enabled with fault_injection option, fault type value
|
||||||
|
is shown below, it supports single or combined type.
|
||||||
|
|
||||||
|
=================== ===========
|
||||||
|
Type_Name Type_Value
|
||||||
|
=================== ===========
|
||||||
|
FAULT_KMALLOC 0x000000001
|
||||||
|
FAULT_KVMALLOC 0x000000002
|
||||||
|
FAULT_PAGE_ALLOC 0x000000004
|
||||||
|
FAULT_PAGE_GET 0x000000008
|
||||||
|
FAULT_ALLOC_BIO 0x000000010 (obsolete)
|
||||||
|
FAULT_ALLOC_NID 0x000000020
|
||||||
|
FAULT_ORPHAN 0x000000040
|
||||||
|
FAULT_BLOCK 0x000000080
|
||||||
|
FAULT_DIR_DEPTH 0x000000100
|
||||||
|
FAULT_EVICT_INODE 0x000000200
|
||||||
|
FAULT_TRUNCATE 0x000000400
|
||||||
|
FAULT_READ_IO 0x000000800
|
||||||
|
FAULT_CHECKPOINT 0x000001000
|
||||||
|
FAULT_DISCARD 0x000002000
|
||||||
|
FAULT_WRITE_IO 0x000004000
|
||||||
|
FAULT_SLAB_ALLOC 0x000008000
|
||||||
|
FAULT_DQUOT_INIT 0x000010000
|
||||||
|
FAULT_LOCK_OP 0x000020000
|
||||||
|
FAULT_BLKADDR 0x000040000
|
||||||
|
=================== ===========
|
||||||
|
|
||||||
|
What: /sys/fs/f2fs/<disk>/discard_io_aware_gran
|
||||||
|
Date: January 2023
|
||||||
|
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||||
|
Description: Controls background discard granularity of inner discard thread
|
||||||
|
when is not in idle. Inner thread will not issue discards with size that
|
||||||
|
is smaller than granularity. The unit size is one block(4KB), now only
|
||||||
|
support configuring in range of [0, 512].
|
||||||
|
Default: 512
|
||||||
|
|
||||||
|
What: /sys/fs/f2fs/<disk>/last_age_weight
|
||||||
|
Date: January 2023
|
||||||
|
Contact: "Ping Xiong" <xiongping1@xiaomi.com>
|
||||||
|
Description: When DATA SEPARATION is on, it controls the weight of last data block age.
|
||||||
|
@ -479,8 +479,16 @@ Spectre variant 2
|
|||||||
On Intel Skylake-era systems the mitigation covers most, but not all,
|
On Intel Skylake-era systems the mitigation covers most, but not all,
|
||||||
cases. See :ref:`[3] <spec_ref3>` for more details.
|
cases. See :ref:`[3] <spec_ref3>` for more details.
|
||||||
|
|
||||||
On CPUs with hardware mitigation for Spectre variant 2 (e.g. Enhanced
|
On CPUs with hardware mitigation for Spectre variant 2 (e.g. IBRS
|
||||||
IBRS on x86), retpoline is automatically disabled at run time.
|
or enhanced IBRS on x86), retpoline is automatically disabled at run time.
|
||||||
|
|
||||||
|
Systems which support enhanced IBRS (eIBRS) enable IBRS protection once at
|
||||||
|
boot, by setting the IBRS bit, and they're automatically protected against
|
||||||
|
Spectre v2 variant attacks, including cross-thread branch target injections
|
||||||
|
on SMT systems (STIBP). In other words, eIBRS enables STIBP too.
|
||||||
|
|
||||||
|
Legacy IBRS systems clear the IBRS bit on exit to userspace and
|
||||||
|
therefore explicitly enable STIBP for that
|
||||||
|
|
||||||
The retpoline mitigation is turned on by default on vulnerable
|
The retpoline mitigation is turned on by default on vulnerable
|
||||||
CPUs. It can be forced on or off by the administrator
|
CPUs. It can be forced on or off by the administrator
|
||||||
@ -504,9 +512,12 @@ Spectre variant 2
|
|||||||
For Spectre variant 2 mitigation, individual user programs
|
For Spectre variant 2 mitigation, individual user programs
|
||||||
can be compiled with return trampolines for indirect branches.
|
can be compiled with return trampolines for indirect branches.
|
||||||
This protects them from consuming poisoned entries in the branch
|
This protects them from consuming poisoned entries in the branch
|
||||||
target buffer left by malicious software. Alternatively, the
|
target buffer left by malicious software.
|
||||||
programs can disable their indirect branch speculation via prctl()
|
|
||||||
(See :ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
|
On legacy IBRS systems, at return to userspace, implicit STIBP is disabled
|
||||||
|
because the kernel clears the IBRS bit. In this case, the userspace programs
|
||||||
|
can disable indirect branch speculation via prctl() (See
|
||||||
|
:ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
|
||||||
On x86, this will turn on STIBP to guard against attacks from the
|
On x86, this will turn on STIBP to guard against attacks from the
|
||||||
sibling thread when the user program is running, and use IBPB to
|
sibling thread when the user program is running, and use IBPB to
|
||||||
flush the branch target buffer when switching to/from the program.
|
flush the branch target buffer when switching to/from the program.
|
||||||
|
@ -7,8 +7,8 @@ workflows related to reporting bugs, submitting patches, and queueing
|
|||||||
patches for stable kernels.
|
patches for stable kernels.
|
||||||
|
|
||||||
For general information about submitting patches, please refer to
|
For general information about submitting patches, please refer to
|
||||||
`Documentation/process/`_. This document only describes additional specifics
|
Documentation/process/submitting-patches.rst. This document only describes
|
||||||
related to BPF.
|
additional specifics related to BPF.
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
:local:
|
:local:
|
||||||
@ -461,15 +461,15 @@ needed::
|
|||||||
|
|
||||||
$ sudo make run_tests
|
$ sudo make run_tests
|
||||||
|
|
||||||
See the kernels selftest `Documentation/dev-tools/kselftest.rst`_
|
See :doc:`kernel selftest documentation </dev-tools/kselftest>`
|
||||||
document for further documentation.
|
for details.
|
||||||
|
|
||||||
To maximize the number of tests passing, the .config of the kernel
|
To maximize the number of tests passing, the .config of the kernel
|
||||||
under test should match the config file fragment in
|
under test should match the config file fragment in
|
||||||
tools/testing/selftests/bpf as closely as possible.
|
tools/testing/selftests/bpf as closely as possible.
|
||||||
|
|
||||||
Finally to ensure support for latest BPF Type Format features -
|
Finally to ensure support for latest BPF Type Format features -
|
||||||
discussed in `Documentation/bpf/btf.rst`_ - pahole version 1.16
|
discussed in Documentation/bpf/btf.rst - pahole version 1.16
|
||||||
is required for kernels built with CONFIG_DEBUG_INFO_BTF=y.
|
is required for kernels built with CONFIG_DEBUG_INFO_BTF=y.
|
||||||
pahole is delivered in the dwarves package or can be built
|
pahole is delivered in the dwarves package or can be built
|
||||||
from source at
|
from source at
|
||||||
@ -684,12 +684,8 @@ when:
|
|||||||
|
|
||||||
|
|
||||||
.. Links
|
.. Links
|
||||||
.. _Documentation/process/: https://www.kernel.org/doc/html/latest/process/
|
|
||||||
.. _netdev-FAQ: https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
|
.. _netdev-FAQ: https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
|
||||||
.. _selftests:
|
.. _selftests:
|
||||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/testing/selftests/bpf/
|
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/testing/selftests/bpf/
|
||||||
.. _Documentation/dev-tools/kselftest.rst:
|
|
||||||
https://www.kernel.org/doc/html/latest/dev-tools/kselftest.html
|
|
||||||
.. _Documentation/bpf/btf.rst: btf.rst
|
|
||||||
|
|
||||||
Happy BPF hacking!
|
Happy BPF hacking!
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
%YAML 1.2
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
$id: http://devicetree.org/schemas/power/supply/richtek,rt9467-charger.yaml#
|
$id: http://devicetree.org/schemas/power/supply/richtek,rt9467.yaml#
|
||||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
title: Richtek RT9467 Switching Battery Charger with Power Path Management
|
title: Richtek RT9467 Switching Battery Charger with Power Path Management
|
||||||
@ -25,7 +25,7 @@ description: |
|
|||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
const: richtek,rt9467-charger
|
const: richtek,rt9467
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
@ -65,7 +65,7 @@ examples:
|
|||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
|
||||||
charger@5b {
|
charger@5b {
|
||||||
compatible = "richtek,rt9467-charger";
|
compatible = "richtek,rt9467";
|
||||||
reg = <0x5b>;
|
reg = <0x5b>;
|
||||||
wakeup-source;
|
wakeup-source;
|
||||||
interrupts-extended = <&gpio_intc 32 IRQ_TYPE_LEVEL_LOW>;
|
interrupts-extended = <&gpio_intc 32 IRQ_TYPE_LEVEL_LOW>;
|
@ -0,0 +1,93 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/pwm/mediatek,mt2712-pwm.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: MediaTek PWM Controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- John Crispin <john@phrozen.org>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: pwm.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- enum:
|
||||||
|
- mediatek,mt2712-pwm
|
||||||
|
- mediatek,mt6795-pwm
|
||||||
|
- mediatek,mt7622-pwm
|
||||||
|
- mediatek,mt7623-pwm
|
||||||
|
- mediatek,mt7628-pwm
|
||||||
|
- mediatek,mt7629-pwm
|
||||||
|
- mediatek,mt8183-pwm
|
||||||
|
- mediatek,mt8365-pwm
|
||||||
|
- mediatek,mt8516-pwm
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- mediatek,mt8195-pwm
|
||||||
|
- const: mediatek,mt8183-pwm
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#pwm-cells":
|
||||||
|
const: 2
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
minItems: 2
|
||||||
|
maxItems: 10
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
description:
|
||||||
|
This controller needs two input clocks for its core and one
|
||||||
|
clock for each PWM output.
|
||||||
|
minItems: 2
|
||||||
|
items:
|
||||||
|
- const: top
|
||||||
|
- const: main
|
||||||
|
- const: pwm1
|
||||||
|
- const: pwm2
|
||||||
|
- const: pwm3
|
||||||
|
- const: pwm4
|
||||||
|
- const: pwm5
|
||||||
|
- const: pwm6
|
||||||
|
- const: pwm7
|
||||||
|
- const: pwm8
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#pwm-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
#include <dt-bindings/clock/mt2712-clk.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
pwm0: pwm@11006000 {
|
||||||
|
compatible = "mediatek,mt2712-pwm";
|
||||||
|
reg = <0x11006000 0x1000>;
|
||||||
|
#pwm-cells = <2>;
|
||||||
|
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
clocks = <&topckgen CLK_TOP_PWM_SEL>, <&pericfg CLK_PERI_PWM>,
|
||||||
|
<&pericfg CLK_PERI_PWM0>, <&pericfg CLK_PERI_PWM1>,
|
||||||
|
<&pericfg CLK_PERI_PWM2>, <&pericfg CLK_PERI_PWM3>,
|
||||||
|
<&pericfg CLK_PERI_PWM4>, <&pericfg CLK_PERI_PWM5>,
|
||||||
|
<&pericfg CLK_PERI_PWM6>, <&pericfg CLK_PERI_PWM7>;
|
||||||
|
clock-names = "top", "main",
|
||||||
|
"pwm1", "pwm2",
|
||||||
|
"pwm3", "pwm4",
|
||||||
|
"pwm5", "pwm6",
|
||||||
|
"pwm7", "pwm8";
|
||||||
|
};
|
@ -1,52 +0,0 @@
|
|||||||
MediaTek PWM controller
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: should be "mediatek,<name>-pwm":
|
|
||||||
- "mediatek,mt2712-pwm": found on mt2712 SoC.
|
|
||||||
- "mediatek,mt6795-pwm": found on mt6795 SoC.
|
|
||||||
- "mediatek,mt7622-pwm": found on mt7622 SoC.
|
|
||||||
- "mediatek,mt7623-pwm": found on mt7623 SoC.
|
|
||||||
- "mediatek,mt7628-pwm": found on mt7628 SoC.
|
|
||||||
- "mediatek,mt7629-pwm": found on mt7629 SoC.
|
|
||||||
- "mediatek,mt8183-pwm": found on mt8183 SoC.
|
|
||||||
- "mediatek,mt8195-pwm", "mediatek,mt8183-pwm": found on mt8195 SoC.
|
|
||||||
- "mediatek,mt8365-pwm": found on mt8365 SoC.
|
|
||||||
- "mediatek,mt8516-pwm": found on mt8516 SoC.
|
|
||||||
- reg: physical base address and length of the controller's registers.
|
|
||||||
- #pwm-cells: must be 2. See pwm.yaml in this directory for a description of
|
|
||||||
the cell format.
|
|
||||||
- clocks: phandle and clock specifier of the PWM reference clock.
|
|
||||||
- clock-names: must contain the following, except for MT7628 which
|
|
||||||
has no clocks
|
|
||||||
- "top": the top clock generator
|
|
||||||
- "main": clock used by the PWM core
|
|
||||||
- "pwm1-3": the three per PWM clocks for mt8365
|
|
||||||
- "pwm1-8": the eight per PWM clocks for mt2712
|
|
||||||
- "pwm1-6": the six per PWM clocks for mt7622
|
|
||||||
- "pwm1-5": the five per PWM clocks for mt7623
|
|
||||||
- "pwm1" : the PWM1 clock for mt7629
|
|
||||||
- pinctrl-names: Must contain a "default" entry.
|
|
||||||
- pinctrl-0: One property must exist for each entry in pinctrl-names.
|
|
||||||
See pinctrl/pinctrl-bindings.txt for details of the property values.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- assigned-clocks: Reference to the PWM clock entries.
|
|
||||||
- assigned-clock-parents: The phandle of the parent clock of PWM clock.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
pwm0: pwm@11006000 {
|
|
||||||
compatible = "mediatek,mt7623-pwm";
|
|
||||||
reg = <0 0x11006000 0 0x1000>;
|
|
||||||
#pwm-cells = <2>;
|
|
||||||
clocks = <&topckgen CLK_TOP_PWM_SEL>,
|
|
||||||
<&pericfg CLK_PERI_PWM>,
|
|
||||||
<&pericfg CLK_PERI_PWM1>,
|
|
||||||
<&pericfg CLK_PERI_PWM2>,
|
|
||||||
<&pericfg CLK_PERI_PWM3>,
|
|
||||||
<&pericfg CLK_PERI_PWM4>,
|
|
||||||
<&pericfg CLK_PERI_PWM5>;
|
|
||||||
clock-names = "top", "main", "pwm1", "pwm2",
|
|
||||||
"pwm3", "pwm4", "pwm5";
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&pwm0_pins>;
|
|
||||||
};
|
|
@ -0,0 +1,68 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
# Copyright (C) 2022 SiFive, Inc.
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/pwm/snps,dw-apb-timers-pwm2.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Synopsys DW-APB timers PWM controller
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Ben Dooks <ben.dooks@sifive.com>
|
||||||
|
|
||||||
|
description:
|
||||||
|
This describes the DesignWare APB timers module when used in the PWM
|
||||||
|
mode. The IP core can be generated with various options which can
|
||||||
|
control the functionality, the number of PWMs available and other
|
||||||
|
internal controls the designer requires.
|
||||||
|
|
||||||
|
The IP block has a version register so this can be used for detection
|
||||||
|
instead of having to encode the IP version number in the device tree
|
||||||
|
comaptible.
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: pwm.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: snps,dw-apb-timers-pwm2
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#pwm-cells":
|
||||||
|
const: 3
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
items:
|
||||||
|
- description: Interface bus clock
|
||||||
|
- description: PWM reference clock
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: bus
|
||||||
|
- const: timer
|
||||||
|
|
||||||
|
snps,pwm-number:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: The number of PWM channels configured for this instance
|
||||||
|
enum: [1, 2, 3, 4, 5, 6, 7, 8]
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- "#pwm-cells"
|
||||||
|
- clocks
|
||||||
|
- clock-names
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
pwm: pwm@180000 {
|
||||||
|
compatible = "snps,dw-apb-timers-pwm2";
|
||||||
|
reg = <0x180000 0x200>;
|
||||||
|
#pwm-cells = <3>;
|
||||||
|
clocks = <&bus>, <&timer>;
|
||||||
|
clock-names = "bus", "timer";
|
||||||
|
};
|
@ -0,0 +1,44 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/rtc/amlogic,meson-vrtc.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Amlogic Virtual RTC (VRTC)
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
This is a Linux interface to an RTC managed by firmware, hence it's
|
||||||
|
virtual from a Linux perspective. The interface is 1 register where
|
||||||
|
an alarm time (in seconds) is to be written.
|
||||||
|
The alarm register is a simple scratch register shared between the
|
||||||
|
application processors (AP) and the secure co-processor (SCP.) When
|
||||||
|
the AP suspends, the SCP will use the value of this register to
|
||||||
|
program an always-on timer before going sleep. When the timer expires,
|
||||||
|
the SCP will wake up and will then wake the AP.
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: rtc.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- amlogic,meson-vrtc
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
rtc@a8 {
|
||||||
|
compatible = "amlogic,meson-vrtc";
|
||||||
|
reg = <0x000a8 0x4>;
|
||||||
|
};
|
@ -11,7 +11,8 @@ maintainers:
|
|||||||
|
|
||||||
description:
|
description:
|
||||||
The Broadcom STB wake-up timer provides a 27Mhz resolution timer, with the
|
The Broadcom STB wake-up timer provides a 27Mhz resolution timer, with the
|
||||||
ability to wake up the system from low-power suspend/standby modes.
|
ability to wake up the system from low-power suspend/standby modes and
|
||||||
|
optionally generate RTC alarm interrupts.
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: "rtc.yaml#"
|
- $ref: "rtc.yaml#"
|
||||||
@ -24,8 +25,14 @@ properties:
|
|||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
interrupts:
|
interrupts:
|
||||||
description: the TIMER interrupt
|
minItems: 1
|
||||||
maxItems: 1
|
items:
|
||||||
|
- description: the TIMER interrupt
|
||||||
|
- description: the ALARM interrupt
|
||||||
|
description:
|
||||||
|
The TIMER interrupt wakes the system from low-power suspend/standby modes.
|
||||||
|
An ALARM interrupt may be specified to interrupt the CPU when an RTC alarm
|
||||||
|
is enabled.
|
||||||
|
|
||||||
clocks:
|
clocks:
|
||||||
description: clock reference in the 27MHz domain
|
description: clock reference in the 27MHz domain
|
||||||
@ -35,10 +42,10 @@ additionalProperties: false
|
|||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
rtc@f0411580 {
|
rtc@f041a080 {
|
||||||
compatible = "brcm,brcmstb-waketimer";
|
compatible = "brcm,brcmstb-waketimer";
|
||||||
reg = <0xf0411580 0x14>;
|
reg = <0xf041a080 0x14>;
|
||||||
interrupts = <0x3>;
|
interrupts-extended = <&aon_pm_l2_intc 0x04>,
|
||||||
interrupt-parent = <&aon_pm_l2_intc>;
|
<&upg_aux_aon_intr2_intc 0x08>;
|
||||||
clocks = <&upg_fixed>;
|
clocks = <&upg_fixed>;
|
||||||
};
|
};
|
||||||
|
@ -11,6 +11,17 @@ maintainers:
|
|||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: rtc.yaml#
|
- $ref: rtc.yaml#
|
||||||
|
- if:
|
||||||
|
not:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- ingenic,jz4770-rtc
|
||||||
|
- ingenic,jz4780-rtc
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
"#clock-cells": false
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
@ -39,6 +50,9 @@ properties:
|
|||||||
clock-names:
|
clock-names:
|
||||||
const: rtc
|
const: rtc
|
||||||
|
|
||||||
|
"#clock-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
system-power-controller:
|
system-power-controller:
|
||||||
description: |
|
description: |
|
||||||
Indicates that the RTC is responsible for powering OFF
|
Indicates that the RTC is responsible for powering OFF
|
||||||
@ -83,3 +97,18 @@ examples:
|
|||||||
clocks = <&cgu JZ4740_CLK_RTC>;
|
clocks = <&cgu JZ4740_CLK_RTC>;
|
||||||
clock-names = "rtc";
|
clock-names = "rtc";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/clock/ingenic,jz4780-cgu.h>
|
||||||
|
rtc: rtc@10003000 {
|
||||||
|
compatible = "ingenic,jz4780-rtc", "ingenic,jz4760-rtc";
|
||||||
|
reg = <0x10003000 0x4c>;
|
||||||
|
|
||||||
|
interrupt-parent = <&intc>;
|
||||||
|
interrupts = <32>;
|
||||||
|
|
||||||
|
clocks = <&cgu JZ4780_CLK_RTCLK>;
|
||||||
|
clock-names = "rtc";
|
||||||
|
|
||||||
|
#clock-cells = <0>;
|
||||||
|
};
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/rtc/microcrystal,rv3028.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Microchip RV-3028 RTC
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: rtc.yaml#
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: microcrystal,rv3028
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
trickle-resistor-ohms:
|
||||||
|
enum:
|
||||||
|
- 3000
|
||||||
|
- 5000
|
||||||
|
- 9000
|
||||||
|
- 15000
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
rtc@51 {
|
||||||
|
compatible = "microcrystal,rv3028";
|
||||||
|
reg = <0x51>;
|
||||||
|
pinctrl-0 = <&rtc_nint_pins>;
|
||||||
|
interrupts-extended = <&gpio1 16 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
trickle-resistor-ohms = <3000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
@ -3,15 +3,15 @@ MOXA ART real-time clock
|
|||||||
Required properties:
|
Required properties:
|
||||||
|
|
||||||
- compatible : Should be "moxa,moxart-rtc"
|
- compatible : Should be "moxa,moxart-rtc"
|
||||||
- gpio-rtc-sclk : RTC sclk gpio, with zero flags
|
- rtc-sclk-gpios : RTC sclk gpio, with zero flags
|
||||||
- gpio-rtc-data : RTC data gpio, with zero flags
|
- rtc-data-gpios : RTC data gpio, with zero flags
|
||||||
- gpio-rtc-reset : RTC reset gpio, with zero flags
|
- rtc-reset-gpios : RTC reset gpio, with zero flags
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
rtc: rtc {
|
rtc: rtc {
|
||||||
compatible = "moxa,moxart-rtc";
|
compatible = "moxa,moxart-rtc";
|
||||||
gpio-rtc-sclk = <&gpio 5 0>;
|
rtc-sclk-gpios = <&gpio 5 0>;
|
||||||
gpio-rtc-data = <&gpio 6 0>;
|
rtc-data-gpios = <&gpio 6 0>;
|
||||||
gpio-rtc-reset = <&gpio 7 0>;
|
rtc-reset-gpios = <&gpio 7 0>;
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,10 @@ maintainers:
|
|||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
const: nxp,pcf2127
|
enum:
|
||||||
|
- nxp,pca2129
|
||||||
|
- nxp,pcf2127
|
||||||
|
- nxp,pcf2129
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
60
Documentation/devicetree/bindings/rtc/nxp,pcf85363.yaml
Normal file
60
Documentation/devicetree/bindings/rtc/nxp,pcf85363.yaml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/rtc/nxp,pcf85363.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Philips PCF85263/PCF85363 Real Time Clock
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: rtc.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- nxp,pcf85263
|
||||||
|
- nxp,pcf85363
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#clock-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
clock-output-names:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
quartz-load-femtofarads:
|
||||||
|
description:
|
||||||
|
The capacitive load of the quartz(x-tal).
|
||||||
|
enum: [6000, 7000, 12500]
|
||||||
|
default: 7000
|
||||||
|
|
||||||
|
start-year: true
|
||||||
|
wakeup-source: true
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
rtc@51 {
|
||||||
|
compatible = "nxp,pcf85363";
|
||||||
|
reg = <0x51>;
|
||||||
|
#clock-cells = <0>;
|
||||||
|
quartz-load-femtofarads = <12500>;
|
||||||
|
};
|
||||||
|
};
|
@ -19,8 +19,6 @@ properties:
|
|||||||
- microcrystal,rv8564
|
- microcrystal,rv8564
|
||||||
- nxp,pca8565
|
- nxp,pca8565
|
||||||
- nxp,pcf8563
|
- nxp,pcf8563
|
||||||
- nxp,pcf85263
|
|
||||||
- nxp,pcf85363
|
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@ -40,6 +40,16 @@ properties:
|
|||||||
description:
|
description:
|
||||||
Indicates that the setting of RTC time is allowed by the host CPU.
|
Indicates that the setting of RTC time is allowed by the host CPU.
|
||||||
|
|
||||||
|
nvmem-cells:
|
||||||
|
items:
|
||||||
|
- description:
|
||||||
|
four-byte nvmem cell holding a little-endian offset from the Unix
|
||||||
|
epoch representing the time when the RTC timer was last reset
|
||||||
|
|
||||||
|
nvmem-cell-names:
|
||||||
|
items:
|
||||||
|
- const: offset
|
||||||
|
|
||||||
wakeup-source: true
|
wakeup-source: true
|
||||||
|
|
||||||
required:
|
required:
|
||||||
@ -69,6 +79,8 @@ examples:
|
|||||||
compatible = "qcom,pm8921-rtc";
|
compatible = "qcom,pm8921-rtc";
|
||||||
reg = <0x11d>;
|
reg = <0x11d>;
|
||||||
interrupts = <0x27 0>;
|
interrupts = <0x27 0>;
|
||||||
|
nvmem-cells = <&rtc_offset>;
|
||||||
|
nvmem-cell-names = "offset";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
* Amlogic Virtual RTC (VRTC)
|
|
||||||
|
|
||||||
This is a Linux interface to an RTC managed by firmware, hence it's
|
|
||||||
virtual from a Linux perspective. The interface is 1 register where
|
|
||||||
an alarm time (in seconds) is to be written.
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible: should be "amlogic,meson-vrtc"
|
|
||||||
- reg: physical address for the alarm register
|
|
||||||
|
|
||||||
The alarm register is a simple scratch register shared between the
|
|
||||||
application processors (AP) and the secure co-processor (SCP.) When
|
|
||||||
the AP suspends, the SCP will use the value of this register to
|
|
||||||
program an always-on timer before going sleep. When the timer expires,
|
|
||||||
the SCP will wake up and will then wake the AP.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
vrtc: rtc@0a8 {
|
|
||||||
compatible = "amlogic,meson-vrtc";
|
|
||||||
reg = <0x0 0x000a8 0x0 0x4>;
|
|
||||||
};
|
|
@ -47,14 +47,12 @@ properties:
|
|||||||
- isil,isl1218
|
- isil,isl1218
|
||||||
# Intersil ISL12022 Real-time Clock
|
# Intersil ISL12022 Real-time Clock
|
||||||
- isil,isl12022
|
- isil,isl12022
|
||||||
# Real Time Clock Module with I2C-Bus
|
# Loongson-2K Socs/LS7A bridge Real-time Clock
|
||||||
- microcrystal,rv3028
|
- loongson,ls2x-rtc
|
||||||
# Real Time Clock Module with I2C-Bus
|
# Real Time Clock Module with I2C-Bus
|
||||||
- microcrystal,rv3029
|
- microcrystal,rv3029
|
||||||
# Real Time Clock
|
# Real Time Clock
|
||||||
- microcrystal,rv8523
|
- microcrystal,rv8523
|
||||||
- nxp,pca2129
|
|
||||||
- nxp,pcf2129
|
|
||||||
# Real-time Clock Module
|
# Real-time Clock Module
|
||||||
- pericom,pt7c4338
|
- pericom,pt7c4338
|
||||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||||
|
@ -23,6 +23,7 @@ properties:
|
|||||||
- enum:
|
- enum:
|
||||||
- apple,t6000-mca
|
- apple,t6000-mca
|
||||||
- apple,t8103-mca
|
- apple,t8103-mca
|
||||||
|
- apple,t8112-mca
|
||||||
- const: apple,mca
|
- const: apple,mca
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
|
@ -67,6 +67,12 @@ properties:
|
|||||||
maxItems: 4
|
maxItems: 4
|
||||||
uniqueItems: true
|
uniqueItems: true
|
||||||
|
|
||||||
|
microchip,startup-delay-us:
|
||||||
|
description: |
|
||||||
|
Specifies the delay in microseconds that needs to be applied after
|
||||||
|
enabling the PDMC microphones to avoid unwanted noise due to microphones
|
||||||
|
not being ready.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
* MSM Timer
|
|
||||||
|
|
||||||
Properties:
|
|
||||||
|
|
||||||
- compatible : Should at least contain "qcom,msm-timer". More specific
|
|
||||||
properties specify which subsystem the timers are paired with.
|
|
||||||
|
|
||||||
"qcom,kpss-timer" - krait subsystem
|
|
||||||
"qcom,scss-timer" - scorpion subsystem
|
|
||||||
|
|
||||||
- interrupts : Interrupts for the debug timer, the first general purpose
|
|
||||||
timer, and optionally a second general purpose timer, and
|
|
||||||
optionally as well, 2 watchdog interrupts, in that order.
|
|
||||||
|
|
||||||
- reg : Specifies the base address of the timer registers.
|
|
||||||
|
|
||||||
- clocks: Reference to the parent clocks, one per output clock. The parents
|
|
||||||
must appear in the same order as the clock names.
|
|
||||||
|
|
||||||
- clock-names: The name of the clocks as free-form strings. They should be in
|
|
||||||
the same order as the clocks.
|
|
||||||
|
|
||||||
- clock-frequency : The frequency of the debug timer and the general purpose
|
|
||||||
timer(s) in Hz in that order.
|
|
||||||
|
|
||||||
Optional:
|
|
||||||
|
|
||||||
- cpu-offset : per-cpu offset used when the timer is accessed without the
|
|
||||||
CPU remapping facilities. The offset is
|
|
||||||
cpu-offset + (0x10000 * cpu-nr).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
timer@200a000 {
|
|
||||||
compatible = "qcom,scss-timer", "qcom,msm-timer";
|
|
||||||
interrupts = <1 1 0x301>,
|
|
||||||
<1 2 0x301>,
|
|
||||||
<1 3 0x301>,
|
|
||||||
<1 4 0x301>,
|
|
||||||
<1 5 0x301>;
|
|
||||||
reg = <0x0200a000 0x100>;
|
|
||||||
clock-frequency = <19200000>,
|
|
||||||
<32768>;
|
|
||||||
clocks = <&sleep_clk>;
|
|
||||||
clock-names = "sleep";
|
|
||||||
cpu-offset = <0x40000>;
|
|
||||||
};
|
|
@ -0,0 +1,50 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/watchdog/amlogic,meson6-wdt.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Amlogic Meson6 SoCs Watchdog timer
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||||
|
- Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: watchdog.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
oneOf:
|
||||||
|
- enum:
|
||||||
|
- amlogic,meson6-wdt
|
||||||
|
- amlogic,meson8-wdt
|
||||||
|
- amlogic,meson8b-wdt
|
||||||
|
- items:
|
||||||
|
- const: amlogic,meson8m2-wdt
|
||||||
|
- const: amlogic,meson8b-wdt
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- interrupts
|
||||||
|
- reg
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
wdt: watchdog@c1109900 {
|
||||||
|
compatible = "amlogic,meson6-wdt";
|
||||||
|
reg = <0xc1109900 0x8>;
|
||||||
|
interrupts = <GIC_SPI 0 IRQ_TYPE_EDGE_RISING>;
|
||||||
|
timeout-sec = <10>;
|
||||||
|
};
|
@ -9,9 +9,6 @@ title: Freescale i.MX Watchdog Timer (WDT) Controller
|
|||||||
maintainers:
|
maintainers:
|
||||||
- Anson Huang <Anson.Huang@nxp.com>
|
- Anson Huang <Anson.Huang@nxp.com>
|
||||||
|
|
||||||
allOf:
|
|
||||||
- $ref: "watchdog.yaml#"
|
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
oneOf:
|
oneOf:
|
||||||
@ -55,11 +52,45 @@ properties:
|
|||||||
If present, the watchdog device is configured to assert its
|
If present, the watchdog device is configured to assert its
|
||||||
external reset (WDOG_B) instead of issuing a software reset.
|
external reset (WDOG_B) instead of issuing a software reset.
|
||||||
|
|
||||||
|
fsl,suspend-in-wait:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description: |
|
||||||
|
If present, the watchdog device is suspended in WAIT mode
|
||||||
|
(Suspend-to-Idle). Only supported on certain devices.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- interrupts
|
- interrupts
|
||||||
- reg
|
- reg
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: watchdog.yaml#
|
||||||
|
- if:
|
||||||
|
not:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- fsl,imx25-wdt
|
||||||
|
- fsl,imx35-wdt
|
||||||
|
- fsl,imx50-wdt
|
||||||
|
- fsl,imx51-wdt
|
||||||
|
- fsl,imx53-wdt
|
||||||
|
- fsl,imx6q-wdt
|
||||||
|
- fsl,imx6sl-wdt
|
||||||
|
- fsl,imx6sll-wdt
|
||||||
|
- fsl,imx6sx-wdt
|
||||||
|
- fsl,imx6ul-wdt
|
||||||
|
- fsl,imx7d-wdt
|
||||||
|
- fsl,imx8mm-wdt
|
||||||
|
- fsl,imx8mn-wdt
|
||||||
|
- fsl,imx8mp-wdt
|
||||||
|
- fsl,imx8mq-wdt
|
||||||
|
- fsl,vf610-wdt
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
fsl,suspend-in-wait: false
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
|
55
Documentation/devicetree/bindings/watchdog/gpio-wdt.yaml
Normal file
55
Documentation/devicetree/bindings/watchdog/gpio-wdt.yaml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/watchdog/gpio-wdt.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: GPIO controlled watchdog
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Robert Marko <robert.marko@sartura.hr>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: linux,wdt-gpio
|
||||||
|
|
||||||
|
gpios:
|
||||||
|
maxItems: 1
|
||||||
|
description: GPIO connected to the WDT reset pin
|
||||||
|
|
||||||
|
hw_algo:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/string
|
||||||
|
description: Algorithm used by the driver
|
||||||
|
oneOf:
|
||||||
|
- description:
|
||||||
|
Either a high-to-low or a low-to-high transition clears the WDT counter.
|
||||||
|
The watchdog timer is disabled when GPIO is left floating or connected
|
||||||
|
to a three-state buffer.
|
||||||
|
const: toggle
|
||||||
|
- description:
|
||||||
|
Low or high level starts counting WDT timeout, the opposite level
|
||||||
|
disables the WDT.
|
||||||
|
Active level is determined by the GPIO flags.
|
||||||
|
const: level
|
||||||
|
|
||||||
|
hw_margin_ms:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: Maximum time to reset watchdog circuit (in milliseconds)
|
||||||
|
minimum: 2
|
||||||
|
maximum: 65535
|
||||||
|
|
||||||
|
always-running:
|
||||||
|
type: boolean
|
||||||
|
description:
|
||||||
|
If the watchdog timer cannot be disabled, add this flag to have the driver
|
||||||
|
keep toggling the signal without a client.
|
||||||
|
It will only cease to toggle the signal when the device is open and the
|
||||||
|
timeout elapsed.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- gpios
|
||||||
|
- hw_algo
|
||||||
|
- hw_margin_ms
|
||||||
|
|
||||||
|
unevaluatedProperties: false
|
@ -19,6 +19,12 @@ properties:
|
|||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
mediatek,sysctl:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description:
|
||||||
|
phandle to system controller 'sysc' syscon node which
|
||||||
|
controls system registers
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
@ -30,4 +36,5 @@ examples:
|
|||||||
watchdog@100 {
|
watchdog@100 {
|
||||||
compatible = "mediatek,mt7621-wdt";
|
compatible = "mediatek,mt7621-wdt";
|
||||||
reg = <0x100 0x100>;
|
reg = <0x100 0x100>;
|
||||||
|
mediatek,sysctl = <&sysc>;
|
||||||
};
|
};
|
||||||
|
@ -52,6 +52,12 @@ properties:
|
|||||||
description: Disable sending output reset signal
|
description: Disable sending output reset signal
|
||||||
type: boolean
|
type: boolean
|
||||||
|
|
||||||
|
mediatek,reset-by-toprgu:
|
||||||
|
description: The Top Reset Generation Unit (TOPRGU) generates reset signals
|
||||||
|
and distributes them to each IP. If present, the watchdog timer will be
|
||||||
|
reset by TOPRGU once system resets.
|
||||||
|
type: boolean
|
||||||
|
|
||||||
'#reset-cells':
|
'#reset-cells':
|
||||||
const: 1
|
const: 1
|
||||||
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
Meson SoCs Watchdog timer
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible : depending on the SoC this should be one of:
|
|
||||||
"amlogic,meson6-wdt" on Meson6 SoCs
|
|
||||||
"amlogic,meson8-wdt" and "amlogic,meson6-wdt" on Meson8 SoCs
|
|
||||||
"amlogic,meson8b-wdt" on Meson8b SoCs
|
|
||||||
"amlogic,meson8m2-wdt" and "amlogic,meson8b-wdt" on Meson8m2 SoCs
|
|
||||||
- reg : Specifies base physical address and size of the registers.
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- timeout-sec: contains the watchdog timeout in seconds.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
wdt: watchdog@c1109900 {
|
|
||||||
compatible = "amlogic,meson6-wdt";
|
|
||||||
reg = <0xc1109900 0x8>;
|
|
||||||
timeout-sec = <10>;
|
|
||||||
};
|
|
@ -9,15 +9,18 @@ title: Qualcomm Krait Processor Sub-system (KPSS) Watchdog timer
|
|||||||
maintainers:
|
maintainers:
|
||||||
- Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
|
- Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
|
||||||
|
|
||||||
allOf:
|
|
||||||
- $ref: watchdog.yaml#
|
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: "^(watchdog|timer)@[0-9a-f]+$"
|
||||||
|
|
||||||
compatible:
|
compatible:
|
||||||
oneOf:
|
oneOf:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
- qcom,kpss-wdt-ipq4019
|
||||||
|
- qcom,apss-wdt-msm8994
|
||||||
- qcom,apss-wdt-qcs404
|
- qcom,apss-wdt-qcs404
|
||||||
|
- qcom,apss-wdt-sa8775p
|
||||||
- qcom,apss-wdt-sc7180
|
- qcom,apss-wdt-sc7180
|
||||||
- qcom,apss-wdt-sc7280
|
- qcom,apss-wdt-sc7280
|
||||||
- qcom,apss-wdt-sc8180x
|
- qcom,apss-wdt-sc8180x
|
||||||
@ -29,15 +32,19 @@ properties:
|
|||||||
- qcom,apss-wdt-sm8150
|
- qcom,apss-wdt-sm8150
|
||||||
- qcom,apss-wdt-sm8250
|
- qcom,apss-wdt-sm8250
|
||||||
- const: qcom,kpss-wdt
|
- const: qcom,kpss-wdt
|
||||||
|
- const: qcom,kpss-wdt
|
||||||
|
deprecated: true
|
||||||
|
- items:
|
||||||
|
- const: qcom,scss-timer
|
||||||
|
- const: qcom,msm-timer
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- qcom,kpss-wdt
|
|
||||||
- qcom,kpss-timer
|
|
||||||
- qcom,kpss-wdt-apq8064
|
- qcom,kpss-wdt-apq8064
|
||||||
- qcom,kpss-wdt-ipq4019
|
|
||||||
- qcom,kpss-wdt-ipq8064
|
- qcom,kpss-wdt-ipq8064
|
||||||
|
- qcom,kpss-wdt-mdm9615
|
||||||
- qcom,kpss-wdt-msm8960
|
- qcom,kpss-wdt-msm8960
|
||||||
- qcom,scss-timer
|
- const: qcom,kpss-timer
|
||||||
|
- const: qcom,msm-timer
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
@ -45,18 +52,87 @@ properties:
|
|||||||
clocks:
|
clocks:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
items:
|
||||||
|
- const: sleep
|
||||||
|
|
||||||
|
clock-frequency:
|
||||||
|
description:
|
||||||
|
The frequency of the general purpose timer in Hz.
|
||||||
|
|
||||||
|
cpu-offset:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description:
|
||||||
|
Per-CPU offset used when the timer is accessed without the CPU remapping
|
||||||
|
facilities. The offset is cpu-offset + (0x10000 * cpu-nr).
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 5
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
- clocks
|
- clocks
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: watchdog.yaml#
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
const: qcom,kpss-wdt
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
clock-frequency: false
|
||||||
|
cpu-offset: false
|
||||||
|
interrupts:
|
||||||
|
minItems: 1
|
||||||
|
items:
|
||||||
|
- description: Bark
|
||||||
|
- description: Bite
|
||||||
|
|
||||||
|
else:
|
||||||
|
properties:
|
||||||
|
interrupts:
|
||||||
|
minItems: 3
|
||||||
|
items:
|
||||||
|
- description: Debug
|
||||||
|
- description: First general purpose timer
|
||||||
|
- description: Second general purpose timer
|
||||||
|
- description: First watchdog
|
||||||
|
- description: Second watchdog
|
||||||
|
required:
|
||||||
|
- clock-frequency
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
watchdog@208a038 {
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
compatible = "qcom,kpss-wdt-ipq8064";
|
|
||||||
reg = <0x0208a038 0x40>;
|
watchdog@17c10000 {
|
||||||
|
compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt";
|
||||||
|
reg = <0x17c10000 0x1000>;
|
||||||
clocks = <&sleep_clk>;
|
clocks = <&sleep_clk>;
|
||||||
|
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
timeout-sec = <10>;
|
timeout-sec = <10>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
watchdog@200a000 {
|
||||||
|
compatible = "qcom,kpss-wdt-ipq8064", "qcom,kpss-timer", "qcom,msm-timer";
|
||||||
|
interrupts = <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
|
||||||
|
<GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
|
||||||
|
<GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
|
||||||
|
<GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
|
||||||
|
<GIC_PPI 5 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>;
|
||||||
|
reg = <0x0200a000 0x100>;
|
||||||
|
clock-frequency = <25000000>;
|
||||||
|
clocks = <&sleep_clk>;
|
||||||
|
clock-names = "sleep";
|
||||||
|
cpu-offset = <0x80000>;
|
||||||
|
};
|
||||||
|
@ -26,7 +26,7 @@ properties:
|
|||||||
|
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- renesas,r9a07g043-wdt # RZ/G2UL
|
- renesas,r9a07g043-wdt # RZ/G2UL and RZ/Five
|
||||||
- renesas,r9a07g044-wdt # RZ/G2{L,LC}
|
- renesas,r9a07g044-wdt # RZ/G2{L,LC}
|
||||||
- renesas,r9a07g054-wdt # RZ/V2L
|
- renesas,r9a07g054-wdt # RZ/V2L
|
||||||
- const: renesas,rzg2l-wdt
|
- const: renesas,rzg2l-wdt
|
||||||
|
@ -14,9 +14,14 @@ description: |
|
|||||||
This document describes generic bindings which can be used to
|
This document describes generic bindings which can be used to
|
||||||
describe watchdog devices in a device tree.
|
describe watchdog devices in a device tree.
|
||||||
|
|
||||||
|
select:
|
||||||
|
properties:
|
||||||
|
$nodename:
|
||||||
|
pattern: "^watchdog(@.*|-[0-9a-f])?$"
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
$nodename:
|
$nodename:
|
||||||
pattern: "^watchdog(@.*|-[0-9a-f])?$"
|
pattern: "^(timer|watchdog)(@.*|-[0-9a-f])?$"
|
||||||
|
|
||||||
timeout-sec:
|
timeout-sec:
|
||||||
description:
|
description:
|
||||||
|
@ -158,7 +158,7 @@ nobarrier This option can be used if underlying storage guarantees
|
|||||||
If this option is set, no cache_flush commands are issued
|
If this option is set, no cache_flush commands are issued
|
||||||
but f2fs still guarantees the write ordering of all the
|
but f2fs still guarantees the write ordering of all the
|
||||||
data writes.
|
data writes.
|
||||||
barrier If this option is set, cache_flush commands are allowed to be
|
barrier If this option is set, cache_flush commands are allowed to be
|
||||||
issued.
|
issued.
|
||||||
fastboot This option is used when a system wants to reduce mount
|
fastboot This option is used when a system wants to reduce mount
|
||||||
time as much as possible, even though normal performance
|
time as much as possible, even though normal performance
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
.. _linux_doc:
|
.. _linux_doc:
|
||||||
|
|
||||||
|
==============================
|
||||||
The Linux Kernel documentation
|
The Linux Kernel documentation
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ documentation are welcome; join the linux-doc list at vger.kernel.org if
|
|||||||
you want to help out.
|
you want to help out.
|
||||||
|
|
||||||
Working with the development community
|
Working with the development community
|
||||||
--------------------------------------
|
======================================
|
||||||
|
|
||||||
The essential guides for interacting with the kernel's development
|
The essential guides for interacting with the kernel's development
|
||||||
community and getting your work upstream.
|
community and getting your work upstream.
|
||||||
@ -29,7 +30,7 @@ community and getting your work upstream.
|
|||||||
|
|
||||||
|
|
||||||
Internal API manuals
|
Internal API manuals
|
||||||
--------------------
|
====================
|
||||||
|
|
||||||
Manuals for use by developers working to interface with the rest of the
|
Manuals for use by developers working to interface with the rest of the
|
||||||
kernel.
|
kernel.
|
||||||
@ -43,7 +44,7 @@ kernel.
|
|||||||
Locking in the kernel <locking/index>
|
Locking in the kernel <locking/index>
|
||||||
|
|
||||||
Development tools and processes
|
Development tools and processes
|
||||||
-------------------------------
|
===============================
|
||||||
|
|
||||||
Various other manuals with useful information for all kernel developers.
|
Various other manuals with useful information for all kernel developers.
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ Various other manuals with useful information for all kernel developers.
|
|||||||
|
|
||||||
|
|
||||||
User-oriented documentation
|
User-oriented documentation
|
||||||
---------------------------
|
===========================
|
||||||
|
|
||||||
The following manuals are written for *users* of the kernel — those who are
|
The following manuals are written for *users* of the kernel — those who are
|
||||||
trying to get it to work optimally on a given system and application
|
trying to get it to work optimally on a given system and application
|
||||||
@ -81,7 +82,7 @@ See also: the `Linux man pages <https://www.kernel.org/doc/man-pages/>`_,
|
|||||||
which are kept separately from the kernel's own documentation.
|
which are kept separately from the kernel's own documentation.
|
||||||
|
|
||||||
Firmware-related documentation
|
Firmware-related documentation
|
||||||
------------------------------
|
==============================
|
||||||
The following holds information on the kernel's expectations regarding the
|
The following holds information on the kernel's expectations regarding the
|
||||||
platform firmwares.
|
platform firmwares.
|
||||||
|
|
||||||
@ -93,7 +94,7 @@ platform firmwares.
|
|||||||
|
|
||||||
|
|
||||||
Architecture-specific documentation
|
Architecture-specific documentation
|
||||||
-----------------------------------
|
===================================
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
@ -102,7 +103,7 @@ Architecture-specific documentation
|
|||||||
|
|
||||||
|
|
||||||
Other documentation
|
Other documentation
|
||||||
-------------------
|
===================
|
||||||
|
|
||||||
There are several unsorted documents that don't seem to fit on other parts
|
There are several unsorted documents that don't seem to fit on other parts
|
||||||
of the documentation body, or may require some adjustments and/or conversion
|
of the documentation body, or may require some adjustments and/or conversion
|
||||||
@ -115,7 +116,7 @@ to ReStructured Text format, or are simply too old.
|
|||||||
|
|
||||||
|
|
||||||
Translations
|
Translations
|
||||||
------------
|
============
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
@ -5,7 +5,7 @@ Kernel Lock Torture Test Operation
|
|||||||
CONFIG_LOCK_TORTURE_TEST
|
CONFIG_LOCK_TORTURE_TEST
|
||||||
========================
|
========================
|
||||||
|
|
||||||
The CONFIG LOCK_TORTURE_TEST config option provides a kernel module
|
The CONFIG_LOCK_TORTURE_TEST config option provides a kernel module
|
||||||
that runs torture tests on core kernel locking primitives. The kernel
|
that runs torture tests on core kernel locking primitives. The kernel
|
||||||
module, 'locktorture', may be built after the fact on the running
|
module, 'locktorture', may be built after the fact on the running
|
||||||
kernel to be tested, if desired. The tests periodically output status
|
kernel to be tested, if desired. The tests periodically output status
|
||||||
@ -67,7 +67,7 @@ torture_type
|
|||||||
|
|
||||||
- "rtmutex_lock":
|
- "rtmutex_lock":
|
||||||
rtmutex_lock() and rtmutex_unlock() pairs.
|
rtmutex_lock() and rtmutex_unlock() pairs.
|
||||||
Kernel must have CONFIG_RT_MUTEX=y.
|
Kernel must have CONFIG_RT_MUTEXES=y.
|
||||||
|
|
||||||
- "rwsem_lock":
|
- "rwsem_lock":
|
||||||
read/write down() and up() semaphore pairs.
|
read/write down() and up() semaphore pairs.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
%YAML 1.2
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
$id: http://kernel.org/schemas/netlink/genetlink-c.yaml#
|
$id: http://kernel.org/schemas/netlink/genetlink-c.yaml#
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
%YAML 1.2
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
$id: http://kernel.org/schemas/netlink/genetlink-legacy.yaml#
|
$id: http://kernel.org/schemas/netlink/genetlink-legacy.yaml#
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
%YAML 1.2
|
%YAML 1.2
|
||||||
---
|
---
|
||||||
$id: http://kernel.org/schemas/netlink/genetlink-legacy.yaml#
|
$id: http://kernel.org/schemas/netlink/genetlink-legacy.yaml#
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
|
||||||
name: ethtool
|
name: ethtool
|
||||||
|
|
||||||
protocol: genetlink-legacy
|
protocol: genetlink-legacy
|
||||||
@ -11,7 +13,6 @@ attribute-sets:
|
|||||||
-
|
-
|
||||||
name: dev-index
|
name: dev-index
|
||||||
type: u32
|
type: u32
|
||||||
value: 1
|
|
||||||
-
|
-
|
||||||
name: dev-name
|
name: dev-name
|
||||||
type: string
|
type: string
|
||||||
@ -25,7 +26,6 @@ attribute-sets:
|
|||||||
-
|
-
|
||||||
name: index
|
name: index
|
||||||
type: u32
|
type: u32
|
||||||
value: 1
|
|
||||||
-
|
-
|
||||||
name: name
|
name: name
|
||||||
type: string
|
type: string
|
||||||
@ -39,14 +39,12 @@ attribute-sets:
|
|||||||
name: bit
|
name: bit
|
||||||
type: nest
|
type: nest
|
||||||
nested-attributes: bitset-bit
|
nested-attributes: bitset-bit
|
||||||
value: 1
|
|
||||||
-
|
-
|
||||||
name: bitset
|
name: bitset
|
||||||
attributes:
|
attributes:
|
||||||
-
|
-
|
||||||
name: nomask
|
name: nomask
|
||||||
type: flag
|
type: flag
|
||||||
value: 1
|
|
||||||
-
|
-
|
||||||
name: size
|
name: size
|
||||||
type: u32
|
type: u32
|
||||||
@ -61,7 +59,6 @@ attribute-sets:
|
|||||||
-
|
-
|
||||||
name: index
|
name: index
|
||||||
type: u32
|
type: u32
|
||||||
value: 1
|
|
||||||
-
|
-
|
||||||
name: value
|
name: value
|
||||||
type: string
|
type: string
|
||||||
@ -71,7 +68,6 @@ attribute-sets:
|
|||||||
-
|
-
|
||||||
name: string
|
name: string
|
||||||
type: nest
|
type: nest
|
||||||
value: 1
|
|
||||||
multi-attr: true
|
multi-attr: true
|
||||||
nested-attributes: string
|
nested-attributes: string
|
||||||
-
|
-
|
||||||
@ -80,7 +76,6 @@ attribute-sets:
|
|||||||
-
|
-
|
||||||
name: id
|
name: id
|
||||||
type: u32
|
type: u32
|
||||||
value: 1
|
|
||||||
-
|
-
|
||||||
name: count
|
name: count
|
||||||
type: u32
|
type: u32
|
||||||
@ -96,14 +91,12 @@ attribute-sets:
|
|||||||
name: stringset
|
name: stringset
|
||||||
type: nest
|
type: nest
|
||||||
multi-attr: true
|
multi-attr: true
|
||||||
value: 1
|
|
||||||
nested-attributes: stringset
|
nested-attributes: stringset
|
||||||
-
|
-
|
||||||
name: strset
|
name: strset
|
||||||
attributes:
|
attributes:
|
||||||
-
|
-
|
||||||
name: header
|
name: header
|
||||||
value: 1
|
|
||||||
type: nest
|
type: nest
|
||||||
nested-attributes: header
|
nested-attributes: header
|
||||||
-
|
-
|
||||||
@ -119,7 +112,6 @@ attribute-sets:
|
|||||||
attributes:
|
attributes:
|
||||||
-
|
-
|
||||||
name: header
|
name: header
|
||||||
value: 1
|
|
||||||
type: nest
|
type: nest
|
||||||
nested-attributes: header
|
nested-attributes: header
|
||||||
-
|
-
|
||||||
@ -132,7 +124,6 @@ attribute-sets:
|
|||||||
attributes:
|
attributes:
|
||||||
-
|
-
|
||||||
name: header
|
name: header
|
||||||
value: 1
|
|
||||||
type: nest
|
type: nest
|
||||||
nested-attributes: header
|
nested-attributes: header
|
||||||
-
|
-
|
||||||
@ -180,7 +171,6 @@ attribute-sets:
|
|||||||
attributes:
|
attributes:
|
||||||
-
|
-
|
||||||
name: pad
|
name: pad
|
||||||
value: 1
|
|
||||||
type: pad
|
type: pad
|
||||||
-
|
-
|
||||||
name: reassembly-errors
|
name: reassembly-errors
|
||||||
@ -205,7 +195,6 @@ attribute-sets:
|
|||||||
attributes:
|
attributes:
|
||||||
-
|
-
|
||||||
name: header
|
name: header
|
||||||
value: 1
|
|
||||||
type: nest
|
type: nest
|
||||||
nested-attributes: header
|
nested-attributes: header
|
||||||
-
|
-
|
||||||
@ -251,13 +240,11 @@ operations:
|
|||||||
|
|
||||||
do: &strset-get-op
|
do: &strset-get-op
|
||||||
request:
|
request:
|
||||||
value: 1
|
|
||||||
attributes:
|
attributes:
|
||||||
- header
|
- header
|
||||||
- stringsets
|
- stringsets
|
||||||
- counts-only
|
- counts-only
|
||||||
reply:
|
reply:
|
||||||
value: 1
|
|
||||||
attributes:
|
attributes:
|
||||||
- header
|
- header
|
||||||
- stringsets
|
- stringsets
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
|
||||||
name: fou
|
name: fou
|
||||||
|
|
||||||
protocol: genetlink-legacy
|
protocol: genetlink-legacy
|
||||||
@ -26,6 +28,7 @@ attribute-sets:
|
|||||||
-
|
-
|
||||||
name: unspec
|
name: unspec
|
||||||
type: unused
|
type: unused
|
||||||
|
value: 0
|
||||||
-
|
-
|
||||||
name: port
|
name: port
|
||||||
type: u16
|
type: u16
|
||||||
@ -71,6 +74,7 @@ operations:
|
|||||||
-
|
-
|
||||||
name: unspec
|
name: unspec
|
||||||
doc: unused
|
doc: unused
|
||||||
|
value: 0
|
||||||
|
|
||||||
-
|
-
|
||||||
name: add
|
name: add
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||||
|
|
||||||
name: netdev
|
name: netdev
|
||||||
|
|
||||||
doc:
|
doc:
|
||||||
@ -48,7 +50,6 @@ attribute-sets:
|
|||||||
name: ifindex
|
name: ifindex
|
||||||
doc: netdev ifindex
|
doc: netdev ifindex
|
||||||
type: u32
|
type: u32
|
||||||
value: 1
|
|
||||||
checks:
|
checks:
|
||||||
min: 1
|
min: 1
|
||||||
-
|
-
|
||||||
@ -66,7 +67,6 @@ operations:
|
|||||||
-
|
-
|
||||||
name: dev-get
|
name: dev-get
|
||||||
doc: Get / dump information about a netdev.
|
doc: Get / dump information about a netdev.
|
||||||
value: 1
|
|
||||||
attribute-set: dev
|
attribute-set: dev
|
||||||
do:
|
do:
|
||||||
request:
|
request:
|
||||||
|
@ -251,7 +251,8 @@ The tags in common use are:
|
|||||||
- Reported-by: names a user who reported a problem which is fixed by this
|
- Reported-by: names a user who reported a problem which is fixed by this
|
||||||
patch; this tag is used to give credit to the (often underappreciated)
|
patch; this tag is used to give credit to the (often underappreciated)
|
||||||
people who test our code and let us know when things do not work
|
people who test our code and let us know when things do not work
|
||||||
correctly.
|
correctly. Note, this tag should be followed by a Link: tag pointing to the
|
||||||
|
report, unless the report is not available on the web.
|
||||||
|
|
||||||
- Cc: the named person received a copy of the patch and had the
|
- Cc: the named person received a copy of the patch and had the
|
||||||
opportunity to comment on it.
|
opportunity to comment on it.
|
||||||
|
@ -496,10 +496,11 @@ Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes:
|
|||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
The Reported-by tag gives credit to people who find bugs and report them and it
|
The Reported-by tag gives credit to people who find bugs and report them and it
|
||||||
hopefully inspires them to help us again in the future. Please note that if
|
hopefully inspires them to help us again in the future. The tag is intended for
|
||||||
the bug was reported in private, then ask for permission first before using the
|
bugs; please do not use it to credit feature requests. The tag should be
|
||||||
Reported-by tag. The tag is intended for bugs; please do not use it to credit
|
followed by a Link: tag pointing to the report, unless the report is not
|
||||||
feature requests.
|
available on the web. Please note that if the bug was reported in private, then
|
||||||
|
ask for permission first before using the Reported-by tag.
|
||||||
|
|
||||||
A Tested-by: tag indicates that the patch has been successfully tested (in
|
A Tested-by: tag indicates that the patch has been successfully tested (in
|
||||||
some environment) by the person named. This tag informs maintainers that
|
some environment) by the person named. This tag informs maintainers that
|
||||||
|
@ -16,4 +16,6 @@ support corresponds to ``S`` values in the ``MAINTAINERS`` file.
|
|||||||
Architecture Level of support Constraints
|
Architecture Level of support Constraints
|
||||||
============ ================ ==============================================
|
============ ================ ==============================================
|
||||||
``x86`` Maintained ``x86_64`` only.
|
``x86`` Maintained ``x86_64`` only.
|
||||||
|
``um`` Maintained ``x86_64`` only.
|
||||||
============ ================ ==============================================
|
============ ================ ==============================================
|
||||||
|
|
||||||
|
@ -17,3 +17,4 @@
|
|||||||
kernel-enforcement-statement
|
kernel-enforcement-statement
|
||||||
email-clients
|
email-clients
|
||||||
magic-number
|
magic-number
|
||||||
|
programming-language
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
.. include:: ../disclaimer-sp.rst
|
||||||
|
|
||||||
|
:Original: :ref:`Documentation/process/programming-language.rst <programming_language>`
|
||||||
|
:Translator: Carlos Bilbao <carlos.bilbao@amd.com>
|
||||||
|
|
||||||
|
.. _sp_programming_language:
|
||||||
|
|
||||||
|
Lenguaje de programación
|
||||||
|
========================
|
||||||
|
|
||||||
|
El kernel está escrito en el lenguaje de programación C [sp-c-language]_.
|
||||||
|
Más concretamente, el kernel normalmente se compila con ``gcc`` [sp-gcc]_
|
||||||
|
bajo ``-std=gnu11`` [sp-gcc-c-dialect-options]_: el dialecto GNU de ISO C11.
|
||||||
|
``clang`` [sp-clang]_ también es compatible, consulte los documentos en
|
||||||
|
:ref:`Building Linux with Clang/LLVM <kbuild_llvm>`.
|
||||||
|
|
||||||
|
Este dialecto contiene muchas extensiones del lenguaje [sp-gnu-extensions]_,
|
||||||
|
y muchos de ellos se usan dentro del kernel de forma habitual.
|
||||||
|
|
||||||
|
Hay algo de soporte para compilar el núcleo con ``icc`` [sp-icc]_ para varias
|
||||||
|
de las arquitecturas, aunque en el momento de escribir este texto, eso no
|
||||||
|
está terminado y requiere parches de terceros.
|
||||||
|
|
||||||
|
Atributos
|
||||||
|
---------
|
||||||
|
|
||||||
|
Una de las comunes extensiones utilizadas en todo el kernel son los atributos
|
||||||
|
[sp-gcc-attribute-syntax]_. Los atributos permiten introducir semántica
|
||||||
|
definida por la implementación a las entidades del lenguaje (como variables,
|
||||||
|
funciones o tipos) sin tener que hacer cambios sintácticos significativos
|
||||||
|
al idioma (por ejemplo, agregar una nueva palabra clave) [sp-n2049]_.
|
||||||
|
|
||||||
|
En algunos casos, los atributos son opcionales (es decir, hay compiladores
|
||||||
|
que no los admiten pero de todos modos deben producir el código adecuado,
|
||||||
|
incluso si es más lento o no realiza tantas comprobaciones/diagnósticos en
|
||||||
|
tiempo de compilación).
|
||||||
|
|
||||||
|
El kernel define pseudo-palabras clave (por ejemplo, ``__pure``) en lugar
|
||||||
|
de usar directamente la sintaxis del atributo GNU (por ejemplo,
|
||||||
|
``__attribute__((__pure__))``) con el fin de detectar cuáles se pueden
|
||||||
|
utilizar y/o acortar el código.
|
||||||
|
|
||||||
|
Por favor consulte ``include/linux/compiler_attributes.h`` para obtener
|
||||||
|
más información.
|
||||||
|
|
||||||
|
.. [sp-c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
|
||||||
|
.. [sp-gcc] https://gcc.gnu.org
|
||||||
|
.. [sp-clang] https://clang.llvm.org
|
||||||
|
.. [sp-icc] https://software.intel.com/en-us/c-compilers
|
||||||
|
.. [sp-gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
|
||||||
|
.. [sp-gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
|
||||||
|
.. [sp-gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
|
||||||
|
.. [sp-n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
|
@ -24,6 +24,9 @@ YAML specifications can be found under ``Documentation/netlink/specs/``
|
|||||||
This document describes details of the schema.
|
This document describes details of the schema.
|
||||||
See :doc:`intro-specs` for a practical starting guide.
|
See :doc:`intro-specs` for a practical starting guide.
|
||||||
|
|
||||||
|
All specs must be licensed under ``GPL-2.0-only OR BSD-3-Clause``
|
||||||
|
to allow for easy adoption in user space code.
|
||||||
|
|
||||||
Compatibility levels
|
Compatibility levels
|
||||||
====================
|
====================
|
||||||
|
|
||||||
@ -197,9 +200,15 @@ value
|
|||||||
Numerical attribute ID, used in serialized Netlink messages.
|
Numerical attribute ID, used in serialized Netlink messages.
|
||||||
The ``value`` property can be skipped, in which case the attribute ID
|
The ``value`` property can be skipped, in which case the attribute ID
|
||||||
will be the value of the previous attribute plus one (recursively)
|
will be the value of the previous attribute plus one (recursively)
|
||||||
and ``0`` for the first attribute in the attribute set.
|
and ``1`` for the first attribute in the attribute set.
|
||||||
|
|
||||||
Note that the ``value`` of an attribute is defined only in its main set.
|
Attributes (and operations) use ``1`` as the default value for the first
|
||||||
|
entry (unlike enums in definitions which start from ``0``) because
|
||||||
|
entry ``0`` is almost always reserved as undefined. Spec can explicitly
|
||||||
|
set value to ``0`` if needed.
|
||||||
|
|
||||||
|
Note that the ``value`` of an attribute is defined only in its main set
|
||||||
|
(not in subsets).
|
||||||
|
|
||||||
enum
|
enum
|
||||||
~~~~
|
~~~~
|
||||||
|
@ -7795,6 +7795,7 @@ M: Chao Yu <chao@kernel.org>
|
|||||||
L: linux-f2fs-devel@lists.sourceforge.net
|
L: linux-f2fs-devel@lists.sourceforge.net
|
||||||
S: Maintained
|
S: Maintained
|
||||||
W: https://f2fs.wiki.kernel.org/
|
W: https://f2fs.wiki.kernel.org/
|
||||||
|
Q: https://patchwork.kernel.org/project/f2fs/list/
|
||||||
B: https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System&component=f2fs
|
B: https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System&component=f2fs
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
|
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
|
||||||
F: Documentation/ABI/testing/sysfs-fs-f2fs
|
F: Documentation/ABI/testing/sysfs-fs-f2fs
|
||||||
@ -7910,6 +7911,7 @@ F: include/trace/events/fs_dax.h
|
|||||||
|
|
||||||
FILESYSTEMS (VFS and infrastructure)
|
FILESYSTEMS (VFS and infrastructure)
|
||||||
M: Alexander Viro <viro@zeniv.linux.org.uk>
|
M: Alexander Viro <viro@zeniv.linux.org.uk>
|
||||||
|
M: Christian Brauner <brauner@kernel.org>
|
||||||
L: linux-fsdevel@vger.kernel.org
|
L: linux-fsdevel@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: fs/*
|
F: fs/*
|
||||||
@ -9789,13 +9791,6 @@ L: netdev@vger.kernel.org
|
|||||||
S: Supported
|
S: Supported
|
||||||
F: drivers/net/ethernet/ibm/ibmvnic.*
|
F: drivers/net/ethernet/ibm/ibmvnic.*
|
||||||
|
|
||||||
IBM Power Virtual Accelerator Switchboard
|
|
||||||
L: linuxppc-dev@lists.ozlabs.org
|
|
||||||
S: Supported
|
|
||||||
F: arch/powerpc/include/asm/vas.h
|
|
||||||
F: arch/powerpc/platforms/powernv/copy-paste.h
|
|
||||||
F: arch/powerpc/platforms/powernv/vas*
|
|
||||||
|
|
||||||
IBM Power Virtual Ethernet Device Driver
|
IBM Power Virtual Ethernet Device Driver
|
||||||
M: Nick Child <nnac123@linux.ibm.com>
|
M: Nick Child <nnac123@linux.ibm.com>
|
||||||
L: netdev@vger.kernel.org
|
L: netdev@vger.kernel.org
|
||||||
|
4
Makefile
4
Makefile
@ -1,8 +1,8 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
VERSION = 6
|
VERSION = 6
|
||||||
PATCHLEVEL = 2
|
PATCHLEVEL = 3
|
||||||
SUBLEVEL = 0
|
SUBLEVEL = 0
|
||||||
EXTRAVERSION =
|
EXTRAVERSION = -rc1
|
||||||
NAME = Hurr durr I'ma ninja sloth
|
NAME = Hurr durr I'ma ninja sloth
|
||||||
|
|
||||||
# *DOCUMENTATION*
|
# *DOCUMENTATION*
|
||||||
|
@ -152,8 +152,11 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
|||||||
the fault. */
|
the fault. */
|
||||||
fault = handle_mm_fault(vma, address, flags, regs);
|
fault = handle_mm_fault(vma, address, flags, regs);
|
||||||
|
|
||||||
if (fault_signal_pending(fault, regs))
|
if (fault_signal_pending(fault, regs)) {
|
||||||
|
if (!user_mode(regs))
|
||||||
|
goto no_context;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* The fault is fully completed (including releasing mmap lock) */
|
/* The fault is fully completed (including releasing mmap lock) */
|
||||||
if (fault & VM_FAULT_COMPLETED)
|
if (fault & VM_FAULT_COMPLETED)
|
||||||
|
@ -100,7 +100,6 @@ config ARM64
|
|||||||
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
|
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
|
||||||
select ARCH_WANT_FRAME_POINTERS
|
select ARCH_WANT_FRAME_POINTERS
|
||||||
select ARCH_WANT_HUGE_PMD_SHARE if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
|
select ARCH_WANT_HUGE_PMD_SHARE if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
|
||||||
select ARCH_WANT_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
|
|
||||||
select ARCH_WANT_LD_ORPHAN_WARN
|
select ARCH_WANT_LD_ORPHAN_WARN
|
||||||
select ARCH_WANTS_NO_INSTR
|
select ARCH_WANTS_NO_INSTR
|
||||||
select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES
|
select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES
|
||||||
@ -187,7 +186,8 @@ config ARM64
|
|||||||
select HAVE_DMA_CONTIGUOUS
|
select HAVE_DMA_CONTIGUOUS
|
||||||
select HAVE_DYNAMIC_FTRACE
|
select HAVE_DYNAMIC_FTRACE
|
||||||
select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \
|
select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \
|
||||||
if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG)
|
if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG && \
|
||||||
|
!CC_OPTIMIZE_FOR_SIZE)
|
||||||
select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \
|
select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY \
|
||||||
if DYNAMIC_FTRACE_WITH_ARGS
|
if DYNAMIC_FTRACE_WITH_ARGS
|
||||||
select HAVE_EFFICIENT_UNALIGNED_ACCESS
|
select HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||||
|
@ -180,6 +180,7 @@
|
|||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/mmdebug.h>
|
#include <linux/mmdebug.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <asm/boot.h>
|
||||||
#include <asm/bug.h>
|
#include <asm/bug.h>
|
||||||
|
|
||||||
#if VA_BITS > 48
|
#if VA_BITS > 48
|
||||||
@ -203,6 +204,16 @@ static inline unsigned long kaslr_offset(void)
|
|||||||
return kimage_vaddr - KIMAGE_VADDR;
|
return kimage_vaddr - KIMAGE_VADDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool kaslr_enabled(void)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The KASLR offset modulo MIN_KIMG_ALIGN is taken from the physical
|
||||||
|
* placement of the image rather than from the seed, so a displacement
|
||||||
|
* of less than MIN_KIMG_ALIGN means that no seed was provided.
|
||||||
|
*/
|
||||||
|
return kaslr_offset() >= MIN_KIMG_ALIGN;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allow all memory at the discovery stage. We will clip it later.
|
* Allow all memory at the discovery stage. We will clip it later.
|
||||||
*/
|
*/
|
||||||
|
@ -435,10 +435,6 @@ int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
|||||||
enum arm_smccc_conduit conduit;
|
enum arm_smccc_conduit conduit;
|
||||||
struct acpi_ffh_data *ffh_ctxt;
|
struct acpi_ffh_data *ffh_ctxt;
|
||||||
|
|
||||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
|
||||||
if (!ffh_ctxt)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
if (arm_smccc_get_version() < ARM_SMCCC_VERSION_1_2)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
@ -448,6 +444,10 @@ int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||||
|
if (!ffh_ctxt)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||||
|
@ -1633,7 +1633,7 @@ bool kaslr_requires_kpti(void)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kaslr_offset() > 0;
|
return kaslr_enabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __meltdown_safe = true;
|
static bool __meltdown_safe = true;
|
||||||
|
@ -2122,9 +2122,6 @@ static int __init fpsimd_init(void)
|
|||||||
pr_notice("Advanced SIMD is not implemented\n");
|
pr_notice("Advanced SIMD is not implemented\n");
|
||||||
|
|
||||||
|
|
||||||
if (cpu_have_named_feature(SME) && !cpu_have_named_feature(SVE))
|
|
||||||
pr_notice("SME is implemented but not SVE\n");
|
|
||||||
|
|
||||||
sve_sysctl_init();
|
sve_sysctl_init();
|
||||||
sme_sysctl_init();
|
sme_sysctl_init();
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ static int __init kaslr_init(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!kaslr_offset()) {
|
if (!kaslr_enabled()) {
|
||||||
pr_warn("KASLR disabled due to lack of seed\n");
|
pr_warn("KASLR disabled due to lack of seed\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -997,7 +997,7 @@ static int cfi_handler(struct pt_regs *regs, unsigned long esr)
|
|||||||
|
|
||||||
switch (report_cfi_failure(regs, regs->pc, &target, type)) {
|
switch (report_cfi_failure(regs, regs->pc, &target, type)) {
|
||||||
case BUG_TRAP_TYPE_BUG:
|
case BUG_TRAP_TYPE_BUG:
|
||||||
die("Oops - CFI", regs, 0);
|
die("Oops - CFI", regs, esr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUG_TRAP_TYPE_WARN:
|
case BUG_TRAP_TYPE_WARN:
|
||||||
|
@ -22,7 +22,8 @@ void copy_highpage(struct page *to, struct page *from)
|
|||||||
copy_page(kto, kfrom);
|
copy_page(kto, kfrom);
|
||||||
|
|
||||||
if (system_supports_mte() && page_mte_tagged(from)) {
|
if (system_supports_mte() && page_mte_tagged(from)) {
|
||||||
page_kasan_tag_reset(to);
|
if (kasan_hw_tags_enabled())
|
||||||
|
page_kasan_tag_reset(to);
|
||||||
/* It's a new page, shouldn't have been tagged yet */
|
/* It's a new page, shouldn't have been tagged yet */
|
||||||
WARN_ON_ONCE(!try_page_mte_tagging(to));
|
WARN_ON_ONCE(!try_page_mte_tagging(to));
|
||||||
mte_copy_page_tags(kto, kfrom);
|
mte_copy_page_tags(kto, kfrom);
|
||||||
|
@ -93,8 +93,11 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
|
|||||||
|
|
||||||
fault = handle_mm_fault(vma, address, flags, regs);
|
fault = handle_mm_fault(vma, address, flags, regs);
|
||||||
|
|
||||||
if (fault_signal_pending(fault, regs))
|
if (fault_signal_pending(fault, regs)) {
|
||||||
|
if (!user_mode(regs))
|
||||||
|
goto no_context;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* The fault is fully completed (including releasing mmap lock) */
|
/* The fault is fully completed (including releasing mmap lock) */
|
||||||
if (fault & VM_FAULT_COMPLETED)
|
if (fault & VM_FAULT_COMPLETED)
|
||||||
|
@ -15,11 +15,7 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
/* include compiler specific intrinsics */
|
/* include compiler specific intrinsics */
|
||||||
#include <asm/ia64regs.h>
|
#include <asm/ia64regs.h>
|
||||||
#ifdef __INTEL_COMPILER
|
#include <asm/gcc_intrin.h>
|
||||||
# include <asm/intel_intrin.h>
|
|
||||||
#else
|
|
||||||
# include <asm/gcc_intrin.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function doesn't exist, so you'll get a linker error if
|
* This function doesn't exist, so you'll get a linker error if
|
||||||
|
@ -1,162 +0,0 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
|
||||||
#ifndef _ASM_IA64_INTEL_INTRIN_H
|
|
||||||
#define _ASM_IA64_INTEL_INTRIN_H
|
|
||||||
/*
|
|
||||||
* Intel Compiler Intrinsics
|
|
||||||
*
|
|
||||||
* Copyright (C) 2002,2003 Jun Nakajima <jun.nakajima@intel.com>
|
|
||||||
* Copyright (C) 2002,2003 Suresh Siddha <suresh.b.siddha@intel.com>
|
|
||||||
* Copyright (C) 2005,2006 Hongjiu Lu <hongjiu.lu@intel.com>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <ia64intrin.h>
|
|
||||||
|
|
||||||
#define ia64_barrier() __memory_barrier()
|
|
||||||
|
|
||||||
#define ia64_stop() /* Nothing: As of now stop bit is generated for each
|
|
||||||
* intrinsic
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define ia64_getreg __getReg
|
|
||||||
#define ia64_setreg __setReg
|
|
||||||
|
|
||||||
#define ia64_hint __hint
|
|
||||||
#define ia64_hint_pause __hint_pause
|
|
||||||
|
|
||||||
#define ia64_mux1_brcst _m64_mux1_brcst
|
|
||||||
#define ia64_mux1_mix _m64_mux1_mix
|
|
||||||
#define ia64_mux1_shuf _m64_mux1_shuf
|
|
||||||
#define ia64_mux1_alt _m64_mux1_alt
|
|
||||||
#define ia64_mux1_rev _m64_mux1_rev
|
|
||||||
|
|
||||||
#define ia64_mux1(x,v) _m_to_int64(_m64_mux1(_m_from_int64(x), (v)))
|
|
||||||
#define ia64_popcnt _m64_popcnt
|
|
||||||
#define ia64_getf_exp __getf_exp
|
|
||||||
#define ia64_shrp _m64_shrp
|
|
||||||
|
|
||||||
#define ia64_tpa __tpa
|
|
||||||
#define ia64_invala __invala
|
|
||||||
#define ia64_invala_gr __invala_gr
|
|
||||||
#define ia64_invala_fr __invala_fr
|
|
||||||
#define ia64_nop __nop
|
|
||||||
#define ia64_sum __sum
|
|
||||||
#define ia64_ssm __ssm
|
|
||||||
#define ia64_rum __rum
|
|
||||||
#define ia64_rsm __rsm
|
|
||||||
#define ia64_fc __fc
|
|
||||||
|
|
||||||
#define ia64_ldfs __ldfs
|
|
||||||
#define ia64_ldfd __ldfd
|
|
||||||
#define ia64_ldfe __ldfe
|
|
||||||
#define ia64_ldf8 __ldf8
|
|
||||||
#define ia64_ldf_fill __ldf_fill
|
|
||||||
|
|
||||||
#define ia64_stfs __stfs
|
|
||||||
#define ia64_stfd __stfd
|
|
||||||
#define ia64_stfe __stfe
|
|
||||||
#define ia64_stf8 __stf8
|
|
||||||
#define ia64_stf_spill __stf_spill
|
|
||||||
|
|
||||||
#define ia64_mf __mf
|
|
||||||
#define ia64_mfa __mfa
|
|
||||||
|
|
||||||
#define ia64_fetchadd4_acq __fetchadd4_acq
|
|
||||||
#define ia64_fetchadd4_rel __fetchadd4_rel
|
|
||||||
#define ia64_fetchadd8_acq __fetchadd8_acq
|
|
||||||
#define ia64_fetchadd8_rel __fetchadd8_rel
|
|
||||||
|
|
||||||
#define ia64_xchg1 _InterlockedExchange8
|
|
||||||
#define ia64_xchg2 _InterlockedExchange16
|
|
||||||
#define ia64_xchg4 _InterlockedExchange
|
|
||||||
#define ia64_xchg8 _InterlockedExchange64
|
|
||||||
|
|
||||||
#define ia64_cmpxchg1_rel _InterlockedCompareExchange8_rel
|
|
||||||
#define ia64_cmpxchg1_acq _InterlockedCompareExchange8_acq
|
|
||||||
#define ia64_cmpxchg2_rel _InterlockedCompareExchange16_rel
|
|
||||||
#define ia64_cmpxchg2_acq _InterlockedCompareExchange16_acq
|
|
||||||
#define ia64_cmpxchg4_rel _InterlockedCompareExchange_rel
|
|
||||||
#define ia64_cmpxchg4_acq _InterlockedCompareExchange_acq
|
|
||||||
#define ia64_cmpxchg8_rel _InterlockedCompareExchange64_rel
|
|
||||||
#define ia64_cmpxchg8_acq _InterlockedCompareExchange64_acq
|
|
||||||
|
|
||||||
#define __ia64_set_dbr(index, val) \
|
|
||||||
__setIndReg(_IA64_REG_INDR_DBR, index, val)
|
|
||||||
#define ia64_set_ibr(index, val) \
|
|
||||||
__setIndReg(_IA64_REG_INDR_IBR, index, val)
|
|
||||||
#define ia64_set_pkr(index, val) \
|
|
||||||
__setIndReg(_IA64_REG_INDR_PKR, index, val)
|
|
||||||
#define ia64_set_pmc(index, val) \
|
|
||||||
__setIndReg(_IA64_REG_INDR_PMC, index, val)
|
|
||||||
#define ia64_set_pmd(index, val) \
|
|
||||||
__setIndReg(_IA64_REG_INDR_PMD, index, val)
|
|
||||||
#define ia64_set_rr(index, val) \
|
|
||||||
__setIndReg(_IA64_REG_INDR_RR, index, val)
|
|
||||||
|
|
||||||
#define ia64_get_cpuid(index) \
|
|
||||||
__getIndReg(_IA64_REG_INDR_CPUID, index)
|
|
||||||
#define __ia64_get_dbr(index) __getIndReg(_IA64_REG_INDR_DBR, index)
|
|
||||||
#define ia64_get_ibr(index) __getIndReg(_IA64_REG_INDR_IBR, index)
|
|
||||||
#define ia64_get_pkr(index) __getIndReg(_IA64_REG_INDR_PKR, index)
|
|
||||||
#define ia64_get_pmc(index) __getIndReg(_IA64_REG_INDR_PMC, index)
|
|
||||||
#define ia64_get_pmd(index) __getIndReg(_IA64_REG_INDR_PMD, index)
|
|
||||||
#define ia64_get_rr(index) __getIndReg(_IA64_REG_INDR_RR, index)
|
|
||||||
|
|
||||||
#define ia64_srlz_d __dsrlz
|
|
||||||
#define ia64_srlz_i __isrlz
|
|
||||||
|
|
||||||
#define ia64_dv_serialize_data()
|
|
||||||
#define ia64_dv_serialize_instruction()
|
|
||||||
|
|
||||||
#define ia64_st1_rel __st1_rel
|
|
||||||
#define ia64_st2_rel __st2_rel
|
|
||||||
#define ia64_st4_rel __st4_rel
|
|
||||||
#define ia64_st8_rel __st8_rel
|
|
||||||
|
|
||||||
/* FIXME: need st4.rel.nta intrinsic */
|
|
||||||
#define ia64_st4_rel_nta __st4_rel
|
|
||||||
|
|
||||||
#define ia64_ld1_acq __ld1_acq
|
|
||||||
#define ia64_ld2_acq __ld2_acq
|
|
||||||
#define ia64_ld4_acq __ld4_acq
|
|
||||||
#define ia64_ld8_acq __ld8_acq
|
|
||||||
|
|
||||||
#define ia64_sync_i __synci
|
|
||||||
#define ia64_thash __thash
|
|
||||||
#define ia64_ttag __ttag
|
|
||||||
#define ia64_itcd __itcd
|
|
||||||
#define ia64_itci __itci
|
|
||||||
#define ia64_itrd __itrd
|
|
||||||
#define ia64_itri __itri
|
|
||||||
#define ia64_ptce __ptce
|
|
||||||
#define ia64_ptcl __ptcl
|
|
||||||
#define ia64_ptcg __ptcg
|
|
||||||
#define ia64_ptcga __ptcga
|
|
||||||
#define ia64_ptri __ptri
|
|
||||||
#define ia64_ptrd __ptrd
|
|
||||||
#define ia64_dep_mi _m64_dep_mi
|
|
||||||
|
|
||||||
/* Values for lfhint in __lfetch and __lfetch_fault */
|
|
||||||
|
|
||||||
#define ia64_lfhint_none __lfhint_none
|
|
||||||
#define ia64_lfhint_nt1 __lfhint_nt1
|
|
||||||
#define ia64_lfhint_nt2 __lfhint_nt2
|
|
||||||
#define ia64_lfhint_nta __lfhint_nta
|
|
||||||
|
|
||||||
#define ia64_lfetch __lfetch
|
|
||||||
#define ia64_lfetch_excl __lfetch_excl
|
|
||||||
#define ia64_lfetch_fault __lfetch_fault
|
|
||||||
#define ia64_lfetch_fault_excl __lfetch_fault_excl
|
|
||||||
|
|
||||||
#define ia64_intrin_local_irq_restore(x) \
|
|
||||||
do { \
|
|
||||||
if ((x) != 0) { \
|
|
||||||
ia64_ssm(IA64_PSR_I); \
|
|
||||||
ia64_srlz_d(); \
|
|
||||||
} else { \
|
|
||||||
ia64_rsm(IA64_PSR_I); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define __builtin_trap() __break(0);
|
|
||||||
|
|
||||||
#endif /* _ASM_IA64_INTEL_INTRIN_H */
|
|
@ -14,11 +14,7 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
/* include compiler specific intrinsics */
|
/* include compiler specific intrinsics */
|
||||||
#include <asm/ia64regs.h>
|
#include <asm/ia64regs.h>
|
||||||
#ifdef __INTEL_COMPILER
|
#include <asm/gcc_intrin.h>
|
||||||
# include <asm/intel_intrin.h>
|
|
||||||
#else
|
|
||||||
# include <asm/gcc_intrin.h>
|
|
||||||
#endif
|
|
||||||
#include <asm/cmpxchg.h>
|
#include <asm/cmpxchg.h>
|
||||||
|
|
||||||
#define ia64_set_rr0_to_rr4(val0, val1, val2, val3, val4) \
|
#define ia64_set_rr0_to_rr4(val0, val1, val2, val3, val4) \
|
||||||
|
@ -783,11 +783,9 @@ __init void prefill_possible_map(void)
|
|||||||
|
|
||||||
static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
|
static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
|
||||||
{
|
{
|
||||||
cpumask_t tmp_map;
|
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
cpumask_complement(&tmp_map, cpu_present_mask);
|
cpu = cpumask_first_zero(cpu_present_mask);
|
||||||
cpu = cpumask_first(&tmp_map);
|
|
||||||
if (cpu >= nr_cpu_ids)
|
if (cpu >= nr_cpu_ids)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -136,8 +136,11 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
|
|||||||
*/
|
*/
|
||||||
fault = handle_mm_fault(vma, address, flags, regs);
|
fault = handle_mm_fault(vma, address, flags, regs);
|
||||||
|
|
||||||
if (fault_signal_pending(fault, regs))
|
if (fault_signal_pending(fault, regs)) {
|
||||||
|
if (!user_mode(regs))
|
||||||
|
goto no_context;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* The fault is fully completed (including releasing mmap lock) */
|
/* The fault is fully completed (including releasing mmap lock) */
|
||||||
if (fault & VM_FAULT_COMPLETED)
|
if (fault & VM_FAULT_COMPLETED)
|
||||||
|
@ -94,15 +94,21 @@ config LOONGARCH
|
|||||||
select HAVE_DYNAMIC_FTRACE_WITH_ARGS
|
select HAVE_DYNAMIC_FTRACE_WITH_ARGS
|
||||||
select HAVE_DYNAMIC_FTRACE_WITH_REGS
|
select HAVE_DYNAMIC_FTRACE_WITH_REGS
|
||||||
select HAVE_EBPF_JIT
|
select HAVE_EBPF_JIT
|
||||||
|
select HAVE_EFFICIENT_UNALIGNED_ACCESS if !ARCH_STRICT_ALIGN
|
||||||
select HAVE_EXIT_THREAD
|
select HAVE_EXIT_THREAD
|
||||||
select HAVE_FAST_GUP
|
select HAVE_FAST_GUP
|
||||||
select HAVE_FTRACE_MCOUNT_RECORD
|
select HAVE_FTRACE_MCOUNT_RECORD
|
||||||
|
select HAVE_FUNCTION_ARG_ACCESS_API
|
||||||
select HAVE_FUNCTION_GRAPH_TRACER
|
select HAVE_FUNCTION_GRAPH_TRACER
|
||||||
select HAVE_FUNCTION_TRACER
|
select HAVE_FUNCTION_TRACER
|
||||||
select HAVE_GENERIC_VDSO
|
select HAVE_GENERIC_VDSO
|
||||||
|
select HAVE_HW_BREAKPOINT if PERF_EVENTS
|
||||||
select HAVE_IOREMAP_PROT
|
select HAVE_IOREMAP_PROT
|
||||||
select HAVE_IRQ_EXIT_ON_IRQ_STACK
|
select HAVE_IRQ_EXIT_ON_IRQ_STACK
|
||||||
select HAVE_IRQ_TIME_ACCOUNTING
|
select HAVE_IRQ_TIME_ACCOUNTING
|
||||||
|
select HAVE_KPROBES
|
||||||
|
select HAVE_KPROBES_ON_FTRACE
|
||||||
|
select HAVE_KRETPROBES
|
||||||
select HAVE_MOD_ARCH_SPECIFIC
|
select HAVE_MOD_ARCH_SPECIFIC
|
||||||
select HAVE_NMI
|
select HAVE_NMI
|
||||||
select HAVE_PCI
|
select HAVE_PCI
|
||||||
@ -441,6 +447,24 @@ config ARCH_IOREMAP
|
|||||||
protection support. However, you can enable LoongArch DMW-based
|
protection support. However, you can enable LoongArch DMW-based
|
||||||
ioremap() for better performance.
|
ioremap() for better performance.
|
||||||
|
|
||||||
|
config ARCH_STRICT_ALIGN
|
||||||
|
bool "Enable -mstrict-align to prevent unaligned accesses" if EXPERT
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Not all LoongArch cores support h/w unaligned access, we can use
|
||||||
|
-mstrict-align build parameter to prevent unaligned accesses.
|
||||||
|
|
||||||
|
CPUs with h/w unaligned access support:
|
||||||
|
Loongson-2K2000/2K3000/3A5000/3C5000/3D5000.
|
||||||
|
|
||||||
|
CPUs without h/w unaligned access support:
|
||||||
|
Loongson-2K500/2K1000.
|
||||||
|
|
||||||
|
This option is enabled by default to make the kernel be able to run
|
||||||
|
on all LoongArch systems. But you can disable it manually if you want
|
||||||
|
to run kernel only on systems with h/w unaligned access support in
|
||||||
|
order to optimise for performance.
|
||||||
|
|
||||||
config KEXEC
|
config KEXEC
|
||||||
bool "Kexec system call"
|
bool "Kexec system call"
|
||||||
select KEXEC_CORE
|
select KEXEC_CORE
|
||||||
@ -454,6 +478,7 @@ config KEXEC
|
|||||||
|
|
||||||
config CRASH_DUMP
|
config CRASH_DUMP
|
||||||
bool "Build kdump crash kernel"
|
bool "Build kdump crash kernel"
|
||||||
|
select RELOCATABLE
|
||||||
help
|
help
|
||||||
Generate crash dump after being started by kexec. This should
|
Generate crash dump after being started by kexec. This should
|
||||||
be normally only set in special crash dump kernels which are
|
be normally only set in special crash dump kernels which are
|
||||||
@ -463,16 +488,38 @@ config CRASH_DUMP
|
|||||||
|
|
||||||
For more details see Documentation/admin-guide/kdump/kdump.rst
|
For more details see Documentation/admin-guide/kdump/kdump.rst
|
||||||
|
|
||||||
config PHYSICAL_START
|
config RELOCATABLE
|
||||||
hex "Physical address where the kernel is loaded"
|
bool "Relocatable kernel"
|
||||||
default "0x90000000a0000000"
|
|
||||||
depends on CRASH_DUMP
|
|
||||||
help
|
help
|
||||||
This gives the XKPRANGE address where the kernel is loaded.
|
This builds the kernel as a Position Independent Executable (PIE),
|
||||||
If you plan to use kernel for capturing the crash dump change
|
which retains all relocation metadata required, so as to relocate
|
||||||
this value to start of the reserved region (the "X" value as
|
the kernel binary at runtime to a different virtual address from
|
||||||
specified in the "crashkernel=YM@XM" command line boot parameter
|
its link address.
|
||||||
passed to the panic-ed kernel).
|
|
||||||
|
config RANDOMIZE_BASE
|
||||||
|
bool "Randomize the address of the kernel (KASLR)"
|
||||||
|
depends on RELOCATABLE
|
||||||
|
help
|
||||||
|
Randomizes the physical and virtual address at which the
|
||||||
|
kernel image is loaded, as a security feature that
|
||||||
|
deters exploit attempts relying on knowledge of the location
|
||||||
|
of kernel internals.
|
||||||
|
|
||||||
|
The kernel will be offset by up to RANDOMIZE_BASE_MAX_OFFSET.
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
config RANDOMIZE_BASE_MAX_OFFSET
|
||||||
|
hex "Maximum KASLR offset" if EXPERT
|
||||||
|
depends on RANDOMIZE_BASE
|
||||||
|
range 0x0 0x10000000
|
||||||
|
default "0x01000000"
|
||||||
|
help
|
||||||
|
When KASLR is active, this provides the maximum offset that will
|
||||||
|
be applied to the kernel image. It should be set according to the
|
||||||
|
amount of physical RAM available in the target system.
|
||||||
|
|
||||||
|
This is limited by the size of the lower address memory, 256MB.
|
||||||
|
|
||||||
config SECCOMP
|
config SECCOMP
|
||||||
bool "Enable seccomp to safely compute untrusted bytecode"
|
bool "Enable seccomp to safely compute untrusted bytecode"
|
||||||
|
@ -71,14 +71,15 @@ KBUILD_AFLAGS_MODULE += -Wa,-mla-global-with-abs
|
|||||||
KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
|
KBUILD_CFLAGS_MODULE += -fplt -Wa,-mla-global-with-abs,-mla-local-with-abs
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_RELOCATABLE),y)
|
||||||
|
KBUILD_CFLAGS_KERNEL += -fPIE
|
||||||
|
LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext
|
||||||
|
endif
|
||||||
|
|
||||||
cflags-y += -ffreestanding
|
cflags-y += -ffreestanding
|
||||||
cflags-y += $(call cc-option, -mno-check-zero-division)
|
cflags-y += $(call cc-option, -mno-check-zero-division)
|
||||||
|
|
||||||
ifndef CONFIG_PHYSICAL_START
|
|
||||||
load-y = 0x9000000000200000
|
load-y = 0x9000000000200000
|
||||||
else
|
|
||||||
load-y = $(CONFIG_PHYSICAL_START)
|
|
||||||
endif
|
|
||||||
bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y)
|
bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y)
|
||||||
|
|
||||||
drivers-$(CONFIG_PCI) += arch/loongarch/pci/
|
drivers-$(CONFIG_PCI) += arch/loongarch/pci/
|
||||||
@ -91,10 +92,15 @@ KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y)
|
|||||||
# instead of .eh_frame so we don't discard them.
|
# instead of .eh_frame so we don't discard them.
|
||||||
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
|
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
|
||||||
|
|
||||||
|
ifdef CONFIG_ARCH_STRICT_ALIGN
|
||||||
# Don't emit unaligned accesses.
|
# Don't emit unaligned accesses.
|
||||||
# Not all LoongArch cores support unaligned access, and as kernel we can't
|
# Not all LoongArch cores support unaligned access, and as kernel we can't
|
||||||
# rely on others to provide emulation for these accesses.
|
# rely on others to provide emulation for these accesses.
|
||||||
KBUILD_CFLAGS += $(call cc-option,-mstrict-align)
|
KBUILD_CFLAGS += $(call cc-option,-mstrict-align)
|
||||||
|
else
|
||||||
|
# Optimise for performance on hardware supports unaligned access.
|
||||||
|
KBUILD_CFLAGS += $(call cc-option,-mno-strict-align)
|
||||||
|
endif
|
||||||
|
|
||||||
KBUILD_CFLAGS += -isystem $(shell $(CC) -print-file-name=include)
|
KBUILD_CFLAGS += -isystem $(shell $(CC) -print-file-name=include)
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ CONFIG_HOTPLUG_CPU=y
|
|||||||
CONFIG_NR_CPUS=64
|
CONFIG_NR_CPUS=64
|
||||||
CONFIG_NUMA=y
|
CONFIG_NUMA=y
|
||||||
CONFIG_KEXEC=y
|
CONFIG_KEXEC=y
|
||||||
|
CONFIG_CRASH_DUMP=y
|
||||||
CONFIG_SUSPEND=y
|
CONFIG_SUSPEND=y
|
||||||
CONFIG_HIBERNATION=y
|
CONFIG_HIBERNATION=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
|
@ -125,4 +125,6 @@ extern unsigned long vm_map_base;
|
|||||||
#define ISA_IOSIZE SZ_16K
|
#define ISA_IOSIZE SZ_16K
|
||||||
#define IO_SPACE_LIMIT (PCI_IOSIZE - 1)
|
#define IO_SPACE_LIMIT (PCI_IOSIZE - 1)
|
||||||
|
|
||||||
|
#define PHYS_LINK_KADDR PHYSADDR(VMLINUX_LOAD_ADDRESS)
|
||||||
|
|
||||||
#endif /* _ASM_ADDRSPACE_H */
|
#endif /* _ASM_ADDRSPACE_H */
|
||||||
|
@ -188,4 +188,14 @@
|
|||||||
#define PTRLOG 3
|
#define PTRLOG 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Annotate a function as being unsuitable for kprobes. */
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
#define _ASM_NOKPROBE(name) \
|
||||||
|
.pushsection "_kprobe_blacklist", "aw"; \
|
||||||
|
.quad name; \
|
||||||
|
.popsection
|
||||||
|
#else
|
||||||
|
#define _ASM_NOKPROBE(name)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __ASM_ASM_H */
|
#endif /* __ASM_ASM_H */
|
||||||
|
@ -274,4 +274,21 @@
|
|||||||
nor \dst, \src, zero
|
nor \dst, \src, zero
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro la_abs reg, sym
|
||||||
|
#ifndef CONFIG_RELOCATABLE
|
||||||
|
la.abs \reg, \sym
|
||||||
|
#else
|
||||||
|
766:
|
||||||
|
lu12i.w \reg, 0
|
||||||
|
ori \reg, \reg, 0
|
||||||
|
lu32i.d \reg, 0
|
||||||
|
lu52i.d \reg, \reg, 0
|
||||||
|
.pushsection ".la_abs", "aw", %progbits
|
||||||
|
768:
|
||||||
|
.dword 768b-766b
|
||||||
|
.dword \sym
|
||||||
|
.popsection
|
||||||
|
#endif
|
||||||
|
.endm
|
||||||
|
|
||||||
#endif /* _ASM_ASMMACRO_H */
|
#endif /* _ASM_ASMMACRO_H */
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#define PRID_SERIES_LA132 0x8000 /* Loongson 32bit */
|
#define PRID_SERIES_LA132 0x8000 /* Loongson 32bit */
|
||||||
#define PRID_SERIES_LA264 0xa000 /* Loongson 64bit, 2-issue */
|
#define PRID_SERIES_LA264 0xa000 /* Loongson 64bit, 2-issue */
|
||||||
#define PRID_SERIES_LA364 0xb000 /* Loongson 64bit,3-issue */
|
#define PRID_SERIES_LA364 0xb000 /* Loongson 64bit, 3-issue */
|
||||||
#define PRID_SERIES_LA464 0xc000 /* Loongson 64bit, 4-issue */
|
#define PRID_SERIES_LA464 0xc000 /* Loongson 64bit, 4-issue */
|
||||||
#define PRID_SERIES_LA664 0xd000 /* Loongson 64bit, 6-issue */
|
#define PRID_SERIES_LA664 0xd000 /* Loongson 64bit, 6-issue */
|
||||||
|
|
||||||
|
145
arch/loongarch/include/asm/hw_breakpoint.h
Normal file
145
arch/loongarch/include/asm/hw_breakpoint.h
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2023 Loongson Technology Corporation Limited
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_HW_BREAKPOINT_H
|
||||||
|
#define __ASM_HW_BREAKPOINT_H
|
||||||
|
|
||||||
|
#include <asm/loongarch.h>
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
/* Breakpoint */
|
||||||
|
#define LOONGARCH_BREAKPOINT_EXECUTE (0 << 0)
|
||||||
|
|
||||||
|
/* Watchpoints */
|
||||||
|
#define LOONGARCH_BREAKPOINT_LOAD (1 << 0)
|
||||||
|
#define LOONGARCH_BREAKPOINT_STORE (1 << 1)
|
||||||
|
|
||||||
|
struct arch_hw_breakpoint_ctrl {
|
||||||
|
u32 __reserved : 28,
|
||||||
|
len : 2,
|
||||||
|
type : 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct arch_hw_breakpoint {
|
||||||
|
u64 address;
|
||||||
|
u64 mask;
|
||||||
|
struct arch_hw_breakpoint_ctrl ctrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Lengths */
|
||||||
|
#define LOONGARCH_BREAKPOINT_LEN_1 0b11
|
||||||
|
#define LOONGARCH_BREAKPOINT_LEN_2 0b10
|
||||||
|
#define LOONGARCH_BREAKPOINT_LEN_4 0b01
|
||||||
|
#define LOONGARCH_BREAKPOINT_LEN_8 0b00
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limits.
|
||||||
|
* Changing these will require modifications to the register accessors.
|
||||||
|
*/
|
||||||
|
#define LOONGARCH_MAX_BRP 8
|
||||||
|
#define LOONGARCH_MAX_WRP 8
|
||||||
|
|
||||||
|
/* Virtual debug register bases. */
|
||||||
|
#define CSR_CFG_ADDR 0
|
||||||
|
#define CSR_CFG_MASK (CSR_CFG_ADDR + LOONGARCH_MAX_BRP)
|
||||||
|
#define CSR_CFG_CTRL (CSR_CFG_MASK + LOONGARCH_MAX_BRP)
|
||||||
|
#define CSR_CFG_ASID (CSR_CFG_CTRL + LOONGARCH_MAX_WRP)
|
||||||
|
|
||||||
|
/* Debug register names. */
|
||||||
|
#define LOONGARCH_CSR_NAME_ADDR ADDR
|
||||||
|
#define LOONGARCH_CSR_NAME_MASK MASK
|
||||||
|
#define LOONGARCH_CSR_NAME_CTRL CTRL
|
||||||
|
#define LOONGARCH_CSR_NAME_ASID ASID
|
||||||
|
|
||||||
|
/* Accessor macros for the debug registers. */
|
||||||
|
#define LOONGARCH_CSR_WATCH_READ(N, REG, T, VAL) \
|
||||||
|
do { \
|
||||||
|
if (T == 0) \
|
||||||
|
VAL = csr_read64(LOONGARCH_CSR_##IB##N##REG); \
|
||||||
|
else \
|
||||||
|
VAL = csr_read64(LOONGARCH_CSR_##DB##N##REG); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LOONGARCH_CSR_WATCH_WRITE(N, REG, T, VAL) \
|
||||||
|
do { \
|
||||||
|
if (T == 0) \
|
||||||
|
csr_write64(VAL, LOONGARCH_CSR_##IB##N##REG); \
|
||||||
|
else \
|
||||||
|
csr_write64(VAL, LOONGARCH_CSR_##DB##N##REG); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Exact number */
|
||||||
|
#define CSR_FWPC_NUM 0x3f
|
||||||
|
#define CSR_MWPC_NUM 0x3f
|
||||||
|
|
||||||
|
#define CTRL_PLV_ENABLE 0x1e
|
||||||
|
|
||||||
|
#define MWPnCFG3_LoadEn 8
|
||||||
|
#define MWPnCFG3_StoreEn 9
|
||||||
|
|
||||||
|
#define MWPnCFG3_Type_mask 0x3
|
||||||
|
#define MWPnCFG3_Size_mask 0x3
|
||||||
|
|
||||||
|
static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl)
|
||||||
|
{
|
||||||
|
return (ctrl.len << 10) | (ctrl.type << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void decode_ctrl_reg(u32 reg, struct arch_hw_breakpoint_ctrl *ctrl)
|
||||||
|
{
|
||||||
|
reg >>= 8;
|
||||||
|
ctrl->type = reg & MWPnCFG3_Type_mask;
|
||||||
|
reg >>= 2;
|
||||||
|
ctrl->len = reg & MWPnCFG3_Size_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct task_struct;
|
||||||
|
struct notifier_block;
|
||||||
|
struct perf_event;
|
||||||
|
struct perf_event_attr;
|
||||||
|
|
||||||
|
extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
||||||
|
int *gen_len, int *gen_type, int *offset);
|
||||||
|
extern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
|
||||||
|
extern int hw_breakpoint_arch_parse(struct perf_event *bp,
|
||||||
|
const struct perf_event_attr *attr,
|
||||||
|
struct arch_hw_breakpoint *hw);
|
||||||
|
extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
|
||||||
|
unsigned long val, void *data);
|
||||||
|
|
||||||
|
extern int arch_install_hw_breakpoint(struct perf_event *bp);
|
||||||
|
extern void arch_uninstall_hw_breakpoint(struct perf_event *bp);
|
||||||
|
extern int hw_breakpoint_slots(int type);
|
||||||
|
extern void hw_breakpoint_pmu_read(struct perf_event *bp);
|
||||||
|
|
||||||
|
void breakpoint_handler(struct pt_regs *regs);
|
||||||
|
void watchpoint_handler(struct pt_regs *regs);
|
||||||
|
|
||||||
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||||
|
extern void ptrace_hw_copy_thread(struct task_struct *task);
|
||||||
|
extern void hw_breakpoint_thread_switch(struct task_struct *next);
|
||||||
|
#else
|
||||||
|
static inline void ptrace_hw_copy_thread(struct task_struct *task)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static inline void hw_breakpoint_thread_switch(struct task_struct *next)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Determine number of BRP registers available. */
|
||||||
|
static inline int get_num_brps(void)
|
||||||
|
{
|
||||||
|
return csr_read64(LOONGARCH_CSR_FWPC) & CSR_FWPC_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine number of WRP registers available. */
|
||||||
|
static inline int get_num_wrps(void)
|
||||||
|
{
|
||||||
|
return csr_read64(LOONGARCH_CSR_MWPC) & CSR_MWPC_NUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
#endif /* __ASM_BREAKPOINT_H */
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
|
||||||
#define INSN_NOP 0x03400000
|
#define INSN_NOP 0x03400000
|
||||||
#define INSN_BREAK 0x002a0000
|
#define INSN_BREAK 0x002a0000
|
||||||
@ -23,6 +24,10 @@
|
|||||||
|
|
||||||
#define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
|
#define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
|
||||||
|
|
||||||
|
enum reg0i15_op {
|
||||||
|
break_op = 0x54,
|
||||||
|
};
|
||||||
|
|
||||||
enum reg0i26_op {
|
enum reg0i26_op {
|
||||||
b_op = 0x14,
|
b_op = 0x14,
|
||||||
bl_op = 0x15,
|
bl_op = 0x15,
|
||||||
@ -32,6 +37,7 @@ enum reg1i20_op {
|
|||||||
lu12iw_op = 0x0a,
|
lu12iw_op = 0x0a,
|
||||||
lu32id_op = 0x0b,
|
lu32id_op = 0x0b,
|
||||||
pcaddi_op = 0x0c,
|
pcaddi_op = 0x0c,
|
||||||
|
pcalau12i_op = 0x0d,
|
||||||
pcaddu12i_op = 0x0e,
|
pcaddu12i_op = 0x0e,
|
||||||
pcaddu18i_op = 0x0f,
|
pcaddu18i_op = 0x0f,
|
||||||
};
|
};
|
||||||
@ -178,6 +184,11 @@ enum reg3sa2_op {
|
|||||||
alsld_op = 0x16,
|
alsld_op = 0x16,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct reg0i15_format {
|
||||||
|
unsigned int immediate : 15;
|
||||||
|
unsigned int opcode : 17;
|
||||||
|
};
|
||||||
|
|
||||||
struct reg0i26_format {
|
struct reg0i26_format {
|
||||||
unsigned int immediate_h : 10;
|
unsigned int immediate_h : 10;
|
||||||
unsigned int immediate_l : 16;
|
unsigned int immediate_l : 16;
|
||||||
@ -263,6 +274,7 @@ struct reg3sa2_format {
|
|||||||
|
|
||||||
union loongarch_instruction {
|
union loongarch_instruction {
|
||||||
unsigned int word;
|
unsigned int word;
|
||||||
|
struct reg0i15_format reg0i15_format;
|
||||||
struct reg0i26_format reg0i26_format;
|
struct reg0i26_format reg0i26_format;
|
||||||
struct reg1i20_format reg1i20_format;
|
struct reg1i20_format reg1i20_format;
|
||||||
struct reg1i21_format reg1i21_format;
|
struct reg1i21_format reg1i21_format;
|
||||||
@ -321,6 +333,11 @@ static inline bool is_imm_negative(unsigned long val, unsigned int bit)
|
|||||||
return val & (1UL << (bit - 1));
|
return val & (1UL << (bit - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_break_ins(union loongarch_instruction *ip)
|
||||||
|
{
|
||||||
|
return ip->reg0i15_format.opcode == break_op;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool is_pc_ins(union loongarch_instruction *ip)
|
static inline bool is_pc_ins(union loongarch_instruction *ip)
|
||||||
{
|
{
|
||||||
return ip->reg1i20_format.opcode >= pcaddi_op &&
|
return ip->reg1i20_format.opcode >= pcaddi_op &&
|
||||||
@ -351,6 +368,47 @@ static inline bool is_stack_alloc_ins(union loongarch_instruction *ip)
|
|||||||
is_imm12_negative(ip->reg2i12_format.immediate);
|
is_imm12_negative(ip->reg2i12_format.immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool is_self_loop_ins(union loongarch_instruction *ip, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
switch (ip->reg0i26_format.opcode) {
|
||||||
|
case b_op:
|
||||||
|
case bl_op:
|
||||||
|
if (ip->reg0i26_format.immediate_l == 0
|
||||||
|
&& ip->reg0i26_format.immediate_h == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ip->reg1i21_format.opcode) {
|
||||||
|
case beqz_op:
|
||||||
|
case bnez_op:
|
||||||
|
case bceqz_op:
|
||||||
|
if (ip->reg1i21_format.immediate_l == 0
|
||||||
|
&& ip->reg1i21_format.immediate_h == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ip->reg2i16_format.opcode) {
|
||||||
|
case beq_op:
|
||||||
|
case bne_op:
|
||||||
|
case blt_op:
|
||||||
|
case bge_op:
|
||||||
|
case bltu_op:
|
||||||
|
case bgeu_op:
|
||||||
|
if (ip->reg2i16_format.immediate == 0)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case jirl_op:
|
||||||
|
if (regs->regs[ip->reg2i16_format.rj] +
|
||||||
|
((unsigned long)ip->reg2i16_format.immediate << 2) == (unsigned long)ip)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simu_pc(struct pt_regs *regs, union loongarch_instruction insn);
|
||||||
|
void simu_branch(struct pt_regs *regs, union loongarch_instruction insn);
|
||||||
|
|
||||||
int larch_insn_read(void *addr, u32 *insnp);
|
int larch_insn_read(void *addr, u32 *insnp);
|
||||||
int larch_insn_write(void *addr, u32 insn);
|
int larch_insn_write(void *addr, u32 insn);
|
||||||
int larch_insn_patch_text(void *addr, u32 insn);
|
int larch_insn_patch_text(void *addr, u32 insn);
|
||||||
|
61
arch/loongarch/include/asm/kprobes.h
Normal file
61
arch/loongarch/include/asm/kprobes.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
#ifndef __ASM_LOONGARCH_KPROBES_H
|
||||||
|
#define __ASM_LOONGARCH_KPROBES_H
|
||||||
|
|
||||||
|
#include <asm-generic/kprobes.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
|
||||||
|
#include <asm/inst.h>
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
|
|
||||||
|
#define __ARCH_WANT_KPROBES_INSN_SLOT
|
||||||
|
#define MAX_INSN_SIZE 2
|
||||||
|
|
||||||
|
#define flush_insn_slot(p) \
|
||||||
|
do { \
|
||||||
|
if (p->addr) \
|
||||||
|
flush_icache_range((unsigned long)p->addr, \
|
||||||
|
(unsigned long)p->addr + \
|
||||||
|
(MAX_INSN_SIZE * sizeof(kprobe_opcode_t))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kretprobe_blacklist_size 0
|
||||||
|
|
||||||
|
typedef union loongarch_instruction kprobe_opcode_t;
|
||||||
|
|
||||||
|
/* Architecture specific copy of original instruction */
|
||||||
|
struct arch_specific_insn {
|
||||||
|
/* copy of the original instruction */
|
||||||
|
kprobe_opcode_t *insn;
|
||||||
|
/* restore address after simulation */
|
||||||
|
unsigned long restore;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct prev_kprobe {
|
||||||
|
struct kprobe *kp;
|
||||||
|
unsigned int status;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* per-cpu kprobe control block */
|
||||||
|
struct kprobe_ctlblk {
|
||||||
|
unsigned int kprobe_status;
|
||||||
|
unsigned long saved_status;
|
||||||
|
struct prev_kprobe prev_kprobe;
|
||||||
|
};
|
||||||
|
|
||||||
|
void arch_remove_kprobe(struct kprobe *p);
|
||||||
|
bool kprobe_fault_handler(struct pt_regs *regs, int trapnr);
|
||||||
|
bool kprobe_breakpoint_handler(struct pt_regs *regs);
|
||||||
|
bool kprobe_singlestep_handler(struct pt_regs *regs);
|
||||||
|
|
||||||
|
void __kretprobe_trampoline(void);
|
||||||
|
void *trampoline_probe_handler(struct pt_regs *regs);
|
||||||
|
|
||||||
|
#else /* !CONFIG_KPROBES */
|
||||||
|
|
||||||
|
static inline bool kprobe_breakpoint_handler(struct pt_regs *regs) { return false; }
|
||||||
|
static inline bool kprobe_singlestep_handler(struct pt_regs *regs) { return false; }
|
||||||
|
|
||||||
|
#endif /* CONFIG_KPROBES */
|
||||||
|
#endif /* __ASM_LOONGARCH_KPROBES_H */
|
@ -970,42 +970,42 @@ static __always_inline void iocsr_write64(u64 val, u32 reg)
|
|||||||
|
|
||||||
#define LOONGARCH_CSR_DB0ADDR 0x310 /* data breakpoint 0 address */
|
#define LOONGARCH_CSR_DB0ADDR 0x310 /* data breakpoint 0 address */
|
||||||
#define LOONGARCH_CSR_DB0MASK 0x311 /* data breakpoint 0 mask */
|
#define LOONGARCH_CSR_DB0MASK 0x311 /* data breakpoint 0 mask */
|
||||||
#define LOONGARCH_CSR_DB0CTL 0x312 /* data breakpoint 0 control */
|
#define LOONGARCH_CSR_DB0CTRL 0x312 /* data breakpoint 0 control */
|
||||||
#define LOONGARCH_CSR_DB0ASID 0x313 /* data breakpoint 0 asid */
|
#define LOONGARCH_CSR_DB0ASID 0x313 /* data breakpoint 0 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DB1ADDR 0x318 /* data breakpoint 1 address */
|
#define LOONGARCH_CSR_DB1ADDR 0x318 /* data breakpoint 1 address */
|
||||||
#define LOONGARCH_CSR_DB1MASK 0x319 /* data breakpoint 1 mask */
|
#define LOONGARCH_CSR_DB1MASK 0x319 /* data breakpoint 1 mask */
|
||||||
#define LOONGARCH_CSR_DB1CTL 0x31a /* data breakpoint 1 control */
|
#define LOONGARCH_CSR_DB1CTRL 0x31a /* data breakpoint 1 control */
|
||||||
#define LOONGARCH_CSR_DB1ASID 0x31b /* data breakpoint 1 asid */
|
#define LOONGARCH_CSR_DB1ASID 0x31b /* data breakpoint 1 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DB2ADDR 0x320 /* data breakpoint 2 address */
|
#define LOONGARCH_CSR_DB2ADDR 0x320 /* data breakpoint 2 address */
|
||||||
#define LOONGARCH_CSR_DB2MASK 0x321 /* data breakpoint 2 mask */
|
#define LOONGARCH_CSR_DB2MASK 0x321 /* data breakpoint 2 mask */
|
||||||
#define LOONGARCH_CSR_DB2CTL 0x322 /* data breakpoint 2 control */
|
#define LOONGARCH_CSR_DB2CTRL 0x322 /* data breakpoint 2 control */
|
||||||
#define LOONGARCH_CSR_DB2ASID 0x323 /* data breakpoint 2 asid */
|
#define LOONGARCH_CSR_DB2ASID 0x323 /* data breakpoint 2 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DB3ADDR 0x328 /* data breakpoint 3 address */
|
#define LOONGARCH_CSR_DB3ADDR 0x328 /* data breakpoint 3 address */
|
||||||
#define LOONGARCH_CSR_DB3MASK 0x329 /* data breakpoint 3 mask */
|
#define LOONGARCH_CSR_DB3MASK 0x329 /* data breakpoint 3 mask */
|
||||||
#define LOONGARCH_CSR_DB3CTL 0x32a /* data breakpoint 3 control */
|
#define LOONGARCH_CSR_DB3CTRL 0x32a /* data breakpoint 3 control */
|
||||||
#define LOONGARCH_CSR_DB3ASID 0x32b /* data breakpoint 3 asid */
|
#define LOONGARCH_CSR_DB3ASID 0x32b /* data breakpoint 3 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DB4ADDR 0x330 /* data breakpoint 4 address */
|
#define LOONGARCH_CSR_DB4ADDR 0x330 /* data breakpoint 4 address */
|
||||||
#define LOONGARCH_CSR_DB4MASK 0x331 /* data breakpoint 4 maks */
|
#define LOONGARCH_CSR_DB4MASK 0x331 /* data breakpoint 4 maks */
|
||||||
#define LOONGARCH_CSR_DB4CTL 0x332 /* data breakpoint 4 control */
|
#define LOONGARCH_CSR_DB4CTRL 0x332 /* data breakpoint 4 control */
|
||||||
#define LOONGARCH_CSR_DB4ASID 0x333 /* data breakpoint 4 asid */
|
#define LOONGARCH_CSR_DB4ASID 0x333 /* data breakpoint 4 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DB5ADDR 0x338 /* data breakpoint 5 address */
|
#define LOONGARCH_CSR_DB5ADDR 0x338 /* data breakpoint 5 address */
|
||||||
#define LOONGARCH_CSR_DB5MASK 0x339 /* data breakpoint 5 mask */
|
#define LOONGARCH_CSR_DB5MASK 0x339 /* data breakpoint 5 mask */
|
||||||
#define LOONGARCH_CSR_DB5CTL 0x33a /* data breakpoint 5 control */
|
#define LOONGARCH_CSR_DB5CTRL 0x33a /* data breakpoint 5 control */
|
||||||
#define LOONGARCH_CSR_DB5ASID 0x33b /* data breakpoint 5 asid */
|
#define LOONGARCH_CSR_DB5ASID 0x33b /* data breakpoint 5 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DB6ADDR 0x340 /* data breakpoint 6 address */
|
#define LOONGARCH_CSR_DB6ADDR 0x340 /* data breakpoint 6 address */
|
||||||
#define LOONGARCH_CSR_DB6MASK 0x341 /* data breakpoint 6 mask */
|
#define LOONGARCH_CSR_DB6MASK 0x341 /* data breakpoint 6 mask */
|
||||||
#define LOONGARCH_CSR_DB6CTL 0x342 /* data breakpoint 6 control */
|
#define LOONGARCH_CSR_DB6CTRL 0x342 /* data breakpoint 6 control */
|
||||||
#define LOONGARCH_CSR_DB6ASID 0x343 /* data breakpoint 6 asid */
|
#define LOONGARCH_CSR_DB6ASID 0x343 /* data breakpoint 6 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DB7ADDR 0x348 /* data breakpoint 7 address */
|
#define LOONGARCH_CSR_DB7ADDR 0x348 /* data breakpoint 7 address */
|
||||||
#define LOONGARCH_CSR_DB7MASK 0x349 /* data breakpoint 7 mask */
|
#define LOONGARCH_CSR_DB7MASK 0x349 /* data breakpoint 7 mask */
|
||||||
#define LOONGARCH_CSR_DB7CTL 0x34a /* data breakpoint 7 control */
|
#define LOONGARCH_CSR_DB7CTRL 0x34a /* data breakpoint 7 control */
|
||||||
#define LOONGARCH_CSR_DB7ASID 0x34b /* data breakpoint 7 asid */
|
#define LOONGARCH_CSR_DB7ASID 0x34b /* data breakpoint 7 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_FWPC 0x380 /* instruction breakpoint config */
|
#define LOONGARCH_CSR_FWPC 0x380 /* instruction breakpoint config */
|
||||||
@ -1013,48 +1013,51 @@ static __always_inline void iocsr_write64(u64 val, u32 reg)
|
|||||||
|
|
||||||
#define LOONGARCH_CSR_IB0ADDR 0x390 /* inst breakpoint 0 address */
|
#define LOONGARCH_CSR_IB0ADDR 0x390 /* inst breakpoint 0 address */
|
||||||
#define LOONGARCH_CSR_IB0MASK 0x391 /* inst breakpoint 0 mask */
|
#define LOONGARCH_CSR_IB0MASK 0x391 /* inst breakpoint 0 mask */
|
||||||
#define LOONGARCH_CSR_IB0CTL 0x392 /* inst breakpoint 0 control */
|
#define LOONGARCH_CSR_IB0CTRL 0x392 /* inst breakpoint 0 control */
|
||||||
#define LOONGARCH_CSR_IB0ASID 0x393 /* inst breakpoint 0 asid */
|
#define LOONGARCH_CSR_IB0ASID 0x393 /* inst breakpoint 0 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_IB1ADDR 0x398 /* inst breakpoint 1 address */
|
#define LOONGARCH_CSR_IB1ADDR 0x398 /* inst breakpoint 1 address */
|
||||||
#define LOONGARCH_CSR_IB1MASK 0x399 /* inst breakpoint 1 mask */
|
#define LOONGARCH_CSR_IB1MASK 0x399 /* inst breakpoint 1 mask */
|
||||||
#define LOONGARCH_CSR_IB1CTL 0x39a /* inst breakpoint 1 control */
|
#define LOONGARCH_CSR_IB1CTRL 0x39a /* inst breakpoint 1 control */
|
||||||
#define LOONGARCH_CSR_IB1ASID 0x39b /* inst breakpoint 1 asid */
|
#define LOONGARCH_CSR_IB1ASID 0x39b /* inst breakpoint 1 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_IB2ADDR 0x3a0 /* inst breakpoint 2 address */
|
#define LOONGARCH_CSR_IB2ADDR 0x3a0 /* inst breakpoint 2 address */
|
||||||
#define LOONGARCH_CSR_IB2MASK 0x3a1 /* inst breakpoint 2 mask */
|
#define LOONGARCH_CSR_IB2MASK 0x3a1 /* inst breakpoint 2 mask */
|
||||||
#define LOONGARCH_CSR_IB2CTL 0x3a2 /* inst breakpoint 2 control */
|
#define LOONGARCH_CSR_IB2CTRL 0x3a2 /* inst breakpoint 2 control */
|
||||||
#define LOONGARCH_CSR_IB2ASID 0x3a3 /* inst breakpoint 2 asid */
|
#define LOONGARCH_CSR_IB2ASID 0x3a3 /* inst breakpoint 2 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_IB3ADDR 0x3a8 /* inst breakpoint 3 address */
|
#define LOONGARCH_CSR_IB3ADDR 0x3a8 /* inst breakpoint 3 address */
|
||||||
#define LOONGARCH_CSR_IB3MASK 0x3a9 /* breakpoint 3 mask */
|
#define LOONGARCH_CSR_IB3MASK 0x3a9 /* breakpoint 3 mask */
|
||||||
#define LOONGARCH_CSR_IB3CTL 0x3aa /* inst breakpoint 3 control */
|
#define LOONGARCH_CSR_IB3CTRL 0x3aa /* inst breakpoint 3 control */
|
||||||
#define LOONGARCH_CSR_IB3ASID 0x3ab /* inst breakpoint 3 asid */
|
#define LOONGARCH_CSR_IB3ASID 0x3ab /* inst breakpoint 3 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_IB4ADDR 0x3b0 /* inst breakpoint 4 address */
|
#define LOONGARCH_CSR_IB4ADDR 0x3b0 /* inst breakpoint 4 address */
|
||||||
#define LOONGARCH_CSR_IB4MASK 0x3b1 /* inst breakpoint 4 mask */
|
#define LOONGARCH_CSR_IB4MASK 0x3b1 /* inst breakpoint 4 mask */
|
||||||
#define LOONGARCH_CSR_IB4CTL 0x3b2 /* inst breakpoint 4 control */
|
#define LOONGARCH_CSR_IB4CTRL 0x3b2 /* inst breakpoint 4 control */
|
||||||
#define LOONGARCH_CSR_IB4ASID 0x3b3 /* inst breakpoint 4 asid */
|
#define LOONGARCH_CSR_IB4ASID 0x3b3 /* inst breakpoint 4 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_IB5ADDR 0x3b8 /* inst breakpoint 5 address */
|
#define LOONGARCH_CSR_IB5ADDR 0x3b8 /* inst breakpoint 5 address */
|
||||||
#define LOONGARCH_CSR_IB5MASK 0x3b9 /* inst breakpoint 5 mask */
|
#define LOONGARCH_CSR_IB5MASK 0x3b9 /* inst breakpoint 5 mask */
|
||||||
#define LOONGARCH_CSR_IB5CTL 0x3ba /* inst breakpoint 5 control */
|
#define LOONGARCH_CSR_IB5CTRL 0x3ba /* inst breakpoint 5 control */
|
||||||
#define LOONGARCH_CSR_IB5ASID 0x3bb /* inst breakpoint 5 asid */
|
#define LOONGARCH_CSR_IB5ASID 0x3bb /* inst breakpoint 5 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_IB6ADDR 0x3c0 /* inst breakpoint 6 address */
|
#define LOONGARCH_CSR_IB6ADDR 0x3c0 /* inst breakpoint 6 address */
|
||||||
#define LOONGARCH_CSR_IB6MASK 0x3c1 /* inst breakpoint 6 mask */
|
#define LOONGARCH_CSR_IB6MASK 0x3c1 /* inst breakpoint 6 mask */
|
||||||
#define LOONGARCH_CSR_IB6CTL 0x3c2 /* inst breakpoint 6 control */
|
#define LOONGARCH_CSR_IB6CTRL 0x3c2 /* inst breakpoint 6 control */
|
||||||
#define LOONGARCH_CSR_IB6ASID 0x3c3 /* inst breakpoint 6 asid */
|
#define LOONGARCH_CSR_IB6ASID 0x3c3 /* inst breakpoint 6 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_IB7ADDR 0x3c8 /* inst breakpoint 7 address */
|
#define LOONGARCH_CSR_IB7ADDR 0x3c8 /* inst breakpoint 7 address */
|
||||||
#define LOONGARCH_CSR_IB7MASK 0x3c9 /* inst breakpoint 7 mask */
|
#define LOONGARCH_CSR_IB7MASK 0x3c9 /* inst breakpoint 7 mask */
|
||||||
#define LOONGARCH_CSR_IB7CTL 0x3ca /* inst breakpoint 7 control */
|
#define LOONGARCH_CSR_IB7CTRL 0x3ca /* inst breakpoint 7 control */
|
||||||
#define LOONGARCH_CSR_IB7ASID 0x3cb /* inst breakpoint 7 asid */
|
#define LOONGARCH_CSR_IB7ASID 0x3cb /* inst breakpoint 7 asid */
|
||||||
|
|
||||||
#define LOONGARCH_CSR_DEBUG 0x500 /* debug config */
|
#define LOONGARCH_CSR_DEBUG 0x500 /* debug config */
|
||||||
#define LOONGARCH_CSR_DERA 0x501 /* debug era */
|
#define LOONGARCH_CSR_DERA 0x501 /* debug era */
|
||||||
#define LOONGARCH_CSR_DESAVE 0x502 /* debug save */
|
#define LOONGARCH_CSR_DESAVE 0x502 /* debug save */
|
||||||
|
|
||||||
|
#define CSR_FWPC_SKIP_SHIFT 16
|
||||||
|
#define CSR_FWPC_SKIP (_ULCAST_(1) << CSR_FWPC_SKIP_SHIFT)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CSR_ECFG IM
|
* CSR_ECFG IM
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <asm/cpu.h>
|
#include <asm/cpu.h>
|
||||||
#include <asm/cpu-info.h>
|
#include <asm/cpu-info.h>
|
||||||
|
#include <asm/hw_breakpoint.h>
|
||||||
#include <asm/loongarch.h>
|
#include <asm/loongarch.h>
|
||||||
#include <asm/vdso/processor.h>
|
#include <asm/vdso/processor.h>
|
||||||
#include <uapi/asm/ptrace.h>
|
#include <uapi/asm/ptrace.h>
|
||||||
@ -124,13 +125,18 @@ struct thread_struct {
|
|||||||
/* Other stuff associated with the thread. */
|
/* Other stuff associated with the thread. */
|
||||||
unsigned long trap_nr;
|
unsigned long trap_nr;
|
||||||
unsigned long error_code;
|
unsigned long error_code;
|
||||||
|
unsigned long single_step; /* Used by PTRACE_SINGLESTEP */
|
||||||
struct loongarch_vdso_info *vdso;
|
struct loongarch_vdso_info *vdso;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FPU & vector registers, must be at last because
|
* FPU & vector registers, must be at the last of inherited
|
||||||
* they are conditionally copied at fork().
|
* context because they are conditionally copied at fork().
|
||||||
*/
|
*/
|
||||||
struct loongarch_fpu fpu FPU_ALIGN;
|
struct loongarch_fpu fpu FPU_ALIGN;
|
||||||
|
|
||||||
|
/* Hardware breakpoints pinned to this task. */
|
||||||
|
struct perf_event *hbp_break[LOONGARCH_MAX_BRP];
|
||||||
|
struct perf_event *hbp_watch[LOONGARCH_MAX_WRP];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define thread_saved_ra(tsk) (tsk->thread.sched_ra)
|
#define thread_saved_ra(tsk) (tsk->thread.sched_ra)
|
||||||
@ -172,6 +178,8 @@ struct thread_struct {
|
|||||||
.fcc = 0, \
|
.fcc = 0, \
|
||||||
.fpr = {{{0,},},}, \
|
.fpr = {{{0,},},}, \
|
||||||
}, \
|
}, \
|
||||||
|
.hbp_break = {0}, \
|
||||||
|
.hbp_watch = {0}, \
|
||||||
}
|
}
|
||||||
|
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
@ -184,10 +192,6 @@ extern unsigned long boot_option_idle_override;
|
|||||||
*/
|
*/
|
||||||
extern void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp);
|
extern void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp);
|
||||||
|
|
||||||
static inline void flush_thread(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long __get_wchan(struct task_struct *p);
|
unsigned long __get_wchan(struct task_struct *p);
|
||||||
|
|
||||||
#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \
|
#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#define _ASM_PTRACE_H
|
#define _ASM_PTRACE_H
|
||||||
|
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
|
#include <asm/irqflags.h>
|
||||||
#include <asm/thread_info.h>
|
#include <asm/thread_info.h>
|
||||||
#include <uapi/asm/ptrace.h>
|
#include <uapi/asm/ptrace.h>
|
||||||
|
|
||||||
@ -109,6 +110,40 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsi
|
|||||||
|
|
||||||
struct task_struct;
|
struct task_struct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* regs_get_kernel_argument() - get Nth function argument in kernel
|
||||||
|
* @regs: pt_regs of that context
|
||||||
|
* @n: function argument number (start from 0)
|
||||||
|
*
|
||||||
|
* regs_get_argument() returns @n th argument of the function call.
|
||||||
|
* Note that this chooses most probably assignment, in some case
|
||||||
|
* it can be incorrect.
|
||||||
|
* This is expected to be called from kprobes or ftrace with regs
|
||||||
|
* where the top of stack is the return address.
|
||||||
|
*/
|
||||||
|
static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
|
||||||
|
unsigned int n)
|
||||||
|
{
|
||||||
|
#define NR_REG_ARGUMENTS 8
|
||||||
|
static const unsigned int args[] = {
|
||||||
|
offsetof(struct pt_regs, regs[4]),
|
||||||
|
offsetof(struct pt_regs, regs[5]),
|
||||||
|
offsetof(struct pt_regs, regs[6]),
|
||||||
|
offsetof(struct pt_regs, regs[7]),
|
||||||
|
offsetof(struct pt_regs, regs[8]),
|
||||||
|
offsetof(struct pt_regs, regs[9]),
|
||||||
|
offsetof(struct pt_regs, regs[10]),
|
||||||
|
offsetof(struct pt_regs, regs[11]),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (n < NR_REG_ARGUMENTS)
|
||||||
|
return regs_get_register(regs, args[n]);
|
||||||
|
else {
|
||||||
|
n -= NR_REG_ARGUMENTS;
|
||||||
|
return regs_get_kernel_stack_nth(regs, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Does the process account for user or for system time?
|
* Does the process account for user or for system time?
|
||||||
*/
|
*/
|
||||||
@ -149,4 +184,8 @@ static inline void user_stack_pointer_set(struct pt_regs *regs,
|
|||||||
regs->regs[3] = val;
|
regs->regs[3] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||||
|
#define arch_has_single_step() (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _ASM_PTRACE_H */
|
#endif /* _ASM_PTRACE_H */
|
||||||
|
@ -21,4 +21,20 @@ extern void per_cpu_trap_init(int cpu);
|
|||||||
extern void set_handler(unsigned long offset, void *addr, unsigned long len);
|
extern void set_handler(unsigned long offset, void *addr, unsigned long len);
|
||||||
extern void set_merr_handler(unsigned long offset, void *addr, unsigned long len);
|
extern void set_merr_handler(unsigned long offset, void *addr, unsigned long len);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RELOCATABLE
|
||||||
|
|
||||||
|
struct rela_la_abs {
|
||||||
|
long offset;
|
||||||
|
long symvalue;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern long __la_abs_begin;
|
||||||
|
extern long __la_abs_end;
|
||||||
|
extern long __rela_dyn_begin;
|
||||||
|
extern long __rela_dyn_end;
|
||||||
|
|
||||||
|
extern void * __init relocate_kernel(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* __SETUP_H */
|
#endif /* __SETUP_H */
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <linux/threads.h>
|
#include <linux/threads.h>
|
||||||
|
|
||||||
|
#include <asm/addrspace.h>
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
#include <asm/asmmacro.h>
|
#include <asm/asmmacro.h>
|
||||||
#include <asm/asm-offsets.h>
|
#include <asm/asm-offsets.h>
|
||||||
@ -36,6 +37,14 @@
|
|||||||
cfi_restore \reg \offset \docfi
|
cfi_restore \reg \offset \docfi
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
/* Jump to the runtime virtual address. */
|
||||||
|
.macro JUMP_VIRT_ADDR temp1 temp2
|
||||||
|
li.d \temp1, CACHE_BASE
|
||||||
|
pcaddi \temp2, 0
|
||||||
|
or \temp1, \temp1, \temp2
|
||||||
|
jirl zero, \temp1, 0xc
|
||||||
|
.endm
|
||||||
|
|
||||||
.macro BACKUP_T0T1
|
.macro BACKUP_T0T1
|
||||||
csrwr t0, EXCEPTION_KS0
|
csrwr t0, EXCEPTION_KS0
|
||||||
csrwr t1, EXCEPTION_KS1
|
csrwr t1, EXCEPTION_KS1
|
||||||
@ -77,7 +86,7 @@
|
|||||||
* new value in sp.
|
* new value in sp.
|
||||||
*/
|
*/
|
||||||
.macro get_saved_sp docfi=0
|
.macro get_saved_sp docfi=0
|
||||||
la.abs t1, kernelsp
|
la_abs t1, kernelsp
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
csrrd t0, PERCPU_BASE_KS
|
csrrd t0, PERCPU_BASE_KS
|
||||||
LONG_ADD t1, t1, t0
|
LONG_ADD t1, t1, t0
|
||||||
@ -90,7 +99,7 @@
|
|||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro set_saved_sp stackp temp temp2
|
.macro set_saved_sp stackp temp temp2
|
||||||
la.abs \temp, kernelsp
|
la.pcrel \temp, kernelsp
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
LONG_ADD \temp, \temp, u0
|
LONG_ADD \temp, \temp, u0
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,6 +34,7 @@ extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev,
|
|||||||
#define switch_to(prev, next, last) \
|
#define switch_to(prev, next, last) \
|
||||||
do { \
|
do { \
|
||||||
lose_fpu_inatomic(1, prev); \
|
lose_fpu_inatomic(1, prev); \
|
||||||
|
hw_breakpoint_thread_switch(next); \
|
||||||
(last) = __switch_to(prev, next, task_thread_info(next), \
|
(last) = __switch_to(prev, next, task_thread_info(next), \
|
||||||
__builtin_return_address(0), __builtin_frame_address(0)); \
|
__builtin_return_address(0), __builtin_frame_address(0)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
extern u64 __ua_limit;
|
extern u64 __ua_limit;
|
||||||
|
|
||||||
#define __UA_ADDR ".dword"
|
#define __UA_ADDR ".dword"
|
||||||
#define __UA_LA "la.abs"
|
|
||||||
#define __UA_LIMIT __ua_limit
|
#define __UA_LIMIT __ua_limit
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -46,6 +46,15 @@ struct user_fp_state {
|
|||||||
uint32_t fcsr;
|
uint32_t fcsr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct user_watch_state {
|
||||||
|
uint16_t dbg_info;
|
||||||
|
struct {
|
||||||
|
uint64_t addr;
|
||||||
|
uint64_t mask;
|
||||||
|
uint32_t ctrl;
|
||||||
|
} dbg_regs[8];
|
||||||
|
};
|
||||||
|
|
||||||
#define PTRACE_SYSEMU 0x1f
|
#define PTRACE_SYSEMU 0x1f
|
||||||
#define PTRACE_SYSEMU_SINGLESTEP 0x20
|
#define PTRACE_SYSEMU_SINGLESTEP 0x20
|
||||||
|
|
||||||
|
@ -8,13 +8,15 @@ extra-y := vmlinux.lds
|
|||||||
obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
|
obj-y += head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \
|
||||||
traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \
|
traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \
|
||||||
elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \
|
elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \
|
||||||
alternative.o unaligned.o unwind.o
|
alternative.o unwind.o
|
||||||
|
|
||||||
obj-$(CONFIG_ACPI) += acpi.o
|
obj-$(CONFIG_ACPI) += acpi.o
|
||||||
obj-$(CONFIG_EFI) += efi.o
|
obj-$(CONFIG_EFI) += efi.o
|
||||||
|
|
||||||
obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
|
obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_ARCH_STRICT_ALIGN) += unaligned.o
|
||||||
|
|
||||||
ifdef CONFIG_FUNCTION_TRACER
|
ifdef CONFIG_FUNCTION_TRACER
|
||||||
ifndef CONFIG_DYNAMIC_FTRACE
|
ifndef CONFIG_DYNAMIC_FTRACE
|
||||||
obj-y += mcount.o ftrace.o
|
obj-y += mcount.o ftrace.o
|
||||||
@ -39,6 +41,8 @@ obj-$(CONFIG_NUMA) += numa.o
|
|||||||
|
|
||||||
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
|
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_RELOCATABLE) += relocate.o
|
||||||
|
|
||||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
|
||||||
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||||
|
|
||||||
@ -46,5 +50,8 @@ obj-$(CONFIG_UNWINDER_GUESS) += unwind_guess.o
|
|||||||
obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o
|
obj-$(CONFIG_UNWINDER_PROLOGUE) += unwind_prologue.o
|
||||||
|
|
||||||
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o
|
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o
|
||||||
|
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_KPROBES) += kprobes.o kprobes_trampoline.o
|
||||||
|
|
||||||
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
|
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
|
||||||
|
@ -19,70 +19,71 @@
|
|||||||
.cfi_sections .debug_frame
|
.cfi_sections .debug_frame
|
||||||
.align 5
|
.align 5
|
||||||
SYM_FUNC_START(handle_syscall)
|
SYM_FUNC_START(handle_syscall)
|
||||||
csrrd t0, PERCPU_BASE_KS
|
csrrd t0, PERCPU_BASE_KS
|
||||||
la.abs t1, kernelsp
|
la.pcrel t1, kernelsp
|
||||||
add.d t1, t1, t0
|
add.d t1, t1, t0
|
||||||
move t2, sp
|
move t2, sp
|
||||||
ld.d sp, t1, 0
|
ld.d sp, t1, 0
|
||||||
|
|
||||||
addi.d sp, sp, -PT_SIZE
|
addi.d sp, sp, -PT_SIZE
|
||||||
cfi_st t2, PT_R3
|
cfi_st t2, PT_R3
|
||||||
cfi_rel_offset sp, PT_R3
|
cfi_rel_offset sp, PT_R3
|
||||||
st.d zero, sp, PT_R0
|
st.d zero, sp, PT_R0
|
||||||
csrrd t2, LOONGARCH_CSR_PRMD
|
csrrd t2, LOONGARCH_CSR_PRMD
|
||||||
st.d t2, sp, PT_PRMD
|
st.d t2, sp, PT_PRMD
|
||||||
csrrd t2, LOONGARCH_CSR_CRMD
|
csrrd t2, LOONGARCH_CSR_CRMD
|
||||||
st.d t2, sp, PT_CRMD
|
st.d t2, sp, PT_CRMD
|
||||||
csrrd t2, LOONGARCH_CSR_EUEN
|
csrrd t2, LOONGARCH_CSR_EUEN
|
||||||
st.d t2, sp, PT_EUEN
|
st.d t2, sp, PT_EUEN
|
||||||
csrrd t2, LOONGARCH_CSR_ECFG
|
csrrd t2, LOONGARCH_CSR_ECFG
|
||||||
st.d t2, sp, PT_ECFG
|
st.d t2, sp, PT_ECFG
|
||||||
csrrd t2, LOONGARCH_CSR_ESTAT
|
csrrd t2, LOONGARCH_CSR_ESTAT
|
||||||
st.d t2, sp, PT_ESTAT
|
st.d t2, sp, PT_ESTAT
|
||||||
cfi_st ra, PT_R1
|
cfi_st ra, PT_R1
|
||||||
cfi_st a0, PT_R4
|
cfi_st a0, PT_R4
|
||||||
cfi_st a1, PT_R5
|
cfi_st a1, PT_R5
|
||||||
cfi_st a2, PT_R6
|
cfi_st a2, PT_R6
|
||||||
cfi_st a3, PT_R7
|
cfi_st a3, PT_R7
|
||||||
cfi_st a4, PT_R8
|
cfi_st a4, PT_R8
|
||||||
cfi_st a5, PT_R9
|
cfi_st a5, PT_R9
|
||||||
cfi_st a6, PT_R10
|
cfi_st a6, PT_R10
|
||||||
cfi_st a7, PT_R11
|
cfi_st a7, PT_R11
|
||||||
csrrd ra, LOONGARCH_CSR_ERA
|
csrrd ra, LOONGARCH_CSR_ERA
|
||||||
st.d ra, sp, PT_ERA
|
st.d ra, sp, PT_ERA
|
||||||
cfi_rel_offset ra, PT_ERA
|
cfi_rel_offset ra, PT_ERA
|
||||||
|
|
||||||
cfi_st tp, PT_R2
|
cfi_st tp, PT_R2
|
||||||
cfi_st u0, PT_R21
|
cfi_st u0, PT_R21
|
||||||
cfi_st fp, PT_R22
|
cfi_st fp, PT_R22
|
||||||
|
|
||||||
SAVE_STATIC
|
SAVE_STATIC
|
||||||
|
|
||||||
move u0, t0
|
move u0, t0
|
||||||
li.d tp, ~_THREAD_MASK
|
li.d tp, ~_THREAD_MASK
|
||||||
and tp, tp, sp
|
and tp, tp, sp
|
||||||
|
|
||||||
move a0, sp
|
move a0, sp
|
||||||
bl do_syscall
|
bl do_syscall
|
||||||
|
|
||||||
RESTORE_ALL_AND_RET
|
RESTORE_ALL_AND_RET
|
||||||
SYM_FUNC_END(handle_syscall)
|
SYM_FUNC_END(handle_syscall)
|
||||||
|
_ASM_NOKPROBE(handle_syscall)
|
||||||
|
|
||||||
SYM_CODE_START(ret_from_fork)
|
SYM_CODE_START(ret_from_fork)
|
||||||
bl schedule_tail # a0 = struct task_struct *prev
|
bl schedule_tail # a0 = struct task_struct *prev
|
||||||
move a0, sp
|
move a0, sp
|
||||||
bl syscall_exit_to_user_mode
|
bl syscall_exit_to_user_mode
|
||||||
RESTORE_STATIC
|
RESTORE_STATIC
|
||||||
RESTORE_SOME
|
RESTORE_SOME
|
||||||
RESTORE_SP_AND_RET
|
RESTORE_SP_AND_RET
|
||||||
SYM_CODE_END(ret_from_fork)
|
SYM_CODE_END(ret_from_fork)
|
||||||
|
|
||||||
SYM_CODE_START(ret_from_kernel_thread)
|
SYM_CODE_START(ret_from_kernel_thread)
|
||||||
bl schedule_tail # a0 = struct task_struct *prev
|
bl schedule_tail # a0 = struct task_struct *prev
|
||||||
move a0, s1
|
move a0, s1
|
||||||
jirl ra, s0, 0
|
jirl ra, s0, 0
|
||||||
move a0, sp
|
move a0, sp
|
||||||
bl syscall_exit_to_user_mode
|
bl syscall_exit_to_user_mode
|
||||||
RESTORE_STATIC
|
RESTORE_STATIC
|
||||||
RESTORE_SOME
|
RESTORE_SOME
|
||||||
RESTORE_SP_AND_RET
|
RESTORE_SP_AND_RET
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/ftrace.h>
|
#include <linux/ftrace.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
#include <asm/inst.h>
|
#include <asm/inst.h>
|
||||||
@ -271,3 +272,66 @@ int ftrace_disable_ftrace_graph_caller(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
|
#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
|
||||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||||
|
|
||||||
|
#ifdef CONFIG_KPROBES_ON_FTRACE
|
||||||
|
/* Ftrace callback handler for kprobes -- called under preepmt disabled */
|
||||||
|
void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
|
||||||
|
struct ftrace_ops *ops, struct ftrace_regs *fregs)
|
||||||
|
{
|
||||||
|
int bit;
|
||||||
|
struct pt_regs *regs;
|
||||||
|
struct kprobe *p;
|
||||||
|
struct kprobe_ctlblk *kcb;
|
||||||
|
|
||||||
|
bit = ftrace_test_recursion_trylock(ip, parent_ip);
|
||||||
|
if (bit < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
p = get_kprobe((kprobe_opcode_t *)ip);
|
||||||
|
if (unlikely(!p) || kprobe_disabled(p))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
regs = ftrace_get_regs(fregs);
|
||||||
|
if (!regs)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
kcb = get_kprobe_ctlblk();
|
||||||
|
if (kprobe_running()) {
|
||||||
|
kprobes_inc_nmissed_count(p);
|
||||||
|
} else {
|
||||||
|
unsigned long orig_ip = instruction_pointer(regs);
|
||||||
|
|
||||||
|
instruction_pointer_set(regs, ip);
|
||||||
|
|
||||||
|
__this_cpu_write(current_kprobe, p);
|
||||||
|
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||||
|
if (!p->pre_handler || !p->pre_handler(p, regs)) {
|
||||||
|
/*
|
||||||
|
* Emulate singlestep (and also recover regs->csr_era)
|
||||||
|
* as if there is a nop
|
||||||
|
*/
|
||||||
|
instruction_pointer_set(regs, (unsigned long)p->addr + MCOUNT_INSN_SIZE);
|
||||||
|
if (unlikely(p->post_handler)) {
|
||||||
|
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||||
|
p->post_handler(p, regs, 0);
|
||||||
|
}
|
||||||
|
instruction_pointer_set(regs, orig_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If pre_handler returns !0, it changes regs->csr_era. We have to
|
||||||
|
* skip emulating post_handler.
|
||||||
|
*/
|
||||||
|
__this_cpu_write(current_kprobe, NULL);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
ftrace_test_recursion_unlock(bit);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(kprobe_ftrace_handler);
|
||||||
|
|
||||||
|
int arch_prepare_kprobe_ftrace(struct kprobe *p)
|
||||||
|
{
|
||||||
|
p->ainsn.insn = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_KPROBES_ON_FTRACE */
|
||||||
|
@ -34,7 +34,7 @@ SYM_FUNC_END(__arch_cpu_idle)
|
|||||||
SYM_FUNC_START(handle_vint)
|
SYM_FUNC_START(handle_vint)
|
||||||
BACKUP_T0T1
|
BACKUP_T0T1
|
||||||
SAVE_ALL
|
SAVE_ALL
|
||||||
la.abs t1, __arch_cpu_idle
|
la_abs t1, __arch_cpu_idle
|
||||||
LONG_L t0, sp, PT_ERA
|
LONG_L t0, sp, PT_ERA
|
||||||
/* 32 byte rollback region */
|
/* 32 byte rollback region */
|
||||||
ori t0, t0, 0x1f
|
ori t0, t0, 0x1f
|
||||||
@ -43,7 +43,7 @@ SYM_FUNC_START(handle_vint)
|
|||||||
LONG_S t0, sp, PT_ERA
|
LONG_S t0, sp, PT_ERA
|
||||||
1: move a0, sp
|
1: move a0, sp
|
||||||
move a1, sp
|
move a1, sp
|
||||||
la.abs t0, do_vint
|
la_abs t0, do_vint
|
||||||
jirl ra, t0, 0
|
jirl ra, t0, 0
|
||||||
RESTORE_ALL_AND_RET
|
RESTORE_ALL_AND_RET
|
||||||
SYM_FUNC_END(handle_vint)
|
SYM_FUNC_END(handle_vint)
|
||||||
@ -72,7 +72,7 @@ SYM_FUNC_END(except_vec_cex)
|
|||||||
SAVE_ALL
|
SAVE_ALL
|
||||||
build_prep_\prep
|
build_prep_\prep
|
||||||
move a0, sp
|
move a0, sp
|
||||||
la.abs t0, do_\handler
|
la_abs t0, do_\handler
|
||||||
jirl ra, t0, 0
|
jirl ra, t0, 0
|
||||||
668:
|
668:
|
||||||
RESTORE_ALL_AND_RET
|
RESTORE_ALL_AND_RET
|
||||||
@ -93,6 +93,6 @@ SYM_FUNC_END(except_vec_cex)
|
|||||||
BUILD_HANDLER reserved reserved none /* others */
|
BUILD_HANDLER reserved reserved none /* others */
|
||||||
|
|
||||||
SYM_FUNC_START(handle_sys)
|
SYM_FUNC_START(handle_sys)
|
||||||
la.abs t0, handle_syscall
|
la_abs t0, handle_syscall
|
||||||
jr t0
|
jr t0
|
||||||
SYM_FUNC_END(handle_sys)
|
SYM_FUNC_END(handle_sys)
|
||||||
|
@ -24,7 +24,7 @@ _head:
|
|||||||
.org 0x8
|
.org 0x8
|
||||||
.dword kernel_entry /* Kernel entry point */
|
.dword kernel_entry /* Kernel entry point */
|
||||||
.dword _end - _text /* Kernel image effective size */
|
.dword _end - _text /* Kernel image effective size */
|
||||||
.quad 0 /* Kernel image load offset from start of RAM */
|
.quad PHYS_LINK_KADDR /* Kernel image load offset from start of RAM */
|
||||||
.org 0x38 /* 0x20 ~ 0x37 reserved */
|
.org 0x38 /* 0x20 ~ 0x37 reserved */
|
||||||
.long LINUX_PE_MAGIC
|
.long LINUX_PE_MAGIC
|
||||||
.long pe_header - _head /* Offset to the PE header */
|
.long pe_header - _head /* Offset to the PE header */
|
||||||
@ -50,11 +50,8 @@ SYM_CODE_START(kernel_entry) # kernel entry point
|
|||||||
li.d t0, CSR_DMW1_INIT # CA, PLV0, 0x9000 xxxx xxxx xxxx
|
li.d t0, CSR_DMW1_INIT # CA, PLV0, 0x9000 xxxx xxxx xxxx
|
||||||
csrwr t0, LOONGARCH_CSR_DMWIN1
|
csrwr t0, LOONGARCH_CSR_DMWIN1
|
||||||
|
|
||||||
/* We might not get launched at the address the kernel is linked to,
|
JUMP_VIRT_ADDR t0, t1
|
||||||
so we jump there. */
|
|
||||||
la.abs t0, 0f
|
|
||||||
jr t0
|
|
||||||
0:
|
|
||||||
/* Enable PG */
|
/* Enable PG */
|
||||||
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
|
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
|
||||||
csrwr t0, LOONGARCH_CSR_CRMD
|
csrwr t0, LOONGARCH_CSR_CRMD
|
||||||
@ -89,6 +86,23 @@ SYM_CODE_START(kernel_entry) # kernel entry point
|
|||||||
PTR_ADD sp, sp, tp
|
PTR_ADD sp, sp, tp
|
||||||
set_saved_sp sp, t0, t1
|
set_saved_sp sp, t0, t1
|
||||||
|
|
||||||
|
#ifdef CONFIG_RELOCATABLE
|
||||||
|
|
||||||
|
bl relocate_kernel
|
||||||
|
|
||||||
|
#ifdef CONFIG_RANDOMIZE_BASE
|
||||||
|
/* Repoint the sp into the new kernel */
|
||||||
|
PTR_LI sp, (_THREAD_SIZE - PT_SIZE)
|
||||||
|
PTR_ADD sp, sp, tp
|
||||||
|
set_saved_sp sp, t0, t1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* relocate_kernel() returns the new kernel entry point */
|
||||||
|
jr a0
|
||||||
|
ASM_BUG()
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
bl start_kernel
|
bl start_kernel
|
||||||
ASM_BUG()
|
ASM_BUG()
|
||||||
|
|
||||||
@ -106,9 +120,8 @@ SYM_CODE_START(smpboot_entry)
|
|||||||
li.d t0, CSR_DMW1_INIT # CA, PLV0
|
li.d t0, CSR_DMW1_INIT # CA, PLV0
|
||||||
csrwr t0, LOONGARCH_CSR_DMWIN1
|
csrwr t0, LOONGARCH_CSR_DMWIN1
|
||||||
|
|
||||||
la.abs t0, 0f
|
JUMP_VIRT_ADDR t0, t1
|
||||||
jr t0
|
|
||||||
0:
|
|
||||||
/* Enable PG */
|
/* Enable PG */
|
||||||
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
|
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
|
||||||
csrwr t0, LOONGARCH_CSR_CRMD
|
csrwr t0, LOONGARCH_CSR_CRMD
|
||||||
@ -117,7 +130,7 @@ SYM_CODE_START(smpboot_entry)
|
|||||||
li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
|
li.w t0, 0x00 # FPE=0, SXE=0, ASXE=0, BTE=0
|
||||||
csrwr t0, LOONGARCH_CSR_EUEN
|
csrwr t0, LOONGARCH_CSR_EUEN
|
||||||
|
|
||||||
la.abs t0, cpuboot_data
|
la.pcrel t0, cpuboot_data
|
||||||
ld.d sp, t0, CPU_BOOT_STACK
|
ld.d sp, t0, CPU_BOOT_STACK
|
||||||
ld.d tp, t0, CPU_BOOT_TINFO
|
ld.d tp, t0, CPU_BOOT_TINFO
|
||||||
|
|
||||||
|
548
arch/loongarch/kernel/hw_breakpoint.c
Normal file
548
arch/loongarch/kernel/hw_breakpoint.c
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022-2023 Loongson Technology Corporation Limited
|
||||||
|
*/
|
||||||
|
#define pr_fmt(fmt) "hw-breakpoint: " fmt
|
||||||
|
|
||||||
|
#include <linux/hw_breakpoint.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
|
#include <linux/perf_event.h>
|
||||||
|
|
||||||
|
#include <asm/hw_breakpoint.h>
|
||||||
|
|
||||||
|
/* Breakpoint currently in use for each BRP. */
|
||||||
|
static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[LOONGARCH_MAX_BRP]);
|
||||||
|
|
||||||
|
/* Watchpoint currently in use for each WRP. */
|
||||||
|
static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[LOONGARCH_MAX_WRP]);
|
||||||
|
|
||||||
|
int hw_breakpoint_slots(int type)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We can be called early, so don't rely on
|
||||||
|
* our static variables being initialised.
|
||||||
|
*/
|
||||||
|
switch (type) {
|
||||||
|
case TYPE_INST:
|
||||||
|
return get_num_brps();
|
||||||
|
case TYPE_DATA:
|
||||||
|
return get_num_wrps();
|
||||||
|
default:
|
||||||
|
pr_warn("unknown slot type: %d\n", type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define READ_WB_REG_CASE(OFF, N, REG, T, VAL) \
|
||||||
|
case (OFF + N): \
|
||||||
|
LOONGARCH_CSR_WATCH_READ(N, REG, T, VAL); \
|
||||||
|
break
|
||||||
|
|
||||||
|
#define WRITE_WB_REG_CASE(OFF, N, REG, T, VAL) \
|
||||||
|
case (OFF + N): \
|
||||||
|
LOONGARCH_CSR_WATCH_WRITE(N, REG, T, VAL); \
|
||||||
|
break
|
||||||
|
|
||||||
|
#define GEN_READ_WB_REG_CASES(OFF, REG, T, VAL) \
|
||||||
|
READ_WB_REG_CASE(OFF, 0, REG, T, VAL); \
|
||||||
|
READ_WB_REG_CASE(OFF, 1, REG, T, VAL); \
|
||||||
|
READ_WB_REG_CASE(OFF, 2, REG, T, VAL); \
|
||||||
|
READ_WB_REG_CASE(OFF, 3, REG, T, VAL); \
|
||||||
|
READ_WB_REG_CASE(OFF, 4, REG, T, VAL); \
|
||||||
|
READ_WB_REG_CASE(OFF, 5, REG, T, VAL); \
|
||||||
|
READ_WB_REG_CASE(OFF, 6, REG, T, VAL); \
|
||||||
|
READ_WB_REG_CASE(OFF, 7, REG, T, VAL);
|
||||||
|
|
||||||
|
#define GEN_WRITE_WB_REG_CASES(OFF, REG, T, VAL) \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 0, REG, T, VAL); \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 1, REG, T, VAL); \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 2, REG, T, VAL); \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 3, REG, T, VAL); \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 4, REG, T, VAL); \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 5, REG, T, VAL); \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 6, REG, T, VAL); \
|
||||||
|
WRITE_WB_REG_CASE(OFF, 7, REG, T, VAL);
|
||||||
|
|
||||||
|
static u64 read_wb_reg(int reg, int n, int t)
|
||||||
|
{
|
||||||
|
u64 val = 0;
|
||||||
|
|
||||||
|
switch (reg + n) {
|
||||||
|
GEN_READ_WB_REG_CASES(CSR_CFG_ADDR, ADDR, t, val);
|
||||||
|
GEN_READ_WB_REG_CASES(CSR_CFG_MASK, MASK, t, val);
|
||||||
|
GEN_READ_WB_REG_CASES(CSR_CFG_CTRL, CTRL, t, val);
|
||||||
|
GEN_READ_WB_REG_CASES(CSR_CFG_ASID, ASID, t, val);
|
||||||
|
default:
|
||||||
|
pr_warn("Attempt to read from unknown breakpoint register %d\n", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(read_wb_reg);
|
||||||
|
|
||||||
|
static void write_wb_reg(int reg, int n, int t, u64 val)
|
||||||
|
{
|
||||||
|
switch (reg + n) {
|
||||||
|
GEN_WRITE_WB_REG_CASES(CSR_CFG_ADDR, ADDR, t, val);
|
||||||
|
GEN_WRITE_WB_REG_CASES(CSR_CFG_MASK, MASK, t, val);
|
||||||
|
GEN_WRITE_WB_REG_CASES(CSR_CFG_CTRL, CTRL, t, val);
|
||||||
|
GEN_WRITE_WB_REG_CASES(CSR_CFG_ASID, ASID, t, val);
|
||||||
|
default:
|
||||||
|
pr_warn("Attempt to write to unknown breakpoint register %d\n", n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(write_wb_reg);
|
||||||
|
|
||||||
|
enum hw_breakpoint_ops {
|
||||||
|
HW_BREAKPOINT_INSTALL,
|
||||||
|
HW_BREAKPOINT_UNINSTALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hw_breakpoint_slot_setup - Find and setup a perf slot according to operations
|
||||||
|
*
|
||||||
|
* @slots: pointer to array of slots
|
||||||
|
* @max_slots: max number of slots
|
||||||
|
* @bp: perf_event to setup
|
||||||
|
* @ops: operation to be carried out on the slot
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* slot index on success
|
||||||
|
* -ENOSPC if no slot is available/matches
|
||||||
|
* -EINVAL on wrong operations parameter
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int hw_breakpoint_slot_setup(struct perf_event **slots, int max_slots,
|
||||||
|
struct perf_event *bp, enum hw_breakpoint_ops ops)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct perf_event **slot;
|
||||||
|
|
||||||
|
for (i = 0; i < max_slots; ++i) {
|
||||||
|
slot = &slots[i];
|
||||||
|
switch (ops) {
|
||||||
|
case HW_BREAKPOINT_INSTALL:
|
||||||
|
if (!*slot) {
|
||||||
|
*slot = bp;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_UNINSTALL:
|
||||||
|
if (*slot == bp) {
|
||||||
|
*slot = NULL;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_warn_once("Unhandled hw breakpoint ops %d\n", ops);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptrace_hw_copy_thread(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
memset(tsk->thread.hbp_break, 0, sizeof(tsk->thread.hbp_break));
|
||||||
|
memset(tsk->thread.hbp_watch, 0, sizeof(tsk->thread.hbp_watch));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unregister breakpoints from this task and reset the pointers in the thread_struct.
|
||||||
|
*/
|
||||||
|
void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct thread_struct *t = &tsk->thread;
|
||||||
|
|
||||||
|
for (i = 0; i < LOONGARCH_MAX_BRP; i++) {
|
||||||
|
if (t->hbp_break[i]) {
|
||||||
|
unregister_hw_breakpoint(t->hbp_break[i]);
|
||||||
|
t->hbp_break[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < LOONGARCH_MAX_WRP; i++) {
|
||||||
|
if (t->hbp_watch[i]) {
|
||||||
|
unregister_hw_breakpoint(t->hbp_watch[i]);
|
||||||
|
t->hbp_watch[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hw_breakpoint_control(struct perf_event *bp,
|
||||||
|
enum hw_breakpoint_ops ops)
|
||||||
|
{
|
||||||
|
u32 ctrl;
|
||||||
|
int i, max_slots, enable;
|
||||||
|
struct perf_event **slots;
|
||||||
|
struct arch_hw_breakpoint *info = counter_arch_bp(bp);
|
||||||
|
|
||||||
|
if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
|
||||||
|
/* Breakpoint */
|
||||||
|
slots = this_cpu_ptr(bp_on_reg);
|
||||||
|
max_slots = boot_cpu_data.watch_ireg_count;
|
||||||
|
} else {
|
||||||
|
/* Watchpoint */
|
||||||
|
slots = this_cpu_ptr(wp_on_reg);
|
||||||
|
max_slots = boot_cpu_data.watch_dreg_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = hw_breakpoint_slot_setup(slots, max_slots, bp, ops);
|
||||||
|
|
||||||
|
if (WARN_ONCE(i < 0, "Can't find any breakpoint slot"))
|
||||||
|
return i;
|
||||||
|
|
||||||
|
switch (ops) {
|
||||||
|
case HW_BREAKPOINT_INSTALL:
|
||||||
|
/* Set the FWPnCFG/MWPnCFG 1~4 register. */
|
||||||
|
write_wb_reg(CSR_CFG_ADDR, i, 0, info->address);
|
||||||
|
write_wb_reg(CSR_CFG_ADDR, i, 1, info->address);
|
||||||
|
write_wb_reg(CSR_CFG_MASK, i, 0, info->mask);
|
||||||
|
write_wb_reg(CSR_CFG_MASK, i, 1, info->mask);
|
||||||
|
write_wb_reg(CSR_CFG_ASID, i, 0, 0);
|
||||||
|
write_wb_reg(CSR_CFG_ASID, i, 1, 0);
|
||||||
|
if (info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) {
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
|
||||||
|
} else {
|
||||||
|
ctrl = encode_ctrl_reg(info->ctrl);
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl | CTRL_PLV_ENABLE |
|
||||||
|
1 << MWPnCFG3_LoadEn | 1 << MWPnCFG3_StoreEn);
|
||||||
|
}
|
||||||
|
enable = csr_read64(LOONGARCH_CSR_CRMD);
|
||||||
|
csr_write64(CSR_CRMD_WE | enable, LOONGARCH_CSR_CRMD);
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_UNINSTALL:
|
||||||
|
/* Reset the FWPnCFG/MWPnCFG 1~4 register. */
|
||||||
|
write_wb_reg(CSR_CFG_ADDR, i, 0, 0);
|
||||||
|
write_wb_reg(CSR_CFG_ADDR, i, 1, 0);
|
||||||
|
write_wb_reg(CSR_CFG_MASK, i, 0, 0);
|
||||||
|
write_wb_reg(CSR_CFG_MASK, i, 1, 0);
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 0, 0);
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 1, 0);
|
||||||
|
write_wb_reg(CSR_CFG_ASID, i, 0, 0);
|
||||||
|
write_wb_reg(CSR_CFG_ASID, i, 1, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Install a perf counter breakpoint.
|
||||||
|
*/
|
||||||
|
int arch_install_hw_breakpoint(struct perf_event *bp)
|
||||||
|
{
|
||||||
|
return hw_breakpoint_control(bp, HW_BREAKPOINT_INSTALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void arch_uninstall_hw_breakpoint(struct perf_event *bp)
|
||||||
|
{
|
||||||
|
hw_breakpoint_control(bp, HW_BREAKPOINT_UNINSTALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_hbp_len(u8 hbp_len)
|
||||||
|
{
|
||||||
|
unsigned int len_in_bytes = 0;
|
||||||
|
|
||||||
|
switch (hbp_len) {
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_1:
|
||||||
|
len_in_bytes = 1;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_2:
|
||||||
|
len_in_bytes = 2;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_4:
|
||||||
|
len_in_bytes = 4;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_8:
|
||||||
|
len_in_bytes = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len_in_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether bp virtual address is in kernel space.
|
||||||
|
*/
|
||||||
|
int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw)
|
||||||
|
{
|
||||||
|
unsigned int len;
|
||||||
|
unsigned long va;
|
||||||
|
|
||||||
|
va = hw->address;
|
||||||
|
len = get_hbp_len(hw->ctrl.len);
|
||||||
|
|
||||||
|
return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract generic type and length encodings from an arch_hw_breakpoint_ctrl.
|
||||||
|
* Hopefully this will disappear when ptrace can bypass the conversion
|
||||||
|
* to generic breakpoint descriptions.
|
||||||
|
*/
|
||||||
|
int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
|
||||||
|
int *gen_len, int *gen_type, int *offset)
|
||||||
|
{
|
||||||
|
/* Type */
|
||||||
|
switch (ctrl.type) {
|
||||||
|
case LOONGARCH_BREAKPOINT_EXECUTE:
|
||||||
|
*gen_type = HW_BREAKPOINT_X;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LOAD:
|
||||||
|
*gen_type = HW_BREAKPOINT_R;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_STORE:
|
||||||
|
*gen_type = HW_BREAKPOINT_W;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LOAD | LOONGARCH_BREAKPOINT_STORE:
|
||||||
|
*gen_type = HW_BREAKPOINT_RW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctrl.len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*offset = __ffs(ctrl.len);
|
||||||
|
|
||||||
|
/* Len */
|
||||||
|
switch (ctrl.len) {
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_1:
|
||||||
|
*gen_len = HW_BREAKPOINT_LEN_1;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_2:
|
||||||
|
*gen_len = HW_BREAKPOINT_LEN_2;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_4:
|
||||||
|
*gen_len = HW_BREAKPOINT_LEN_4;
|
||||||
|
break;
|
||||||
|
case LOONGARCH_BREAKPOINT_LEN_8:
|
||||||
|
*gen_len = HW_BREAKPOINT_LEN_8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct an arch_hw_breakpoint from a perf_event.
|
||||||
|
*/
|
||||||
|
static int arch_build_bp_info(struct perf_event *bp,
|
||||||
|
const struct perf_event_attr *attr,
|
||||||
|
struct arch_hw_breakpoint *hw)
|
||||||
|
{
|
||||||
|
/* Type */
|
||||||
|
switch (attr->bp_type) {
|
||||||
|
case HW_BREAKPOINT_X:
|
||||||
|
hw->ctrl.type = LOONGARCH_BREAKPOINT_EXECUTE;
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_R:
|
||||||
|
hw->ctrl.type = LOONGARCH_BREAKPOINT_LOAD;
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_W:
|
||||||
|
hw->ctrl.type = LOONGARCH_BREAKPOINT_STORE;
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_RW:
|
||||||
|
hw->ctrl.type = LOONGARCH_BREAKPOINT_LOAD | LOONGARCH_BREAKPOINT_STORE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Len */
|
||||||
|
switch (attr->bp_len) {
|
||||||
|
case HW_BREAKPOINT_LEN_1:
|
||||||
|
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_1;
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_LEN_2:
|
||||||
|
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_2;
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_LEN_4:
|
||||||
|
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_4;
|
||||||
|
break;
|
||||||
|
case HW_BREAKPOINT_LEN_8:
|
||||||
|
hw->ctrl.len = LOONGARCH_BREAKPOINT_LEN_8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Address */
|
||||||
|
hw->address = attr->bp_addr;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate the arch-specific HW Breakpoint register settings.
|
||||||
|
*/
|
||||||
|
int hw_breakpoint_arch_parse(struct perf_event *bp,
|
||||||
|
const struct perf_event_attr *attr,
|
||||||
|
struct arch_hw_breakpoint *hw)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u64 alignment_mask, offset;
|
||||||
|
|
||||||
|
/* Build the arch_hw_breakpoint. */
|
||||||
|
ret = arch_build_bp_info(bp, attr, hw);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (hw->ctrl.type != LOONGARCH_BREAKPOINT_EXECUTE)
|
||||||
|
alignment_mask = 0x7;
|
||||||
|
offset = hw->address & alignment_mask;
|
||||||
|
|
||||||
|
hw->address &= ~alignment_mask;
|
||||||
|
hw->ctrl.len <<= offset;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_bp_registers(struct pt_regs *regs, int enable, int type)
|
||||||
|
{
|
||||||
|
u32 ctrl;
|
||||||
|
int i, max_slots;
|
||||||
|
struct perf_event **slots;
|
||||||
|
struct arch_hw_breakpoint *info;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
slots = this_cpu_ptr(bp_on_reg);
|
||||||
|
max_slots = boot_cpu_data.watch_ireg_count;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
slots = this_cpu_ptr(wp_on_reg);
|
||||||
|
max_slots = boot_cpu_data.watch_dreg_count;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < max_slots; ++i) {
|
||||||
|
if (!slots[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
info = counter_arch_bp(slots[i]);
|
||||||
|
if (enable) {
|
||||||
|
if ((info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) && (type == 0)) {
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 0, CTRL_PLV_ENABLE);
|
||||||
|
} else {
|
||||||
|
ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1);
|
||||||
|
if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD)
|
||||||
|
ctrl |= 0x1 << MWPnCFG3_LoadEn;
|
||||||
|
if (info->ctrl.type == LOONGARCH_BREAKPOINT_STORE)
|
||||||
|
ctrl |= 0x1 << MWPnCFG3_StoreEn;
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl);
|
||||||
|
}
|
||||||
|
regs->csr_prmd |= CSR_PRMD_PWE;
|
||||||
|
} else {
|
||||||
|
if ((info->ctrl.type == LOONGARCH_BREAKPOINT_EXECUTE) && (type == 0)) {
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 0, 0);
|
||||||
|
} else {
|
||||||
|
ctrl = read_wb_reg(CSR_CFG_CTRL, i, 1);
|
||||||
|
if (info->ctrl.type == LOONGARCH_BREAKPOINT_LOAD)
|
||||||
|
ctrl &= ~0x1 << MWPnCFG3_LoadEn;
|
||||||
|
if (info->ctrl.type == LOONGARCH_BREAKPOINT_STORE)
|
||||||
|
ctrl &= ~0x1 << MWPnCFG3_StoreEn;
|
||||||
|
write_wb_reg(CSR_CFG_CTRL, i, 1, ctrl);
|
||||||
|
}
|
||||||
|
regs->csr_prmd &= ~CSR_PRMD_PWE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(update_bp_registers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug exception handlers.
|
||||||
|
*/
|
||||||
|
void breakpoint_handler(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct perf_event *bp, **slots;
|
||||||
|
|
||||||
|
slots = this_cpu_ptr(bp_on_reg);
|
||||||
|
|
||||||
|
for (i = 0; i < boot_cpu_data.watch_ireg_count; ++i) {
|
||||||
|
bp = slots[i];
|
||||||
|
if (bp == NULL)
|
||||||
|
continue;
|
||||||
|
perf_bp_event(bp, regs);
|
||||||
|
}
|
||||||
|
update_bp_registers(regs, 0, 0);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(breakpoint_handler);
|
||||||
|
|
||||||
|
void watchpoint_handler(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct perf_event *wp, **slots;
|
||||||
|
|
||||||
|
slots = this_cpu_ptr(wp_on_reg);
|
||||||
|
|
||||||
|
for (i = 0; i < boot_cpu_data.watch_dreg_count; ++i) {
|
||||||
|
wp = slots[i];
|
||||||
|
if (wp == NULL)
|
||||||
|
continue;
|
||||||
|
perf_bp_event(wp, regs);
|
||||||
|
}
|
||||||
|
update_bp_registers(regs, 0, 1);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(watchpoint_handler);
|
||||||
|
|
||||||
|
static int __init arch_hw_breakpoint_init(void)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
boot_cpu_data.watch_ireg_count = get_num_brps();
|
||||||
|
boot_cpu_data.watch_dreg_count = get_num_wrps();
|
||||||
|
|
||||||
|
pr_info("Found %d breakpoint and %d watchpoint registers.\n",
|
||||||
|
boot_cpu_data.watch_ireg_count, boot_cpu_data.watch_dreg_count);
|
||||||
|
|
||||||
|
for (cpu = 1; cpu < NR_CPUS; cpu++) {
|
||||||
|
cpu_data[cpu].watch_ireg_count = boot_cpu_data.watch_ireg_count;
|
||||||
|
cpu_data[cpu].watch_dreg_count = boot_cpu_data.watch_dreg_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
arch_initcall(arch_hw_breakpoint_init);
|
||||||
|
|
||||||
|
void hw_breakpoint_thread_switch(struct task_struct *next)
|
||||||
|
{
|
||||||
|
u64 addr, mask;
|
||||||
|
struct pt_regs *regs = task_pt_regs(next);
|
||||||
|
|
||||||
|
if (test_tsk_thread_flag(next, TIF_SINGLESTEP)) {
|
||||||
|
addr = read_wb_reg(CSR_CFG_ADDR, 0, 0);
|
||||||
|
mask = read_wb_reg(CSR_CFG_MASK, 0, 0);
|
||||||
|
if (!((regs->csr_era ^ addr) & ~mask))
|
||||||
|
csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS);
|
||||||
|
regs->csr_prmd |= CSR_PRMD_PWE;
|
||||||
|
} else {
|
||||||
|
/* Update breakpoints */
|
||||||
|
update_bp_registers(regs, 1, 0);
|
||||||
|
/* Update watchpoints */
|
||||||
|
update_bp_registers(regs, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hw_breakpoint_pmu_read(struct perf_event *bp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy function to register with die_notifier.
|
||||||
|
*/
|
||||||
|
int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
|
||||||
|
unsigned long val, void *data)
|
||||||
|
{
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
@ -10,6 +10,129 @@
|
|||||||
|
|
||||||
static DEFINE_RAW_SPINLOCK(patch_lock);
|
static DEFINE_RAW_SPINLOCK(patch_lock);
|
||||||
|
|
||||||
|
void simu_pc(struct pt_regs *regs, union loongarch_instruction insn)
|
||||||
|
{
|
||||||
|
unsigned long pc = regs->csr_era;
|
||||||
|
unsigned int rd = insn.reg1i20_format.rd;
|
||||||
|
unsigned int imm = insn.reg1i20_format.immediate;
|
||||||
|
|
||||||
|
if (pc & 3) {
|
||||||
|
pr_warn("%s: invalid pc 0x%lx\n", __func__, pc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (insn.reg1i20_format.opcode) {
|
||||||
|
case pcaddi_op:
|
||||||
|
regs->regs[rd] = pc + sign_extend64(imm << 2, 21);
|
||||||
|
break;
|
||||||
|
case pcaddu12i_op:
|
||||||
|
regs->regs[rd] = pc + sign_extend64(imm << 12, 31);
|
||||||
|
break;
|
||||||
|
case pcaddu18i_op:
|
||||||
|
regs->regs[rd] = pc + sign_extend64(imm << 18, 37);
|
||||||
|
break;
|
||||||
|
case pcalau12i_op:
|
||||||
|
regs->regs[rd] = pc + sign_extend64(imm << 12, 31);
|
||||||
|
regs->regs[rd] &= ~((1 << 12) - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_info("%s: unknown opcode\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs->csr_era += LOONGARCH_INSN_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simu_branch(struct pt_regs *regs, union loongarch_instruction insn)
|
||||||
|
{
|
||||||
|
unsigned int imm, imm_l, imm_h, rd, rj;
|
||||||
|
unsigned long pc = regs->csr_era;
|
||||||
|
|
||||||
|
if (pc & 3) {
|
||||||
|
pr_warn("%s: invalid pc 0x%lx\n", __func__, pc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imm_l = insn.reg0i26_format.immediate_l;
|
||||||
|
imm_h = insn.reg0i26_format.immediate_h;
|
||||||
|
switch (insn.reg0i26_format.opcode) {
|
||||||
|
case b_op:
|
||||||
|
regs->csr_era = pc + sign_extend64((imm_h << 16 | imm_l) << 2, 27);
|
||||||
|
return;
|
||||||
|
case bl_op:
|
||||||
|
regs->csr_era = pc + sign_extend64((imm_h << 16 | imm_l) << 2, 27);
|
||||||
|
regs->regs[1] = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imm_l = insn.reg1i21_format.immediate_l;
|
||||||
|
imm_h = insn.reg1i21_format.immediate_h;
|
||||||
|
rj = insn.reg1i21_format.rj;
|
||||||
|
switch (insn.reg1i21_format.opcode) {
|
||||||
|
case beqz_op:
|
||||||
|
if (regs->regs[rj] == 0)
|
||||||
|
regs->csr_era = pc + sign_extend64((imm_h << 16 | imm_l) << 2, 22);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
return;
|
||||||
|
case bnez_op:
|
||||||
|
if (regs->regs[rj] != 0)
|
||||||
|
regs->csr_era = pc + sign_extend64((imm_h << 16 | imm_l) << 2, 22);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
imm = insn.reg2i16_format.immediate;
|
||||||
|
rj = insn.reg2i16_format.rj;
|
||||||
|
rd = insn.reg2i16_format.rd;
|
||||||
|
switch (insn.reg2i16_format.opcode) {
|
||||||
|
case beq_op:
|
||||||
|
if (regs->regs[rj] == regs->regs[rd])
|
||||||
|
regs->csr_era = pc + sign_extend64(imm << 2, 17);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
break;
|
||||||
|
case bne_op:
|
||||||
|
if (regs->regs[rj] != regs->regs[rd])
|
||||||
|
regs->csr_era = pc + sign_extend64(imm << 2, 17);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
break;
|
||||||
|
case blt_op:
|
||||||
|
if ((long)regs->regs[rj] < (long)regs->regs[rd])
|
||||||
|
regs->csr_era = pc + sign_extend64(imm << 2, 17);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
break;
|
||||||
|
case bge_op:
|
||||||
|
if ((long)regs->regs[rj] >= (long)regs->regs[rd])
|
||||||
|
regs->csr_era = pc + sign_extend64(imm << 2, 17);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
break;
|
||||||
|
case bltu_op:
|
||||||
|
if (regs->regs[rj] < regs->regs[rd])
|
||||||
|
regs->csr_era = pc + sign_extend64(imm << 2, 17);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
break;
|
||||||
|
case bgeu_op:
|
||||||
|
if (regs->regs[rj] >= regs->regs[rd])
|
||||||
|
regs->csr_era = pc + sign_extend64(imm << 2, 17);
|
||||||
|
else
|
||||||
|
regs->csr_era = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
break;
|
||||||
|
case jirl_op:
|
||||||
|
regs->csr_era = regs->regs[rj] + sign_extend64(imm << 2, 17);
|
||||||
|
regs->regs[rd] = pc + LOONGARCH_INSN_SIZE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_info("%s: unknown opcode\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int larch_insn_read(void *addr, u32 *insnp)
|
int larch_insn_read(void *addr, u32 *insnp)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
406
arch/loongarch/kernel/kprobes.c
Normal file
406
arch/loongarch/kernel/kprobes.c
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#include <linux/kdebug.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
|
#include <linux/preempt.h>
|
||||||
|
#include <asm/break.h>
|
||||||
|
|
||||||
|
static const union loongarch_instruction breakpoint_insn = {
|
||||||
|
.reg0i15_format = {
|
||||||
|
.opcode = break_op,
|
||||||
|
.immediate = BRK_KPROBE_BP,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const union loongarch_instruction singlestep_insn = {
|
||||||
|
.reg0i15_format = {
|
||||||
|
.opcode = break_op,
|
||||||
|
.immediate = BRK_KPROBE_SSTEPBP,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
|
||||||
|
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
|
||||||
|
|
||||||
|
static bool insns_not_supported(union loongarch_instruction insn)
|
||||||
|
{
|
||||||
|
switch (insn.reg2i14_format.opcode) {
|
||||||
|
case llw_op:
|
||||||
|
case lld_op:
|
||||||
|
case scw_op:
|
||||||
|
case scd_op:
|
||||||
|
pr_notice("kprobe: ll and sc instructions are not supported\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (insn.reg1i21_format.opcode) {
|
||||||
|
case bceqz_op:
|
||||||
|
pr_notice("kprobe: bceqz and bcnez instructions are not supported\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(insns_not_supported);
|
||||||
|
|
||||||
|
static bool insns_need_simulation(struct kprobe *p)
|
||||||
|
{
|
||||||
|
if (is_pc_ins(&p->opcode))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (is_branch_ins(&p->opcode))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(insns_need_simulation);
|
||||||
|
|
||||||
|
static void arch_simulate_insn(struct kprobe *p, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
if (is_pc_ins(&p->opcode))
|
||||||
|
simu_pc(regs, p->opcode);
|
||||||
|
else if (is_branch_ins(&p->opcode))
|
||||||
|
simu_branch(regs, p->opcode);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_simulate_insn);
|
||||||
|
|
||||||
|
static void arch_prepare_ss_slot(struct kprobe *p)
|
||||||
|
{
|
||||||
|
p->ainsn.insn[0] = *p->addr;
|
||||||
|
p->ainsn.insn[1] = singlestep_insn;
|
||||||
|
p->ainsn.restore = (unsigned long)p->addr + LOONGARCH_INSN_SIZE;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_prepare_ss_slot);
|
||||||
|
|
||||||
|
static void arch_prepare_simulate(struct kprobe *p)
|
||||||
|
{
|
||||||
|
p->ainsn.restore = 0;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_prepare_simulate);
|
||||||
|
|
||||||
|
int arch_prepare_kprobe(struct kprobe *p)
|
||||||
|
{
|
||||||
|
if ((unsigned long)p->addr & 0x3)
|
||||||
|
return -EILSEQ;
|
||||||
|
|
||||||
|
/* copy instruction */
|
||||||
|
p->opcode = *p->addr;
|
||||||
|
|
||||||
|
/* decode instruction */
|
||||||
|
if (insns_not_supported(p->opcode))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (insns_need_simulation(p)) {
|
||||||
|
p->ainsn.insn = NULL;
|
||||||
|
} else {
|
||||||
|
p->ainsn.insn = get_insn_slot();
|
||||||
|
if (!p->ainsn.insn)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare the instruction */
|
||||||
|
if (p->ainsn.insn)
|
||||||
|
arch_prepare_ss_slot(p);
|
||||||
|
else
|
||||||
|
arch_prepare_simulate(p);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_prepare_kprobe);
|
||||||
|
|
||||||
|
/* Install breakpoint in text */
|
||||||
|
void arch_arm_kprobe(struct kprobe *p)
|
||||||
|
{
|
||||||
|
*p->addr = breakpoint_insn;
|
||||||
|
flush_insn_slot(p);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_arm_kprobe);
|
||||||
|
|
||||||
|
/* Remove breakpoint from text */
|
||||||
|
void arch_disarm_kprobe(struct kprobe *p)
|
||||||
|
{
|
||||||
|
*p->addr = p->opcode;
|
||||||
|
flush_insn_slot(p);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_disarm_kprobe);
|
||||||
|
|
||||||
|
void arch_remove_kprobe(struct kprobe *p)
|
||||||
|
{
|
||||||
|
if (p->ainsn.insn) {
|
||||||
|
free_insn_slot(p->ainsn.insn, 0);
|
||||||
|
p->ainsn.insn = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_remove_kprobe);
|
||||||
|
|
||||||
|
static void save_previous_kprobe(struct kprobe_ctlblk *kcb)
|
||||||
|
{
|
||||||
|
kcb->prev_kprobe.kp = kprobe_running();
|
||||||
|
kcb->prev_kprobe.status = kcb->kprobe_status;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(save_previous_kprobe);
|
||||||
|
|
||||||
|
static void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
|
||||||
|
{
|
||||||
|
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
|
||||||
|
kcb->kprobe_status = kcb->prev_kprobe.status;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(restore_previous_kprobe);
|
||||||
|
|
||||||
|
static void set_current_kprobe(struct kprobe *p)
|
||||||
|
{
|
||||||
|
__this_cpu_write(current_kprobe, p);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(set_current_kprobe);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupts need to be disabled before single-step mode is set,
|
||||||
|
* and not reenabled until after single-step mode ends.
|
||||||
|
* Without disabling interrupt on local CPU, there is a chance of
|
||||||
|
* interrupt occurrence in the period of exception return and start
|
||||||
|
* of out-of-line single-step, that result in wrongly single stepping
|
||||||
|
* into the interrupt handler.
|
||||||
|
*/
|
||||||
|
static void save_local_irqflag(struct kprobe_ctlblk *kcb,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
kcb->saved_status = regs->csr_prmd;
|
||||||
|
regs->csr_prmd &= ~CSR_PRMD_PIE;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(save_local_irqflag);
|
||||||
|
|
||||||
|
static void restore_local_irqflag(struct kprobe_ctlblk *kcb,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
regs->csr_prmd = kcb->saved_status;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(restore_local_irqflag);
|
||||||
|
|
||||||
|
static void post_kprobe_handler(struct kprobe *cur, struct kprobe_ctlblk *kcb,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
/* return addr restore if non-branching insn */
|
||||||
|
if (cur->ainsn.restore != 0)
|
||||||
|
instruction_pointer_set(regs, cur->ainsn.restore);
|
||||||
|
|
||||||
|
/* restore back original saved kprobe variables and continue */
|
||||||
|
if (kcb->kprobe_status == KPROBE_REENTER) {
|
||||||
|
restore_previous_kprobe(kcb);
|
||||||
|
preempt_enable_no_resched();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update the kcb status even if the cur->post_handler is
|
||||||
|
* not set because reset_curent_kprobe() doesn't update kcb.
|
||||||
|
*/
|
||||||
|
kcb->kprobe_status = KPROBE_HIT_SSDONE;
|
||||||
|
if (cur->post_handler)
|
||||||
|
cur->post_handler(cur, regs, 0);
|
||||||
|
|
||||||
|
reset_current_kprobe();
|
||||||
|
preempt_enable_no_resched();
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(post_kprobe_handler);
|
||||||
|
|
||||||
|
static void setup_singlestep(struct kprobe *p, struct pt_regs *regs,
|
||||||
|
struct kprobe_ctlblk *kcb, int reenter)
|
||||||
|
{
|
||||||
|
if (reenter) {
|
||||||
|
save_previous_kprobe(kcb);
|
||||||
|
set_current_kprobe(p);
|
||||||
|
kcb->kprobe_status = KPROBE_REENTER;
|
||||||
|
} else {
|
||||||
|
kcb->kprobe_status = KPROBE_HIT_SS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->ainsn.insn) {
|
||||||
|
/* IRQs and single stepping do not mix well */
|
||||||
|
save_local_irqflag(kcb, regs);
|
||||||
|
/* set ip register to prepare for single stepping */
|
||||||
|
regs->csr_era = (unsigned long)p->ainsn.insn;
|
||||||
|
} else {
|
||||||
|
/* simulate single steping */
|
||||||
|
arch_simulate_insn(p, regs);
|
||||||
|
/* now go for post processing */
|
||||||
|
post_kprobe_handler(p, kcb, regs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(setup_singlestep);
|
||||||
|
|
||||||
|
static bool reenter_kprobe(struct kprobe *p, struct pt_regs *regs,
|
||||||
|
struct kprobe_ctlblk *kcb)
|
||||||
|
{
|
||||||
|
switch (kcb->kprobe_status) {
|
||||||
|
case KPROBE_HIT_SS:
|
||||||
|
case KPROBE_HIT_SSDONE:
|
||||||
|
case KPROBE_HIT_ACTIVE:
|
||||||
|
kprobes_inc_nmissed_count(p);
|
||||||
|
setup_singlestep(p, regs, kcb, 1);
|
||||||
|
break;
|
||||||
|
case KPROBE_REENTER:
|
||||||
|
pr_warn("Failed to recover from reentered kprobes.\n");
|
||||||
|
dump_kprobe(p);
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON(1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(reenter_kprobe);
|
||||||
|
|
||||||
|
bool kprobe_breakpoint_handler(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct kprobe_ctlblk *kcb;
|
||||||
|
struct kprobe *p, *cur_kprobe;
|
||||||
|
kprobe_opcode_t *addr = (kprobe_opcode_t *)regs->csr_era;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't want to be preempted for the entire
|
||||||
|
* duration of kprobe processing.
|
||||||
|
*/
|
||||||
|
preempt_disable();
|
||||||
|
kcb = get_kprobe_ctlblk();
|
||||||
|
cur_kprobe = kprobe_running();
|
||||||
|
|
||||||
|
p = get_kprobe(addr);
|
||||||
|
if (p) {
|
||||||
|
if (cur_kprobe) {
|
||||||
|
if (reenter_kprobe(p, regs, kcb))
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
/* Probe hit */
|
||||||
|
set_current_kprobe(p);
|
||||||
|
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have no pre-handler or it returned 0, we
|
||||||
|
* continue with normal processing. If we have a
|
||||||
|
* pre-handler and it returned non-zero, it will
|
||||||
|
* modify the execution path and no need to single
|
||||||
|
* stepping. Let's just reset current kprobe and exit.
|
||||||
|
*
|
||||||
|
* pre_handler can hit a breakpoint and can step thru
|
||||||
|
* before return.
|
||||||
|
*/
|
||||||
|
if (!p->pre_handler || !p->pre_handler(p, regs)) {
|
||||||
|
setup_singlestep(p, regs, kcb, 0);
|
||||||
|
} else {
|
||||||
|
reset_current_kprobe();
|
||||||
|
preempt_enable_no_resched();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr->word != breakpoint_insn.word) {
|
||||||
|
/*
|
||||||
|
* The breakpoint instruction was removed right
|
||||||
|
* after we hit it. Another cpu has removed
|
||||||
|
* either a probepoint or a debugger breakpoint
|
||||||
|
* at this address. In either case, no further
|
||||||
|
* handling of this interrupt is appropriate.
|
||||||
|
* Return back to original instruction, and continue.
|
||||||
|
*/
|
||||||
|
regs->csr_era = (unsigned long)addr;
|
||||||
|
preempt_enable_no_resched();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
preempt_enable_no_resched();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(kprobe_breakpoint_handler);
|
||||||
|
|
||||||
|
bool kprobe_singlestep_handler(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct kprobe *cur = kprobe_running();
|
||||||
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||||
|
unsigned long addr = instruction_pointer(regs);
|
||||||
|
|
||||||
|
if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) &&
|
||||||
|
((unsigned long)&cur->ainsn.insn[1] == addr)) {
|
||||||
|
restore_local_irqflag(kcb, regs);
|
||||||
|
post_kprobe_handler(cur, kcb, regs);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
preempt_enable_no_resched();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(kprobe_singlestep_handler);
|
||||||
|
|
||||||
|
bool kprobe_fault_handler(struct pt_regs *regs, int trapnr)
|
||||||
|
{
|
||||||
|
struct kprobe *cur = kprobe_running();
|
||||||
|
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
|
||||||
|
|
||||||
|
switch (kcb->kprobe_status) {
|
||||||
|
case KPROBE_HIT_SS:
|
||||||
|
case KPROBE_REENTER:
|
||||||
|
/*
|
||||||
|
* We are here because the instruction being single
|
||||||
|
* stepped caused a page fault. We reset the current
|
||||||
|
* kprobe and the ip points back to the probe address
|
||||||
|
* and allow the page fault handler to continue as a
|
||||||
|
* normal page fault.
|
||||||
|
*/
|
||||||
|
regs->csr_era = (unsigned long)cur->addr;
|
||||||
|
WARN_ON_ONCE(!instruction_pointer(regs));
|
||||||
|
|
||||||
|
if (kcb->kprobe_status == KPROBE_REENTER) {
|
||||||
|
restore_previous_kprobe(kcb);
|
||||||
|
} else {
|
||||||
|
restore_local_irqflag(kcb, regs);
|
||||||
|
reset_current_kprobe();
|
||||||
|
}
|
||||||
|
preempt_enable_no_resched();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(kprobe_fault_handler);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provide a blacklist of symbols identifying ranges which cannot be kprobed.
|
||||||
|
* This blacklist is exposed to userspace via debugfs (kprobes/blacklist).
|
||||||
|
*/
|
||||||
|
int __init arch_populate_kprobe_blacklist(void)
|
||||||
|
{
|
||||||
|
return kprobe_add_area_blacklist((unsigned long)__irqentry_text_start,
|
||||||
|
(unsigned long)__irqentry_text_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __init arch_init_kprobes(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ASM function that handles the kretprobes must not be probed */
|
||||||
|
NOKPROBE_SYMBOL(__kretprobe_trampoline);
|
||||||
|
|
||||||
|
/* Called from __kretprobe_trampoline */
|
||||||
|
void __used *trampoline_probe_handler(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
return (void *)kretprobe_trampoline_handler(regs, NULL);
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(trampoline_probe_handler);
|
||||||
|
|
||||||
|
void arch_prepare_kretprobe(struct kretprobe_instance *ri,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
ri->ret_addr = (kprobe_opcode_t *)regs->regs[1];
|
||||||
|
ri->fp = NULL;
|
||||||
|
|
||||||
|
/* Replace the return addr with trampoline addr */
|
||||||
|
regs->regs[1] = (unsigned long)&__kretprobe_trampoline;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_prepare_kretprobe);
|
||||||
|
|
||||||
|
int arch_trampoline_kprobe(struct kprobe *p)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
NOKPROBE_SYMBOL(arch_trampoline_kprobe);
|
96
arch/loongarch/kernel/kprobes_trampoline.S
Normal file
96
arch/loongarch/kernel/kprobes_trampoline.S
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
#include <linux/linkage.h>
|
||||||
|
#include <asm/stackframe.h>
|
||||||
|
|
||||||
|
.text
|
||||||
|
|
||||||
|
.macro save_all_base_regs
|
||||||
|
cfi_st ra, PT_R1
|
||||||
|
cfi_st tp, PT_R2
|
||||||
|
cfi_st a0, PT_R4
|
||||||
|
cfi_st a1, PT_R5
|
||||||
|
cfi_st a2, PT_R6
|
||||||
|
cfi_st a3, PT_R7
|
||||||
|
cfi_st a4, PT_R8
|
||||||
|
cfi_st a5, PT_R9
|
||||||
|
cfi_st a6, PT_R10
|
||||||
|
cfi_st a7, PT_R11
|
||||||
|
cfi_st t0, PT_R12
|
||||||
|
cfi_st t1, PT_R13
|
||||||
|
cfi_st t2, PT_R14
|
||||||
|
cfi_st t3, PT_R15
|
||||||
|
cfi_st t4, PT_R16
|
||||||
|
cfi_st t5, PT_R17
|
||||||
|
cfi_st t6, PT_R18
|
||||||
|
cfi_st t7, PT_R19
|
||||||
|
cfi_st t8, PT_R20
|
||||||
|
cfi_st u0, PT_R21
|
||||||
|
cfi_st fp, PT_R22
|
||||||
|
cfi_st s0, PT_R23
|
||||||
|
cfi_st s1, PT_R24
|
||||||
|
cfi_st s2, PT_R25
|
||||||
|
cfi_st s3, PT_R26
|
||||||
|
cfi_st s4, PT_R27
|
||||||
|
cfi_st s5, PT_R28
|
||||||
|
cfi_st s6, PT_R29
|
||||||
|
cfi_st s7, PT_R30
|
||||||
|
cfi_st s8, PT_R31
|
||||||
|
csrrd t0, LOONGARCH_CSR_CRMD
|
||||||
|
andi t0, t0, 0x7 /* extract bit[1:0] PLV, bit[2] IE */
|
||||||
|
LONG_S t0, sp, PT_CRMD
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro restore_all_base_regs
|
||||||
|
cfi_ld tp, PT_R2
|
||||||
|
cfi_ld a0, PT_R4
|
||||||
|
cfi_ld a1, PT_R5
|
||||||
|
cfi_ld a2, PT_R6
|
||||||
|
cfi_ld a3, PT_R7
|
||||||
|
cfi_ld a4, PT_R8
|
||||||
|
cfi_ld a5, PT_R9
|
||||||
|
cfi_ld a6, PT_R10
|
||||||
|
cfi_ld a7, PT_R11
|
||||||
|
cfi_ld t0, PT_R12
|
||||||
|
cfi_ld t1, PT_R13
|
||||||
|
cfi_ld t2, PT_R14
|
||||||
|
cfi_ld t3, PT_R15
|
||||||
|
cfi_ld t4, PT_R16
|
||||||
|
cfi_ld t5, PT_R17
|
||||||
|
cfi_ld t6, PT_R18
|
||||||
|
cfi_ld t7, PT_R19
|
||||||
|
cfi_ld t8, PT_R20
|
||||||
|
cfi_ld u0, PT_R21
|
||||||
|
cfi_ld fp, PT_R22
|
||||||
|
cfi_ld s0, PT_R23
|
||||||
|
cfi_ld s1, PT_R24
|
||||||
|
cfi_ld s2, PT_R25
|
||||||
|
cfi_ld s3, PT_R26
|
||||||
|
cfi_ld s4, PT_R27
|
||||||
|
cfi_ld s5, PT_R28
|
||||||
|
cfi_ld s6, PT_R29
|
||||||
|
cfi_ld s7, PT_R30
|
||||||
|
cfi_ld s8, PT_R31
|
||||||
|
LONG_L t0, sp, PT_CRMD
|
||||||
|
li.d t1, 0x7 /* mask bit[1:0] PLV, bit[2] IE */
|
||||||
|
csrxchg t0, t1, LOONGARCH_CSR_CRMD
|
||||||
|
.endm
|
||||||
|
|
||||||
|
SYM_CODE_START(__kretprobe_trampoline)
|
||||||
|
addi.d sp, sp, -PT_SIZE
|
||||||
|
save_all_base_regs
|
||||||
|
|
||||||
|
addi.d t0, sp, PT_SIZE
|
||||||
|
LONG_S t0, sp, PT_R3
|
||||||
|
|
||||||
|
move a0, sp /* pt_regs */
|
||||||
|
|
||||||
|
bl trampoline_probe_handler
|
||||||
|
|
||||||
|
/* use the result as the return-address */
|
||||||
|
move ra, a0
|
||||||
|
|
||||||
|
restore_all_base_regs
|
||||||
|
addi.d sp, sp, PT_SIZE
|
||||||
|
|
||||||
|
jr ra
|
||||||
|
SYM_CODE_END(__kretprobe_trampoline)
|
@ -18,6 +18,7 @@
|
|||||||
#include <linux/sched/debug.h>
|
#include <linux/sched/debug.h>
|
||||||
#include <linux/sched/task.h>
|
#include <linux/sched/task.h>
|
||||||
#include <linux/sched/task_stack.h>
|
#include <linux/sched/task_stack.h>
|
||||||
|
#include <linux/hw_breakpoint.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
||||||
@ -96,6 +97,11 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
|
|||||||
regs->regs[3] = sp;
|
regs->regs[3] = sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flush_thread(void)
|
||||||
|
{
|
||||||
|
flush_ptrace_hw_breakpoint(current);
|
||||||
|
}
|
||||||
|
|
||||||
void exit_thread(struct task_struct *tsk)
|
void exit_thread(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -181,6 +187,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
|
|||||||
childregs->regs[2] = tls;
|
childregs->regs[2] = tls;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
ptrace_hw_copy_thread(p);
|
||||||
clear_tsk_thread_flag(p, TIF_USEDFPU);
|
clear_tsk_thread_flag(p, TIF_USEDFPU);
|
||||||
clear_tsk_thread_flag(p, TIF_USEDSIMD);
|
clear_tsk_thread_flag(p, TIF_USEDSIMD);
|
||||||
clear_tsk_thread_flag(p, TIF_LSX_CTX_LIVE);
|
clear_tsk_thread_flag(p, TIF_LSX_CTX_LIVE);
|
||||||
|
@ -20,7 +20,9 @@
|
|||||||
#include <linux/context_tracking.h>
|
#include <linux/context_tracking.h>
|
||||||
#include <linux/elf.h>
|
#include <linux/elf.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/hw_breakpoint.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/nospec.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
#include <linux/regset.h>
|
#include <linux/regset.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
@ -29,6 +31,7 @@
|
|||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/stddef.h>
|
#include <linux/stddef.h>
|
||||||
#include <linux/seccomp.h>
|
#include <linux/seccomp.h>
|
||||||
|
#include <linux/thread_info.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
@ -39,6 +42,7 @@
|
|||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
|
#include <asm/ptrace.h>
|
||||||
#include <asm/reg.h>
|
#include <asm/reg.h>
|
||||||
#include <asm/syscall.h>
|
#include <asm/syscall.h>
|
||||||
|
|
||||||
@ -246,6 +250,384 @@ static int cfg_set(struct task_struct *target,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle hitting a HW-breakpoint.
|
||||||
|
*/
|
||||||
|
static void ptrace_hbptriggered(struct perf_event *bp,
|
||||||
|
struct perf_sample_data *data,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
|
||||||
|
|
||||||
|
for (i = 0; i < LOONGARCH_MAX_BRP; ++i)
|
||||||
|
if (current->thread.hbp_break[i] == bp)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (i = 0; i < LOONGARCH_MAX_WRP; ++i)
|
||||||
|
if (current->thread.hbp_watch[i] == bp)
|
||||||
|
break;
|
||||||
|
|
||||||
|
force_sig_ptrace_errno_trap(i, (void __user *)bkpt->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct perf_event *ptrace_hbp_get_event(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx)
|
||||||
|
{
|
||||||
|
struct perf_event *bp;
|
||||||
|
|
||||||
|
switch (note_type) {
|
||||||
|
case NT_LOONGARCH_HW_BREAK:
|
||||||
|
if (idx >= LOONGARCH_MAX_BRP)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
idx = array_index_nospec(idx, LOONGARCH_MAX_BRP);
|
||||||
|
bp = tsk->thread.hbp_break[idx];
|
||||||
|
break;
|
||||||
|
case NT_LOONGARCH_HW_WATCH:
|
||||||
|
if (idx >= LOONGARCH_MAX_WRP)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
idx = array_index_nospec(idx, LOONGARCH_MAX_WRP);
|
||||||
|
bp = tsk->thread.hbp_watch[idx];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_set_event(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx,
|
||||||
|
struct perf_event *bp)
|
||||||
|
{
|
||||||
|
switch (note_type) {
|
||||||
|
case NT_LOONGARCH_HW_BREAK:
|
||||||
|
if (idx >= LOONGARCH_MAX_BRP)
|
||||||
|
return -EINVAL;
|
||||||
|
idx = array_index_nospec(idx, LOONGARCH_MAX_BRP);
|
||||||
|
tsk->thread.hbp_break[idx] = bp;
|
||||||
|
break;
|
||||||
|
case NT_LOONGARCH_HW_WATCH:
|
||||||
|
if (idx >= LOONGARCH_MAX_WRP)
|
||||||
|
return -EINVAL;
|
||||||
|
idx = array_index_nospec(idx, LOONGARCH_MAX_WRP);
|
||||||
|
tsk->thread.hbp_watch[idx] = bp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct perf_event *ptrace_hbp_create(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx)
|
||||||
|
{
|
||||||
|
int err, type;
|
||||||
|
struct perf_event *bp;
|
||||||
|
struct perf_event_attr attr;
|
||||||
|
|
||||||
|
switch (note_type) {
|
||||||
|
case NT_LOONGARCH_HW_BREAK:
|
||||||
|
type = HW_BREAKPOINT_X;
|
||||||
|
break;
|
||||||
|
case NT_LOONGARCH_HW_WATCH:
|
||||||
|
type = HW_BREAKPOINT_RW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrace_breakpoint_init(&attr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialise fields to sane defaults
|
||||||
|
* (i.e. values that will pass validation).
|
||||||
|
*/
|
||||||
|
attr.bp_addr = 0;
|
||||||
|
attr.bp_len = HW_BREAKPOINT_LEN_4;
|
||||||
|
attr.bp_type = type;
|
||||||
|
attr.disabled = 1;
|
||||||
|
|
||||||
|
bp = register_user_hw_breakpoint(&attr, ptrace_hbptriggered, NULL, tsk);
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return bp;
|
||||||
|
|
||||||
|
err = ptrace_hbp_set_event(note_type, tsk, idx, bp);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_fill_attr_ctrl(unsigned int note_type,
|
||||||
|
struct arch_hw_breakpoint_ctrl ctrl,
|
||||||
|
struct perf_event_attr *attr)
|
||||||
|
{
|
||||||
|
int err, len, type, offset;
|
||||||
|
|
||||||
|
err = arch_bp_generic_fields(ctrl, &len, &type, &offset);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
switch (note_type) {
|
||||||
|
case NT_LOONGARCH_HW_BREAK:
|
||||||
|
if ((type & HW_BREAKPOINT_X) != type)
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
case NT_LOONGARCH_HW_WATCH:
|
||||||
|
if ((type & HW_BREAKPOINT_RW) != type)
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr->bp_len = len;
|
||||||
|
attr->bp_type = type;
|
||||||
|
attr->bp_addr += offset;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_get_resource_info(unsigned int note_type, u16 *info)
|
||||||
|
{
|
||||||
|
u8 num;
|
||||||
|
u16 reg = 0;
|
||||||
|
|
||||||
|
switch (note_type) {
|
||||||
|
case NT_LOONGARCH_HW_BREAK:
|
||||||
|
num = hw_breakpoint_slots(TYPE_INST);
|
||||||
|
break;
|
||||||
|
case NT_LOONGARCH_HW_WATCH:
|
||||||
|
num = hw_breakpoint_slots(TYPE_DATA);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*info = reg | num;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct perf_event *ptrace_hbp_get_initialised_bp(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx)
|
||||||
|
{
|
||||||
|
struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
|
||||||
|
|
||||||
|
if (!bp)
|
||||||
|
bp = ptrace_hbp_create(note_type, tsk, idx);
|
||||||
|
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_get_ctrl(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx, u32 *ctrl)
|
||||||
|
{
|
||||||
|
struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
|
||||||
|
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return PTR_ERR(bp);
|
||||||
|
|
||||||
|
*ctrl = bp ? encode_ctrl_reg(counter_arch_bp(bp)->ctrl) : 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_get_mask(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx, u64 *mask)
|
||||||
|
{
|
||||||
|
struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
|
||||||
|
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return PTR_ERR(bp);
|
||||||
|
|
||||||
|
*mask = bp ? counter_arch_bp(bp)->mask : 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_get_addr(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx, u64 *addr)
|
||||||
|
{
|
||||||
|
struct perf_event *bp = ptrace_hbp_get_event(note_type, tsk, idx);
|
||||||
|
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return PTR_ERR(bp);
|
||||||
|
|
||||||
|
*addr = bp ? counter_arch_bp(bp)->address : 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_set_ctrl(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx, u32 uctrl)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct perf_event *bp;
|
||||||
|
struct perf_event_attr attr;
|
||||||
|
struct arch_hw_breakpoint_ctrl ctrl;
|
||||||
|
|
||||||
|
bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return PTR_ERR(bp);
|
||||||
|
|
||||||
|
attr = bp->attr;
|
||||||
|
decode_ctrl_reg(uctrl, &ctrl);
|
||||||
|
err = ptrace_hbp_fill_attr_ctrl(note_type, ctrl, &attr);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return modify_user_hw_breakpoint(bp, &attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_set_mask(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx, u64 mask)
|
||||||
|
{
|
||||||
|
struct perf_event *bp;
|
||||||
|
struct perf_event_attr attr;
|
||||||
|
struct arch_hw_breakpoint *info;
|
||||||
|
|
||||||
|
bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return PTR_ERR(bp);
|
||||||
|
|
||||||
|
attr = bp->attr;
|
||||||
|
info = counter_arch_bp(bp);
|
||||||
|
info->mask = mask;
|
||||||
|
|
||||||
|
return modify_user_hw_breakpoint(bp, &attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptrace_hbp_set_addr(unsigned int note_type,
|
||||||
|
struct task_struct *tsk,
|
||||||
|
unsigned long idx, u64 addr)
|
||||||
|
{
|
||||||
|
struct perf_event *bp;
|
||||||
|
struct perf_event_attr attr;
|
||||||
|
|
||||||
|
bp = ptrace_hbp_get_initialised_bp(note_type, tsk, idx);
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return PTR_ERR(bp);
|
||||||
|
|
||||||
|
attr = bp->attr;
|
||||||
|
attr.bp_addr = addr;
|
||||||
|
|
||||||
|
return modify_user_hw_breakpoint(bp, &attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PTRACE_HBP_CTRL_SZ sizeof(u32)
|
||||||
|
#define PTRACE_HBP_ADDR_SZ sizeof(u64)
|
||||||
|
#define PTRACE_HBP_MASK_SZ sizeof(u64)
|
||||||
|
|
||||||
|
static int hw_break_get(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
struct membuf to)
|
||||||
|
{
|
||||||
|
u16 info;
|
||||||
|
u32 ctrl;
|
||||||
|
u64 addr, mask;
|
||||||
|
int ret, idx = 0;
|
||||||
|
unsigned int note_type = regset->core_note_type;
|
||||||
|
|
||||||
|
/* Resource info */
|
||||||
|
ret = ptrace_hbp_get_resource_info(note_type, &info);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
membuf_write(&to, &info, sizeof(info));
|
||||||
|
|
||||||
|
/* (address, ctrl) registers */
|
||||||
|
while (to.left) {
|
||||||
|
ret = ptrace_hbp_get_addr(note_type, target, idx, &addr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ptrace_hbp_get_mask(note_type, target, idx, &mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ptrace_hbp_get_ctrl(note_type, target, idx, &ctrl);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
membuf_store(&to, addr);
|
||||||
|
membuf_store(&to, mask);
|
||||||
|
membuf_store(&to, ctrl);
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hw_break_set(struct task_struct *target,
|
||||||
|
const struct user_regset *regset,
|
||||||
|
unsigned int pos, unsigned int count,
|
||||||
|
const void *kbuf, const void __user *ubuf)
|
||||||
|
{
|
||||||
|
u32 ctrl;
|
||||||
|
u64 addr, mask;
|
||||||
|
int ret, idx = 0, offset, limit;
|
||||||
|
unsigned int note_type = regset->core_note_type;
|
||||||
|
|
||||||
|
/* Resource info */
|
||||||
|
offset = offsetof(struct user_watch_state, dbg_regs);
|
||||||
|
user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, 0, offset);
|
||||||
|
|
||||||
|
/* (address, ctrl) registers */
|
||||||
|
limit = regset->n * regset->size;
|
||||||
|
while (count && offset < limit) {
|
||||||
|
if (count < PTRACE_HBP_ADDR_SZ)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
|
||||||
|
offset, offset + PTRACE_HBP_ADDR_SZ);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ptrace_hbp_set_addr(note_type, target, idx, addr);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
offset += PTRACE_HBP_ADDR_SZ;
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &mask,
|
||||||
|
offset, offset + PTRACE_HBP_ADDR_SZ);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ptrace_hbp_set_mask(note_type, target, idx, mask);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
offset += PTRACE_HBP_MASK_SZ;
|
||||||
|
|
||||||
|
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &mask,
|
||||||
|
offset, offset + PTRACE_HBP_MASK_SZ);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = ptrace_hbp_set_ctrl(note_type, target, idx, ctrl);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
offset += PTRACE_HBP_CTRL_SZ;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
struct pt_regs_offset {
|
struct pt_regs_offset {
|
||||||
const char *name;
|
const char *name;
|
||||||
int offset;
|
int offset;
|
||||||
@ -319,6 +701,10 @@ enum loongarch_regset {
|
|||||||
REGSET_GPR,
|
REGSET_GPR,
|
||||||
REGSET_FPR,
|
REGSET_FPR,
|
||||||
REGSET_CPUCFG,
|
REGSET_CPUCFG,
|
||||||
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||||
|
REGSET_HW_BREAK,
|
||||||
|
REGSET_HW_WATCH,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct user_regset loongarch64_regsets[] = {
|
static const struct user_regset loongarch64_regsets[] = {
|
||||||
@ -346,6 +732,24 @@ static const struct user_regset loongarch64_regsets[] = {
|
|||||||
.regset_get = cfg_get,
|
.regset_get = cfg_get,
|
||||||
.set = cfg_set,
|
.set = cfg_set,
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||||
|
[REGSET_HW_BREAK] = {
|
||||||
|
.core_note_type = NT_LOONGARCH_HW_BREAK,
|
||||||
|
.n = sizeof(struct user_watch_state) / sizeof(u32),
|
||||||
|
.size = sizeof(u32),
|
||||||
|
.align = sizeof(u32),
|
||||||
|
.regset_get = hw_break_get,
|
||||||
|
.set = hw_break_set,
|
||||||
|
},
|
||||||
|
[REGSET_HW_WATCH] = {
|
||||||
|
.core_note_type = NT_LOONGARCH_HW_WATCH,
|
||||||
|
.n = sizeof(struct user_watch_state) / sizeof(u32),
|
||||||
|
.size = sizeof(u32),
|
||||||
|
.align = sizeof(u32),
|
||||||
|
.regset_get = hw_break_get,
|
||||||
|
.set = hw_break_set,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct user_regset_view user_loongarch64_view = {
|
static const struct user_regset_view user_loongarch64_view = {
|
||||||
@ -431,3 +835,71 @@ long arch_ptrace(struct task_struct *child, long request,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||||
|
static void ptrace_triggered(struct perf_event *bp,
|
||||||
|
struct perf_sample_data *data, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
struct perf_event_attr attr;
|
||||||
|
|
||||||
|
attr = bp->attr;
|
||||||
|
attr.disabled = true;
|
||||||
|
modify_user_hw_breakpoint(bp, &attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_single_step(struct task_struct *tsk, unsigned long addr)
|
||||||
|
{
|
||||||
|
struct perf_event *bp;
|
||||||
|
struct perf_event_attr attr;
|
||||||
|
struct arch_hw_breakpoint *info;
|
||||||
|
struct thread_struct *thread = &tsk->thread;
|
||||||
|
|
||||||
|
bp = thread->hbp_break[0];
|
||||||
|
if (!bp) {
|
||||||
|
ptrace_breakpoint_init(&attr);
|
||||||
|
|
||||||
|
attr.bp_addr = addr;
|
||||||
|
attr.bp_len = HW_BREAKPOINT_LEN_8;
|
||||||
|
attr.bp_type = HW_BREAKPOINT_X;
|
||||||
|
|
||||||
|
bp = register_user_hw_breakpoint(&attr, ptrace_triggered,
|
||||||
|
NULL, tsk);
|
||||||
|
if (IS_ERR(bp))
|
||||||
|
return PTR_ERR(bp);
|
||||||
|
|
||||||
|
thread->hbp_break[0] = bp;
|
||||||
|
} else {
|
||||||
|
int err;
|
||||||
|
|
||||||
|
attr = bp->attr;
|
||||||
|
attr.bp_addr = addr;
|
||||||
|
|
||||||
|
/* Reenable breakpoint */
|
||||||
|
attr.disabled = false;
|
||||||
|
err = modify_user_hw_breakpoint(bp, &attr);
|
||||||
|
if (unlikely(err))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
csr_write64(attr.bp_addr, LOONGARCH_CSR_IB0ADDR);
|
||||||
|
}
|
||||||
|
info = counter_arch_bp(bp);
|
||||||
|
info->mask = TASK_SIZE - 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ptrace API */
|
||||||
|
void user_enable_single_step(struct task_struct *task)
|
||||||
|
{
|
||||||
|
struct thread_info *ti = task_thread_info(task);
|
||||||
|
|
||||||
|
set_single_step(task, task_pt_regs(task)->csr_era);
|
||||||
|
task->thread.single_step = task_pt_regs(task)->csr_era;
|
||||||
|
set_ti_thread_flag(ti, TIF_SINGLESTEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_disable_single_step(struct task_struct *task)
|
||||||
|
{
|
||||||
|
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
242
arch/loongarch/kernel/relocate.c
Normal file
242
arch/loongarch/kernel/relocate.c
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Support for Kernel relocation at boot time
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Loongson Technology Corporation Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/elf.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/printk.h>
|
||||||
|
#include <linux/panic_notifier.h>
|
||||||
|
#include <linux/start_kernel.h>
|
||||||
|
#include <asm/bootinfo.h>
|
||||||
|
#include <asm/early_ioremap.h>
|
||||||
|
#include <asm/inst.h>
|
||||||
|
#include <asm/sections.h>
|
||||||
|
#include <asm/setup.h>
|
||||||
|
|
||||||
|
#define RELOCATED(x) ((void *)((long)x + reloc_offset))
|
||||||
|
#define RELOCATED_KASLR(x) ((void *)((long)x + random_offset))
|
||||||
|
|
||||||
|
static unsigned long reloc_offset;
|
||||||
|
|
||||||
|
static inline void __init relocate_relative(void)
|
||||||
|
{
|
||||||
|
Elf64_Rela *rela, *rela_end;
|
||||||
|
rela = (Elf64_Rela *)&__rela_dyn_begin;
|
||||||
|
rela_end = (Elf64_Rela *)&__rela_dyn_end;
|
||||||
|
|
||||||
|
for ( ; rela < rela_end; rela++) {
|
||||||
|
Elf64_Addr addr = rela->r_offset;
|
||||||
|
Elf64_Addr relocated_addr = rela->r_addend;
|
||||||
|
|
||||||
|
if (rela->r_info != R_LARCH_RELATIVE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (relocated_addr >= VMLINUX_LOAD_ADDRESS)
|
||||||
|
relocated_addr = (Elf64_Addr)RELOCATED(relocated_addr);
|
||||||
|
|
||||||
|
*(Elf64_Addr *)RELOCATED(addr) = relocated_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __init relocate_absolute(long random_offset)
|
||||||
|
{
|
||||||
|
void *begin, *end;
|
||||||
|
struct rela_la_abs *p;
|
||||||
|
|
||||||
|
begin = RELOCATED_KASLR(&__la_abs_begin);
|
||||||
|
end = RELOCATED_KASLR(&__la_abs_end);
|
||||||
|
|
||||||
|
for (p = begin; (void *)p < end; p++) {
|
||||||
|
long v = p->symvalue;
|
||||||
|
uint32_t lu12iw, ori, lu32id, lu52id;
|
||||||
|
union loongarch_instruction *insn = (void *)p - p->offset;
|
||||||
|
|
||||||
|
lu12iw = (v >> 12) & 0xfffff;
|
||||||
|
ori = v & 0xfff;
|
||||||
|
lu32id = (v >> 32) & 0xfffff;
|
||||||
|
lu52id = v >> 52;
|
||||||
|
|
||||||
|
insn[0].reg1i20_format.immediate = lu12iw;
|
||||||
|
insn[1].reg2i12_format.immediate = ori;
|
||||||
|
insn[2].reg1i20_format.immediate = lu32id;
|
||||||
|
insn[3].reg2i12_format.immediate = lu52id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RANDOMIZE_BASE
|
||||||
|
static inline __init unsigned long rotate_xor(unsigned long hash,
|
||||||
|
const void *area, size_t size)
|
||||||
|
{
|
||||||
|
size_t i, diff;
|
||||||
|
const typeof(hash) *ptr = PTR_ALIGN(area, sizeof(hash));
|
||||||
|
|
||||||
|
diff = (void *)ptr - area;
|
||||||
|
if (size < diff + sizeof(hash))
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
size = ALIGN_DOWN(size - diff, sizeof(hash));
|
||||||
|
|
||||||
|
for (i = 0; i < size / sizeof(hash); i++) {
|
||||||
|
/* Rotate by odd number of bits and XOR. */
|
||||||
|
hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
|
||||||
|
hash ^= ptr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __init unsigned long get_random_boot(void)
|
||||||
|
{
|
||||||
|
unsigned long hash = 0;
|
||||||
|
unsigned long entropy = random_get_entropy();
|
||||||
|
|
||||||
|
/* Attempt to create a simple but unpredictable starting entropy. */
|
||||||
|
hash = rotate_xor(hash, linux_banner, strlen(linux_banner));
|
||||||
|
|
||||||
|
/* Add in any runtime entropy we can get */
|
||||||
|
hash = rotate_xor(hash, &entropy, sizeof(entropy));
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __init bool kaslr_disabled(void)
|
||||||
|
{
|
||||||
|
char *str;
|
||||||
|
const char *builtin_cmdline = CONFIG_CMDLINE;
|
||||||
|
|
||||||
|
str = strstr(builtin_cmdline, "nokaslr");
|
||||||
|
if (str == builtin_cmdline || (str > builtin_cmdline && *(str - 1) == ' '))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
str = strstr(boot_command_line, "nokaslr");
|
||||||
|
if (str == boot_command_line || (str > boot_command_line && *(str - 1) == ' '))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Choose a new address for the kernel */
|
||||||
|
static inline void __init *determine_relocation_address(void)
|
||||||
|
{
|
||||||
|
unsigned long kernel_length;
|
||||||
|
unsigned long random_offset;
|
||||||
|
void *destination = _text;
|
||||||
|
|
||||||
|
if (kaslr_disabled())
|
||||||
|
return destination;
|
||||||
|
|
||||||
|
kernel_length = (long)_end - (long)_text;
|
||||||
|
|
||||||
|
random_offset = get_random_boot() << 16;
|
||||||
|
random_offset &= (CONFIG_RANDOMIZE_BASE_MAX_OFFSET - 1);
|
||||||
|
if (random_offset < kernel_length)
|
||||||
|
random_offset += ALIGN(kernel_length, 0xffff);
|
||||||
|
|
||||||
|
return RELOCATED_KASLR(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __init relocation_addr_valid(void *location_new)
|
||||||
|
{
|
||||||
|
if ((unsigned long)location_new & 0x00000ffff)
|
||||||
|
return 0; /* Inappropriately aligned new location */
|
||||||
|
|
||||||
|
if ((unsigned long)location_new < (unsigned long)_end)
|
||||||
|
return 0; /* New location overlaps original kernel */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void __init update_reloc_offset(unsigned long *addr, long random_offset)
|
||||||
|
{
|
||||||
|
unsigned long *new_addr = (unsigned long *)RELOCATED_KASLR(addr);
|
||||||
|
|
||||||
|
*new_addr = (unsigned long)reloc_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * __init relocate_kernel(void)
|
||||||
|
{
|
||||||
|
unsigned long kernel_length;
|
||||||
|
unsigned long random_offset = 0;
|
||||||
|
void *location_new = _text; /* Default to original kernel start */
|
||||||
|
void *kernel_entry = start_kernel; /* Default to original kernel entry point */
|
||||||
|
char *cmdline = early_ioremap(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */
|
||||||
|
|
||||||
|
strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RANDOMIZE_BASE
|
||||||
|
location_new = determine_relocation_address();
|
||||||
|
|
||||||
|
/* Sanity check relocation address */
|
||||||
|
if (relocation_addr_valid(location_new))
|
||||||
|
random_offset = (unsigned long)location_new - (unsigned long)(_text);
|
||||||
|
#endif
|
||||||
|
reloc_offset = (unsigned long)_text - VMLINUX_LOAD_ADDRESS;
|
||||||
|
|
||||||
|
if (random_offset) {
|
||||||
|
kernel_length = (long)(_end) - (long)(_text);
|
||||||
|
|
||||||
|
/* Copy the kernel to it's new location */
|
||||||
|
memcpy(location_new, _text, kernel_length);
|
||||||
|
|
||||||
|
/* Sync the caches ready for execution of new kernel */
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"ibar 0 \t\n"
|
||||||
|
"dbar 0 \t\n"
|
||||||
|
::: "memory");
|
||||||
|
|
||||||
|
reloc_offset += random_offset;
|
||||||
|
|
||||||
|
/* Return the new kernel's entry point */
|
||||||
|
kernel_entry = RELOCATED_KASLR(start_kernel);
|
||||||
|
|
||||||
|
/* The current thread is now within the relocated kernel */
|
||||||
|
__current_thread_info = RELOCATED_KASLR(__current_thread_info);
|
||||||
|
|
||||||
|
update_reloc_offset(&reloc_offset, random_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reloc_offset)
|
||||||
|
relocate_relative();
|
||||||
|
|
||||||
|
relocate_absolute(random_offset);
|
||||||
|
|
||||||
|
return kernel_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show relocation information on panic.
|
||||||
|
*/
|
||||||
|
static void show_kernel_relocation(const char *level)
|
||||||
|
{
|
||||||
|
if (reloc_offset > 0) {
|
||||||
|
printk(level);
|
||||||
|
pr_cont("Kernel relocated by 0x%lx\n", reloc_offset);
|
||||||
|
pr_cont(" .text @ 0x%px\n", _text);
|
||||||
|
pr_cont(" .data @ 0x%px\n", _sdata);
|
||||||
|
pr_cont(" .bss @ 0x%px\n", __bss_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kernel_location_notifier_fn(struct notifier_block *self,
|
||||||
|
unsigned long v, void *p)
|
||||||
|
{
|
||||||
|
show_kernel_relocation(KERN_EMERG);
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct notifier_block kernel_location_notifier = {
|
||||||
|
.notifier_call = kernel_location_notifier_fn
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init register_kernel_offset_dumper(void)
|
||||||
|
{
|
||||||
|
atomic_notifier_chain_register(&panic_notifier_list,
|
||||||
|
&kernel_location_notifier);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
arch_initcall(register_kernel_offset_dumper);
|
@ -234,11 +234,14 @@ static void __init arch_reserve_vmcore(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 2MB alignment for crash kernel regions */
|
||||||
|
#define CRASH_ALIGN SZ_2M
|
||||||
|
#define CRASH_ADDR_MAX SZ_4G
|
||||||
|
|
||||||
static void __init arch_parse_crashkernel(void)
|
static void __init arch_parse_crashkernel(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_KEXEC
|
#ifdef CONFIG_KEXEC
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long long start;
|
|
||||||
unsigned long long total_mem;
|
unsigned long long total_mem;
|
||||||
unsigned long long crash_base, crash_size;
|
unsigned long long crash_base, crash_size;
|
||||||
|
|
||||||
@ -247,8 +250,13 @@ static void __init arch_parse_crashkernel(void)
|
|||||||
if (ret < 0 || crash_size <= 0)
|
if (ret < 0 || crash_size <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
start = memblock_phys_alloc_range(crash_size, 1, crash_base, crash_base + crash_size);
|
if (crash_base <= 0) {
|
||||||
if (start != crash_base) {
|
crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN, CRASH_ALIGN, CRASH_ADDR_MAX);
|
||||||
|
if (!crash_base) {
|
||||||
|
pr_warn("crashkernel reservation failed - No suitable area found.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (!memblock_phys_alloc_range(crash_size, CRASH_ALIGN, crash_base, crash_base + crash_size)) {
|
||||||
pr_warn("Invalid memory region reserved for crash kernel\n");
|
pr_warn("Invalid memory region reserved for crash kernel\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -140,16 +140,17 @@ static int get_timer_irq(void)
|
|||||||
|
|
||||||
int constant_clockevent_init(void)
|
int constant_clockevent_init(void)
|
||||||
{
|
{
|
||||||
int irq;
|
|
||||||
unsigned int cpu = smp_processor_id();
|
unsigned int cpu = smp_processor_id();
|
||||||
unsigned long min_delta = 0x600;
|
unsigned long min_delta = 0x600;
|
||||||
unsigned long max_delta = (1UL << 48) - 1;
|
unsigned long max_delta = (1UL << 48) - 1;
|
||||||
struct clock_event_device *cd;
|
struct clock_event_device *cd;
|
||||||
static int timer_irq_installed = 0;
|
static int irq = 0, timer_irq_installed = 0;
|
||||||
|
|
||||||
irq = get_timer_irq();
|
if (!timer_irq_installed) {
|
||||||
if (irq < 0)
|
irq = get_timer_irq();
|
||||||
pr_err("Failed to map irq %d (timer)\n", irq);
|
if (irq < 0)
|
||||||
|
pr_err("Failed to map irq %d (timer)\n", irq);
|
||||||
|
}
|
||||||
|
|
||||||
cd = &per_cpu(constant_clockevent_device, cpu);
|
cd = &per_cpu(constant_clockevent_device, cpu);
|
||||||
|
|
||||||
|
@ -371,9 +371,14 @@ int no_unaligned_warning __read_mostly = 1; /* Only 1 warning by default */
|
|||||||
|
|
||||||
asmlinkage void noinstr do_ale(struct pt_regs *regs)
|
asmlinkage void noinstr do_ale(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned int *pc;
|
|
||||||
irqentry_state_t state = irqentry_enter(regs);
|
irqentry_state_t state = irqentry_enter(regs);
|
||||||
|
|
||||||
|
#ifndef CONFIG_ARCH_STRICT_ALIGN
|
||||||
|
die_if_kernel("Kernel ale access", regs);
|
||||||
|
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
|
||||||
|
#else
|
||||||
|
unsigned int *pc;
|
||||||
|
|
||||||
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr);
|
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->csr_badvaddr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -397,8 +402,8 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs)
|
|||||||
sigbus:
|
sigbus:
|
||||||
die_if_kernel("Kernel ale access", regs);
|
die_if_kernel("Kernel ale access", regs);
|
||||||
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
|
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
#endif
|
||||||
irqentry_exit(regs, state);
|
irqentry_exit(regs, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +437,9 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
|
|||||||
unsigned long era = exception_era(regs);
|
unsigned long era = exception_era(regs);
|
||||||
irqentry_state_t state = irqentry_enter(regs);
|
irqentry_state_t state = irqentry_enter(regs);
|
||||||
|
|
||||||
local_irq_enable();
|
if (regs->csr_prmd & CSR_PRMD_PIE)
|
||||||
|
local_irq_enable();
|
||||||
|
|
||||||
current->thread.trap_nr = read_csr_excode();
|
current->thread.trap_nr = read_csr_excode();
|
||||||
if (__get_inst(&opcode, (u32 *)era, user))
|
if (__get_inst(&opcode, (u32 *)era, user))
|
||||||
goto out_sigsegv;
|
goto out_sigsegv;
|
||||||
@ -445,14 +452,12 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
|
|||||||
*/
|
*/
|
||||||
switch (bcode) {
|
switch (bcode) {
|
||||||
case BRK_KPROBE_BP:
|
case BRK_KPROBE_BP:
|
||||||
if (notify_die(DIE_BREAK, "Kprobe", regs, bcode,
|
if (kprobe_breakpoint_handler(regs))
|
||||||
current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
|
|
||||||
goto out;
|
goto out;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
case BRK_KPROBE_SSTEPBP:
|
case BRK_KPROBE_SSTEPBP:
|
||||||
if (notify_die(DIE_SSTEPBP, "Kprobe_SingleStep", regs, bcode,
|
if (kprobe_singlestep_handler(regs))
|
||||||
current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
|
|
||||||
goto out;
|
goto out;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
@ -495,7 +500,9 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
local_irq_disable();
|
if (regs->csr_prmd & CSR_PRMD_PIE)
|
||||||
|
local_irq_disable();
|
||||||
|
|
||||||
irqentry_exit(regs, state);
|
irqentry_exit(regs, state);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -506,7 +513,52 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
|
|||||||
|
|
||||||
asmlinkage void noinstr do_watch(struct pt_regs *regs)
|
asmlinkage void noinstr do_watch(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
irqentry_state_t state = irqentry_enter(regs);
|
||||||
|
|
||||||
|
#ifndef CONFIG_HAVE_HW_BREAKPOINT
|
||||||
pr_warn("Hardware watch point handler not implemented!\n");
|
pr_warn("Hardware watch point handler not implemented!\n");
|
||||||
|
#else
|
||||||
|
if (test_tsk_thread_flag(current, TIF_SINGLESTEP)) {
|
||||||
|
int llbit = (csr_read32(LOONGARCH_CSR_LLBCTL) & 0x1);
|
||||||
|
unsigned long pc = instruction_pointer(regs);
|
||||||
|
union loongarch_instruction *ip = (union loongarch_instruction *)pc;
|
||||||
|
|
||||||
|
if (llbit) {
|
||||||
|
/*
|
||||||
|
* When the ll-sc combo is encountered, it is regarded as an single
|
||||||
|
* instruction. So don't clear llbit and reset CSR.FWPS.Skip until
|
||||||
|
* the llsc execution is completed.
|
||||||
|
*/
|
||||||
|
csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS);
|
||||||
|
csr_write32(CSR_LLBCTL_KLO, LOONGARCH_CSR_LLBCTL);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pc == current->thread.single_step) {
|
||||||
|
/*
|
||||||
|
* Certain insns are occasionally not skipped when CSR.FWPS.Skip is
|
||||||
|
* set, such as fld.d/fst.d. So singlestep needs to compare whether
|
||||||
|
* the csr_era is equal to the value of singlestep which last time set.
|
||||||
|
*/
|
||||||
|
if (!is_self_loop_ins(ip, regs)) {
|
||||||
|
/*
|
||||||
|
* Check if the given instruction the target pc is equal to the
|
||||||
|
* current pc, If yes, then we should not set the CSR.FWPS.SKIP
|
||||||
|
* bit to break the original instruction stream.
|
||||||
|
*/
|
||||||
|
csr_write32(CSR_FWPC_SKIP, LOONGARCH_CSR_FWPS);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
breakpoint_handler(regs);
|
||||||
|
watchpoint_handler(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
force_sig(SIGTRAP);
|
||||||
|
out:
|
||||||
|
#endif
|
||||||
|
irqentry_exit(regs, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void noinstr do_ri(struct pt_regs *regs)
|
asmlinkage void noinstr do_ri(struct pt_regs *regs)
|
||||||
|
@ -65,10 +65,21 @@ SECTIONS
|
|||||||
__alt_instructions_end = .;
|
__alt_instructions_end = .;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_RELOCATABLE
|
||||||
|
. = ALIGN(8);
|
||||||
|
.la_abs : AT(ADDR(.la_abs) - LOAD_OFFSET) {
|
||||||
|
__la_abs_begin = .;
|
||||||
|
*(.la_abs)
|
||||||
|
__la_abs_end = .;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
.got : ALIGN(16) { *(.got) }
|
.got : ALIGN(16) { *(.got) }
|
||||||
.plt : ALIGN(16) { *(.plt) }
|
.plt : ALIGN(16) { *(.plt) }
|
||||||
.got.plt : ALIGN(16) { *(.got.plt) }
|
.got.plt : ALIGN(16) { *(.got.plt) }
|
||||||
|
|
||||||
|
.data.rel : { *(.data.rel*) }
|
||||||
|
|
||||||
. = ALIGN(PECOFF_SEGMENT_ALIGN);
|
. = ALIGN(PECOFF_SEGMENT_ALIGN);
|
||||||
__init_begin = .;
|
__init_begin = .;
|
||||||
__inittext_begin = .;
|
__inittext_begin = .;
|
||||||
@ -92,8 +103,6 @@ SECTIONS
|
|||||||
PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
|
PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
.rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
|
|
||||||
|
|
||||||
.init.bss : {
|
.init.bss : {
|
||||||
*(.init.bss)
|
*(.init.bss)
|
||||||
}
|
}
|
||||||
@ -106,6 +115,12 @@ SECTIONS
|
|||||||
RO_DATA(4096)
|
RO_DATA(4096)
|
||||||
RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
|
RW_DATA(1 << CONFIG_L1_CACHE_SHIFT, PAGE_SIZE, THREAD_SIZE)
|
||||||
|
|
||||||
|
.rela.dyn : ALIGN(8) {
|
||||||
|
__rela_dyn_begin = .;
|
||||||
|
*(.rela.dyn) *(.rela*)
|
||||||
|
__rela_dyn_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
.sdata : {
|
.sdata : {
|
||||||
*(.sdata)
|
*(.sdata)
|
||||||
}
|
}
|
||||||
@ -132,6 +147,7 @@ SECTIONS
|
|||||||
|
|
||||||
DISCARDS
|
DISCARDS
|
||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
|
*(.dynamic .dynsym .dynstr .hash .gnu.hash)
|
||||||
*(.gnu.attributes)
|
*(.gnu.attributes)
|
||||||
*(.options)
|
*(.options)
|
||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user