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

Change-Id: I3e09c0c3d47483bc645f02310380ecb7fc6f4041
diff --git a/ap/os/linux/linux-3.4.x/ipc/Makefile b/ap/os/linux/linux-3.4.x/ipc/Makefile
index 9075e17..bb1c60c 100644
--- a/ap/os/linux/linux-3.4.x/ipc/Makefile
+++ b/ap/os/linux/linux-3.4.x/ipc/Makefile
@@ -9,4 +9,5 @@
 obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
 obj-$(CONFIG_IPC_NS) += namespace.o
 obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o
-
+obj-$(CONFIG_SYSVIPC_CROSSMSG) += cross_msg.o
+obj-$(CONFIG_SYSVIPC_CROSS_SHM) += shm_ctrl.o
diff --git a/ap/os/linux/linux-3.4.x/ipc/cross_msg.c b/ap/os/linux/linux-3.4.x/ipc/cross_msg.c
new file mode 100755
index 0000000..c5491bc
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/ipc/cross_msg.c
@@ -0,0 +1,142 @@
+/*
+ * linux/ipc/cross_msg.c
+ * Copyright (C) 2023 Sanechips Technology Co., Ltd.
+ */
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+
+#include "cross_msg.h"
+
+extern int msg_chn_ready;
+extern struct mutex cross_msg_mutex;
+
+extern int sys_msgget(key_t key, int msgflg);
+extern long do_kmsgsnd(int msqid, struct msgbuf* msgp, size_t msgsz, int msgflg);
+
+static void msg_ap_icp_init(void)
+{
+	mutex_init(&cross_msg_mutex);
+
+	if (zDrvRpMsg_CreateChannel_Cap(CROSS_MSG_ACT, CROSS_MSG_CHN, CROSS_CHN_SIZE)) {
+		panic(CROSS_PRINT "Failed create ap->cap msg channel id %d!\n", CROSS_MSG_CHN);
+	} else {
+		printk(KERN_INFO CROSS_PRINT "create ap->cap msg channel success!\n");
+		msg_chn_ready = 1;
+	}
+	
+	if (zDrvRpMsg_CreateChannel_Cap(CROSS_MSG_ACT, CROSS_MSG_CHN_CAP, CROSS_CHN_SIZE)) {
+		panic(CROSS_PRINT "Failed create cap->ap msg channel id %d\n", CROSS_MSG_CHN_CAP);
+	} else {
+		printk(KERN_INFO CROSS_PRINT "create cap->ap msg channel success!\n");
+	}
+}
+
+void cross_msg_recv()
+{
+	T_sc_msg_header *msgheader = NULL;
+	long *typeheader = NULL;
+	char *textheader = NULL;
+	T_ZDrvRpMsg_Msg Icp_Msg;
+	int ret;
+	int msqid, alen;
+	
+	msgheader = (T_sc_msg_header *)kmalloc(CROSS_MSG_SIZE, GFP_KERNEL);
+	if (!msgheader) {
+		panic(CROSS_PRINT "Failed malloc send msgheader!\n");
+	}
+
+	while (1)
+	{
+		memset(msgheader, 0, sizeof(T_sc_msg_header));
+		Icp_Msg.actorID	= CROSS_MSG_ACT;
+		Icp_Msg.chID	= CROSS_MSG_CHN_CAP;
+		Icp_Msg.buf		= msgheader; 
+		Icp_Msg.len		= CROSS_MSG_SIZE;
+		Icp_Msg.flag	= 0;
+		ret = zDrvRpMsg_Read_Cap(&Icp_Msg);
+#if CROSS_DEBUG 
+		printk(KERN_INFO CROSS_PRINT "cross message rpmsg recv header %x ops %x\n", msgheader->head, msgheader->ops);
+#endif
+		if(ret < 0) {
+			printk(KERN_ERR CROSS_PRINT "read rmpsg from cap error:(%d)\n", ret);
+			continue;
+		}
+		if (msgheader->head != CROSS_MSG_HEAD)
+		{
+			printk(KERN_ERR CROSS_PRINT "read rmpsg content error\n");
+			continue;
+		}
+		switch (msgheader->ops) {
+			case MSGGET_F: {
+				break;
+			}
+			case MSGCTL_F: {
+				break;
+			}
+			case MSGSND_F: {
+				typeheader = (long *)(msgheader + 1);
+				textheader = (char *)(typeheader + 1);
+#if CROSS_DEBUG 
+				printk(KERN_INFO CROSS_PRINT "cross message msgget key:(%d) flag:(%d)\n", msgheader->sndp.getp.key, msgheader->sndp.getp.msgflg);
+#endif
+				msqid = sys_msgget(msgheader->sndp.getp.key, msgheader->sndp.getp.msgflg);
+				if (msqid < 0) {
+					printk(KERN_ERR CROSS_PRINT "msgget error:(%d)\n", msqid);
+					ret = msqid;
+					goto ack;
+				}
+#if CROSS_DEBUG 
+				printk(KERN_INFO CROSS_PRINT "cross message msgsnd text:(%s) msgtyp:(%d)\n", textheader, *typeheader);
+				printk(KERN_INFO CROSS_PRINT "cross message msgsnd msgflg: %x, msgsz:(%d)\n", msgheader->sndp.msgflg, msgheader->sndp.msgsz);
+#endif
+				ret = do_kmsgsnd(msqid, typeheader, msgheader->sndp.msgsz, msgheader->sndp.msgflg);
+				if (ret < 0) {
+					printk(KERN_ERR CROSS_PRINT "msgsnd error:(%d)\n", ret);
+					goto ack;
+				}
+#if CROSS_DEBUG 
+				printk(KERN_INFO CROSS_PRINT "cross message msgsnd ret:(%d)\n", ret);
+#endif
+ack:		 
+				msgheader->head	= CROSS_MSG_HEAD;
+				msgheader->ret	= ret;
+				Icp_Msg.actorID	= CROSS_MSG_ACT;
+				Icp_Msg.chID	= CROSS_MSG_CHN_CAP;
+				Icp_Msg.flag	= RPMSG_WRITE_INT;
+				Icp_Msg.buf		= msgheader;
+				Icp_Msg.len		= sizeof(T_sc_msg_header);
+				ret = zDrvRpMsg_Write_Cap(&Icp_Msg);
+				if (ret < 0)
+					printk(KERN_INFO CROSS_PRINT "write rpmsg to cap error:(%d)\n", ret);
+				break;
+			}
+			case MSGRCV_F: {
+				break;
+			}
+			default: {
+				printk(KERN_INFO CROSS_PRINT "cross message msg options unknow:(%d)\n", ret);
+				break;
+			}
+		}
+	}
+	
+}
+
+void __init cross_msg_init(void)
+{
+	struct task_struct *recv_msg_thread; 
+	msg_ap_icp_init();
+	
+	printk(KERN_INFO CROSS_PRINT "cross message init");
+	recv_msg_thread = kthread_run(cross_msg_recv, NULL, "cross_msg_recv");
+	if (IS_ERR(recv_msg_thread)) {
+		panic("create recv_msg_thread err");
+	}
+	else {
+		wake_up_process(recv_msg_thread);	  
+	}
+}
+late_initcall(cross_msg_init);
+
diff --git a/ap/os/linux/linux-3.4.x/ipc/cross_msg.h b/ap/os/linux/linux-3.4.x/ipc/cross_msg.h
new file mode 100755
index 0000000..eedcd6f
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/ipc/cross_msg.h
@@ -0,0 +1,62 @@
+/*
+ * linux/ipc/cross_msg.h
+ * Copyright (C) 2023 Sanechips Technology Co., Ltd.
+ */
+#ifndef _CROSS_MSG_H
+#define _CROSS_MSG_H
+
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+#include <linux/soc/zte/rpm/rpmsg.h>
+
+#define CROSS_MSG_ACT		CAP_ID
+#define CROSS_MSG_CHN		13
+#define CROSS_MSG_CHN_CAP	14
+#define CROSS_MSG_SIZE		((size_t)0x1000)
+#define CROSS_MSG_NUM		(4)
+#define CROSS_CHN_SIZE		((size_t)CROSS_MSG_SIZE * CROSS_MSG_NUM)
+#define CROSS_PRINT			"[MESSAGE QUEUE] "
+#define CROSS_DEBUG			0
+
+#define CROSS_MSG_HEAD		0xABBA
+#define CROSS_MSG_MASK		0xFFFF0000
+#define CROSS_REMOTE_MASK	0x80000000
+
+enum msg_function {
+	MSGGET_F = 0xAA,
+	MSGCTL_F = 0xBB,
+	MSGSND_F = 0xCC,
+	MSGRCV_F = 0xDD
+};
+
+struct msgget_para {
+	key_t key;
+	int msgflg;
+};
+
+struct msgctl_para {
+	struct msgget_para getp;
+	int cmd;
+};
+
+struct msgsnd_para {
+	struct msgget_para getp;
+	int msgflg;
+	size_t msgsz;
+};
+
+typedef struct msg_para {
+	unsigned short head;
+	unsigned short ops;
+	union {
+		struct msgctl_para ctlp;
+		struct msgsnd_para sndp;
+		struct {
+			int ret;
+			int merrno;
+		};
+	};
+} T_sc_msg_header;
+
+#endif
+#endif // _CROSS_MSG_H
+
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);
 }
 
