Skip to contentSkip to conversation

arm64 CONFIG_DEBUG_SET_MODULE_RONX support

PATCH Superseded Laura Abbott 4 participants 17 messages Aug 19, 2014 – Sep 12, 2014 arm64

v4 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v4 cover arm64 CONFIG_DEBUG_SET_MODULE_RONX support

Hi,

This is another version of DEBUG_SET_MODULE_RONX support for arm64.

Thanks,
Laura

v4: Switch to one function to do set/clear per suggestion of Will

v3: Addressed comments by Will/Steve

Laura Abbott (2):
arm64: Introduce {set,clear}_pte_bit
arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

 arch/arm64/Kconfig.debug            | 11 +++++
 arch/arm64/include/asm/cacheflush.h |  4 ++
 arch/arm64/include/asm/pgtable.h    | 33 +++++++------
 arch/arm64/mm/Makefile              |  2 +-
 arch/arm64/mm/pageattr.c            | 96 +++++++++++++++++++++++++++++++++++++
 5 files changed, 131 insertions(+), 15 deletions(-)
 create mode 100644 arch/arm64/mm/pageattr.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#1 lore raw

PATCH v4 1/2 arm64: Introduce {set,clear}_pte_bit

It's useful to be able to change individual bits in ptes at times. Introduce functions for this and update existing pte_mk* functions to use these primatives.

---
 arch/arm64/include/asm/pgtable.h | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)
arch/arm64/include/asm/pgtable.h +19 -14
index ffe1ba0..ca41449 100644
@@ -149,46 +149,51 @@ extern struct page *empty_zero_page;
 #define pte_valid_not_user(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 
-static inline pte_t pte_wrprotect(pte_t pte)
+static pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) &= ~PTE_WRITE;
+	pte_val(pte) &= ~pgprot_val(prot);
 	return pte;
 }
 
-static inline pte_t pte_mkwrite(pte_t pte)
+static pte_t set_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) |= PTE_WRITE;
+	pte_val(pte) |= pgprot_val(prot);
 	return pte;
 }
 
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+	return clear_pte_bit(pte, __pgprot(PTE_WRITE));
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+	return set_pte_bit(pte, __pgprot(PTE_WRITE));
+}
+
 static inline pte_t pte_mkclean(pte_t pte)
 {
-	pte_val(pte) &= ~PTE_DIRTY;
-	return pte;
+	return clear_pte_bit(pte, __pgprot(PTE_DIRTY));
 }
 
 static inline pte_t pte_mkdirty(pte_t pte)
 {
-	pte_val(pte) |= PTE_DIRTY;
-	return pte;
+	return set_pte_bit(pte, __pgprot(PTE_DIRTY));
 }
 
 static inline pte_t pte_mkold(pte_t pte)
 {
-	pte_val(pte) &= ~PTE_AF;
-	return pte;
+	return clear_pte_bit(pte, __pgprot(PTE_AF));
 }
 
 static inline pte_t pte_mkyoung(pte_t pte)
 {
-	pte_val(pte) |= PTE_AF;
-	return pte;
+	return set_pte_bit(pte, __pgprot(PTE_AF));
 }
 
 static inline pte_t pte_mkspecial(pte_t pte)
 {
-	pte_val(pte) |= PTE_SPECIAL;
-	return pte;
+	return set_pte_bit(pte, __pgprot(PTE_SPECIAL));
 }
 
 static inline void set_pte(pte_t *ptep, pte_t pte)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#2 lore raw

PATCH v4 1/2 arm64: Introduce {set,clear}_pte_bit

Quoted 13 lines · Laura Abbott
arch/arm64/include/asm/pgtable.h +2 -2
index ffe1ba0..ca41449 100644
@@ -149,46 +149,51 @@ extern struct page *empty_zero_page;
 #define pte_valid_not_user(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 
-static inline pte_t pte_wrprotect(pte_t pte)
+static pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) &= ~PTE_WRITE;
+	pte_val(pte) &= ~pgprot_val(prot);

arch/arm64/include/asm/pgtable.h extern struct page *empty_zero_page; · line 162

Quoted 10 lines
arch/arm64/include/asm/pgtable.h +2 -2
 	return pte;
 }
 
-static inline pte_t pte_mkwrite(pte_t pte)
+static pte_t set_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) |= PTE_WRITE;
+	pte_val(pte) |= pgprot_val(prot);
 	return pte;
 }

