Linux userland API discussions
 help / color / mirror / Atom feed
* [PATCH RFC v4 net-next 02/26] net: filter: split filter.h and expose eBPF to user space
From: Alexei Starovoitov @ 2014-08-13  7:57 UTC (permalink / raw)
  To: David S. Miller
  Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
	Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
	H. Peter Anvin, Andrew Morton, Kees Cook, linux-api, netdev,
	linux-kernel
In-Reply-To: <1407916658-8731-1-git-send-email-ast@plumgrid.com>

eBPF can be used from user space.

uapi/linux/bpf.h: eBPF instruction set definition

linux/filter.h: the rest

This patch only moves macro definitions, but practically it freezes existing
eBPF instruction set, though new instructions can still be added in the future.

These eBPF definitions cannot go into uapi/linux/filter.h, since the names
may conflict with existing applications.

Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
 include/linux/filter.h    |  305 +------------------------------------------
 include/uapi/linux/Kbuild |    1 +
 include/uapi/linux/bpf.h  |  314 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 316 insertions(+), 304 deletions(-)
 create mode 100644 include/uapi/linux/bpf.h

diff --git a/include/linux/filter.h b/include/linux/filter.h
index 73a6d505e729..f04793474d16 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -9,315 +9,12 @@
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <uapi/linux/filter.h>
-
-/* Internally used and optimized filter representation with extended
- * instruction set based on top of classic BPF.
- */
-
-/* instruction classes */
-#define BPF_ALU64	0x07	/* alu mode in double word width */
-
-/* ld/ldx fields */
-#define BPF_DW		0x18	/* double word */
-#define BPF_XADD	0xc0	/* exclusive add */
-
-/* alu/jmp fields */
-#define BPF_MOV		0xb0	/* mov reg to reg */
-#define BPF_ARSH	0xc0	/* sign extending arithmetic shift right */
-
-/* change endianness of a register */
-#define BPF_END		0xd0	/* flags for endianness conversion: */
-#define BPF_TO_LE	0x00	/* convert to little-endian */
-#define BPF_TO_BE	0x08	/* convert to big-endian */
-#define BPF_FROM_LE	BPF_TO_LE
-#define BPF_FROM_BE	BPF_TO_BE
-
-#define BPF_JNE		0x50	/* jump != */
-#define BPF_JSGT	0x60	/* SGT is signed '>', GT in x86 */
-#define BPF_JSGE	0x70	/* SGE is signed '>=', GE in x86 */
-#define BPF_CALL	0x80	/* function call */
-#define BPF_EXIT	0x90	/* function return */
-
-/* Register numbers */
-enum {
-	BPF_REG_0 = 0,
-	BPF_REG_1,
-	BPF_REG_2,
-	BPF_REG_3,
-	BPF_REG_4,
-	BPF_REG_5,
-	BPF_REG_6,
-	BPF_REG_7,
-	BPF_REG_8,
-	BPF_REG_9,
-	BPF_REG_10,
-	__MAX_BPF_REG,
-};
-
-/* BPF has 10 general purpose 64-bit registers and stack frame. */
-#define MAX_BPF_REG	__MAX_BPF_REG
-
-/* ArgX, context and stack frame pointer register positions. Note,
- * Arg1, Arg2, Arg3, etc are used as argument mappings of function
- * calls in BPF_CALL instruction.
- */
-#define BPF_REG_ARG1	BPF_REG_1
-#define BPF_REG_ARG2	BPF_REG_2
-#define BPF_REG_ARG3	BPF_REG_3
-#define BPF_REG_ARG4	BPF_REG_4
-#define BPF_REG_ARG5	BPF_REG_5
-#define BPF_REG_CTX	BPF_REG_6
-#define BPF_REG_FP	BPF_REG_10
-
-/* Additional register mappings for converted user programs. */
-#define BPF_REG_A	BPF_REG_0
-#define BPF_REG_X	BPF_REG_7
-#define BPF_REG_TMP	BPF_REG_8
-
-/* BPF program can access up to 512 bytes of stack space. */
-#define MAX_BPF_STACK	512
-
-/* Helper macros for filter block array initializers. */
-
-/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
-
-#define BPF_ALU64_REG(OP, DST, SRC)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU64 | BPF_OP(OP) | BPF_X,	\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = 0,					\
-		.imm   = 0 })
-
-#define BPF_ALU32_REG(OP, DST, SRC)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU | BPF_OP(OP) | BPF_X,		\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = 0,					\
-		.imm   = 0 })
-
-/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
-
-#define BPF_ALU64_IMM(OP, DST, IMM)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU64 | BPF_OP(OP) | BPF_K,	\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-#define BPF_ALU32_IMM(OP, DST, IMM)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU | BPF_OP(OP) | BPF_K,		\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-/* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */
-
-#define BPF_ENDIAN(TYPE, DST, LEN)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU | BPF_END | BPF_SRC(TYPE),	\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = LEN })
-
-/* Short form of mov, dst_reg = src_reg */
-
-#define BPF_MOV64_REG(DST, SRC)					\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU64 | BPF_MOV | BPF_X,		\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = 0,					\
-		.imm   = 0 })
-
-#define BPF_MOV32_REG(DST, SRC)					\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU | BPF_MOV | BPF_X,		\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = 0,					\
-		.imm   = 0 })
-
-/* Short form of mov, dst_reg = imm32 */
-
-#define BPF_MOV64_IMM(DST, IMM)					\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU64 | BPF_MOV | BPF_K,		\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-#define BPF_MOV32_IMM(DST, IMM)					\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU | BPF_MOV | BPF_K,		\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-/* use two of BPF_LD_IMM64 to encode single move 64-bit insn
- * first macro to carry lower 32-bits and second for higher 32-bits
- */
-#define BPF_LD_IMM64(DST, IMM)					\
-	((struct bpf_insn) {					\
-		.code  = BPF_LD | BPF_DW | BPF_IMM,		\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-/* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
-
-#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM)			\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE),	\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-#define BPF_MOV32_RAW(TYPE, DST, SRC, IMM)			\
-	((struct bpf_insn) {					\
-		.code  = BPF_ALU | BPF_MOV | BPF_SRC(TYPE),	\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
-
-#define BPF_LD_ABS(SIZE, IMM)					\
-	((struct bpf_insn) {					\
-		.code  = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS,	\
-		.dst_reg = 0,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-/* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */
-
-#define BPF_LD_IND(SIZE, SRC, IMM)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_LD | BPF_SIZE(SIZE) | BPF_IND,	\
-		.dst_reg = 0,					\
-		.src_reg = SRC,					\
-		.off   = 0,					\
-		.imm   = IMM })
-
-/* Memory load, dst_reg = *(uint *) (src_reg + off16) */
-
-#define BPF_LDX_MEM(SIZE, DST, SRC, OFF)			\
-	((struct bpf_insn) {					\
-		.code  = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM,	\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = OFF,					\
-		.imm   = 0 })
-
-/* Memory store, *(uint *) (dst_reg + off16) = src_reg */
-
-#define BPF_STX_MEM(SIZE, DST, SRC, OFF)			\
-	((struct bpf_insn) {					\
-		.code  = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM,	\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = OFF,					\
-		.imm   = 0 })
-
-/* Memory store, *(uint *) (dst_reg + off16) = imm32 */
-
-#define BPF_ST_MEM(SIZE, DST, OFF, IMM)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM,	\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = OFF,					\
-		.imm   = IMM })
-
-/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */
-
-#define BPF_JMP_REG(OP, DST, SRC, OFF)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_JMP | BPF_OP(OP) | BPF_X,		\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = OFF,					\
-		.imm   = 0 })
-
-/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
-
-#define BPF_JMP_IMM(OP, DST, IMM, OFF)				\
-	((struct bpf_insn) {					\
-		.code  = BPF_JMP | BPF_OP(OP) | BPF_K,		\
-		.dst_reg = DST,					\
-		.src_reg = 0,					\
-		.off   = OFF,					\
-		.imm   = IMM })
-
-/* Function call */
-
-#define BPF_EMIT_CALL(FUNC)					\
-	((struct bpf_insn) {					\
-		.code  = BPF_JMP | BPF_CALL,			\
-		.dst_reg = 0,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = ((FUNC) - __bpf_call_base) })
-
-/* Raw code statement block */
-
-#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM)			\
-	((struct bpf_insn) {					\
-		.code  = CODE,					\
-		.dst_reg = DST,					\
-		.src_reg = SRC,					\
-		.off   = OFF,					\
-		.imm   = IMM })
-
-/* Program exit */
-
-#define BPF_EXIT_INSN()						\
-	((struct bpf_insn) {					\
-		.code  = BPF_JMP | BPF_EXIT,			\
-		.dst_reg = 0,					\
-		.src_reg = 0,					\
-		.off   = 0,					\
-		.imm   = 0 })
-
-#define bytes_to_bpf_size(bytes)				\
-({								\
-	int bpf_size = -EINVAL;					\
-								\
-	if (bytes == sizeof(u8))				\
-		bpf_size = BPF_B;				\
-	else if (bytes == sizeof(u16))				\
-		bpf_size = BPF_H;				\
-	else if (bytes == sizeof(u32))				\
-		bpf_size = BPF_W;				\
-	else if (bytes == sizeof(u64))				\
-		bpf_size = BPF_DW;				\
-								\
-	bpf_size;						\
-})
+#include <uapi/linux/bpf.h>
 
 /* Macro to invoke filter function. */
 #define SK_RUN_FILTER(filter, ctx) \
 	(*filter->prog->bpf_func)(ctx, filter->prog->insnsi)
 
-struct bpf_insn {
-	__u8	code;		/* opcode */
-	__u8	dst_reg:4;	/* dest register */
-	__u8	src_reg:4;	/* source register */
-	__s16	off;		/* signed offset */
-	__s32	imm;		/* signed immediate constant */
-};
-
 #ifdef CONFIG_COMPAT
 /* A struct sock_filter is architecture independent. */
 struct compat_sock_fprog {
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 24e9033f8b3f..fb3f7b675229 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -67,6 +67,7 @@ header-y += bfs_fs.h
 header-y += binfmts.h
 header-y += blkpg.h
 header-y += blktrace_api.h
+header-y += bpf.h
 header-y += bpqether.h
 header-y += bsg.h
 header-y += btrfs.h
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
new file mode 100644
index 000000000000..6f6e10875e95
--- /dev/null
+++ b/include/uapi/linux/bpf.h
@@ -0,0 +1,314 @@
+/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#ifndef _UAPI__LINUX_BPF_H__
+#define _UAPI__LINUX_BPF_H__
+
+#include <linux/types.h>
+
+/* Extended instruction set based on top of classic BPF */
+
+/* instruction classes */
+#define BPF_ALU64	0x07	/* alu mode in double word width */
+
+/* ld/ldx fields */
+#define BPF_DW		0x18	/* double word */
+#define BPF_XADD	0xc0	/* exclusive add */
+
+/* alu/jmp fields */
+#define BPF_MOV		0xb0	/* mov reg to reg */
+#define BPF_ARSH	0xc0	/* sign extending arithmetic shift right */
+
+/* change endianness of a register */
+#define BPF_END		0xd0	/* flags for endianness conversion: */
+#define BPF_TO_LE	0x00	/* convert to little-endian */
+#define BPF_TO_BE	0x08	/* convert to big-endian */
+#define BPF_FROM_LE	BPF_TO_LE
+#define BPF_FROM_BE	BPF_TO_BE
+
+#define BPF_JNE		0x50	/* jump != */
+#define BPF_JSGT	0x60	/* SGT is signed '>', GT in x86 */
+#define BPF_JSGE	0x70	/* SGE is signed '>=', GE in x86 */
+#define BPF_CALL	0x80	/* function call */
+#define BPF_EXIT	0x90	/* function return */
+
+/* Register numbers */
+enum {
+	BPF_REG_0 = 0,
+	BPF_REG_1,
+	BPF_REG_2,
+	BPF_REG_3,
+	BPF_REG_4,
+	BPF_REG_5,
+	BPF_REG_6,
+	BPF_REG_7,
+	BPF_REG_8,
+	BPF_REG_9,
+	BPF_REG_10,
+	__MAX_BPF_REG,
+};
+
+/* BPF has 10 general purpose 64-bit registers and stack frame. */
+#define MAX_BPF_REG	__MAX_BPF_REG
+
+/* ArgX, context and stack frame pointer register positions. Note,
+ * Arg1, Arg2, Arg3, etc are used as argument mappings of function
+ * calls in BPF_CALL instruction.
+ */
+#define BPF_REG_ARG1	BPF_REG_1
+#define BPF_REG_ARG2	BPF_REG_2
+#define BPF_REG_ARG3	BPF_REG_3
+#define BPF_REG_ARG4	BPF_REG_4
+#define BPF_REG_ARG5	BPF_REG_5
+#define BPF_REG_CTX	BPF_REG_6
+#define BPF_REG_FP	BPF_REG_10
+
+/* Additional register mappings for converted user programs. */
+#define BPF_REG_A	BPF_REG_0
+#define BPF_REG_X	BPF_REG_7
+#define BPF_REG_TMP	BPF_REG_8
+
+/* BPF program can access up to 512 bytes of stack space. */
+#define MAX_BPF_STACK	512
+
+/* Helper macros for filter block array initializers. */
+
+/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
+
+#define BPF_ALU64_REG(OP, DST, SRC)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_OP(OP) | BPF_X,	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+#define BPF_ALU32_REG(OP, DST, SRC)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_OP(OP) | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
+
+#define BPF_ALU64_IMM(OP, DST, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_OP(OP) | BPF_K,	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_ALU32_IMM(OP, DST, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_OP(OP) | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */
+
+#define BPF_ENDIAN(TYPE, DST, LEN)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_END | BPF_SRC(TYPE),	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = LEN })
+
+/* Short form of mov, dst_reg = src_reg */
+
+#define BPF_MOV64_REG(DST, SRC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+#define BPF_MOV32_REG(DST, SRC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_MOV | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+/* Short form of mov, dst_reg = imm32 */
+
+#define BPF_MOV64_IMM(DST, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_MOV32_IMM(DST, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_MOV | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* use two of BPF_LD_IMM64 to encode single move 64-bit insn
+ * first macro to carry lower 32-bits and second for higher 32-bits
+ */
+#define BPF_LD_IMM64(DST, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_LD | BPF_DW | BPF_IMM,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
+
+#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE),	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_MOV32_RAW(TYPE, DST, SRC, IMM)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_MOV | BPF_SRC(TYPE),	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
+
+#define BPF_LD_ABS(SIZE, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS,	\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */
+
+#define BPF_LD_IND(SIZE, SRC, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_LD | BPF_SIZE(SIZE) | BPF_IND,	\
+		.dst_reg = 0,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Memory load, dst_reg = *(uint *) (src_reg + off16) */
+
+#define BPF_LDX_MEM(SIZE, DST, SRC, OFF)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM,	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = src_reg */
+
+#define BPF_STX_MEM(SIZE, DST, SRC, OFF)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM,	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = imm32 */
+
+#define BPF_ST_MEM(SIZE, DST, OFF, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM,	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */
+
+#define BPF_JMP_REG(OP, DST, SRC, OFF)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_OP(OP) | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = 0 })
+
+/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_OP(OP) | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+/* Function call */
+
+#define BPF_EMIT_CALL(FUNC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_CALL,			\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = ((FUNC) - __bpf_call_base) })
+
+/* Raw code statement block */
+
+#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM)			\
+	((struct bpf_insn) {					\
+		.code  = CODE,					\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+/* Program exit */
+
+#define BPF_EXIT_INSN()						\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_EXIT,			\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+#define bytes_to_bpf_size(bytes)				\
+({								\
+	int bpf_size = -EINVAL;					\
+								\
+	if (bytes == sizeof(u8))				\
+		bpf_size = BPF_B;				\
+	else if (bytes == sizeof(u16))				\
+		bpf_size = BPF_H;				\
+	else if (bytes == sizeof(u32))				\
+		bpf_size = BPF_W;				\
+	else if (bytes == sizeof(u64))				\
+		bpf_size = BPF_DW;				\
+								\
+	bpf_size;						\
+})
+
+struct bpf_insn {
+	__u8	code;		/* opcode */
+	__u8	dst_reg:4;	/* dest register */
+	__u8	src_reg:4;	/* source register */
+	__s16	off;		/* signed offset */
+	__s32	imm;		/* signed immediate constant */
+};
+
+#endif /* _UAPI__LINUX_BPF_H__ */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH RFC v4 net-next 01/26] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-13  7:57 UTC (permalink / raw)
  To: David S. Miller
  Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
	Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
	H. Peter Anvin, Andrew Morton, Kees Cook, linux-api, netdev,
	linux-kernel
In-Reply-To: <1407916658-8731-1-git-send-email-ast@plumgrid.com>

add BPF_LD_IMM64 instruction to load 64-bit immediate value into register.
All previous instructions were 8-byte. This is first 16-byte instruction.
Two consecutive 'struct bpf_insn' blocks are interpreted as single instruction:
insn[0/1].code = BPF_LD | BPF_DW | BPF_IMM
insn[0/1].dst_reg = destination register
insn[0].imm = lower 32-bit
insn[1].imm = upper 32-bit

Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM
which loads 32-bit immediate value into a register.

x64 JITs it as single 'movabsq %rax, imm64'
arm64 may JIT as sequence of four 'movk x0, #imm16, lsl #shift' insn

Note that old eBPF programs are binary compatible with new interpreter.

Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
 Documentation/networking/filter.txt |    8 +++++++-
 arch/x86/net/bpf_jit_comp.c         |    9 +++++++++
 include/linux/filter.h              |   11 +++++++++++
 kernel/bpf/core.c                   |    5 +++++
 lib/test_bpf.c                      |   22 ++++++++++++++++++++++
 5 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
index c48a9704bda8..81916ab5d96f 100644
--- a/Documentation/networking/filter.txt
+++ b/Documentation/networking/filter.txt
@@ -951,7 +951,7 @@ Size modifier is one of ...
 
 Mode modifier is one of:
 
-  BPF_IMM  0x00  /* classic BPF only, reserved in eBPF */
+  BPF_IMM  0x00  /* used for 32-bit mov in classic BPF and 64-bit in eBPF */
   BPF_ABS  0x20
   BPF_IND  0x40
   BPF_MEM  0x60
@@ -995,6 +995,12 @@ BPF_XADD | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg
 Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW. Note that 1 and
 2 byte atomic increments are not supported.
 
+eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM which consists
+of two consecutive 'struct bpf_insn' 8-byte blocks and interpreted as single
+instruction that loads 64-bit immediate value into a dst_reg.
+Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM which loads
+32-bit immediate value into a register.
+
 Testing
 -------
 
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 5c8cb8043c5a..67b666aab20e 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -393,6 +393,15 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
 			EMIT1_off32(add_1reg(0xB8, dst_reg), imm32);
 			break;
 
+		case BPF_LD | BPF_IMM | BPF_DW:
+			/* movabsq %rax, imm64 */
+			EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
+			EMIT(insn->imm, 4);
+			insn++;
+			i++;
+			EMIT(insn->imm, 4);
+			break;
+
 			/* dst %= src, dst /= src, dst %= imm32, dst /= imm32 */
 		case BPF_ALU | BPF_MOD | BPF_X:
 		case BPF_ALU | BPF_DIV | BPF_X:
diff --git a/include/linux/filter.h b/include/linux/filter.h
index a5227ab8ccb1..73a6d505e729 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -161,6 +161,17 @@ enum {
 		.off   = 0,					\
 		.imm   = IMM })
 
+/* use two of BPF_LD_IMM64 to encode single move 64-bit insn
+ * first macro to carry lower 32-bits and second for higher 32-bits
+ */
+#define BPF_LD_IMM64(DST, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_LD | BPF_DW | BPF_IMM,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
 /* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
 
 #define BPF_MOV64_RAW(TYPE, DST, SRC, IMM)			\
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 7f0dbcbb34af..0434c2170f2b 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -180,6 +180,7 @@ static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
 		[BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W,
 		[BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H,
 		[BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B,
+		[BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW,
 	};
 	void *ptr;
 	int off;
@@ -239,6 +240,10 @@ select_insn:
 	ALU64_MOV_K:
 		DST = IMM;
 		CONT;
+	LD_IMM_DW:
+		DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32;
+		insn++;
+		CONT;
 	ALU64_ARSH_X:
 		(*(s64 *) &DST) >>= SRC;
 		CONT;
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 89e0345733bd..d59444262dc0 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -1697,6 +1697,28 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 1, 0 } },
 	},
+	{
+		"load 64-bit immediate",
+		.u.insns_int = {
+			BPF_LD_IMM64(R1, 0x1234), /* lower 32-bit */
+			BPF_LD_IMM64(R1, 0x5678), /* higher 32-bit */
+			BPF_MOV64_REG(R2, R1),
+			BPF_MOV64_REG(R3, R2),
+			BPF_ALU64_IMM(BPF_RSH, R2, 32),
+			BPF_ALU64_IMM(BPF_LSH, R3, 32),
+			BPF_ALU64_IMM(BPF_RSH, R3, 32),
+			BPF_ALU64_IMM(BPF_MOV, R0, 0),
+			BPF_JMP_IMM(BPF_JEQ, R2, 0x5678, 1),
+			BPF_EXIT_INSN(),
+			BPF_JMP_IMM(BPF_JEQ, R3, 0x1234, 1),
+			BPF_EXIT_INSN(),
+			BPF_ALU64_IMM(BPF_MOV, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } }
+	},
 };
 
 static struct net_device dev;
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH RFC v4 net-next 00/26] BPF syscall, maps, verifier, samples, llvm
From: Alexei Starovoitov @ 2014-08-13  7:57 UTC (permalink / raw)
  To: David S. Miller
  Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
	Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
	H. Peter Anvin, Andrew Morton, Kees Cook,
	linux-api-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Hi All,

one more RFC...

Major difference vs previous set is a new 'load 64-bit immediate' eBPF insn.
Which is first 16-byte instruction. It shows how eBPF ISA can be extended
while maintaining backward compatibility, but mainly it cleans up eBPF
program access to maps and improves run-time performance.
In V3 I've been using 'fixup' section in eBPF program to tell kernel
which instructions are accessing maps. With new instruction 'fixup' is gone
and map IDR (internal map_ids) are removed.
To understand the logic behind new insn, I need to explain two main
eBPF design constraints:
1. eBPF interpreter must be generic. It should know nothing about maps or
   any custom instructions or functions.
2. llvm compiler backend must be generic. It also should know nothing about
   maps, helper functions, sockets, tracing, etc. LLVM just takes normal C
   and compiles it for some 'fake' HW that happened to be called eBPF ISA.

patch #1 implements BPF_LD_IMM64 insn. It's just a move of 64-bit immediate
value into a register. Nothing fancy.

The reason it improved eBPF program run-time is the following:
in V3 the program used to look like:
  bpf_mov r1, const_internal_map_id
  bpf_call bpf_map_lookup
so in-kernel bpf_map_lookup() helper would do map_id->map_ptr conversion via
  map = idr_find(&bpf_map_id_idr, map_id);
For the life of the program map_id is constant and that lookup was returning
the same value, but there was no easy way to store pointer inside eBPF insn.

With new insn the programs look like:
  bpf_ld_imm64 r1, const_internal_map_ptr
  bpf_call bpf_map_lookup
and the bpf_map_lookup() helper does:
  struct bpf_map *map = (struct bpf_map *) (unsigned long) r1;
Though it's a small performance gain, every nsec counts.
Also new insn allows further optimizations in JIT compilers.

How does it help to cleanup program interface towards maps?
Obviously user space doesn't know what kernel map pointer is associated
with process-local map-FD.
So it's using pseudo BPF_LD_IMM64 instruction.
BPF_LD_IMM64 with src_reg == 0 -> generic move 64-bit immediate into dst_reg
BPF_LD_IMM64 with src_reg == BPF_PSEUDO_MAP_FD -> mov map_fd into dst_reg
Other values are reserved for now. (They will be used to implement
global variables, strings and other constants and per-cpu areas in the future)
So the programs look like:
  BPF_LD_MAP_FD(BPF_REG_1, process_local_map_fd),
  BPF_CALL(BPF_FUNC_map_lookup_elem),
eBPF verifier scans the program for such pseudo instructions, converts
process_local_map_fd -> in-kernel map pointer
and drops 'pseudo' flag of BPF_LD_IMM64 instruction.
eBPF interpreter stays generic and LLVM stays generic, since they know
nothing about pseudo instructions.
Another pseudo instruction is BPF_CALL. User space encodes one of
BPF_FUNC_xxx function ids as part of 'imm' field of the instruction
and eBPF program loader converts it to in-kernel helper function pointer.

The idea to use special instructions to access maps was suggested by Jonathan ;)
It took awhile to figure out how to do it within above two design constraints,
but the end result I think is much cleaner than what I had in V2/V3.

Another difference vs previous set is verifier split into 6 patches and
verifier testsuite is added. Beyond old checks verifier got 'tidiness' checks
to make sure all unused fields of instructions are zero.
Unfortunately classic BPF doesn't check for this. Lesson learned.

Tracing use case got some improvements as well. Now eBPF programs can be
attached to tracepoint, syscall, kprobe and C examples are more usable:
ex1_kern.c - demonstrate how programs can walk in-kernel data structures
ex2_kern.c - in-kernel event accounting and user space histograms
See patch #25

TODO:
- verifier is safe, but not secure, since it allows kernel address leaking.
  fix that before lifting root-only restriction
- allow seecomp to use eBPF
- write manpage for eBPF syscall

As always all patches are available at:

  git://git.kernel.org/pub/scm/linux/kernel/git/ast/bpf master

V3->V4:
- introduced 'load 64-bit immediate' eBPF instruction
- use BPF_LD_IMM64 in LLVM, verifier, programs
- got rid of 'fixup' section in eBPF programs
- got rid of map IDR and internal map_id
- split verifier into 6 patches and added verifier testsuite
- add verifier check for reserved instruction fields
- fixed bug in LLVM eBPF backend (it was miscompiling __builtin_expect)
- fixed race condition in htab_map_update_elem()
- tracing filters can now attach to tracepoint, syscall, kprobe events
- improved C examples 

V2->V3:
- fixed verifier register range bug and addressed other comments (Thanks Kees!)
- re-added LLVM eBPF backend
- added two examples in C
- user space ELF parser and loader example

V1->V2:
- got rid of global id, everything now FD based (Thanks Andy!)
- split type enum in verifier (as suggested by Andy and Namhyung)
- switched gpl enforcement to be kmod like (as suggested by Andy and David)
- addressed feedback from Namhyung, Chema, Joe
- added more comments to verifier
- renamed sock_filter_int -> bpf_insn
- rebased on net-next

FD approach made eBPF user interface much cleaner for sockets/seccomp/tracing
use cases. Now socket and tracing examples (patch 15 and 16) can be Ctrl-C in
the middle and kernel will auto cleanup everything including tracing filters.

----

Old V1 cover letter:

'maps' is a generic storage of different types for sharing data between kernel
and userspace. Maps are referrenced by file descriptor. Root process can create
multiple maps of different types where key/value are opaque bytes of data.
It's up to user space and eBPF program to decide what they store in the maps.

eBPF programs are similar to kernel modules. They are loaded by the user space
program and unload on closing of fd. Each program is a safe run-to-completion
set of instructions. eBPF verifier statically determines that the program
terminates and safe to execute. During verification the program takes a hold of
maps that it intends to use, so selected maps cannot be removed until program is
unloaded. The program can be attached to different events. These events can
be packets, tracepoint events and other types in the future. New event triggers
execution of the program which may store information about the event in the maps.
Beyond storing data the programs may call into in-kernel helper functions
which may, for example, dump stack, do trace_printk or other forms of live
kernel debugging. Same program can be attached to multiple events. Different
programs can access the same map:

  tracepoint  tracepoint  tracepoint    sk_buff    sk_buff
   event A     event B     event C      on eth0    on eth1
    |             |          |            |          |
    |             |          |            |          |
    --> tracing <--      tracing       socket      socket
         prog_1           prog_2       prog_3      prog_4
         |  |               |            |
      |---  -----|  |-------|           map_3
    map_1       map_2

