diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 6bcbfe4..1a95fdc 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -88,6 +88,10 @@ SYSCTL_ULONG(_kern, KERN_PS_STRINGS, ps_strings, CTLFLAG_RD, &ps_strings, 0, "")
 static u_long usrstack = USRSTACK;
 SYSCTL_ULONG(_kern, KERN_USRSTACK, usrstack, CTLFLAG_RD, &usrstack, 0, "");
 
+int noexec_stack_enable = 0;
+SYSCTL_INT(_kern, KERN_ENABLE_NOEXEC_STACK, noexec_stack_enable,
+	CTLFLAG_RW, &noexec_stack_enable, 0, "");
+
 u_long ps_arg_cache_limit = PAGE_SIZE / 16;
 SYSCTL_LONG(_kern, OID_AUTO, ps_arg_cache_limit, CTLFLAG_RW, 
     &ps_arg_cache_limit, 0, "");
@@ -843,8 +847,18 @@ exec_new_vmspace(struct image_params *imgp, struct vmspace *vmcopy)
 	}
 
 	/* Allocate a new stack */
+	vm_prot_t prot;
+	if (p->p_flags & P_STACK_NOEXEC) {
+		kprintf("noexec protect\n");
+		prot = VM_PROT_READ | VM_PROT_WRITE;
+	} else {
+		prot = VM_PROT_ALL;
+	}
+	
 	error = vm_map_stack(&vmspace->vm_map, stack_addr, (vm_size_t)maxssiz,
-			     0, VM_PROT_ALL, VM_PROT_ALL, 0);
+			     0,
+			     prot,
+			     prot, 0);
 	if (error)
 		return (error);
 
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 842f3e9..95127f6 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -85,6 +85,8 @@ static struct lwp *lwp_fork(struct lwp *, struct proc *, int flags);
 
 int forksleep; /* Place for fork1() to sleep on. */
 
+extern int noexec_stack_enable;
+
 /*
  * Red-Black tree support for LWPs
  */
@@ -438,6 +440,9 @@ fork1(struct lwp *lp1, int flags, struct proc **procp)
 	if (jailed(p2->p_ucred))
 		p2->p_flags |= P_JAILED;
 
+	if ((p1->p_flags & P_STACK_NOEXEC) || noexec_stack_enable)
+		p2->p_flags |= P_STACK_NOEXEC;
+
 	if (p2->p_args)
 		refcount_acquire(&p2->p_args->ar_ref);
 
