Merge tag 'loongarch-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson

Pull LoongArch fixes from Huacai Chen:
 "Fix missing NULL checks for kstrdup(), workaround LS2K/LS7A GPU
  DMA hang bug, emit GNU_EH_FRAME for vDSO correctly, and fix some
  KVM-related bugs"

* tag 'loongarch-fixes-7.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
  LoongArch: KVM: Fix base address calculation in kvm_eiointc_regs_access()
  LoongArch: KVM: Handle the case that EIOINTC's coremap is empty
  LoongArch: KVM: Make kvm_get_vcpu_by_cpuid() more robust
  LoongArch: vDSO: Emit GNU_EH_FRAME correctly
  LoongArch: Workaround LS2K/LS7A GPU DMA hang bug
  LoongArch: Fix missing NULL checks for kstrdup()
This commit is contained in:
Linus Torvalds
2026-03-27 15:39:41 -07:00
10 changed files with 147 additions and 22 deletions

View File

@@ -41,4 +41,40 @@
.cfi_endproc; \
SYM_END(name, SYM_T_NONE)
/*
* This is for the signal handler trampoline, which is used as the return
* address of the signal handlers in userspace instead of called normally.
* The long standing libgcc bug https://gcc.gnu.org/PR124050 requires a
* nop between .cfi_startproc and the actual address of the trampoline, so
* we cannot simply use SYM_FUNC_START.
*
* This wrapper also contains all the .cfi_* directives for recovering
* the content of the GPRs and the "return address" (where the rt_sigreturn
* syscall will jump to), assuming there is a struct rt_sigframe (where
* a struct sigcontext containing those information we need to recover) at
* $sp. The "DWARF for the LoongArch(TM) Architecture" manual states
* column 0 is for $zero, but it does not make too much sense to
* save/restore the hardware zero register. Repurpose this column here
* for the return address (here it's not the content of $ra we cannot use
* the default column 3).
*/
#define SYM_SIGFUNC_START(name) \
.cfi_startproc; \
.cfi_signal_frame; \
.cfi_def_cfa 3, RT_SIGFRAME_SC; \
.cfi_return_column 0; \
.cfi_offset 0, SC_PC; \
\
.irp num, 1, 2, 3, 4, 5, 6, 7, 8, \
9, 10, 11, 12, 13, 14, 15, 16, \
17, 18, 19, 20, 21, 22, 23, 24, \
25, 26, 27, 28, 29, 30, 31; \
.cfi_offset \num, SC_REGS + \num * SZREG; \
.endr; \
\
nop; \
SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)
#define SYM_SIGFUNC_END(name) SYM_FUNC_END(name)
#endif

View File

@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#include <asm/siginfo.h>
#include <asm/ucontext.h>
struct rt_sigframe {
struct siginfo rs_info;
struct ucontext rs_uctx;
};

View File

@@ -16,6 +16,7 @@
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/ftrace.h>
#include <asm/sigframe.h>
#include <vdso/datapage.h>
static void __used output_ptreg_defines(void)
@@ -220,6 +221,7 @@ static void __used output_sc_defines(void)
COMMENT("Linux sigcontext offsets.");
OFFSET(SC_REGS, sigcontext, sc_regs);
OFFSET(SC_PC, sigcontext, sc_pc);
OFFSET(RT_SIGFRAME_SC, rt_sigframe, rs_uctx.uc_mcontext);
BLANK();
}

View File

