The arm64 kernel requires some metadata for each system register it may need to access. Currently we have:
* A SYS_<regname> definition which sorresponds to a sys_reg() macro. This is used both to look up a sysreg by encoding (e.g. in KVM), and also to generate code to access a sysreg where the assembler is unaware of the specific sysreg encoding.
Where assemblers support the S3_<op1>_C<crn>_C<crm>_<op2> syntax for system registers, we could use this rather than manually assembling the instructions. However, we don't have consistent definitions for these and we currently still need to handle toolchains that lack this feature.
* A set of <regname>_<fieldname>_SHIFT and <regname>_<fieldname>_MASK definitions, which can be used to extract fields from the register, or to construct a register from a set of fields.
These do not follow the convention used by <linux/bitfield.h>, and the masks are not shifted into place, preventing their use in FIELD_PREP() and FIELD_GET(). We require the SHIFT definitions for inline assembly (and WIDTH definitions would be helpful for UBFX/SBFX), so we cannot only define a shifted MASK. Defining a SHIFT, WIDTH, shifted MASK and unshifted MASK is tedious and error-prone and life is much easier when they can be relied up to exist when writing code.
* A set of <regname>_<fieldname>_<valname> definitions for each enumerated value a field may hold. These are used when identifying the presence of features.
Atop of this, other code has to build up metadata at runtime (e.g. the sets of RES0/RES1 bits in a register).
Alejandro Tafalla (1): arm64/sysreg: Fix typo in Enum element regex
James Morse (1): arm64/sysreg: Extend the maximum width of a register and symbol name
Marc Zyngier (1): arm64: Allow the definition of UNKNOWN system register fields
Mark Brown (6): arm64/sysreg: Enable automatic generation of system register definitions arm64/sysreg: Introduce helpers for access to sysreg fields arm64/sysreg: Add SYS_FIELD_GET() helper arm64/sysreg: Support generation of RAZ fields arm64/sysreg: Allow leading blanks on comments in sysreg file arm64/sysreg: Allow enumerations to be declared as signed or unsigned
Mark Rutland (4): arm64: Add sysreg header generation scripting arm64/sysreg: improve comment for regs without fields arm64/sysreg: fix odd line spacing arm64/sysreg: allow *Enum blocks in SysregFields blocks
arch/arm64/Makefile | 3 + arch/arm64/include/asm/Kbuild | 2 + arch/arm64/include/asm/sysreg.h | 17 ++ arch/arm64/tools/Makefile | 18 ++ arch/arm64/tools/gen-sysreg.awk | 336 ++++++++++++++++++++++++++++++++ arch/arm64/tools/sysreg | 50 +++++ 6 files changed, 426 insertions(+) create mode 100644 arch/arm64/tools/Makefile create mode 100755 arch/arm64/tools/gen-sysreg.awk create mode 100644 arch/arm64/tools/sysreg
From: Mark Rutland mark.rutland@arm.com
mainline inclusion from mainline-v5.18-rc1 commit 66847e0618d7dcaf34d9626e2b1f699fc05a2fef category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
The arm64 kernel requires some metadata for each system register it may need to access. Currently we have:
* A SYS_<regname> definition which sorresponds to a sys_reg() macro. This is used both to look up a sysreg by encoding (e.g. in KVM), and also to generate code to access a sysreg where the assembler is unaware of the specific sysreg encoding.
Where assemblers support the S3_<op1>_C<crn>_C<crm>_<op2> syntax for system registers, we could use this rather than manually assembling the instructions. However, we don't have consistent definitions for these and we currently still need to handle toolchains that lack this feature.
* A set of <regname>_<fieldname>_SHIFT and <regname>_<fieldname>_MASK definitions, which can be used to extract fields from the register, or to construct a register from a set of fields.
These do not follow the convention used by <linux/bitfield.h>, and the masks are not shifted into place, preventing their use in FIELD_PREP() and FIELD_GET(). We require the SHIFT definitions for inline assembly (and WIDTH definitions would be helpful for UBFX/SBFX), so we cannot only define a shifted MASK. Defining a SHIFT, WIDTH, shifted MASK and unshifted MASK is tedious and error-prone and life is much easier when they can be relied up to exist when writing code.
* A set of <regname>_<fieldname>_<valname> definitions for each enumerated value a field may hold. These are used when identifying the presence of features.
Atop of this, other code has to build up metadata at runtime (e.g. the sets of RES0/RES1 bits in a register).
This patch adds scripting so that we can have an easier-to-manage canonical representation of this metadata, from which we can generate all the definitions necessary for various use-cases, e.g.
| #define REG_ID_AA64ISAR0_EL1 S3_0_C0_C6_0 | #define SYS_ID_AA64ISAR0_EL1 sys_reg(3, 0, 0, 6, 0) | #define SYS_ID_AA64ISAR0_EL1_Op0 3 | #define SYS_ID_AA64ISAR0_EL1_Op1 0 | #define SYS_ID_AA64ISAR0_EL1_CRn 0 | #define SYS_ID_AA64ISAR0_EL1_CRm 6 | #define SYS_ID_AA64ISAR0_EL1_Op2 0
| #define ID_AA64ISAR0_EL1_RNDR GENMASK(63, 60) | #define ID_AA64ISAR0_EL1_RNDR_MASK GENMASK(63, 60) | #define ID_AA64ISAR0_EL1_RNDR_SHIFT 60 | #define ID_AA64ISAR0_EL1_RNDR_WIDTH 4 | #define ID_AA64ISAR0_EL1_RNDR_NI UL(0b0000) | #define ID_AA64ISAR0_EL1_RNDR_IMP UL(0b0001)
The script requires that all bits in the register be specified and that there be no overlapping fields. This helps the script spot errors in the input but means that the few registers which change layout at runtime depending on things like virtualisation settings will need some manual handling. No actual register conversions are done here but a header for the register data with some documention of the format is provided.
For cases where multiple registers share a layout (eg, when identical controls are provided at multiple ELs) the register fields can be defined once and referenced from the actual registers, currently we do not generate actual defines for the individual registers.
At the moment this is only intended to express metadata from the architecture, and does not handle policy imposed by the kernel, such as values exposed to userspace or VMs. In future this could be extended to express such information.
This script was mostly written by Mark Rutland but has been extended by Mark Brown to improve validation of input and better integrate with the kernel.
Signed-off-by: Mark Rutland mark.rutland@arm.com Co-Developed-by: Mark Brown broonie@kernel.org Signed-off-by: Mark Brown broonie@kernel.org Link: https://lore.kernel.org/r/20220503170233.507788-9-broonie@kernel.org Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 261 ++++++++++++++++++++++++++++++++ arch/arm64/tools/sysreg | 48 ++++++ 2 files changed, 309 insertions(+) create mode 100755 arch/arm64/tools/gen-sysreg.awk create mode 100644 arch/arm64/tools/sysreg
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk new file mode 100755 index 000000000000..3ffd77cbb499 --- /dev/null +++ b/arch/arm64/tools/gen-sysreg.awk @@ -0,0 +1,261 @@ +#!/bin/awk -f +# SPDX-License-Identifier: GPL-2.0 +# gen-sysreg.awk: arm64 sysreg header generator +# +# Usage: awk -f gen-sysreg.awk sysregs.txt + +# Log an error and terminate +function fatal(msg) { + print "Error at " NR ": " msg > "/dev/stderr" + exit 1 +} + +# Sanity check that the start or end of a block makes sense at this point in +# the file. If not, produce an error and terminate. +# +# @this - the $Block or $EndBlock +# @prev - the only valid block to already be in (value of @block) +# @new - the new value of @block +function change_block(this, prev, new) { + if (block != prev) + fatal("unexpected " this " (inside " block ")") + + block = new +} + +# Sanity check the number of records for a field makes sense. If not, produce +# an error and terminate. +function expect_fields(nf) { + if (NF != nf) + fatal(NF " fields found where " nf " expected") +} + +# Print a CPP macro definition, padded with spaces so that the macro bodies +# line up in a column +function define(name, val) { + printf "%-48s%s\n", "#define " name, val +} + +# Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field +function define_field(reg, field, msb, lsb) { + define(reg "_" field, "GENMASK(" msb ", " lsb ")") + define(reg "_" field "_MASK", "GENMASK(" msb ", " lsb ")") + define(reg "_" field "_SHIFT", lsb) + define(reg "_" field "_WIDTH", msb - lsb + 1) +} + +# Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb +function parse_bitdef(reg, field, bitdef, _bits) +{ + if (bitdef ~ /^[0-9]+$/) { + msb = bitdef + lsb = bitdef + } else if (split(bitdef, _bits, ":") == 2) { + msb = _bits[1] + lsb = _bits[2] + } else { + fatal("invalid bit-range definition '" bitdef "'") + } + + + if (msb != next_bit) + fatal(reg "." field " starts at " msb " not " next_bit) + if (63 < msb || msb < 0) + fatal(reg "." field " invalid high bit in '" bitdef "'") + if (63 < lsb || lsb < 0) + fatal(reg "." field " invalid low bit in '" bitdef "'") + if (msb < lsb) + fatal(reg "." field " invalid bit-range '" bitdef "'") + if (low > high) + fatal(reg "." field " has invalid range " high "-" low) + + next_bit = lsb - 1 +} + +BEGIN { + print "#ifndef __ASM_SYSREG_DEFS_H" + print "#define __ASM_SYSREG_DEFS_H" + print "" + print "/* Generated file - do not edit */" + + block = "None" +} + +END { + print "#endif /* __ASM_SYSREG_DEFS_H */" +} + +# skip blank lines and comment lines +/^$/ { next } +/^#/ { next } + +/^SysregFields/ { + change_block("SysregFields", "None", "SysregFields") + expect_fields(2) + + reg = $2 + + res0 = "UL(0)" + res1 = "UL(0)" + + print "" + + next_bit = 63 + + next +} + +/^EndSysregFields/ { + if (next_bit > 0) + fatal("Unspecified bits in " reg) + + change_block("EndSysregFields", "SysregFields", "None") + + define(reg "_RES0", "(" res0 ")") + define(reg "_RES1", "(" res1 ")") + print "" + + reg = null + res0 = null + res1 = null + + next +} + +/^Sysreg/ { + change_block("Sysreg", "None", "Sysreg") + expect_fields(7) + + reg = $2 + op0 = $3 + op1 = $4 + crn = $5 + crm = $6 + op2 = $7 + + res0 = "UL(0)" + res1 = "UL(0)" + + define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2) + define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")") + + define("SYS_" reg "_Op0", op0) + define("SYS_" reg "_Op1", op1) + define("SYS_" reg "_CRn", crn) + define("SYS_" reg "_CRm", crm) + define("SYS_" reg "_Op2", op2) + + print "" + + next_bit = 63 + + next +} + +/^EndSysreg/ { + if (next_bit > 0) + fatal("Unspecified bits in " reg) + + change_block("EndSysreg", "Sysreg", "None") + + if (res0 != null) + define(reg "_RES0", "(" res0 ")") + if (res1 != null) + define(reg "_RES1", "(" res1 ")") + print "" + + reg = null + op0 = null + op1 = null + crn = null + crm = null + op2 = null + res0 = null + res1 = null + + next +} + +# Currently this is effectivey a comment, in future we may want to emit +# defines for the fields. +/^Fields/ && (block == "Sysreg") { + expect_fields(2) + + if (next_bit != 63) + fatal("Some fields already defined for " reg) + + print "/* See " $2 " */" + print "" + + next_bit = 0 + res0 = null + res1 = null + + next +} + + +/^Res0/ && (block == "Sysreg" || block == "SysregFields") { + expect_fields(2) + parse_bitdef(reg, "RES0", $2) + field = "RES0_" msb "_" lsb + + res0 = res0 " | GENMASK_ULL(" msb ", " lsb ")" + + next +} + +/^Res1/ && (block == "Sysreg" || block == "SysregFields") { + expect_fields(2) + parse_bitdef(reg, "RES1", $2) + field = "RES1_" msb "_" lsb + + res1 = res1 " | GENMASK_ULL(" msb ", " lsb ")" + + next +} + +/^Field/ && (block == "Sysreg" || block == "SysregFields") { + expect_fields(3) + field = $3 + parse_bitdef(reg, field, $2) + + define_field(reg, field, msb, lsb) + print "" + + next +} + +/^Enum/ { + change_block("Enum", "Sysreg", "Enum") + expect_fields(3) + field = $3 + parse_bitdef(reg, field, $2) + + define_field(reg, field, msb, lsb) + + next +} + +/^EndEnum/ { + change_block("EndEnum", "Enum", "Sysreg") + field = null + msb = null + lsb = null + print "" + next +} + +/0b[01]+/ && block = "Enum" { + expect_fields(2) + val = $1 + name = $2 + + define(reg "_" field "_" name, "UL(" val ")") + next +} + +# Any lines not handled by previous rules are unexpected +{ + fatal("unhandled statement") +} diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg new file mode 100644 index 000000000000..8e39c718c1b8 --- /dev/null +++ b/arch/arm64/tools/sysreg @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# System register metadata + +# Each System register is described by a Sysreg block: + +# Sysreg <name> <op0> <op1> <crn> <crm> <op2> +# <field> +# ... +# EndSysreg + +# Within a Sysreg block, each field can be described as one of: + +# Res0 <msb>[:<lsb>] + +# Res1 <msb>[:<lsb>] + +# Field <msb>[:<lsb>] <name> + +# Enum <msb>[:<lsb>] <name> +# <enumval> <enumname> +# ... +# EndEnum + +# Alternatively if multiple registers share the same layout then +# a SysregFields block can be used to describe the shared layout + +# SysregFields <fieldsname> +# <field> +# ... +# EndSysregFields + +# and referenced from within the Sysreg: + +# Sysreg <name> <op0> <op1> <crn> <crm> <op2> +# Fields <fieldsname> +# EndSysreg + +# For ID registers we adopt a few conventions for translating the +# language in the ARM into defines: +# +# NI - Not implemented +# IMP - Implemented +# +# In general it is recommended that new enumeration items be named for the +# feature that introduces them (eg, FEAT_LS64_ACCDATA introduces enumeration +# item ACCDATA) though it may be more taseful to do something else. +
From: Mark Brown broonie@kernel.org
mainline inclusion from mainline-v5.18-rc1 commit c07d8017bceb82cbe5fedd129d072c59a53f5513 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Now that we have a script for generating system registers hook it up to the build system similarly to cpucaps. Since we don't currently have any actual register information in the input file this should produce no change in the built kernel. For ease of review the register information will be converted in separate patches.
Signed-off-by: Mark Brown broonie@kernel.org Acked-by: Mark Rutland mark.rutland@arm.com Link: https://lore.kernel.org/r/20220503170233.507788-10-broonie@kernel.org Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/Makefile | 3 +++ arch/arm64/include/asm/Kbuild | 2 ++ arch/arm64/include/asm/sysreg.h | 8 ++++++++ arch/arm64/tools/Makefile | 18 ++++++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 arch/arm64/tools/Makefile
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 4a42de35a898..5971ca85a6a1 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -170,6 +170,9 @@ vdso_install: $(if $(CONFIG_COMPAT_VDSO), \ $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 $@)
+archprepare: + $(Q)$(MAKE) $(build)=arch/arm64/tools kapi + # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/arm64/include/asm/Kbuild b/arch/arm64/include/asm/Kbuild index a3426b61ff65..cef37f080b05 100644 --- a/arch/arm64/include/asm/Kbuild +++ b/arch/arm64/include/asm/Kbuild @@ -4,3 +4,5 @@ generic-y += mcs_spinlock.h generic-y += qrwlock.h generic-y += set_memory.h generic-y += user.h + +generated-y += sysreg-defs.h diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 7aded7acdd06..ca9c9b8ca571 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -111,6 +111,14 @@ #define SYS_DC_CSW sys_insn(1, 0, 7, 10, 2) #define SYS_DC_CISW sys_insn(1, 0, 7, 14, 2)
+/* + * Automatically generated definitions for system registers, the + * manual encodings below are in the process of being converted to + * come from here. The header relies on the definition of sys_reg() + * earlier in this file. + */ +#include "asm/sysreg-defs.h" + /* * System registers, organised loosely by encoding but grouped together * where the architected name contains an index. e.g. ID_MMFR<n>_EL1. diff --git a/arch/arm64/tools/Makefile b/arch/arm64/tools/Makefile new file mode 100644 index 000000000000..9c3b7edfd720 --- /dev/null +++ b/arch/arm64/tools/Makefile @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +gen := arch/$(ARCH)/include/generated +kapi := $(gen)/asm + +kapi-hdrs-y := $(kapi)/sysreg-defs.h + +targets += $(addprefix ../../../, $(kapi-hdrs-y)) + +PHONY += kapi + +kapi: $(kapi-hdrs-y) + +quiet_cmd_gen_sysreg = GEN $@ + cmd_gen_sysreg = mkdir -p $(dir $@); $(AWK) -f $(real-prereqs) > $@ + +$(kapi)/sysreg-defs.h: $(src)/gen-sysreg.awk $(src)/sysreg FORCE + $(call if_changed,gen_sysreg)
From: Mark Brown broonie@kernel.org
mainline inclusion from mainline-v5.18-rc1 commit e6a6b34f97efe3ded077b31f4370b4c1206c9e56 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
The macros we define for the bitfields within sysregs have very regular names, especially once we switch to automatic generation of those macros. Take advantage of this to define wrappers around FIELD_PREP() allowing us to simplify setting values in fields either numerically
SYS_FIELD_PREP(SCTLR_EL1, TCF0, 0x0)
or using the values of enumerations within the fields
SYS_FIELD_PREP_ENUM(SCTLR_EL1, TCF0, ASYMM)
Suggested-by: Mark Rutland mark.rutland@arm.com Signed-off-by: Mark Brown broonie@kernel.org Link: https://lore.kernel.org/r/20220503170233.507788-2-broonie@kernel.org Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/include/asm/sysreg.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index ca9c9b8ca571..80a9dac43479 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -1232,4 +1232,10 @@
#endif
+#define SYS_FIELD_PREP(reg, field, val) \ + FIELD_PREP(reg##_##field##_MASK, val) + +#define SYS_FIELD_PREP_ENUM(reg, field, val) \ + FIELD_PREP(reg##_##field##_MASK, reg##_##field##_##val) + #endif /* __ASM_SYSREG_H */
From: Mark Brown broonie@kernel.org
mainline inclusion from mainline-v5.18-rc1 commit 3a87d53853c57c4abea0a2f37cc874c102c2c712 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Add a SYS_FIELD_GET() helper to match SYS_FIELD_PREP(), providing a simplified interface to FIELD_GET() when using the generated defines with standardized naming.
Signed-off-by: Mark Brown broonie@kernel.org Acked-by: Mark Rutland mark.rutland@arm.com Link: https://lore.kernel.org/r/20220704170302.2609529-5-broonie@kernel.org Signed-off-by: Will Deacon will@kernel.org Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/include/asm/sysreg.h | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 80a9dac43479..62b81a00ac58 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -1232,6 +1232,9 @@
#endif
+#define SYS_FIELD_GET(reg, field, val) \ + FIELD_GET(reg##_##field##_MASK, val) + #define SYS_FIELD_PREP(reg, field, val) \ FIELD_PREP(reg##_##field##_MASK, val)
From: Mark Rutland mark.rutland@arm.com
mainline inclusion from mainline-v5.18-rc1 commit 82bf59002e0f84e51c16589080c2feba6e6ec78a category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Currently for registers without fields we create a comment pointing at the common definitions, e.g.
| #define REG_TTBR0_EL1 S3_0_C2_C0_0 | #define SYS_TTBR0_EL1 sys_reg(3, 0, 2, 0, 0) | #define SYS_TTBR0_EL1_Op0 3 | #define SYS_TTBR0_EL1_Op1 0 | #define SYS_TTBR0_EL1_CRn 2 | #define SYS_TTBR0_EL1_CRm 0 | #define SYS_TTBR0_EL1_Op2 0 | | /* See TTBRx_EL1 */
It would be slightly nicer if the comment said what we should be looking for, e.g.
| #define REG_TTBR0_EL1 S3_0_C2_C0_0 | #define SYS_TTBR0_EL1 sys_reg(3, 0, 2, 0, 0) | #define SYS_TTBR0_EL1_Op0 3 | #define SYS_TTBR0_EL1_Op1 0 | #define SYS_TTBR0_EL1_CRn 2 | #define SYS_TTBR0_EL1_CRm 0 | #define SYS_TTBR0_EL1_Op2 0 | | /* For TTBR0_EL1 fields see TTBRx_EL1 */
Update the comment generation accordingly.
Signed-off-by: Mark Rutland mark.rutland@arm.com Cc: Mark Brown broonie@kernel.org Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20220513174118.266966-2-mark.rutland@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index 3ffd77cbb499..f41feb87d0ca 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -184,7 +184,7 @@ END { if (next_bit != 63) fatal("Some fields already defined for " reg)
- print "/* See " $2 " */" + print "/* For " reg " fields see " $2 " */" print ""
next_bit = 0
From: Mark Rutland mark.rutland@arm.com
mainline inclusion from mainline-v5.18-rc1 commit 5005d1dbbb3828078f32dff24b77866502e45e93 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Between the header and the definitions, there's no line gap, and in a couple of places a double line gap for no semantic reason, which makes the output look a little odd.
Fix this so blocks are consistently separated with a single line gap:
* Add a newline after the "Generated file" comment line, so this is clearly split from whatever the first definition in the file is.
* At the start of a SysregFields block there's no need for a newline as we haven't output any sysreg encoding details prior to this.
* At the end of a Sysreg block there's no need for a newline if we have no RES0 or RES1 fields, as there will be a line gap after the previous element (e.g. a Fields line).
There should be no functional change as a result of this patch.
Signed-off-by: Mark Rutland mark.rutland@arm.com Cc: Mark Brown broonie@kernel.org Cc: Will Deacon will@kernel.org Link: https://lore.kernel.org/r/20220513174118.266966-3-mark.rutland@arm.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index f41feb87d0ca..4aa7ff8ce707 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -77,6 +77,7 @@ BEGIN { print "#define __ASM_SYSREG_DEFS_H" print "" print "/* Generated file - do not edit */" + print ""
block = "None" } @@ -98,8 +99,6 @@ END { res0 = "UL(0)" res1 = "UL(0)"
- print "" - next_bit = 63
next @@ -162,7 +161,8 @@ END { define(reg "_RES0", "(" res0 ")") if (res1 != null) define(reg "_RES1", "(" res1 ")") - print "" + if (res0 != null || res1 != null) + print ""
reg = null op0 = null
From: Mark Brown broonie@kernel.org
mainline inclusion from mainline-v5.18-rc1 commit 9e2c0819ac853d94c927d5d2f59e2ca2b48500b4 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Add a statement for RAZ bitfields to the automatic register generation script. Nothing is emitted to the header for these fields.
Signed-off-by: Mark Brown broonie@kernel.org Acked-by: Mark Rutland mark.rutland@arm.com Link: https://lore.kernel.org/r/20220510161208.631259-7-broonie@kernel.org Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index 4aa7ff8ce707..89bfb74e28de 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -226,6 +226,13 @@ END { next }
+/^Raz/ && (block == "Sysreg" || block == "SysregFields") { + expect_fields(2) + parse_bitdef(reg, field, $2) + + next +} + /^Enum/ { change_block("Enum", "Sysreg", "Enum") expect_fields(3)
From: Alejandro Tafalla atafalla@dnyon.com
mainline inclusion from mainline-v5.18-rc1 commit ce253b8573ce3de1278513395f07118650a49e39 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
In the awk script, there was a typo with the comparison operator when checking if the matched pattern is inside an Enum block. This prevented the generation of the whole sysreg-defs.h header.
Fixes: 66847e0618d7 ("arm64: Add sysreg header generation scripting") Signed-off-by: Alejandro Tafalla atafalla@dnyon.com Reviewed-by: Mark Brown broonie@kernel.org Link: https://lore.kernel.org/r/20220609204220.12112-1-atafalla@dnyon.com Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index 89bfb74e28de..5c55509eb43f 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -253,7 +253,7 @@ END { next }
-/0b[01]+/ && block = "Enum" { +/0b[01]+/ && block == "Enum" { expect_fields(2) val = $1 name = $2
From: Mark Brown broonie@kernel.org
mainline inclusion from mainline-v5.18-rc1 commit f43ff286512ec2da2e1038ab76471e9a07e3a951 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Currently we only accept comments where the # is placed at the start of a line, allow leading blanks so we can format comments inside definitions in a more pleasing manner.
Signed-off-by: Mark Brown broonie@kernel.org Link: https://lore.kernel.org/r/20220704170302.2609529-4-broonie@kernel.org Signed-off-by: Will Deacon will@kernel.org Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index 5c55509eb43f..db461921d256 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -88,7 +88,7 @@ END {
# skip blank lines and comment lines /^$/ { next } -/^#/ { next } +/^[\t ]*#/ { next }
/^SysregFields/ { change_block("SysregFields", "None", "SysregFields")
From: James Morse james.morse@arm.com
mainline inclusion from mainline-v6.1-rc1 commit 7587cdef55928ef70d4e945003646711ad39e405 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
32bit has multiple values for its id registers, as extra properties were added to the CPUs. Some of these end up having long names, which exceed the fixed 48 character column that the sysreg awk script generates.
For example, the ID_MMFR1_EL1.L1Hvd field has an encoding whose natural name would be 'invalidate Iside only'. Using this causes compile errors as the script generates the following: #define ID_MMFR1_EL1_L1Hvd_INVALIDATE_ISIDE_ONLYUL(0b0001)
Add a few extra characters.
Reviewed-by: Mark Brown broonie@kernel.org Signed-off-by: James Morse james.morse@arm.com Link: https://lore.kernel.org/r/20221130171637.718182-17-james.morse@arm.com Signed-off-by: Will Deacon will@kernel.org Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index db461921d256..c350164a3955 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -33,7 +33,7 @@ function expect_fields(nf) { # Print a CPP macro definition, padded with spaces so that the macro bodies # line up in a column function define(name, val) { - printf "%-48s%s\n", "#define " name, val + printf "%-56s%s\n", "#define " name, val }
# Print standard BITMASK/SHIFT/WIDTH CPP definitions for a field
From: Mark Brown broonie@kernel.org
mainline inclusion from mainline-v6.2-rc1 commit a55d1425fb2f4000a415164ba08712de9c1b7755 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
Many of our enumerations follow a standard scheme where the values can be treated as signed however there are some where the value must be treated as signed and others that are simple enumerations where there is no clear ordering to the values. Provide new field types SignedEnum and UnsignedEnum which allows the signedness to be specified in the sysreg definition and emit a REG_FIELD_SIGNED define for these which is a boolean corresponding to our current FTR_UNSIGNED and FTR_SIGNED macros.
Existing Enums will need to be converted, since these do not have a define generated anyone wishing to use the sign of one of these will need to explicitly annotate that field so nothing should start going wrong by default.
Acked-by: Mark Rutland mark.rutland@arm.com Signed-off-by: Mark Brown broonie@kernel.org Link: https://lore.kernel.org/r/20221207-arm64-sysreg-helpers-v4-1-25b6b3fb9d18@ke... Signed-off-by: Catalin Marinas catalin.marinas@arm.com Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index c350164a3955..7f27d66a17e1 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -44,6 +44,11 @@ function define_field(reg, field, msb, lsb) { define(reg "_" field "_WIDTH", msb - lsb + 1) }
+# Print a field _SIGNED definition for a field +function define_field_sign(reg, field, sign) { + define(reg "_" field "_SIGNED", sign) +} + # Parse a "<msb>[:<lsb>]" string into the global variables @msb and @lsb function parse_bitdef(reg, field, bitdef, _bits) { @@ -233,6 +238,30 @@ END { next }
+/^SignedEnum/ { + change_block("Enum<", "Sysreg", "Enum") + expect_fields(3) + field = $3 + parse_bitdef(reg, field, $2) + + define_field(reg, field, msb, lsb) + define_field_sign(reg, field, "true") + + next +} + +/^UnsignedEnum/ { + change_block("Enum<", "Sysreg", "Enum") + expect_fields(3) + field = $3 + parse_bitdef(reg, field, $2) + + define_field(reg, field, msb, lsb) + define_field_sign(reg, field, "false") + + next +} + /^Enum/ { change_block("Enum", "Sysreg", "Enum") expect_fields(3)
From: Marc Zyngier maz@kernel.org
mainline inclusion from mainline-v6.2-rc1 commit e2c0b51f1c9dacc68292ce9ebffbfd4204d1ca58 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
The CCSIDR_EL1 register contains an UNKNOWN field (which replaces fields that were actually defined in previous revisions of the architecture).
Define an 'Unkn' field type modeled after the Res0/Res1 types to allow such description. This allows the generation of
#define CCSIDR_EL1_UNKN (UL(0) | GENMASK_ULL(31, 28))
which may have its use one day. Hopefully the architecture doesn't add too many of those in the future.
Signed-off-by: Marc Zyngier maz@kernel.org Signed-off-by: Akihiko Odaki akihiko.odaki@gmail.com Reviewed-by: Mark Brown broonie@kernel.org Link: https://lore.kernel.org/r/20230112023852.42012-2-akihiko.odaki@daynix.com Signed-off-by: Oliver Upton oliver.upton@linux.dev Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 20 +++++++++++++++++++- arch/arm64/tools/sysreg | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index 7f27d66a17e1..6fa0468caa00 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -103,6 +103,7 @@ END {
res0 = "UL(0)" res1 = "UL(0)" + unkn = "UL(0)"
next_bit = 63
@@ -117,11 +118,13 @@ END {
define(reg "_RES0", "(" res0 ")") define(reg "_RES1", "(" res1 ")") + define(reg "_UNKN", "(" unkn ")") print ""
reg = null res0 = null res1 = null + unkn = null
next } @@ -139,6 +142,7 @@ END {
res0 = "UL(0)" res1 = "UL(0)" + unkn = "UL(0)"
define("REG_" reg, "S" op0 "_" op1 "_C" crn "_C" crm "_" op2) define("SYS_" reg, "sys_reg(" op0 ", " op1 ", " crn ", " crm ", " op2 ")") @@ -166,7 +170,9 @@ END { define(reg "_RES0", "(" res0 ")") if (res1 != null) define(reg "_RES1", "(" res1 ")") - if (res0 != null || res1 != null) + if (unkn != null) + define(reg "_UNKN", "(" unkn ")") + if (res0 != null || res1 != null || unkn != null) print ""
reg = null @@ -177,6 +183,7 @@ END { op2 = null res0 = null res1 = null + unkn = null
next } @@ -195,6 +202,7 @@ END { next_bit = 0 res0 = null res1 = null + unkn = null
next } @@ -220,6 +228,16 @@ END { next }
+/^Unkn/ && (block == "Sysreg" || block == "SysregFields") { + expect_fields(2) + parse_bitdef(reg, "UNKN", $2) + field = "UNKN_" msb "_" lsb + + unkn = unkn " | GENMASK_ULL(" msb ", " lsb ")" + + next +} + /^Field/ && (block == "Sysreg" || block == "SysregFields") { expect_fields(3) field = $3 diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg index 8e39c718c1b8..936aca8504f9 100644 --- a/arch/arm64/tools/sysreg +++ b/arch/arm64/tools/sysreg @@ -15,6 +15,8 @@
# Res1 <msb>[:<lsb>]
+# Unkn <msb>[:<lsb>] + # Field <msb>[:<lsb>] <name>
# Enum <msb>[:<lsb>] <name>
From: Mark Rutland mark.rutland@arm.com
mainline inclusion from mainline-v6.3-rc1 commit 013ecd4439784bc98fe83bfe3413924db97c3b38 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8DFTV CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
We'd like to support Enum/SignedEnum/UnsignedEnum blocks within SysregFields blocks, so that we can define enumerations for sets of registers. This isn't currently supported by gen-sysreg.awk due to the way we track the active block, which can't handle more than a single layer of nesting, which imposes an awkward requirement that when ending a block we know what the parent block is when calling change_block()
Make this nicer by using a stack of active blocks, with block_push() to start a block, and block_pop() to end a block. Doing so means that we only need to check the active block at the start of parsing a line: for the start of a block we can check the parent is valid, and for the end of a block we check that the active block is valid.
This structure makes the block parsing simpler and makes it easy to permit a block to live under several potential parents (e.g. by permitting Enum to start when the active block is Sysreg or SysregFields). It also permits further nesting, if we need that in future.
To aid debugging, the stack of active blocks is reported for fatal errors, and an error is raised if the file is terminated without ending the active block. For clarity I've renamed the top-level element from "None" to "Root".
The Fields element it intended only for use within Sysreg blocks, and does not make sense within SysregFields blocks, and so remains forbidden within a SysregFields block.
I've verified using sha1sum that this patch does not change the current generated contents of <asm/sysreg-defs.h>.
Signed-off-by: Mark Rutland mark.rutland@arm.com Cc: Anshuman Khandual anshuman.khandual@arm.com Cc: Catalin Marinas catalin.marinas@arm.com Cc: Marc Zyngier maz@kernel.org Cc: Mark Brown broonie@kernel.org Cc: Will Deacon will@kernel.org Reviewed-by: Anshuman Khandual anshuman.khandual@arm.com Reviewed-by: Mark Brown broonie@kernel.org Link: https://lore.kernel.org/r/20230306114836.2575432-1-mark.rutland@arm.com Signed-off-by: Will Deacon will@kernel.org Signed-off-by: Junhao He hejunhao3@huawei.com --- arch/arm64/tools/gen-sysreg.awk | 95 ++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 37 deletions(-)
diff --git a/arch/arm64/tools/gen-sysreg.awk b/arch/arm64/tools/gen-sysreg.awk index 6fa0468caa00..d1254a056114 100755 --- a/arch/arm64/tools/gen-sysreg.awk +++ b/arch/arm64/tools/gen-sysreg.awk @@ -4,23 +4,35 @@ # # Usage: awk -f gen-sysreg.awk sysregs.txt
+function block_current() { + return __current_block[__current_block_depth]; +} + # Log an error and terminate function fatal(msg) { print "Error at " NR ": " msg > "/dev/stderr" + + printf "Current block nesting:" + + for (i = 0; i <= __current_block_depth; i++) { + printf " " __current_block[i] + } + printf "\n" + exit 1 }
-# Sanity check that the start or end of a block makes sense at this point in -# the file. If not, produce an error and terminate. -# -# @this - the $Block or $EndBlock -# @prev - the only valid block to already be in (value of @block) -# @new - the new value of @block -function change_block(this, prev, new) { - if (block != prev) - fatal("unexpected " this " (inside " block ")") - - block = new +# Enter a new block, setting the active block to @block +function block_push(block) { + __current_block[++__current_block_depth] = block +} + +# Exit a block, setting the active block to the parent block +function block_pop() { + if (__current_block_depth == 0) + fatal("error: block_pop() in root block") + + __current_block_depth--; }
# Sanity check the number of records for a field makes sense. If not, produce @@ -84,10 +96,14 @@ BEGIN { print "/* Generated file - do not edit */" print ""
- block = "None" + __current_block_depth = 0 + __current_block[__current_block_depth] = "Root" }
END { + if (__current_block_depth != 0) + fatal("Missing terminator for " block_current() " block") + print "#endif /* __ASM_SYSREG_DEFS_H */" }
@@ -95,8 +111,9 @@ END { /^$/ { next } /^[\t ]*#/ { next }
-/^SysregFields/ { - change_block("SysregFields", "None", "SysregFields") +/^SysregFields/ && block_current() == "Root" { + block_push("SysregFields") + expect_fields(2)
reg = $2 @@ -110,12 +127,10 @@ END { next }
-/^EndSysregFields/ { +/^EndSysregFields/ && block_current() == "SysregFields" { if (next_bit > 0) fatal("Unspecified bits in " reg)
- change_block("EndSysregFields", "SysregFields", "None") - define(reg "_RES0", "(" res0 ")") define(reg "_RES1", "(" res1 ")") define(reg "_UNKN", "(" unkn ")") @@ -126,11 +141,13 @@ END { res1 = null unkn = null
+ block_pop() next }
-/^Sysreg/ { - change_block("Sysreg", "None", "Sysreg") +/^Sysreg/ && block_current() == "Root" { + block_push("Sysreg") + expect_fields(7)
reg = $2 @@ -160,12 +177,10 @@ END { next }
-/^EndSysreg/ { +/^EndSysreg/ && block_current() == "Sysreg" { if (next_bit > 0) fatal("Unspecified bits in " reg)
- change_block("EndSysreg", "Sysreg", "None") - if (res0 != null) define(reg "_RES0", "(" res0 ")") if (res1 != null) @@ -185,12 +200,13 @@ END { res1 = null unkn = null
+ block_pop() next }
# Currently this is effectivey a comment, in future we may want to emit # defines for the fields. -/^Fields/ && (block == "Sysreg") { +/^Fields/ && block_current() == "Sysreg" { expect_fields(2)
if (next_bit != 63) @@ -208,7 +224,7 @@ END { }
-/^Res0/ && (block == "Sysreg" || block == "SysregFields") { +/^Res0/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { expect_fields(2) parse_bitdef(reg, "RES0", $2) field = "RES0_" msb "_" lsb @@ -218,7 +234,7 @@ END { next }
-/^Res1/ && (block == "Sysreg" || block == "SysregFields") { +/^Res1/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { expect_fields(2) parse_bitdef(reg, "RES1", $2) field = "RES1_" msb "_" lsb @@ -228,7 +244,7 @@ END { next }
-/^Unkn/ && (block == "Sysreg" || block == "SysregFields") { +/^Unkn/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { expect_fields(2) parse_bitdef(reg, "UNKN", $2) field = "UNKN_" msb "_" lsb @@ -238,7 +254,7 @@ END { next }
-/^Field/ && (block == "Sysreg" || block == "SysregFields") { +/^Field/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { expect_fields(3) field = $3 parse_bitdef(reg, field, $2) @@ -249,15 +265,16 @@ END { next }
-/^Raz/ && (block == "Sysreg" || block == "SysregFields") { +/^Raz/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { expect_fields(2) parse_bitdef(reg, field, $2)
next }
-/^SignedEnum/ { - change_block("Enum<", "Sysreg", "Enum") +/^SignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { + block_push("Enum") + expect_fields(3) field = $3 parse_bitdef(reg, field, $2) @@ -268,8 +285,9 @@ END { next }
-/^UnsignedEnum/ { - change_block("Enum<", "Sysreg", "Enum") +/^UnsignedEnum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { + block_push("Enum") + expect_fields(3) field = $3 parse_bitdef(reg, field, $2) @@ -280,8 +298,9 @@ END { next }
-/^Enum/ { - change_block("Enum", "Sysreg", "Enum") +/^Enum/ && (block_current() == "Sysreg" || block_current() == "SysregFields") { + block_push("Enum") + expect_fields(3) field = $3 parse_bitdef(reg, field, $2) @@ -291,16 +310,18 @@ END { next }
-/^EndEnum/ { - change_block("EndEnum", "Enum", "Sysreg") +/^EndEnum/ && block_current() == "Enum" { + field = null msb = null lsb = null print "" + + block_pop() next }
-/0b[01]+/ && block == "Enum" { +/0b[01]+/ && block_current() == "Enum" { expect_fields(2) val = $1 name = $2
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/2736 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/J...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/2736 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/J...