User space (via syscall) and eBPF programs access maps concurrently.

------

Alexei Starovoitov (26):
  net: filter: add "load 64-bit immediate" eBPF instruction
  net: filter: split filter.h and expose eBPF to user space
  bpf: introduce syscall(BPF, ...) and BPF maps
  bpf: enable bpf syscall on x64
  bpf: add lookup/update/delete/iterate methods to BPF maps
  bpf: add hashtable type of BPF maps
  bpf: expand BPF syscall with program load/unload
  bpf: handle pseudo BPF_CALL insn
  bpf: verifier (add docs)
  bpf: verifier (add ability to receive verification log)
  bpf: handle pseudo BPF_LD_IMM64 insn
  bpf: verifier (add branch/goto checks)
  bpf: verifier (add verifier core)
  bpf: verifier (add state prunning optimization)
  bpf: allow eBPF programs to use maps
  net: sock: allow eBPF programs to be attached to sockets
  tracing: allow eBPF programs to be attached to events
  tracing: allow eBPF programs to be attached to kprobe/kretprobe
  samples: bpf: add mini eBPF library to manipulate maps and programs
  samples: bpf: example of stateful socket filtering
  samples: bpf: example of tracing filters with eBPF
  bpf: llvm backend
  samples: bpf: elf file loader
  samples: bpf: eBPF example in C
  samples: bpf: counting eBPF example in C
  bpf: verifier test

-- 
1.7.9.5

^ permalink raw reply

* Re: [PATCH RFC v2 net-next 10/16] bpf: add eBPF verifier
From: Alexei Starovoitov @ 2014-08-12 20:43 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
	Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Thomas Gleixner,
	H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
	Network Development,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALCETrUV+CSJzBzec7fRc6k4yDd+kCxz6Zi8zGNOQvACoKkP9A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Tue, Aug 12, 2014 at 1:10 PM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
> On Tue, Aug 12, 2014 at 1:00 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>> On Tue, Aug 12, 2014 at 12:32 PM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>>> On Thu, Jul 24, 2014 at 12:25 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>>>> On Thu, Jul 24, 2014 at 11:25 AM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>>>>> On Thu, Jul 17, 2014 at 9:20 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>>>>>> Safety of eBPF programs is statically determined by the verifier, which detects:
>>>>>> - loops
>>>>>> - out of range jumps
>>>>>> - unreachable instructions
>>>>>> - invalid instructions
>>>>>> - uninitialized register access
>>>>>> - uninitialized stack access
>>>>>> - misaligned stack access
>>>>>> - out of range stack access
>>>>>> - invalid calling convention
>>>>>
>>>>> Is there something that documents exactly what conditions an eBPF
>>>>> program must satisfy in order to be considered valid?
>>>>
>>>> I did a writeup in the past on things that verifiers checks and gave it
>>>> to internal folks to review. Guys have said that now they understand very
>>>> well how it works, but in reality it didn't help at all to write valid programs.
>>>> What worked is 'verification trace' = the instruction by instruction dump
>>>> of verifier state while it's analyzing the program.
>>>> I gave few simple examples of it in
>>>> 'Understanding eBPF verifier messages' section:
>>>> https://git.kernel.org/cgit/linux/kernel/git/ast/bpf.git/diff/Documentation/networking/filter.txt?id=b22459133b9f52d2176c8c0f8b5eb036478a40c9
>>>> Every example there is what "program must satisfy to be valid"...
>>>>
>>>> Therefore I'm addressing two things:
>>>> 1. how verifier works and what it checks for.
>>>>   that is described in 'eBPF verifier' section of the doc and
>>>>   in 200 lines of comments inside verifier.c
>>>
>>> That doc is pretty good.  I'll try to read it carefully soon.  Sorry
>>> for the huge delay here -- I've been on vacation.
>>
>> I've been sitting on v4 for few weeks, since it's a merge window.
>> So please hold on a careful review. I'll post v4 later today.
>> Mainly I've split the verifier into several patches to make it
>> easier to read.
>> Thanks!
>
> Will you be at KS / LSS / LinuxCon?

I would love to, but I didn't get an invite for KS.
I'll be at plumbers in October.

^ permalink raw reply

* Re: [PATCH RFC v2 net-next 10/16] bpf: add eBPF verifier
From: Andy Lutomirski @ 2014-08-12 20:10 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
	Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Thomas Gleixner,
	H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
	Network Development,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMEtUuz2DS8Ks0L15K0Jsj_nFjgvDh0TBwb+5pHzrdU+o6co_g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Tue, Aug 12, 2014 at 1:00 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
> On Tue, Aug 12, 2014 at 12:32 PM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>> On Thu, Jul 24, 2014 at 12:25 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>>> On Thu, Jul 24, 2014 at 11:25 AM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>>>> On Thu, Jul 17, 2014 at 9:20 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>>>>> Safety of eBPF programs is statically determined by the verifier, which detects:
>>>>> - loops
>>>>> - out of range jumps
>>>>> - unreachable instructions
>>>>> - invalid instructions
>>>>> - uninitialized register access
>>>>> - uninitialized stack access
>>>>> - misaligned stack access
>>>>> - out of range stack access
>>>>> - invalid calling convention
>>>>
>>>> Is there something that documents exactly what conditions an eBPF
>>>> program must satisfy in order to be considered valid?
>>>
>>> I did a writeup in the past on things that verifiers checks and gave it
>>> to internal folks to review. Guys have said that now they understand very
>>> well how it works, but in reality it didn't help at all to write valid programs.
>>> What worked is 'verification trace' = the instruction by instruction dump
>>> of verifier state while it's analyzing the program.
>>> I gave few simple examples of it in
>>> 'Understanding eBPF verifier messages' section:
>>> https://git.kernel.org/cgit/linux/kernel/git/ast/bpf.git/diff/Documentation/networking/filter.txt?id=b22459133b9f52d2176c8c0f8b5eb036478a40c9
>>> Every example there is what "program must satisfy to be valid"...
>>>
>>> Therefore I'm addressing two things:
>>> 1. how verifier works and what it checks for.
>>>   that is described in 'eBPF verifier' section of the doc and
>>>   in 200 lines of comments inside verifier.c
>>
>> That doc is pretty good.  I'll try to read it carefully soon.  Sorry
>> for the huge delay here -- I've been on vacation.
>
> I've been sitting on v4 for few weeks, since it's a merge window.
> So please hold on a careful review. I'll post v4 later today.
> Mainly I've split the verifier into several patches to make it
> easier to read.
> Thanks!

Will you be at KS / LSS / LinuxCon?

--Andy

-- 
Andy Lutomirski
AMA Capital Management, LLC

^ permalink raw reply

* Re: [PATCH RFC v2 net-next 10/16] bpf: add eBPF verifier
From: Alexei Starovoitov @ 2014-08-12 20:00 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
	Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Thomas Gleixner,
	H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
	Network Development,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALCETrUDb6kLH_Qp=YMm=m3P_hmEu3dfDTse=ptCsdpO9EEcAQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Tue, Aug 12, 2014 at 12:32 PM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
> On Thu, Jul 24, 2014 at 12:25 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>> On Thu, Jul 24, 2014 at 11:25 AM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>>> On Thu, Jul 17, 2014 at 9:20 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>>>> Safety of eBPF programs is statically determined by the verifier, which detects:
>>>> - loops
>>>> - out of range jumps
>>>> - unreachable instructions
>>>> - invalid instructions
>>>> - uninitialized register access
>>>> - uninitialized stack access
>>>> - misaligned stack access
>>>> - out of range stack access
>>>> - invalid calling convention
>>>
>>> Is there something that documents exactly what conditions an eBPF
>>> program must satisfy in order to be considered valid?
>>
>> I did a writeup in the past on things that verifiers checks and gave it
>> to internal folks to review. Guys have said that now they understand very
>> well how it works, but in reality it didn't help at all to write valid programs.
>> What worked is 'verification trace' = the instruction by instruction dump
>> of verifier state while it's analyzing the program.
>> I gave few simple examples of it in
>> 'Understanding eBPF verifier messages' section:
>> https://git.kernel.org/cgit/linux/kernel/git/ast/bpf.git/diff/Documentation/networking/filter.txt?id=b22459133b9f52d2176c8c0f8b5eb036478a40c9
>> Every example there is what "program must satisfy to be valid"...
>>
>> Therefore I'm addressing two things:
>> 1. how verifier works and what it checks for.
>>   that is described in 'eBPF verifier' section of the doc and
>>   in 200 lines of comments inside verifier.c
>
> That doc is pretty good.  I'll try to read it carefully soon.  Sorry
> for the huge delay here -- I've been on vacation.

I've been sitting on v4 for few weeks, since it's a merge window.
So please hold on a careful review. I'll post v4 later today.
Mainly I've split the verifier into several patches to make it
easier to read.
Thanks!

^ permalink raw reply

* Re: [PATCH RFC v2 net-next 10/16] bpf: add eBPF verifier
From: Andy Lutomirski @ 2014-08-12 19:32 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: David S. Miller, Ingo Molnar, Linus Torvalds, Steven Rostedt,
	Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Jiri Olsa, Thomas Gleixner,
	H. Peter Anvin, Andrew Morton, Kees Cook, Linux API,
	Network Development,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMEtUuygJoH+PBNksTwRHyRObCZixoTDFzmnHroErZHZLaGNbg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Thu, Jul 24, 2014 at 12:25 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
> On Thu, Jul 24, 2014 at 11:25 AM, Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org> wrote:
>> On Thu, Jul 17, 2014 at 9:20 PM, Alexei Starovoitov <ast-uqk4Ao+rVK5Wk0Htik3J/w@public.gmane.org> wrote:
>>> Safety of eBPF programs is statically determined by the verifier, which detects:
>>> - loops
>>> - out of range jumps
>>> - unreachable instructions
>>> - invalid instructions
>>> - uninitialized register access
>>> - uninitialized stack access
>>> - misaligned stack access
>>> - out of range stack access
>>> - invalid calling convention
>>
>> Is there something that documents exactly what conditions an eBPF
>> program must satisfy in order to be considered valid?
>
> I did a writeup in the past on things that verifiers checks and gave it
> to internal folks to review. Guys have said that now they understand very
> well how it works, but in reality it didn't help at all to write valid programs.
> What worked is 'verification trace' = the instruction by instruction dump
> of verifier state while it's analyzing the program.
> I gave few simple examples of it in
> 'Understanding eBPF verifier messages' section:
> https://git.kernel.org/cgit/linux/kernel/git/ast/bpf.git/diff/Documentation/networking/filter.txt?id=b22459133b9f52d2176c8c0f8b5eb036478a40c9
> Every example there is what "program must satisfy to be valid"...
>
> Therefore I'm addressing two things:
> 1. how verifier works and what it checks for.
>   that is described in 'eBPF verifier' section of the doc and
>   in 200 lines of comments inside verifier.c

That doc is pretty good.  I'll try to read it carefully soon.  Sorry
for the huge delay here -- I've been on vacation.

--Andy

> 2. how to write valid programs
>  that's more important one, since it's a key to happy users.
>  'verification trace' is the first step. I'm planning to add debug info and
>  user space tool that points out to line in C instead of assembler trace.
>  In other words to bring errors to user as early as possible during
>  compilation process.
>  This is not a concern when programs are written in assembler,
>  since the programs will be much shorter and thought through by
>  the author. However I don't think there will be too many users
>  willing to understand ebpf assembler.
>
> I suspect you're more concerned about #1 at this point whereas
> I'm concerned about #2.



-- 
Andy Lutomirski
AMA Capital Management, LLC

^ permalink raw reply

* Re: seccomp: add "seccomp" syscall
From: Kees Cook @ 2014-08-12 16:25 UTC (permalink / raw)
  To: Geert Uytterhoeven; +Cc: Linux-Arch, linux-kernel@vger.kernel.org, Linux API
In-Reply-To: <CAMuHMdWp1iWm9xLqRN0q3hV72bD8jPRLDW74Cm+Gxp3gB76asQ@mail.gmail.com>

On Mon, Aug 11, 2014 at 1:07 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> Hi Kees,
>
> v3.17 is gonna get a lot of new syscalls...

4 so far! :P

>
> On Wed, Aug 6, 2014 at 6:27 PM, Linux Kernel Mailing List
> <linux-kernel@vger.kernel.org> wrote:
>> Gitweb:     http://git.kernel.org/linus/;a=commit;h=48dc92b9fc3926844257316e75ba11eb5c742b2c
>> Commit:     48dc92b9fc3926844257316e75ba11eb5c742b2c
>> Parent:     3b23dd12846215eff4afb073366b80c0c4d7543e
>> Refname:    refs/heads/master
>> Author:     Kees Cook <keescook@chromium.org>
>> AuthorDate: Wed Jun 25 16:08:24 2014 -0700
>> Committer:  Kees Cook <keescook@chromium.org>
>> CommitDate: Fri Jul 18 12:13:37 2014 -0700
>>
>>     seccomp: add "seccomp" syscall
>>
>>     This adds the new "seccomp" syscall with both an "operation" and "flags"
>>     parameter for future expansion. The third argument is a pointer value,
>>     used with the SECCOMP_SET_MODE_FILTER operation. Currently, flags must
>>     be 0. This is functionally equivalent to prctl(PR_SET_SECCOMP, ...).
>>
>>     In addition to the TSYNC flag later in this patch series, there is a
>>     non-zero chance that this syscall could be used for configuring a fixed
>>     argument area for seccomp-tracer-aware processes to pass syscall arguments
>>     in the future. Hence, the use of "seccomp" not simply "seccomp_add_filter"
>>     for this syscall. Additionally, this syscall uses operation, flags,
>>     and user pointer for arguments because strictly passing arguments via
>>     a user pointer would mean seccomp itself would be unable to trivially
>>     filter the seccomp syscall itself.
>>
>>     Signed-off-by: Kees Cook <keescook@chromium.org>
>>     Reviewed-by: Oleg Nesterov <oleg@redhat.com>
>>     Reviewed-by: Andy Lutomirski <luto@amacapital.net>
>
> Is this something that I should enable?
>
> As it depends on CONFIG_SECCOMP, it only makes sense on architectures that
> already support CONFIG_SECCOMP, right?
> Does it make sense to reserve a syscall slot for it on architectures that
> don't support it yet?

I don't see a good reason to reserve the syscall slot if seccomp
filter is not already implemented. I've CCed linux-api in case there
is something I'm not considering, though.

FWIW, if someone wants to add it for m68k, the steps to support
seccomp are listed in the arch/Kconfig for HAVE_ARCH_SECCOMP_FILTER.

-Kees

-- 
Kees Cook
Chrome OS Security

^ permalink raw reply

* Re: [PATCH 0/5] video: describe data bus formats
From: Boris BREZILLON @ 2014-08-12 11:02 UTC (permalink / raw)
  To: Boris BREZILLON
  Cc: Thierry Reding, Laurent Pinchart, David Airlie,
	dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Mauro Carvalho Chehab,
	linux-media-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1406031827-12432-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Hi,

On Tue, 22 Jul 2014 14:23:42 +0200
Boris BREZILLON <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:

> Hello,
> 
> This patch series is a proposal to describe the different data formats used
> by HW components to connect with each other.
> 
> This is just a copy of the existing V4L2_MBUS_FMT defintions with a neutral
> name so that it can be used by V4L2 and DRM/KMS subsystem.
> 
> This series also makes use of this video_bus_format enum in the DRM/KMS
> subsystem to define the data fomats supported on the connector <-> device
> link.
> 
> The video bus formats are not documented yet (and I don't know where this doc
> should be stored), but I'm pretty sure this version won't be the last one ;-).

Laurent, Thierry (and other DRM/KMS folks), any comments on this
series ?

I'd really like to get the HLCDC driver mainlined for 3.18 and it
depends on this series now...

Best Regards,

Boris
-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* Re: futex(2) man page update help request
From: chrubis-AlSwsSmVLrQ @ 2014-08-11 10:19 UTC (permalink / raw)
  To: Darren Hart
  Cc: Michael Kerrisk (man-pages), Thomas Gleixner, Ingo Molnar,
	Jakub Jelinek, linux-man-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	lkml, Davidlohr Bueso, Arnd Bergmann, Steven Rostedt,
	Peter Zijlstra, Linux API, Carlos O'Donell
In-Reply-To: <CF9A658E.91322%dvhart-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

Hi!
> >> How much LTP harness type code needs to be used?
> >
> >Not much.
> >
> >For this complexity of tests you would just need to call the tst_resm()
> >interface to report success/failure and, at the end of the test,
> >tst_exit() to return the stored overall test status.
> >
> >And ideally call the standard option parsing code and call the test in
> >standard loop so that the test can take advantage of standard options as
> >number of iterations to run, etc.
> >
> >Have a look at:
> >
> >https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines
> >
> >there is simple test example as well as description of the interfaces.
> 
> 
> Thanks Cyril,
> 
> I'll follow up with you in a couple weeks most likely. I have some urgent
> things that will be taking all my time and then some until then. Feel free
> to poke me though if I lose track of it :-)

Ping :)

-- 
Cyril Hrubis
chrubis-AlSwsSmVLrQ@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe linux-man" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH 1/9] drm: Add drm driver for Rockchip Socs
From: mark yao @ 2014-08-07  8:32 UTC (permalink / raw)
  To: heiko, Rob Clark, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, Randy Dunlap, David Airlie,
	Grant Likely, Greg Kroah-Hartman, John Stultz, Rom Lemarchand
  Cc: devicetree, linux-doc, linux-kernel, dri-devel, linux-api, olof,
	djkurtz, xjq, kfx, cym, cf, zyw, zwl, xxm, huangtao, kever.yang,
	zhangqing, yxj, wxt, xw, mark yao
In-Reply-To: <1407127507-1612-1-git-send-email-yzq@rock-chips.com>

This patch is a DRM Driver for Rockchip Socs, driver provides an abstraction
for the graphics hardware, such as lcd controller and connector interface.

Signed-off-by: mark yao <yzq@rock-chips.com>
---
changes since v1:

Adviced by Daniel Vetter:
- Switch to universal plane API's
---
 drivers/gpu/drm/Kconfig                           |    2 +
 drivers/gpu/drm/Makefile                          |    1 +
 drivers/gpu/drm/rockchip/Kconfig                  |   40 ++
 drivers/gpu/drm/rockchip/Makefile                 |   12 +
 drivers/gpu/drm/rockchip/rockchip_drm_connector.c |  412 ++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_connector.h |   36 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c       |  600 +++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h       |  128 ++++
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c        |   48 ++
 drivers/gpu/drm/rockchip/rockchip_drm_fb.h        |   28 +
 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c     |   63 ++
 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h     |   24 +
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c       |  163 +++++
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h       |   40 ++
 drivers/gpu/drm/rockchip/rockchip_drm_lcdc.c      |  722 +++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_lcdc.h      |  131 ++++
 include/uapi/drm/rockchip_drm.h                   |  110 ++++
 17 files changed, 2560 insertions(+)
 create mode 100644 drivers/gpu/drm/rockchip/Kconfig
 create mode 100644 drivers/gpu/drm/rockchip/Makefile
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_connector.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_connector.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_drv.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_drv.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fb.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fb.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_gem.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_gem.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_lcdc.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_lcdc.h
 create mode 100644 include/uapi/drm/rockchip_drm.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index f512004..5951c2c 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -170,6 +170,8 @@ config DRM_SAVAGE
 
 source "drivers/gpu/drm/exynos/Kconfig"
 
+source "drivers/gpu/drm/rockchip/Kconfig"
+
 source "drivers/gpu/drm/vmwgfx/Kconfig"
 
 source "drivers/gpu/drm/gma500/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index dd2ba42..40babd2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)	+=via/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
+obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
 obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
