[Feature][ZXW-65]merged P49 base code

Change-Id: I3e09c0c3d47483bc645f02310380ecb7fc6f4041
diff --git a/ap/os/linux/linux-3.4.x/ipc/msg.c b/ap/os/linux/linux-3.4.x/ipc/msg.c
index a1cf543..038d954 100755
--- a/ap/os/linux/linux-3.4.x/ipc/msg.c
+++ b/ap/os/linux/linux-3.4.x/ipc/msg.c
@@ -40,6 +40,11 @@
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+#include <linux/soc/zte/rpm/rpmsg.h>
+#include "cross_msg.h"
+#endif
+
 #include "util.h"
 
 /*
@@ -62,6 +67,12 @@
 	struct task_struct	*tsk;
 };
 
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+int msg_chn_ready;
+struct mutex cross_msg_mutex;
+T_sc_msg_header *msgheader = NULL;
+#endif
+
 #define SEARCH_ANY		1
 #define SEARCH_EQUAL		2
 #define SEARCH_NOTEQUAL		3
@@ -136,7 +147,7 @@
 		init_ipc_ns.msg_ctlmni);
     
 	if (IS_ENABLED(CONFIG_PROC_STRIPPED))
-		return 0;
+		return;
 
 	ipc_init_proc_interface("sysvipc/msg",
 				"       key      msqid perms      cbytes       qnum lspid lrpid   uid   gid  cuid  cgid      stime      rtime      ctime\n",
@@ -336,10 +347,63 @@
 
 	msg_params.key = key;
 	msg_params.flg = msgflg;
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+	if ((key & CROSS_MSG_MASK) == CROSS_MSG_MASK)
+		msg_params.flg |= IPC_CREAT;
+#endif
 
 	return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params);
 }
 
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+static inline unsigned long
+copy_msqid_by_version(void *buf, struct msqid64_ds *in, int version)
+{
+	switch(version) {
+	case IPC_64:
+		memcpy(buf, in, sizeof(*in));
+		return 0;
+	case IPC_OLD:
+	{
+		struct msqid_ds out;
+
+		memset(&out, 0, sizeof(out));
+
+		ipc64_perm_to_ipc_perm(&in->msg_perm, &out.msg_perm);
+
+		out.msg_stime		= in->msg_stime;
+		out.msg_rtime		= in->msg_rtime;
+		out.msg_ctime		= in->msg_ctime;
+
+		if (in->msg_cbytes > USHRT_MAX)
+			out.msg_cbytes	= USHRT_MAX;
+		else
+			out.msg_cbytes	= in->msg_cbytes;
+		out.msg_lcbytes		= in->msg_cbytes;
+
+		if (in->msg_qnum > USHRT_MAX)
+			out.msg_qnum	= USHRT_MAX;
+		else
+			out.msg_qnum	= in->msg_qnum;
+
+		if (in->msg_qbytes > USHRT_MAX)
+			out.msg_qbytes	= USHRT_MAX;
+		else
+			out.msg_qbytes	= in->msg_qbytes;
+		out.msg_lqbytes		= in->msg_qbytes;
+
+		out.msg_lspid		= in->msg_lspid;
+		out.msg_lrpid		= in->msg_lrpid;
+
+		memcpy(buf, &out, sizeof(out));
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+}
+#endif
+
 static inline unsigned long
 copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
 {
@@ -479,6 +543,67 @@
 	return err;
 }
 
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+static int get_msgstat(int msqid, int cmd, struct msqid_ds * buf)
+{
+	struct msg_queue *msq;
+	int err, version;
+	struct ipc_namespace *ns;
+
+	if (msqid < 0 || cmd < 0)
+		return -EINVAL;
+
+	version = ipc_parse_version(&cmd);
+	ns = current->nsproxy->ipc_ns;
+
+	switch (cmd) {
+	case IPC_STAT:
+	{
+		struct msqid64_ds tbuf;
+		int success_return;
+
+		if (!buf)
+			return -EFAULT;
+
+
+		msq = msg_lock_check(ns, msqid);
+		if (IS_ERR(msq))
+			return PTR_ERR(msq);
+		success_return = 0;
+		
+		err = -EACCES;
+		if (ipcperms(ns, &msq->q_perm, S_IRUGO))
+			goto out_unlock;
+
+		err = security_msg_queue_msgctl(msq, cmd);
+		if (err)
+			goto out_unlock;
+
+		memset(&tbuf, 0, sizeof(tbuf));
+
+		kernel_to_ipc64_perm(&msq->q_perm, &tbuf.msg_perm);
+		tbuf.msg_stime  = msq->q_stime;
+		tbuf.msg_rtime  = msq->q_rtime;
+		tbuf.msg_ctime  = msq->q_ctime;
+		tbuf.msg_cbytes = msq->q_cbytes;
+		tbuf.msg_qnum   = msq->q_qnum;
+		tbuf.msg_qbytes = msq->q_qbytes;
+		tbuf.msg_lspid  = msq->q_lspid;
+		tbuf.msg_lrpid  = msq->q_lrpid;
+		msg_unlock(msq);
+		copy_msqid_by_version(buf, &tbuf, version);
+		return success_return;
+	}
+	default:
+		return  -EINVAL;
+	}
+
+out_unlock:
+	msg_unlock(msq);
+	return err;
+}
+#endif
+
 SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
 {
 	struct msg_queue *msq;
@@ -744,6 +869,104 @@
 	return err;
 }
 
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+long do_kmsgsnd(int msqid, struct msgbuf* msgp, size_t msgsz, int msgflg)
+{
+	struct msg_queue *msq;
+	struct msg_msg *msg;
+	int err;
+	struct ipc_namespace *ns;
+	long mtype; 
+	char *mtext;
+
+	ns = current->nsproxy->ipc_ns;
+
+	mtype = msgp->mtype;
+	mtext = msgp->mtext;
+
+	if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
+		return -EINVAL;
+	if (mtype < 1)
+		return -EINVAL;
+
+	msg = load_kmsg(mtext, msgsz);
+	if (IS_ERR(msg))
+		return PTR_ERR(msg);
+
+	msg->m_type = mtype;
+	msg->m_ts = msgsz;
+
+	msq = msg_lock_check(ns, msqid);
+	if (IS_ERR(msq)) {
+		err = PTR_ERR(msq);
+		goto out_free;
+	}
+
+	for (;;) {
+		struct msg_sender s;
+
+		err = -EACCES;
+		if (ipcperms(ns, &msq->q_perm, S_IWUGO))
+			goto out_unlock_free;
+
+		err = security_msg_queue_msgsnd(msq, msg, msgflg);
+		if (err)
+			goto out_unlock_free;
+
+		if (msgsz + msq->q_cbytes <= msq->q_qbytes &&
+				1 + msq->q_qnum <= msq->q_qbytes) {
+			break;
+		}
+
+		/* queue full, wait: */
+		if (msgflg & IPC_NOWAIT) {
+			err = -EAGAIN;
+			goto out_unlock_free;
+		}
+		ss_add(msq, &s);
+		ipc_rcu_getref(msq);
+		msg_unlock(msq);
+		schedule();
+
+		ipc_lock_by_ptr(&msq->q_perm);
+		ipc_rcu_putref(msq);
+		if (msq->q_perm.deleted) {
+			err = -EIDRM;
+			goto out_unlock_free;
+		}
+		ss_del(&s);
+
+		if (signal_pending(current)) {
+			err = -ERESTARTNOHAND;
+			goto out_unlock_free;
+		}
+	}
+
+	msq->q_lspid = task_tgid_vnr(current);
+	msq->q_stime = get_seconds();
+
+	if (!pipelined_send(msq, msg)) {
+		/* no one is waiting for this message, enqueue it */
+		list_add_tail(&msg->m_list, &msq->q_messages);
+		msq->q_cbytes += msgsz;
+		msq->q_qnum++;
+		atomic_add(msgsz, &ns->msg_bytes);
+		atomic_inc(&ns->msg_hdrs);
+	}
+
+	err = 0;
+	msg = NULL;
+
+out_unlock_free:
+	msg_unlock(msq);
+out_free:
+	if (msg != NULL)
+		free_msg(msg);
+	return err;
+  
+}
+#endif
+
 SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
 		int, msgflg)
 {
@@ -751,6 +974,99 @@
 
 	if (get_user(mtype, &msgp->mtype))
 		return -EFAULT;
+
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+	struct msqid_ds msgque;
+	struct ipc_perm *ipcp = &msgque.msg_perm;
+	T_ZDrvRpMsg_Msg Icp_Msg;
+	T_sc_msg_header *msgrcvheader = NULL;
+	long *typeheader = NULL;
+	char *textheader = NULL;
+	int ret, key;
+	size_t alen;
+
+	ret = get_msgstat(msqid, IPC_STAT, &msgque);
+	if (ret < 0) {
+		return ret;
+	}
+	key = ipcp->key;
+	//跨核处理
+	if (msg_chn_ready && ((key & CROSS_MSG_MASK) == CROSS_MSG_MASK)) {
+#if CROSS_DEBUG 
+		printk(KERN_INFO CROSS_PRINT "msg key beyond (%x)\n", key);
+#endif
+		mutex_lock(&cross_msg_mutex);
+		alen = sizeof(T_sc_msg_header) + sizeof(long) + msgsz;
+		if (alen > CROSS_MSG_SIZE) {
+			mutex_unlock(&cross_msg_mutex);
+			return -EINVAL;
+	   }
+		if (!msgheader)
+			msgheader = (T_sc_msg_header *)kmalloc(CROSS_MSG_SIZE, GFP_KERNEL);
+		if (!msgheader) {
+			panic(CROSS_PRINT "Failed malloc send msgheader!\n");
+		}
+		memset(msgheader, 0, sizeof(T_sc_msg_header));
+		msgheader->head = CROSS_MSG_HEAD;
+		msgheader->ops = MSGSND_F;
+		msgheader->sndp.getp.key = key;
+		msgheader->sndp.getp.msgflg = ipcp->mode | IPC_CREAT;
+		msgheader->sndp.msgflg = msgflg;
+		msgheader->sndp.msgsz = msgsz;
+		typeheader = (long *)(msgheader + 1);
+		*typeheader = mtype;
+		textheader = (char *)(typeheader + 1);
+		ret = copy_from_user(textheader, msgp->mtext, alen - sizeof(T_sc_msg_header) - sizeof(long));   
+		if (ret < 0) {
+			mutex_unlock(&cross_msg_mutex);
+			return -EFAULT;
+		}
+#if CROSS_DEBUG
+		printk(KERN_INFO CROSS_PRINT "msg send text:(%s) msgtyp:(%d) msgsize:(%d)\n", textheader, *typeheader, msgsz);
+#endif
+		Icp_Msg.actorID = CROSS_MSG_ACT;
+		Icp_Msg.chID	= CROSS_MSG_CHN;
+		Icp_Msg.flag	= RPMSG_WRITE_INT;	  /* 1- means send an icp interrupt> */
+		Icp_Msg.buf	 = msgheader;
+		Icp_Msg.len	 = alen;
+
+		ret = zDrvRpMsg_Write_Cap(&Icp_Msg);
+		if(ret < 0) {
+			printk(KERN_ERR CROSS_PRINT "write rpmsg error:(%d)\n", ret);
+			mutex_unlock(&cross_msg_mutex);
+			return ret;
+		}
+		else {
+#if CROSS_DEBUG
+			printk(KERN_INFO CROSS_PRINT "write rpmsg ok:(%d)\n", ret);
+#endif
+		}      
+		Icp_Msg.actorID = CROSS_MSG_ACT;
+		Icp_Msg.chID	= CROSS_MSG_CHN;
+		Icp_Msg.flag	= 0;
+		Icp_Msg.buf	 = msgheader;
+		Icp_Msg.len	 = CROSS_MSG_SIZE;
+
+		ret = zDrvRpMsg_Read_Cap(&Icp_Msg);
+		mutex_unlock(&cross_msg_mutex);
+		if(ret < 0) {
+			printk(KERN_ERR CROSS_PRINT "read rpmsg error:(%d)\n", ret);
+			return ret;
+		}
+		else {
+#if CROSS_DEBUG
+			printk(KERN_INFO CROSS_PRINT "read rpmsg ok:(%d)\n", ret);
+#endif
+		}
+		msgrcvheader = (T_sc_msg_header *)Icp_Msg.buf;
+		ret = msgrcvheader->ret;
+#if CROSS_DEBUG 
+		printk(KERN_INFO CROSS_PRINT "msgsnd return number:(%x)\n", ret);
+#endif
+		return ret;
+	}   
+#endif
+
 	return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
 }