diff --git a/ap/os/linux/linux-3.4.x/ipc/msgutil.c b/ap/os/linux/linux-3.4.x/ipc/msgutil.c
old mode 100644
new mode 100755
index 52be05a..e384793
--- a/ap/os/linux/linux-3.4.x/ipc/msgutil.c
+++ b/ap/os/linux/linux-3.4.x/ipc/msgutil.c
@@ -42,6 +42,61 @@
 #define DATALEN_MSG	((size_t)PAGE_SIZE-sizeof(struct msg_msg))
 #define DATALEN_SEG	((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
 
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+struct msg_msg *load_kmsg(const void *src, size_t len)
+{
+	struct msg_msg *msg;
+	struct msg_msgseg **pseg;
+	int err;
+	size_t alen;
+
+	alen = len;
+	if (alen > DATALEN_MSG)
+		alen = DATALEN_MSG;
+
+	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
+	if (msg == NULL)
+		return ERR_PTR(-ENOMEM);
+
+	msg->next = NULL;
+	msg->security = NULL;
+
+	memcpy(msg + 1, src, alen);
+
+	len -= alen;
+	src = ((char *)src) + alen;
+	pseg = &msg->next;
+	while (len > 0) {
+		struct msg_msgseg *seg;
+		alen = len;
+		if (alen > DATALEN_SEG)
+			alen = DATALEN_SEG;
+		seg = kmalloc(sizeof(*seg) + alen,
+						 GFP_KERNEL);
+		if (seg == NULL) {
+			err = -ENOMEM;
+			goto out_err;
+		}
+		*pseg = seg;
+		seg->next = NULL;
+		memcpy(seg + 1, src, alen);
+		pseg = &seg->next;
+		len -= alen;
+		src = ((char *)src) + alen;
+	}
+
+	err = security_msg_msg_alloc(msg);
+	if (err)
+		goto out_err;
+
+	return msg;
+
+out_err:
+	free_msg(msg);
+	return ERR_PTR(err);
+}
+#endif
+
 struct msg_msg *load_msg(const void __user *src, size_t len)
 {
 	struct msg_msg *msg;
diff --git a/ap/os/linux/linux-3.4.x/ipc/shm.c b/ap/os/linux/linux-3.4.x/ipc/shm.c
index 054c4e0..47d3255 100755
--- a/ap/os/linux/linux-3.4.x/ipc/shm.c
+++ b/ap/os/linux/linux-3.4.x/ipc/shm.c
@@ -43,6 +43,9 @@
 #include <asm/uaccess.h>
 
 #include "util.h"
+#ifdef CONFIG_SYSVIPC_CROSS_SHM
+#include "shm_ctrl.h"
+#endif
 
 struct shm_file_data {
 	int id;
@@ -69,6 +72,11 @@
 static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
 #endif
 
+#ifdef CONFIG_SYSVIPC_CROSS_SHM
+extern int shm_remote_free_pages(struct vm_area_struct *unmap_vma);
+extern int shm_do_remote_map_vma(struct vm_area_struct *vma, key_t key);
+#endif
+
 void shm_init_ns(struct ipc_namespace *ns)
 {
 	ns->shm_ctlmax = SHMMAX;
@@ -141,6 +149,24 @@
 	return container_of(ipcp, struct shmid_kernel, shm_perm);
 }
 
+#ifdef CONFIG_SYSVIPC_CROSS_SHM
+void shm_mmap_pagetable(struct vm_area_struct *vma, struct file *file)
+{
+	int ret = 0;
+	struct shm_file_data *sfd;
+	struct shmid_kernel  *shp;
+
+	sfd = shm_file_data(file);
+	shp = shm_lock(sfd->ns, sfd->id);
+
+	ret = shm_do_remote_map_vma(vma, shp->shm_perm.key);
+	if (ret < 0)
+		printk("shm_mmap_pagetable Error");
+
+	shm_unlock(shp);
+}
+#endif
+
 static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
 {
 	rcu_read_lock();
@@ -240,6 +266,10 @@
 	shp->shm_lprid = task_tgid_vnr(current);
 	shp->shm_dtim = get_seconds();
 	shp->shm_nattch--;
+#ifdef CONFIG_SYSVIPC_CROSS_SHM
+	if (shp->shm_perm.rpmflag == TRUE)
+		shm_remote_free_pages(shp->shm_perm.key);
+#endif
 	if (shm_may_destroy(ns, shp))
 		shm_destroy(ns, shp);
 	else
@@ -517,6 +547,12 @@
 	shp->shm_nattch = 0;
 	shp->shm_file = file;
 	shp->shm_creator = current;
+#ifdef CONFIG_SYSVIPC_CROSS_SHM
+	if((key & SHM_REMOTE_ATTR_MASK) == SHM_REMOTE_ATTR_MASK)
+		shp->shm_perm.rpmflag = TRUE;
+	else
+		shp->shm_perm.rpmflag = FALSE;
+#endif
 	/*
 	 * shmid gets reported as "inode#" in /proc/pid/maps.
 	 * proc-ps tools use this. Changing this will break them.
@@ -1049,7 +1085,10 @@
 	sfd->ns = get_ipc_ns(ns);
 	sfd->file = shp->shm_file;
 	sfd->vm_ops = NULL;
-
+#ifdef CONFIG_SYSVIPC_CROSS_SHM	
+	if(shp->shm_perm.rpmflag == TRUE)
+		file->f_flags = SHM_REMOTE_ATTR_YES;
+#endif
 	down_write(&current->mm->mmap_sem);
 	if (addr && !(shmflg & SHM_REMAP)) {
 		err = -EINVAL;
diff --git a/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.c b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.c
new file mode 100755
index 0000000..598cb28
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.c
@@ -0,0 +1,504 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/ipc/shm_ctrl.c
+ * Copyright (C) 1992, 1993 Krishna Balasubramanian
+ * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
+ * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
+ *
+ * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
+ * Make shmmax, shmall, shmmni sysctl'able, Christoph Rohland <cr@sap.com>
+ * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
+ *
+ * Better ipc lock (kern_ipc_perm.lock) handling
+ * Davidlohr Bueso <davidlohr.bueso@hp.com>, June 2013.
+ */
+#include <linux/mm.h>
+#include <asm/pgtable.h>
+#include "shm_ctrl.h"
+#include "../mm/internal.h"
+
+/**
+ * ºê¶¨Òå
+ */
+#define SHM_UNIT_BUFF_ORDER       (12)
+#define SHM_KEYS_STATUS_LEN       (4*1024)
+#define SHM_REMOTE_BUFF_LEN       (128*1024)
+#define SHM_BUFF_BASE_PHY_ADDR    (g_shm_phyAddr)
+ 
+#define SHM_UNIT_BUFF_SIZE        (1UL<<SHM_UNIT_BUFF_ORDER) /*4KB*/
+#define SHM_UNIT_INDEX(addr)      (((unsigned long)addr - SHM_BUFF_BASE_PHY_ADDR) >> SHM_UNIT_BUFF_ORDER)
+#define SHM_UNIT_PAGE_ADDR(index) ((void *)(SHM_BUFF_BASE_PHY_ADDR + ((unsigned long)index << SHM_UNIT_BUFF_ORDER))) 
+#define SHM_UNIT_NUM_BITS         (SHM_REMOTE_BUFF_LEN >> SHM_UNIT_BUFF_ORDER)
+#define SHM_CTRL_BITMAP_NUM       (SHM_UNIT_NUM_BITS / SHM_CTRL_LONG_32BIT)
+
+struct shm_key_node {
+    key_t         key;
+    unsigned int  vma_count;
+    DECLARE_BITMAP(shm_inuse_index, SHM_UNIT_NUM_BITS);
+};
+
+struct shm_entity {
+    DECLARE_BITMAP(shm_regions_bitmap, SHM_UNIT_NUM_BITS);/*×ÜÄÚ´æ³Ø¹ÜÀíÐÅÏ¢*/
+    struct shm_key_node keys_info_head[SHM_UNIT_NUM_BITS]; /*ÿ¸öshmµÄkey¹ÜÀíÐÅÏ¢*/
+};
+
+/**
+ * È«¾Ö±äÁ¿¶¨Òå
+ */
+phys_addr_t   g_shm_phyAddr = 0;
+void         *g_shm_region = NULL;
+
+struct shm_entity *shm_remote_manager;
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_quary_keyArray
+* ²ÎÊý˵Ã÷:
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for search a special key in array
+*******************************************************************************/
+static int shm_quary_keyArray(const key_t key)
+{
+    unsigned int          index     = 0;
+    struct   shm_key_node *shm_data = NULL;
+
+    shm_data = shm_remote_manager->keys_info_head;
+    
+    for (; index < SHM_UNIT_NUM_BITS; index++)
+    {
+        if (shm_data[index].key == key)
+            return index;
+    }
+    return SHM_CTRL_ERROR;    
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_ctrl_pte_range
+* ²ÎÊý˵Ã÷:
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for clear the pagetable pte 
+*******************************************************************************/
+unsigned long shm_ctrl_pte_range(struct mm_struct *mm,
+                struct vm_area_struct *vma, pmd_t *pmd,
+                unsigned long addr, unsigned long end)
+{
+    spinlock_t *ptl;
+    pte_t *start_pte;
+    pte_t *pte;
+
+    start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+    pte = start_pte;
+    arch_enter_lazy_mmu_mode();
+    do {
+        pte_t ptent = *pte;
+        if (pte_none(ptent)) {
+            continue;
+        }
+
+        if (pte_present(ptent)) {
+            
+            ptent = ptep_get_and_clear(mm, addr, pte);
+        }
+        pte_clear_not_present_full(mm, addr, pte, 0);
+    } while (pte++, addr += PAGE_SIZE, addr != end);
+
+    arch_leave_lazy_mmu_mode();
+    pte_unmap_unlock(start_pte, ptl);
+
+    return addr;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_ctrl_pmd_range
+* ²ÎÊý˵Ã÷:
+*    (´«Èë²ÎÊý)    mm: ÈÎÎñµÄÄÚ´æÃèÊö·û
+*    (´«Èë²ÎÊý)    vma£º¿çºË¹²ÏíÄÚ´æ½ø³ÌµØÖ·¿Õ¼ävma
+*    (´«Èë²ÎÊý)    pud£ºpudÒ³ÉϲãĿ¼
+*    (´«Èë²ÎÊý)    addr: ÐéÄâÆðʼµØÖ·
+*    (´«Èë²ÎÊý)    end:  ÐéÄâ½áÊøµØÖ·
+*    (´«³ö²ÎÊý)    ¿Õ
+* ·µ »Ø Öµ:     addr
+* ÆäËü˵Ã÷:     This function is used for clear the pagetable pte 
+*******************************************************************************/
+static inline unsigned long shm_ctrl_pmd_range(struct mm_struct *mm,
+                struct vm_area_struct *vma, pud_t *pud,
+                unsigned long addr, unsigned long end)
+{
+    pmd_t *pmd;
+    unsigned long next;
+
+    pmd = pmd_offset(pud, addr);
+    do {
+        next = pmd_addr_end(addr, end);
+        /*
+         * Here there can be other concurrent MADV_DONTNEED or
+         * trans huge page faults running, and if the pmd is
+         * none or trans huge it can change under us. This is
+         * because MADV_DONTNEED holds the mmap_sem in read
+         * mode.
+         */
+        if (pmd_none_or_trans_huge_or_clear_bad(pmd))
+            goto next;
+        next = shm_ctrl_pte_range(mm, vma, pmd, addr, next);
+next:
+        cond_resched();
+    } while (pmd++, addr = next, addr != end);
+
+    return addr;
+}
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_ctrl_pud_range
+* ²ÎÊý˵Ã÷:
+*    (´«Èë²ÎÊý)    mm:  ÈÎÎñµÄÄÚ´æÃèÊö·û
+*    (´«Èë²ÎÊý)    vma: ¿çºË¹²ÏíÄÚ´æ½ø³ÌµØÖ·¿Õ¼ävma
+*    (´«Èë²ÎÊý)    pgd: pgdҳĿ¼Ïî
+*    (´«Èë²ÎÊý)    addr: ÐéÄâÆðʼµØÖ·
+*    (´«Èë²ÎÊý)    end:  ÐéÄâ½áÊøµØÖ·
+*    (´«³ö²ÎÊý)    ÎÞ
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for find pud
+*******************************************************************************/
+static inline unsigned long shm_ctrl_pud_range(struct mm_struct *mm, 
+                                                struct vm_area_struct *vma, pgd_t *pgd,
+                                                unsigned long addr, unsigned long end)
+{
+    pud_t *pud;
+    unsigned long next;
+
+    pud = pud_offset(pgd, addr);
+    do {
+        next = pud_addr_end(addr, end);
+        if (pud_none_or_clear_bad(pud))
+            continue;
+        next = shm_ctrl_pmd_range(mm, vma, pud, addr, next);
+    } while (pud++, addr = next, addr != end);
+
+    return addr;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_unmap_page_range
+* ²ÎÊý˵Ã÷:
+*    (´«Èë²ÎÊý)    mm: ÈÎÎñµÄÄÚ´æÃèÊö·û
+*    (´«Èë²ÎÊý)    vma ¿çºË¹²ÏíÄÚ´æ½ø³ÌµØÖ·¿Õ¼ävma 
+*    (´«Èë²ÎÊý)    addr ÐéÄâÆðʼµØÖ·
+*    (´«Èë²ÎÊý)    end  ÐéÄâ½áÊøµØÖ·
+*    (´«³ö²ÎÊý)    ¿Õ
+* ·µ »Ø Öµ:     void
+* ÆäËü˵Ã÷:     This function is used for unmap the shm memory
+*******************************************************************************/
+void shm_unmap_page_range(struct mm_struct *mm, struct vm_area_struct *vma,
+                 unsigned long addr, unsigned long end)
+{
+    pgd_t *pgd;
+    unsigned long next;
+
+    BUG_ON(addr >= end);
+    pgd = pgd_offset(vma->vm_mm, addr);
+    do {
+        next = pgd_addr_end(addr, end);
+        if (pgd_none_or_clear_bad(pgd))
+            continue;
+        next = shm_ctrl_pud_range(mm, vma, pgd, addr, next);
+    } while (pgd++, addr = next, addr != end);
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_vma_write_pagetable
+* ²ÎÊý˵Ã÷:     
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void 
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for create pagetable for shm mem region                          
+*******************************************************************************/
+static int shm_vma_write_pagetable(struct vm_area_struct *vma, unsigned long vm_addr,
+            phys_addr_t shmaddr_phy)
+{
+    pte_t  *pte;
+    int    retval  = 0;
+    pte_t  pte_val = 0;
+    spinlock_t *ptl;
+
+    if (vm_addr < vma->vm_start || vm_addr >= vma->vm_end)
+        return -EFAULT;
+
+    pte = get_locked_pte(vma->vm_mm, vm_addr, &ptl);
+    if ((!pte) || (!pte_none(*pte)))
+        return -EFAULT;
+
+    pte_val = __pte((phys_addr_t)(shmaddr_phy) | pgprot_val(vma->vm_page_prot));
+
+    set_pte_at(vma->vm_mm, vm_addr, pte, pte_val);
+    pte_unmap_unlock(pte, ptl);
+
+    return retval;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_fill_keytable
+* ²ÎÊý˵Ã÷:     
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void 
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for record the key and index relation                         
+*******************************************************************************/
+int shm_fill_keytable(struct shm_key_node  *keydata)
+{
+    unsigned int  key_index = 0;
+
+    if (keydata == NULL)
+        return SHM_CTRL_ERROR;
+
+    for(; key_index < SHM_UNIT_NUM_BITS; key_index++)
+    {
+        if(shm_remote_manager->keys_info_head[key_index].key == 0)
+        {
+            memcpy(&shm_remote_manager->keys_info_head[key_index], keydata, sizeof(struct shm_key_node));
+            return SHM_CTRL_OK;
+        }
+    }
+    return SHM_CTRL_ERROR;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_remove_keynode
+* ²ÎÊý˵Ã÷:     
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void 
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for remove the key and index relation                         
+*******************************************************************************/
+static void shm_remove_keynode(unsigned int key_index)
+{
+    memset(&shm_remote_manager->keys_info_head[key_index], 0, sizeof(struct shm_key_node));
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_alloc_new_page
+* ²ÎÊý˵Ã÷:     
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void 
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for  alloc page from shm mem region                          
+*******************************************************************************/
+int shm_alloc_new_page(struct vm_area_struct *vma,  key_t key)
+{
+    unsigned long        vm_addr      = 0;
+    unsigned int         region_index = 0;
+    void                 *new_page    = NULL;
+    struct shm_key_node  new_key      = {0};
+
+    if((vma == NULL) || (g_shm_region == NULL))
+    {
+        printk("Shm region is not ready\n");
+        return SHM_CTRL_ERROR;
+    }
+
+    vm_addr = vma->vm_start;
+    
+    for (; vm_addr < vma->vm_end; vm_addr += PAGE_SIZE)
+    {
+        region_index = find_first_zero_bit(shm_remote_manager->shm_regions_bitmap, SHM_UNIT_NUM_BITS);
+
+        if (region_index < SHM_UNIT_NUM_BITS) 
+        {
+            set_bit(region_index, shm_remote_manager->shm_regions_bitmap);    
+            new_page = SHM_UNIT_PAGE_ADDR(region_index);
+            
+            if (shm_vma_write_pagetable(vma, vm_addr, new_page))
+            {
+                return SHM_CTRL_ERROR;
+            }
+            set_bit(region_index, new_key.shm_inuse_index);
+        }
+        else
+        {
+            return SHM_CTRL_ERROR;
+        }
+    }
+
+    if (!bitmap_empty(new_key.shm_inuse_index, SHM_UNIT_NUM_BITS))
+    {
+        new_key.key = key;    
+        new_key.vma_count++;
+        shm_fill_keytable(&new_key);
+    }
+    return SHM_CTRL_OK;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_do_remote_map_vma
+* ²ÎÊý˵Ã÷:     
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for 
+*                   
+/*²éѯkey,Èç¹ûÒÑ·ÖÅä¹ýʹÓÃkey¶ÔÓ¦µÄbitmap, ·ñÔò´Ó×ÜÄÚ´æ³Ø·ÖÅä           
+*******************************************************************************/
+int shm_do_remote_map_vma(struct vm_area_struct *vma,  key_t key)
+{
+    int                   ret           = 0;
+    unsigned long         vm_addr       = 0;
+    unsigned int          region_index  = 0;
+    int                   key_index     = 0;
+    void                  *new_page_phy = NULL;
+    struct   shm_key_node *key_node     = NULL;
+    DECLARE_BITMAP(shm_inuse_tmp, SHM_UNIT_NUM_BITS);
+
+    if((vma == NULL) || (g_shm_region == NULL))
+    {
+        printk("shm_do_remote_map_vma:Shm region is not ready\n");
+        return SHM_CTRL_ERROR;
+    }
+
+    /*Ó³ÉävmaΪ·ÇcacheÊôÐÔ*/
+    pgprot_noncached(vma->vm_page_prot);
+
+    soft_spin_lock(SHM_SFLOCK);
+
+    key_index = shm_quary_keyArray(key);
+    
+    if (key_index < 0) 
+    {
+        ret = shm_alloc_new_page(vma, key);
+        soft_spin_unlock(SHM_SFLOCK);    
+        if (ret < 0)
+            panic("shm_alloc_new_page Fail\n");
+        return ret;
+    }
+
+    vm_addr = vma->vm_start;
+    
+    if ((0 <= key_index) && (key_index < SHM_UNIT_NUM_BITS))
+        key_node = &shm_remote_manager->keys_info_head[key_index];
+    else
+        panic("key_index out of range: failed\n");
+
+    memcpy(shm_inuse_tmp, key_node->shm_inuse_index, sizeof(shm_inuse_tmp));
+
+    for (; vm_addr < vma->vm_end; vm_addr += PAGE_SIZE)
+    {    
+        region_index = find_first_bit(shm_inuse_tmp, SHM_UNIT_NUM_BITS);
+        if (region_index < SHM_UNIT_NUM_BITS) 
+        {
+            new_page_phy = SHM_UNIT_PAGE_ADDR(region_index);
+            if (shm_vma_write_pagetable(vma, vm_addr, new_page_phy))
+            {
+                soft_spin_unlock(SHM_SFLOCK);
+                panic("shm_do_remote_map_vma vm_insert_page failed\n");
+                return SHM_CTRL_ERROR;
+            }
+            clear_bit(region_index, shm_inuse_tmp);    
+        }
+        else
+        {
+            return SHM_CTRL_ERROR;
+        }
+    }
+    key_node->vma_count++;
+
+    soft_spin_unlock(SHM_SFLOCK);
+    return SHM_CTRL_OK;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_remote_free_pages
+* ²ÎÊý˵Ã÷:     
+*    (´«Èë²ÎÊý)    void
+*    (´«³ö²ÎÊý)    void
+* ·µ »Ø Öµ:     SHM_CTRL_OK or SHM_CTRL_ERROR
+* ÆäËü˵Ã÷:     This function is used for 
+*******************************************************************************/
+int shm_remote_free_pages(key_t key)
+{
+    int                  key_index = 0;
+    unsigned int         region_index = 0;
+    struct  shm_key_node *key_node = NULL;
+    
+    if(g_shm_region == NULL)
+    {
+        printk("shm_remote_free_pages: Shm region is not ready\n");
+        return SHM_CTRL_ERROR;
+    }
+
+    soft_spin_lock(SHM_SFLOCK);
+
+    /*²éѯkey*/
+    key_index = shm_quary_keyArray(key);
+    if(key_index < 0 || key_index >= SHM_UNIT_NUM_BITS) 
+    {
+        soft_spin_unlock(SHM_SFLOCK);
+        panic("error\n");
+    }
+
+    /*ÊôÓÚ¿çºËµÄ¾ÍÊͷŵ½³Ø×ÓÀï*/
+    key_node = &shm_remote_manager->keys_info_head[key_index];
+
+    key_node->vma_count--;
+
+    if(key_node->vma_count == 0)
+    {
+        for_each_set_bit(region_index, key_node->shm_inuse_index, SHM_UNIT_NUM_BITS)
+        {
+            clear_bit(region_index, shm_remote_manager->shm_regions_bitmap);        
+        }
+        shm_remove_keynode(key_index);
+    }
+    soft_spin_unlock(SHM_SFLOCK);
+    return SHM_CTRL_OK;
+}
+
+/*******************************************************************************
+* ¹¦ÄÜÃèÊö:     shm_rpcore_init
+* ²ÎÊý˵Ã÷:
+*   (´«Èë²ÎÊý)  void
+*   (´«³ö²ÎÊý)  void
+* ·µ »Ø Öµ:
+* ÆäËü˵Ã÷:     This function is used for shm ctrl init
+*******************************************************************************/
+static int __init shm_rpcore_init(void)
+{    
+    dma_addr_t           dma_phys;
+    dma_addr_t           shm_keyInfo_phys;
+    struct shm_pool_msg  shm_msg = {0};
+     
+    g_shm_region = dma_alloc_coherent(NULL,
+                                      (size_t)SHM_REMOTE_BUFF_LEN,
+                                      &dma_phys,
+                                      GFP_KERNEL);
+    if(!g_shm_region)
+    {
+        panic("g_shm_region NOMEM\n");
+    }
+
+    g_shm_phyAddr = dma_phys;
+
+    shm_remote_manager = dma_alloc_coherent(NULL,
+                                            (size_t)(SHM_KEYS_STATUS_LEN),
+                                            &shm_keyInfo_phys,
+                                            GFP_KERNEL);
+    if(!shm_remote_manager)    
+    {
+        panic("shm_remote_manager NOMEM\n");
+    }
+
+    memset(shm_remote_manager, 0, sizeof(struct shm_entity));
+    shm_msg.shm_len        = SHM_REMOTE_BUFF_LEN; 
+    shm_msg.key_manage_len = SHM_KEYS_STATUS_LEN; 
+    shm_msg.shm_memory_phy = g_shm_phyAddr; 
+    shm_msg.key_manage_phy = shm_keyInfo_phys; 
+
+    memcpy((void*)IRAM_BASE_ADDR_SHM_REMOTE_REGION, &shm_msg, sizeof(struct shm_pool_msg));
+
+    return SHM_CTRL_OK;
+
+}
+
+late_initcall(shm_rpcore_init);
+
+
+
diff --git a/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.h b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.h
new file mode 100755
index 0000000..5a850a1
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/ipc/shm_ctrl.h
@@ -0,0 +1,56 @@
+/*
+ * linux/ipc/shm_ctrl.h
+ * Copyright (C) 2023 Sanechips Technology Co., Ltd.
+ */
+#ifndef _SHM_CTRL_H
+#define _SHM_CTRL_H
+
+#ifdef CONFIG_SYSVIPC_CROSS_SHM
+/**
+ * ºê¶¨Òå
+ */
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/io.h> 
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/list.h>
+#include <linux/mman.h>
+#include <linux/shmem_fs.h>
+#include <linux/audit.h>
+#include <linux/capability.h>
+#include <linux/ptrace.h>
+#include <linux/rwsem.h>
+#include <linux/nsproxy.h>
+#include <linux/ipc_namespace.h> 
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <mach/spinlock.h>
+
+/**
+ * Êý¾ÝÀàÐͶ¨Òå
+ */
+#define TRUE   1
+#define FALSE  0
+#define SHM_REMOTE_ATTR_YES       (0x594553) /*YES ASCIIÂë*/
+#define SHM_REMOTE_ATTR_MASK      (0xFFFFF000)
+#define SHM_CTRL_OK               (0)
+#define SHM_CTRL_ERROR            (-1)
+#define SHM_CTRL_VMA_LINK_NUM     (2)
+#define SHM_CTRL_MEMSYNC_CHANNEL  (15)
+#define SHM_CTRL_CHANNEL_SIZE     (0x40)
+#define SHM_CTRL_LONG_32BIT       (32)
+
+struct shm_pool_msg
+{
+    unsigned int shm_len;
+    unsigned int key_manage_len;
+    phys_addr_t  shm_memory_phy;
+    phys_addr_t  key_manage_phy;
+};
+
+
+#endif
+#endif // _SHM_CTRL_H
+
diff --git a/ap/os/linux/linux-3.4.x/ipc/util.h b/ap/os/linux/linux-3.4.x/ipc/util.h
old mode 100644
new mode 100755
index 0bfc934..f8c1757
--- a/ap/os/linux/linux-3.4.x/ipc/util.h
+++ b/ap/os/linux/linux-3.4.x/ipc/util.h
@@ -138,6 +138,9 @@
 #endif
 
 extern void free_msg(struct msg_msg *msg);
+#ifdef CONFIG_SYSVIPC_CROSSMSG
+extern struct msg_msg *load_kmsg(const void __user *src, size_t len);
+#endif
 extern struct msg_msg *load_msg(const void __user *src, size_t len);
 extern int store_msg(void __user *dest, struct msg_msg *msg, size_t len);