new file mode 100644
index 0000000..592e999
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -0,0 +1,40 @@
+config DRM_ROCKCHIP
+	tristate "DRM Support for Rockchip"
+	depends on DRM
+	select DRM_KMS_HELPER
+	select DRM_KMS_FB_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_GEM_CMA_HELPER
+	select DRM_PANEL
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
+	select VIDEOMODE_HELPERS
+	select OF
+	help
+	  Choose this option if you have a Rockchip soc chipset.
+	  This driver provides kernel mode setting and buffer
+	  management to userspace. This driver does not provides
+	  2D or 3D acceleration; acceleration is performed by other
+	  IP found on the SoC.
+
+config DRM_ROCKCHIP_LCDC
+	bool "ROCKCHIP DRM LCDC"
+	depends on DRM_ROCKCHIP
+	select FB_MODE_HELPERS
+	help
+	  Choose this option if you want to use Rockchip lcdc for DRM.
+	  The driver provides an abstraction for Rockchip lcd controller,
+	  lcd controller is the display interface from memory frame buffer
+	  to display device.
+
+config DRM_ROCKCHIP_CONNECTOR
+	bool "ROCKCHIP DRM CONNECTOR"
+	depends on OF && DRM_ROCKCHIP && DRM_ROCKCHIP_LCDC
+	select FB_MODE_HELPERS
+	select VIDEOMODE_HELPERS
+	help
+	  Choose this option if you want to use Rockchip Primary DISPLAY.
+	  The driver provides an abstraction for Rockchip display devices,
+	  such as lcd plane, lvds, edp , mipi, etc.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
new file mode 100644
index 0000000..45c9d50
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/rockchip
+
+rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_gem.o \
+		rockchip_drm_fb.o rockchip_drm_fbdev.o
+
+obj-$(CONFIG_DRM_ROCKCHIP_CONNECTOR) += rockchip_drm_connector.o
+obj-$(CONFIG_DRM_ROCKCHIP_LCDC) += rockchip_drm_lcdc.o
+obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_connector.c b/drivers/gpu/drm/rockchip/rockchip_drm_connector.c
new file mode 100644
index 0000000..337b618
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_connector.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_dpi.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include <linux/component.h>
+
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_connector.h"
+#include "rockchip_drm_lcdc.h"
+
+struct rockchip_conn_context {
+	struct device *dev;
+
+	struct drm_panel *panel;
+	struct rockchip_connector *conn;
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+
+	struct drm_display_mode mode;
+
+	u32 flags;
+	int type;
+
+	int dpms_mode;
+};
+
+#define connector_to_ctx(c) \
+		container_of(c, struct rockchip_conn_context, connector)
+
+#define encoder_to_ctx(c) \
+		container_of(c, struct rockchip_conn_context, encoder)
+
+static inline int rockchip_convert_conn_type(int type)
+{
+	switch (type) {
+	case ROCKCHIP_DISPLAY_TYPE_RGB:
+	case ROCKCHIP_DISPLAY_TYPE_LVDS:
+		return DRM_MODE_CONNECTOR_LVDS;
+	case ROCKCHIP_DISPLAY_TYPE_EDP:
+		return DRM_MODE_CONNECTOR_eDP;
+	}
+
+	return  DRM_MODE_CONNECTOR_Unknown;
+}
+
+static inline int rockchip_convert_encoder_type(int type)
+{
+	switch (type) {
+	case ROCKCHIP_DISPLAY_TYPE_RGB:
+	case ROCKCHIP_DISPLAY_TYPE_LVDS:
+	case ROCKCHIP_DISPLAY_TYPE_EDP:
+		return DRM_MODE_ENCODER_LVDS;
+	}
+
+	return DRM_MODE_ENCODER_NONE;
+}
+
+static enum drm_connector_status
+rockchip_conn_detect(struct drm_connector *connector, bool force)
+{
+	return true;
+}
+
+static void rockchip_connector_destroy(struct drm_connector *connector)
+{
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs rockchip_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.detect = rockchip_conn_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = rockchip_connector_destroy,
+};
+
+static int rockchip_conn_get_modes(struct drm_connector *connector)
+{
+	struct rockchip_conn_context *ctx = connector_to_ctx(connector);
+	struct drm_panel *panel = ctx->panel;
+
+	return panel->funcs->get_modes(panel);
+}
+
+static struct drm_encoder *
+	rockchip_conn_best_encoder(struct drm_connector *connector)
+{
+	struct rockchip_conn_context *ctx = connector_to_ctx(connector);
+
+	return &ctx->encoder;
+}
+
+static struct drm_connector_helper_funcs rockchip_connector_helper_funcs = {
+	.get_modes = rockchip_conn_get_modes,
+	.best_encoder = rockchip_conn_best_encoder,
+};
+
+static void rockchip_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct rockchip_conn_context *ctx = encoder_to_ctx(encoder);
+	struct rockchip_connector *conn = ctx->conn;
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		if (ctx->dpms_mode != DRM_MODE_DPMS_ON) {
+			conn->enable(conn);
+			ctx->panel->funcs->enable(ctx->panel);
+		}
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		if (ctx->dpms_mode == DRM_MODE_DPMS_ON) {
+			ctx->panel->funcs->disable(ctx->panel);
+			conn->disable(conn);
+		}
+		break;
+	default:
+		break;
+	}
+
+	ctx->dpms_mode = mode;
+}
+
+static bool
+rockchip_drm_encoder_mode_fixup(struct drm_encoder *encoder,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct rockchip_panel_special *priv_mode =
+					(void *)adjusted_mode->private;
+	struct rockchip_conn_context *ctx = encoder_to_ctx(encoder);
+
+	priv_mode->out_type = ctx->conn->type;
+
+	return true;
+}
+
+static void rockchip_drm_encoder_mode_set(struct drm_encoder *encoder,
+					  struct drm_display_mode *mode,
+					  struct drm_display_mode *adjusted)
+{
+	/* just set dummy now */
+}
+
+static void rockchip_drm_encoder_prepare(struct drm_encoder *encoder)
+{
+	/* drm framework doesn't check NULL. */
+}
+
+static void rockchip_drm_encoder_commit(struct drm_encoder *encoder)
+{
+	rockchip_drm_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void rockchip_drm_encoder_disable(struct drm_encoder *encoder)
+{
+	struct drm_plane *plane;
+	struct drm_device *dev = encoder->dev;
+
+	rockchip_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+	/* all planes connected to this encoder should be also disabled. */
+	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+		if (plane->crtc && (plane->crtc == encoder->crtc))
+			plane->funcs->disable_plane(plane);
+	}
+}
+
+
+static struct drm_encoder_helper_funcs rockchip_encoder_helper_funcs = {
+	.dpms = rockchip_drm_encoder_dpms,
+	.mode_fixup = rockchip_drm_encoder_mode_fixup,
+	.mode_set = rockchip_drm_encoder_mode_set,
+	.prepare = rockchip_drm_encoder_prepare,
+	.commit = rockchip_drm_encoder_commit,
+	.disable = rockchip_drm_encoder_disable,
+};
+static void rockchip_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static struct drm_encoder_funcs rockchip_encoder_funcs = {
+	.destroy = rockchip_drm_encoder_destroy,
+};
+
+static unsigned int rockchip_drm_encoder_clones(struct drm_encoder *encoder)
+{
+	struct rockchip_conn_context *ctx = encoder_to_ctx(encoder);
+	struct drm_encoder *clone;
+	struct drm_device *dev = encoder->dev;
+	unsigned int clone_mask = 0;
+	int cnt = 0;
+
+	list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
+		switch (ctx->type) {
+		case ROCKCHIP_DISPLAY_TYPE_RGB:
+		case ROCKCHIP_DISPLAY_TYPE_LVDS:
+		case ROCKCHIP_DISPLAY_TYPE_EDP:
+		case ROCKCHIP_DISPLAY_TYPE_HDMI:
+			clone_mask |= (1 << (cnt++));
+			break;
+		default:
+			continue;
+		}
+	}
+
+	return clone_mask;
+}
+
+static int rockchip_conn_bind(struct device *dev, struct device *master,
+			      void *data)
+{
+	struct rockchip_conn_context *ctx;
+	unsigned long possible_crtcs = 0;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct device_node *panel_node;
+	struct drm_device *drm_dev = data;
+	int ret;
+
+	ctx = rockchip_drm_component_data_get(dev,
+					      ROCKCHIP_DEVICE_TYPE_CONNECTOR);
+	if (!ctx) {
+		DRM_ERROR("can't find dp content form component\n");
+		return -EINVAL;
+	}
+
+	ret = rockchip_drm_pipe_get(dev);
+	if (ret < 0) {
+		DRM_ERROR("failed to bind display port\n");
+		return ret;
+	}
+
+	possible_crtcs |= 1 << ret;
+
+	encoder = &ctx->encoder;
+	encoder->possible_crtcs = possible_crtcs;
+
+	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+	ret = drm_encoder_init(drm_dev, encoder, &rockchip_encoder_funcs,
+			       rockchip_convert_encoder_type(ctx->type));
+	if (ret) {
+		DRM_ERROR("failed to initialize encoder with drm\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &rockchip_encoder_helper_funcs);
+
+	connector = &ctx->connector;
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+	connector->dpms = DRM_MODE_DPMS_OFF;
+
+	ret = drm_connector_init(drm_dev, connector,
+				 &rockchip_connector_funcs,
+				 rockchip_convert_conn_type(ctx->type));
+	if (ret) {
+		DRM_ERROR("failed to initialize connector with drm\n");
+		goto err_free_encoder;
+	}
+
+	drm_connector_helper_add(connector,
+				 &rockchip_connector_helper_funcs);
+
+	ret = drm_sysfs_connector_add(connector);
+	if (ret) {
+		DRM_ERROR("failed to add drm_sysfs\n");
+		goto err_free_connector;
+	}
+
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
+	if (ret) {
+		DRM_ERROR("failed to attach connector and encoder\n");
+		goto err_free_connector_sysfs;
+	}
+
+	panel_node = of_parse_phandle(dev->of_node, "rockchip,panel", 0);
+	if (!panel_node) {
+		DRM_ERROR("failed to find diaplay panel\n");
+		goto err_free_connector_sysfs;
+	}
+	ctx->panel = of_drm_find_panel(panel_node);
+	if (!ctx->panel) {
+		DRM_ERROR("failed to find diaplay panel\n");
+		ret = -ENODEV;
+		goto err_free_connector_sysfs;
+	}
+
+	of_node_put(panel_node);
+
+	ret = drm_panel_attach(ctx->panel, connector);
+	if (ret) {
+		DRM_ERROR("failed to attach connector and encoder\n");
+		goto err_free_connector_sysfs;
+	}
+
+	return 0;
+
+err_free_connector_sysfs:
+	drm_sysfs_connector_remove(connector);
+err_free_connector:
+	drm_connector_cleanup(connector);
+err_free_encoder:
+	drm_encoder_cleanup(encoder);
+	return ret;
+}
+
+static void rockchip_conn_unbind(struct device *dev, struct device *master,
+				 void *data)
+{
+	struct rockchip_conn_context *ctx;
+	struct drm_encoder *encoder;
+
+	ctx = rockchip_drm_component_data_get(dev,
+					      ROCKCHIP_DEVICE_TYPE_CONNECTOR);
+	encoder = &ctx->encoder;
+
+	drm_panel_detach(ctx->panel);
+
+	rockchip_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+	encoder->funcs->destroy(encoder);
+	drm_sysfs_connector_remove(&ctx->connector);
+	drm_connector_cleanup(&ctx->connector);
+	drm_encoder_cleanup(encoder);
+
+	rockchip_drm_component_del(dev, ROCKCHIP_DEVICE_TYPE_CONNECTOR);
+}
+
+static const struct component_ops rockchip_conn_component_ops = {
+	.bind = rockchip_conn_bind,
+	.unbind = rockchip_conn_unbind,
+};
+
+void *rockchip_connector_register(struct rockchip_connector *conn)
+{
+	struct rockchip_conn_context *ctx;
+	struct device *dev = conn->dev;
+	int ret;
+
+	if (!dev) {
+		DRM_ERROR("please provide a device at dp register\n");
+		return NULL;
+	}
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return NULL;
+
+	ret = rockchip_drm_component_add(dev, ROCKCHIP_DEVICE_TYPE_CONNECTOR,
+					 conn->type, ctx);
+	if (ret < 0) {
+		DRM_ERROR("register connector component fail ret =%d\n", ret);
+		return NULL;
+	}
+
+	ctx->conn = conn;
+	ctx->dev = dev;
+	ctx->type = conn->type;
+	ctx->dpms_mode = DRM_MODE_DPMS_OFF;
+
+	ret = component_add(dev, &rockchip_conn_component_ops);
+	if (ret)
+		goto err_del_component;
+
+	DRM_DEBUG_KMS("succes register connector type=%d\n", conn->type);
+
+	return ctx;
+
+err_del_component:
+	rockchip_drm_component_del(dev, ROCKCHIP_DEVICE_TYPE_CONNECTOR);
+	return NULL;
+}
+
+void rockchip_connector_unregister(void *data)
+{
+	struct rockchip_conn_context *ctx = data;
+
+	if (!ctx)
+		return;
+	rockchip_drm_component_del(ctx->dev, ROCKCHIP_DEVICE_TYPE_CONNECTOR);
+	component_del(ctx->dev, &rockchip_conn_component_ops);
+}
+
+void rockchip_drm_encoder_setup(struct drm_device *dev)
+{
+	struct drm_encoder *encoder;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		encoder->possible_clones =
+				rockchip_drm_encoder_clones(encoder);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_connector.h b/drivers/gpu/drm/rockchip/rockchip_drm_connector.h
new file mode 100644
index 0000000..191f9fc
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_connector.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_DRM_CONNECTOR_H_
+#define _ROCKCHIP_DRM_CONNECTOR_H_
+
+#include <drm/drm_crtc.h>
+
+#include "rockchip_drm_drv.h"
+
+struct rockchip_connector {
+	struct device *dev;
+	int type;
+	void *priv;
+	u32 flags;
+
+	void (*enable)(struct rockchip_connector *conn);
+	void (*disable)(struct rockchip_connector *conn);
+	int (*setmode)(struct rockchip_connector *conn,
+		       struct drm_display_mode *mode);
+};
+
+void *rockchip_connector_register(struct rockchip_connector *conn);
+void rockchip_connector_unregister(void *data);
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
new file mode 100644
index 0000000..4871867
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_drv.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/pm_runtime.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include <linux/anon_inodes.h>
+#include <linux/component.h>
+
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_gem.h"
+
+#define DRIVER_NAME	"rockchip-drm"
+#define DRIVER_DESC	"RockChip Soc DRM"
+#define DRIVER_DATE	"20140725"
+#define DRIVER_MAJOR	1
+#define DRIVER_MINOR	0
+
+#define VBLANK_OFF_DELAY	50000
+
+static struct platform_device *rockchip_drm_pdev;
+
+static DEFINE_MUTEX(drm_component_lock);
+static LIST_HEAD(drm_component_list);
+
+struct component_dev {
+	struct list_head list;
+	struct device *crtc_dev;
+	struct device *conn_dev;
+	unsigned int out_type;
+	int pipe;
+	void *crtc_data;
+	void *conn_data;
+};
+
+static int rockchip_drm_load(struct drm_device *dev, unsigned long flags)
+{
+	struct rockchip_drm_private *private;
+	int ret;
+	int nr;
+
+	private = kzalloc(sizeof(*private), GFP_KERNEL);
+	if (!private)
+		return -ENOMEM;
+
+	dev_set_drvdata(dev->dev, dev);
+	dev->dev_private = (void *)private;
+
+	drm_mode_config_init(dev);
+
+	rockchip_drm_mode_config_init(dev);
+
+
+	/* Try to bind all sub drivers. */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret)
+		goto err_cleanup_vblank;
+
+	for (nr = 0; nr < MAX_PLANE; nr++) {
+		struct drm_plane *plane;
+		unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
+
+		plane = rockchip_plane_init(dev, possible_crtcs, false);
+		if (!plane)
+			goto err_mode_config_cleanup;
+	}
+
+	/* init kms poll for handling hpd */
+	drm_kms_helper_poll_init(dev);
+
+	ret = drm_vblank_init(dev, MAX_CRTC);
+	if (ret)
+		goto err_mode_config_cleanup;
+
+	/* setup possible_clones. */
+	rockchip_drm_encoder_setup(dev);
+
+	drm_vblank_offdelay = VBLANK_OFF_DELAY;
+
+	platform_set_drvdata(dev->platformdev, dev);
+	rockchip_drm_fbdev_init(dev);
+
+	/* force connectors detection */
+	drm_helper_hpd_irq_event(dev);
+
+	return 0;
+
+err_cleanup_vblank:
+	drm_vblank_cleanup(dev);
+err_mode_config_cleanup:
+	drm_mode_config_cleanup(dev);
+	kfree(private);
+
+	return ret;
+}
+
+static int rockchip_drm_unload(struct drm_device *dev)
+{
+	rockchip_drm_fbdev_fini(dev);
+	drm_vblank_cleanup(dev);
+	drm_kms_helper_poll_fini(dev);
+	drm_mode_config_cleanup(dev);
+
+	kfree(dev->dev_private);
+
+	component_unbind_all(dev->dev, dev);
+	dev->dev_private = NULL;
+
+	return 0;
+}
+
+static int rockchip_drm_suspend(struct drm_device *dev, pm_message_t state)
+{
+	struct drm_connector *connector;
+
+	drm_modeset_lock_all(dev);
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		int old_dpms = connector->dpms;
+
+		if (connector->funcs->dpms)
+			connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
+		/* Set the old mode back to the connector for resume */
+		connector->dpms = old_dpms;
+	}
+	drm_modeset_unlock_all(dev);
+
+	return 0;
+}
+
+static int rockchip_drm_resume(struct drm_device *dev)
+{
+	struct drm_connector *connector;
+
+	drm_modeset_lock_all(dev);
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->funcs->dpms)
+			connector->funcs->dpms(connector, connector->dpms);
+	}
+	drm_modeset_unlock_all(dev);
+
+	drm_helper_resume_force_mode(dev);
+
+	return 0;
+}
+
+static int rockchip_drm_open(struct drm_device *dev, struct drm_file *file)
+{
+	return 0;
+}
+
+static void rockchip_drm_postclose(struct drm_device *dev,
+				   struct drm_file *file)
+{
+	struct drm_pending_event *e, *et;
+	unsigned long flags;
+
+	if (!file->driver_priv)
+		return;
+
+	/* Release all events not unhandled by page flip handler. */
+	rockchip_drm_crtc_cancel_pending_flip(dev);
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	/* Release all events handled by page flip handler but not freed. */
+	list_for_each_entry_safe(e, et, &file->event_list, link) {
+		list_del(&e->link);
+		e->destroy(e);
+	}
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	kfree(file->driver_priv);
+	file->driver_priv = NULL;
+}
+
+static const struct drm_ioctl_desc rockchip_ioctls[] = {
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_CREATE, rockchip_drm_gem_create_ioctl,
+			  DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MAP_OFFSET,
+			  rockchip_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
+			  DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MMAP, rockchip_drm_gem_mmap_ioctl,
+			  DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_GET, rockchip_drm_gem_get_ioctl,
+			  DRM_UNLOCKED),
+};
+
+static const struct file_operations rockchip_drm_driver_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.mmap = drm_gem_cma_mmap,
+	.poll = drm_poll,
+	.read = drm_read,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
+	.release = drm_release,
+};
+
+static struct drm_driver rockchip_drm_driver = {
+	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+	.load			= rockchip_drm_load,
+	.unload			= rockchip_drm_unload,
+	.suspend		= rockchip_drm_suspend,
+	.resume			= rockchip_drm_resume,
+	.open			= rockchip_drm_open,
+	.postclose		= rockchip_drm_postclose,
+	.get_vblank_counter	= drm_vblank_count,
+	.enable_vblank		= rockchip_drm_crtc_enable_vblank,
+	.disable_vblank		= rockchip_drm_crtc_disable_vblank,
+	.gem_free_object        = drm_gem_cma_free_object,
+	.gem_vm_ops             = &drm_gem_cma_vm_ops,
+	.dumb_create            = drm_gem_cma_dumb_create,
+	.dumb_map_offset        = drm_gem_cma_dumb_map_offset,
+	.dumb_destroy           = drm_gem_dumb_destroy,
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_import       = drm_gem_prime_import,
+	.gem_prime_export       = drm_gem_prime_export,
+	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap         = drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap       = drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap         = drm_gem_cma_prime_mmap,
+	.ioctls			= rockchip_ioctls,
+	.num_ioctls		= ARRAY_SIZE(rockchip_ioctls),
+	.fops			= &rockchip_drm_driver_fops,
+	.name	= DRIVER_NAME,
+	.desc	= DRIVER_DESC,
+	.date	= DRIVER_DATE,
+	.major	= DRIVER_MAJOR,
+	.minor	= DRIVER_MINOR,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_drm_sys_suspend(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+	pm_message_t message;
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	message.event = PM_EVENT_SUSPEND;
+
+	return rockchip_drm_suspend(drm_dev, message);
+}
+
+static int rockchip_drm_sys_resume(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return rockchip_drm_resume(drm_dev);
+}
+#endif
+
+static const struct dev_pm_ops rockchip_drm_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend,
+				rockchip_drm_sys_resume)
+};
+
+int rockchip_drm_pipe_get(struct device *dev)
+{
+	struct component_dev *cdev, *next;
+	int pipe = -1;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
+		if ((cdev->crtc_dev == dev) || (cdev->conn_dev == dev)) {
+			pipe = cdev->pipe;
+			break;
+		}
+	}
+
+	mutex_unlock(&drm_component_lock);
+
+	return pipe;
+}
+
+int rockchip_drm_out_type_get(struct device *dev)
+{
+	struct component_dev *cdev, *next;
+	int type = -1;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
+		if ((cdev->crtc_dev == dev) || (cdev->conn_dev == dev)) {
+			type = cdev->out_type;
+			break;
+		}
+	}
+
+	mutex_unlock(&drm_component_lock);
+
+	return type;
+}
+
+void *rockchip_drm_component_data_get(struct device *dev,
+				      enum rockchip_drm_device_type dev_type)
+{
+	struct component_dev *cdev, *next;
+	void *data = NULL;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
+		if ((cdev->crtc_dev == dev) || (cdev->conn_dev == dev)) {
+			if (dev_type == ROCKCHIP_DEVICE_TYPE_CRTC)
+				data = cdev->crtc_data;
+			else if (dev_type == ROCKCHIP_DEVICE_TYPE_CONNECTOR)
+				data = cdev->conn_data;
+			break;
+		}
+	}
+
+	mutex_unlock(&drm_component_lock);
+
+	return data;
+}
+
+int rockchip_drm_component_add(struct device *dev,
+			       enum rockchip_drm_device_type dev_type,
+			       int out_type, void *data)
+{
+	struct component_dev *cdev;
+	int pipe = -1;
+
+	if (dev_type != ROCKCHIP_DEVICE_TYPE_CRTC &&
+	    dev_type != ROCKCHIP_DEVICE_TYPE_CONNECTOR) {
+		DRM_ERROR("invalid device type.\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&drm_component_lock);
+
+	/*
+	 * Make sure to check if there is a component which has two device
+	 * objects, for connector and for encoder/connector.
+	 * It should make sure that crtc and encoder/connector drivers are
+	 * ready before rockchip drm core binds them.
+	 */
+	list_for_each_entry(cdev, &drm_component_list, list) {
+		pipe++;
+		/*
+		 * out_type from crtc and display port, crtc set possible
+		 * out_type maskbit at out_type, and display posr set out_type
+		 * directly. and if crtc and display port all register, set
+		 * out_type not maskbit;
+		 */
+		if (cdev->out_type & out_type) {
+			if (cdev->crtc_dev && cdev->conn_dev) {
+				DRM_ERROR("already register, not allow");
+				return -EINVAL;
+			}
+
+			if (dev_type == ROCKCHIP_DEVICE_TYPE_CRTC) {
+				cdev->pipe = pipe;
+				cdev->crtc_dev = dev;
+				cdev->crtc_data = data;
+			} else if (dev_type == ROCKCHIP_DEVICE_TYPE_CONNECTOR) {
+				cdev->conn_dev = dev;
+				cdev->conn_data = data;
+				cdev->out_type = out_type;
+			}
+
+			mutex_unlock(&drm_component_lock);
+			return 0;
+		}
+	}
+
+	mutex_unlock(&drm_component_lock);
+
+	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+	if (!cdev)
+		return -ENOMEM;
+
+	if (dev_type == ROCKCHIP_DEVICE_TYPE_CRTC) {
+		cdev->crtc_dev = dev;
+		cdev->crtc_data = data;
+	} else if (dev_type == ROCKCHIP_DEVICE_TYPE_CONNECTOR) {
+		cdev->conn_dev = dev;
+		cdev->conn_data = data;
+	}
+
+	cdev->out_type = out_type;
+
+	mutex_lock(&drm_component_lock);
+	list_add_tail(&cdev->list, &drm_component_list);
+	mutex_unlock(&drm_component_lock);
+
+	return 0;
+}
+
+void rockchip_drm_component_del(struct device *dev,
+				enum rockchip_drm_device_type dev_type)
+{
+	struct component_dev *cdev, *next;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
+		if (dev_type == ROCKCHIP_DEVICE_TYPE_CRTC) {
+			if (cdev->crtc_dev == dev)
+				cdev->crtc_dev = NULL;
+		}
+
+		if (dev_type == ROCKCHIP_DEVICE_TYPE_CONNECTOR) {
+			if (cdev->conn_dev == dev)
+				cdev->conn_dev = NULL;
+		}
+
+		/*
+		 * Release cdev object only in case that both of crtc and
+		 * encoder/connector device objects are NULL.
+		 */
+		if (!cdev->crtc_dev && !cdev->conn_dev) {
+			list_del(&cdev->list);
+			kfree(cdev);
+		}
+
+		break;
+	}
+
+	mutex_unlock(&drm_component_lock);
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev == (struct device *)data;
+}
+
+static int rockchip_drm_add_components(struct device *dev, struct master *m)
+{
+	struct component_dev *cdev;
+	unsigned int attach_cnt = 0;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry(cdev, &drm_component_list, list) {
+		int ret;
+
+		/*
+		 * Add components to master only in case that crtc and
+		 * encoder/connector device objects exist.
+		 */
+		if (!cdev->crtc_dev || !cdev->conn_dev)
+			continue;
+
+		attach_cnt++;
+
+		mutex_unlock(&drm_component_lock);
+
+		/*
+		 * Do not chage below call order.
+		 * crtc device first should be added to master because
+		 * connector/encoder need pipe number of crtc when they
+		 * are created.
+		 */
+		ret = component_master_add_child(m, compare_of, cdev->crtc_dev);
+		ret |= component_master_add_child(m, compare_of,
+						  cdev->conn_dev);
+		if (ret < 0)
+			return ret;
+
+		mutex_lock(&drm_component_lock);
+	}
+
+	mutex_unlock(&drm_component_lock);
+
+	return attach_cnt ? 0 : -ENODEV;
+}
+
+static int rockchip_drm_bind(struct device *dev)
+{
+	return drm_platform_init(&rockchip_drm_driver, to_platform_device(dev));
+}
+
+static void rockchip_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops rockchip_drm_ops = {
+	.add_components = rockchip_drm_add_components,
+	.bind = rockchip_drm_bind,
+	.unbind = rockchip_drm_unbind,
+};
+
+static int rockchip_drm_platform_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	rockchip_drm_driver.num_ioctls = ARRAY_SIZE(rockchip_ioctls);
+
+	ret = component_master_add(&pdev->dev, &rockchip_drm_ops);
+	if (ret < 0)
+		DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
+
+	return 0;
+}
+
+static int rockchip_drm_platform_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &rockchip_drm_ops);
+
+	return 0;
+}
+
+static struct platform_driver rockchip_drm_platform_driver = {
+	.probe = rockchip_drm_platform_probe,
+	.remove = rockchip_drm_platform_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "rockchip-drm",
+		.pm = &rockchip_drm_pm_ops,
+	},
+};
+
+static int rockchip_drm_init(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&rockchip_panel_platform_driver);
+	if (ret < 0)
+		return -ENOMEM;
+
+#ifdef CONFIG_DRM_ROCKCHIP_LCDC
+	ret = platform_driver_register(&rockchip_lcdc_platform_driver);
+	if (ret < 0)
+		goto out_lcdc;
+#endif
+
+	rockchip_drm_pdev = platform_device_register_simple("rockchip-drm", -1,
+							    NULL, 0);
+	if (IS_ERR(rockchip_drm_pdev)) {
+		ret = PTR_ERR(rockchip_drm_pdev);
+		goto out_drm_pdev;
+	}
+
+	ret = platform_driver_register(&rockchip_drm_platform_driver);
+	if (ret)
+		goto out_drm_driver;
+
+	return 0;
+
+out_drm_driver:
+	platform_device_unregister(rockchip_drm_pdev);
+out_drm_pdev:
+#ifdef CONFIG_DRM_ROCKCHIP_LCDC
+	platform_driver_unregister(&rockchip_lcdc_platform_driver);
+out_lcdc:
+#endif
+	platform_driver_unregister(&rockchip_panel_platform_driver);
+	return ret;
+}
+
+static void rockchip_drm_exit(void)
+{
+	platform_device_unregister(rockchip_drm_pdev);
+	platform_driver_unregister(&rockchip_drm_platform_driver);
+#ifdef CONFIG_DRM_ROCKCHIP_LCDC
+	platform_driver_unregister(&rockchip_lcdc_platform_driver);
+#endif
+	platform_driver_unregister(&rockchip_panel_platform_driver);
+}
+
+module_init(rockchip_drm_init);
+module_exit(rockchip_drm_exit);
+
+MODULE_AUTHOR("mark yao <mark.yao@rock-chips.com>");
+MODULE_DESCRIPTION("ROCKCHIP DRM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
new file mode 100644
index 0000000..c0c1d89
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_drv.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_DRM_DRV_H_
+#define _ROCKCHIP_DRM_DRV_H_
+
+#include <linux/module.h>
+
+#define MAX_CRTC	3
+#define MAX_PLANE	5
+#define MAX_FB_BUFFER	4
+#define DEFAULT_ZPOS	-1
+
+struct drm_device;
+struct drm_connector;
+
+/*
+ * display output interface supported by rockchip lcdc
+ */
+#define ROCKCHIP_OUTFACE_P888	0
+#define ROCKCHIP_OUTFACE_P666	1
+#define ROCKCHIP_OUTFACE_P565	2
+/* for use special outface */
+#define ROCKCHIP_OUTFACE_AAAA	15
+
+#define ROCKCHIP_COLOR_SWAP_RG	0x1
+#define ROCKCHIP_COLOR_SWAP_RB	0x2
+#define ROCKCHIP_COLOR_SWAP_GB	0x4
+/*
+ * Special panel info for rockchip
+ *
+ * @out_type: lcd controller need to know the sceen type.
+ * @out_face: the output pin interface.
+ * @color_swap: if want to swap color at output, use this.
+ * @pwr18: choice the power supply 1.8 or 3.3 mode for lcdc
+ * @dither: use dither func at lcd output
+ * @flags: the display flags, now just for pin sync level.
+ */
+struct rockchip_panel_special {
+	int out_type;
+	int out_face;
+	u32 color_swap;
+	bool pwr18;
+	bool dither;
+	u32 flags;
+};
+
+/* This enumerates device type. */
+enum rockchip_drm_device_type {
+	ROCKCHIP_DEVICE_TYPE_NONE,
+	ROCKCHIP_DEVICE_TYPE_CRTC,
+	ROCKCHIP_DEVICE_TYPE_CONNECTOR,
+};
+
+/* this enumerates display type. */
+enum rockchip_drm_output_type {
+	ROCKCHIP_DISPLAY_TYPE_NONE = 0,
+	/* RGB Interface. */
+	ROCKCHIP_DISPLAY_TYPE_RGB = (1 << 0),
+	/* LVDS Interface. */
+	ROCKCHIP_DISPLAY_TYPE_LVDS = (1 << 1),
+	/* DUAL LVDS Interface. */
+	ROCKCHIP_DISPLAY_TYPE_DUAL_LVDS = (1 << 2),
+	/* EDP Interface. */
+	ROCKCHIP_DISPLAY_TYPE_EDP = (1 << 3),
+	/* MIPI Interface. */
+	ROCKCHIP_DISPLAY_TYPE_MIPI = (1 << 4),
+	/* HDMI Interface. */
+	ROCKCHIP_DISPLAY_TYPE_HDMI = (1 << 5),
+};
+
+/*
+ * Rockchip drm private structure.
+ *
+ * @pipe: the pipe number for this crtc/manager.
+ */
+struct rockchip_drm_private {
+	struct drm_fbdev_cma *fbdev_cma;
+	/*
+	 * created crtc object would be contained at this array and
+	 * this array is used to be aware of which crtc did it request vblank.
+	 */
+	struct drm_crtc *crtc[MAX_CRTC];
+	struct drm_property *plane_zpos_property;
+	struct drm_property *crtc_mode_property;
+
+	unsigned int pipe;
+};
+
+
+void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
+void rockchip_drm_crtc_cancel_pending_flip(struct drm_device *dev);
+int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
+void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
+
+struct drm_plane *rockchip_plane_init(struct drm_device *dev,
+				      unsigned long possible_crtcs, bool priv);
+
+void rockchip_drm_encoder_setup(struct drm_device *dev);
+
+void *rockchip_drm_component_data_get(struct device *dev,
+				      enum rockchip_drm_device_type dev_type);
+int rockchip_drm_pipe_get(struct device *dev);
+
+int rockchip_drm_component_add(struct device *dev,
+			       enum rockchip_drm_device_type dev_type,
+			       int out_type, void *data);
+void rockchip_drm_component_del(struct device *dev,
+				enum rockchip_drm_device_type dev_type);
+
+extern struct platform_driver rockchip_panel_platform_driver;
+#ifdef CONFIG_DRM_ROCKCHIP_LCDC
+extern struct platform_driver rockchip_lcdc_platform_driver;
+#endif
+#endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
new file mode 100644
index 0000000..a04024b
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_fb.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include <uapi/drm/rockchip_drm.h>
+
+static struct drm_framebuffer *
+rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+			struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
+static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
+	.fb_create = rockchip_user_fb_create,
+};
+
+void rockchip_drm_mode_config_init(struct drm_device *dev)
+{
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+
+	/*
+	 * set max width and height as default value(4096x4096).
+	 * this value would be used to check framebuffer size limitation
+	 * at drm_mode_addfb().
+	 */
+	dev->mode_config.max_width = 4096;
+	dev->mode_config.max_height = 4096;
+
+	dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
new file mode 100644
index 0000000..6258de6
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
@@ -0,0 +1,28 @@
+/*
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_fb.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_DRM_FB_H_
+#define _ROCKCHIP_DRM_FB_H_
+
+struct drm_framebuffer *
+rockchip_drm_framebuffer_init(struct drm_device *dev,
+			      struct drm_mode_fb_cmd2 *mode_cmd,
+			      struct drm_gem_object *obj);
+
+void rockchip_drm_mode_config_init(struct drm_device *dev);
+
+#endif /* _ROCKCHIP_DRM_FB_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
new file mode 100644
index 0000000..d32fa57
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_fbdev.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+
+#define MAX_CONNECTOR		4
+#define PREFERRED_BPP		32
+
+int rockchip_drm_fbdev_init(struct drm_device *dev)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct drm_fbdev_cma *fbdev_cma;
+	unsigned int num_crtc;
+
+	if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
+		return 0;
+
+	if (private->fbdev_cma) {
+		DRM_ERROR("no allow to reinit cma fbdev\n");
+		return -EINVAL;
+	}
+
+	num_crtc = dev->mode_config.num_crtc;
+
+	fbdev_cma = drm_fbdev_cma_init(dev, PREFERRED_BPP, num_crtc,
+				       MAX_CONNECTOR);
+	if (!fbdev_cma) {
+		DRM_ERROR("failed to init cma fbdev\n");
+		return -ENOMEM;
+	}
+
+	private->fbdev_cma = fbdev_cma;
+
+	return 0;
+}
+
+void rockchip_drm_fbdev_fini(struct drm_device *dev)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+
+	if (!private || !private->fbdev_cma)
+		return;
+
+	drm_fbdev_cma_fini(private->fbdev_cma);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
new file mode 100644
index 0000000..91cb535
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_fbdev.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_DRM_FBDEV_H_
+#define _ROCKCHIP_DRM_FBDEV_H_
+
+int rockchip_drm_fbdev_init(struct drm_device *dev);
+void rockchip_drm_fbdev_fini(struct drm_device *dev);
+
+#endif /* _ROCKCHIP_DRM_FBDEV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
new file mode 100644
index 0000000..f0219cd
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -0,0 +1,163 @@
+/*
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_gem.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_vma_manager.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+
+int rockchip_drm_gem_create_ioctl(struct drm_device *dev, void *data,
+				  struct drm_file *file_priv)
+{
+	struct drm_rockchip_gem_create *args = data;
+	struct drm_gem_cma_object *cma_obj;
+	struct drm_gem_object *gem_obj;
+	int ret;
+
+	cma_obj = drm_gem_cma_create(dev, args->size);
+	if (IS_ERR(cma_obj))
+		return PTR_ERR_OR_ZERO(cma_obj);
+
+	gem_obj = &cma_obj->base;
+
+	/*
+	 * allocate a id of idr table where the obj is registered
+	 * and handle has the id what user can see.
+	 */
+	ret = drm_gem_handle_create(file_priv, gem_obj, &args->handle);
+	if (ret)
+		goto err_handle_create;
+
+	/* drop reference from allocate - handle holds it now. */
+	drm_gem_object_unreference_unlocked(gem_obj);
+
+	return PTR_ERR_OR_ZERO(cma_obj);
+
+err_handle_create:
+	drm_gem_cma_free_object(gem_obj);
+	return ret;
+}
+
+int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *file_priv)
+{
+	struct drm_rockchip_gem_map_off *args = data;
+
+	DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
+		      args->handle, (unsigned long)args->offset);
+
+	return drm_gem_cma_dumb_map_offset(file_priv, dev, args->handle,
+					   &args->offset);
+}
+
+int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
+				struct drm_file *file_priv)
+{
+	struct drm_rockchip_gem_mmap *args = data;
+	struct drm_gem_object *obj;
+	unsigned long addr;
+
+	mutex_lock(&dev->struct_mutex);
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		mutex_unlock(&dev->struct_mutex);
+		return -EINVAL;
+	}
+
+	addr = vm_mmap(obj->filp, 0, args->size, PROT_READ | PROT_WRITE,
+		       MAP_SHARED, 0);
+
+	drm_gem_object_unreference(obj);
+
+	if (IS_ERR_VALUE(addr)) {
+		mutex_unlock(&dev->struct_mutex);
+		return (int)addr;
+	}
+
+	mutex_unlock(&dev->struct_mutex);
+
+	args->mapped = addr;
+
+	DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
+
+	return 0;
+}
+
+int rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+			       struct drm_file *file_priv)
+{
+	struct drm_rockchip_gem_info *args = data;
+	struct drm_gem_object *obj;
+
+	mutex_lock(&dev->struct_mutex);
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		mutex_unlock(&dev->struct_mutex);
+		return -EINVAL;
+	}
+
+	args->size = obj->size;
+
+	drm_gem_object_unreference(obj);
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+int rockchip_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+				     struct drm_device *dev, uint32_t handle,
+				     uint64_t *offset)
+{
+	struct drm_gem_object *obj;
+	int ret = 0;
+
+	mutex_lock(&dev->struct_mutex);
+
+	/*
+	 * get offset of memory allocated for drm framebuffer.
+	 * - this callback would be called by user application
+	 * with DRM_IOCTL_MODE_MAP_DUMB command.
+	 */
+
+	obj = drm_gem_object_lookup(dev, file_priv, handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	ret = drm_gem_create_mmap_offset(obj);
+	if (ret)
+		goto out;
+
+	*offset = drm_vma_node_offset_addr(&obj->vma_node);
+	DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
+
+out:
+	drm_gem_object_unreference(obj);
+unlock:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
new file mode 100644
index 0000000..fe8285f
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_DRM_GEM_H_
+#define _ROCKCHIP_DRM_GEM_H_
+
+/*
+ * request gem object creation and buffer allocation as the size
+ * that it is calculated with framebuffer information such as width,
+ * height and bpp.
+ */
+int rockchip_drm_gem_create_ioctl(struct drm_device *dev, void *data,
+				  struct drm_file *file_priv);
+
+/* get buffer offset to map to user space. */
+int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *file_priv);
+
+/*
+ * mmap the physically continuous memory that a gem object contains
+ * to user space.
+ */
+int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
+				struct drm_file *file_priv);
+
+/* get buffer information to memory region allocated by gem. */
+int rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+			       struct drm_file *file_priv);
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_lcdc.c b/drivers/gpu/drm/rockchip/rockchip_drm_lcdc.c
new file mode 100644
index 0000000..98bfbab
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_lcdc.c
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * based on exynos_drm_fimd.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/component.h>
+
+#include <drm/rockchip_drm.h>
+
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_lcdc.h"
+
+#define LCDC_DEFAULT_FRAMERATE 60
+
+#define ROCKCHIP_DISPLAY_TYPE_LCD (ROCKCHIP_DISPLAY_TYPE_RGB | \
+					ROCKCHIP_DISPLAY_TYPE_LVDS | \
+					ROCKCHIP_DISPLAY_TYPE_EDP)
+
+static const uint32_t formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+};
+
+struct rockchip_plane {
+	int zpos;
+	struct drm_plane base;
+};
+
+struct lcdc_context {
+	struct device *dev;
+	struct drm_device *drm_dev;
+	struct drm_crtc crtc;
+	struct drm_pending_vblank_event *event;
+	struct drm_display_mode mode;
+	struct drm_plane *plane;
+	struct lcdc_driver *drv;
+	unsigned int default_win;
+	unsigned int dpms;
+	int pipe;
+	wait_queue_head_t wait_vsync_queue;
+	atomic_t wait_vsync_event;
+};
+
+#define to_lcdc_data(x) ((x)->drv->data)
+#define to_lcdc_ctx(x) container_of(x, struct lcdc_context, crtc)
+#define to_rockchip_plane(x) container_of(x, struct rockchip_plane, base)
+
+const struct of_device_id lcdc_driver_dt_match[] = {
+#ifdef CONFIG_LCDC_RK3288
+	{ .compatible = "rockchip,rk3288-lcdc",
+	  .data = (void *)&rockchip_rk3288_lcdc },
+#endif
+	{},
+};
+
+static inline struct lcdc_driver_data *drm_lcdc_get_driver_data(
+	struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+			of_match_device(lcdc_driver_dt_match, &pdev->dev);
+
+	return (struct lcdc_driver_data *)of_id->data;
+}
+
+static int rockchip_plane_get_size(int start, unsigned length, unsigned last)
+{
+	int end = start + length;
+	int size = 0;
+
+	if (start <= 0) {
+		if (end > 0)
+			size = min_t(unsigned, end, last);
+	} else if (start <= last) {
+		size = min_t(unsigned, last - start, length);
+	}
+
+	return size;
+}
+
+static int rockchip_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+				 struct drm_framebuffer *fb, int crtc_x,
+				 int crtc_y, unsigned int crtc_w,
+				 unsigned int crtc_h, uint32_t src_x,
+				 uint32_t src_y, uint32_t src_w, uint32_t src_h)
+{
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+	struct lcdc_context *ctx = to_lcdc_ctx(crtc);
+	struct lcdc_driver_data *lcdc_data = to_lcdc_data(ctx);
+	struct drm_gem_cma_object *gem;
+	struct lcdc_win_data *win_data;
+	unsigned long offset;
+	unsigned int actual_w;
+	unsigned int actual_h;
+	int win;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+	if (!gem) {
+		DRM_ERROR("fail to get cma object from framebuffer\n");
+		return -EINVAL;
+	}
+
+	actual_w = rockchip_plane_get_size(crtc_x,
+					   crtc_w, crtc->mode.hdisplay);
+	actual_h = rockchip_plane_get_size(crtc_y,
+					   crtc_h, crtc->mode.vdisplay);
+	if (crtc_x < 0) {
+		if (actual_w)
+			src_x -= crtc_x;
+		crtc_x = 0;
+	}
+
+	if (crtc_y < 0) {
+		if (actual_h)
+			src_y -= crtc_y;
+		crtc_y = 0;
+	}
+
+	win = rockchip_plane->zpos;
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win >= ZPOS_MAX_NUM)
+		return -EINVAL;
+
+	offset = (src_x >> 16) * (fb->bits_per_pixel >> 3);
+	offset += (src_y >> 16) * fb->pitches[0];
+
+	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, fb->pitches[0]);
+
+	win_data = lcdc_data->get_win(ctx->drv, win);
+
+	win_data->xpos = crtc_x;
+	win_data->ypos = crtc_y;
+	win_data->xsize = actual_w;
+	win_data->ysize = actual_h;
+	win_data->xact = fb->width;
+	win_data->yact = fb->height;
+	win_data->y_vir_stride = fb->pitches[0] / (fb->bits_per_pixel >> 3);
+	win_data->yrgb_addr = gem->paddr + offset;
+	win_data->uv_addr = 0;
+	win_data->alpha_en = false;
+
+	switch (fb->pixel_format) {
+	case DRM_FORMAT_ARGB8888:
+		win_data->alpha_en = true;
+	case DRM_FORMAT_XRGB8888:
+		win_data->format = ARGB888;
+		break;
+	case DRM_FORMAT_RGB565:
+		win_data->format = RGB565;
+		win_data->y_vir_stride =
+			((win_data->y_vir_stride * 3) >> 2)
+			+ win_data->y_vir_stride % 3;
+		break;
+	default:
+		DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
+		win_data->alpha_en = false;
+		win_data->format = ARGB888;
+		break;
+	}
+	win_data->enabled = true;
+	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+		      win_data->xpos, win_data->ypos);
+	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+		      win_data->xsize, win_data->ysize);
+	DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->yrgb_addr);
+	DRM_DEBUG_KMS("fb_width = %d, actual_w = %d\n",
+		      fb->width, actual_w);
+
+	lcdc_data->win_commit(ctx->drv, win_data);
+	return 0;
+}
+
+static int rockchip_disable_plane(struct drm_plane *plane)
+{
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+	struct lcdc_context *ctx = to_lcdc_ctx(plane->crtc);
+	struct lcdc_driver_data *lcdc_data = to_lcdc_data(ctx);
+	struct lcdc_win_data *win_data;
+	int win = rockchip_plane->zpos;
+
+	if (win == DEFAULT_ZPOS)
+		win = ctx->default_win;
+
+	if (win < 0 || win >= ZPOS_MAX_NUM)
+		return -EINVAL;
+
+	win_data = lcdc_data->get_win(ctx->drv, win);
+
+	win_data->enabled = false;
+	lcdc_data->win_commit(ctx->drv, win_data);
+
+	return 0;
+}
+
+static void rockchip_plane_destroy(struct drm_plane *plane)
+{
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	rockchip_disable_plane(plane);
+	drm_plane_cleanup(plane);
+	kfree(rockchip_plane);
+}
+
+static int rockchip_plane_set_property(struct drm_plane *plane,
+				       struct drm_property *property,
+				       uint64_t val)
+{
+	struct drm_device *dev = plane->dev;
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	if (property == dev_priv->plane_zpos_property) {
+		rockchip_plane->zpos = val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static struct drm_plane_funcs rockchip_plane_funcs = {
+	.update_plane = rockchip_update_plane,
+	.disable_plane = rockchip_disable_plane,
+	.destroy = rockchip_plane_destroy,
+	.set_property = rockchip_plane_set_property,
+};
+
+static void rockchip_plane_attach_zpos_property(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+	struct drm_property *prop;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	prop = dev_priv->plane_zpos_property;
+	if (!prop) {
+		prop = drm_property_create_range(dev, 0, "zpos", 0,
+						 MAX_PLANE - 1);
+		if (!prop)
+			return;
+
+		dev_priv->plane_zpos_property = prop;
+	}
+
+	drm_object_attach_property(&plane->base, prop, 0);
+}
+
+struct drm_plane *rockchip_plane_init(struct drm_device *dev,
+				      unsigned long possible_crtcs, bool priv)
+{
+	struct rockchip_plane *rockchip_plane;
+	struct rockchip_drm_private *private = dev->dev_private;
+	enum drm_plane_type type;
+	int err;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	rockchip_plane = kzalloc(sizeof(*rockchip_plane), GFP_KERNEL);
+	if (!rockchip_plane)
+		return NULL;
+
+	type = priv ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+	err = drm_universal_plane_init(dev, &rockchip_plane->base,
+				       possible_crtcs, &rockchip_plane_funcs,
+				       formats, ARRAY_SIZE(formats), type);
+	if (err) {
+		DRM_ERROR("failed to initialize plane\n");
+		kfree(rockchip_plane);
+		return NULL;
+	}
+
+	if (priv) {
+		rockchip_plane->base.crtc = private->crtc[0];
+		rockchip_plane->zpos = DEFAULT_ZPOS;
+	} else {
+		rockchip_plane_attach_zpos_property(&rockchip_plane->base);
+	}
+
+	return &rockchip_plane->base;
+}
+
+int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct lcdc_context *ctx = to_lcdc_ctx(private->crtc[pipe]);
+	struct lcdc_driver_data *lcdc_data = to_lcdc_data(ctx);
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	if (ctx->dpms != DRM_MODE_DPMS_ON)
+		return -EPERM;
+
+	lcdc_data->enable_vblank(ctx->drv);
+
+	return 0;
+}
+
+void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct lcdc_context *ctx = to_lcdc_ctx(private->crtc[pipe]);
+	struct lcdc_driver_data *lcdc_data = to_lcdc_data(ctx);
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	if (ctx->dpms != DRM_MODE_DPMS_ON)
+		return;
+
+	lcdc_data->disable_vblank(ctx->drv);
+}
+
+static void rockchip_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct lcdc_context *ctx = to_lcdc_ctx(crtc);
+	struct lcdc_driver_data *lcdc_data = to_lcdc_data(ctx);
+
+	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
+
+	if (ctx->dpms == mode) {
+		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
+		return;
+	}
+
+	if (mode > DRM_MODE_DPMS_ON) {
+		/* wait for the completion of page flip. */
+		if (!wait_event_timeout(ctx->wait_vsync_queue,
+					!atomic_read(&ctx->wait_vsync_event),
+					HZ/20))
+			DRM_DEBUG_KMS("vblank wait timed out.\n");
+		drm_vblank_off(crtc->dev, ctx->pipe);
+	}
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		lcdc_data->dpms(ctx->drv, DRM_MODE_DPMS_ON);
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		lcdc_data->dpms(ctx->drv, DRM_MODE_DPMS_OFF);
+		break;
+	default:
+		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+		break;
+	}
+
+	ctx->dpms = mode;
+}
+
+static void rockchip_drm_crtc_prepare(struct drm_crtc *crtc)
+{
+	/* drm framework doesn't check NULL. */
+}
+
+static bool rockchip_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+					 const struct drm_display_mode *mode,
+					 struct drm_display_mode *adjusted_mode)
+{
+	/* just do dummy now */
+
+	return true;
+}
+
+static int rockchip_drm_crtc_mode_set(struct drm_crtc *crtc,
+				      struct drm_display_mode *mode,
+				      struct drm_display_mode *adjusted_mode,
+				      int x, int y,
+				      struct drm_framebuffer *fb)
+{
+	struct lcdc_context *ctx = to_lcdc_ctx(crtc);
+	struct lcdc_driver_data *lcdc_data = to_lcdc_data(ctx);
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	/* nothing to do if we haven't set the mode yet */
+	if (adjusted_mode->htotal == 0 || adjusted_mode->vtotal == 0)
+		return -EINVAL;
+
+	drm_mode_copy(&ctx->mode, adjusted_mode);
+	lcdc_data->mode_set(ctx->drv, &ctx->mode);
+
+	return 0;
+}
+static int rockchip_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+					   struct drm_framebuffer *old_fb)
+{
+	struct lcdc_context *ctx = to_lcdc_ctx(crtc);
+	unsigned int crtc_w;
+	unsigned int crtc_h;
+	int ret;
+
+	crtc_w = crtc->primary->fb->width - crtc->x;
+	crtc_h = crtc->primary->fb->height - crtc->y;
+
+	ret = rockchip_update_plane(ctx->plane, crtc, crtc->primary->fb, 0, 0,
+				    crtc_w, crtc_h, crtc->x, crtc->y, crtc_w,
+				    crtc_h);
+	if (ret < 0) {
+		DRM_ERROR("fail to update plane\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void rockchip_drm_crtc_commit(struct drm_crtc *crtc)
+{
+	rockchip_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
+					crtc->primary->fb);
+}
+
+static struct drm_crtc_helper_funcs rockchip_crtc_helper_funcs = {
+	.dpms = rockchip_drm_crtc_dpms,
+	.prepare = rockchip_drm_crtc_prepare,
+	.mode_fixup = rockchip_drm_crtc_mode_fixup,
+	.mode_set = rockchip_drm_crtc_mode_set,
+	.mode_set_base = rockchip_drm_crtc_mode_set_base,
+	.commit = rockchip_drm_crtc_commit,
+};
+
+static int rockchip_drm_crtc_page_flip(struct drm_crtc *crtc,
+				       struct drm_framebuffer *fb,
+				       struct drm_pending_vblank_event *event,
+				       uint32_t page_flip_flags)
+{
+	struct drm_device *dev = crtc->dev;
+	struct lcdc_context *ctx = to_lcdc_ctx(crtc);
+	struct drm_framebuffer *old_fb = crtc->primary->fb;
+	unsigned int crtc_w;
+	unsigned int crtc_h;
+	int ret = -EINVAL;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	/* when the page flip is requested, crtc's dpms should be on */
+	if (ctx->dpms > DRM_MODE_DPMS_ON) {
+		DRM_ERROR("failed page flip request.\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->struct_mutex);
+
+	/*
+	 * the pipe from user always is 0 so we can set pipe number
+	 * of current owner to event.
+	 */
+	ret = drm_vblank_get(dev, ctx->pipe);
+	if (ret) {
+		DRM_DEBUG("failed to acquire vblank counter\n");
+		goto out;
+	}
+
+	spin_lock_irq(&dev->event_lock);
+	if (ctx->event) {
+		spin_unlock_irq(&dev->event_lock);
+		DRM_ERROR("already pending flip!\n");
+		ret = -EBUSY;
+		goto out;
+	}
+	ctx->event = event;
+	atomic_set(&ctx->wait_vsync_event, 1);
+	spin_unlock_irq(&dev->event_lock);
+
+	crtc->primary->fb = fb;
+	crtc_w = crtc->primary->fb->width - crtc->x;
+	crtc_h = crtc->primary->fb->height - crtc->y;
+
+	ret = rockchip_update_plane(ctx->plane, crtc, fb, 0, 0, crtc_w, crtc_h,
+				    crtc->x, crtc->y, crtc_w, crtc_h);
+	if (ret) {
+		crtc->primary->fb = old_fb;
+
+		spin_lock_irq(&dev->event_lock);
+		drm_vblank_put(dev, ctx->pipe);
+		atomic_set(&ctx->wait_vsync_event, 0);
+		ctx->event = NULL;
+		spin_unlock_irq(&dev->event_lock);
+
+		goto out;
+	}
+out:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
+
+void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
+{
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+	struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
+	struct lcdc_context *ctx;
+	struct drm_pending_vblank_event *event;
+	unsigned long flags;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	if (!drm_crtc)
+		return;
+
+	ctx = to_lcdc_ctx(drm_crtc);
+	event = ctx->event;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	if (event) {
+		ctx->event = NULL;
+		drm_send_vblank_event(dev, -1, event);
+		drm_vblank_put(dev, pipe);
+		atomic_set(&ctx->wait_vsync_event, 0);
+		wake_up(&ctx->wait_vsync_queue);
+	}
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+void rockchip_drm_crtc_cancel_pending_flip(struct drm_device *dev)
+{
+	int i;
+
+	DRM_DEBUG_KMS("cancle pending flip\n");
+	for (i = 0; i < dev->num_crtcs; i++)
+		rockchip_drm_crtc_finish_pageflip(dev, i);
+}
+
+static void rockchip_drm_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct lcdc_context *ctx = to_lcdc_ctx(crtc);
+	struct rockchip_drm_private *private = crtc->dev->dev_private;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	private->crtc[ctx->pipe] = NULL;
+
+	drm_crtc_cleanup(crtc);
+}
+
+static struct drm_crtc_funcs rockchip_crtc_funcs = {
+	.set_config = drm_crtc_helper_set_config,
+	.page_flip = rockchip_drm_crtc_page_flip,
+	.destroy = rockchip_drm_crtc_destroy,
+};
+
+void lcdc_vsync_event_handler(struct device *dev)
+{
+	struct drm_pending_vblank_event *event;
+	struct lcdc_context *ctx = dev_get_drvdata(dev);
+	struct drm_device *drm_dev;
+	unsigned long flags;
+
+	DRM_DEBUG_KMS("LINE[%d]\n", __LINE__);
+	/* check the crtc is detached already from encoder */
+	if (ctx && (ctx->pipe < 0 || !ctx->drm_dev))
+		return;
+
+	drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+
+	event = ctx->event;
+	drm_dev = ctx->drm_dev;
+
+	spin_lock_irqsave(&drm_dev->event_lock, flags);
+
+	if (event) {
+		ctx->event = NULL;
+		drm_send_vblank_event(drm_dev, -1, event);
+		drm_vblank_put(drm_dev, ctx->pipe);
+		atomic_set(&ctx->wait_vsync_event, 0);
+		wake_up(&ctx->wait_vsync_queue);
+	}
+
+	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+}
+
+static int lcdc_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm_dev = data;
+	struct rockchip_drm_private *private = drm_dev->dev_private;
+	struct lcdc_context *ctx = dev_get_drvdata(dev);
+	struct drm_crtc *crtc;
+
+	ctx->drm_dev = drm_dev;
+
+	ctx->pipe = rockchip_drm_pipe_get(dev);
+	ctx->dpms = DRM_MODE_DPMS_OFF;
+	crtc = &ctx->crtc;
+
+	private->crtc[ctx->pipe] = crtc;
+	ctx->plane = rockchip_plane_init(drm_dev, 1 << ctx->pipe, true);
+	drm_crtc_init_with_planes(drm_dev, crtc, ctx->plane, NULL, &rockchip_crtc_funcs);
+	drm_crtc_helper_add(crtc, &rockchip_crtc_helper_funcs);
+
+	/*
+	 * enable drm irq mode.
+	 * - with irq_enabled = true, we can use the vblank feature.
+	 *
+	 * P.S. note that we wouldn't use drm irq handler but
+	 *      just specific driver own one instead because
+	 *      drm framework supports only one irq handler.
+	 */
+	drm_dev->irq_enabled = true;
+
+	/*
+	 * with vblank_disable_allowed = true, vblank interrupt will be disabled
+	 * by drm timer once a current process gives up ownership of
+	 * vblank event.(after drm_vblank_put function is called)
+	 */
+	drm_dev->vblank_disable_allowed = true;
+
+	return 0;
+}
+
+static void lcdc_unbind(struct device *dev, struct device *master,
+			void *data)
+{	struct drm_device *drm_dev = data;
+	struct rockchip_drm_private *private = drm_dev->dev_private;
+	struct lcdc_context *ctx = dev_get_drvdata(dev);
+	struct drm_crtc *crtc = &ctx->crtc;
+
+	drm_crtc_cleanup(crtc);
+	private->crtc[ctx->pipe] = NULL;
+}
+
+static const struct component_ops lcdc_component_ops = {
+	.bind = lcdc_bind,
+	.unbind = lcdc_unbind,
+};
+
+static int lcdc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lcdc_context *ctx;
+	struct lcdc_driver *lcdc_drv;
+	struct lcdc_driver_data *lcdc_data = drm_lcdc_get_driver_data(pdev);
+	int ret = -EINVAL;
+
+	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	if (!(lcdc_data->num_win && lcdc_data->init &&
+	      lcdc_data->deinit && lcdc_data->dpms &&
+	      lcdc_data->mode_set && lcdc_data->enable_vblank &&
+	      lcdc_data->disable_vblank &&
+	      lcdc_data->win_commit)) {
+		DRM_ERROR("lcdc driver ops is Incomplete\n");
+		return -EINVAL;
+	}
+	lcdc_drv = lcdc_data->init(pdev);
+	if (!lcdc_drv)
+		return -EINVAL;
+
+	lcdc_drv->data = lcdc_data;
+	ret = rockchip_drm_component_add(&pdev->dev, ROCKCHIP_DEVICE_TYPE_CRTC,
+					 ROCKCHIP_DISPLAY_TYPE_LCD, ctx);
+	if (ret)
+		goto err_deinit_lcdc;
+
+	ctx->dev = dev;
+	ctx->default_win = ZPOS_DEFAULT_WIN;
+
+	ctx->drv = lcdc_drv;
+
+	init_waitqueue_head(&ctx->wait_vsync_queue);
+	atomic_set(&ctx->wait_vsync_event, 0);
+
+	platform_set_drvdata(pdev, ctx);
+
+	pm_runtime_enable(&pdev->dev);
+
+	ret = component_add(&pdev->dev, &lcdc_component_ops);
+	if (ret)
+		goto err_disable_pm_runtime;
+
+	return ret;
+
+err_disable_pm_runtime:
+	pm_runtime_disable(dev);
+	rockchip_drm_component_del(dev, ROCKCHIP_DEVICE_TYPE_CRTC);
+err_deinit_lcdc:
+	lcdc_data->deinit(ctx->drv);
+	return ret;
+}
+
+static int lcdc_remove(struct platform_device *pdev)
+{
+	pm_runtime_disable(&pdev->dev);
+
+	component_del(&pdev->dev, &lcdc_component_ops);
+	rockchip_drm_component_del(&pdev->dev, ROCKCHIP_DEVICE_TYPE_CRTC);
+
+	return 0;
+}
+
+struct platform_driver rockchip_lcdc_platform_driver = {
+	.probe = lcdc_probe,
+	.remove = lcdc_remove,
+	.driver = {
+		.name = "rockchip-lcdc",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(lcdc_driver_dt_match),
+	},
+};
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_lcdc.h b/drivers/gpu/drm/rockchip/rockchip_drm_lcdc.h
new file mode 100644
index 0000000..0a0f9c2
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_lcdc.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao@rock-chips.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_DRM_LCDC_H_
+#define _ROCKCHIP_DRM_LCDC_H_
+#include <linux/platform_device.h>
+#include <drm/drm_crtc.h>
+
+#include "rockchip_drm_drv.h"
+
+enum {
+	ZPOS_DEFAULT_WIN = 0,
+	ZPOS_CURSOR_WIN,
+	ZPOS_MAX_NUM,
+	ZPOS_UNUSED_WIN
+};
+
+enum data_format {
+	ARGB888 = 0,
+	RGB888,
+	RGB565,
+	YUV420 = 4,
+	YUV422,
+	YUV444,
+	XRGB888,
+	XBGR888,
+	ABGR888,
+	YUV420_A = 10,
+	YUV422_A,
+	YUV444_A
+};
+
+struct lcdc_win_data {
+	int zpos;
+	int id;
+	enum data_format format;
+	u32 xact;
+	u32 yact;
+	u32 xsize;
+	u32 ysize;
+	u32 xpos;
+	u32 ypos;
+	u32 y_vir_stride;
+	u32 uv_vir_stride;
+	bool alpha_en;
+	bool enabled;
+	bool resume;
+
+	dma_addr_t yrgb_addr;
+	dma_addr_t uv_addr;
+
+	int dsp_stx;
+	int dsp_sty;
+	/* win sel layer */
+	int z_order;
+	u8 fmt_cfg;
+	u8 fmt_10;
+	u8 swap_rb;
+	u32 reserved;
+	u32 area_num;
+	u32 scale_yrgb_x;
+	u32 scale_yrgb_y;
+	u32 scale_cbcr_x;
+	u32 scale_cbcr_y;
+	bool support_3d;
+
+	u8 win_lb_mode;
+
+	u8 bic_coe_el;
+	/* h 01:scale up ;10:down */
+	u8 yrgb_hor_scl_mode;
+	/* v 01:scale up ;10:down */
+	u8 yrgb_ver_scl_mode;
+	/* h scale down mode */
+	u8 yrgb_hsd_mode;
+	/* v scale up mode */
+	u8 yrgb_vsu_mode;
+	/* v scale down mode */
+	u8 yrgb_vsd_mode;
+	u8 cbr_hor_scl_mode;
+	u8 cbr_ver_scl_mode;
+	u8 cbr_hsd_mode;
+	u8 cbr_vsu_mode;
+	u8 cbr_vsd_mode;
+	u8 vsd_yrgb_gt4;
+	u8 vsd_yrgb_gt2;
+	u8 vsd_cbr_gt4;
+	u8 vsd_cbr_gt2;
+
+	u32 alpha_mode;
+	u32 g_alpha_val;
+	u32 color_key_val;
+};
+
+struct lcdc_driver_data {
+	int num_win;
+	struct lcdc_driver * (*init)(struct platform_device *pdev);
+	void (*deinit)(struct lcdc_driver *drv);
+	void (*dpms)(struct lcdc_driver *drv, int mode);
+	void (*mode_set)(struct lcdc_driver *drv,
+			 struct drm_display_mode *mode);
+	void (*enable_vblank)(struct lcdc_driver *drv);
+	void (*disable_vblank)(struct lcdc_driver *drv);
+	struct lcdc_win_data * (*get_win)(struct lcdc_driver *drv, int zpos);
+	void (*win_commit)(struct lcdc_driver *drv,
+			   struct lcdc_win_data *win);
+};
+
+struct lcdc_driver {
+	int id;
+
+	struct lcdc_driver_data *data;
+};
+
+
+void lcdc_vsync_event_handler(struct device *dev);
+#ifdef CONFIG_LCDC_RK3288
+extern struct lcdc_driver_data rockchip_rk3288_lcdc;
+#endif
+#endif /* _ROCKCHIP_DRM_LCDC_H_ */
diff --git a/include/uapi/drm/rockchip_drm.h b/include/uapi/drm/rockchip_drm.h
new file mode 100644
index 0000000..1b567f7
--- /dev/null
+++ b/include/uapi/drm/rockchip_drm.h
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright (c) Fuzhou Rockchip Electronics Co.Ltd
+ * Authors:
+ *       mark yao <yzq@rock-chips.com>
+ *
+ * base on exynos_drm.h
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _UAPI_ROCKCHIP_DRM_H_
+#define _UAPI_ROCKCHIP_DRM_H_
+
+#include <drm/drm.h>
+
+/**
+ * User-desired buffer creation information structure.
+ *
+ * @size: user-desired memory allocation size.
+ *     - this size value would be page-aligned internally.
+ * @flags: user request for setting memory type or cache attributes.
+ * @handle: returned a handle to created gem object.
+ *     - this handle will be set by gem module of kernel side.
+ */
+struct drm_rockchip_gem_create {
+	uint64_t size;
+	unsigned int flags;
+	unsigned int handle;
+};
+
+/**
+ * A structure for getting buffer offset.
+ *
+ * @handle: a pointer to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @offset: relatived offset value of the memory region allocated.
+ *     - this value should be set by user.
+ */
+struct drm_rockchip_gem_map_off {
+	unsigned int handle;
+	unsigned int pad;
+	uint64_t offset;
+};
+
+/**
+ * A structure for mapping buffer.
+ *
+ * @handle: a handle to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @size: memory size to be mapped.
+ * @mapped: having user virtual address mmaped.
+ *      - this variable would be filled by rockchip gem module
+ *      of kernel side with user virtual address which is allocated
+ *      by do_mmap().
+ */
+struct drm_rockchip_gem_mmap {
+	unsigned int handle;
+	unsigned int pad;
+	uint64_t size;
+	uint64_t mapped;
+};
+
+/**
+ * A structure to gem information.
+ *
+ * @handle: a handle to gem object created.
+ * @flags: flag value including memory type and cache attribute and
+ *      this value would be set by driver.
+ * @size: size to memory region allocated by gem and this size would
+ *      be set by driver.
+ */
+struct drm_rockchip_gem_info {
+	unsigned int handle;
+	unsigned int flags;
+	uint64_t size;
+};
+
+/* memory type definitions. */
+enum e_drm_rockchip_gem_mem_type {
+	/* non-cachable mapping and used as default. */
+	ROCKCHIP_BO_NONCACHABLE = 0 << 0,
+	/* cachable mapping. */
+	ROCKCHIP_BO_CACHABLE = 1 << 0,
+	/* write-combine mapping. */
+	ROCKCHIP_BO_WC = 1 << 1,
+	ROCKCHIP_BO_MASK = ROCKCHIP_BO_CACHABLE | ROCKCHIP_BO_WC
+};
+
+#define DRM_ROCKCHIP_GEM_CREATE		0x00
+#define DRM_ROCKCHIP_GEM_MAP_OFFSET	0x01
+#define DRM_ROCKCHIP_GEM_MMAP		0x02
+/* Reserved 0x03 ~ 0x05 for rockchip specific gem ioctl */
+#define DRM_ROCKCHIP_GEM_GET		0x04
+
+#define DRM_IOCTL_ROCKCHIP_GEM_CREATE	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_CREATE, struct drm_rockchip_gem_create)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_MAP_OFFSET, struct drm_rockchip_gem_map_off)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_MMAP	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_MMAP, struct drm_rockchip_gem_mmap)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_GET	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_GET, struct drm_rockchip_gem_info)
+#endif /* _UAPI_ROCKCHIP_DRM_H_ */
-- 
1.7.9.5



^ permalink raw reply related

* Re: [REVIEW][PATCH 2/4] proc: Implement /proc/thread-self to point at the directory of the current thread
From: Serge Hallyn @ 2014-08-06 18:32 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-api-u79uwXL29TY76Z2rM5mHXA, Linux Containers,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Michael Kerrisk (man-pages),
	linux-fsdevel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <871tsttr4u.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>

Quoting Eric W. Biederman (ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org):
> > Hi Eric,
> >
> > I've not had a chance to test these, but apart from two trivial
> > comments below these look good to me, and I appreciate the feature.
> > So with the two fixes (if needed),
> >
> > Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
> 
> >> +static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
> >> +			      int buflen)
> >> +{
> >> +	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
> >> +	pid_t tgid = task_tgid_nr_ns(current, ns);
> >> +	pid_t pid = task_pid_nr_ns(current, ns);
> >> +	char tmp[PROC_NUMBUF + 6 + PROC_NUMBUF];
> >
> > In the extreme case you're not adding space for a \0 ?  (Unless
> > PROC_NUMBUF includes that)
> 
> PROC_NUMBUF has enough space for a sign for the maximum of 10 digits
> for a newline and a terminating \0.  So yes PROC_NUMBUF includes the
> space for a terminating \0.

Ah, I see it's 13.  Sounds good then, thanks.

^ permalink raw reply

* Re: [REVIEW][PATCH 2/4] proc: Implement /proc/thread-self to point at the directory of the current thread
From: Eric W. Biederman @ 2014-08-06 18:22 UTC (permalink / raw)
  To: Serge E. Hallyn
  Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Linux Containers,
	Michael Kerrisk (man-pages), linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20140806143500.GA23127-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>

> Hi Eric,
>
> I've not had a chance to test these, but apart from two trivial
> comments below these look good to me, and I appreciate the feature.
> So with the two fixes (if needed),
>
> Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>

>> +static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
>> +			      int buflen)
>> +{
>> +	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
>> +	pid_t tgid = task_tgid_nr_ns(current, ns);
>> +	pid_t pid = task_pid_nr_ns(current, ns);
>> +	char tmp[PROC_NUMBUF + 6 + PROC_NUMBUF];
>
> In the extreme case you're not adding space for a \0 ?  (Unless
> PROC_NUMBUF includes that)

PROC_NUMBUF has enough space for a sign for the maximum of 10 digits
for a newline and a terminating \0.  So yes PROC_NUMBUF includes the
space for a terminating \0.

Eric

^ permalink raw reply

* Re: [REVIEW][PATCH 2/4] proc: Implement /proc/thread-self to point at the directory of the current thread
From: Serge E. Hallyn @ 2014-08-06 14:35 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA, Linux Containers,
	Michael Kerrisk (man-pages), linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <87bns5cakh.fsf-JOvCrm2gF+uungPnsOpG7nhyD016LWXt@public.gmane.org>

Quoting Eric W. Biederman (ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org):
> 
> /proc/thread-self is derived from /proc/self.  /proc/thread-self
> points to the directory in proc containing information about the
> current thread.
> 
> This funtionality has been missing for a long time, and is tricky to
> implement in userspace as gettid() is not exported by glibc.  More
> importantly this allows fixing defects in /proc/mounts and /proc/net
> where in a threaded application today they wind up being empty files
> when only the initial pthread has exited, causing problems for other
> threads.
> 
> Signed-off-by: "Eric W. Biederman" <ebiederm-aS9lmoZGLiVWk0Htik3J/w@public.gmane.org>

Hi Eric,

I've not had a chance to test these, but apart from two trivial
comments below these look good to me, and I appreciate the feature.
So with the two fixes (if needed),

Acked-by: Serge Hallyn <serge.hallyn-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>

> ---
>  fs/proc/Makefile              |  1 +
>  fs/proc/base.c                | 15 +++++---
>  fs/proc/inode.c               |  7 +++-
>  fs/proc/internal.h            |  6 +++
>  fs/proc/root.c                |  3 ++
>  fs/proc/thread_self.c         | 85 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pid_namespace.h |  1 +
>  7 files changed, 112 insertions(+), 6 deletions(-)
>  create mode 100644 fs/proc/thread_self.c
> 
> diff --git a/fs/proc/Makefile b/fs/proc/Makefile
> index 239493ec718e..7151ea428041 100644
> --- a/fs/proc/Makefile
> +++ b/fs/proc/Makefile
> @@ -23,6 +23,7 @@ proc-y	+= version.o
>  proc-y	+= softirqs.o
>  proc-y	+= namespaces.o
>  proc-y	+= self.o
> +proc-y	+= thread_self.o
>  proc-$(CONFIG_PROC_SYSCTL)	+= proc_sysctl.o
>  proc-$(CONFIG_NET)		+= proc_net.o
>  proc-$(CONFIG_PROC_KCORE)	+= kcore.o
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index ed34e405c6b9..0131156ce7c9 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -2847,7 +2847,7 @@ retry:
>  	return iter;
>  }
>  
> -#define TGID_OFFSET (FIRST_PROCESS_ENTRY + 1)
> +#define TGID_OFFSET (FIRST_PROCESS_ENTRY + 2)
>  
>  /* for the /proc/ directory itself, after non-process stuff has been done */
>  int proc_pid_readdir(struct file *file, struct dir_context *ctx)
> @@ -2859,14 +2859,19 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
>  	if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
>  		return 0;
>  
> -	if (pos == TGID_OFFSET - 1) {
> +	if (pos == TGID_OFFSET - 2) {
>  		struct inode *inode = ns->proc_self->d_inode;
>  		if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
>  			return 0;
> -		iter.tgid = 0;
> -	} else {
> -		iter.tgid = pos - TGID_OFFSET;
> +		ctx->pos = pos = pos + 1;
> +	}
> +	if (pos == TGID_OFFSET - 1) {
> +		struct inode *inode = ns->proc_thread_self->d_inode;
> +		if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))
> +			return 0;
> +		ctx->pos = pos = pos + 1;
>  	}
> +	iter.tgid = pos - TGID_OFFSET;
>  	iter.task = NULL;
>  	for (iter = next_tgid(ns, iter);
>  	     iter.task;
> diff --git a/fs/proc/inode.c b/fs/proc/inode.c
> index 0adbc02d60e3..333080d7a671 100644
> --- a/fs/proc/inode.c
> +++ b/fs/proc/inode.c
> @@ -442,6 +442,7 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
>  int proc_fill_super(struct super_block *s)
>  {
>  	struct inode *root_inode;
> +	int ret;
>  
>  	s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC;
>  	s->s_blocksize = 1024;
> @@ -463,5 +464,9 @@ int proc_fill_super(struct super_block *s)
>  		return -ENOMEM;
>  	}
>  
> -	return proc_setup_self(s);
> +	ret = proc_setup_self(s);
> +	if (ret) {
> +		return ret;
> +	}
> +	return proc_setup_thread_self(s);
>  }
> diff --git a/fs/proc/internal.h b/fs/proc/internal.h
> index 3ab6d14e71c5..ee04619173b2 100644
> --- a/fs/proc/internal.h
> +++ b/fs/proc/internal.h
> @@ -234,6 +234,12 @@ static inline int proc_net_init(void) { return 0; }
>  extern int proc_setup_self(struct super_block *);
>  
>  /*
> + * proc_thread_self.c
> + */
> +extern int proc_setup_thread_self(struct super_block *);
> +extern void proc_thread_self_init(void);
> +
> +/*
>   * proc_sysctl.c
>   */
>  #ifdef CONFIG_PROC_SYSCTL
> diff --git a/fs/proc/root.c b/fs/proc/root.c
> index 5dbadecb234d..48f1c03bc7ed 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -149,6 +149,8 @@ static void proc_kill_sb(struct super_block *sb)
>  	ns = (struct pid_namespace *)sb->s_fs_info;
>  	if (ns->proc_self)
>  		dput(ns->proc_self);
> +	if (ns->proc_thread_self)
> +		dput(ns->proc_thread_self);
>  	kill_anon_super(sb);
>  	put_pid_ns(ns);
>  }
> @@ -170,6 +172,7 @@ void __init proc_root_init(void)
>  		return;
>  
>  	proc_self_init();
> +	proc_thread_self_init();
>  	proc_symlink("mounts", NULL, "self/mounts");
>  
>  	proc_net_init();
> diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
> new file mode 100644
> index 000000000000..59075b509df3
> --- /dev/null
> +++ b/fs/proc/thread_self.c
> @@ -0,0 +1,85 @@
> +#include <linux/sched.h>
> +#include <linux/namei.h>
> +#include <linux/slab.h>
> +#include <linux/pid_namespace.h>
> +#include "internal.h"
> +
> +/*
> + * /proc/thread_self:
> + */
> +static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
> +			      int buflen)
> +{
> +	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
> +	pid_t tgid = task_tgid_nr_ns(current, ns);
> +	pid_t pid = task_pid_nr_ns(current, ns);
> +	char tmp[PROC_NUMBUF + 6 + PROC_NUMBUF];

In the extreme case you're not adding space for a \0 ?  (Unless
PROC_NUMBUF includes that)