diff --git a/sys/platform/pc64/include/pmap.h b/sys/platform/pc64/include/pmap.h
index 84b94eb..4c513c9 100644
--- a/sys/platform/pc64/include/pmap.h
+++ b/sys/platform/pc64/include/pmap.h
@@ -290,7 +290,7 @@ struct pmap {
 	struct lwkt_token	pm_token;
 	long			pm_invgen;
 	uint64_t		pmap_bits[PG_BITS_SIZE];
-	int			protection_codes[PROTECTION_CODES_SIZE];
+	uint64_t		protection_codes[PROTECTION_CODES_SIZE];
 	pt_entry_t		pmap_cache_bits[PAT_INDEX_SIZE];
 	pt_entry_t		pmap_cache_mask;
 	int (*copyinstr)(const void *, void *, size_t, size_t *);
diff --git a/sys/platform/pc64/x86_64/initcpu.c b/sys/platform/pc64/x86_64/initcpu.c
index e3acf4f..29a6c25 100644
--- a/sys/platform/pc64/x86_64/initcpu.c
+++ b/sys/platform/pc64/x86_64/initcpu.c
@@ -42,6 +42,7 @@
 
 #include <vm/vm.h>
 #include <vm/pmap.h>
+#include <cpu/pmap.h>
 
 static int	hw_instruction_sse;
 SYSCTL_INT(_hw, OID_AUTO, instruction_sse, CTLFLAG_RD,
@@ -69,6 +70,7 @@ u_int	cpu_stdext_feature;
 u_int	cpu_thermal_feature;
 u_int	cpu_mwait_feature;
 u_int	cpu_mwait_extemu;
+int	pg_nx = 1;		/* Page NX (no-execute) bit */
 
 /*
  * -1: automatic (enable on h/w, disable on VMs)
@@ -215,9 +217,8 @@ initializecpu(int cpu)
 	if ((amd_feature & AMDID_NX) != 0) {
 		msr = rdmsr(MSR_EFER) | EFER_NXE;
 		wrmsr(MSR_EFER, msr);
-#if 0 /* JG */
-		pg_nx = PG_NX;
-#endif
+		kprintf("XXX enable NX support\n");
+		pg_nx = 1; //X86_PG_NX;
 	}
 	if (cpu_vendor_id == CPU_VENDOR_CENTAUR &&
 	    CPUID_TO_FAMILY(cpu_id) == 0x6 &&
diff --git a/sys/platform/pc64/x86_64/pmap.c b/sys/platform/pc64/x86_64/pmap.c
index c4178a6..b561b71 100644
--- a/sys/platform/pc64/x86_64/pmap.c
+++ b/sys/platform/pc64/x86_64/pmap.c
@@ -149,7 +149,7 @@
  */
 #define pte_prot(m, p)		\
 	(m->protection_codes[p & (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE)])
-static int protection_codes[PROTECTION_CODES_SIZE];
+static uint64_t protection_codes[PROTECTION_CODES_SIZE];
 
 struct pmap kernel_pmap;
 static TAILQ_HEAD(,pmap)	pmap_list = TAILQ_HEAD_INITIALIZER(pmap_list);
@@ -210,7 +210,7 @@ struct msgbuf *msgbufp=NULL;
  * PMAP default PG_* bits. Needed to be able to add
  * EPT/NPT pagetable pmap_bits for the VMM module
  */
-uint64_t pmap_bits_default[] = {
+static const uint64_t pmap_bits_default[] = {
 		REGULAR_PMAP,					/* TYPE_IDX		0 */
 		X86_PG_V,					/* PG_V_IDX		1 */
 		X86_PG_RW,					/* PG_RW_IDX		2 */
@@ -247,6 +247,11 @@ SYSCTL_INT(_machdep, OID_AUTO, pmap_fast_kernel_cpusync, CTLFLAG_RW,
 
 #define DISABLE_PSE
 
+/*
+ * Page no-execute NX flag
+ */
+extern int pg_nx;
+
 /* Standard user access funtions */
 extern int std_copyinstr (const void *udaddr, void *kaddr, size_t len,
     size_t *lencopied);
@@ -4854,6 +4859,7 @@ void
 pmap_page_protect(vm_page_t m, vm_prot_t prot)
 {
 	/* JG NX support? */
+	// XXX: MN NX
 	if ((prot & VM_PROT_WRITE) == 0) {
 		if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
 			/*
@@ -4956,25 +4962,29 @@ static
 void
 i386_protection_init(void)
 {
-	int *kp, prot;
+	uint64_t *kp, prot;
 
-	/* JG NX support may go here; No VM_PROT_EXECUTE ==> set NX bit  */
 	kp = protection_codes;
 	for (prot = 0; prot < PROTECTION_CODES_SIZE; prot++) {
 		switch (prot) {
 		case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
+		case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
 			/*
-			 * Read access is also 0. There isn't any execute bit,
-			 * so just make it readable.
+			 * Read access is also 0.
 			 */
-		case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
+			*kp++ = pg_nx ? X86_PG_NX : 0;
+			break;
+
 		case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
 		case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
 			*kp++ = 0;
 			break;
 		case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
-		case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
 		case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
+			*kp++ = pmap_bits_default[PG_RW_IDX] |
+				(pg_nx ? X86_PG_NX : 0);
+			break;
+		case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
 		case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
 			*kp++ = pmap_bits_default[PG_RW_IDX];
 			break;
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index fe239b3..1cf6752 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -387,7 +387,7 @@ struct	proc {
 #define	P_SIGVTALRM	0x02000000 /* signal SIGVTALRM pending due to itimer */
 #define	P_SIGPROF	0x04000000 /* signal SIGPROF pending due to itimer */
 #define	P_INEXEC	0x08000000 /* Process is in execve(). */
-#define P_UNUSED28	0x10000000
+#define P_STACK_NOEXEC	0x10000000 /* Process has non-executable stack */
 #define	P_UNUSED29	0x20000000
 #define P_XCPU		0x40000000 /* SIGXCPU */
 
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
index 8dff75d..0847917 100644
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -394,6 +394,7 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry);
 #define	KERN_IOV_MAX		35	/* int: value of UIO_MAXIOV */
 #define KERN_MAXPOSIXLOCKSPERUID 36	/* int: max POSIX locks per uid */
 #define KERN_MAXID		37      /* number of valid kern ids */
+#define KERN_ENABLE_NOEXEC_STACK 38	/* int: enable noexec stacks */
 
 #define CTL_KERN_NAMES { \
 	{ 0, 0 }, \
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index 9495215..48965aa 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -3813,10 +3813,19 @@ Retry:
 		addr = end;
 	}
 
+	vm_prot_t prot;
+	if (p->p_flags & P_STACK_NOEXEC) {
+		kprintf("growstack: noexec protect\n");
+		prot = VM_PROT_READ | VM_PROT_WRITE;
+	} else {
+		prot = VM_PROT_ALL;
+	}
+
 	rv = vm_map_insert(map, &count, NULL, NULL,
 			   0, addr, stack_entry->start,
 			   VM_MAPTYPE_NORMAL,
-			   VM_PROT_ALL, VM_PROT_ALL, 0);
+			   prot,
+			   prot, 0);
 
 	/* Adjust the available stack space by the amount we grew. */
 	if (rv == KERN_SUCCESS) {
diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h
index 883ab18..98a421f 100644
--- a/sys/vm/vm_page.h
+++ b/sys/vm/vm_page.h
@@ -319,6 +319,7 @@ extern struct vpgqueues vm_page_queues[PQ_COUNT];
 #define PG_ACTIONLIST	0x00010000	/* lookaside action list present */
 #define PG_SBUSY	0x00020000	/* soft-busy also set */
 #define PG_NEED_COMMIT	0x00040000	/* clean page requires commit */
+#define PG_EXECUTABLE	0x00080000	/* page is executable */
 
 /*
  * Misc constants.
diff --git a/sys/vm/vm_page2.h b/sys/vm/vm_page2.h
index a99cabe..41e83eb 100644
--- a/sys/vm/vm_page2.h
+++ b/sys/vm/vm_page2.h
@@ -307,9 +307,10 @@ vm_page_flash(vm_page_t m)
 static __inline void
 vm_page_protect(vm_page_t m, int prot)
 {
+	// XXX: MN 
 	KKASSERT(m->flags & PG_BUSY);
 	if (prot == VM_PROT_NONE) {
-		if (m->flags & (PG_WRITEABLE|PG_MAPPED)) {
+		if (m->flags & (PG_EXECUTABLE|PG_WRITEABLE|PG_MAPPED)) {
 			pmap_page_protect(m, VM_PROT_NONE);
 			/* PG_WRITEABLE & PG_MAPPED cleared by call */
 		}