@@ -42,16 +42,15 @@ static int __init init_cpu_fullname(void)
int cpu, ret;
char *cpuname;
const char *model;
struct device_node *root;
/* Parsing cpuname from DTS model property */
root = of_find_node_by_path("/");
ret = of_property_read_string(root, "model", &model);
ret = of_property_read_string(of_root, "model", &model);
if (ret == 0) {
cpuname = kstrdup(model, GFP_KERNEL);
if (!cpuname)
return -ENOMEM;
loongson_sysconf.cpuname = strsep(&cpuname, " ");
}
of_node_put(root);
if (loongson_sysconf.cpuname && !strncmp(loongson_sysconf.cpuname, "Loongson", 8)) {
for (cpu = 0; cpu < NR_CPUS; cpu++)

View File

@@ -35,6 +35,7 @@
#include <asm/cpu-features.h>
#include <asm/fpu.h>
#include <asm/lbt.h>
#include <asm/sigframe.h>
#include <asm/ucontext.h>
#include <asm/vdso.h>
@@ -51,11 +52,6 @@
#define lock_lbt_owner() ({ preempt_disable(); pagefault_disable(); })
#define unlock_lbt_owner() ({ pagefault_enable(); preempt_enable(); })
struct rt_sigframe {
struct siginfo rs_info;
struct ucontext rs_uctx;
};
struct _ctx_layout {
struct sctx_info *addr;
unsigned int size;

View File

@@ -83,7 +83,7 @@ static inline void eiointc_update_sw_coremap(struct loongarch_eiointc *s,
if (!(s->status & BIT(EIOINTC_ENABLE_CPU_ENCODE))) {
cpuid = ffs(cpuid) - 1;
cpuid = (cpuid >= 4) ? 0 : cpuid;
cpuid = ((cpuid < 0) || (cpuid >= 4)) ? 0 : cpuid;
}
vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid);
@@ -472,34 +472,34 @@ static int kvm_eiointc_regs_access(struct kvm_device *dev,
switch (addr) {
case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
offset = (addr - EIOINTC_NODETYPE_START) / 4;
p = s->nodetype + offset * 4;
p = (void *)s->nodetype + offset * 4;
break;
case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END:
offset = (addr - EIOINTC_IPMAP_START) / 4;
p = &s->ipmap + offset * 4;
p = (void *)&s->ipmap + offset * 4;
break;
case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
offset = (addr - EIOINTC_ENABLE_START) / 4;
p = s->enable + offset * 4;
p = (void *)s->enable + offset * 4;
break;
case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END:
offset = (addr - EIOINTC_BOUNCE_START) / 4;
p = s->bounce + offset * 4;
p = (void *)s->bounce + offset * 4;
break;
case EIOINTC_ISR_START ... EIOINTC_ISR_END:
offset = (addr - EIOINTC_ISR_START) / 4;
p = s->isr + offset * 4;
p = (void *)s->isr + offset * 4;
break;
case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
if (cpu >= s->num_cpu)
return -EINVAL;
offset = (addr - EIOINTC_COREISR_START) / 4;
p = s->coreisr[cpu] + offset * 4;
p = (void *)s->coreisr[cpu] + offset * 4;
break;
case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
offset = (addr - EIOINTC_COREMAP_START) / 4;
p = s->coremap + offset * 4;
p = (void *)s->coremap + offset * 4;
break;
default:
kvm_err("%s: unknown eiointc register, addr = %d\n", __func__, addr);

View File

@@ -588,6 +588,9 @@ struct kvm_vcpu *kvm_get_vcpu_by_cpuid(struct kvm *kvm, int cpuid)
{
struct kvm_phyid_map *map;
if (cpuid < 0)
return NULL;
if (cpuid >= KVM_MAX_PHYID)
return NULL;

View File

@@ -5,9 +5,11 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <asm/cacheflush.h>
#include <asm/loongson.h>
@@ -15,6 +17,9 @@
#define PCI_DEVICE_ID_LOONGSON_DC1 0x7a06
#define PCI_DEVICE_ID_LOONGSON_DC2 0x7a36
#define PCI_DEVICE_ID_LOONGSON_DC3 0x7a46
#define PCI_DEVICE_ID_LOONGSON_GPU1 0x7a15
#define PCI_DEVICE_ID_LOONGSON_GPU2 0x7a25
#define PCI_DEVICE_ID_LOONGSON_GPU3 0x7a35
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
int reg, int len, u32 *val)
@@ -99,3 +104,78 @@ static void pci_fixup_vgadev(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC1, pci_fixup_vgadev);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC2, pci_fixup_vgadev);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_DC3, pci_fixup_vgadev);
#define CRTC_NUM_MAX 2
#define CRTC_OUTPUT_ENABLE 0x100
static void loongson_gpu_fixup_dma_hang(struct pci_dev *pdev, bool on)
{
u32 i, val, count, crtc_offset, device;
void __iomem *crtc_reg, *base, *regbase;
static u32 crtc_status[CRTC_NUM_MAX] = { 0 };
base = pdev->bus->ops->map_bus(pdev->bus, pdev->devfn + 1, 0);
device = readw(base + PCI_DEVICE_ID);
regbase = ioremap(readq(base + PCI_BASE_ADDRESS_0) & ~0xffull, SZ_64K);
if (!regbase) {
pci_err(pdev, "Failed to ioremap()\n");
return;
}
switch (device) {
case PCI_DEVICE_ID_LOONGSON_DC2:
crtc_reg = regbase + 0x1240;
crtc_offset = 0x10;
break;
case PCI_DEVICE_ID_LOONGSON_DC3:
crtc_reg = regbase;
crtc_offset = 0x400;
break;
}
for (i = 0; i < CRTC_NUM_MAX; i++, crtc_reg += crtc_offset) {
val = readl(crtc_reg);
if (!on)
crtc_status[i] = val;
/* No need to fixup if the status is off at startup. */
if (!(crtc_status[i] & CRTC_OUTPUT_ENABLE))
continue;
if (on)
val |= CRTC_OUTPUT_ENABLE;
else
val &= ~CRTC_OUTPUT_ENABLE;
mb();
writel(val, crtc_reg);
for (count = 0; count < 40; count++) {
val = readl(crtc_reg) & CRTC_OUTPUT_ENABLE;
if ((on && val) || (!on && !val))
break;
udelay(1000);
}
pci_info(pdev, "DMA hang fixup at reg[0x%lx]: 0x%x\n",
(unsigned long)crtc_reg & 0xffff, readl(crtc_reg));
}
iounmap(regbase);
}
static void pci_fixup_dma_hang_early(struct pci_dev *pdev)
{
loongson_gpu_fixup_dma_hang(pdev, false);
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_early);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_early);
static void pci_fixup_dma_hang_final(struct pci_dev *pdev)
{
loongson_gpu_fixup_dma_hang(pdev, true);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU2, pci_fixup_dma_hang_final);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, PCI_DEVICE_ID_LOONGSON_GPU3, pci_fixup_dma_hang_final);