> +	if (!pid)
> +		return -ENOENT;
> +	sprintf(tmp, "%d/task/%d", tgid, pid);
> +	return readlink_copy(buffer, buflen, tmp);
> +}
> +
> +static void *proc_thread_self_follow_link(struct dentry *dentry, struct nameidata *nd)
> +{
> +	struct pid_namespace *ns = dentry->d_sb->s_fs_info;
> +	pid_t tgid = task_tgid_nr_ns(current, ns);
> +	pid_t pid = task_pid_nr_ns(current, ns);
> +	char *name = ERR_PTR(-ENOENT);
> +	if (pid) {
> +		name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);

Same here.

> +		if (!name)
> +			name = ERR_PTR(-ENOMEM);
> +		else
> +			sprintf(name, "%d/task/%d", tgid, pid);
> +	}
> +	nd_set_link(nd, name);
> +	return NULL;
> +}
> +
> +static const struct inode_operations proc_thread_self_inode_operations = {
> +	.readlink	= proc_thread_self_readlink,
> +	.follow_link	= proc_thread_self_follow_link,
> +	.put_link	= kfree_put_link,
> +};
> +
> +static unsigned thread_self_inum;
> +
> +int proc_setup_thread_self(struct super_block *s)
> +{
> +	struct inode *root_inode = s->s_root->d_inode;
> +	struct pid_namespace *ns = s->s_fs_info;
> +	struct dentry *thread_self;
> +
> +	mutex_lock(&root_inode->i_mutex);
> +	thread_self = d_alloc_name(s->s_root, "thread-self");
> +	if (thread_self) {
> +		struct inode *inode = new_inode_pseudo(s);
> +		if (inode) {
> +			inode->i_ino = thread_self_inum;
> +			inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
> +			inode->i_mode = S_IFLNK | S_IRWXUGO;
> +			inode->i_uid = GLOBAL_ROOT_UID;
> +			inode->i_gid = GLOBAL_ROOT_GID;
> +			inode->i_op = &proc_thread_self_inode_operations;
> +			d_add(thread_self, inode);
> +		} else {
> +			dput(thread_self);
> +			thread_self = ERR_PTR(-ENOMEM);
> +		}
> +	} else {
> +		thread_self = ERR_PTR(-ENOMEM);
> +	}
> +	mutex_unlock(&root_inode->i_mutex);
> +	if (IS_ERR(thread_self)) {
> +		pr_err("proc_fill_super: can't allocate /proc/thread_self\n");
> +		return PTR_ERR(thread_self);
> +	}
> +	ns->proc_thread_self = thread_self;
> +	return 0;
> +}
> +
> +void __init proc_thread_self_init(void)
> +{
> +	proc_alloc_inum(&thread_self_inum);
> +}
> diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
> index 7246ef3d4455..1997ffc295a7 100644
> --- a/include/linux/pid_namespace.h
> +++ b/include/linux/pid_namespace.h
> @@ -33,6 +33,7 @@ struct pid_namespace {
>  #ifdef CONFIG_PROC_FS
>  	struct vfsmount *proc_mnt;
>  	struct dentry *proc_self;
> +	struct dentry *proc_thread_self;
>  #endif
>  #ifdef CONFIG_BSD_PROCESS_ACCT
>  	struct bsd_acct_struct *bacct;
> -- 
> 1.9.1
> 
> _______________________________________________
> Containers mailing list
> Containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
> https://lists.linuxfoundation.org/mailman/listinfo/containers

^ permalink raw reply

* Re: [PATCH 1/2] xen: Implement ioctl to restrict privcmd to a specific domain
From: Frediano Ziglio @ 2014-08-06 10:52 UTC (permalink / raw)
  To: David Vrabel
  Cc: Konrad Rzeszutek Wilk, Boris Ostrovsky, linux-kernel, xen-devel,
	linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <53E0DFFE.9090202-Sxgqhf6Nn4DQT0dZR+AlfA@public.gmane.org>

On Tue, 2014-08-05 at 14:45 +0100, David Vrabel wrote:
> On 05/08/14 14:42, Konrad Rzeszutek Wilk wrote:
> > 
> >  - Some of these hypercalls don't have an ABI so we can't depend
> >    on them being stable. How do you want to handle that?
> 
> We are not going any further with this series because of this.
> 
> David

Well, this is partially true. We agree the patches as they are cannot be
accepted however in the long term we'd like to find a solution.

The current ABI from user-space to kernel defined by these patches is
perfectly fine (just two ioctl to restrict event channel/privcmd to a
specific domain).

For the implementation we were looking at different approaches:
- add an additional target field in vcpu structure to restrict to a
target for a particular vCPU with some additional hypercalls (like
multicall) that restrict contained hypercalls to a domain;
- an additional hypercall to do domctl but with restriction (this
probably require less changes to current patches);
- using flask. This looks easy to implement but currently code does not
deals well with vCPUs as labels are attached to domains.

Frediano

^ permalink raw reply

* Re: [PATCH 4/7] locking/rwsem: threshold limited spinning for active readers
From: Waiman Long @ 2014-08-05 18:14 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: Ingo Molnar, Peter Zijlstra, linux-kernel, linux-api, linux-doc,
	Jason Low, Scott J Norton
In-Reply-To: <1407214461.2566.14.camel@buesod1.americas.hpqcorp.net>

On 08/05/2014 12:54 AM, Davidlohr Bueso wrote:
> On Sun, 2014-08-03 at 22:36 -0400, Waiman Long wrote:
>> Even thought only the writers can perform optimistic spinning, there
>> is still a chance that readers may take the lock before a spinning
>> writer can get it. In that case, the owner field will be NULL and the
>> spinning writer can spin indefinitely until its time quantum expires
>> when some lock owning readers are not running.
> Right, now I understand where you were coming from in patch 3/7 ;)
>
>> This patch tries to handle this special case by:
>>   1) setting the owner field to a special value RWSEM_READ_OWNED
>>      to indicate that the current or last owner is a reader.
>>   2) seting a threshold on how many times (currently 100) spinning will
>       ^^setting
>>      be done with active readers before giving up as there is no easy
>>      way to determine if all of them are currently running.
>>
>> By doing so, it tries to strike a balance between giving up too early
>> and losing potential performance gain and wasting too many precious
>> CPU cycles when some lock owning readers are not running.
> That's exactly why these kind of magic things aren't a good thing, much
> less in locking. And other alternatives are much more involved, creating
> more overhead, which can make the whole thing pretty much useless.
>
> Nor does the amount of times trying to spin strike me as the correct
> metric to determine such things. Instead something y cycles or time
> based.

