mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-21 06:50:25 +00:00

* arm64/for-next/perf: perf: Switch back to struct platform_driver::remove() perf: arm_pmuv3: Add support for Samsung Mongoose PMU dt-bindings: arm: pmu: Add Samsung Mongoose core compatible perf/dwc_pcie: Fix typos in event names perf/dwc_pcie: Add support for Ampere SoCs ARM: pmuv3: Add missing write_pmuacr() perf/marvell: Marvell PEM performance monitor support perf/arm_pmuv3: Add PMUv3.9 per counter EL0 access control perf/dwc_pcie: Convert the events with mixed case to lowercase perf/cxlpmu: Support missing events in 3.1 spec perf: imx_perf: add support for i.MX91 platform dt-bindings: perf: fsl-imx-ddr: Add i.MX91 compatible drivers perf: remove unused field pmu_node * for-next/gcs: (42 commits) : arm64 Guarded Control Stack user-space support kselftest/arm64: Fix missing printf() argument in gcs/gcs-stress.c arm64/gcs: Fix outdated ptrace documentation kselftest/arm64: Ensure stable names for GCS stress test results kselftest/arm64: Validate that GCS push and write permissions work kselftest/arm64: Enable GCS for the FP stress tests kselftest/arm64: Add a GCS stress test kselftest/arm64: Add GCS signal tests kselftest/arm64: Add test coverage for GCS mode locking kselftest/arm64: Add a GCS test program built with the system libc kselftest/arm64: Add very basic GCS test program kselftest/arm64: Always run signals tests with GCS enabled kselftest/arm64: Allow signals tests to specify an expected si_code kselftest/arm64: Add framework support for GCS to signal handling tests kselftest/arm64: Add GCS as a detected feature in the signal tests kselftest/arm64: Verify the GCS hwcap arm64: Add Kconfig for Guarded Control Stack (GCS) arm64/ptrace: Expose GCS via ptrace and core files arm64/signal: Expose GCS state in signal frames arm64/signal: Set up and restore the GCS context for signal handlers arm64/mm: Implement map_shadow_stack() ... * for-next/probes: : Various arm64 uprobes/kprobes cleanups arm64: insn: Simulate nop instruction for better uprobe performance arm64: probes: Remove probe_opcode_t arm64: probes: Cleanup kprobes endianness conversions arm64: probes: Move kprobes-specific fields arm64: probes: Fix uprobes for big-endian kernels arm64: probes: Fix simulate_ldr*_literal() arm64: probes: Remove broken LDR (literal) uprobe support * for-next/asm-offsets: : arm64 asm-offsets.c cleanup (remove unused offsets) arm64: asm-offsets: remove PREEMPT_DISABLE_OFFSET arm64: asm-offsets: remove DMA_{TO,FROM}_DEVICE arm64: asm-offsets: remove VM_EXEC and PAGE_SZ arm64: asm-offsets: remove MM_CONTEXT_ID arm64: asm-offsets: remove COMPAT_{RT_,SIGFRAME_REGS_OFFSET arm64: asm-offsets: remove VMA_VM_* arm64: asm-offsets: remove TSK_ACTIVE_MM * for-next/tlb: : TLB flushing optimisations arm64: optimize flush tlb kernel range arm64: tlbflush: add __flush_tlb_range_limit_excess() * for-next/misc: : Miscellaneous patches arm64: tls: Fix context-switching of tpidrro_el0 when kpti is enabled arm64/ptrace: Clarify documentation of VL configuration via ptrace acpi/arm64: remove unnecessary cast arm64/mm: Change protval as 'pteval_t' in map_range() arm64: uprobes: Optimize cache flushes for xol slot acpi/arm64: Adjust error handling procedure in gtdt_parse_timer_block() arm64: fix .data.rel.ro size assertion when CONFIG_LTO_CLANG arm64/ptdump: Test both PTE_TABLE_BIT and PTE_VALID for block mappings arm64/mm: Sanity check PTE address before runtime P4D/PUD folding arm64/mm: Drop setting PTE_TYPE_PAGE in pte_mkcont() ACPI: GTDT: Tighten the check for the array of platform timer structures arm64/fpsimd: Fix a typo arm64: Expose ID_AA64ISAR1_EL1.XS to sanitised feature consumers arm64: Return early when break handler is found on linked-list arm64/mm: Re-organize arch_make_huge_pte() arm64/mm: Drop _PROT_SECT_DEFAULT arm64: Add command-line override for ID_AA64MMFR0_EL1.ECV arm64: head: Drop SWAPPER_TABLE_SHIFT arm64: cpufeature: add POE to cpucap_is_possible() arm64/mm: Change pgattr_change_is_safe() arguments as pteval_t * for-next/mte: : Various MTE improvements selftests: arm64: add hugetlb mte tests hugetlb: arm64: add mte support * for-next/sysreg: : arm64 sysreg updates arm64/sysreg: Update ID_AA64MMFR1_EL1 to DDI0601 2024-09 * for-next/stacktrace: : arm64 stacktrace improvements arm64: preserve pt_regs::stackframe during exec*() arm64: stacktrace: unwind exception boundaries arm64: stacktrace: split unwind_consume_stack() arm64: stacktrace: report recovered PCs arm64: stacktrace: report source of unwind data arm64: stacktrace: move dump_backtrace() to kunwind_stack_walk() arm64: use a common struct frame_record arm64: pt_regs: swap 'unused' and 'pmr' fields arm64: pt_regs: rename "pmr_save" -> "pmr" arm64: pt_regs: remove stale big-endian layout arm64: pt_regs: assert pt_regs is a multiple of 16 bytes * for-next/hwcap3: : Add AT_HWCAP3 support for arm64 (also wire up AT_HWCAP4) arm64: Support AT_HWCAP3 binfmt_elf: Wire up AT_HWCAP3 at AT_HWCAP4 * for-next/kselftest: (30 commits) : arm64 kselftest fixes/cleanups kselftest/arm64: Try harder to generate different keys during PAC tests kselftest/arm64: Don't leak pipe fds in pac.exec_sign_all() kselftest/arm64: Corrupt P0 in the irritator when testing SSVE kselftest/arm64: Add FPMR coverage to fp-ptrace kselftest/arm64: Expand the set of ZA writes fp-ptrace does kselftets/arm64: Use flag bits for features in fp-ptrace assembler code kselftest/arm64: Enable build of PAC tests with LLVM=1 kselftest/arm64: Check that SVCR is 0 in signal handlers kselftest/arm64: Fix printf() compiler warnings in the arm64 syscall-abi.c tests kselftest/arm64: Fix printf() warning in the arm64 MTE prctl() test kselftest/arm64: Fix printf() compiler warnings in the arm64 fp tests kselftest/arm64: Fix build with stricter assemblers kselftest/arm64: Test signal handler state modification in fp-stress kselftest/arm64: Provide a SIGUSR1 handler in the kernel mode FP stress test kselftest/arm64: Implement irritators for ZA and ZT kselftest/arm64: Remove unused ADRs from irritator handlers kselftest/arm64: Correct misleading comments on fp-stress irritators kselftest/arm64: Poll less often while waiting for fp-stress children kselftest/arm64: Increase frequency of signal delivery in fp-stress kselftest/arm64: Fix encoding for SVE B16B16 test ... * for-next/crc32: : Optimise CRC32 using PMULL instructions arm64/crc32: Implement 4-way interleave using PMULL arm64/crc32: Reorganize bit/byte ordering macros arm64/lib: Handle CRC-32 alternative in C code * for-next/guest-cca: : Support for running Linux as a guest in Arm CCA arm64: Document Arm Confidential Compute virt: arm-cca-guest: TSM_REPORT support for realms arm64: Enable memory encrypt for Realms arm64: mm: Avoid TLBI when marking pages as valid arm64: Enforce bounce buffers for realm DMA efi: arm64: Map Device with Prot Shared arm64: rsi: Map unprotected MMIO as decrypted arm64: rsi: Add support for checking whether an MMIO is protected arm64: realm: Query IPA size from the RMM arm64: Detect if in a realm and set RIPAS RAM arm64: rsi: Add RSI definitions * for-next/haft: : Support for arm64 FEAT_HAFT arm64: pgtable: Warn unexpected pmdp_test_and_clear_young() arm64: Enable ARCH_HAS_NONLEAF_PMD_YOUNG arm64: Add support for FEAT_HAFT arm64: setup: name 'tcr2' register arm64/sysreg: Update ID_AA64MMFR1_EL1 register * for-next/scs: : Dynamic shadow call stack fixes arm64/scs: Drop unused prototype __pi_scs_patch_vmlinux() arm64/scs: Deal with 64-bit relative offsets in FDE frames arm64/scs: Fix handling of DWARF augmentation data in CIE/FDE frames
415 lines
9.9 KiB
C
415 lines
9.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Early cpufeature override framework
|
|
*
|
|
* Copyright (C) 2020 Google LLC
|
|
* Author: Marc Zyngier <maz@kernel.org>
|
|
*/
|
|
|
|
#include <linux/ctype.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/libfdt.h>
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/cpufeature.h>
|
|
#include <asm/setup.h>
|
|
|
|
#include "pi.h"
|
|
|
|
#define FTR_DESC_NAME_LEN 20
|
|
#define FTR_DESC_FIELD_LEN 10
|
|
#define FTR_ALIAS_NAME_LEN 30
|
|
#define FTR_ALIAS_OPTION_LEN 116
|
|
|
|
static u64 __boot_status __initdata;
|
|
|
|
typedef bool filter_t(u64 val);
|
|
|
|
struct ftr_set_desc {
|
|
char name[FTR_DESC_NAME_LEN];
|
|
PREL64(struct arm64_ftr_override, override);
|
|
struct {
|
|
char name[FTR_DESC_FIELD_LEN];
|
|
u8 shift;
|
|
u8 width;
|
|
PREL64(filter_t, filter);
|
|
} fields[];
|
|
};
|
|
|
|
#define FIELD(n, s, f) { .name = n, .shift = s, .width = 4, .filter = f }
|
|
|
|
static const struct ftr_set_desc mmfr0 __prel64_initconst = {
|
|
.name = "id_aa64mmfr0",
|
|
.override = &id_aa64mmfr0_override,
|
|
.fields = {
|
|
FIELD("ecv", ID_AA64MMFR0_EL1_ECV_SHIFT, NULL),
|
|
{}
|
|
},
|
|
};
|
|
|
|
static bool __init mmfr1_vh_filter(u64 val)
|
|
{
|
|
/*
|
|
* If we ever reach this point while running VHE, we're
|
|
* guaranteed to be on one of these funky, VHE-stuck CPUs. If
|
|
* the user was trying to force nVHE on us, proceed with
|
|
* attitude adjustment.
|
|
*/
|
|
return !(__boot_status == (BOOT_CPU_FLAG_E2H | BOOT_CPU_MODE_EL2) &&
|
|
val == 0);
|
|
}
|
|
|
|
static const struct ftr_set_desc mmfr1 __prel64_initconst = {
|
|
.name = "id_aa64mmfr1",
|
|
.override = &id_aa64mmfr1_override,
|
|
.fields = {
|
|
FIELD("vh", ID_AA64MMFR1_EL1_VH_SHIFT, mmfr1_vh_filter),
|
|
{}
|
|
},
|
|
};
|
|
|
|
|
|
static bool __init mmfr2_varange_filter(u64 val)
|
|
{
|
|
int __maybe_unused feat;
|
|
|
|
if (val)
|
|
return false;
|
|
|
|
#ifdef CONFIG_ARM64_LPA2
|
|
feat = cpuid_feature_extract_signed_field(read_sysreg(id_aa64mmfr0_el1),
|
|
ID_AA64MMFR0_EL1_TGRAN_SHIFT);
|
|
if (feat >= ID_AA64MMFR0_EL1_TGRAN_LPA2) {
|
|
id_aa64mmfr0_override.val |=
|
|
(ID_AA64MMFR0_EL1_TGRAN_LPA2 - 1) << ID_AA64MMFR0_EL1_TGRAN_SHIFT;
|
|
id_aa64mmfr0_override.mask |= 0xfU << ID_AA64MMFR0_EL1_TGRAN_SHIFT;
|
|
}
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
static const struct ftr_set_desc mmfr2 __prel64_initconst = {
|
|
.name = "id_aa64mmfr2",
|
|
.override = &id_aa64mmfr2_override,
|
|
.fields = {
|
|
FIELD("varange", ID_AA64MMFR2_EL1_VARange_SHIFT, mmfr2_varange_filter),
|
|
{}
|
|
},
|
|
};
|
|
|
|
static bool __init pfr0_sve_filter(u64 val)
|
|
{
|
|
/*
|
|
* Disabling SVE also means disabling all the features that
|
|
* are associated with it. The easiest way to do it is just to
|
|
* override id_aa64zfr0_el1 to be 0.
|
|
*/
|
|
if (!val) {
|
|
id_aa64zfr0_override.val = 0;
|
|
id_aa64zfr0_override.mask = GENMASK(63, 0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static const struct ftr_set_desc pfr0 __prel64_initconst = {
|
|
.name = "id_aa64pfr0",
|
|
.override = &id_aa64pfr0_override,
|
|
.fields = {
|
|
FIELD("sve", ID_AA64PFR0_EL1_SVE_SHIFT, pfr0_sve_filter),
|
|
FIELD("el0", ID_AA64PFR0_EL1_EL0_SHIFT, NULL),
|
|
{}
|
|
},
|
|
};
|
|
|
|
static bool __init pfr1_sme_filter(u64 val)
|
|
{
|
|
/*
|
|
* Similarly to SVE, disabling SME also means disabling all
|
|
* the features that are associated with it. Just set
|
|
* id_aa64smfr0_el1 to 0 and don't look back.
|
|
*/
|
|
if (!val) {
|
|
id_aa64smfr0_override.val = 0;
|
|
id_aa64smfr0_override.mask = GENMASK(63, 0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static const struct ftr_set_desc pfr1 __prel64_initconst = {
|
|
.name = "id_aa64pfr1",
|
|
.override = &id_aa64pfr1_override,
|
|
.fields = {
|
|
FIELD("bt", ID_AA64PFR1_EL1_BT_SHIFT, NULL ),
|
|
FIELD("gcs", ID_AA64PFR1_EL1_GCS_SHIFT, NULL),
|
|
FIELD("mte", ID_AA64PFR1_EL1_MTE_SHIFT, NULL),
|
|
FIELD("sme", ID_AA64PFR1_EL1_SME_SHIFT, pfr1_sme_filter),
|
|
{}
|
|
},
|
|
};
|
|
|
|
static const struct ftr_set_desc isar1 __prel64_initconst = {
|
|
.name = "id_aa64isar1",
|
|
.override = &id_aa64isar1_override,
|
|
.fields = {
|
|
FIELD("gpi", ID_AA64ISAR1_EL1_GPI_SHIFT, NULL),
|
|
FIELD("gpa", ID_AA64ISAR1_EL1_GPA_SHIFT, NULL),
|
|
FIELD("api", ID_AA64ISAR1_EL1_API_SHIFT, NULL),
|
|
FIELD("apa", ID_AA64ISAR1_EL1_APA_SHIFT, NULL),
|
|
{}
|
|
},
|
|
};
|
|
|
|
static const struct ftr_set_desc isar2 __prel64_initconst = {
|
|
.name = "id_aa64isar2",
|
|
.override = &id_aa64isar2_override,
|
|
.fields = {
|
|
FIELD("gpa3", ID_AA64ISAR2_EL1_GPA3_SHIFT, NULL),
|
|
FIELD("apa3", ID_AA64ISAR2_EL1_APA3_SHIFT, NULL),
|
|
FIELD("mops", ID_AA64ISAR2_EL1_MOPS_SHIFT, NULL),
|
|
{}
|
|
},
|
|
};
|
|
|
|
static const struct ftr_set_desc smfr0 __prel64_initconst = {
|
|
.name = "id_aa64smfr0",
|
|
.override = &id_aa64smfr0_override,
|
|
.fields = {
|
|
FIELD("smever", ID_AA64SMFR0_EL1_SMEver_SHIFT, NULL),
|
|
/* FA64 is a one bit field... :-/ */
|
|
{ "fa64", ID_AA64SMFR0_EL1_FA64_SHIFT, 1, },
|
|
{}
|
|
},
|
|
};
|
|
|
|
static bool __init hvhe_filter(u64 val)
|
|
{
|
|
u64 mmfr1 = read_sysreg(id_aa64mmfr1_el1);
|
|
|
|
return (val == 1 &&
|
|
lower_32_bits(__boot_status) == BOOT_CPU_MODE_EL2 &&
|
|
cpuid_feature_extract_unsigned_field(mmfr1,
|
|
ID_AA64MMFR1_EL1_VH_SHIFT));
|
|
}
|
|
|
|
static const struct ftr_set_desc sw_features __prel64_initconst = {
|
|
.name = "arm64_sw",
|
|
.override = &arm64_sw_feature_override,
|
|
.fields = {
|
|
FIELD("nokaslr", ARM64_SW_FEATURE_OVERRIDE_NOKASLR, NULL),
|
|
FIELD("hvhe", ARM64_SW_FEATURE_OVERRIDE_HVHE, hvhe_filter),
|
|
FIELD("rodataoff", ARM64_SW_FEATURE_OVERRIDE_RODATA_OFF, NULL),
|
|
{}
|
|
},
|
|
};
|
|
|
|
static const
|
|
PREL64(const struct ftr_set_desc, reg) regs[] __prel64_initconst = {
|
|
{ &mmfr0 },
|
|
{ &mmfr1 },
|
|
{ &mmfr2 },
|
|
{ &pfr0 },
|
|
{ &pfr1 },
|
|
{ &isar1 },
|
|
{ &isar2 },
|
|
{ &smfr0 },
|
|
{ &sw_features },
|
|
};
|
|
|
|
static const struct {
|
|
char alias[FTR_ALIAS_NAME_LEN];
|
|
char feature[FTR_ALIAS_OPTION_LEN];
|
|
} aliases[] __initconst = {
|
|
{ "kvm_arm.mode=nvhe", "arm64_sw.hvhe=0 id_aa64mmfr1.vh=0" },
|
|
{ "kvm_arm.mode=protected", "arm64_sw.hvhe=1" },
|
|
{ "arm64.nosve", "id_aa64pfr0.sve=0" },
|
|
{ "arm64.nosme", "id_aa64pfr1.sme=0" },
|
|
{ "arm64.nobti", "id_aa64pfr1.bt=0" },
|
|
{ "arm64.nogcs", "id_aa64pfr1.gcs=0" },
|
|
{ "arm64.nopauth",
|
|
"id_aa64isar1.gpi=0 id_aa64isar1.gpa=0 "
|
|
"id_aa64isar1.api=0 id_aa64isar1.apa=0 "
|
|
"id_aa64isar2.gpa3=0 id_aa64isar2.apa3=0" },
|
|
{ "arm64.nomops", "id_aa64isar2.mops=0" },
|
|
{ "arm64.nomte", "id_aa64pfr1.mte=0" },
|
|
{ "nokaslr", "arm64_sw.nokaslr=1" },
|
|
{ "rodata=off", "arm64_sw.rodataoff=1" },
|
|
{ "arm64.nolva", "id_aa64mmfr2.varange=0" },
|
|
{ "arm64.no32bit_el0", "id_aa64pfr0.el0=1" },
|
|
};
|
|
|
|
static int __init parse_hexdigit(const char *p, u64 *v)
|
|
{
|
|
// skip "0x" if it comes next
|
|
if (p[0] == '0' && tolower(p[1]) == 'x')
|
|
p += 2;
|
|
|
|
// check whether the RHS is a single hex digit
|
|
if (!isxdigit(p[0]) || (p[1] && !isspace(p[1])))
|
|
return -EINVAL;
|
|
|
|
*v = tolower(*p) - (isdigit(*p) ? '0' : 'a' - 10);
|
|
return 0;
|
|
}
|
|
|
|
static int __init find_field(const char *cmdline, char *opt, int len,
|
|
const struct ftr_set_desc *reg, int f, u64 *v)
|
|
{
|
|
int flen = strlen(reg->fields[f].name);
|
|
|
|
// append '<fieldname>=' to obtain '<name>.<fieldname>='
|
|
memcpy(opt + len, reg->fields[f].name, flen);
|
|
len += flen;
|
|
opt[len++] = '=';
|
|
|
|
if (memcmp(cmdline, opt, len))
|
|
return -1;
|
|
|
|
return parse_hexdigit(cmdline + len, v);
|
|
}
|
|
|
|
static void __init match_options(const char *cmdline)
|
|
{
|
|
char opt[FTR_DESC_NAME_LEN + FTR_DESC_FIELD_LEN + 2];
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
|
const struct ftr_set_desc *reg = prel64_pointer(regs[i].reg);
|
|
struct arm64_ftr_override *override;
|
|
int len = strlen(reg->name);
|
|
int f;
|
|
|
|
override = prel64_pointer(reg->override);
|
|
|
|
// set opt[] to '<name>.'
|
|
memcpy(opt, reg->name, len);
|
|
opt[len++] = '.';
|
|
|
|
for (f = 0; reg->fields[f].name[0] != '\0'; f++) {
|
|
u64 shift = reg->fields[f].shift;
|
|
u64 width = reg->fields[f].width ?: 4;
|
|
u64 mask = GENMASK_ULL(shift + width - 1, shift);
|
|
bool (*filter)(u64 val);
|
|
u64 v;
|
|
|
|
if (find_field(cmdline, opt, len, reg, f, &v))
|
|
continue;
|
|
|
|
/*
|
|
* If an override gets filtered out, advertise
|
|
* it by setting the value to the all-ones while
|
|
* clearing the mask... Yes, this is fragile.
|
|
*/
|
|
filter = prel64_pointer(reg->fields[f].filter);
|
|
if (filter && !filter(v)) {
|
|
override->val |= mask;
|
|
override->mask &= ~mask;
|
|
continue;
|
|
}
|
|
|
|
override->val &= ~mask;
|
|
override->val |= (v << shift) & mask;
|
|
override->mask |= mask;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static __init void __parse_cmdline(const char *cmdline, bool parse_aliases)
|
|
{
|
|
do {
|
|
char buf[256];
|
|
size_t len;
|
|
int i;
|
|
|
|
cmdline = skip_spaces(cmdline);
|
|
|
|
/* terminate on "--" appearing on the command line by itself */
|
|
if (cmdline[0] == '-' && cmdline[1] == '-' && isspace(cmdline[2]))
|
|
return;
|
|
|
|
for (len = 0; cmdline[len] && !isspace(cmdline[len]); len++) {
|
|
if (len >= sizeof(buf) - 1)
|
|
break;
|
|
if (cmdline[len] == '-')
|
|
buf[len] = '_';
|
|
else
|
|
buf[len] = cmdline[len];
|
|
}
|
|
if (!len)
|
|
return;
|
|
|
|
buf[len] = 0;
|
|
|
|
cmdline += len;
|
|
|
|
match_options(buf);
|
|
|
|
for (i = 0; parse_aliases && i < ARRAY_SIZE(aliases); i++)
|
|
if (!memcmp(buf, aliases[i].alias, len + 1))
|
|
__parse_cmdline(aliases[i].feature, false);
|
|
} while (1);
|
|
}
|
|
|
|
static __init const u8 *get_bootargs_cmdline(const void *fdt, int node)
|
|
{
|
|
static char const bootargs[] __initconst = "bootargs";
|
|
const u8 *prop;
|
|
|
|
if (node < 0)
|
|
return NULL;
|
|
|
|
prop = fdt_getprop(fdt, node, bootargs, NULL);
|
|
if (!prop)
|
|
return NULL;
|
|
|
|
return strlen(prop) ? prop : NULL;
|
|
}
|
|
|
|
static __init void parse_cmdline(const void *fdt, int chosen)
|
|
{
|
|
static char const cmdline[] __initconst = CONFIG_CMDLINE;
|
|
const u8 *prop = get_bootargs_cmdline(fdt, chosen);
|
|
|
|
if (IS_ENABLED(CONFIG_CMDLINE_FORCE) || !prop)
|
|
__parse_cmdline(cmdline, true);
|
|
|
|
if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && prop)
|
|
__parse_cmdline(prop, true);
|
|
}
|
|
|
|
void __init init_feature_override(u64 boot_status, const void *fdt,
|
|
int chosen)
|
|
{
|
|
struct arm64_ftr_override *override;
|
|
const struct ftr_set_desc *reg;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
|
reg = prel64_pointer(regs[i].reg);
|
|
override = prel64_pointer(reg->override);
|
|
|
|
override->val = 0;
|
|
override->mask = 0;
|
|
}
|
|
|
|
__boot_status = boot_status;
|
|
|
|
parse_cmdline(fdt, chosen);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(regs); i++) {
|
|
reg = prel64_pointer(regs[i].reg);
|
|
override = prel64_pointer(reg->override);
|
|
dcache_clean_inval_poc((unsigned long)override,
|
|
(unsigned long)(override + 1));
|
|
}
|
|
}
|
|
|
|
char * __init skip_spaces(const char *str)
|
|
{
|
|
while (isspace(*str))
|
|
++str;
|
|
return (char *)str;
|
|
}
|