mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-03 19:55:31 +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_cpu'
|
||||
- 'for_each_cpu_and'
|
||||
- 'for_each_cpu_not'
|
||||
- 'for_each_cpu_wrap'
|
||||
- 'for_each_dapm_widgets'
|
||||
- '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@mips.com>
|
||||
<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> <[dbaryshkov@gmail.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@linux.alibaba.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> <gerald.schaefer@de.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> <m.chehab@samsung.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@free-electrons.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 Kelley <simon@thekelleys.org.uk>
|
||||
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@opengridcomputing.com>
|
||||
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@sw.ru>
|
||||
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@linux.intel.com>
|
||||
Vinod Koul <vkoul@kernel.org> <vkoul@infradead.org>
|
||||
|
@ -437,7 +437,8 @@ What: /sys/class/power_supply/<supply_name>/present
|
||||
Date: May 2007
|
||||
Contact: linux-pm@vger.kernel.org
|
||||
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
|
||||
|
||||
|
@ -6,6 +6,19 @@ Description:
|
||||
device at boot. It is equivalent to WDIOC_GETBOOTSTATUS of
|
||||
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
|
||||
Date: August 2015
|
||||
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.
|
||||
updates in f2fs. User can set:
|
||||
|
||||
==== =================
|
||||
0x01 F2FS_IPU_FORCE
|
||||
0x02 F2FS_IPU_SSR
|
||||
0x04 F2FS_IPU_UTIL
|
||||
0x08 F2FS_IPU_SSR_UTIL
|
||||
0x10 F2FS_IPU_FSYNC
|
||||
0x20 F2FS_IPU_ASYNC
|
||||
0x40 F2FS_IPU_NOCACHE
|
||||
0x80 F2FS_IPU_HONOR_OPU_WRITE
|
||||
==== =================
|
||||
===== =============== ===================================================
|
||||
value policy description
|
||||
0x00 DISABLE disable IPU(=default option in LFS mode)
|
||||
0x01 FORCE all the time
|
||||
0x02 SSR if SSR mode is activated
|
||||
0x04 UTIL if FS utilization is over threashold
|
||||
0x08 SSR_UTIL if SSR mode is activated and FS utilization is over
|
||||
threashold
|
||||
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.
|
||||
|
||||
@ -669,3 +676,56 @@ Contact: "Ping Xiong" <xiongping1@xiaomi.com>
|
||||
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
|
||||
(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,
|
||||
cases. See :ref:`[3] <spec_ref3>` for more details.
|
||||
|
||||
On CPUs with hardware mitigation for Spectre variant 2 (e.g. Enhanced
|
||||
IBRS on x86), retpoline is automatically disabled at run time.
|
||||
On CPUs with hardware mitigation for Spectre variant 2 (e.g. IBRS
|
||||
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
|
||||
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
|
||||
can be compiled with return trampolines for indirect branches.
|
||||
This protects them from consuming poisoned entries in the branch
|
||||
target buffer left by malicious software. Alternatively, the
|
||||
programs can disable their indirect branch speculation via prctl()
|
||||
(See :ref:`Documentation/userspace-api/spec_ctrl.rst <set_spec_ctrl>`).
|
||||
target buffer left by malicious software.
|
||||
|
||||
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
|
||||
sibling thread when the user program is running, and use IBPB to
|
||||
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.
|
||||
|
||||
For general information about submitting patches, please refer to
|
||||
`Documentation/process/`_. This document only describes additional specifics
|
||||
related to BPF.
|
||||
Documentation/process/submitting-patches.rst. This document only describes
|
||||
additional specifics related to BPF.
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
@ -461,15 +461,15 @@ needed::
|
||||
|
||||
$ sudo make run_tests
|
||||
|
||||
See the kernels selftest `Documentation/dev-tools/kselftest.rst`_
|
||||
document for further documentation.
|
||||
See :doc:`kernel selftest documentation </dev-tools/kselftest>`
|
||||
for details.
|
||||
|
||||
To maximize the number of tests passing, the .config of the kernel
|
||||
under test should match the config file fragment in
|
||||
tools/testing/selftests/bpf as closely as possible.
|
||||
|
||||
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.
|
||||
pahole is delivered in the dwarves package or can be built
|
||||
from source at
|
||||
@ -684,12 +684,8 @@ when:
|
||||
|
||||
|
||||
.. Links
|
||||
.. _Documentation/process/: https://www.kernel.org/doc/html/latest/process/
|
||||
.. _netdev-FAQ: https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
|
||||
.. _selftests:
|
||||
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!
|
||||
|
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%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#
|
||||
|
||||
title: Richtek RT9467 Switching Battery Charger with Power Path Management
|
||||
@ -25,7 +25,7 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: richtek,rt9467-charger
|
||||
const: richtek,rt9467
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -65,7 +65,7 @@ examples:
|
||||
#size-cells = <0>;
|
||||
|
||||
charger@5b {
|
||||
compatible = "richtek,rt9467-charger";
|
||||
compatible = "richtek,rt9467";
|
||||
reg = <0x5b>;
|
||||
wakeup-source;
|
||||
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:
|
||||
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:
|
||||
- $ref: "rtc.yaml#"
|
||||
@ -24,8 +25,14 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
description: the TIMER interrupt
|
||||
maxItems: 1
|
||||
minItems: 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:
|
||||
description: clock reference in the 27MHz domain
|
||||
@ -35,10 +42,10 @@ additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
rtc@f0411580 {
|
||||
rtc@f041a080 {
|
||||
compatible = "brcm,brcmstb-waketimer";
|
||||
reg = <0xf0411580 0x14>;
|
||||
interrupts = <0x3>;
|
||||
interrupt-parent = <&aon_pm_l2_intc>;
|
||||
reg = <0xf041a080 0x14>;
|
||||
interrupts-extended = <&aon_pm_l2_intc 0x04>,
|
||||
<&upg_aux_aon_intr2_intc 0x08>;
|
||||
clocks = <&upg_fixed>;
|
||||
};
|
||||
|
@ -11,6 +11,17 @@ maintainers:
|
||||
|
||||
allOf:
|
||||
- $ref: rtc.yaml#
|
||||
- if:
|
||||
not:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- ingenic,jz4770-rtc
|
||||
- ingenic,jz4780-rtc
|
||||
then:
|
||||
properties:
|
||||
"#clock-cells": false
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -39,6 +50,9 @@ properties:
|
||||
clock-names:
|
||||
const: rtc
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
system-power-controller:
|
||||
description: |
|
||||
Indicates that the RTC is responsible for powering OFF
|
||||
@ -83,3 +97,18 @@ examples:
|
||||
clocks = <&cgu JZ4740_CLK_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:
|
||||
|
||||
- compatible : Should be "moxa,moxart-rtc"
|
||||
- gpio-rtc-sclk : RTC sclk gpio, with zero flags
|
||||
- gpio-rtc-data : RTC data gpio, with zero flags
|
||||
- gpio-rtc-reset : RTC reset gpio, with zero flags
|
||||
- rtc-sclk-gpios : RTC sclk gpio, with zero flags
|
||||
- rtc-data-gpios : RTC data gpio, with zero flags
|
||||
- rtc-reset-gpios : RTC reset gpio, with zero flags
|
||||
|
||||
Example:
|
||||
|
||||
rtc: rtc {
|
||||
compatible = "moxa,moxart-rtc";
|
||||
gpio-rtc-sclk = <&gpio 5 0>;
|
||||
gpio-rtc-data = <&gpio 6 0>;
|
||||
gpio-rtc-reset = <&gpio 7 0>;
|
||||
rtc-sclk-gpios = <&gpio 5 0>;
|
||||
rtc-data-gpios = <&gpio 6 0>;
|
||||
rtc-reset-gpios = <&gpio 7 0>;
|
||||
};
|
||||
|
@ -14,7 +14,10 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: nxp,pcf2127
|
||||
enum:
|
||||
- nxp,pca2129
|
||||
- nxp,pcf2127
|
||||
- nxp,pcf2129
|
||||
|
||||
reg:
|
||||
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
|
||||
- nxp,pca8565
|
||||
- nxp,pcf8563
|
||||
- nxp,pcf85263
|
||||
- nxp,pcf85363
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -40,6 +40,16 @@ properties:
|
||||
description:
|
||||
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
|
||||
|
||||
required:
|
||||
@ -69,6 +79,8 @@ examples:
|
||||
compatible = "qcom,pm8921-rtc";
|
||||
reg = <0x11d>;
|
||||
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
|
||||
# Intersil ISL12022 Real-time Clock
|
||||
- isil,isl12022
|
||||
# Real Time Clock Module with I2C-Bus
|
||||
- microcrystal,rv3028
|
||||
# Loongson-2K Socs/LS7A bridge Real-time Clock
|
||||
- loongson,ls2x-rtc
|
||||
# Real Time Clock Module with I2C-Bus
|
||||
- microcrystal,rv3029
|
||||
# Real Time Clock
|
||||
- microcrystal,rv8523
|
||||
- nxp,pca2129
|
||||
- nxp,pcf2129
|
||||
# Real-time Clock Module
|
||||
- pericom,pt7c4338
|
||||
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
|
@ -23,6 +23,7 @@ properties:
|
||||
- enum:
|
||||
- apple,t6000-mca
|
||||
- apple,t8103-mca
|
||||
- apple,t8112-mca
|
||||
- const: apple,mca
|
||||
|
||||
reg:
|
||||
|
@ -67,6 +67,12 @@ properties:
|
||||
maxItems: 4
|
||||
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:
|
||||
- compatible
|
||||
- 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:
|
||||
- Anson Huang <Anson.Huang@nxp.com>
|
||||
|
||||
allOf:
|
||||
- $ref: "watchdog.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
@ -55,11 +52,45 @@ properties:
|
||||
If present, the watchdog device is configured to assert its
|
||||
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:
|
||||
- compatible
|
||||
- interrupts
|
||||
- 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
|
||||
|
||||
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:
|
||||
maxItems: 1
|
||||
|
||||
mediatek,sysctl:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
phandle to system controller 'sysc' syscon node which
|
||||
controls system registers
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -30,4 +36,5 @@ examples:
|
||||
watchdog@100 {
|
||||
compatible = "mediatek,mt7621-wdt";
|
||||
reg = <0x100 0x100>;
|
||||
mediatek,sysctl = <&sysc>;
|
||||
};
|
||||
|
@ -52,6 +52,12 @@ properties:
|
||||
description: Disable sending output reset signal
|
||||
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':
|
||||
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:
|
||||
- Sai Prakash Ranjan <saiprakash.ranjan@codeaurora.org>
|
||||
|
||||
allOf:
|
||||
- $ref: watchdog.yaml#
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^(watchdog|timer)@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,kpss-wdt-ipq4019
|
||||
- qcom,apss-wdt-msm8994
|
||||
- qcom,apss-wdt-qcs404
|
||||
- qcom,apss-wdt-sa8775p
|
||||
- qcom,apss-wdt-sc7180
|
||||
- qcom,apss-wdt-sc7280
|
||||
- qcom,apss-wdt-sc8180x
|
||||
@ -29,15 +32,19 @@ properties:
|
||||
- qcom,apss-wdt-sm8150
|
||||
- qcom,apss-wdt-sm8250
|
||||
- const: qcom,kpss-wdt
|
||||
- const: qcom,kpss-wdt
|
||||
deprecated: true
|
||||
- items:
|
||||
- const: qcom,scss-timer
|
||||
- const: qcom,msm-timer
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,kpss-wdt
|
||||
- qcom,kpss-timer
|
||||
- qcom,kpss-wdt-apq8064
|
||||
- qcom,kpss-wdt-ipq4019
|
||||
- qcom,kpss-wdt-ipq8064
|
||||
- qcom,kpss-wdt-mdm9615
|
||||
- qcom,kpss-wdt-msm8960
|
||||
- qcom,scss-timer
|
||||
- const: qcom,kpss-timer
|
||||
- const: qcom,msm-timer
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -45,18 +52,87 @@ properties:
|
||||
clocks:
|
||||
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:
|
||||
- compatible
|
||||
- reg
|
||||
- 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
|
||||
|
||||
examples:
|
||||
- |
|
||||
watchdog@208a038 {
|
||||
compatible = "qcom,kpss-wdt-ipq8064";
|
||||
reg = <0x0208a038 0x40>;
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
watchdog@17c10000 {
|
||||
compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt";
|
||||
reg = <0x17c10000 0x1000>;
|
||||
clocks = <&sleep_clk>;
|
||||
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
|
||||
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:
|
||||
- enum:
|
||||
- renesas,r9a07g043-wdt # RZ/G2UL
|
||||
- renesas,r9a07g043-wdt # RZ/G2UL and RZ/Five
|
||||
- renesas,r9a07g044-wdt # RZ/G2{L,LC}
|
||||
- renesas,r9a07g054-wdt # RZ/V2L
|
||||
- const: renesas,rzg2l-wdt
|
||||
|
@ -14,9 +14,14 @@ description: |
|
||||
This document describes generic bindings which can be used to
|
||||
describe watchdog devices in a device tree.
|
||||
|
||||
select:
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^watchdog(@.*|-[0-9a-f])?$"
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^watchdog(@.*|-[0-9a-f])?$"
|
||||
pattern: "^(timer|watchdog)(@.*|-[0-9a-f])?$"
|
||||
|
||||
timeout-sec:
|
||||
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
|
||||
but f2fs still guarantees the write ordering of all the
|
||||
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.
|
||||
fastboot This option is used when a system wants to reduce mount
|
||||
time as much as possible, even though normal performance
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
.. _linux_doc:
|
||||
|
||||
==============================
|
||||
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.
|
||||
|
||||
Working with the development community
|
||||
--------------------------------------
|
||||
======================================
|
||||
|
||||
The essential guides for interacting with the kernel's development
|
||||
community and getting your work upstream.
|
||||
@ -29,7 +30,7 @@ community and getting your work upstream.
|
||||
|
||||
|
||||
Internal API manuals
|
||||
--------------------
|
||||
====================
|
||||
|
||||
Manuals for use by developers working to interface with the rest of the
|
||||
kernel.
|
||||
@ -43,7 +44,7 @@ kernel.
|
||||
Locking in the kernel <locking/index>
|
||||
|
||||
Development tools and processes
|
||||
-------------------------------
|
||||
===============================
|
||||
|
||||
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
|
||||
---------------------------
|
||||
===========================
|
||||
|
||||
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
|
||||
@ -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.
|
||||
|
||||
Firmware-related documentation
|
||||
------------------------------
|
||||
==============================
|
||||
The following holds information on the kernel's expectations regarding the
|
||||
platform firmwares.
|
||||
|
||||
@ -93,7 +94,7 @@ platform firmwares.
|
||||
|
||||
|
||||
Architecture-specific documentation
|
||||
-----------------------------------
|
||||
===================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
@ -102,7 +103,7 @@ Architecture-specific documentation
|
||||
|
||||
|
||||
Other documentation
|
||||
-------------------
|
||||
===================
|
||||
|
||||
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
|
||||
@ -115,7 +116,7 @@ to ReStructured Text format, or are simply too old.
|
||||
|
||||
|
||||
Translations
|
||||
------------
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
@ -5,7 +5,7 @@ Kernel Lock Torture Test Operation
|
||||
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
|
||||
module, 'locktorture', may be built after the fact on the running
|
||||
kernel to be tested, if desired. The tests periodically output status
|
||||
@ -67,7 +67,7 @@ torture_type
|
||||
|
||||
- "rtmutex_lock":
|
||||
rtmutex_lock() and rtmutex_unlock() pairs.
|
||||
Kernel must have CONFIG_RT_MUTEX=y.
|
||||
Kernel must have CONFIG_RT_MUTEXES=y.
|
||||
|
||||
- "rwsem_lock":
|
||||
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
|
||||
---
|
||||
$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
|
||||
---
|
||||
$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
|
||||
---
|
||||
$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
|
||||
|
||||
protocol: genetlink-legacy
|
||||
@ -11,7 +13,6 @@ attribute-sets:
|
||||
-
|
||||
name: dev-index
|
||||
type: u32
|
||||
value: 1
|
||||
-
|
||||
name: dev-name
|
||||
type: string
|
||||
@ -25,7 +26,6 @@ attribute-sets:
|
||||
-
|
||||
name: index
|
||||
type: u32
|
||||
value: 1
|
||||
-
|
||||
name: name
|
||||
type: string
|
||||
@ -39,14 +39,12 @@ attribute-sets:
|
||||
name: bit
|
||||
type: nest
|
||||
nested-attributes: bitset-bit
|
||||
value: 1
|
||||
-
|
||||
name: bitset
|
||||
attributes:
|
||||
-
|
||||
name: nomask
|
||||
type: flag
|
||||
value: 1
|
||||
-
|
||||
name: size
|
||||
type: u32
|
||||
@ -61,7 +59,6 @@ attribute-sets:
|
||||
-
|
||||
name: index
|
||||
type: u32
|
||||
value: 1
|
||||
-
|
||||
name: value
|
||||
type: string
|
||||
@ -71,7 +68,6 @@ attribute-sets:
|
||||
-
|
||||
name: string
|
||||
type: nest
|
||||
value: 1
|
||||
multi-attr: true
|
||||
nested-attributes: string
|
||||
-
|
||||
@ -80,7 +76,6 @@ attribute-sets:
|
||||
-
|
||||
name: id
|
||||
type: u32
|
||||
value: 1
|
||||
-
|
||||
name: count
|
||||
type: u32
|
||||
@ -96,14 +91,12 @@ attribute-sets:
|
||||
name: stringset
|
||||
type: nest
|
||||
multi-attr: true
|
||||
value: 1
|
||||
nested-attributes: stringset
|
||||
-
|
||||
name: strset
|
||||
attributes:
|
||||
-
|
||||
name: header
|
||||
value: 1
|
||||
type: nest
|
||||
nested-attributes: header
|
||||
-
|
||||
@ -119,7 +112,6 @@ attribute-sets:
|
||||
attributes:
|
||||
-
|
||||
name: header
|
||||
value: 1
|
||||
type: nest
|
||||
nested-attributes: header
|
||||
-
|
||||
@ -132,7 +124,6 @@ attribute-sets:
|
||||
attributes:
|
||||
-
|
||||
name: header
|
||||
value: 1
|
||||
type: nest
|
||||
nested-attributes: header
|
||||
-
|
||||
@ -180,7 +171,6 @@ attribute-sets:
|
||||
attributes:
|
||||
-
|
||||
name: pad
|
||||
value: 1
|
||||
type: pad
|
||||
-
|
||||
name: reassembly-errors
|
||||
@ -205,7 +195,6 @@ attribute-sets:
|
||||
attributes:
|
||||
-
|
||||
name: header
|
||||
value: 1
|
||||
type: nest
|
||||
nested-attributes: header
|
||||
-
|
||||
@ -251,13 +240,11 @@ operations:
|
||||
|
||||
do: &strset-get-op
|
||||
request:
|
||||
value: 1
|
||||
attributes:
|
||||
- header
|
||||
- stringsets
|
||||
- counts-only
|
||||
reply:
|
||||
value: 1
|
||||
attributes:
|
||||
- header
|
||||
- stringsets
|
||||
|
@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
|
||||
name: fou
|
||||
|
||||
protocol: genetlink-legacy
|
||||
@ -26,6 +28,7 @@ attribute-sets:
|
||||
-
|
||||
name: unspec
|
||||
type: unused
|
||||
value: 0
|
||||
-
|
||||
name: port
|
||||
type: u16
|
||||
@ -71,6 +74,7 @@ operations:
|
||||
-
|
||||
name: unspec
|
||||
doc: unused
|
||||
value: 0
|
||||
|
||||
-
|
||||
name: add
|
||||
|
@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
|
||||
name: netdev
|
||||
|
||||
doc:
|
||||
@ -48,7 +50,6 @@ attribute-sets:
|
||||
name: ifindex
|
||||
doc: netdev ifindex
|
||||
type: u32
|
||||
value: 1
|
||||
checks:
|
||||
min: 1
|
||||
-
|
||||
@ -66,7 +67,6 @@ operations:
|
||||
-
|
||||
name: dev-get
|
||||
doc: Get / dump information about a netdev.
|
||||
value: 1
|
||||
attribute-set: dev
|
||||
do:
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
hopefully inspires them to help us again in the future. Please note that if
|
||||
the bug was reported in private, then ask for permission first before using the
|
||||
Reported-by tag. The tag is intended for bugs; please do not use it to credit
|
||||
feature requests.
|
||||
hopefully inspires them to help us again in the future. The tag is intended for
|
||||
bugs; please do not use it to credit feature requests. The tag should be
|
||||
followed by a Link: tag pointing to the report, unless the report is not
|
||||
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
|
||||
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
|
||||
============ ================ ==============================================
|
||||
``x86`` Maintained ``x86_64`` only.
|
||||
``um`` Maintained ``x86_64`` only.
|
||||
============ ================ ==============================================
|
||||
|
||||
|
@ -17,3 +17,4 @@
|
||||
kernel-enforcement-statement
|
||||
email-clients
|
||||
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.
|
||||
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
|
||||
====================
|
||||
|
||||
@ -197,9 +200,15 @@ value
|
||||
Numerical attribute ID, used in serialized Netlink messages.
|
||||
The ``value`` property can be skipped, in which case the attribute ID
|
||||
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
|
||||
~~~~
|
||||
|
@ -7795,6 +7795,7 @@ M: Chao Yu <chao@kernel.org>
|
||||
L: linux-f2fs-devel@lists.sourceforge.net
|
||||
S: Maintained
|
||||
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
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
|
||||
F: Documentation/ABI/testing/sysfs-fs-f2fs
|
||||
@ -7910,6 +7911,7 @@ F: include/trace/events/fs_dax.h
|
||||
|
||||
FILESYSTEMS (VFS and infrastructure)
|
||||
M: Alexander Viro <viro@zeniv.linux.org.uk>
|
||||
M: Christian Brauner <brauner@kernel.org>
|
||||
L: linux-fsdevel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: fs/*
|
||||
@ -9789,13 +9791,6 @@ L: netdev@vger.kernel.org
|
||||
S: Supported
|
||||
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
|
||||
M: Nick Child <nnac123@linux.ibm.com>
|
||||
L: netdev@vger.kernel.org
|
||||
|
4
Makefile
4
Makefile
@ -1,8 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
VERSION = 6
|
||||
PATCHLEVEL = 2
|
||||
PATCHLEVEL = 3
|
||||
SUBLEVEL = 0
|
||||
EXTRAVERSION =
|
||||
EXTRAVERSION = -rc1
|
||||
NAME = Hurr durr I'ma ninja sloth
|
||||
|
||||
# *DOCUMENTATION*
|
||||
|
@ -152,8 +152,11 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
|
||||
the fault. */
|
||||
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;
|
||||
}
|
||||
|
||||
/* The fault is fully completed (including releasing mmap lock) */
|
||||
if (fault & VM_FAULT_COMPLETED)
|
||||
|
@ -100,7 +100,6 @@ config ARM64
|
||||
select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
|
||||
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_HUGETLB_PAGE_OPTIMIZE_VMEMMAP
|
||||
select ARCH_WANT_LD_ORPHAN_WARN
|
||||
select ARCH_WANTS_NO_INSTR
|
||||
select ARCH_WANTS_THP_SWAP if ARM64_4K_PAGES
|
||||
@ -187,7 +186,8 @@ config ARM64
|
||||
select HAVE_DMA_CONTIGUOUS
|
||||
select HAVE_DYNAMIC_FTRACE
|
||||
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 \
|
||||
if DYNAMIC_FTRACE_WITH_ARGS
|
||||
select HAVE_EFFICIENT_UNALIGNED_ACCESS
|
||||
|
@ -180,6 +180,7 @@
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/mmdebug.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/boot.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#if VA_BITS > 48
|
||||
@ -203,6 +204,16 @@ static inline unsigned long kaslr_offset(void)
|
||||
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.
|
||||
*/
|
||||
|
@ -435,10 +435,6 @@ int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
enum arm_smccc_conduit conduit;
|
||||
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)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@ -448,6 +444,10 @@ int acpi_ffh_address_space_arch_setup(void *handler_ctxt, void **region_ctxt)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ffh_ctxt = kzalloc(sizeof(*ffh_ctxt), GFP_KERNEL);
|
||||
if (!ffh_ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
if (conduit == SMCCC_CONDUIT_SMC) {
|
||||
ffh_ctxt->invoke_ffh_fn = __arm_smccc_smc;
|
||||
ffh_ctxt->invoke_ffh64_fn = arm_smccc_1_2_smc;
|
||||
|
@ -1633,7 +1633,7 @@ bool kaslr_requires_kpti(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
return kaslr_offset() > 0;
|
||||
return kaslr_enabled();
|
||||
}
|
||||
|
||||
static bool __meltdown_safe = true;
|
||||
|
@ -2122,9 +2122,6 @@ static int __init fpsimd_init(void)
|
||||
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();
|
||||
sme_sysctl_init();
|
||||
|
||||
|
@ -41,7 +41,7 @@ static int __init kaslr_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!kaslr_offset()) {
|
||||
if (!kaslr_enabled()) {
|
||||
pr_warn("KASLR disabled due to lack of seed\n");
|
||||
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)) {
|
||||
case BUG_TRAP_TYPE_BUG:
|
||||
die("Oops - CFI", regs, 0);
|
||||
die("Oops - CFI", regs, esr);
|
||||
break;
|
||||
|
||||
case BUG_TRAP_TYPE_WARN:
|
||||
|
@ -22,7 +22,8 @@ void copy_highpage(struct page *to, struct page *from)
|
||||
copy_page(kto, kfrom);
|
||||
|
||||
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 */
|
||||
WARN_ON_ONCE(!try_page_mte_tagging(to));
|
||||
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);
|
||||
|
||||
if (fault_signal_pending(fault, regs))
|
||||
if (fault_signal_pending(fault, regs)) {
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The fault is fully completed (including releasing mmap lock) */
|
||||
if (fault & VM_FAULT_COMPLETED)
|
||||
|
@ -15,11 +15,7 @@
|
||||
#include <linux/types.h>
|
||||
/* include compiler specific intrinsics */
|
||||
#include <asm/ia64regs.h>
|
||||
#ifdef __INTEL_COMPILER
|
||||
# include <asm/intel_intrin.h>
|
||||
#else
|
||||
# include <asm/gcc_intrin.h>
|
||||
#endif
|
||||
#include <asm/gcc_intrin.h>
|
||||
|
||||
/*
|
||||
* 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 compiler specific intrinsics */
|
||||
#include <asm/ia64regs.h>
|
||||
#ifdef __INTEL_COMPILER
|
||||
# include <asm/intel_intrin.h>
|
||||
#else
|
||||
# include <asm/gcc_intrin.h>
|
||||
#endif
|
||||
#include <asm/gcc_intrin.h>
|
||||
#include <asm/cmpxchg.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
cpumask_t tmp_map;
|
||||
int cpu;
|
||||
|
||||
cpumask_complement(&tmp_map, cpu_present_mask);
|
||||
cpu = cpumask_first(&tmp_map);
|
||||
cpu = cpumask_first_zero(cpu_present_mask);
|
||||
if (cpu >= nr_cpu_ids)
|
||||
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);
|
||||
|
||||
if (fault_signal_pending(fault, regs))
|
||||
if (fault_signal_pending(fault, regs)) {
|
||||
if (!user_mode(regs))
|
||||
goto no_context;
|
||||
return;
|
||||
}
|
||||
|
||||
/* The fault is fully completed (including releasing mmap lock) */
|
||||
if (fault & VM_FAULT_COMPLETED)
|
||||
|
@ -94,15 +94,21 @@ config LOONGARCH
|
||||
select HAVE_DYNAMIC_FTRACE_WITH_ARGS
|
||||
select HAVE_DYNAMIC_FTRACE_WITH_REGS
|
||||
select HAVE_EBPF_JIT
|
||||
select HAVE_EFFICIENT_UNALIGNED_ACCESS if !ARCH_STRICT_ALIGN
|
||||
select HAVE_EXIT_THREAD
|
||||
select HAVE_FAST_GUP
|
||||
select HAVE_FTRACE_MCOUNT_RECORD
|
||||
select HAVE_FUNCTION_ARG_ACCESS_API
|
||||
select HAVE_FUNCTION_GRAPH_TRACER
|
||||
select HAVE_FUNCTION_TRACER
|
||||
select HAVE_GENERIC_VDSO
|
||||
select HAVE_HW_BREAKPOINT if PERF_EVENTS
|
||||
select HAVE_IOREMAP_PROT
|
||||
select HAVE_IRQ_EXIT_ON_IRQ_STACK
|
||||
select HAVE_IRQ_TIME_ACCOUNTING
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KPROBES_ON_FTRACE
|
||||
select HAVE_KRETPROBES
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select HAVE_NMI
|
||||
select HAVE_PCI
|
||||
@ -441,6 +447,24 @@ config ARCH_IOREMAP
|
||||
protection support. However, you can enable LoongArch DMW-based
|
||||
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
|
||||
bool "Kexec system call"
|
||||
select KEXEC_CORE
|
||||
@ -454,6 +478,7 @@ config KEXEC
|
||||
|
||||
config CRASH_DUMP
|
||||
bool "Build kdump crash kernel"
|
||||
select RELOCATABLE
|
||||
help
|
||||
Generate crash dump after being started by kexec. This should
|
||||
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
|
||||
|
||||
config PHYSICAL_START
|
||||
hex "Physical address where the kernel is loaded"
|
||||
default "0x90000000a0000000"
|
||||
depends on CRASH_DUMP
|
||||
config RELOCATABLE
|
||||
bool "Relocatable kernel"
|
||||
help
|
||||
This gives the XKPRANGE address where the kernel is loaded.
|
||||
If you plan to use kernel for capturing the crash dump change
|
||||
this value to start of the reserved region (the "X" value as
|
||||
specified in the "crashkernel=YM@XM" command line boot parameter
|
||||
passed to the panic-ed kernel).
|
||||
This builds the kernel as a Position Independent Executable (PIE),
|
||||
which retains all relocation metadata required, so as to relocate
|
||||
the kernel binary at runtime to a different virtual address from
|
||||
its link address.
|
||||
|
||||
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
|
||||
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
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_RELOCATABLE),y)
|
||||
KBUILD_CFLAGS_KERNEL += -fPIE
|
||||
LDFLAGS_vmlinux += -static -pie --no-dynamic-linker -z notext
|
||||
endif
|
||||
|
||||
cflags-y += -ffreestanding
|
||||
cflags-y += $(call cc-option, -mno-check-zero-division)
|
||||
|
||||
ifndef CONFIG_PHYSICAL_START
|
||||
load-y = 0x9000000000200000
|
||||
else
|
||||
load-y = $(CONFIG_PHYSICAL_START)
|
||||
endif
|
||||
bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y)
|
||||
|
||||
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.
|
||||
KBUILD_CFLAGS += -fno-asynchronous-unwind-tables
|
||||
|
||||
ifdef CONFIG_ARCH_STRICT_ALIGN
|
||||
# Don't emit unaligned accesses.
|
||||
# Not all LoongArch cores support unaligned access, and as kernel we can't
|
||||
# rely on others to provide emulation for these accesses.
|
||||
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)
|
||||
|
||||
|
@ -48,6 +48,7 @@ CONFIG_HOTPLUG_CPU=y
|
||||
CONFIG_NR_CPUS=64
|
||||
CONFIG_NUMA=y
|
||||
CONFIG_KEXEC=y
|
||||
CONFIG_CRASH_DUMP=y
|
||||
CONFIG_SUSPEND=y
|
||||
CONFIG_HIBERNATION=y
|
||||
CONFIG_ACPI=y
|
||||
|
@ -125,4 +125,6 @@ extern unsigned long vm_map_base;
|
||||
#define ISA_IOSIZE SZ_16K
|
||||
#define IO_SPACE_LIMIT (PCI_IOSIZE - 1)
|
||||
|
||||
#define PHYS_LINK_KADDR PHYSADDR(VMLINUX_LOAD_ADDRESS)
|
||||
|
||||
#endif /* _ASM_ADDRSPACE_H */
|
||||
|
@ -188,4 +188,14 @@
|
||||
#define PTRLOG 3
|
||||
#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 */
|
||||
|
@ -274,4 +274,21 @@
|
||||
nor \dst, \src, zero
|
||||
.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 */
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
#define PRID_SERIES_LA132 0x8000 /* Loongson 32bit */
|
||||
#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_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 <asm/asm.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#define INSN_NOP 0x03400000
|
||||
#define INSN_BREAK 0x002a0000
|
||||
@ -23,6 +24,10 @@
|
||||
|
||||
#define ADDR_IMM(addr, INSN) ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
|
||||
|
||||
enum reg0i15_op {
|
||||
break_op = 0x54,
|
||||
};
|
||||
|
||||
enum reg0i26_op {
|
||||
b_op = 0x14,
|
||||
bl_op = 0x15,
|
||||
@ -32,6 +37,7 @@ enum reg1i20_op {
|
||||
lu12iw_op = 0x0a,
|
||||
lu32id_op = 0x0b,
|
||||
pcaddi_op = 0x0c,
|
||||
pcalau12i_op = 0x0d,
|
||||
pcaddu12i_op = 0x0e,
|
||||
pcaddu18i_op = 0x0f,
|
||||
};
|
||||
@ -178,6 +184,11 @@ enum reg3sa2_op {
|
||||
alsld_op = 0x16,
|
||||
};
|
||||
|
||||
struct reg0i15_format {
|
||||
unsigned int immediate : 15;
|
||||
unsigned int opcode : 17;
|
||||
};
|
||||
|
||||
struct reg0i26_format {
|
||||
unsigned int immediate_h : 10;
|
||||
unsigned int immediate_l : 16;
|
||||
@ -263,6 +274,7 @@ struct reg3sa2_format {
|
||||
|
||||
union loongarch_instruction {
|
||||
unsigned int word;
|
||||
struct reg0i15_format reg0i15_format;
|
||||
struct reg0i26_format reg0i26_format;
|
||||
struct reg1i20_format reg1i20_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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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_write(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_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_DB1ADDR 0x318 /* data breakpoint 1 address */
|
||||
#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_DB2ADDR 0x320 /* data breakpoint 2 address */
|
||||
#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_DB3ADDR 0x328 /* data breakpoint 3 address */
|
||||
#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_DB4ADDR 0x330 /* data breakpoint 4 address */
|
||||
#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_DB5ADDR 0x338 /* data breakpoint 5 address */
|
||||
#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_DB6ADDR 0x340 /* data breakpoint 6 address */
|
||||
#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_DB7ADDR 0x348 /* data breakpoint 7 address */
|
||||
#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_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_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_IB1ADDR 0x398 /* inst breakpoint 1 address */
|
||||
#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_IB2ADDR 0x3a0 /* inst breakpoint 2 address */
|
||||
#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_IB3ADDR 0x3a8 /* inst breakpoint 3 address */
|
||||
#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_IB4ADDR 0x3b0 /* inst breakpoint 4 address */
|
||||
#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_IB5ADDR 0x3b8 /* inst breakpoint 5 address */
|
||||
#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_IB6ADDR 0x3c0 /* inst breakpoint 6 address */
|
||||
#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_IB7ADDR 0x3c8 /* inst breakpoint 7 address */
|
||||
#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_DEBUG 0x500 /* debug config */
|
||||
#define LOONGARCH_CSR_DERA 0x501 /* debug era */
|
||||
#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
|
||||
*/
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cpu-info.h>
|
||||
#include <asm/hw_breakpoint.h>
|
||||
#include <asm/loongarch.h>
|
||||
#include <asm/vdso/processor.h>
|
||||
#include <uapi/asm/ptrace.h>
|
||||
@ -124,13 +125,18 @@ struct thread_struct {
|
||||
/* Other stuff associated with the thread. */
|
||||
unsigned long trap_nr;
|
||||
unsigned long error_code;
|
||||
unsigned long single_step; /* Used by PTRACE_SINGLESTEP */
|
||||
struct loongarch_vdso_info *vdso;
|
||||
|
||||
/*
|
||||
* FPU & vector registers, must be at last because
|
||||
* they are conditionally copied at fork().
|
||||
* FPU & vector registers, must be at the last of inherited
|
||||
* context because they are conditionally copied at fork().
|
||||
*/
|
||||
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)
|
||||
@ -172,6 +178,8 @@ struct thread_struct {
|
||||
.fcc = 0, \
|
||||
.fpr = {{{0,},},}, \
|
||||
}, \
|
||||
.hbp_break = {0}, \
|
||||
.hbp_watch = {0}, \
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
static inline void flush_thread(void)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long __get_wchan(struct task_struct *p);
|
||||
|
||||
#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + \
|
||||
|
@ -6,6 +6,7 @@
|
||||
#define _ASM_PTRACE_H
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/irqflags.h>
|
||||
#include <asm/thread_info.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;
|
||||
|
||||
/**
|
||||
* 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?
|
||||
*/
|
||||
@ -149,4 +184,8 @@ static inline void user_stack_pointer_set(struct pt_regs *regs,
|
||||
regs->regs[3] = val;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
#define arch_has_single_step() (1)
|
||||
#endif
|
||||
|
||||
#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_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 */
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/threads.h>
|
||||
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/asm.h>
|
||||
#include <asm/asmmacro.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
@ -36,6 +37,14 @@
|
||||
cfi_restore \reg \offset \docfi
|
||||
.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
|
||||
csrwr t0, EXCEPTION_KS0
|
||||
csrwr t1, EXCEPTION_KS1
|
||||
@ -77,7 +86,7 @@
|
||||
* new value in sp.
|
||||
*/
|
||||
.macro get_saved_sp docfi=0
|
||||
la.abs t1, kernelsp
|
||||
la_abs t1, kernelsp
|
||||
#ifdef CONFIG_SMP
|
||||
csrrd t0, PERCPU_BASE_KS
|
||||
LONG_ADD t1, t1, t0
|
||||
@ -90,7 +99,7 @@
|
||||
.endm
|
||||
|
||||
.macro set_saved_sp stackp temp temp2
|
||||
la.abs \temp, kernelsp
|
||||
la.pcrel \temp, kernelsp
|
||||
#ifdef CONFIG_SMP
|
||||
LONG_ADD \temp, \temp, u0
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@ extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev,
|
||||
#define switch_to(prev, next, last) \
|
||||
do { \
|
||||
lose_fpu_inatomic(1, prev); \
|
||||
hw_breakpoint_thread_switch(next); \
|
||||
(last) = __switch_to(prev, next, task_thread_info(next), \
|
||||
__builtin_return_address(0), __builtin_frame_address(0)); \
|
||||
} while (0)
|
||||
|
@ -22,7 +22,6 @@
|
||||
extern u64 __ua_limit;
|
||||
|
||||
#define __UA_ADDR ".dword"
|
||||
#define __UA_LA "la.abs"
|
||||
#define __UA_LIMIT __ua_limit
|
||||
|
||||
/*
|
||||
|
@ -46,6 +46,15 @@ struct user_fp_state {
|
||||
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_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 \
|
||||
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 \
|
||||
alternative.o unaligned.o unwind.o
|
||||
alternative.o unwind.o
|
||||
|
||||
obj-$(CONFIG_ACPI) += acpi.o
|
||||
obj-$(CONFIG_EFI) += efi.o
|
||||
|
||||
obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
|
||||
|
||||
obj-$(CONFIG_ARCH_STRICT_ALIGN) += unaligned.o
|
||||
|
||||
ifdef CONFIG_FUNCTION_TRACER
|
||||
ifndef CONFIG_DYNAMIC_FTRACE
|
||||
obj-y += mcount.o ftrace.o
|
||||
@ -39,6 +41,8 @@ obj-$(CONFIG_NUMA) += numa.o
|
||||
|
||||
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
|
||||
|
||||
obj-$(CONFIG_RELOCATABLE) += relocate.o
|
||||
|
||||
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.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_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)
|
||||
|
@ -19,70 +19,71 @@
|
||||
.cfi_sections .debug_frame
|
||||
.align 5
|
||||
SYM_FUNC_START(handle_syscall)
|
||||
csrrd t0, PERCPU_BASE_KS
|
||||
la.abs t1, kernelsp
|
||||
add.d t1, t1, t0
|
||||
move t2, sp
|
||||
ld.d sp, t1, 0
|
||||
csrrd t0, PERCPU_BASE_KS
|
||||
la.pcrel t1, kernelsp
|
||||
add.d t1, t1, t0
|
||||
move t2, sp
|
||||
ld.d sp, t1, 0
|
||||
|
||||
addi.d sp, sp, -PT_SIZE
|
||||
cfi_st t2, PT_R3
|
||||
addi.d sp, sp, -PT_SIZE
|
||||
cfi_st t2, PT_R3
|
||||
cfi_rel_offset sp, PT_R3
|
||||
st.d zero, sp, PT_R0
|
||||
csrrd t2, LOONGARCH_CSR_PRMD
|
||||
st.d t2, sp, PT_PRMD
|
||||
csrrd t2, LOONGARCH_CSR_CRMD
|
||||
st.d t2, sp, PT_CRMD
|
||||
csrrd t2, LOONGARCH_CSR_EUEN
|
||||
st.d t2, sp, PT_EUEN
|
||||
csrrd t2, LOONGARCH_CSR_ECFG
|
||||
st.d t2, sp, PT_ECFG
|
||||
csrrd t2, LOONGARCH_CSR_ESTAT
|
||||
st.d t2, sp, PT_ESTAT
|
||||
cfi_st ra, PT_R1
|
||||
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
|
||||
csrrd ra, LOONGARCH_CSR_ERA
|
||||
st.d ra, sp, PT_ERA
|
||||
st.d zero, sp, PT_R0
|
||||
csrrd t2, LOONGARCH_CSR_PRMD
|
||||
st.d t2, sp, PT_PRMD
|
||||
csrrd t2, LOONGARCH_CSR_CRMD
|
||||
st.d t2, sp, PT_CRMD
|
||||
csrrd t2, LOONGARCH_CSR_EUEN
|
||||
st.d t2, sp, PT_EUEN
|
||||
csrrd t2, LOONGARCH_CSR_ECFG
|
||||
st.d t2, sp, PT_ECFG
|
||||
csrrd t2, LOONGARCH_CSR_ESTAT
|
||||
st.d t2, sp, PT_ESTAT
|
||||
cfi_st ra, PT_R1
|
||||
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
|
||||
csrrd ra, LOONGARCH_CSR_ERA
|
||||
st.d ra, sp, PT_ERA
|
||||
cfi_rel_offset ra, PT_ERA
|
||||
|
||||
cfi_st tp, PT_R2
|
||||
cfi_st u0, PT_R21
|
||||
cfi_st fp, PT_R22
|
||||
cfi_st tp, PT_R2
|
||||
cfi_st u0, PT_R21
|
||||
cfi_st fp, PT_R22
|
||||
|
||||
SAVE_STATIC
|
||||
|
||||
move u0, t0
|
||||
li.d tp, ~_THREAD_MASK
|
||||
and tp, tp, sp
|
||||
move u0, t0
|
||||
li.d tp, ~_THREAD_MASK
|
||||
and tp, tp, sp
|
||||
|
||||
move a0, sp
|
||||
bl do_syscall
|
||||
move a0, sp
|
||||
bl do_syscall
|
||||
|
||||
RESTORE_ALL_AND_RET
|
||||
SYM_FUNC_END(handle_syscall)
|
||||
_ASM_NOKPROBE(handle_syscall)
|
||||
|
||||
SYM_CODE_START(ret_from_fork)
|
||||
bl schedule_tail # a0 = struct task_struct *prev
|
||||
move a0, sp
|
||||
bl syscall_exit_to_user_mode
|
||||
bl schedule_tail # a0 = struct task_struct *prev
|
||||
move a0, sp
|
||||
bl syscall_exit_to_user_mode
|
||||
RESTORE_STATIC
|
||||
RESTORE_SOME
|
||||
RESTORE_SP_AND_RET
|
||||
SYM_CODE_END(ret_from_fork)
|
||||
|
||||
SYM_CODE_START(ret_from_kernel_thread)
|
||||
bl schedule_tail # a0 = struct task_struct *prev
|
||||
move a0, s1
|
||||
jirl ra, s0, 0
|
||||
move a0, sp
|
||||
bl syscall_exit_to_user_mode
|
||||
bl schedule_tail # a0 = struct task_struct *prev
|
||||
move a0, s1
|
||||
jirl ra, s0, 0
|
||||
move a0, sp
|
||||
bl syscall_exit_to_user_mode
|
||||
RESTORE_STATIC
|
||||
RESTORE_SOME
|
||||
RESTORE_SP_AND_RET
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/ftrace.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/uaccess.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_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)
|
||||
BACKUP_T0T1
|
||||
SAVE_ALL
|
||||
la.abs t1, __arch_cpu_idle
|
||||
la_abs t1, __arch_cpu_idle
|
||||
LONG_L t0, sp, PT_ERA
|
||||
/* 32 byte rollback region */
|
||||
ori t0, t0, 0x1f
|
||||
@ -43,7 +43,7 @@ SYM_FUNC_START(handle_vint)
|
||||
LONG_S t0, sp, PT_ERA
|
||||
1: move a0, sp
|
||||
move a1, sp
|
||||
la.abs t0, do_vint
|
||||
la_abs t0, do_vint
|
||||
jirl ra, t0, 0
|
||||
RESTORE_ALL_AND_RET
|
||||
SYM_FUNC_END(handle_vint)
|
||||
@ -72,7 +72,7 @@ SYM_FUNC_END(except_vec_cex)
|
||||
SAVE_ALL
|
||||
build_prep_\prep
|
||||
move a0, sp
|
||||
la.abs t0, do_\handler
|
||||
la_abs t0, do_\handler
|
||||
jirl ra, t0, 0
|
||||
668:
|
||||
RESTORE_ALL_AND_RET
|
||||
@ -93,6 +93,6 @@ SYM_FUNC_END(except_vec_cex)
|
||||
BUILD_HANDLER reserved reserved none /* others */
|
||||
|
||||
SYM_FUNC_START(handle_sys)
|
||||
la.abs t0, handle_syscall
|
||||
la_abs t0, handle_syscall
|
||||
jr t0
|
||||
SYM_FUNC_END(handle_sys)
|
||||
|
@ -24,7 +24,7 @@ _head:
|
||||
.org 0x8
|
||||
.dword kernel_entry /* Kernel entry point */
|
||||
.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 */
|
||||
.long LINUX_PE_MAGIC
|
||||
.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
|
||||
csrwr t0, LOONGARCH_CSR_DMWIN1
|
||||
|
||||
/* We might not get launched at the address the kernel is linked to,
|
||||
so we jump there. */
|
||||
la.abs t0, 0f
|
||||
jr t0
|
||||
0:
|
||||
JUMP_VIRT_ADDR t0, t1
|
||||
|
||||
/* Enable PG */
|
||||
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
|
||||
csrwr t0, LOONGARCH_CSR_CRMD
|
||||
@ -89,6 +86,23 @@ SYM_CODE_START(kernel_entry) # kernel entry point
|
||||
PTR_ADD sp, sp, tp
|
||||
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
|
||||
ASM_BUG()
|
||||
|
||||
@ -106,9 +120,8 @@ SYM_CODE_START(smpboot_entry)
|
||||
li.d t0, CSR_DMW1_INIT # CA, PLV0
|
||||
csrwr t0, LOONGARCH_CSR_DMWIN1
|
||||
|
||||
la.abs t0, 0f
|
||||
jr t0
|
||||
0:
|
||||
JUMP_VIRT_ADDR t0, t1
|
||||
|
||||
/* Enable PG */
|
||||
li.w t0, 0xb0 # PLV=0, IE=0, PG=1
|
||||
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
|
||||
csrwr t0, LOONGARCH_CSR_EUEN
|
||||
|
||||
la.abs t0, cpuboot_data
|
||||
la.pcrel t0, cpuboot_data
|
||||
ld.d sp, t0, CPU_BOOT_STACK
|
||||
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);
|
||||
|
||||
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 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/task.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
#include <linux/hw_breakpoint.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/stddef.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;
|
||||
}
|
||||
|
||||
void flush_thread(void)
|
||||
{
|
||||
flush_ptrace_hw_breakpoint(current);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
out:
|
||||
ptrace_hw_copy_thread(p);
|
||||
clear_tsk_thread_flag(p, TIF_USEDFPU);
|
||||
clear_tsk_thread_flag(p, TIF_USEDSIMD);
|
||||
clear_tsk_thread_flag(p, TIF_LSX_CTX_LIVE);
|
||||
|
@ -20,7 +20,9 @@
|
||||
#include <linux/context_tracking.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/hw_breakpoint.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/nospec.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/sched.h>
|
||||
@ -29,6 +31,7 @@
|
||||
#include <linux/smp.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/seccomp.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
@ -39,6 +42,7 @@
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/reg.h>
|
||||
#include <asm/syscall.h>
|
||||
|
||||
@ -246,6 +250,384 @@ static int cfg_set(struct task_struct *target,
|
||||
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 {
|
||||
const char *name;
|
||||
int offset;
|
||||
@ -319,6 +701,10 @@ enum loongarch_regset {
|
||||
REGSET_GPR,
|
||||
REGSET_FPR,
|
||||
REGSET_CPUCFG,
|
||||
#ifdef CONFIG_HAVE_HW_BREAKPOINT
|
||||
REGSET_HW_BREAK,
|
||||
REGSET_HW_WATCH,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct user_regset loongarch64_regsets[] = {
|
||||
@ -346,6 +732,24 @@ static const struct user_regset loongarch64_regsets[] = {
|
||||
.regset_get = cfg_get,
|
||||
.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 = {
|
||||
@ -431,3 +835,71 @@ long arch_ptrace(struct task_struct *child, long request,
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
/* 2MB alignment for crash kernel regions */
|
||||
#define CRASH_ALIGN SZ_2M
|
||||
#define CRASH_ADDR_MAX SZ_4G
|
||||
|
||||
static void __init arch_parse_crashkernel(void)
|
||||
{
|
||||
#ifdef CONFIG_KEXEC
|
||||
int ret;
|
||||
unsigned long long start;
|
||||
unsigned long long total_mem;
|
||||
unsigned long long crash_base, crash_size;
|
||||
|
||||
@ -247,8 +250,13 @@ static void __init arch_parse_crashkernel(void)
|
||||
if (ret < 0 || crash_size <= 0)
|
||||
return;
|
||||
|
||||
start = memblock_phys_alloc_range(crash_size, 1, crash_base, crash_base + crash_size);
|
||||
if (start != crash_base) {
|
||||
if (crash_base <= 0) {
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
@ -140,16 +140,17 @@ static int get_timer_irq(void)
|
||||
|
||||
int constant_clockevent_init(void)
|
||||
{
|
||||
int irq;
|
||||
unsigned int cpu = smp_processor_id();
|
||||
unsigned long min_delta = 0x600;
|
||||
unsigned long max_delta = (1UL << 48) - 1;
|
||||
struct clock_event_device *cd;
|
||||
static int timer_irq_installed = 0;
|
||||
static int irq = 0, timer_irq_installed = 0;
|
||||
|
||||
irq = get_timer_irq();
|
||||
if (irq < 0)
|
||||
pr_err("Failed to map irq %d (timer)\n", irq);
|
||||
if (!timer_irq_installed) {
|
||||
irq = get_timer_irq();
|
||||
if (irq < 0)
|
||||
pr_err("Failed to map irq %d (timer)\n", irq);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned int *pc;
|
||||
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);
|
||||
|
||||
/*
|
||||
@ -397,8 +402,8 @@ asmlinkage void noinstr do_ale(struct pt_regs *regs)
|
||||
sigbus:
|
||||
die_if_kernel("Kernel ale access", regs);
|
||||
force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)regs->csr_badvaddr);
|
||||
|
||||
out:
|
||||
#endif
|
||||
irqentry_exit(regs, state);
|
||||
}
|
||||
|
||||
@ -432,7 +437,9 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
|
||||
unsigned long era = exception_era(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();
|
||||
if (__get_inst(&opcode, (u32 *)era, user))
|
||||
goto out_sigsegv;
|
||||
@ -445,14 +452,12 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
|
||||
*/
|
||||
switch (bcode) {
|
||||
case BRK_KPROBE_BP:
|
||||
if (notify_die(DIE_BREAK, "Kprobe", regs, bcode,
|
||||
current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
|
||||
if (kprobe_breakpoint_handler(regs))
|
||||
goto out;
|
||||
else
|
||||
break;
|
||||
case BRK_KPROBE_SSTEPBP:
|
||||
if (notify_die(DIE_SSTEPBP, "Kprobe_SingleStep", regs, bcode,
|
||||
current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
|
||||
if (kprobe_singlestep_handler(regs))
|
||||
goto out;
|
||||
else
|
||||
break;
|
||||
@ -495,7 +500,9 @@ asmlinkage void noinstr do_bp(struct pt_regs *regs)
|
||||
}
|
||||
|
||||
out:
|
||||
local_irq_disable();
|
||||
if (regs->csr_prmd & CSR_PRMD_PIE)
|
||||
local_irq_disable();
|
||||
|
||||
irqentry_exit(regs, state);
|
||||
return;
|
||||
|
||||
@ -506,7 +513,52 @@ asmlinkage void noinstr do_bp(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");
|
||||
#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)
|
||||
|
@ -65,10 +65,21 @@ SECTIONS
|
||||
__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) }
|
||||
.plt : ALIGN(16) { *(.plt) }
|
||||
.got.plt : ALIGN(16) { *(.got.plt) }
|
||||
|
||||
.data.rel : { *(.data.rel*) }
|
||||
|
||||
. = ALIGN(PECOFF_SEGMENT_ALIGN);
|
||||
__init_begin = .;
|
||||
__inittext_begin = .;
|
||||
@ -92,8 +103,6 @@ SECTIONS
|
||||
PERCPU_SECTION(1 << CONFIG_L1_CACHE_SHIFT)
|
||||
#endif
|
||||
|
||||
.rela.dyn : ALIGN(8) { *(.rela.dyn) *(.rela*) }
|
||||
|
||||
.init.bss : {
|
||||
*(.init.bss)
|
||||
}
|
||||
@ -106,6 +115,12 @@ SECTIONS
|
||||
RO_DATA(4096)
|
||||
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)
|
||||
}
|
||||
@ -132,6 +147,7 @@ SECTIONS
|
||||
|
||||
DISCARDS
|
||||
/DISCARD/ : {
|
||||
*(.dynamic .dynsym .dynstr .hash .gnu.hash)
|
||||
*(.gnu.attributes)
|
||||
*(.options)
|
||||
*(.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