I can make it to be time-based. Still we need some kind of magic number 
of ns of spinning before we give up. Also, it will make the code more 
complicated. Now I am thinking about reduce the threshold to a small 
number, say 16, in addition to whether the sem count is changing to 
decide when to give up. Hopefully, that will reduce the number of 
useless spinning when the readers are running.

> [...]
>>   #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
>> +/*
>> + * The owner field is set to RWSEM_READ_OWNED if the last owner(s) are
>> + * readers. It is not reset until a writer takes over and set it to its
>> + * task structure pointer or NULL when it frees the lock. So a value
>> + * of RWSEM_READ_OWNED doesn't mean it currently has active readers.
>> + */
>> +#define RWSEM_READ_OWNED	((struct task_struct *)-1)
> Looks rather weird...

Overloading pointers with some kind of special value is a technique that 
is also used elsewhere in the kernel.

>
>>   #define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL
>>   #else
>>   #define __RWSEM_OPT_INIT(lockname)
>> diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
>> index 9f71a67..576d4cd 100644
>> --- a/kernel/locking/rwsem-xadd.c
>> +++ b/kernel/locking/rwsem-xadd.c
>> @@ -304,6 +304,11 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem)
>>
>>   #ifdef CONFIG_RWSEM_SPIN_ON_OWNER
>>   /*
>> + * Threshold for optimistic spinning on readers
>> + */
>> +#define RWSEM_READ_SPIN_THRESHOLD	100
> I dislike this for the same reasons they weren't welcomed in spinlocks.
> We don't know how it can impact workloads that have not been tested.

Well, this kind of fixed threshold spinning is actually used in the 
para-virtualized spinlock. Please see the SPIN_THRESHOLD macro in 
arch/x86/include/asm/spinlock.h for more details.

