[RFC,07/13] powerpc/vas: Update CSB and notify process for fault CRBs
diff mbox series

Message ID 1571464636.24387.32.camel@hbabu-laptop
State New
Headers show
Series
  • powerpc/vas: Page fault handling for user space NX requests
Related show

Commit Message

Haren Myneni Oct. 19, 2019, 5:57 a.m. UTC
For each fault CRB, update fault address in CRB (fault_storage_addr)
and translation error status in CSB. If the actual fault is in CSB,
send signal to process with SIGSEGV. Process can send new request by
touching the fault address.

Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Signed-off-by: Haren Myneni <haren@us.ibm.com>
---
 arch/powerpc/platforms/powernv/vas-fault.c | 115 +++++++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/vas.h       |   5 ++
 2 files changed, 120 insertions(+)

Patch
diff mbox series

diff --git a/arch/powerpc/platforms/powernv/vas-fault.c b/arch/powerpc/platforms/powernv/vas-fault.c
index 02b5c10..7aacce9 100644
--- a/arch/powerpc/platforms/powernv/vas-fault.c
+++ b/arch/powerpc/platforms/powernv/vas-fault.c
@@ -40,6 +40,120 @@  void vas_wakeup_fault_handler(int virq, void *arg)
 }
 
 /*
+ * Check if the fault occurred in the CSB itself. Return true if so, false
+ */
+static bool fault_in_csb(struct coprocessor_request_block *crb)
+{
+	u64 fault_addr, csb_start, csb_end;
+
+	fault_addr = crb_nx_fault_addr(crb);
+	csb_start = crb_csb_addr(crb);
+	csb_end = csb_start + sizeof(struct coprocessor_status_block);
+
+	if (fault_addr >= csb_start && fault_addr < csb_end) {
+		pr_err("CSB Fault: csb start/end 0x%llx/0x%llx, addr 0x%llx\n",
+			csb_start, csb_end, fault_addr);
+		return true;
+	}
+
+	return false;
+}
+
+static void notify_process(pid_t pid, u64 fault_addr)
+{
+	int rc;
+	struct kernel_siginfo info;
+
+	memset(&info, 0, sizeof(info));
+
+	info.si_signo = SIGSEGV;
+	info.si_errno = 0;
+	info.si_code = 0;
+
+	info.si_addr = (void *)fault_addr;
+	rcu_read_lock();
+	rc = kill_pid_info(SIGSEGV, &info, find_vpid(pid));
+	rcu_read_unlock();
+
+	pr_devel("%s(): pid %d kill_proc_info() rc %d\n", __func__, pid, rc);
+}
+
+/*
+ * Update the CSB to indicate a translation error.
+ *
+ * If the fault is in the CSB address itself or if we are unable to
+ * update the CSB, send a signal to the process, because we have no
+ * other way of notifying the user process.
+ *
+ * Remaining settings in the CSB are based on wait_for_csb() of
+ * NX-GZIP.
+*/
+static void update_csb(int pid, struct coprocessor_request_block *crb)
+{
+	int rc;
+	void __user *csb_addr;
+	struct task_struct *tsk;
+	struct coprocessor_status_block csb;
+
+	if (fault_in_csb(crb))
+		goto notify;
+
+	csb_addr = (void *)__be64_to_cpu(crb->csb_addr);
+
+	csb.cc = CSB_CC_TRANSLATION;
+	csb.ce = CSB_CE_TERMINATION;
+	csb.cs = 0;
+	csb.count = 0;
+
+	/*
+	 * Returns the fault address in CPU format since it is passed with
+	 * signal. But if the user space expects BE format, need changes.
+	 * i.e either kernel (here) or user should convert to CPU format.
+	 * Not both!
+	 */
+	csb.address = crb_nx_fault_addr(crb);
+	csb.flags = CSB_V;
+
+	rcu_read_lock();
+	tsk = find_task_by_vpid(pid);
+	if (!tsk) {
+		/*
+		 * vas_win_close() waits for any pending CRBs and pending
+		 * send window credits. In case of this fault CRB, the send
+		 * credit is not yet returned. So we should NOT end up with a
+		 * non-existent task for this fault CRB.
+		 */
+		WARN_ON_ONCE(!tsk);
+		rcu_read_unlock();
+		return;
+	}
+
+	if (tsk->flags & PF_EXITING) {
+		rcu_read_unlock();
+		return;
+	}
+
+	get_task_struct(tsk);
+	rcu_read_unlock();
+
+	use_mm(tsk->mm);
+	rc = copy_to_user(csb_addr, &csb, sizeof(csb));
+	unuse_mm(tsk->mm);
+	put_task_struct(tsk);
+
+	if (rc) {
+		pr_err("CSB: Error updating CSB address 0x%p signalling\n",
+			csb_addr);
+		goto notify;
+	}
+
+	return;
+
+notify:
+	notify_process(pid, crb_nx_fault_addr(crb));
+}
+
+/*
  * Process CRBs that we receive on the fault window.
  */
 static void process_fault_crbs(struct vas_instance *vinst)
@@ -116,6 +230,7 @@  static void process_fault_crbs(struct vas_instance *vinst)
 			return;
 		}
 
+		update_csb(vas_window_pid(window), crb);
 	} while (true);
 }
 
diff --git a/arch/powerpc/platforms/powernv/vas.h b/arch/powerpc/platforms/powernv/vas.h
index eb929c7..be1aefa 100644
--- a/arch/powerpc/platforms/powernv/vas.h
+++ b/arch/powerpc/platforms/powernv/vas.h
@@ -424,6 +424,11 @@  struct vas_winctx {
 extern struct vas_window *vas_pswid_to_window(struct vas_instance *vinst,
 						uint32_t pswid);
 
+static inline int vas_window_pid(struct vas_window *window)
+{
+	return window->pid;
+}
+
 static inline void vas_log_write(struct vas_window *win, char *name,
 			void *regptr, u64 val)
 {