Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Pull LoongArch fixes from Huacai Chen:
"Fix some build warnings for RUST-enabled objtool check, align ACPI
structures for ARCH_STRICT_ALIGN, fix an unreliable stack for live
patching, add some NULL pointer checkings, and fix some bugs around
KVM"

* tag 'loongarch-fixes-6.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
LoongArch: KVM: Avoid copy_*_user() with lock hold in kvm_pch_pic_regs_access()
LoongArch: KVM: Avoid copy_*_user() with lock hold in kvm_eiointc_sw_status_access()
LoongArch: KVM: Avoid copy_*_user() with lock hold in kvm_eiointc_regs_access()
LoongArch: KVM: Avoid copy_*_user() with lock hold in kvm_eiointc_ctrl_access()
LoongArch: KVM: Fix VM migration failure with PTW enabled
LoongArch: KVM: Remove unused returns and semicolons
LoongArch: vDSO: Check kcalloc() result in init_vdso()
LoongArch: Fix unreliable stack for live patching
LoongArch: Replace sprintf() with sysfs_emit()
LoongArch: Check the return value when creating kobj
LoongArch: Align ACPI structures if ARCH_STRICT_ALIGN enabled
LoongArch: Update help info of ARCH_STRICT_ALIGN
LoongArch: Handle jump tables options for RUST
LoongArch: Make LTO case independent in Makefile
objtool/LoongArch: Mark special atomic instruction as INSN_BUG type
objtool/LoongArch: Mark types based on break immediate code