> [...]
>>   static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
>>   {
>>   	struct task_struct *owner;
>>   	bool taken = false;
>> +	int  read_spincnt = 0;
>>
>>   	preempt_disable();
>>
>> @@ -397,8 +409,12 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
>>
>>   	while (true) {
>>   		owner = ACCESS_ONCE(sem->owner);
>> -		if (owner&&  !rwsem_spin_on_owner(sem, owner))
>> +		if (owner == RWSEM_READ_OWNED) {
>> +			if (++read_spincnt>  RWSEM_READ_SPIN_THRESHOLD)
>> +				break;
> This is still a pretty fast-path and is going to affect writers, so we
> really want to keep it un-clobbered.
>
> Thanks,
> Davidlohr
>

When the lock is writer-owned, the only overhead is an additional check 
for (owner == RWSEM_READ_OWNED) which should be negligible compared to 
reading the contended semaphore cacheline. I don't think that it will 
have any performance impact in this case.

-Longman

^ permalink raw reply

* Re: [PATCH 3/7] locking/rwsem: check for active writer/spinner before wakeup
From: Waiman Long @ 2014-08-05 17:56 UTC (permalink / raw)
  To: Jason Low
  Cc: Ingo Molnar, Peter Zijlstra, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, Davidlohr Bueso, Scott J Norton
In-Reply-To: <1407187217.11985.14.camel@j-VirtualBox>

On 08/04/2014 05:20 PM, Jason Low wrote:
> On Sun, 2014-08-03 at 22:36 -0400, Waiman Long wrote:
>> On a highly contended rwsem, spinlock contention due to the slow
>> rwsem_wake() call can be a significant portion of the total CPU cycles
>> used. With writer lock stealing and writer optimistic spinning, there
>> is also a pretty good chance that the lock may have been stolen
>> before the waker wakes up the waiters. The woken tasks, if any,
>> will have to go back to sleep again.
>>
>> This patch adds checking code at the beginning of the rwsem_wake()
>> and __rwsem_do_wake() function to look for spinner and active
>> writer respectively.  The presence of an active writer will abort the
>> wakeup operation.  The presence of a spinner will still allow wakeup
>> operation to proceed as long as the trylock operation succeeds. This
>> strikes a good balance between excessive spinlock contention especially
>> when there are a lot of active readers and a lot of failed fastpath
>> operations because there are tasks waiting in the queue.
>>
>> Signed-off-by: Waiman Long<Waiman.Long-VXdhtT5mjnY@public.gmane.org>
>> ---
>>   include/linux/osq_lock.h    |    5 ++++
>>   kernel/locking/rwsem-xadd.c |   57 ++++++++++++++++++++++++++++++++++++++++++-
>>   2 files changed, 61 insertions(+), 1 deletions(-)
>>
>> diff --git a/include/linux/osq_lock.h b/include/linux/osq_lock.h
>> index 90230d5..79db546 100644
>> --- a/include/linux/osq_lock.h
>> +++ b/include/linux/osq_lock.h
>> @@ -24,4 +24,9 @@ static inline void osq_lock_init(struct optimistic_spin_queue *lock)
>>   	atomic_set(&lock->tail, OSQ_UNLOCKED_VAL);
>>   }
>>
>> +static inline bool osq_has_spinner(struct optimistic_spin_queue *lock)
>> +{
>> +	return atomic_read(&lock->tail) != OSQ_UNLOCKED_VAL;
>> +}
> Like with other locks, should we make this "osq_is_locked"? We can still
> add the rwsem has_spinner() abstractions which makes use of
> osq_is_locked() if we want.
>
>

Yes, that is a good idea. I will make the change in the next version.

-Longman

^ permalink raw reply

* Re: [PATCH 1/7] locking/rwsem: don't resched at the end of optimistic spinning
From: Waiman Long @ 2014-08-05 17:54 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, Davidlohr Bueso, Jason Low,
	Scott J Norton
In-Reply-To: <20140804204824.GT3935@laptop>

On 08/04/2014 04:48 PM, Peter Zijlstra wrote:
> On Mon, Aug 04, 2014 at 02:36:35PM -0400, Waiman Long wrote:
>> On 08/04/2014 03:55 AM, Peter Zijlstra wrote:
>>> On Sun, Aug 03, 2014 at 10:36:16PM -0400, Waiman Long wrote:
>>>> For a fully preemptive kernel, a call to preempt_enable() could
>>>> potentially trigger a task rescheduling event. In the case of rwsem
>>>> optimistic spinning, the task has either gotten the lock or is going
>>>> to sleep soon. So there is no point to do rescheduling here.
>>> Uh what? Why shouldn't we preempt if we've gotten the lock? What if a
>>> FIFO task just woke up?
>> I didn't mean that we shouldn't preempt if there is a higher priority task.
>> I am sure that there will be other preemption points along the way that a
>> higher priority task can take over the CPU. I just want to say that doing it
>> here may not be the best place especially if the task is going to sleep
>> soon.
>>
>> If you think this patch does not make sense, I can remove it as other
>> patches in the set has no dependency on this one.
> Yeah, its actively harmful, you delay preemption by an unspecified
> amount of time in case of the spin-acquire. We've had such bugs in -rt
> and they're not fun.
>
> Basically the only time you should use no_resched is if the very next
> statement is schedule().

Thank for the clarification. I will remove patch 1 from the patch set.

-Longman

^ permalink raw reply

* Re: [PATCH 1/2] xen: Implement ioctl to restrict privcmd to a specific domain
From: David Vrabel @ 2014-08-05 13:45 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk, Frediano Ziglio
  Cc: Boris Ostrovsky, linux-kernel, xen-devel,
	linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20140805134220.GD13057-0iZWjJA6G8GSPmnEAIUT9EEOCMrvLtNR@public.gmane.org>

On 05/08/14 14:42, Konrad Rzeszutek Wilk wrote:
> 
>  - Some of these hypercalls don't have an ABI so we can't depend
>    on them being stable. How do you want to handle that?

We are not going any further with this series because of this.

David

^ permalink raw reply

* Re: [PATCH 1/2] xen: Implement ioctl to restrict privcmd to a specific domain
From: Konrad Rzeszutek Wilk @ 2014-08-05 13:42 UTC (permalink / raw)
  To: Frediano Ziglio
  Cc: xen-devel, Boris Ostrovsky, linux-api, David Vrabel, linux-kernel
In-Reply-To: <1407229819.26842.4.camel@hamster.uk.xensource.com>

On Tue, Aug 05, 2014 at 10:10:19AM +0100, Frediano Ziglio wrote:
> On Mon, 2014-08-04 at 16:26 -0400, Konrad Rzeszutek Wilk wrote:
> > On Thu, Jul 31, 2014 at 02:16:44PM +0100, Frediano Ziglio wrote:
> > > Add a RESTRICT ioctl to /dev/xen/privcmd, which allows privileged commands
> > > file descriptor to be restricted to only working with a particular domain.
> > 
> > I feel I am missing an justification or use case here.
> > 
> 
> Running Qemu in domain0 but not allowing it to mess up with other
> domains.

Ok, so multiple levels of security. That is good.

Comments:
 - Once the restriction is in place, there is only a subset of
   hypercalls you can make. There is no mechanism to dynamically
   adjust it (so say you upgrade Xen to a new version with a new
   toolstack - and - you leave the kernel at its original version).
   One way to solve this is to allow the ioctl to define which
   hypercalls to tie down - but that might be too complex.
   Perhaps there ought to be a version field with the ioctl so that
   if you have a newer toolstack and it supplies a version that
   is mismatched with the kernel - the kernel will fail the operation.
   The toolstack is free to supply the ioctl again, but with an
   older version?

 - Some of these hypercalls don't have an ABI so we can't depend
   on them being stable. How do you want to handle that?

 - Please run the patch through scripts/checkpatch.pl 
   
> 
> Basically our Qemu version is quite restricted (normal user, chroot,
> single domain and others) but still can fully support a virtual machine.

Any ETA on when the patch for using this ioctl will be posted?
> 
> The reason for not using stub domains is mainly for scalability reasons.
> Allocating fixed memory for every Qemu running (not taking into account
> the missing memory sharing) is quite memory consuming. 4gb dom0 can
> support 500 VMs.
> 
> Frediano
> 
> 
> > > 
> > > Signed-off-by: Frediano Ziglio <frediano.ziglio@citrix.com>
> > > ---
> > >  drivers/xen/privcmd.c              |  209 ++++++-
> > >  include/uapi/xen/privcmd.h         |    6 +
> > >  include/xen/interface/domctl.h     | 1090 ++++++++++++++++++++++++++++++++++++
> > >  include/xen/interface/hvm/hvm_op.h |   66 +++
> > >  include/xen/interface/memory.h     |    8 +
> > >  include/xen/interface/xen.h        |    1 +
> > >  6 files changed, 1373 insertions(+), 7 deletions(-)
> > >  create mode 100644 include/xen/interface/domctl.h
> > > 
> > > diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
> > > index 569a13b..c177850 100644
> > > --- a/drivers/xen/privcmd.c
> > > +++ b/drivers/xen/privcmd.c
> > > @@ -32,6 +32,10 @@
> > >  #include <xen/xen.h>
> > >  #include <xen/privcmd.h>
> > >  #include <xen/interface/xen.h>
> > > +#include <xen/interface/sched.h>
> > > +#include <xen/interface/memory.h>
> > > +#include <xen/interface/domctl.h>
> > > +#include <xen/interface/hvm/hvm_op.h>
> > >  #include <xen/features.h>
> > >  #include <xen/page.h>
> > >  #include <xen/xen-ops.h>
> > > @@ -43,24 +47,173 @@ MODULE_LICENSE("GPL");
> > >  
> > >  #define PRIV_VMA_LOCKED ((void *)1)
> > >  
> > > +#define UNRESTRICTED_DOMID ((domid_t)-1)
> > > +
> > >  static int privcmd_vma_range_is_mapped(
> > >                 struct vm_area_struct *vma,
> > >                 unsigned long addr,
> > >                 unsigned long nr_pages);
> > >  
> > > -static long privcmd_ioctl_hypercall(void __user *udata)
> > > +struct privcmd_check_buf {
> > > +	unsigned copy_back;
> > > +	void __user *copy_ptr;
> > > +	union {
> > > +		struct sched_remote_shutdown remote_shutdown;
> > > +		struct xen_memory_exchange mem_exchange;
> > > +		struct xen_domctl domctl;
> > > +		unsigned char buf[1];
> > > +	} u;
> > > +};
> > > +
> > > +static long privcmd_check_hypercall(struct privcmd_hypercall *hypercall,
> > > +				    struct privcmd_check *check,
> > > +				    domid_t restrict_domid)
> > > +{
> > > +#define DOMID_AT(type, field) do { \
> > > +	BUILD_BUG_ON(sizeof(type) > sizeof(check->u)); \
> > > +	BUILD_BUG_ON(sizeof(((type *) 0)->field) != sizeof(domid_t)); \
> > > +	check->copy_back = sizeof(type); \
> > > +	domid_offset = offsetof(type, field); \
> > > +	} while (0)
> > > +
> > > +/* we copy from userspace and replace arguments to avoid unsafe data */
> > > +#define FETCH_ARG(dest, arg_num, size) do { \
> > > +	check->copy_ptr = (void *) (long) hypercall->arg[arg_num]; \
> > > +	if (copy_from_user(dest, check->copy_ptr, size)) \
> > > +		return -EFAULT; \
> > > +	hypercall->arg[arg_num] = (long) dest; \
> > > +	} while (0)
> > > +
> > > +	unsigned domid_offset;
> > > +
> > > +	/* default to invalid so on cases not handled we fail */
> > > +	domid_t domid = UNRESTRICTED_DOMID;
> > > +
> > > +	switch (hypercall->op) {
> > > +	case __HYPERVISOR_sched_op:
> > > +		if (hypercall->arg[0] == SCHEDOP_remote_shutdown) {
> > > +			FETCH_ARG(&check->u.remote_shutdown, 1,
> > > +				  sizeof(check->u.remote_shutdown));
> > > +			domid = check->u.remote_shutdown.domain_id;
> > > +		}
> > > +		break;
> > > +
> > > +	case __HYPERVISOR_domctl:
> > > +		FETCH_ARG(&check->u.domctl, 0, sizeof(check->u.domctl));
> > > +		check->copy_back = sizeof(check->u.domctl);
> > > +		/* avoid to create a domain */
> > > +		if (check->u.domctl.cmd == XEN_DOMCTL_createdomain)
> > > +			return -EACCES;
> > > +		/* limit versions to avoid possible future bigger buffer */
> > > +		if (check->u.domctl.interface_version > XEN_DOMCTL_INTERFACE_VERSION)
> > > +			return -EACCES;
> > > +		domid = check->u.domctl.domain;
> > > +		break;
> > > +
> > > +	case __HYPERVISOR_memory_op:
> > > +		switch (hypercall->arg[0]) {
> > > +		case XENMEM_increase_reservation:
> > > +		case XENMEM_decrease_reservation:
> > > +		case XENMEM_populate_physmap:
> > > +			DOMID_AT(struct xen_memory_reservation, domid);
> > > +			break;
> > > +		case XENMEM_exchange:
> > > +			DOMID_AT(struct xen_memory_exchange, in.domid);
> > > +			break;
> > > +		case XENMEM_current_reservation:
> > > +		case XENMEM_maximum_reservation:
> > > +		case XENMEM_maximum_gpfn:
> > > +			check->copy_back = sizeof(domid);
> > > +			domid_offset = 0;
> > > +			break;
> > > +		case XENMEM_add_to_physmap:
> > > +			DOMID_AT(struct xen_add_to_physmap, domid);
> > > +			break;
> > > +		case XENMEM_set_memory_map:
> > > +			DOMID_AT(struct xen_foreign_memory_map, domid);
> > > +			break;
> > > +		default:
> > > +			return -EACCES;
> > > +		}
> > > +		FETCH_ARG(&check->u, 1, check->copy_back);
> > > +		domid = *((domid_t *) &check->u.buf[domid_offset]);
> > > +
> > > +		/* extra check for XENMEM_exchange, exchange in the same
> > > +		 * domain */
> > > +		if (hypercall->arg[0] == XENMEM_exchange &&
> > > +		    check->u.mem_exchange.in.domid != check->u.mem_exchange.out.domid)
> > > +			return -EACCES;
> > > +		break;
> > > +
> > > +	case __HYPERVISOR_hvm_op:
> > > +		switch (hypercall->arg[0]) {
> > > +		case HVMOP_set_param:
> > > +		case HVMOP_get_param:
> > > +			DOMID_AT(struct xen_hvm_param, domid);
> > > +			break;
> > > +		case HVMOP_set_pci_intx_level:
> > > +			DOMID_AT(struct xen_hvm_set_pci_intx_level, domid);
> > > +			break;
> > > +		case HVMOP_set_isa_irq_level:
> > > +			DOMID_AT(struct xen_hvm_set_isa_irq_level, domid);
> > > +			break;
> > > +		case HVMOP_set_pci_link_route:
> > > +			DOMID_AT(struct xen_hvm_set_pci_link_route, domid);
> > > +			break;
> > > +		case HVMOP_modified_memory:
> > > +			DOMID_AT(struct xen_hvm_modified_memory, domid);
> > > +			break;
> > > +		case HVMOP_set_mem_type:
> > > +			DOMID_AT(struct xen_hvm_set_mem_type, domid);
> > > +			break;
> > > +		case HVMOP_track_dirty_vram:
> > > +			DOMID_AT(struct xen_hvm_track_dirty_vram, domid);
> > > +			break;
> > > +		default:
> > > +			return -EACCES;
> > > +		}
> > > +		FETCH_ARG(&check->u, 1, check->copy_back);
> > > +		domid = *((domid_t *) &check->u.buf[domid_offset]);
> > > +		break;
> > > +	}
> > > +
> > > +	if (domid != restrict_domid)
> > > +		return -EACCES;
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static long privcmd_ioctl_hypercall(void __user *udata,
> > > +				    domid_t restrict_domid)
> > >  {
> > >  	struct privcmd_hypercall hypercall;
> > > +	struct privcmd_check_buf check_buf;
> > >  	long ret;
> > >  
> > > +	check_buf.copy_back = 0;
> > > +	check_buf.copy_ptr = NULL;
> > > +
> > >  	if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
> > >  		return -EFAULT;
> > >  
> > > +	/* we must check domain we are using */
> > > +	if (restrict_domid != UNRESTRICTED_DOMID) {
> > > +		ret = privcmd_check_hypercall(&hypercall, &check_buf,
> > > +					      restrict_domid);
> > > +		if (ret)
> > > +			return ret;
> > > +	}
> > > +
> > >  	ret = privcmd_call(hypercall.op,
> > >  			   hypercall.arg[0], hypercall.arg[1],
> > >  			   hypercall.arg[2], hypercall.arg[3],
> > >  			   hypercall.arg[4]);
> > >  
> > > +	if (check_buf.copy_back && check_buf.copy_ptr && ret >= 0)
> > > +		if (copy_to_user(check_buf.copy_ptr, &check_buf.u,
> > > +				 check_buf.copy_back))
> > > +			ret = -EFAULT;
> > > +
> > >  	return ret;
> > >  }
> > >  
> > > @@ -193,7 +346,7 @@ static int mmap_mfn_range(void *data, void *state)
> > >  	return 0;
> > >  }
> > >  
> > > -static long privcmd_ioctl_mmap(void __user *udata)
> > > +static long privcmd_ioctl_mmap(void __user *udata, domid_t restrict_domid)
> > >  {
> > >  	struct privcmd_mmap mmapcmd;
> > >  	struct mm_struct *mm = current->mm;
> > > @@ -209,6 +362,10 @@ static long privcmd_ioctl_mmap(void __user *udata)
> > >  	if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
> > >  		return -EFAULT;
> > >  
> > > +	if (restrict_domid != UNRESTRICTED_DOMID &&
> > > +	    restrict_domid != mmapcmd.dom)
> > > +		return -EACCES;
> > > +
> > >  	rc = gather_array(&pagelist,
> > >  			  mmapcmd.num, sizeof(struct privcmd_mmap_entry),
> > >  			  mmapcmd.entry);
> > > @@ -367,7 +524,8 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs)
> > >  
> > >  static struct vm_operations_struct privcmd_vm_ops;
> > >  
> > > -static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
> > > +static long privcmd_ioctl_mmap_batch(void __user *udata, int version,
> > > +				     domid_t restrict_domid)
> > >  {
> > >  	int ret;
> > >  	struct privcmd_mmapbatch_v2 m;
> > > @@ -397,6 +555,10 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
> > >  		return -EINVAL;
> > >  	}
> > >  
> > > +	if (restrict_domid != UNRESTRICTED_DOMID &&
> > > +	    restrict_domid != m.dom)
> > > +		return -EACCES;
> > > +
> > >  	nr_pages = m.num;
> > >  	if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
> > >  		return -EINVAL;
> > > @@ -498,27 +660,53 @@ out_unlock:
> > >  	goto out;
> > >  }
> > >  
> > > +static inline domid_t privcmd_get_restrict_domid(const struct file *file)
> > > +{
> > > +	return (domid_t) (long) file->private_data;
> > > +}
> > > +
> > > +static inline void privcmd_set_restrict_domid(struct file *file,
> > > +					      domid_t domid)
> > > +{
> > > +	file->private_data = (void *) (long) domid;
> > > +}
> > > +
> > >  static long privcmd_ioctl(struct file *file,
> > >  			  unsigned int cmd, unsigned long data)
> > >  {
> > >  	int ret = -ENOSYS;
> > >  	void __user *udata = (void __user *) data;
> > > +	domid_t restrict_domid = privcmd_get_restrict_domid(file);
> > >  
> > >  	switch (cmd) {
> > >  	case IOCTL_PRIVCMD_HYPERCALL:
> > > -		ret = privcmd_ioctl_hypercall(udata);
> > > +		ret = privcmd_ioctl_hypercall(udata, restrict_domid);
> > >  		break;
> > >  
> > >  	case IOCTL_PRIVCMD_MMAP:
> > > -		ret = privcmd_ioctl_mmap(udata);
> > > +		ret = privcmd_ioctl_mmap(udata, restrict_domid);
> > >  		break;
> > >  
> > >  	case IOCTL_PRIVCMD_MMAPBATCH:
> > > -		ret = privcmd_ioctl_mmap_batch(udata, 1);
> > > +		ret = privcmd_ioctl_mmap_batch(udata, 1, restrict_domid);
> > >  		break;
> > >  
> > >  	case IOCTL_PRIVCMD_MMAPBATCH_V2:
> > > -		ret = privcmd_ioctl_mmap_batch(udata, 2);
> > > +		ret = privcmd_ioctl_mmap_batch(udata, 2, restrict_domid);
> > > +		break;
> > > +
> > > +	case IOCTL_PRIVCMD_RESTRICT_DOMID: {
> > > +		struct privcmd_restrict_domid prd;
> > > +
> > > +		if (restrict_domid != UNRESTRICTED_DOMID)
> > > +			return -EACCES;
> > > +		if (copy_from_user(&prd, udata, sizeof(prd)))
> > > +			return -EFAULT;
> > > +		if (prd.domid >= DOMID_FIRST_RESERVED)
> > > +			return -EINVAL;
> > > +		privcmd_set_restrict_domid(file, prd.domid);
> > > +		ret = 0;
> > > +		}
> > >  		break;
> > >  
> > >  	default:
> > > @@ -593,10 +781,17 @@ static int privcmd_vma_range_is_mapped(
> > >  				   is_mapped_fn, NULL) != 0;
> > >  }
> > >  
> > > +static int privcmd_open(struct inode *ino, struct file *filp)
> > > +{
> > > +	privcmd_set_restrict_domid(filp, UNRESTRICTED_DOMID);
> > > +	return 0;
> > > +}
> > > +
> > >  const struct file_operations xen_privcmd_fops = {
> > >  	.owner = THIS_MODULE,
> > >  	.unlocked_ioctl = privcmd_ioctl,
> > >  	.mmap = privcmd_mmap,
> > > +	.open = privcmd_open,
> > >  };
> > >  EXPORT_SYMBOL_GPL(xen_privcmd_fops);
> > >  
> > > diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h
> > > index a853168..461a999 100644
> > > --- a/include/uapi/xen/privcmd.h
> > > +++ b/include/uapi/xen/privcmd.h
> > > @@ -73,6 +73,10 @@ struct privcmd_mmapbatch_v2 {
> > >  	int __user *err;  /* array of error codes */
> > >  };
> > >  
> > > +struct privcmd_restrict_domid {
> > > +	domid_t domid;
> > > +};
> > > +
> > >  /*
> > >   * @cmd: IOCTL_PRIVCMD_HYPERCALL
> > >   * @arg: &privcmd_hypercall_t
> > > @@ -94,5 +98,7 @@ struct privcmd_mmapbatch_v2 {
> > >  	_IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
> > >  #define IOCTL_PRIVCMD_MMAPBATCH_V2				\
> > >  	_IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2))
> > > +#define IOCTL_PRIVCMD_RESTRICT_DOMID				\
> > > +	_IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_restrict_domid))
> > >  
> > >  #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
> > > diff --git a/include/xen/interface/domctl.h b/include/xen/interface/domctl.h
> > > new file mode 100644
> > > index 0000000..0668fed
> > > --- /dev/null
> > > +++ b/include/xen/interface/domctl.h
> > > @@ -0,0 +1,1090 @@
> > > +/******************************************************************************
> > > + * domctl.h
> > > + *
> > > + * Domain management operations. For use by node control stack.
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person obtaining a copy
> > > + * of this software and associated documentation files (the "Software"), to
> > > + * deal in the Software without restriction, including without limitation the
> > > + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
> > > + * sell copies of the Software, and to permit persons to whom the Software is
> > > + * furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice shall be included in
> > > + * all copies or substantial portions of the Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> > > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> > > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> > > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> > > + * DEALINGS IN THE SOFTWARE.
> > > + *
> > > + * Copyright (c) 2002-2003, B Dragovic
> > > + * Copyright (c) 2002-2006, K Fraser
> > > + */
> > > +
> > > +#ifndef __XEN_PUBLIC_DOMCTL_H__
> > > +#define __XEN_PUBLIC_DOMCTL_H__
> > > +
> > > +#include "xen.h"
> > > +#include "grant_table.h"
> > > +
> > > +#define XEN_DOMCTL_INTERFACE_VERSION 0x0000000a
> > > +
> > > +#if 1
> > > +/*
> > > + * NB. xen_domctl.domain is an IN/OUT parameter for this operation.
> > > + * If it is specified as zero, an id is auto-allocated and returned.
> > > + */
> > > +/* XEN_DOMCTL_createdomain */
> > > +struct xen_domctl_createdomain {
> > > +	/* IN parameters */
> > > +	uint32_t ssidref;
> > > +	xen_domain_handle_t handle;
> > > + /* Is this an HVM guest (as opposed to a PVH or PV guest)? */
> > > +#define _XEN_DOMCTL_CDF_hvm_guest     0
> > > +#define XEN_DOMCTL_CDF_hvm_guest      (1U<<_XEN_DOMCTL_CDF_hvm_guest)
> > > + /* Use hardware-assisted paging if available? */
> > > +#define _XEN_DOMCTL_CDF_hap           1
> > > +#define XEN_DOMCTL_CDF_hap            (1U<<_XEN_DOMCTL_CDF_hap)
> > > + /* Should domain memory integrity be verifed by tboot during Sx? */
> > > +#define _XEN_DOMCTL_CDF_s3_integrity  2
> > > +#define XEN_DOMCTL_CDF_s3_integrity   (1U<<_XEN_DOMCTL_CDF_s3_integrity)
> > > + /* Disable out-of-sync shadow page tables? */
> > > +#define _XEN_DOMCTL_CDF_oos_off       3
> > > +#define XEN_DOMCTL_CDF_oos_off        (1U<<_XEN_DOMCTL_CDF_oos_off)
> > > + /* Is this a PVH guest (as opposed to an HVM or PV guest)? */
> > > +#define _XEN_DOMCTL_CDF_pvh_guest     4
> > > +#define XEN_DOMCTL_CDF_pvh_guest      (1U<<_XEN_DOMCTL_CDF_pvh_guest)
> > > +	uint32_t flags;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_createdomain);
> > > +
> > > +/* XEN_DOMCTL_getdomaininfo */
> > > +struct xen_domctl_getdomaininfo {
> > > +	/* OUT variables. */
> > > +	domid_t  domain;              /* Also echoed in domctl.domain */
> > > + /* Domain is scheduled to die. */
> > > +#define _XEN_DOMINF_dying     0
> > > +#define XEN_DOMINF_dying      (1U<<_XEN_DOMINF_dying)
> > > + /* Domain is an HVM guest (as opposed to a PV guest). */
> > > +#define _XEN_DOMINF_hvm_guest 1
> > > +#define XEN_DOMINF_hvm_guest  (1U<<_XEN_DOMINF_hvm_guest)
> > > + /* The guest OS has shut down. */
> > > +#define _XEN_DOMINF_shutdown  2
> > > +#define XEN_DOMINF_shutdown   (1U<<_XEN_DOMINF_shutdown)
> > > + /* Currently paused by control software. */
> > > +#define _XEN_DOMINF_paused    3
> > > +#define XEN_DOMINF_paused     (1U<<_XEN_DOMINF_paused)
> > > + /* Currently blocked pending an event.     */
> > > +#define _XEN_DOMINF_blocked   4
> > > +#define XEN_DOMINF_blocked    (1U<<_XEN_DOMINF_blocked)
> > > + /* Domain is currently running.            */
> > > +#define _XEN_DOMINF_running   5
> > > +#define XEN_DOMINF_running    (1U<<_XEN_DOMINF_running)
> > > + /* Being debugged.  */
> > > +#define _XEN_DOMINF_debugged  6
> > > +#define XEN_DOMINF_debugged   (1U<<_XEN_DOMINF_debugged)
> > > +/* domain is PVH */
> > > +#define _XEN_DOMINF_pvh_guest 7
> > > +#define XEN_DOMINF_pvh_guest  (1U<<_XEN_DOMINF_pvh_guest)
> > > + /* XEN_DOMINF_shutdown guest-supplied code.  */
> > > +#define XEN_DOMINF_shutdownmask 255
> > > +#define XEN_DOMINF_shutdownshift 16
> > > +	uint32_t flags;              /* XEN_DOMINF_* */
> > > +	aligned_u64 tot_pages;
> > > +	aligned_u64 max_pages;
> > > +	aligned_u64 outstanding_pages;
> > > +	aligned_u64 shr_pages;
> > > +	aligned_u64 paged_pages;
> > > +	aligned_u64 shared_info_frame; /* GMFN of shared_info struct */
> > > +	aligned_u64 cpu_time;
> > > +	uint32_t nr_online_vcpus;    /* Number of VCPUs currently online. */
> > > +	uint32_t max_vcpu_id;        /* Maximum VCPUID in use by this domain. */
> > > +	uint32_t ssidref;
> > > +	xen_domain_handle_t handle;
> > > +	uint32_t cpupool;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getdomaininfo);
> > > +
> > > +
> > > +/* XEN_DOMCTL_getmemlist */
> > > +struct xen_domctl_getmemlist {
> > > +	/* IN variables. */
> > > +	/* Max entries to write to output buffer. */
> > > +	aligned_u64 max_pfns;
> > > +	/* Start index in guest's page list. */
> > > +	aligned_u64 start_pfn;
> > > +	GUEST_HANDLE(uint64_t) buffer;
> > > +	/* OUT variables. */
> > > +	aligned_u64 num_pfns;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getmemlist);
> > > +
> > > +
> > > +/* XEN_DOMCTL_getpageframeinfo */
> > > +
> > > +#define XEN_DOMCTL_PFINFO_LTAB_SHIFT 28
> > > +#define XEN_DOMCTL_PFINFO_NOTAB   (0x0U<<28)
> > > +#define XEN_DOMCTL_PFINFO_L1TAB   (0x1U<<28)
> > > +#define XEN_DOMCTL_PFINFO_L2TAB   (0x2U<<28)
> > > +#define XEN_DOMCTL_PFINFO_L3TAB   (0x3U<<28)
> > > +#define XEN_DOMCTL_PFINFO_L4TAB   (0x4U<<28)
> > > +#define XEN_DOMCTL_PFINFO_LTABTYPE_MASK (0x7U<<28)
> > > +#define XEN_DOMCTL_PFINFO_LPINTAB (0x1U<<31)
> > > +#define XEN_DOMCTL_PFINFO_XTAB    (0xfU<<28) /* invalid page */
> > > +#define XEN_DOMCTL_PFINFO_XALLOC  (0xeU<<28) /* allocate-only page */
> > > +#define XEN_DOMCTL_PFINFO_BROKEN  (0xdU<<28) /* broken page */
> > > +#define XEN_DOMCTL_PFINFO_LTAB_MASK (0xfU<<28)
> > > +
> > > +struct xen_domctl_getpageframeinfo {
> > > +	/* IN variables. */
> > > +	aligned_u64 gmfn; /* GMFN to query */
> > > +	/* OUT variables. */
> > > +	/* Is the page PINNED to a type? */
> > > +	uint32_t type;         /* see above type defs */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getpageframeinfo);
> > > +
> > > +
> > > +/* XEN_DOMCTL_getpageframeinfo2 */
> > > +struct xen_domctl_getpageframeinfo2 {
> > > +	/* IN variables. */
> > > +	aligned_u64 num;
> > > +	/* IN/OUT variables. */
> > > +	GUEST_HANDLE(uint32_t) array;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getpageframeinfo2);
> > > +
> > > +/* XEN_DOMCTL_getpageframeinfo3 */
> > > +struct xen_domctl_getpageframeinfo3 {
> > > +	/* IN variables. */
> > > +	aligned_u64 num;
> > > +	/* IN/OUT variables. */
> > > +	GUEST_HANDLE(xen_pfn_t) array;
> > > +};
> > > +
> > > +
> > > +/*
> > > + * Control shadow pagetables operation
> > > + */
> > > +/* XEN_DOMCTL_shadow_op */
> > > +
> > > +/* Disable shadow mode. */
> > > +#define XEN_DOMCTL_SHADOW_OP_OFF         0
> > > +
> > > +/* Enable shadow mode (mode contains ORed XEN_DOMCTL_SHADOW_ENABLE_* flags). */
> > > +#define XEN_DOMCTL_SHADOW_OP_ENABLE      32
> > > +
> > > +/* Log-dirty bitmap operations. */
> > > + /* Return the bitmap and clean internal copy for next round. */
> > > +#define XEN_DOMCTL_SHADOW_OP_CLEAN       11
> > > + /* Return the bitmap but do not modify internal copy. */
> > > +#define XEN_DOMCTL_SHADOW_OP_PEEK        12
> > > +
> > > +/* Memory allocation accessors. */
> > > +#define XEN_DOMCTL_SHADOW_OP_GET_ALLOCATION   30
> > > +#define XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION   31
> > > +
> > > +/* Legacy enable operations. */
> > > + /* Equiv. to ENABLE with no mode flags. */
> > > +#define XEN_DOMCTL_SHADOW_OP_ENABLE_TEST       1
> > > + /* Equiv. to ENABLE with mode flag ENABLE_LOG_DIRTY. */
> > > +#define XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY   2
> > > + /* Equiv. to ENABLE with mode flags ENABLE_REFCOUNT and ENABLE_TRANSLATE. */
> > > +#define XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE  3
> > > +
> > > +/* Mode flags for XEN_DOMCTL_SHADOW_OP_ENABLE. */
> > > + /*
> > > +  * Shadow pagetables are refcounted: guest does not use explicit mmu
> > > +  * operations nor write-protect its pagetables.
> > > +  */
> > > +#define XEN_DOMCTL_SHADOW_ENABLE_REFCOUNT  (1 << 1)
> > > + /*
> > > +  * Log pages in a bitmap as they are dirtied.
> > > +  * Used for live relocation to determine which pages must be re-sent.
> > > +  */
> > > +#define XEN_DOMCTL_SHADOW_ENABLE_LOG_DIRTY (1 << 2)
> > > + /*
> > > +  * Automatically translate GPFNs into MFNs.
> > > +  */
> > > +#define XEN_DOMCTL_SHADOW_ENABLE_TRANSLATE (1 << 3)
> > > + /*
> > > +  * Xen does not steal virtual address space from the guest.
> > > +  * Requires HVM support.
> > > +  */
> > > +#define XEN_DOMCTL_SHADOW_ENABLE_EXTERNAL  (1 << 4)
> > > +
> > > +struct xen_domctl_shadow_op_stats {
> > > +	uint32_t fault_count;
> > > +	uint32_t dirty_count;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_shadow_op_stats);
> > > +
> > > +struct xen_domctl_shadow_op {
> > > +	/* IN variables. */
> > > +	uint32_t       op;       /* XEN_DOMCTL_SHADOW_OP_* */
> > > +
> > > +	/* OP_ENABLE */
> > > +	uint32_t       mode;     /* XEN_DOMCTL_SHADOW_ENABLE_* */
> > > +
> > > +	/* OP_GET_ALLOCATION / OP_SET_ALLOCATION */
> > > +	uint32_t       mb;       /* Shadow memory allocation in MB */
> > > +
> > > +	/* OP_PEEK / OP_CLEAN */
> > > +	GUEST_HANDLE(uchar) dirty_bitmap;
> > > +	aligned_u64 pages; /* Size of buffer. Updated with actual size. */
> > > +	struct xen_domctl_shadow_op_stats stats;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_shadow_op);
> > > +
> > > +
> > > +/* XEN_DOMCTL_max_mem */
> > > +struct xen_domctl_max_mem {
> > > +	/* IN variables. */
> > > +	aligned_u64 max_memkb;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_max_mem);
> > > +
> > > +
> > > +/* XEN_DOMCTL_setvcpucontext */
> > > +/* XEN_DOMCTL_getvcpucontext */
> > > +struct xen_domctl_vcpucontext {
> > > +	uint32_t              vcpu;                  /* IN */
> > > +	GUEST_HANDLE(vcpu_guest_context) ctxt; /* IN/OUT */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpucontext);
> > > +
> > > +
> > > +/* XEN_DOMCTL_getvcpuinfo */
> > > +struct xen_domctl_getvcpuinfo {
> > > +	/* IN variables. */
> > > +	uint32_t vcpu;
> > > +	/* OUT variables. */
> > > +	uint8_t  online;         /* currently online (not hotplugged)? */
> > > +	uint8_t  blocked;        /* blocked waiting for an event? */
> > > +	uint8_t  running;        /* currently scheduled on its CPU? */
> > > +	aligned_u64 cpu_time;    /* total cpu time consumed (ns) */
> > > +	uint32_t cpu;            /* current mapping   */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_getvcpuinfo);
> > > +
> > > +#if 0
> > > +/* Get/set the NUMA node(s) with which the guest has affinity with. */
> > > +/* XEN_DOMCTL_setnodeaffinity */
> > > +/* XEN_DOMCTL_getnodeaffinity */
> > > +struct xen_domctl_nodeaffinity {
> > > +	struct xenctl_bitmap nodemap;/* IN */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_nodeaffinity);
> > > +
> > > +
> > > +/* Get/set which physical cpus a vcpu can execute on. */
> > > +/* XEN_DOMCTL_setvcpuaffinity */
> > > +/* XEN_DOMCTL_getvcpuaffinity */
> > > +struct xen_domctl_vcpuaffinity {
> > > +	uint32_t  vcpu;              /* IN */
> > > +	struct xenctl_bitmap cpumap; /* IN/OUT */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpuaffinity);
> > > +#endif
> > > +
> > > +
> > > +/* XEN_DOMCTL_max_vcpus */
> > > +struct xen_domctl_max_vcpus {
> > > +	uint32_t max;           /* maximum number of vcpus */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_max_vcpus);
> > > +
> > > +
> > > +/* XEN_DOMCTL_scheduler_op */
> > > +/* Scheduler types. */
> > > +#define XEN_SCHEDULER_SEDF     4
> > > +#define XEN_SCHEDULER_CREDIT   5
> > > +#define XEN_SCHEDULER_CREDIT2  6
> > > +#define XEN_SCHEDULER_ARINC653 7
> > > +/* Set or get info? */
> > > +#define XEN_DOMCTL_SCHEDOP_putinfo 0
> > > +#define XEN_DOMCTL_SCHEDOP_getinfo 1
> > > +struct xen_domctl_scheduler_op {
> > > +	uint32_t sched_id;  /* XEN_SCHEDULER_* */
> > > +	uint32_t cmd;       /* XEN_DOMCTL_SCHEDOP_* */
> > > +	union {
> > > +		struct xen_domctl_sched_sedf {
> > > +			aligned_u64 period;
> > > +			aligned_u64 slice;
> > > +			aligned_u64 latency;
> > > +			uint32_t extratime;
> > > +			uint32_t weight;
> > > +		} sedf;
> > > +		struct xen_domctl_sched_credit {
> > > +			uint16_t weight;
> > > +			uint16_t cap;
> > > +		} credit;
> > > +		struct xen_domctl_sched_credit2 {
> > > +			uint16_t weight;
> > > +		} credit2;
> > > +	} u;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_scheduler_op);
> > > +
> > > +
> > > +/* XEN_DOMCTL_setdomainhandle */
> > > +struct xen_domctl_setdomainhandle {
> > > +	xen_domain_handle_t handle;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_setdomainhandle);
> > > +
> > > +
> > > +/* XEN_DOMCTL_setdebugging */
> > > +struct xen_domctl_setdebugging {
> > > +	uint8_t enable;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_setdebugging);
> > > +
> > > +
> > > +/* XEN_DOMCTL_irq_permission */
> > > +struct xen_domctl_irq_permission {
> > > +	uint8_t pirq;
> > > +	uint8_t allow_access; /* flag to specify enable/disable of IRQ access */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_irq_permission);
> > > +
> > > +
> > > +/* XEN_DOMCTL_iomem_permission */
> > > +struct xen_domctl_iomem_permission {
> > > +	aligned_u64 first_mfn;/* first page (physical page number) in range */
> > > +	aligned_u64 nr_mfns;  /* number of pages in range (>0) */
> > > +	uint8_t  allow_access;     /* allow (!0) or deny (0) access to range? */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_iomem_permission);
> > > +
> > > +
> > > +/* XEN_DOMCTL_ioport_permission */
> > > +struct xen_domctl_ioport_permission {
> > > +	uint32_t first_port;              /* first port int range */
> > > +	uint32_t nr_ports;                /* size of port range */
> > > +	uint8_t  allow_access;            /* allow or deny access to range? */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ioport_permission);
> > > +
> > > +
> > > +/* XEN_DOMCTL_hypercall_init */
> > > +struct xen_domctl_hypercall_init {
> > > +	aligned_u64  gmfn;           /* GMFN to be initialised */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hypercall_init);
> > > +
> > > +
> > > +/* XEN_DOMCTL_arch_setup */
> > > +#define _XEN_DOMAINSETUP_hvm_guest 0
> > > +#define XEN_DOMAINSETUP_hvm_guest  (1UL<<_XEN_DOMAINSETUP_hvm_guest)
> > > +#define _XEN_DOMAINSETUP_query 1 /* Get parameters (for save)  */
> > > +#define XEN_DOMAINSETUP_query  (1UL<<_XEN_DOMAINSETUP_query)
> > > +#define _XEN_DOMAINSETUP_sioemu_guest 2
> > > +#define XEN_DOMAINSETUP_sioemu_guest  (1UL<<_XEN_DOMAINSETUP_sioemu_guest)
> > > +struct xen_domctl_arch_setup {
> > > +	aligned_u64 flags;  /* XEN_DOMAINSETUP_* */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_arch_setup);
> > > +
> > > +
> > > +/* XEN_DOMCTL_settimeoffset */
> > > +struct xen_domctl_settimeoffset {
> > > +	int32_t  time_offset_seconds; /* applied to domain wallclock time */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_settimeoffset);
> > > +
> > > +/* XEN_DOMCTL_gethvmcontext */
> > > +/* XEN_DOMCTL_sethvmcontext */
> > > +struct xen_domctl_hvmcontext {
> > > +	uint32_t size; /* IN/OUT: size of buffer / bytes filled */
> > > +	GUEST_HANDLE(uchar) buffer; /* IN/OUT: data, or call
> > > +				     * gethvmcontext with NULL
> > > +				     * buffer to get size req'd */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hvmcontext);
> > > +
> > > +
> > > +/* XEN_DOMCTL_set_address_size */
> > > +/* XEN_DOMCTL_get_address_size */
> > > +struct xen_domctl_address_size {
> > > +	uint32_t size;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_address_size);
> > > +
> > > +
> > > +/* XEN_DOMCTL_real_mode_area */
> > > +struct xen_domctl_real_mode_area {
> > > +	uint32_t log; /* log2 of Real Mode Area size */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_real_mode_area);
> > > +
> > > +
> > > +/* XEN_DOMCTL_sendtrigger */
> > > +#define XEN_DOMCTL_SENDTRIGGER_NMI    0
> > > +#define XEN_DOMCTL_SENDTRIGGER_RESET  1
> > > +#define XEN_DOMCTL_SENDTRIGGER_INIT   2
> > > +#define XEN_DOMCTL_SENDTRIGGER_POWER  3
> > > +#define XEN_DOMCTL_SENDTRIGGER_SLEEP  4
> > > +struct xen_domctl_sendtrigger {
> > > +	uint32_t  trigger;  /* IN */
> > > +	uint32_t  vcpu;     /* IN */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_sendtrigger);
> > > +
> > > +
> > > +/* Assign PCI device to HVM guest. Sets up IOMMU structures. */
> > > +/* XEN_DOMCTL_assign_device */
> > > +/* XEN_DOMCTL_test_assign_device */
> > > +/* XEN_DOMCTL_deassign_device */
> > > +struct xen_domctl_assign_device {
> > > +	uint32_t  machine_sbdf;   /* machine PCI ID of assigned device */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_assign_device);
> > > +
> > > +/* Retrieve sibling devices infomation of machine_sbdf */
> > > +/* XEN_DOMCTL_get_device_group */
> > > +struct xen_domctl_get_device_group {
> > > +	uint32_t  machine_sbdf;     /* IN */
> > > +	uint32_t  max_sdevs;        /* IN */
> > > +	uint32_t  num_sdevs;        /* OUT */
> > > +	GUEST_HANDLE(uint32_t)  sdev_array;   /* OUT */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_get_device_group);
> > > +
> > > +/* Pass-through interrupts: bind real irq -> hvm devfn. */
> > > +/* XEN_DOMCTL_bind_pt_irq */
> > > +/* XEN_DOMCTL_unbind_pt_irq */
> > > +enum pt_irq_type_e {
> > > +	PT_IRQ_TYPE_PCI,
> > > +	PT_IRQ_TYPE_ISA,
> > > +	PT_IRQ_TYPE_MSI,
> > > +	PT_IRQ_TYPE_MSI_TRANSLATE,
> > > +};
> > > +struct xen_domctl_bind_pt_irq {
> > > +	uint32_t machine_irq;
> > > +	enum pt_irq_type_e irq_type;
> > > +	uint32_t hvm_domid;
> > > +
> > > +	union {
> > > +		struct {
> > > +			uint8_t isa_irq;
> > > +		} isa;
> > > +		struct {
> > > +			uint8_t bus;
> > > +			uint8_t device;
> > > +			uint8_t intx;
> > > +		} pci;
> > > +		struct {
> > > +			uint8_t gvec;
> > > +			uint32_t gflags;
> > > +			aligned_u64 gtable;
> > > +		} msi;
> > > +	} u;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_bind_pt_irq);
> > > +
> > > +
> > > +/* Bind machine I/O address range -> HVM address range. */
> > > +/* XEN_DOMCTL_memory_mapping */
> > > +#define DPCI_ADD_MAPPING         1
> > > +#define DPCI_REMOVE_MAPPING      0
> > > +struct xen_domctl_memory_mapping {
> > > +	aligned_u64 first_gfn; /* first page (hvm guest phys page) in range */
> > > +	aligned_u64 first_mfn; /* first page (machine page) in range */
> > > +	aligned_u64 nr_mfns;   /* number of pages in range (>0) */
> > > +	uint32_t add_mapping;       /* add or remove mapping */
> > > +	uint32_t padding;           /* padding for 64-bit aligned structure */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_memory_mapping);
> > > +
> > > +
> > > +/* Bind machine I/O port range -> HVM I/O port range. */
> > > +/* XEN_DOMCTL_ioport_mapping */
> > > +struct xen_domctl_ioport_mapping {
> > > +	uint32_t first_gport;     /* first guest IO port*/
> > > +	uint32_t first_mport;     /* first machine IO port */
> > > +	uint32_t nr_ports;        /* size of port range */
> > > +	uint32_t add_mapping;     /* add or remove mapping */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ioport_mapping);
> > > +
> > > +
> > > +/*
> > > + * Pin caching type of RAM space for x86 HVM domU.
> > > + */
> > > +/* XEN_DOMCTL_pin_mem_cacheattr */
> > > +/* Caching types: these happen to be the same as x86 MTRR/PAT type codes. */
> > > +#define XEN_DOMCTL_MEM_CACHEATTR_UC  0
> > > +#define XEN_DOMCTL_MEM_CACHEATTR_WC  1
> > > +#define XEN_DOMCTL_MEM_CACHEATTR_WT  4
> > > +#define XEN_DOMCTL_MEM_CACHEATTR_WP  5
> > > +#define XEN_DOMCTL_MEM_CACHEATTR_WB  6
> > > +#define XEN_DOMCTL_MEM_CACHEATTR_UCM 7
> > > +struct xen_domctl_pin_mem_cacheattr {
> > > +	aligned_u64 start, end;
> > > +	uint32_t type; /* XEN_DOMCTL_MEM_CACHEATTR_* */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_pin_mem_cacheattr);
> > > +
> > > +
> > > +#if 0
> > > +/* XEN_DOMCTL_set_ext_vcpucontext */
> > > +/* XEN_DOMCTL_get_ext_vcpucontext */
> > > +struct xen_domctl_ext_vcpucontext {
> > > +	/* IN: VCPU that this call applies to. */
> > > +	uint32_t         vcpu;
> > > +	/*
> > > +	 * SET: Size of struct (IN)
> > > +	 * GET: Size of struct (OUT, up to 128 bytes)
> > > +	 */
> > > +	uint32_t         size;
> > > +#if defined(__i386__) || defined(__x86_64__)
> > > +	/* SYSCALL from 32-bit mode and SYSENTER callback information. */
> > > +	/* NB. SYSCALL from 64-bit mode is contained in vcpu_guest_context_t */
> > > +	aligned_u64 syscall32_callback_eip;
> > > +	aligned_u64 sysenter_callback_eip;
> > > +	uint16_t         syscall32_callback_cs;
> > > +	uint16_t         sysenter_callback_cs;
> > > +	uint8_t          syscall32_disables_events;
> > > +	uint8_t          sysenter_disables_events;
> > > +#if defined(__GNUC__)
> > > +	union {
> > > +		aligned_u64 mcg_cap;
> > > +		struct hvm_vmce_vcpu vmce;
> > > +	};
> > > +#else
> > > +	struct hvm_vmce_vcpu vmce;
> > > +#endif
> > > +#endif
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_ext_vcpucontext);
> > > +#endif
> > > +
> > > +/*
> > > + * Set the target domain for a domain
> > > + */
> > > +/* XEN_DOMCTL_set_target */
> > > +struct xen_domctl_set_target {
> > > +	domid_t target;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_target);
> > > +
> > > +#if defined(__i386__) || defined(__x86_64__)
> > > +# define XEN_CPUID_INPUT_UNUSED  0xFFFFFFFF
> > > +/* XEN_DOMCTL_set_cpuid */
> > > +struct xen_domctl_cpuid {
> > > +	uint32_t input[2];
> > > +	uint32_t eax;
> > > +	uint32_t ebx;
> > > +	uint32_t ecx;
> > > +	uint32_t edx;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_cpuid);
> > > +#endif
> > > +
> > > +/*
> > > + * Arranges that if the domain suspends (specifically, if it shuts
> > > + * down with code SHUTDOWN_suspend), this event channel will be
> > > + * notified.
> > > + *
> > > + * This is _instead of_ the usual notification to the global
> > > + * VIRQ_DOM_EXC.  (In most systems that pirq is owned by xenstored.)
> > > + *
> > > + * Only one subscription per domain is possible.  Last subscriber
> > > + * wins; others are silently displaced.
> > > + *
> > > + * NB that contrary to the rather general name, it only applies to
> > > + * domain shutdown with code suspend.  Shutdown for other reasons
> > > + * (including crash), and domain death, are notified to VIRQ_DOM_EXC
> > > + * regardless.
> > > + */
> > > +/* XEN_DOMCTL_subscribe */
> > > +struct xen_domctl_subscribe {
> > > +	uint32_t port; /* IN */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_subscribe);
> > > +
> > > +/*
> > > + * Define the maximum machine address size which should be allocated
> > > + * to a guest.
> > > + */
> > > +/* XEN_DOMCTL_set_machine_address_size */
> > > +/* XEN_DOMCTL_get_machine_address_size */
> > > +
> > > +/*
> > > + * Do not inject spurious page faults into this domain.
> > > + */
> > > +/* XEN_DOMCTL_suppress_spurious_page_faults */
> > > +
> > > +/* XEN_DOMCTL_debug_op */
> > > +#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF         0
> > > +#define XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON          1
> > > +struct xen_domctl_debug_op {
> > > +	uint32_t op;   /* IN */
> > > +	uint32_t vcpu; /* IN */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_debug_op);
> > > +
> > > +/*
> > > + * Request a particular record from the HVM context
> > > + */
> > > +/* XEN_DOMCTL_gethvmcontext_partial */
> > > +struct xen_domctl_hvmcontext_partial {
> > > +	uint32_t type;                      /* IN: Type of record required */
> > > +	uint32_t instance;                  /* IN: Instance of that type */
> > > +	GUEST_HANDLE(uchar) buffer;  /* OUT: buffer to write record into */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_hvmcontext_partial);
> > > +
> > > +/* XEN_DOMCTL_disable_migrate */
> > > +struct xen_domctl_disable_migrate {
> > > +	uint32_t disable; /* IN: 1: disable migration and restore */
> > > +};
> > > +
> > > +
> > > +/* XEN_DOMCTL_gettscinfo */
> > > +/* XEN_DOMCTL_settscinfo */
> > > +struct xen_guest_tsc_info {
> > > +	uint32_t tsc_mode;
> > > +	uint32_t gtsc_khz;
> > > +	uint32_t incarnation;
> > > +	uint32_t pad;
> > > +	aligned_u64 elapsed_nsec;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_guest_tsc_info);
> > > +
> > > +struct xen_domctl_tsc_info {
> > > +	GUEST_HANDLE(xen_guest_tsc_info) out_info; /* OUT */
> > > +	struct xen_guest_tsc_info info; /* IN */
> > > +};
> > > +
> > > +/* XEN_DOMCTL_gdbsx_guestmemio      guest mem io */
> > > +struct xen_domctl_gdbsx_memio {
> > > +	/* IN */
> > > +	aligned_u64 pgd3val;/* optional: init_mm.pgd[3] value */
> > > +	aligned_u64 gva;    /* guest virtual address */
> > > +	aligned_u64 uva;    /* user buffer virtual address */
> > > +	uint32_t         len;    /* number of bytes to read/write */
> > > +	uint8_t          gwr;    /* 0 = read from guest. 1 = write to guest */
> > > +	/* OUT */
> > > +	uint32_t         remain; /* bytes remaining to be copied */
> > > +};
> > > +
> > > +/* XEN_DOMCTL_gdbsx_pausevcpu */
> > > +/* XEN_DOMCTL_gdbsx_unpausevcpu */
> > > +struct xen_domctl_gdbsx_pauseunp_vcpu { /* pause/unpause a vcpu */
> > > +	uint32_t         vcpu;         /* which vcpu */
> > > +};
> > > +
> > > +/* XEN_DOMCTL_gdbsx_domstatus */
> > > +struct xen_domctl_gdbsx_domstatus {
> > > +	/* OUT */
> > > +	uint8_t          paused;     /* is the domain paused */
> > > +	uint32_t         vcpu_id;    /* any vcpu in an event? */
> > > +	uint32_t         vcpu_ev;    /* if yes, what event? */
> > > +};
> > > +
> > > +/*
> > > + * Memory event operations
> > > + */
> > > +
> > > +/* XEN_DOMCTL_mem_event_op */
> > > +
> > > +/*
> > > + * Domain memory paging
> > > + * Page memory in and out.
> > > + * Domctl interface to set up and tear down the
> > > + * pager<->hypervisor interface. Use XENMEM_paging_op*
> > > + * to perform per-page operations.
> > > + *
> > > + * The XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE domctl returns several
> > > + * non-standard error codes to indicate why paging could not be enabled:
> > > + * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> > > + * EMLINK - guest has iommu passthrough enabled
> > > + * EXDEV  - guest has PoD enabled
> > > + * EBUSY  - guest has or had paging enabled, ring buffer still active
> > > + */
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING            1
> > > +
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING_ENABLE     0
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING_DISABLE    1
> > > +
> > > +/*
> > > + * Access permissions.
> > > + *
> > > + * As with paging, use the domctl for teardown/setup of the
> > > + * helper<->hypervisor interface.
> > > + *
> > > + * There are HVM hypercalls to set the per-page access permissions of every
> > > + * page in a domain.  When one of these permissions--independent, read,
> > > + * write, and execute--is violated, the VCPU is paused and a memory event
> > > + * is sent with what happened.  (See public/mem_event.h) .
> > > + *
> > > + * The memory event handler can then resume the VCPU and redo the access
> > > + * with a XENMEM_access_op_resume hypercall.
> > > + *
> > > + * The XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE domctl returns several
> > > + * non-standard error codes to indicate why access could not be enabled:
> > > + * ENODEV - host lacks HAP support (EPT/NPT) or HAP is disabled in guest
> > > + * EBUSY  - guest has or had access enabled, ring buffer still active
> > > + */
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS            2
> > > +
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS_ENABLE     0
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS_DISABLE    1
> > > +
> > > +/*
> > > + * Sharing ENOMEM helper.
> > > + *
> > > + * As with paging, use the domctl for teardown/setup of the
> > > + * helper<->hypervisor interface.
> > > + *
> > > + * If setup, this ring is used to communicate failed allocations
> > > + * in the unshare path. XENMEM_sharing_op_resume is used to wake up
> > > + * vcpus that could not unshare.
> > > + *
> > > + * Note that shring can be turned on (as per the domctl below)
> > > + * *without* this ring being setup.
> > > + */
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING           3
> > > +
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING_ENABLE    0
> > > +#define XEN_DOMCTL_MEM_EVENT_OP_SHARING_DISABLE   1
> > > +
> > > +/* Use for teardown/setup of helper<->hypervisor interface for paging,
> > > + * access and sharing.*/
> > > +struct xen_domctl_mem_event_op {
> > > +	uint32_t       op;           /* XEN_DOMCTL_MEM_EVENT_OP_*_* */
> > > +	uint32_t       mode;         /* XEN_DOMCTL_MEM_EVENT_OP_* */
> > > +
> > > +	uint32_t port;              /* OUT: event channel for ring */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_mem_event_op);
> > > +
> > > +/*
> > > + * Memory sharing operations
> > > + */
> > > +/* XEN_DOMCTL_mem_sharing_op.
> > > + * The CONTROL sub-domctl is used for bringup/teardown. */
> > > +#define XEN_DOMCTL_MEM_SHARING_CONTROL          0
> > > +
> > > +struct xen_domctl_mem_sharing_op {
> > > +	uint8_t op; /* XEN_DOMCTL_MEM_SHARING_* */
> > > +
> > > +	union {
> > > +		uint8_t enable;                   /* CONTROL */
> > > +	} u;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_mem_sharing_op);
> > > +
> > > +struct xen_domctl_audit_p2m {
> > > +	/* OUT error counts */
> > > +	uint64_t orphans;
> > > +	uint64_t m2p_bad;
> > > +	uint64_t p2m_bad;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_audit_p2m);
> > > +
> > > +struct xen_domctl_set_virq_handler {
> > > +	uint32_t virq; /* IN */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_virq_handler);
> > > +
> > > +#if defined(__i386__) || defined(__x86_64__)
> > > +/* XEN_DOMCTL_setvcpuextstate */
> > > +/* XEN_DOMCTL_getvcpuextstate */
> > > +struct xen_domctl_vcpuextstate {
> > > +	/* IN: VCPU that this call applies to. */
> > > +	uint32_t         vcpu;
> > > +	/*
> > > +	 * SET: Ignored.
> > > +	 * GET: xfeature support mask of struct (IN/OUT)
> > > +	 * xfeature mask is served as identifications of the saving format
> > > +	 * so that compatible CPUs can have a check on format to decide
> > > +	 * whether it can restore.
> > > +	 */
> > > +	aligned_u64         xfeature_mask;
> > > +	/*
> > > +	 * SET: Size of struct (IN)
> > > +	 * GET: Size of struct (IN/OUT)
> > > +	 */
> > > +	aligned_u64         size;
> > > +	GUEST_HANDLE(uint64_t) buffer;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpuextstate);
> > > +#endif
> > > +
> > > +/* XEN_DOMCTL_set_access_required: sets whether a memory event listener
> > > + * must be present to handle page access events: if false, the page
> > > + * access will revert to full permissions if no one is listening;
> > > + *  */
> > > +struct xen_domctl_set_access_required {
> > > +	uint8_t access_required;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_access_required);
> > > +
> > > +struct xen_domctl_set_broken_page_p2m {
> > > +	aligned_u64 pfn;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_broken_page_p2m);
> > > +
> > > +/*
> > > + * XEN_DOMCTL_set_max_evtchn: sets the maximum event channel port
> > > + * number the guest may use.  Use this limit the amount of resources
> > > + * (global mapping space, xenheap) a guest may use for event channels.
> > > + */
> > > +struct xen_domctl_set_max_evtchn {
> > > +	uint32_t max_port;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_set_max_evtchn);
> > > +
> > > +/*
> > > + * ARM: Clean and invalidate caches associated with given region of
> > > + * guest memory.
> > > + */
> > > +struct xen_domctl_cacheflush {
> > > +	/* IN: page range to flush. */
> > > +	xen_pfn_t start_pfn, nr_pfns;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_cacheflush);
> > > +
> > > +#if defined(__i386__) || defined(__x86_64__)
> > > +struct xen_domctl_vcpu_msr {
> > > +	uint32_t         index;
> > > +	uint32_t         reserved;
> > > +	aligned_u64 value;
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpu_msr);
> > > +
> > > +/*
> > > + * XEN_DOMCTL_set_vcpu_msrs / XEN_DOMCTL_get_vcpu_msrs.
> > > + *
> > > + * Input:
> > > + * - A NULL 'msrs' guest handle is a request for the maximum 'msr_count'.
> > > + * - Otherwise, 'msr_count' is the number of entries in 'msrs'.
> > > + *
> > > + * Output for get:
> > > + * - If 'msr_count' is less than the number Xen needs to write, -ENOBUFS shall
> > > + *   be returned and 'msr_count' updated to reflect the intended number.
> > > + * - On success, 'msr_count' shall indicate the number of MSRs written, which
> > > + *   may be less than the maximum if some are not currently used by the vcpu.
> > > + *
> > > + * Output for set:
> > > + * - If Xen encounters an error with a specific MSR, -EINVAL shall be returned
> > > + *   and 'msr_count' shall be set to the offending index, to aid debugging.
> > > + */
> > > +struct xen_domctl_vcpu_msrs {
> > > +	uint32_t vcpu;                                   /* IN     */
> > > +	uint32_t msr_count;                              /* IN/OUT */
> > > +	GUEST_HANDLE(xen_domctl_vcpu_msr) msrs; /* IN/OUT */
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_vcpu_msrs);
> > > +#endif
> > > +
> > > +/*
> > > + * Return information about the state and running time of a domain.
> > > + * The "domain runstate" is based on the runstates of all the vcpus of the
> > > + * domain (see below).
> > > + * @extra_arg == pointer to domain_runstate_info structure.
> > > + */
> > > +struct xen_domctl_runstate_info {
> > > +	/* VCPU's current state (RUNSTATE_*). */
> > > +	uint32_t      state;
> > > +	uint32_t missed_changes;
> > > +	/* Number of times we missed an update due to contention */
> > > +	/* When was current state entered (system time, ns)? */
> > > +	uint64_t state_entry_time;
> > > +	/*
> > > +	 * Time spent in each RUNSTATE_* (ns). The sum of these times is
> > > +	 * NOT guaranteed not to drift from system time.
> > > +	 */
> > > +	uint64_t time[6];
> > > +};
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_runstate_info);
> > > +
> > > +/* All vcpus are running */
> > > +#define DOMAIN_RUNSTATE_full_run           0
> > > +
> > > +/* All vcpus are runnable (i.e., waiting for cpu) */
> > > +#define DOMAIN_RUNSTATE_full_contention    1
> > > +
> > > +/* Some vcpus are running, some are runnable */
> > > +#define DOMAIN_RUNSTATE_concurrency_hazard 2
> > > +
> > > +/* All vcpus are blocked / offline */
> > > +#define DOMAIN_RUNSTATE_blocked            3
> > > +
> > > +/* Some vpcus are running, some are blocked */
> > > +#define DOMAIN_RUNSTATE_partial_run        4
> > > +
> > > +/* Some vcpus are runnable, some are blocked */
> > > +#define DOMAIN_RUNSTATE_partial_contention 5
> > > +
> > > +struct xen_domctl_corespersocket {
> > > +	uint32_t cores_per_socket;
> > > +};
> > > +
> > > +DEFINE_GUEST_HANDLE_STRUCT(xen_domctl_corespersocket);
> > > +#endif
> > > +
> > > +struct xen_domctl {
> > > +	uint32_t cmd;
> > > +#define XEN_DOMCTL_createdomain                   1
> > > +#define XEN_DOMCTL_destroydomain                  2
> > > +#define XEN_DOMCTL_pausedomain                    3
> > > +#define XEN_DOMCTL_unpausedomain                  4
> > > +#define XEN_DOMCTL_getdomaininfo                  5
> > > +#define XEN_DOMCTL_getmemlist                     6
> > > +#define XEN_DOMCTL_getpageframeinfo               7
> > > +#define XEN_DOMCTL_getpageframeinfo2              8
> > > +#define XEN_DOMCTL_setvcpuaffinity                9
> > > +#define XEN_DOMCTL_shadow_op                     10
> > > +#define XEN_DOMCTL_max_mem                       11
> > > +#define XEN_DOMCTL_setvcpucontext                12
> > > +#define XEN_DOMCTL_getvcpucontext                13
> > > +#define XEN_DOMCTL_getvcpuinfo                   14
> > > +#define XEN_DOMCTL_max_vcpus                     15
> > > +#define XEN_DOMCTL_scheduler_op                  16
> > > +#define XEN_DOMCTL_setdomainhandle               17
> > > +#define XEN_DOMCTL_setdebugging                  18
> > > +#define XEN_DOMCTL_irq_permission                19
> > > +#define XEN_DOMCTL_iomem_permission              20
> > > +#define XEN_DOMCTL_ioport_permission             21
> > > +#define XEN_DOMCTL_hypercall_init                22
> > > +#define XEN_DOMCTL_arch_setup                    23
> > > +#define XEN_DOMCTL_settimeoffset                 24
> > > +#define XEN_DOMCTL_getvcpuaffinity               25
> > > +#define XEN_DOMCTL_real_mode_area                26
> > > +#define XEN_DOMCTL_resumedomain                  27
> > > +#define XEN_DOMCTL_sendtrigger                   28
> > > +#define XEN_DOMCTL_subscribe                     29
> > > +#define XEN_DOMCTL_gethvmcontext                 33
> > > +#define XEN_DOMCTL_sethvmcontext                 34
> > > +#define XEN_DOMCTL_set_address_size              35
> > > +#define XEN_DOMCTL_get_address_size              36
> > > +#define XEN_DOMCTL_assign_device                 37
> > > +#define XEN_DOMCTL_bind_pt_irq                   38
> > > +#define XEN_DOMCTL_memory_mapping                39
> > > +#define XEN_DOMCTL_ioport_mapping                40
> > > +#define XEN_DOMCTL_pin_mem_cacheattr             41
> > > +#define XEN_DOMCTL_set_ext_vcpucontext           42
> > > +#define XEN_DOMCTL_get_ext_vcpucontext           43
> > > +#define XEN_DOMCTL_set_opt_feature               44 /* Obsolete IA64 only */
> > > +#define XEN_DOMCTL_test_assign_device            45
> > > +#define XEN_DOMCTL_set_target                    46
> > > +#define XEN_DOMCTL_deassign_device               47
> > > +#define XEN_DOMCTL_unbind_pt_irq                 48
> > > +#define XEN_DOMCTL_set_cpuid                     49
> > > +#define XEN_DOMCTL_get_device_group              50
> > > +#define XEN_DOMCTL_set_machine_address_size      51
> > > +#define XEN_DOMCTL_get_machine_address_size      52
> > > +#define XEN_DOMCTL_suppress_spurious_page_faults 53
> > > +#define XEN_DOMCTL_debug_op                      54
> > > +#define XEN_DOMCTL_gethvmcontext_partial         55
> > > +#define XEN_DOMCTL_mem_event_op                  56
> > > +#define XEN_DOMCTL_mem_sharing_op                57
> > > +#define XEN_DOMCTL_disable_migrate               58
> > > +#define XEN_DOMCTL_gettscinfo                    59
> > > +#define XEN_DOMCTL_settscinfo                    60
> > > +#define XEN_DOMCTL_getpageframeinfo3             61
> > > +#define XEN_DOMCTL_setvcpuextstate               62
> > > +#define XEN_DOMCTL_getvcpuextstate               63
> > > +#define XEN_DOMCTL_set_access_required           64
> > > +#define XEN_DOMCTL_audit_p2m                     65
> > > +#define XEN_DOMCTL_set_virq_handler              66
> > > +#define XEN_DOMCTL_set_broken_page_p2m           67
> > > +#define XEN_DOMCTL_setnodeaffinity               68
> > > +#define XEN_DOMCTL_getnodeaffinity               69
> > > +#define XEN_DOMCTL_set_max_evtchn                70
> > > +#define XEN_DOMCTL_cacheflush                    71
> > > +#define XEN_DOMCTL_get_vcpu_msrs                 72
> > > +#define XEN_DOMCTL_set_vcpu_msrs                 73
> > > +#define XEN_DOMCTL_get_runstate_info             98
> > > +#define XEN_DOMCTL_gdbsx_guestmemio            1000
> > > +#define XEN_DOMCTL_gdbsx_pausevcpu             1001
> > > +#define XEN_DOMCTL_gdbsx_unpausevcpu           1002
> > > +#define XEN_DOMCTL_gdbsx_domstatus             1003
> > > +#define XEN_DOMCTL_setcorespersocket           4001
> > > +	uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
> > > +	domid_t  domain;
> > > +	union {
> > > +		struct xen_domctl_createdomain      createdomain;
> > > +		struct xen_domctl_getdomaininfo     getdomaininfo;
> > > +		struct xen_domctl_getmemlist        getmemlist;
> > > +		struct xen_domctl_getpageframeinfo  getpageframeinfo;
> > > +		struct xen_domctl_getpageframeinfo2 getpageframeinfo2;
> > > +		struct xen_domctl_getpageframeinfo3 getpageframeinfo3;
> > > +#if 0
> > > +		struct xen_domctl_nodeaffinity      nodeaffinity;
> > > +		struct xen_domctl_vcpuaffinity      vcpuaffinity;
> > > +#endif
> > > +		struct xen_domctl_shadow_op         shadow_op;
> > > +		struct xen_domctl_max_mem           max_mem;
> > > +		struct xen_domctl_vcpucontext       vcpucontext;
> > > +		struct xen_domctl_getvcpuinfo       getvcpuinfo;
> > > +		struct xen_domctl_max_vcpus         max_vcpus;
> > > +		struct xen_domctl_scheduler_op      scheduler_op;
> > > +		struct xen_domctl_setdomainhandle   setdomainhandle;
> > > +		struct xen_domctl_setdebugging      setdebugging;
> > > +		struct xen_domctl_irq_permission    irq_permission;
> > > +		struct xen_domctl_iomem_permission  iomem_permission;
> > > +		struct xen_domctl_ioport_permission ioport_permission;
> > > +		struct xen_domctl_hypercall_init    hypercall_init;
> > > +		struct xen_domctl_arch_setup        arch_setup;
> > > +		struct xen_domctl_settimeoffset     settimeoffset;
> > > +		struct xen_domctl_disable_migrate   disable_migrate;
> > > +		struct xen_domctl_tsc_info          tsc_info;
> > > +		struct xen_domctl_real_mode_area    real_mode_area;
> > > +		struct xen_domctl_hvmcontext        hvmcontext;
> > > +		struct xen_domctl_hvmcontext_partial hvmcontext_partial;
> > > +		struct xen_domctl_address_size      address_size;
> > > +		struct xen_domctl_sendtrigger       sendtrigger;
> > > +		struct xen_domctl_get_device_group  get_device_group;
> > > +		struct xen_domctl_assign_device     assign_device;
> > > +		struct xen_domctl_bind_pt_irq       bind_pt_irq;
> > > +		struct xen_domctl_memory_mapping    memory_mapping;
> > > +		struct xen_domctl_ioport_mapping    ioport_mapping;
> > > +		struct xen_domctl_pin_mem_cacheattr pin_mem_cacheattr;
> > > +#if 0
> > > +		struct xen_domctl_ext_vcpucontext   ext_vcpucontext;
> > > +#endif
> > > +		struct xen_domctl_set_target        set_target;
> > > +		struct xen_domctl_subscribe         subscribe;
> > > +		struct xen_domctl_debug_op          debug_op;
> > > +		struct xen_domctl_mem_event_op      mem_event_op;
> > > +		struct xen_domctl_mem_sharing_op    mem_sharing_op;
> > > +#if defined(__i386__) || defined(__x86_64__)
> > > +		struct xen_domctl_cpuid             cpuid;
> > > +		struct xen_domctl_vcpuextstate      vcpuextstate;
> > > +		struct xen_domctl_vcpu_msrs         vcpu_msrs;
> > > +#endif
> > > +		struct xen_domctl_set_access_required access_required;
> > > +		struct xen_domctl_audit_p2m         audit_p2m;
> > > +		struct xen_domctl_set_virq_handler  set_virq_handler;
> > > +		struct xen_domctl_set_max_evtchn    set_max_evtchn;
> > > +		struct xen_domctl_runstate_info     domain_runstate;
> > > +		struct xen_domctl_corespersocket    corespersocket;
> > > +		struct xen_domctl_gdbsx_memio       gdbsx_guest_memio;
> > > +		struct xen_domctl_set_broken_page_p2m set_broken_page_p2m;
> > > +		struct xen_domctl_cacheflush        cacheflush;
> > > +		struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu;
> > > +		struct xen_domctl_gdbsx_domstatus   gdbsx_domstatus;
> > > +		uint8_t                             pad[128];
> > > +	} u __aligned(8);
> > > +};
> > > +
> > > +#endif /* __XEN_PUBLIC_DOMCTL_H__ */
> > > +
> > > +/*
> > > + * Local variables:
> > > + * mode: C
> > > + * c-file-style: "BSD"
> > > + * c-basic-offset: 4
> > > + * tab-width: 4
> > > + * indent-tabs-mode: nil
> > > + * End:
> > > + */
> > > diff --git a/include/xen/interface/hvm/hvm_op.h b/include/xen/interface/hvm/hvm_op.h
> > > index 956a046..5fb5260 100644
> > > --- a/include/xen/interface/hvm/hvm_op.h
> > > +++ b/include/xen/interface/hvm/hvm_op.h
> > > @@ -32,6 +32,72 @@ struct xen_hvm_param {
> > >  };
> > >  DEFINE_GUEST_HANDLE_STRUCT(xen_hvm_param);
> > >  
> > > +#define HVMOP_set_pci_intx_level  2
> > > +struct xen_hvm_set_pci_intx_level {
> > > +	/* Domain to be updated. */
> > > +	domid_t  domid;
> > > +	/* PCI INTx identification in PCI topology (domain:bus:device:intx). */
> > > +	uint8_t  domain, bus, device, intx;
> > > +	/* Assertion level (0 = unasserted, 1 = asserted). */
> > > +	uint8_t  level;
> > > +};
> > > +
> > > +#define HVMOP_set_isa_irq_level   3
> > > +struct xen_hvm_set_isa_irq_level {
> > > +	/* Domain to be updated. */
> > > +	domid_t  domid;
> > > +	/* ISA device identification, by ISA IRQ (0-15). */
> > > +	uint8_t  isa_irq;
> > > +	/* Assertion level (0 = unasserted, 1 = asserted). */
> > > +	uint8_t  level;
> > > +};
> > > +
> > > +#define HVMOP_set_pci_link_route  4
> > > +struct xen_hvm_set_pci_link_route {
> > > +	/* Domain to be updated. */
> > > +	domid_t  domid;
> > > +	/* PCI link identifier (0-3). */
> > > +	uint8_t  link;
> > > +	/* ISA IRQ (1-15), or 0 (disable link). */
> > > +	uint8_t  isa_irq;
> > > +};
> > > +
> > > +#define HVMOP_track_dirty_vram    6
> > > +struct xen_hvm_track_dirty_vram {
> > > +	/* Domain to be tracked. */
> > > +	domid_t  domid;
> > > +	/* First pfn to track. */
> > > +	aligned_u64 first_pfn;
> > > +	/* Number of pages to track. */
> > > +	aligned_u64 nr;
> > > +	/* OUT variable. */
> > > +	/* Dirty bitmap buffer. */
> > > +	aligned_u64 dirty_bitmap;
> > > +};
> > > +
> > > +#define HVMOP_modified_memory    7
> > > +struct xen_hvm_modified_memory {
> > > +	/* Domain to be updated. */
> > > +	domid_t  domid;
> > > +	/* First pfn. */
> > > +	aligned_u64 first_pfn;
> > > +	/* Number of pages. */
> > > +	aligned_u64 nr;
> > > +};
> > > +
> > > +#define HVMOP_set_mem_type    8
> > > +/* Notify that a region of memory is to be treated in a specific way. */
> > > +struct xen_hvm_set_mem_type {
> > > +	/* Domain to be updated. */
> > > +	domid_t domid;
> > > +	/* Memory type */
> > > +	uint16_t hvmmem_type;
> > > +	/* Number of pages. */
> > > +	uint32_t nr;
> > > +	/* First pfn. */
> > > +	aligned_u64 first_pfn;
> > > +};
> > > +
> > >  /* Hint from PV drivers for pagetable destruction. */
> > >  #define HVMOP_pagetable_dying       9
> > >  struct xen_hvm_pagetable_dying {
> > > diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
> > > index 2ecfe4f..a5fd2e6 100644
> > > --- a/include/xen/interface/memory.h
> > > +++ b/include/xen/interface/memory.h
> > > @@ -248,6 +248,14 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_memory_map);
> > >   */
> > >  extern spinlock_t xen_reservation_lock;
> > >  
> > > +#define XENMEM_set_memory_map       13
> > > +struct xen_foreign_memory_map {
> > > +	domid_t domid;
> > > +	struct xen_memory_map map;
> > > +};
> > > +
> > > +#define XENMEM_maximum_gpfn         14
> > > +
> > >  /*
> > >   * Unmaps the page appearing at a particular GPFN from the specified guest's
> > >   * pseudophysical address space.
> > > diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
> > > index de08213..075cb6f 100644
> > > --- a/include/xen/interface/xen.h
> > > +++ b/include/xen/interface/xen.h
> > > @@ -57,6 +57,7 @@
> > >  #define __HYPERVISOR_event_channel_op     32
> > >  #define __HYPERVISOR_physdev_op           33
> > >  #define __HYPERVISOR_hvm_op               34
> > > +#define __HYPERVISOR_domctl               36
> > >  #define __HYPERVISOR_tmem_op              38
> > >  
> > >  /* Architecture-specific hypercall definitions. */
> > > -- 
> > > 1.9.1
> > > 
> > > 
> 
> 