Why these two functions don't have an "inline"?

Signature · 1 line
Catalin
#3 lore raw

PATCH v4 1/2 arm64: Introduce {set,clear}_pte_bit

Quoted 17 lines · Catalin Marinas
Quoted 16 lines · Laura Abbott
arch/arm64/include/asm/pgtable.h +2 -2
index ffe1ba0..ca41449 100644
@@ -149,46 +149,51 @@ extern struct page *empty_zero_page;
 #define pte_valid_not_user(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 
-static inline pte_t pte_wrprotect(pte_t pte)
+static pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) &= ~PTE_WRITE;
+	pte_val(pte) &= ~pgprot_val(prot);
 	return pte;
 }
 
Quoted 10 lines

arch/arm64/include/asm/pgtable.h extern struct page *empty_zero_page; · line 162

Quoted 7 lines
arch/arm64/include/asm/pgtable.h +2 -2
-static inline pte_t pte_mkwrite(pte_t pte)
+static pte_t set_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) |= PTE_WRITE;
+	pte_val(pte) |= pgprot_val(prot);
 	return pte;
 }

Why these two functions don't have an "inline"?

That's an error on my part.

Will, you mentioned you applied these patches already, how would you like to fix this up?

Laura

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#4 lore raw

PATCH v4 1/2 arm64: Introduce {set,clear}_pte_bit

Quoted 29 lines · Laura Abbott
Quoted 17 lines · Catalin Marinas
Quoted 16 lines · Laura Abbott
arch/arm64/include/asm/pgtable.h +2 -2
index ffe1ba0..ca41449 100644
@@ -149,46 +149,51 @@ extern struct page *empty_zero_page;
 #define pte_valid_not_user(pte) \
 	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 
-static inline pte_t pte_wrprotect(pte_t pte)
+static pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) &= ~PTE_WRITE;
+	pte_val(pte) &= ~pgprot_val(prot);
 	return pte;
 }
 
Quoted 10 lines

arch/arm64/include/asm/pgtable.h extern struct page *empty_zero_page; · line 162

Quoted 7 lines
arch/arm64/include/asm/pgtable.h +2 -2
-static inline pte_t pte_mkwrite(pte_t pte)
+static pte_t set_pte_bit(pte_t pte, pgprot_t prot)
 {
-	pte_val(pte) |= PTE_WRITE;
+	pte_val(pte) |= pgprot_val(prot);
 	return pte;
 }

Why these two functions don't have an "inline"?

Quoted 4 lines

That's an error on my part.

Will, you mentioned you applied these patches already, how would you like to fix this up?

Yup, I can easily add the missing inline keywords. Did you see Catalin's other comment? It looks like we're missing a '-1' on the end address before checking whether or not it sits in a module. If you confirm, I can add that too.

Will

#5 lore raw

PATCH v4 1/2 arm64: Introduce {set,clear}_pte_bit