+162 -69
+10 -2
arch/loongarch/Kconfig
··· 298 298 config CC_HAS_ANNOTATE_TABLEJUMP 299 299 def_bool $(cc-option,-mannotate-tablejump) 300 300 301 + config RUSTC_HAS_ANNOTATE_TABLEJUMP 302 + depends on RUST 303 + def_bool $(rustc-option,-Cllvm-args=--loongarch-annotate-tablejump) 304 + 301 305 menu "Kernel type and options" 302 306 303 307 source "kernel/Kconfig.hz" ··· 567 563 -mstrict-align build parameter to prevent unaligned accesses. 568 564 569 565 CPUs with h/w unaligned access support: 570 - Loongson-2K2000/2K3000/3A5000/3C5000/3D5000. 566 + Loongson-2K2000/2K3000 and all of Loongson-3 series processors 567 + based on LoongArch. 571 568 572 569 CPUs without h/w unaligned access support: 573 - Loongson-2K500/2K1000. 570 + Loongson-2K0300/2K0500/2K1000. 571 + 572 + If you want to make sure whether to support unaligned memory access 573 + on your hardware, please read the bit 20 (UAL) of CPUCFG1 register. 574 574 575 575 This option is enabled by default to make the kernel be able to run 576 576 on all LoongArch systems. But you can disable it manually if you want
+10 -5
arch/loongarch/Makefile
··· 102 102 103 103 ifdef CONFIG_OBJTOOL 104 104 ifdef CONFIG_CC_HAS_ANNOTATE_TABLEJUMP 105 + KBUILD_CFLAGS += -mannotate-tablejump 106 + else 107 + KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers 108 + endif 109 + ifdef CONFIG_RUSTC_HAS_ANNOTATE_TABLEJUMP 110 + KBUILD_RUSTFLAGS += -Cllvm-args=--loongarch-annotate-tablejump 111 + else 112 + KBUILD_RUSTFLAGS += -Zno-jump-tables # keep compatibility with older compilers 113 + endif 114 + ifdef CONFIG_LTO_CLANG 105 115 # The annotate-tablejump option can not be passed to LLVM backend when LTO is enabled. 106 116 # Ensure it is aware of linker with LTO, '--loongarch-annotate-tablejump' also needs to 107 117 # be passed via '-mllvm' to ld.lld. 108 - KBUILD_CFLAGS += -mannotate-tablejump 109 - ifdef CONFIG_LTO_CLANG 110 118 KBUILD_LDFLAGS += -mllvm --loongarch-annotate-tablejump 111 - endif 112 - else 113 - KBUILD_CFLAGS += -fno-jump-tables # keep compatibility with older compilers 114 119 endif 115 120 endif 116 121
+3 -4
arch/loongarch/include/asm/acenv.h
··· 10 10 #ifndef _ASM_LOONGARCH_ACENV_H 11 11 #define _ASM_LOONGARCH_ACENV_H 12 12 13 - /* 14 - * This header is required by ACPI core, but we have nothing to fill in 15 - * right now. Will be updated later when needed. 16 - */ 13 + #ifdef CONFIG_ARCH_STRICT_ALIGN 14 + #define ACPI_MISALIGNMENT_NOT_SUPPORTED 15 + #endif /* CONFIG_ARCH_STRICT_ALIGN */ 17 16 18 17 #endif /* _ASM_LOONGARCH_ACENV_H */
+16 -4
arch/loongarch/include/asm/kvm_mmu.h
··· 16 16 */ 17 17 #define KVM_MMU_CACHE_MIN_PAGES (CONFIG_PGTABLE_LEVELS - 1) 18 18 19 + /* 20 + * _PAGE_MODIFIED is a SW pte bit, it records page ever written on host 21 + * kernel, on secondary MMU it records the page writeable attribute, in 22 + * order for fast path handling. 23 + */ 24 + #define KVM_PAGE_WRITEABLE _PAGE_MODIFIED 25 + 19 26 #define _KVM_FLUSH_PGTABLE 0x1 20 27 #define _KVM_HAS_PGMASK 0x2 21 28 #define kvm_pfn_pte(pfn, prot) (((pfn) << PFN_PTE_SHIFT) | pgprot_val(prot)) ··· 59 52 WRITE_ONCE(*ptep, val); 60 53 } 61 54 62 - static inline int kvm_pte_write(kvm_pte_t pte) { return pte & _PAGE_WRITE; } 63 - static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & _PAGE_DIRTY; } 64 55 static inline int kvm_pte_young(kvm_pte_t pte) { return pte & _PAGE_ACCESSED; } 65 56 static inline int kvm_pte_huge(kvm_pte_t pte) { return pte & _PAGE_HUGE; } 57 + static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & __WRITEABLE; } 58 + static inline int kvm_pte_writeable(kvm_pte_t pte) { return pte & KVM_PAGE_WRITEABLE; } 66 59 67 60 static inline kvm_pte_t kvm_pte_mkyoung(kvm_pte_t pte) 68 61 { ··· 76 69 77 70 static inline kvm_pte_t kvm_pte_mkdirty(kvm_pte_t pte) 78 71 { 79 - return pte | _PAGE_DIRTY; 72 + return pte | __WRITEABLE; 80 73 } 81 74 82 75 static inline kvm_pte_t kvm_pte_mkclean(kvm_pte_t pte) 83 76 { 84 - return pte & ~_PAGE_DIRTY; 77 + return pte & ~__WRITEABLE; 85 78 } 86 79 87 80 static inline kvm_pte_t kvm_pte_mkhuge(kvm_pte_t pte) ··· 92 85 static inline kvm_pte_t kvm_pte_mksmall(kvm_pte_t pte) 93 86 { 94 87 return pte & ~_PAGE_HUGE; 88 + } 89 + 90 + static inline kvm_pte_t kvm_pte_mkwriteable(kvm_pte_t pte) 91 + { 92 + return pte | KVM_PAGE_WRITEABLE; 95 93 } 96 94 97 95 static inline int kvm_need_flush(kvm_ptw_ctx *ctx)
+3 -1
arch/loongarch/kernel/env.c
··· 86 86 static ssize_t boardinfo_show(struct kobject *kobj, 87 87 struct kobj_attribute *attr, char *buf) 88 88 { 89 - return sprintf(buf, 89 + return sysfs_emit(buf, 90 90 "BIOS Information\n" 91 91 "Vendor\t\t\t: %s\n" 92 92 "Version\t\t\t: %s\n" ··· 109 109 struct kobject *loongson_kobj; 110 110 111 111 loongson_kobj = kobject_create_and_add("loongson", firmware_kobj); 112 + if (!loongson_kobj) 113 + return -ENOMEM; 112 114 113 115 return sysfs_create_file(loongson_kobj, &boardinfo_attr.attr); 114 116 }
+2 -1
arch/loongarch/kernel/stacktrace.c
··· 51 51 if (task == current) { 52 52 regs->regs[3] = (unsigned long)__builtin_frame_address(0); 53 53 regs->csr_era = (unsigned long)__builtin_return_address(0); 54 + regs->regs[22] = 0; 54 55 } else { 55 56 regs->regs[3] = thread_saved_fp(task); 56 57 regs->csr_era = thread_saved_ra(task); 58 + regs->regs[22] = task->thread.reg22; 57 59 } 58 60 regs->regs[1] = 0; 59 - regs->regs[22] = 0; 60 61 61 62 for (unwind_start(&state, task, regs); 62 63 !unwind_done(&state) && !unwind_error(&state); unwind_next_frame(&state)) {
+3
arch/loongarch/kernel/vdso.c
··· 54 54 vdso_info.code_mapping.pages = 55 55 kcalloc(vdso_info.size / PAGE_SIZE, sizeof(struct page *), GFP_KERNEL); 56 56 57 + if (!vdso_info.code_mapping.pages) 58 + return -ENOMEM; 59 + 57 60 pfn = __phys_to_pfn(__pa_symbol(vdso_info.vdso)); 58 61 for (i = 0; i < vdso_info.size / PAGE_SIZE; i++) 59 62 vdso_info.code_mapping.pages[i] = pfn_to_page(pfn + i);
+2 -4
arch/loongarch/kvm/exit.c
··· 778 778 return 0; 779 779 default: 780 780 return KVM_HCALL_INVALID_CODE; 781 - }; 782 - 783 - return KVM_HCALL_INVALID_CODE; 784 - }; 781 + } 782 + } 785 783 786 784 /* 787 785 * kvm_handle_lsx_disabled() - Guest used LSX while disabled in root.
+53 -34
arch/loongarch/kvm/intc/eiointc.c
··· 426 426 struct loongarch_eiointc *s = dev->kvm->arch.eiointc; 427 427 428 428 data = (void __user *)attr->addr; 429 + switch (type) { 430 + case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU: 431 + case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE: 432 + if (copy_from_user(&val, data, 4)) 433 + return -EFAULT; 434 + break; 435 + default: 436 + break; 437 + } 438 + 429 439 spin_lock_irqsave(&s->lock, flags); 430 440 switch (type) { 431 441 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU: 432 - if (copy_from_user(&val, data, 4)) 433 - ret = -EFAULT; 434 - else { 435 - if (val >= EIOINTC_ROUTE_MAX_VCPUS) 436 - ret = -EINVAL; 437 - else 438 - s->num_cpu = val; 439 - } 442 + if (val >= EIOINTC_ROUTE_MAX_VCPUS) 443 + ret = -EINVAL; 444 + else 445 + s->num_cpu = val; 440 446 break; 441 447 case KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE: 442 - if (copy_from_user(&s->features, data, 4)) 443 - ret = -EFAULT; 448 + s->features = val; 444 449 if (!(s->features & BIT(EIOINTC_HAS_VIRT_EXTENSION))) 445 450 s->status |= BIT(EIOINTC_ENABLE); 446 451 break; ··· 467 462 468 463 static int kvm_eiointc_regs_access(struct kvm_device *dev, 469 464 struct kvm_device_attr *attr, 470 - bool is_write) 465 + bool is_write, int *data) 471 466 { 472 467 int addr, cpu, offset, ret = 0; 473 468 unsigned long flags; 474 469 void *p = NULL; 475 - void __user *data; 476 470 struct loongarch_eiointc *s; 477 471 478 472 s = dev->kvm->arch.eiointc; 479 473 addr = attr->attr; 480 474 cpu = addr >> 16; 481 475 addr &= 0xffff; 482 - data = (void __user *)attr->addr; 483 476 switch (addr) { 484 477 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END: 485 478 offset = (addr - EIOINTC_NODETYPE_START) / 4; ··· 516 513 } 517 514 518 515 spin_lock_irqsave(&s->lock, flags); 519 - if (is_write) { 520 - if (copy_from_user(p, data, 4)) 521 - ret = -EFAULT; 522 - } else { 523 - if (copy_to_user(data, p, 4)) 524 - ret = -EFAULT; 525 - } 516 + if (is_write) 517 + memcpy(p, data, 4); 518 + else 519 + memcpy(data, p, 4); 526 520 spin_unlock_irqrestore(&s->lock, flags); 527 521 528 522 return ret; ··· 527 527 528 528 static int kvm_eiointc_sw_status_access(struct kvm_device *dev, 529 529 struct kvm_device_attr *attr, 530 - bool is_write) 530 + bool is_write, int *data) 531 531 { 532 532 int addr, ret = 0; 533 533 unsigned long flags; 534 534 void *p = NULL; 535 - void __user *data; 536 535 struct loongarch_eiointc *s; 537 536 538 537 s = dev->kvm->arch.eiointc; 539 538 addr = attr->attr; 540 539 addr &= 0xffff; 541 540 542 - data = (void __user *)attr->addr; 543 541 switch (addr) { 544 542 case KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU: 545 543 if (is_write) ··· 559 561 return -EINVAL; 560 562 } 561 563 spin_lock_irqsave(&s->lock, flags); 562 - if (is_write) { 563 - if (copy_from_user(p, data, 4)) 564 - ret = -EFAULT; 565 - } else { 566 - if (copy_to_user(data, p, 4)) 567 - ret = -EFAULT; 568 - } 564 + if (is_write) 565 + memcpy(p, data, 4); 566 + else 567 + memcpy(data, p, 4); 569 568 spin_unlock_irqrestore(&s->lock, flags); 570 569 571 570 return ret; ··· 571 576 static int kvm_eiointc_get_attr(struct kvm_device *dev, 572 577 struct kvm_device_attr *attr) 573 578 { 579 + int ret, data; 580 + 574 581 switch (attr->group) { 575 582 case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS: 576 - return kvm_eiointc_regs_access(dev, attr, false); 583 + ret = kvm_eiointc_regs_access(dev, attr, false, &data); 584 + if (ret) 585 + return ret; 586 + 587 + if (copy_to_user((void __user *)attr->addr, &data, 4)) 588 + ret = -EFAULT; 589 + 590 + return ret; 577 591 case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS: 578 - return kvm_eiointc_sw_status_access(dev, attr, false); 592 + ret = kvm_eiointc_sw_status_access(dev, attr, false, &data); 593 + if (ret) 594 + return ret; 595 + 596 + if (copy_to_user((void __user *)attr->addr, &data, 4)) 597 + ret = -EFAULT; 598 + 599 + return ret; 579 600 default: 580 601 return -EINVAL; 581 602 } ··· 600 589 static int kvm_eiointc_set_attr(struct kvm_device *dev, 601 590 struct kvm_device_attr *attr) 602 591 { 592 + int data; 593 + 603 594 switch (attr->group) { 604 595 case KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL: 605 596 return kvm_eiointc_ctrl_access(dev, attr); 606 597 case KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS: 607 - return kvm_eiointc_regs_access(dev, attr, true); 598 + if (copy_from_user(&data, (void __user *)attr->addr, 4)) 599 + return -EFAULT; 600 + 601 + return kvm_eiointc_regs_access(dev, attr, true, &data); 608 602 case KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS: 609 - return kvm_eiointc_sw_status_access(dev, attr, true); 603 + if (copy_from_user(&data, (void __user *)attr->addr, 4)) 604 + return -EFAULT; 605 + 606 + return kvm_eiointc_sw_status_access(dev, attr, true, &data); 610 607 default: 611 608 return -EINVAL; 612 609 }
+14 -7
arch/loongarch/kvm/intc/pch_pic.c
··· 348 348 struct kvm_device_attr *attr, 349 349 bool is_write) 350 350 { 351 + char buf[8]; 351 352 int addr, offset, len = 8, ret = 0; 352 353 void __user *data; 353 354 void *p = NULL; ··· 398 397 return -EINVAL; 399 398 } 400 399 401 - spin_lock(&s->lock); 402 - /* write or read value according to is_write */ 403 400 if (is_write) { 404 - if (copy_from_user(p, data, len)) 405 - ret = -EFAULT; 406 - } else { 407 - if (copy_to_user(data, p, len)) 408 - ret = -EFAULT; 401 + if (copy_from_user(buf, data, len)) 402 + return -EFAULT; 409 403 } 404 + 405 + spin_lock(&s->lock); 406 + if (is_write) 407 + memcpy(p, buf, len); 408 + else 409 + memcpy(buf, p, len); 410 410 spin_unlock(&s->lock); 411 + 412 + if (!is_write) { 413 + if (copy_to_user(data, buf, len)) 414 + return -EFAULT; 415 + } 411 416 412 417 return ret; 413 418 }
+4 -4
arch/loongarch/kvm/mmu.c
··· 569 569 /* Track access to pages marked old */ 570 570 new = kvm_pte_mkyoung(*ptep); 571 571 if (write && !kvm_pte_dirty(new)) { 572 - if (!kvm_pte_write(new)) { 572 + if (!kvm_pte_writeable(new)) { 573 573 ret = -EFAULT; 574 574 goto out; 575 575 } ··· 856 856 prot_bits |= _CACHE_SUC; 857 857 858 858 if (writeable) { 859 - prot_bits |= _PAGE_WRITE; 859 + prot_bits = kvm_pte_mkwriteable(prot_bits); 860 860 if (write) 861 - prot_bits |= __WRITEABLE; 861 + prot_bits = kvm_pte_mkdirty(prot_bits); 862 862 } 863 863 864 864 /* Disable dirty logging on HugePages */ ··· 904 904 kvm_release_faultin_page(kvm, page, false, writeable); 905 905 spin_unlock(&kvm->mmu_lock); 906 906 907 - if (prot_bits & _PAGE_DIRTY) 907 + if (kvm_pte_dirty(prot_bits)) 908 908 mark_page_dirty_in_slot(kvm, memslot, gfn); 909 909 910 910 out:
+12
tools/arch/loongarch/include/asm/inst.h
··· 51 51 bgeu_op = 0x1b, 52 52 }; 53 53 54 + enum reg3_op { 55 + amswapw_op = 0x70c0, 56 + }; 57 + 54 58 struct reg0i15_format { 55 59 unsigned int immediate : 15; 56 60 unsigned int opcode : 17; ··· 100 96 unsigned int opcode : 6; 101 97 }; 102 98 99 + struct reg3_format { 100 + unsigned int rd : 5; 101 + unsigned int rj : 5; 102 + unsigned int rk : 5; 103 + unsigned int opcode : 17; 104 + }; 105 + 103 106 union loongarch_instruction { 104 107 unsigned int word; 105 108 struct reg0i15_format reg0i15_format; ··· 116 105 struct reg2i12_format reg2i12_format; 117 106 struct reg2i14_format reg2i14_format; 118 107 struct reg2i16_format reg2i16_format; 108 + struct reg3_format reg3_format; 119 109 }; 120 110 121 111 #define LOONGARCH_INSN_SIZE sizeof(union loongarch_instruction)
+30 -3
tools/objtool/arch/loongarch/decode.c
··· 278 278 return true; 279 279 } 280 280 281 + static bool decode_insn_reg3_fomat(union loongarch_instruction inst, 282 + struct instruction *insn) 283 + { 284 + switch (inst.reg3_format.opcode) { 285 + case amswapw_op: 286 + if (inst.reg3_format.rd == LOONGARCH_GPR_ZERO && 287 + inst.reg3_format.rk == LOONGARCH_GPR_RA && 288 + inst.reg3_format.rj == LOONGARCH_GPR_ZERO) { 289 + /* amswap.w $zero, $ra, $zero */ 290 + insn->type = INSN_BUG; 291 + } 292 + break; 293 + default: 294 + return false; 295 + } 296 + 297 + return true; 298 + } 299 + 281 300 int arch_decode_instruction(struct objtool_file *file, const struct section *sec, 282 301 unsigned long offset, unsigned int maxlen, 283 302 struct instruction *insn) ··· 328 309 return 0; 329 310 if (decode_insn_reg2i16_fomat(inst, insn)) 330 311 return 0; 312 + if (decode_insn_reg3_fomat(inst, insn)) 313 + return 0; 331 314 332 - if (inst.word == 0) 315 + if (inst.word == 0) { 316 + /* andi $zero, $zero, 0x0 */ 333 317 insn->type = INSN_NOP; 334 - else if (inst.reg0i15_format.opcode == break_op) { 335 - /* break */ 318 + } else if (inst.reg0i15_format.opcode == break_op && 319 + inst.reg0i15_format.immediate == 0x0) { 320 + /* break 0x0 */ 321 + insn->type = INSN_TRAP; 322 + } else if (inst.reg0i15_format.opcode == break_op && 323 + inst.reg0i15_format.immediate == 0x1) { 324 + /* break 0x1 */ 336 325 insn->type = INSN_BUG; 337 326 } else if (inst.reg2_format.opcode == ertn_op) { 338 327 /* ertn */