^ permalink raw reply

* Re: [PATCH 2/3] tty: serial: 8250: Add Mediatek UART driver
From: Alan Cox @ 2014-08-05 13:38 UTC (permalink / raw)
  To: Varka Bhadram
  Cc: Matthias Brugger, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, jslaby-AlSwsSmVLrQ,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	heikki.krogerus-VuQAYsv1563Yd54FQh9/CA,
	paul.gortmaker-CWA4WttNNZF54TAoqtyWWQ,
	asierra-AQeFf1F/bRxBDgjK7y7TUQ, mwelling-EkmVulN54Sk,
	dianders-F7+t8E8rja9g9hUCZPvPmw, m-karicheri2-l0cyMroinI0,
	jschultz-AQeFf1F/bRxBDgjK7y7TUQ, mingo-X9Un+BFzKDI,
	balbi-l0cyMroinI0, heiko-4mtYJXux2i+zQB+pC5nmwQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <53E0C839.3000808-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Tue, 2014-08-05 at 17:34 +0530, Varka Bhadram wrote:
> On 08/05/2014 05:32 PM, Alan Cox wrote:
> > On Tue, 2014-08-05 at 17:25 +0530, Varka Bhadram wrote:
> >> On 08/05/2014 04:24 PM, Matthias Brugger wrote:
> >>
> >> (...)
> >>
> >>> +#include <linux/io.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/serial_8250.h>
> >>> +#include <linux/of_irq.h>
> >>> +#include <linux/of_platform.h>
> >>> +#include <linux/platform_device.h>
> >>> +#include <linux/clk.h>
> >>> +#include <linux/pm_runtime.h>
> >>> +#include "8250.h"
> >>> +
> >> Better if we have includes in alphabetical order..
> >
> > So 8250.h would be first and it wouldn't compile ???
> >
> > Can we stick to serious critiques ?
> 
> The local headers should be at the end of all includes