Quoted 35 lines · Will Deacon
Quoted 29 lines · Laura Abbott
Quoted 17 lines · Catalin Marinas
Quoted 16 lines · Laura Abbott
arch/arm64/include/asm/pgtable.h +2 -2
index ffe1ba0..ca41449 100644
@@ -149,46 +149,51 @@ extern struct page *empty_zero_page;
  #define pte_valid_not_user(pte) \
  	((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
 
-static inline pte_t pte_wrprotect(pte_t pte)
+static pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
  {
-	pte_val(pte) &= ~PTE_WRITE;
+	pte_val(pte) &= ~pgprot_val(prot);
  	return pte;
  }
 
Quoted 10 lines

arch/arm64/include/asm/pgtable.h extern struct page *empty_zero_page; · line 162

Quoted 7 lines
arch/arm64/include/asm/pgtable.h +2 -2
-static inline pte_t pte_mkwrite(pte_t pte)
+static pte_t set_pte_bit(pte_t pte, pgprot_t prot)
  {
-	pte_val(pte) |= PTE_WRITE;
+	pte_val(pte) |= pgprot_val(prot);
  	return pte;
  }

Why these two functions don't have an "inline"?

Quoted 4 lines

That's an error on my part.

Will, you mentioned you applied these patches already, how would you like to fix this up?

Quoted 7 lines

Yup, I can easily add the missing inline keywords. Did you see Catalin's other comment? It looks like we're missing a '-1' on the end address before checking whether or not it sits in a module. If you confirm, I can add that too.

Will

Yes, Catalin's review was correct, we need the -1 as well.

Thanks,
Laura

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#6 lore raw

PATCH v4 2/2 arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

In reply to Laura Abbott

In a similar fashion to other architecture, add the infrastructure and Kconfig to enable DEBUG_SET_MODULE_RONX support. When enabled, module ranges will be marked read-only/no-execute as appropriate.

---
 arch/arm64/Kconfig.debug            | 11 +++++
 arch/arm64/include/asm/cacheflush.h |  4 ++
 arch/arm64/mm/Makefile              |  2 +-
 arch/arm64/mm/pageattr.c            | 96 +++++++++++++++++++++++++++++++++++++
 4 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm64/mm/pageattr.c
arch/arm64/Kconfig.debug +11 -0
index 4ee8e90..0a12933 100644
@@ -43,4 +43,15 @@ config ARM64_RANDOMIZE_TEXT_OFFSET
 	  of TEXT_OFFSET and platforms must not require a specific
 	  value.
 
+config DEBUG_SET_MODULE_RONX
+        bool "Set loadable kernel module data as NX and text as RO"
+        depends on MODULES
+        help
+          This option helps catch unintended modifications to loadable
+          kernel module's text and read-only data. It also prevents execution
+          of module data. Such protection may interfere with run-time code
+          patching and dynamic kernel tracing - and they might also protect
+          against certain classes of kernel exploits.
+          If in doubt, say "N".
+
 endmenu
arch/arm64/include/asm/cacheflush.h +4 -0
index f2defe1..689b637 100644
@@ -148,4 +148,8 @@ static inline void flush_cache_vunmap(unsigned long start, unsigned long end)
 {
 }
 
+int set_memory_ro(unsigned long addr, int numpages);
+int set_memory_rw(unsigned long addr, int numpages);
+int set_memory_x(unsigned long addr, int numpages);
+int set_memory_nx(unsigned long addr, int numpages);
 #endif
arch/arm64/mm/Makefile +1 -1
index 3ecb56c..c56179e 100644
@@ -1,5 +1,5 @@
 obj-y				:= dma-mapping.o extable.o fault.o init.o \
 				   cache.o copypage.o flush.o \
 				   ioremap.o mmap.o pgd.o mmu.o \
-				   context.o proc.o
+				   context.o proc.o pageattr.o
 obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
arch/arm64/mm/pageattr.c new file +96 -0

96 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
maintainer
#7 lore raw

PATCH v4 2/2 arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

Quoted 2 lines · Laura Abbott
arch/arm64/mm/pageattr.c new file +0 -0

[...]

Quoted 6 lines
arch/arm64/mm/pageattr.c new file +6 -0
+static int change_memory_common(unsigned long addr, int numpages,
+				pgprot_t set_mask, pgprot_t clear_mask)
+{
+	unsigned long start = addr;
+	unsigned long size = PAGE_SIZE*numpages;
+	unsigned long end = start + size;

arch/arm64/mm/pageattr.c line 54

Quoted 10 lines
arch/arm64/mm/pageattr.c new file +10 -0
+	int ret;
+	struct page_change_data data;
+
+	if (!IS_ALIGNED(addr, PAGE_SIZE)) {
+		addr &= PAGE_MASK;
+		WARN_ON_ONCE(1);
+	}
+
+	if (!is_module_address(start) || !is_module_address(end))
+		return -EINVAL;

Minor thing, "end" is exclusive here. Do you still get the right check with is_module_address(end)?

Signature · 1 line
Catalin
#8 lore raw

PATCH v4 2/2 arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

Quoted 15 lines · Catalin Marinas
Quoted 2 lines · Laura Abbott
arch/arm64/mm/pageattr.c new file +0 -0

[...]

Quoted 11 lines
arch/arm64/mm/pageattr.c new file +11 -0
+static int change_memory_common(unsigned long addr, int numpages,
+				pgprot_t set_mask, pgprot_t clear_mask)
+{
+	unsigned long start = addr;
+	unsigned long size = PAGE_SIZE*numpages;
+	unsigned long end = start + size;
+	int ret;
+	struct page_change_data data;
+
+	if (!IS_ALIGNED(addr, PAGE_SIZE)) {
+		addr &= PAGE_MASK;
Quoted 9 lines

arch/arm64/mm/pageattr.c line 54

Quoted 5 lines
arch/arm64/mm/pageattr.c new file +5 -0
+		WARN_ON_ONCE(1);
+	}
+
+	if (!is_module_address(start) || !is_module_address(end))
+		return -EINVAL;

Minor thing, "end" is exclusive here. Do you still get the right check with is_module_address(end)?

No, You are correct. I'll talk to Will to get that fixed up.

Thanks,
Laura

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#9 lore raw

PATCH v4 2/2 arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

Quoted 26 lines · Laura Abbott
Quoted 15 lines · Catalin Marinas
Quoted 2 lines · Laura Abbott
arch/arm64/mm/pageattr.c new file +0 -0

[...]

Quoted 11 lines
arch/arm64/mm/pageattr.c new file +11 -0
+static int change_memory_common(unsigned long addr, int numpages,
+				pgprot_t set_mask, pgprot_t clear_mask)
+{
+	unsigned long start = addr;
+	unsigned long size = PAGE_SIZE*numpages;
+	unsigned long end = start + size;
+	int ret;
+	struct page_change_data data;
+
+	if (!IS_ALIGNED(addr, PAGE_SIZE)) {
+		addr &= PAGE_MASK;
Quoted 9 lines

arch/arm64/mm/pageattr.c line 54

Quoted 5 lines
arch/arm64/mm/pageattr.c new file +5 -0
+		WARN_ON_ONCE(1);
+	}
+
+	if (!is_module_address(start) || !is_module_address(end))
+		return -EINVAL;

Minor thing, "end" is exclusive here. Do you still get the right check with is_module_address(end)?

Quoted 1 line

No, You are correct. I'll talk to Will to get that fixed up.

I already had a crack at fixing it:

https://git.kernel.org/cgit/linux/kernel/git/arm64/linux.git/commit/?h=devel&id=a8b974874c4770860c2a356adb9397d38f6c2b70

How did I do?

Will

#10 lore raw

PATCH v4 2/2 arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

Hi Will,

Quoted 6 lines · Will Deacon
Quoted 5 lines · Laura Abbott
Quoted 4 lines · Catalin Marinas
Quoted 2 lines · Laura Abbott
arch/arm64/mm/pageattr.c new file +0 -0

[...]

Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

arch/arm64/mm/pageattr.c line 49

Quoted 11 lines
arch/arm64/mm/pageattr.c new file +11 -0
+static int change_memory_common(unsigned long addr, int numpages,
+                          pgprot_t set_mask, pgprot_t clear_mask)
+{
+  unsigned long start = addr;
+  unsigned long size = PAGE_SIZE*numpages;
+  unsigned long end = start + size;
+  int ret;
+  struct page_change_data data;
+
+  if (!IS_ALIGNED(addr, PAGE_SIZE)) {
+          addr &= PAGE_MASK;

I don't see any uses of addr after this.
Perhaps we also meant to compute start and end?

Quoted 24 lines
Quoted 11 lines
Quoted 9 lines

arch/arm64/mm/pageattr.c line 54

Quoted 5 lines
arch/arm64/mm/pageattr.c new file +5 -0
+          WARN_ON_ONCE(1);
+  }
+
+  if (!is_module_address(start) || !is_module_address(end))
+          return -EINVAL;

Minor thing, "end" is exclusive here. Do you still get the right check with is_module_address(end)?

No, You are correct. I'll talk to Will to get that fixed up.

I already had a crack at fixing it:

https://git.kernel.org/cgit/linux/kernel/git/arm64/linux.git/commit/?h=devel&id=a8b974874c4770860c2a356adb9397d38f6c2b70

How did I do?

Will

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#11 lore raw

PATCH v4 2/2 arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

Quoted 7 lines · Zi Shen Lim
Quoted 6 lines · Will Deacon
Quoted 5 lines · Laura Abbott
Quoted 4 lines · Catalin Marinas
Quoted 2 lines · Laura Abbott
arch/arm64/mm/pageattr.c new file +0 -0

[...]

Quoted 14 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

arch/arm64/mm/pageattr.c line 49

Quoted 11 lines
arch/arm64/mm/pageattr.c new file +11 -0
+static int change_memory_common(unsigned long addr, int numpages,
+                          pgprot_t set_mask, pgprot_t clear_mask)
+{
+  unsigned long start = addr;
+  unsigned long size = PAGE_SIZE*numpages;
+  unsigned long end = start + size;
+  int ret;
+  struct page_change_data data;
+
+  if (!IS_ALIGNED(addr, PAGE_SIZE)) {
+          addr &= PAGE_MASK;

I don't see any uses of addr after this.
Perhaps we also meant to compute start and end?

Actually, I think the alignment fixup should just be performed directly on start, but this is Laura's code so it would be good if she could confirm.

Laura -- what's the right thing to do here? (sending a fix patch would be ideal :)

Will

#12 lore raw

PATCH v4 2/2 arm64: Add CONFIG_DEBUG_SET_MODULE_RONX support

Quoted 24 lines · Will Deacon
Quoted 7 lines · Zi Shen Lim
Quoted 6 lines · Will Deacon
Quoted 5 lines · Laura Abbott
Quoted 4 lines · Catalin Marinas
Quoted 2 lines · Laura Abbott
arch/arm64/mm/pageattr.c new file +0 -0

[...]

Quoted 14 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines

arch/arm64/mm/pageattr.c line 49

Quoted 11 lines
arch/arm64/mm/pageattr.c new file +11 -0
+static int change_memory_common(unsigned long addr, int numpages,
+                          pgprot_t set_mask, pgprot_t clear_mask)
+{
+  unsigned long start = addr;
+  unsigned long size = PAGE_SIZE*numpages;
+  unsigned long end = start + size;
+  int ret;
+  struct page_change_data data;
+
+  if (!IS_ALIGNED(addr, PAGE_SIZE)) {
+          addr &= PAGE_MASK;

I don't see any uses of addr after this.
Perhaps we also meant to compute start and end?

Quoted 8 lines

Actually, I think the alignment fixup should just be performed directly on start, but this is Laura's code so it would be good if she could confirm.

Laura -- what's the right thing to do here? (sending a fix patch would be ideal :)

Will

Yes this needs to be fixed. I'll send a patch out tomorrow.

Thanks,
Laura

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#13 lore raw

PATCH 1/1 arm64: pageattr: Correctly adjust unaligned start addresses

The start address needs to be actually updated after it is detected to be unaligned. Adjust it and the end address properly.

---
 arch/arm64/mm/pageattr.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/mm/pageattr.c +2 -1
index 75e744e..bb0ea94 100644
@@ -46,7 +46,8 @@ static int change_memory_common(unsigned long addr, int numpages,
 	struct page_change_data data;
 
 	if (!IS_ALIGNED(addr, PAGE_SIZE)) {
-		addr &= PAGE_MASK;
+		start &= PAGE_MASK;
+		end = start + size;
 		WARN_ON_ONCE(1);
 	}
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#14 lore raw

PATCH 1/1 arm64: pageattr: Correctly adjust unaligned start addresses

Quoted 15 lines · Laura Abbott

The start address needs to be actually updated after it is detected to be unaligned. Adjust it and the end address properly.

---
 arch/arm64/mm/pageattr.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/mm/pageattr.c +0 -0
index 75e744e..bb0ea94 100644

arch/arm64/mm/pageattr.c static int change_memory_common(unsigned long addr, int numpages, · line 53

Quoted 9 lines
arch/arm64/mm/pageattr.c +2 -1
@@ -46,7 +46,8 @@ static int change_memory_common(unsigned long addr, int numpages,
        struct page_change_data data;
 
        if (!IS_ALIGNED(addr, PAGE_SIZE)) {
-               addr &= PAGE_MASK;
+               start &= PAGE_MASK;
+               end = start + size;
                WARN_ON_ONCE(1);
        }
 

Looks good to me.

Quoted 4 lines

--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation

maintainer Applied
#15 lore raw

PATCH 1/1 arm64: pageattr: Correctly adjust unaligned start addresses

In reply to Laura Abbott
Quoted 9 lines · Laura Abbott

The start address needs to be actually updated after it is detected to be unaligned. Adjust it and the end address properly.

---
 arch/arm64/mm/pageattr.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Applied. Thanks.

Signature · 1 line
Catalin
#16 lore raw

v4 cover arm64 CONFIG_DEBUG_SET_MODULE_RONX support

In reply to Laura Abbott
Quoted 6 lines · Laura Abbott

This is another version of DEBUG_SET_MODULE_RONX support for arm64.

Thanks,
Laura

v4: Switch to one function to do set/clear per suggestion of Will

Thanks Laura. It looks like you addressed all the comments I made after you sent this too, so I've applied it to our devel branch for the moment.

Cheers,

Will