Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Documentation/bpf/bpf_devel_QA.rst
  b7abcd9c65 ("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:
Jakub Kicinski 2023-03-09 22:18:59 -08:00
commit d0ddf5065f
726 changed files with 13956 additions and 6646 deletions

View file

@ -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'

View file

@ -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>

View file

@ -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

View file

@ -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>

View file

@ -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.

View file

@ -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.

View file

@ -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!

View file

@ -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>;

View file

@ -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";
};

View file

@ -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>;
};

View file

@ -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";
};

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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>;
};
};
...

View file

@ -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>;
};

View file

@ -14,7 +14,10 @@ maintainers:
properties:
compatible:
const: nxp,pcf2127
enum:
- nxp,pca2129
- nxp,pcf2127
- nxp,pcf2129
reg:
maxItems: 1

View 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>;
};
};

View file

@ -19,8 +19,6 @@ properties:
- microcrystal,rv8564
- nxp,pca8565
- nxp,pcf8563
- nxp,pcf85263
- nxp,pcf85363
reg:
maxItems: 1

View file

@ -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";
};
};
};

View file

@ -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>;
};

View file

@ -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

View file

@ -23,6 +23,7 @@ properties:
- enum:
- apple,t6000-mca
- apple,t8103-mca
- apple,t8112-mca
- const: apple,mca
reg:

View file

@ -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

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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:

View 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

View file

@ -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>;
};

View file

@ -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

View file

@ -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>;
};

View file

@ -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>;
};

View file

@ -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

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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#

View file

@ -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#

View file

@ -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#

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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.

View file

@ -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

View file

@ -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.
============ ================ ==============================================

View file

@ -17,3 +17,4 @@
kernel-enforcement-statement
email-clients
magic-number
programming-language

View file

@ -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

View file

@ -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
~~~~

View file

@ -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

View file

@ -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*

View file

@ -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)

View file

@ -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

View file

@ -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.
*/

View file

@ -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;

View file

@ -1633,7 +1633,7 @@ bool kaslr_requires_kpti(void)
return false;
}
return kaslr_offset() > 0;
return kaslr_enabled();
}
static bool __meltdown_safe = true;

View file

@ -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();

View file

@ -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;
}

View file

@ -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:

View file

@ -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);

View file

@ -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)

View file

@ -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

View file

@ -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 */

View file

@ -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) \

View file

@ -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;

View file

@ -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)

View file

@ -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"

View file

@ -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)

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 64bit3-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 */

View 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 */

View file

@ -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);

View 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 */

View file

@ -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
*/

View file

@ -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) + \

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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)

View file

@ -22,7 +22,6 @@
extern u64 __ua_limit;
#define __UA_ADDR ".dword"
#define __UA_LA "la.abs"
#define __UA_LIMIT __ua_limit
/*

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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 */

View file

@ -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)

View file

@ -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

View 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;
}

View file

@ -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;

View 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);

View 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)

View file

@ -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);

View file

@ -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

View 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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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)

View file

@ -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