diff --git a/.vscode/settings.json b/.vscode/settings.json index 205c65d..ec616e2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -34,7 +34,10 @@ "assert.h": "c", "mman.h": "c", "time.h": "c", - "vmmeter.h": "c" + "vmmeter.h": "c", + "malloc.h": "c", + "lock.h": "c", + "proc.h": "c" }, "C_Cpp.errorSquiggles": "disabled" } \ No newline at end of file diff --git a/dpdk/kernel/freebsd/contigmem/contigmem.c b/dpdk/kernel/freebsd/contigmem/contigmem.c index cd761d4..f05f204 100644 --- a/dpdk/kernel/freebsd/contigmem/contigmem.c +++ b/dpdk/kernel/freebsd/contigmem/contigmem.c @@ -33,6 +33,80 @@ __FBSDID("$FreeBSD$"); #include #include +// -- Debug contigous allocator header files -- +#include +// #include "opt_ddb.h" +// #include "opt_vm.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef EPOCH_TRACE +#include +#endif + +#include + +// #include +#include "vm_domainset.h" +#include +#include +#include "vm_extern.h" +#include +#include +#include +#include +#include + +#ifdef DEBUG_MEMGUARD +#include +#endif +#ifdef DEBUG_REDZONE +#include +#endif + +#if defined(INVARIANTS) && defined(__i386__) +#include +#endif + +#include + +#ifdef KDTRACE_HOOKS +#include + +bool __read_frequently dtrace_malloc_enabled; +dtrace_malloc_probe_func_t __read_mostly dtrace_malloc_probe; +#endif + +#if defined(INVARIANTS) || defined(MALLOC_MAKE_FAILURES) || \ + defined(DEBUG_MEMGUARD) || defined(DEBUG_REDZONE) +#define MALLOC_DEBUG 1 +#endif + +#if defined(KASAN) || defined(DEBUG_REDZONE) +#define DEBUG_REDZONE_ARG_DEF , unsigned long osize +#define DEBUG_REDZONE_ARG , osize +#else +#define DEBUG_REDZONE_ARG_DEF +#define DEBUG_REDZONE_ARG +#endif + +// ----------------------------- + +// -------------------- Inside contig malloc +#include + +#include + +#include +#include + +// ------------------------------------- + // #define RTE_CONTIGMEM_DEFAULT_BUF_SIZE 1073741824 // added to print uint @@ -122,6 +196,180 @@ static struct cdevsw contigmem_ops = { .d_close = contigmem_close, }; +static void +vm_domainset_iter_ignore(struct vm_domainset_iter *di, int domain) +{ + KASSERT(DOMAINSET_ISSET(domain, &di->di_valid_mask), + ("%s: domain %d not present in di_valid_mask for di %p", + __func__, domain, di)); + DOMAINSET_CLR(domain, &di->di_valid_mask); +} + +static __always_inline void +kmem_alloc_san(vm_offset_t addr, vm_size_t size, vm_size_t asize, int flags) +{ + if ((flags & M_ZERO) == 0) { + kmsan_mark((void *)addr, asize, KMSAN_STATE_UNINIT); + kmsan_orig((void *)addr, asize, KMSAN_TYPE_KMEM, + KMSAN_RET_ADDR); + } else { + kmsan_mark((void *)addr, asize, KMSAN_STATE_INITED); + } + kasan_mark((void *)addr, size, asize, KASAN_KMEM_REDZONE); +} + +static vm_page_t +kmem_alloc_contig_pages(vm_object_t object, vm_pindex_t pindex, int domain, + int pflags, u_long npages, vm_paddr_t low, vm_paddr_t high, + u_long alignment, vm_paddr_t boundary, vm_memattr_t memattr) +{ + vm_page_t m; + int tries; + bool wait, reclaim; + + VM_OBJECT_ASSERT_WLOCKED(object); + + wait = (pflags & VM_ALLOC_WAITOK) != 0; + reclaim = (pflags & VM_ALLOC_NORECLAIM) == 0; + pflags &= ~(VM_ALLOC_NOWAIT | VM_ALLOC_WAITOK | VM_ALLOC_WAITFAIL); + pflags |= VM_ALLOC_NOWAIT; + for (tries = wait ? 3 : 1;; tries--) { + m = vm_page_alloc_contig_domain(object, pindex, domain, pflags, + npages, low, high, alignment, boundary, memattr); + if (m != NULL || tries == 0 || !reclaim) + break; + + VM_OBJECT_WUNLOCK(object); + if (vm_page_reclaim_contig_domain(domain, pflags, npages, + low, high, alignment, boundary) == ENOMEM && wait) + vm_wait_domain(domain); + VM_OBJECT_WLOCK(object); + } + return (m); +} + +static void * +kmem_alloc_contig_domain(int domain, vm_size_t size, int flags, vm_paddr_t low, + vm_paddr_t high, u_long alignment, vm_paddr_t boundary, + vm_memattr_t memattr) +{ + vmem_t *vmem; + vm_object_t object; + vm_pointer_t addr; + vm_offset_t offset, tmp; + vm_page_t end_m, m; + vm_size_t asize; + u_long npages; + int pflags; + +#ifdef __CHERI_PURE_CAPABILITY__ + size = CHERI_REPRESENTABLE_LENGTH(size); +#endif + object = kernel_object; + asize = round_page(size); + vmem = vm_dom[domain].vmd_kernel_arena; + if (vmem_alloc(vmem, asize, flags | M_BESTFIT, &addr)) + return (NULL); + addr = cheri_kern_andperm(addr, CHERI_PERMS_KERNEL_DATA); + offset = addr - VM_MIN_KERNEL_ADDRESS; + pflags = malloc2vm_flags(flags) | VM_ALLOC_WIRED; + npages = atop(asize); + VM_OBJECT_WLOCK(object); + printf("reaches to contig pages"); + m = kmem_alloc_contig_pages(object, atop(offset), domain, + pflags, npages, low, high, alignment, boundary, memattr); + if (m == NULL) { + VM_OBJECT_WUNLOCK(object); + vmem_free(vmem, addr, asize); + return (NULL); + } + KASSERT(vm_page_domain(m) == domain, + ("kmem_alloc_contig_domain: Domain mismatch %d != %d", + vm_page_domain(m), domain)); + end_m = m + npages; + tmp = addr; + for (; m < end_m; m++) { + if ((flags & M_ZERO) && (m->flags & PG_ZERO) == 0) + pmap_zero_page(m); + vm_page_valid(m); + VM_OBJECT_ASSERT_CAP(object, VM_PROT_RW_CAP); + vm_page_aflag_set(m, PGA_CAPSTORE | PGA_CAPDIRTY); + // To modify pmap_enter to use only huge pages + pmap_enter(kernel_pmap, tmp, m, VM_PROT_RW_CAP, + VM_PROT_RW_CAP | PMAP_ENTER_WIRED, 0); + tmp += PAGE_SIZE; + } + VM_OBJECT_WUNLOCK(object); + kmem_alloc_san(addr, size, asize, flags); +#ifdef __CHERI_PURE_CAPABILITY__ + KASSERT(cheri_gettag(addr), ("Expected valid capability")); + KASSERT(cheri_getlen(addr) == asize, + ("Inexact bounds expected %zx found %zx", + (size_t)asize, (size_t)cheri_getlen(addr))); +#endif + return ((void *)addr); +} + +static void * +kmem_alloc_contig_domainset(struct domainset *ds, vm_size_t size, int flags, + vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary, + vm_memattr_t memattr) +{ + struct vm_domainset_iter di; + vm_page_t bounds[2]; + void *addr; + int domain; + int start_segind; + + start_segind = -1; + + vm_domainset_iter_policy_init(&di, ds, &domain, &flags); + do { + addr = kmem_alloc_contig_domain(domain, size, flags, low, high, + alignment, boundary, memattr); + if (addr != NULL) + break; + if (start_segind == -1) + start_segind = vm_phys_lookup_segind(low); + if (vm_phys_find_range(bounds, start_segind, domain, + atop(round_page(size)), low, high) == -1) { + vm_domainset_iter_ignore(&di, domain); + } + } while (vm_domainset_iter_policy(&di, &domain) == 0); + + return (addr); +} + +static void * +kmem_alloc_contig(vm_size_t size, int flags, vm_paddr_t low, vm_paddr_t high, + u_long alignment, vm_paddr_t boundary, vm_memattr_t memattr) +{ + + return (kmem_alloc_contig_domainset(DOMAINSET_RR(), size, flags, low, + high, alignment, boundary, memattr)); +} + +static void * +contigmalloc(unsigned long size, struct malloc_type *type, int flags, + vm_paddr_t low, vm_paddr_t high, unsigned long alignment, + vm_paddr_t boundary) +{ + printf("contigmalloc called"); + void *ret; + + ret = (void *)kmem_alloc_contig(size, flags, low, high, alignment, + boundary, VM_MEMATTR_DEFAULT); + if (ret != NULL) + malloc_type_allocated(type, ret, round_page(size)); +#ifdef __CHERI_PURE_CAPABILITY__ + KASSERT(cheri_gettag(ret), ("Expected valid capability")); +#endif + + return (ret); +} + +// -------------------- Contigous kernel module load ------------------------------- + static int contigmem_load() { @@ -131,7 +379,6 @@ contigmem_load() // get page size printf("%d buffer size \n",buffer_size); - printf("%d buffer size \n",buffer_size); char index_string[8], description[32]; int i, error = 0; diff --git a/dpdk/kernel/freebsd/contigmem/kern_alloc.c b/dpdk/kernel/freebsd/contigmem/malloc.c similarity index 100% rename from dpdk/kernel/freebsd/contigmem/kern_alloc.c rename to dpdk/kernel/freebsd/contigmem/malloc.c diff --git a/dpdk/kernel/freebsd/contigmem/malloc.h b/dpdk/kernel/freebsd/contigmem/malloc.h index ff2a56e..a3a6a53 100644 --- a/dpdk/kernel/freebsd/contigmem/malloc.h +++ b/dpdk/kernel/freebsd/contigmem/malloc.h @@ -180,10 +180,10 @@ extern struct mtx malloc_mtx; typedef void malloc_type_list_func_t(struct malloc_type *, void *); void contigfree(void *addr, unsigned long size, struct malloc_type *type); -void *contigmalloc(unsigned long size, struct malloc_type *type, int flags, - vm_paddr_t low, vm_paddr_t high, unsigned long alignment, - vm_paddr_t boundary) __malloc_like __result_use_check - __alloc_size(1) __alloc_align(6); +// void *contigmalloc(unsigned long size, struct malloc_type *type, int flags, +// vm_paddr_t low, vm_paddr_t high, unsigned long alignment, +// vm_paddr_t boundary) __malloc_like __result_use_check +// __alloc_size(1) __alloc_align(6); void *contigmalloc_domainset(unsigned long size, struct malloc_type *type, struct domainset *ds, int flags, vm_paddr_t low, vm_paddr_t high, unsigned long alignment, vm_paddr_t boundary) diff --git a/dpdk/kernel/freebsd/contigmem/meson.build b/dpdk/kernel/freebsd/contigmem/meson.build index 8fb2ab7..15a18d5 100644 --- a/dpdk/kernel/freebsd/contigmem/meson.build +++ b/dpdk/kernel/freebsd/contigmem/meson.build @@ -1,4 +1,4 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -sources = files('contigmem.c') +sources = files('contigmem.c','malloc.c') diff --git a/dpdk/kernel/freebsd/contigmem/vm_domainset.h b/dpdk/kernel/freebsd/contigmem/vm_domainset.h new file mode 100644 index 0000000..22fc5e7 --- /dev/null +++ b/dpdk/kernel/freebsd/contigmem/vm_domainset.h @@ -0,0 +1,55 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2017, Jeffrey Roberson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __VM_DOMAINSET_H__ +#define __VM_DOMAINSET_H__ + +struct vm_domainset_iter { + struct domainset *di_domain; + unsigned int *di_iter; + domainset_t di_valid_mask; + vm_pindex_t di_offset; + int di_flags; + uint16_t di_policy; + domainid_t di_n; + bool di_minskip; +}; + +int vm_domainset_iter_page(struct vm_domainset_iter *, struct vm_object *, + int *); +void vm_domainset_iter_page_init(struct vm_domainset_iter *, + struct vm_object *, vm_pindex_t, int *, int *); +int vm_domainset_iter_policy(struct vm_domainset_iter *, int *); +void vm_domainset_iter_policy_init(struct vm_domainset_iter *, + struct domainset *, int *, int *); +void vm_domainset_iter_policy_ref_init(struct vm_domainset_iter *, + struct domainset_ref *, int *, int *); +// void vm_domainset_iter_ignore(struct vm_domainset_iter *, int); + +int vm_wait_doms(const domainset_t *, int mflags); + +#endif /* __VM_DOMAINSET_H__ */ \ No newline at end of file diff --git a/dpdk/kernel/freebsd/contigmem/vm_extern.h b/dpdk/kernel/freebsd/contigmem/vm_extern.h new file mode 100644 index 0000000..2fbef87 --- /dev/null +++ b/dpdk/kernel/freebsd/contigmem/vm_extern.h @@ -0,0 +1,197 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vm_extern.h 8.2 (Berkeley) 1/12/94 + */ + +#ifndef _VM_EXTERN_H_ +#define _VM_EXTERN_H_ + +struct pmap; +struct proc; +struct vmspace; +struct vnode; +struct vmem; + +#ifdef _KERNEL +#include + +struct cdev; +struct cdevsw; +struct domainset; + +/* These operate on kernel virtual addresses only. */ +vm_pointer_t kva_alloc(vm_size_t); +void kva_free(vm_pointer_t, vm_size_t); + +/* These operate on pageable virtual addresses. */ +vm_pointer_t kmap_alloc_wait(vm_map_t, vm_size_t); +void kmap_free_wakeup(vm_map_t, vm_offset_t, vm_size_t); + +/* These operate on virtual addresses backed by memory. */ +void *kmem_alloc_attr(vm_size_t size, int flags, + vm_paddr_t low, vm_paddr_t high, vm_memattr_t memattr); +void *kmem_alloc_attr_domainset(struct domainset *ds, vm_size_t size, + int flags, vm_paddr_t low, vm_paddr_t high, vm_memattr_t memattr); +// vm_page_t +// kmem_alloc_contig_pages(vm_object_t object, vm_pindex_t pindex, int domain, +// int pflags, u_long npages, vm_paddr_t low, vm_paddr_t high, +// u_long alignment, vm_paddr_t boundary, vm_memattr_t memattr); +// static __always_inline void +// kmem_alloc_san(vm_offset_t addr, vm_size_t size, vm_size_t asize, int flags); +// void *kmem_alloc_contig_domain(int domain, vm_size_t size, int flags, vm_paddr_t low, +// vm_paddr_t high, u_long alignment, vm_paddr_t boundary, +// vm_memattr_t memattr); +// void *kmem_alloc_contig(vm_size_t size, int flags, +// vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary, +// vm_memattr_t memattr); +// void *kmem_alloc_contig_domainset(struct domainset *ds, vm_size_t size, +// int flags, vm_paddr_t low, vm_paddr_t high, u_long alignment, +// vm_paddr_t boundary, vm_memattr_t memattr); +void *kmem_malloc(vm_size_t size, int flags); +void *kmem_malloc_domainset(struct domainset *ds, vm_size_t size, + int flags); +void kmem_free(void *addr, vm_size_t size); + +/* This provides memory for previously allocated address space. */ +int kmem_back(vm_object_t, vm_pointer_t, vm_size_t, int); +int kmem_back_domain(int, vm_object_t, vm_pointer_t, vm_size_t, int); +void kmem_unback(vm_object_t, vm_offset_t, vm_size_t); + +/* Bootstrapping. */ +void kmem_bootstrap_free(vm_offset_t, vm_size_t); +void kmem_subinit(vm_map_t, vm_map_t, vm_pointer_t *, vm_pointer_t *, vm_size_t, + bool); +void kmem_init(vm_pointer_t, vm_pointer_t); +void kmem_init_zero_region(void); +void kmeminit(void); + +int kernacc(void *, int, int); +int useracc(void * __capability, int, int); +#if __has_feature(capabilities) +bool vm_cap_allows_prot(const void * __capability, vm_prot_t); +#endif +int vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, + int fault_flags, vm_page_t *m_hold); +void vm_fault_copy_entry(vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t, + vm_ooffset_t *); +int vm_fault_disable_pagefaults(void); +void vm_fault_enable_pagefaults(int save); +int vm_fault_quick_hold_pages(vm_map_t map, void * __capability addr, + vm_size_t len, vm_prot_t prot, vm_page_t *ma, int max_count); +int vm_fault_trap(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, + int fault_flags, int *signo, int *ucode); +int vm_forkproc(struct thread *, struct proc *, struct thread *, + struct vmspace *, int); +void vm_waitproc(struct proc *); +int vm_mmap(vm_map_t, vm_pointer_t *, vm_size_t, vm_prot_t, vm_prot_t, int, + objtype_t, void *, vm_ooffset_t); +int vm_mmap_object(vm_map_t, vm_pointer_t *, vm_offset_t, vm_size_t, + vm_prot_t, vm_prot_t, int, vm_object_t, vm_ooffset_t, boolean_t, + struct thread *); +int vm_mmap_to_errno(int rv); +int vm_mmap_cdev(struct thread *, vm_size_t, vm_prot_t *, vm_prot_t *, + int *, struct cdev *, struct cdevsw *, vm_ooffset_t *, vm_object_t *); +int vm_mmap_vnode(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, int *, + struct vnode *, vm_ooffset_t *, vm_object_t *, boolean_t *); +void vm_set_page_size(void); +void vm_sync_icache(vm_map_t, vm_offset_t, vm_size_t); +typedef int (*pmap_pinit_t)(struct pmap *pmap); +struct vmspace *vmspace_alloc(vm_pointer_t, vm_pointer_t, pmap_pinit_t); +struct vmspace *vmspace_fork(struct vmspace *, vm_ooffset_t *); +int vmspace_exec(struct proc *, vm_offset_t, vm_offset_t); +int vmspace_unshare(struct proc *); +void vmspace_exit(struct thread *); +struct vmspace *vmspace_acquire_ref(struct proc *); +void vmspace_free(struct vmspace *); +void vmspace_exitfree(struct proc *); +void vmspace_switch_aio(struct vmspace *); +#if __has_feature(capabilities) +uint64_t vmspace_cid_alloc(struct vmspace *); +#endif +void vnode_pager_setsize(struct vnode *, vm_ooffset_t); +void vnode_pager_purge_range(struct vnode *, vm_ooffset_t, vm_ooffset_t); +int vslock(void * __capability, size_t); +void vsunlock(void * __capability, size_t); +struct sf_buf *vm_imgact_map_page(vm_object_t object, vm_ooffset_t offset); +void vm_imgact_unmap_page(struct sf_buf *sf); +void vm_thread_dispose(struct thread *td); +int vm_thread_new(struct thread *td, int pages); +void vm_thread_stack_back(struct domainset *ds, vm_offset_t kaddr, + vm_page_t ma[], int npages, int req_class); +u_int vm_active_count(void); +u_int vm_inactive_count(void); +u_int vm_laundry_count(void); +u_int vm_wait_count(void); + +/* + * Is pa a multiple of alignment, which is a power-of-two? + */ +static inline bool +vm_addr_align_ok(vm_paddr_t pa, u_long alignment) +{ + KASSERT(powerof2(alignment), ("%s: alignment is not a power of 2: %#lx", + __func__, alignment)); + return ((pa & (alignment - 1)) == 0); +} + +/* + * Do the first and last addresses of a range match in all bits except the ones + * in -boundary (a power-of-two)? For boundary == 0, all addresses match. + */ +static inline bool +vm_addr_bound_ok(vm_paddr_t pa, vm_paddr_t size, vm_paddr_t boundary) +{ + KASSERT(powerof2(boundary), ("%s: boundary is not a power of 2: %#jx", + __func__, (uintmax_t)boundary)); + return (((pa ^ (pa + size - 1)) & -boundary) == 0); +} + +static inline bool +vm_addr_ok(vm_paddr_t pa, vm_paddr_t size, u_long alignment, + vm_paddr_t boundary) +{ + return (vm_addr_align_ok(pa, alignment) && + vm_addr_bound_ok(pa, size, boundary)); +} +#endif /* _KERNEL */ +#endif /* !_VM_EXTERN_H_ */ +// CHERI CHANGES START +// { +// "updated": 20230509, +// "target_type": "header", +// "changes": [ +// "user_capabilities" +// ], +// "changes_purecap": [ +// "pointer_as_integer" +// ] +// } +// CHERI CHANGES END \ No newline at end of file