k1: support user-space load and store misaligned on io memory area

The PCIe BAR area must be mapped as IO attribute for GPU VRAM area,
but, there may be some misaligned access in user-space program. Then,
it will trigger 5# exception when misaligned load and 7# excepiton
when misaligned store. And user-space program will crash because of
the 5# exception and 7# exception can't be fixed.
So, we try to process the user-space io area misligned access firstly
when the 5# exception and 7# exception are caught

Change-Id: Iac78bcdb8505dd113dcc4deed782e78016ddbf9b
This commit is contained in:
zhangmeng
2025-07-16 09:48:44 +08:00
committed by 张猛
parent 14d1b98300
commit db0d3fc566
2 changed files with 91 additions and 0 deletions

View File

@@ -176,6 +176,19 @@ config SPACEMIT_ERRATA_LOAD_ATOMIC
help
This enable fix errata caused by readforward and writeback.
config SPACEMIT_K1_PCIE_USR_MISALIGNED
bool "process user space misaligned access on PCIe Slave IO Area"
depends on SOC_SPACEMIT_K1X
default y
help
The PCIe controller in Spacemit K1 does not support discontinuous
write operations with AXI bus-generated wstrb signals. Consequently,
the PCIe slave memory space is mapped as IO attributes. However,
when user-space programs perform unaligned memory accesses in this
IO-attributed space, memory access faults occur. Specialized handling
for this specific error type is implemented to ensure proper execution
of user-space programs.
endif
endmenu # "SoC selection"

View File

@@ -211,8 +211,63 @@ asmlinkage __visible __trap_section void do_trap_insn_illegal(struct pt_regs *re
}
}
#ifdef CONFIG_SPACEMIT_K1_PCIE_USR_MISALIGNED
#define SPACEMIT_K1_PCIE_DATA_LOW (0x80000000)
#define SPACEMIT_K1_PCIE_DATA_HIGH (0xB7FFFFFF)
static int check_if_user_io_area_misaligned(struct pt_regs *regs)
{
pte_t *ptep;
spinlock_t *ptl;
unsigned long v_addr = regs->badaddr, phy_addr;
struct mm_struct *mm = current->mm;
/* try to get the pte of the trap address */
ptep = get_locked_pte(mm, v_addr, &ptl);
if (!ptep)
return 0;
/* check if the area is _PAGE_IO attribute */
if (!pte_present(*ptep) || !(pte_val(*ptep) & _PAGE_IO)) {
pte_unmap_unlock(ptep, ptl);
return 0;
}
/* release the pte */
pte_unmap_unlock(ptep, ptl);
/* check if the area is in pcie memory area */
phy_addr = (pte_pfn(*ptep) << PAGE_SHIFT) | (v_addr & ~PAGE_MASK);
if ((phy_addr < SPACEMIT_K1_PCIE_DATA_LOW) || (phy_addr > SPACEMIT_K1_PCIE_DATA_HIGH)) {
return 0;
}
return 1;
}
DO_ERROR_INFO(do_trap_load_fault_inner,
SIGSEGV, SEGV_ACCERR, "load access fault");
asmlinkage __visible __trap_section void do_trap_load_fault(struct pt_regs *regs)
{
/* Try to process the exception as a load misaligned on io memory area */
if (user_mode(regs)) {
irqentry_enter_from_user_mode(regs);
if (check_if_user_io_area_misaligned(regs) && !handle_misaligned_load(regs)) {
irqentry_exit_to_user_mode(regs);
return;
}
irqentry_exit_to_user_mode(regs);
}
do_trap_load_fault_inner(regs);
}
#else
DO_ERROR_INFO(do_trap_load_fault,
SIGSEGV, SEGV_ACCERR, "load access fault");
#endif
asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
{
@@ -255,8 +310,31 @@ asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs
irqentry_nmi_exit(regs, state);
}
}
#ifdef CONFIG_SPACEMIT_K1_PCIE_USR_MISALIGNED
DO_ERROR_INFO(do_trap_store_fault_inner,
SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
asmlinkage __visible __trap_section void do_trap_store_fault(struct pt_regs *regs)
{
/* Try to process the exception as a store misaligned on io memory area */
if (user_mode(regs)) {
irqentry_enter_from_user_mode(regs);
if (check_if_user_io_area_misaligned(regs) && !handle_misaligned_store(regs)) {
irqentry_exit_to_user_mode(regs);
return;
}
irqentry_exit_to_user_mode(regs);
}
do_trap_store_fault_inner(regs);
}
#else
DO_ERROR_INFO(do_trap_store_fault,
SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
#endif
DO_ERROR_INFO(do_trap_ecall_s,
SIGILL, ILL_ILLTRP, "environment call from S-mode");
DO_ERROR_INFO(do_trap_ecall_m,