mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-15 09:34:17 +00:00
RISC-V Fixes for 6.13-rc7
* A handful of selftest fixes. * A fix for a memory leak in relocation processing during module loading. * A fix to avoid sleeping in die(). * A fix for kprobe intsruction slot address calculations. * A fix for a DT node reference leak in SBI idle probing. * A fix for to avoid initializing out of bounds pages on sparse vmemmap systems with a gap at the start of their physical memory map. * A fix for backtracing through exceptions. * _Q_PENDING_LOOPS is now defined whenever QUEUED_SPINLOCKS=y. * Local labels in entry.S are now marked with ".L", which prevents them from trashing backtraces. * A handful of fixes for SBI-based performance counters. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmeBUxcTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRAuExnzX7sYibx3D/0cT2Vc8CWq2oWmIQ4FBEJlQGNfKbI8 JojRh2q76Qq3IWsLLigRgP/9QmkS2z1LWSu8o85UtFsS+kK1cfI7twvoVsmAJHst jNV6729usSAxEukHGQMU/Kn5+yWR2PQi7CChbglMS2vaTlnQVzvThePcxM4A+l2y z5mcI3JVNO9mfLDSIp45IXsxpO4fIWDguB2dtN6sljEzweB0yRMBNSemsF0iuujb sSuZYSWqVfrQ0a1JZ3/MHZ2xnToMpvYwTqH+P5kXX+49vQfGb4pE4Tq7MQgF65w1 TnFesLIQE0c1D0M+1uretIcsNNk4B7eVTCH4DuPgmKVOTQNxsX4szLgLYv+orReW MpKW3P1AR0LDm4bhDTItzrRRxVSrM2gCsSgEHFnw+E1Oe3shCfs5yYzXObiduMwt I6eN2iW47nBqTbY9MHIQxZKAHrH/6h9f70NMbps9MJYKC4SqVNmK/DL/uJCr9o1A FB0Uvnea1ZaenKQy1UM6u4XI5Gfqqn3otJr07Ph5b+YFgBwmjEWmxCP0tQXZ07kW GX7a5pNoHEtsf4V95hqFZ6GNjlqwj12/3FbD2fuT9eVGRbQAiT6dNsohmR2cbfPI Vo7HfeVHLFCIEtNNTiALDZAqFWfyE/zdUlqpiuizE71LBa2IJudDgbaoOEG7OnHN 6jrDh3vuKLv4PA== =6ZPP -----END PGP SIGNATURE----- Merge tag 'riscv-for-linus-6.13-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux Pull RISC-V fixes from Palmer Dabbelt: - a handful of selftest fixes - fix a memory leak in relocation processing during module loading - avoid sleeping in die() - fix kprobe instruction slot address calculations - fix DT node reference leak in SBI idle probing - avoid initializing out of bounds pages on sparse vmemmap systems with a gap at the start of their physical memory map - fix backtracing through exceptions - _Q_PENDING_LOOPS is now defined whenever QUEUED_SPINLOCKS=y - local labels in entry.S are now marked with ".L", which prevents them from trashing backtraces - a handful of fixes for SBI-based performance counters * tag 'riscv-for-linus-6.13-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux: drivers/perf: riscv: Do not allow invalid raw event config drivers/perf: riscv: Return error for default case drivers/perf: riscv: Fix Platform firmware event data tools: selftests: riscv: Add test count for vstate_prctl tools: selftests: riscv: Add pass message for v_initval_nolibc riscv: use local label names instead of global ones in assembly riscv: qspinlock: Fixup _Q_PENDING_LOOPS definition riscv: stacktrace: fix backtracing through exceptions riscv: mm: Fix the out of bound issue of vmemmap address cpuidle: riscv-sbi: fix device node release in early exit of for_each_possible_cpu riscv: kprobes: Fix incorrect address calculation riscv: Fix sleeping in invalid context in die() riscv: module: remove relocation_head rel_entry member allocation riscv: selftests: Fix warnings pointer masking test
This commit is contained in:
commit
f8c6263347
@ -122,6 +122,7 @@ struct kernel_mapping {
|
||||
|
||||
extern struct kernel_mapping kernel_map;
|
||||
extern phys_addr_t phys_ram_base;
|
||||
extern unsigned long vmemmap_start_pfn;
|
||||
|
||||
#define is_kernel_mapping(x) \
|
||||
((x) >= kernel_map.virt_addr && (x) < (kernel_map.virt_addr + kernel_map.size))
|
||||
|
@ -87,7 +87,7 @@
|
||||
* Define vmemmap for pfn_to_page & page_to_pfn calls. Needed if kernel
|
||||
* is configured with CONFIG_SPARSEMEM_VMEMMAP enabled.
|
||||
*/
|
||||
#define vmemmap ((struct page *)VMEMMAP_START - (phys_ram_base >> PAGE_SHIFT))
|
||||
#define vmemmap ((struct page *)VMEMMAP_START - vmemmap_start_pfn)
|
||||
|
||||
#define PCI_IO_SIZE SZ_16M
|
||||
#define PCI_IO_END VMEMMAP_START
|
||||
|
@ -159,6 +159,7 @@ struct riscv_pmu_snapshot_data {
|
||||
};
|
||||
|
||||
#define RISCV_PMU_RAW_EVENT_MASK GENMASK_ULL(47, 0)
|
||||
#define RISCV_PMU_PLAT_FW_EVENT_MASK GENMASK_ULL(61, 0)
|
||||
#define RISCV_PMU_RAW_EVENT_IDX 0x20000
|
||||
#define RISCV_PLAT_FW_EVENT 0xFFFF
|
||||
|
||||
|
@ -3,8 +3,11 @@
|
||||
#ifndef __ASM_RISCV_SPINLOCK_H
|
||||
#define __ASM_RISCV_SPINLOCK_H
|
||||
|
||||
#ifdef CONFIG_RISCV_COMBO_SPINLOCKS
|
||||
#ifdef CONFIG_QUEUED_SPINLOCKS
|
||||
#define _Q_PENDING_LOOPS (1 << 9)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RISCV_COMBO_SPINLOCKS
|
||||
|
||||
#define __no_arch_spinlock_redefine
|
||||
#include <asm/ticket_spinlock.h>
|
||||
|
@ -23,21 +23,21 @@
|
||||
REG_S a0, TASK_TI_A0(tp)
|
||||
csrr a0, CSR_CAUSE
|
||||
/* Exclude IRQs */
|
||||
blt a0, zero, _new_vmalloc_restore_context_a0
|
||||
blt a0, zero, .Lnew_vmalloc_restore_context_a0
|
||||
|
||||
REG_S a1, TASK_TI_A1(tp)
|
||||
/* Only check new_vmalloc if we are in page/protection fault */
|
||||
li a1, EXC_LOAD_PAGE_FAULT
|
||||
beq a0, a1, _new_vmalloc_kernel_address
|
||||
beq a0, a1, .Lnew_vmalloc_kernel_address
|
||||
li a1, EXC_STORE_PAGE_FAULT
|
||||
beq a0, a1, _new_vmalloc_kernel_address
|
||||
beq a0, a1, .Lnew_vmalloc_kernel_address
|
||||
li a1, EXC_INST_PAGE_FAULT
|
||||
bne a0, a1, _new_vmalloc_restore_context_a1
|
||||
bne a0, a1, .Lnew_vmalloc_restore_context_a1
|
||||
|
||||
_new_vmalloc_kernel_address:
|
||||
.Lnew_vmalloc_kernel_address:
|
||||
/* Is it a kernel address? */
|
||||
csrr a0, CSR_TVAL
|
||||
bge a0, zero, _new_vmalloc_restore_context_a1
|
||||
bge a0, zero, .Lnew_vmalloc_restore_context_a1
|
||||
|
||||
/* Check if a new vmalloc mapping appeared that could explain the trap */
|
||||
REG_S a2, TASK_TI_A2(tp)
|
||||
@ -69,7 +69,7 @@ _new_vmalloc_kernel_address:
|
||||
/* Check the value of new_vmalloc for this cpu */
|
||||
REG_L a2, 0(a0)
|
||||
and a2, a2, a1
|
||||
beq a2, zero, _new_vmalloc_restore_context
|
||||
beq a2, zero, .Lnew_vmalloc_restore_context
|
||||
|
||||
/* Atomically reset the current cpu bit in new_vmalloc */
|
||||
amoxor.d a0, a1, (a0)
|
||||
@ -83,11 +83,11 @@ _new_vmalloc_kernel_address:
|
||||
csrw CSR_SCRATCH, x0
|
||||
sret
|
||||
|
||||
_new_vmalloc_restore_context:
|
||||
.Lnew_vmalloc_restore_context:
|
||||
REG_L a2, TASK_TI_A2(tp)
|
||||
_new_vmalloc_restore_context_a1:
|
||||
.Lnew_vmalloc_restore_context_a1:
|
||||
REG_L a1, TASK_TI_A1(tp)
|
||||
_new_vmalloc_restore_context_a0:
|
||||
.Lnew_vmalloc_restore_context_a0:
|
||||
REG_L a0, TASK_TI_A0(tp)
|
||||
.endm
|
||||
|
||||
@ -278,6 +278,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception)
|
||||
#else
|
||||
sret
|
||||
#endif
|
||||
SYM_INNER_LABEL(ret_from_exception_end, SYM_L_GLOBAL)
|
||||
SYM_CODE_END(ret_from_exception)
|
||||
ASM_NOKPROBE(ret_from_exception)
|
||||
|
||||
|
@ -23,7 +23,7 @@ struct used_bucket {
|
||||
|
||||
struct relocation_head {
|
||||
struct hlist_node node;
|
||||
struct list_head *rel_entry;
|
||||
struct list_head rel_entry;
|
||||
void *location;
|
||||
};
|
||||
|
||||
@ -634,7 +634,7 @@ process_accumulated_relocations(struct module *me,
|
||||
location = rel_head_iter->location;
|
||||
list_for_each_entry_safe(rel_entry_iter,
|
||||
rel_entry_iter_tmp,
|
||||
rel_head_iter->rel_entry,
|
||||
&rel_head_iter->rel_entry,
|
||||
head) {
|
||||
curr_type = rel_entry_iter->type;
|
||||
reloc_handlers[curr_type].reloc_handler(
|
||||
@ -704,16 +704,7 @@ static int add_relocation_to_accumulate(struct module *me, int type,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rel_head->rel_entry =
|
||||
kmalloc(sizeof(struct list_head), GFP_KERNEL);
|
||||
|
||||
if (!rel_head->rel_entry) {
|
||||
kfree(entry);
|
||||
kfree(rel_head);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(rel_head->rel_entry);
|
||||
INIT_LIST_HEAD(&rel_head->rel_entry);
|
||||
rel_head->location = location;
|
||||
INIT_HLIST_NODE(&rel_head->node);
|
||||
if (!current_head->first) {
|
||||
@ -722,7 +713,6 @@ static int add_relocation_to_accumulate(struct module *me, int type,
|
||||
|
||||
if (!bucket) {
|
||||
kfree(entry);
|
||||
kfree(rel_head->rel_entry);
|
||||
kfree(rel_head);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -735,7 +725,7 @@ static int add_relocation_to_accumulate(struct module *me, int type,
|
||||
}
|
||||
|
||||
/* Add relocation to head of discovered rel_head */
|
||||
list_add_tail(&entry->head, rel_head->rel_entry);
|
||||
list_add_tail(&entry->head, &rel_head->rel_entry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ static void __kprobes arch_prepare_ss_slot(struct kprobe *p)
|
||||
p->ainsn.api.restore = (unsigned long)p->addr + len;
|
||||
|
||||
patch_text_nosync(p->ainsn.api.insn, &p->opcode, len);
|
||||
patch_text_nosync(p->ainsn.api.insn + len, &insn, GET_INSN_LENGTH(insn));
|
||||
patch_text_nosync((void *)p->ainsn.api.insn + len, &insn, GET_INSN_LENGTH(insn));
|
||||
}
|
||||
|
||||
static void __kprobes arch_prepare_simulate(struct kprobe *p)
|
||||
|
@ -17,6 +17,7 @@
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
|
||||
extern asmlinkage void handle_exception(void);
|
||||
extern unsigned long ret_from_exception_end;
|
||||
|
||||
static inline int fp_is_valid(unsigned long fp, unsigned long sp)
|
||||
{
|
||||
@ -71,7 +72,8 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
|
||||
fp = frame->fp;
|
||||
pc = ftrace_graph_ret_addr(current, &graph_idx, frame->ra,
|
||||
&frame->ra);
|
||||
if (pc == (unsigned long)handle_exception) {
|
||||
if (pc >= (unsigned long)handle_exception &&
|
||||
pc < (unsigned long)&ret_from_exception_end) {
|
||||
if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc)))
|
||||
break;
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
int show_unhandled_signals = 1;
|
||||
|
||||
static DEFINE_SPINLOCK(die_lock);
|
||||
static DEFINE_RAW_SPINLOCK(die_lock);
|
||||
|
||||
static int copy_code(struct pt_regs *regs, u16 *val, const u16 *insns)
|
||||
{
|
||||
@ -81,7 +81,7 @@ void die(struct pt_regs *regs, const char *str)
|
||||
|
||||
oops_enter();
|
||||
|
||||
spin_lock_irqsave(&die_lock, flags);
|
||||
raw_spin_lock_irqsave(&die_lock, flags);
|
||||
console_verbose();
|
||||
bust_spinlocks(1);
|
||||
|
||||
@ -100,7 +100,7 @@ void die(struct pt_regs *regs, const char *str)
|
||||
|
||||
bust_spinlocks(0);
|
||||
add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
|
||||
spin_unlock_irqrestore(&die_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&die_lock, flags);
|
||||
oops_exit();
|
||||
|
||||
if (in_interrupt())
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/soc.h>
|
||||
#include <asm/sparsemem.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#include "../kernel/head.h"
|
||||
@ -62,6 +63,13 @@ EXPORT_SYMBOL(pgtable_l5_enabled);
|
||||
phys_addr_t phys_ram_base __ro_after_init;
|
||||
EXPORT_SYMBOL(phys_ram_base);
|
||||
|
||||
#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
||||
#define VMEMMAP_ADDR_ALIGN (1ULL << SECTION_SIZE_BITS)
|
||||
|
||||
unsigned long vmemmap_start_pfn __ro_after_init;
|
||||
EXPORT_SYMBOL(vmemmap_start_pfn);
|
||||
#endif
|
||||
|
||||
unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]
|
||||
__page_aligned_bss;
|
||||
EXPORT_SYMBOL(empty_zero_page);
|
||||
@ -240,8 +248,12 @@ static void __init setup_bootmem(void)
|
||||
* Make sure we align the start of the memory on a PMD boundary so that
|
||||
* at worst, we map the linear mapping with PMD mappings.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_XIP_KERNEL))
|
||||
if (!IS_ENABLED(CONFIG_XIP_KERNEL)) {
|
||||
phys_ram_base = memblock_start_of_DRAM() & PMD_MASK;
|
||||
#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
||||
vmemmap_start_pfn = round_down(phys_ram_base, VMEMMAP_ADDR_ALIGN) >> PAGE_SHIFT;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* In 64-bit, any use of __va/__pa before this point is wrong as we
|
||||
@ -1101,6 +1113,9 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
|
||||
kernel_map.xiprom_sz = (uintptr_t)(&_exiprom) - (uintptr_t)(&_xiprom);
|
||||
|
||||
phys_ram_base = CONFIG_PHYS_RAM_BASE;
|
||||
#ifdef CONFIG_SPARSEMEM_VMEMMAP
|
||||
vmemmap_start_pfn = round_down(phys_ram_base, VMEMMAP_ADDR_ALIGN) >> PAGE_SHIFT;
|
||||
#endif
|
||||
kernel_map.phys_addr = (uintptr_t)CONFIG_PHYS_RAM_BASE;
|
||||
kernel_map.size = (uintptr_t)(&_end) - (uintptr_t)(&_start);
|
||||
|
||||
|
@ -504,12 +504,12 @@ static int sbi_cpuidle_probe(struct platform_device *pdev)
|
||||
int cpu, ret;
|
||||
struct cpuidle_driver *drv;
|
||||
struct cpuidle_device *dev;
|
||||
struct device_node *np, *pds_node;
|
||||
struct device_node *pds_node;
|
||||
|
||||
/* Detect OSI support based on CPU DT nodes */
|
||||
sbi_cpuidle_use_osi = true;
|
||||
for_each_possible_cpu(cpu) {
|
||||
np = of_cpu_device_node_get(cpu);
|
||||
struct device_node *np __free(device_node) = of_cpu_device_node_get(cpu);
|
||||
if (np &&
|
||||
of_property_present(np, "power-domains") &&
|
||||
of_property_present(np, "power-domain-names")) {
|
||||
|
@ -507,8 +507,7 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
|
||||
{
|
||||
u32 type = event->attr.type;
|
||||
u64 config = event->attr.config;
|
||||
u64 raw_config_val;
|
||||
int ret;
|
||||
int ret = -ENOENT;
|
||||
|
||||
/*
|
||||
* Ensure we are finished checking standard hardware events for
|
||||
@ -528,21 +527,23 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
|
||||
case PERF_TYPE_RAW:
|
||||
/*
|
||||
* As per SBI specification, the upper 16 bits must be unused
|
||||
* for a raw event.
|
||||
* for a hardware raw event.
|
||||
* Bits 63:62 are used to distinguish between raw events
|
||||
* 00 - Hardware raw event
|
||||
* 10 - SBI firmware events
|
||||
* 11 - Risc-V platform specific firmware event
|
||||
*/
|
||||
raw_config_val = config & RISCV_PMU_RAW_EVENT_MASK;
|
||||
|
||||
switch (config >> 62) {
|
||||
case 0:
|
||||
ret = RISCV_PMU_RAW_EVENT_IDX;
|
||||
*econfig = raw_config_val;
|
||||
/* Return error any bits [48-63] is set as it is not allowed by the spec */
|
||||
if (!(config & ~RISCV_PMU_RAW_EVENT_MASK)) {
|
||||
*econfig = config & RISCV_PMU_RAW_EVENT_MASK;
|
||||
ret = RISCV_PMU_RAW_EVENT_IDX;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
ret = (raw_config_val & 0xFFFF) |
|
||||
(SBI_PMU_EVENT_TYPE_FW << 16);
|
||||
ret = (config & 0xFFFF) | (SBI_PMU_EVENT_TYPE_FW << 16);
|
||||
break;
|
||||
case 3:
|
||||
/*
|
||||
@ -551,12 +552,13 @@ static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
|
||||
* Event data - raw event encoding
|
||||
*/
|
||||
ret = SBI_PMU_EVENT_TYPE_FW << 16 | RISCV_PLAT_FW_EVENT;
|
||||
*econfig = raw_config_val;
|
||||
*econfig = config & RISCV_PMU_PLAT_FW_EVENT_MASK;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -ENOENT;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -185,8 +185,20 @@ static void test_fork_exec(void)
|
||||
}
|
||||
}
|
||||
|
||||
static bool pwrite_wrapper(int fd, void *buf, size_t count, const char *msg)
|
||||
{
|
||||
int ret = pwrite(fd, buf, count, 0);
|
||||
|
||||
if (ret != count) {
|
||||
ksft_perror(msg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void test_tagged_addr_abi_sysctl(void)
|
||||
{
|
||||
char *err_pwrite_msg = "failed to write to /proc/sys/abi/tagged_addr_disabled\n";
|
||||
char value;
|
||||
int fd;
|
||||
|
||||
@ -200,14 +212,18 @@ static void test_tagged_addr_abi_sysctl(void)
|
||||
}
|
||||
|
||||
value = '1';
|
||||
pwrite(fd, &value, 1, 0);
|
||||
ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == -EINVAL,
|
||||
"sysctl disabled\n");
|
||||
if (!pwrite_wrapper(fd, &value, 1, "write '1'"))
|
||||
ksft_test_result_fail(err_pwrite_msg);
|
||||
else
|
||||
ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == -EINVAL,
|
||||
"sysctl disabled\n");
|
||||
|
||||
value = '0';
|
||||
pwrite(fd, &value, 1, 0);
|
||||
ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == 0,
|
||||
"sysctl enabled\n");
|
||||
if (!pwrite_wrapper(fd, &value, 1, "write '0'"))
|
||||
ksft_test_result_fail(err_pwrite_msg);
|
||||
else
|
||||
ksft_test_result(set_tagged_addr_ctrl(min_pmlen, true) == 0,
|
||||
"sysctl enabled\n");
|
||||
|
||||
set_tagged_addr_ctrl(0, false);
|
||||
|
||||
|
@ -25,6 +25,8 @@ int main(void)
|
||||
unsigned long vl;
|
||||
char *datap, *tmp;
|
||||
|
||||
ksft_set_plan(1);
|
||||
|
||||
datap = malloc(MAX_VSIZE);
|
||||
if (!datap) {
|
||||
ksft_test_result_fail("fail to allocate memory for size = %d\n", MAX_VSIZE);
|
||||
@ -63,6 +65,8 @@ int main(void)
|
||||
}
|
||||
|
||||
free(datap);
|
||||
|
||||
ksft_test_result_pass("tests for v_initval_nolibc pass\n");
|
||||
ksft_exit_pass();
|
||||
return 0;
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ int main(void)
|
||||
long flag, expected;
|
||||
long rc;
|
||||
|
||||
ksft_set_plan(1);
|
||||
|
||||
pair.key = RISCV_HWPROBE_KEY_IMA_EXT_0;
|
||||
rc = riscv_hwprobe(&pair, 1, 0, NULL, 0);
|
||||
if (rc < 0) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user