View File

@@ -26,7 +26,7 @@ cflags-vdso := $(ccflags-vdso) \
$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
-std=gnu11 -fms-extensions -O2 -g -fno-strict-aliasing -fno-common -fno-builtin \
-fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
$(call cc-option, -fno-asynchronous-unwind-tables) \
$(call cc-option, -fasynchronous-unwind-tables) \
$(call cc-option, -fno-stack-protector)
aflags-vdso := $(ccflags-vdso) \
-D__ASSEMBLY__ -Wa,-gdwarf-2
@@ -41,7 +41,7 @@ endif
# VDSO linker flags.
ldflags-y := -Bsymbolic --no-undefined -soname=linux-vdso.so.1 \
$(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id -T
$(filter -E%,$(KBUILD_CFLAGS)) -shared --build-id --eh-frame-hdr -T
#
# Shared build commands.

View File

@@ -12,13 +12,13 @@
#include <asm/regdef.h>
#include <asm/asm.h>
#include <asm/asm-offsets.h>
.section .text
.cfi_sections .debug_frame
SYM_FUNC_START(__vdso_rt_sigreturn)
SYM_SIGFUNC_START(__vdso_rt_sigreturn)
li.w a7, __NR_rt_sigreturn
syscall 0
SYM_FUNC_END(__vdso_rt_sigreturn)
SYM_SIGFUNC_END(__vdso_rt_sigreturn)