Which is not alaphetical order

The include ordering does not matter, please stick to actual things that
matter.

^ permalink raw reply

* Re: [PATCH 2/3] tty: serial: 8250: Add Mediatek UART driver
From: Varka Bhadram @ 2014-08-05 12:04 UTC (permalink / raw)
  To: Alan Cox
  Cc: Matthias Brugger, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, jslaby-AlSwsSmVLrQ,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	heikki.krogerus-VuQAYsv1563Yd54FQh9/CA,
	paul.gortmaker-CWA4WttNNZF54TAoqtyWWQ,
	asierra-AQeFf1F/bRxBDgjK7y7TUQ, mwelling-EkmVulN54Sk,
	dianders-F7+t8E8rja9g9hUCZPvPmw, m-karicheri2-l0cyMroinI0,
	jschultz-AQeFf1F/bRxBDgjK7y7TUQ, mingo-X9Un+BFzKDI,
	balbi-l0cyMroinI0, heiko-4mtYJXux2i+zQB+pC5nmwQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1407240147.30675.29.camel-wU3TRTJX3O1FGiH78xh5akvbDziVy8sZEvhb3Hwu1Ks@public.gmane.org>

On 08/05/2014 05:32 PM, Alan Cox wrote:
> On Tue, 2014-08-05 at 17:25 +0530, Varka Bhadram wrote:
>> On 08/05/2014 04:24 PM, Matthias Brugger wrote:
>>
>> (...)
>>
>>> +#include <linux/io.h>
>>> +#include <linux/module.h>
>>> +#include <linux/serial_8250.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include "8250.h"
>>> +
>> Better if we have includes in alphabetical order..
>
> So 8250.h would be first and it wouldn't compile ???
>
> Can we stick to serious critiques ?

The local headers should be at the end of all includes..?


-- 
Regards,
Varka Bhadram.

^ permalink raw reply

* Re: [PATCH 2/3] tty: serial: 8250: Add Mediatek UART driver
From: Alan Cox @ 2014-08-05 12:02 UTC (permalink / raw)
  To: Varka Bhadram
  Cc: Matthias Brugger, linux-kernel, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, rdunlap, gregkh, jslaby, grant.likely,
	heikki.krogerus, paul.gortmaker, asierra, mwelling, dianders,
	m-karicheri2, jschultz, mingo, balbi, heiko, devicetree,
	linux-doc, linux-serial, linux-api
In-Reply-To: <53E0C633.7060600@gmail.com>

On Tue, 2014-08-05 at 17:25 +0530, Varka Bhadram wrote:
> On 08/05/2014 04:24 PM, Matthias Brugger wrote:
> 
> (...)
> 
> > +#include <linux/io.h>
> > +#include <linux/module.h>
> > +#include <linux/serial_8250.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/clk.h>
> > +#include <linux/pm_runtime.h>
> > +#include "8250.h"
> > +
> 
> Better if we have includes in alphabetical order..


So 8250.h would be first and it wouldn't compile ???

Can we stick to serious critiques ?

Alan



^ permalink raw reply

* Re: [PATCH 2/3] tty: serial: 8250: Add Mediatek UART driver
From: Varka Bhadram @ 2014-08-05 11:55 UTC (permalink / raw)
  To: Matthias Brugger, linux-kernel
  Cc: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rdunlap,
	gregkh, jslaby, grant.likely, heikki.krogerus, alan,
	paul.gortmaker, asierra, mwelling, dianders, m-karicheri2,
	jschultz, mingo, balbi, heiko, devicetree, linux-doc,
	linux-serial, linux-api
In-Reply-To: <1407236054-30994-3-git-send-email-matthias.bgg@gmail.com>

On 08/05/2014 04:24 PM, Matthias Brugger wrote:

(...)

> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/serial_8250.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/pm_runtime.h>
> +#include "8250.h"
> +

Better if we have includes in alphabetical order..

> +#define MTK_UART_RATE_FIX 0x0D /* UART Rate Fix Register */
> +
> +struct mtk8250_data {
> +	int			line;
> +	struct clk		*clk;
> +};
> +
> +static void
> +mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
> +{
> +	if (!state)
> +		pm_runtime_get_sync(port->dev);
> +
> +	serial8250_do_pm(port, state, old);
> +
> +	if (state)
> +		pm_runtime_put_sync_suspend(port->dev);
> +}
> +
> +static int mtk8250_probe_of(struct uart_port *p,
> +			   struct mtk8250_data *data)

static int mtk8250_probe_of(struct uart_port *p,
			    struct mtk8250_data *data)

> +{
> +	int err;
> +	struct device_node	*np = p->dev->of_node;
> +
> +	data->clk = of_clk_get(np, 0);
> +	if (IS_ERR(data->clk)) {
> +		pr_warn("Can't get timer clock");

missed terminating new line...

> +		return PTR_ERR(data->clk);
> +	}
> +
> +	err = clk_prepare_enable(data->clk);
> +	if (err) {
> +		pr_warn("Can't prepare clock");

same...

> +		clk_put(data->clk);
> +		return err;
> +	}
> +	p->uartclk = clk_get_rate(data->clk);
> +
> +	return 0;
> +}

(...)

> +static struct platform_driver mtk8250_platform_driver = {
> +	.driver = {
> +		.name		= "mt6577-uart",
> +		.owner		= THIS_MODULE,

No need to update this field...

> +		.pm		= &mtk8250_pm_ops,
> +		.of_match_table	= mtk8250_of_match,
> +	},
> +	.probe			= mtk8250_probe,
> +	.remove			= mtk8250_remove,
> +};
> +module_platform_driver(mtk8250_platform_driver);
>
-- 
Regards,
Varka Bhadram.


^ permalink raw reply

* Re: [PATCH 1/3] tty: serial: 8250: Add new capability for highspeed register
From: One Thousand Gnomes @ 2014-08-05 11:43 UTC (permalink / raw)
  To: Matthias Brugger
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, pawel.moll-5wv7dgnIgG8,
	mark.rutland-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, rdunlap-wEGCiKHe2LqWVfeAwA7xHQ,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r, jslaby-AlSwsSmVLrQ,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A,
	heikki.krogerus-VuQAYsv1563Yd54FQh9/CA,
	alan-VuQAYsv1563Yd54FQh9/CA,
	paul.gortmaker-CWA4WttNNZF54TAoqtyWWQ,
	asierra-AQeFf1F/bRxBDgjK7y7TUQ, mwelling-EkmVulN54Sk,
	dianders-F7+t8E8rja9g9hUCZPvPmw, m-karicheri2-l0cyMroinI0,
	jschultz-AQeFf1F/bRxBDgjK7y7TUQ, mingo-X9Un+BFzKDI,
	balbi-l0cyMroinI0, heiko-4mtYJXux2i+zQB+pC5nmwQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-serial-u79uwXL29TY76Z2rM5mHXA,
	linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1407236054-30994-2-git-send-email-matthias.bgg-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

>  
>  	/*
> +	 * Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS)
> +	 *
> +	 * We need to recalcualte the quot register, as the claculation depends
> +	 * on the vaule in the highspeed register.
> +	 *
> +	 * Some baudrates are not supported by the chip, so we use the next
> +	 * lower rate supported.
> +	 *
> +	 * If highspeed register is set to 3, we need to specify sample count
> +	 * and sample point to increase accuracy. If not, we reset the
> +	 * registers to their default values.
> +	 */

Don't put stuff in the core driver core for your chip specific weirdness,
wrap the termios method with your own in your driver code as a fair
number of other 8250ish drivers do.

If you do that then you don't need to waste a UART CAPS flag and you
don't need to put anything in the core driver code.

Alan

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox