From 36640a07fc3fd1126d8406940dfd4957c26fa987 Mon Sep 17 00:00:00 2001 From: Akilan Date: Mon, 20 Jan 2025 13:34:14 +0000 Subject: [PATCH] added introduction section --- .vscode/settings.json | 4 +- KernelModule/customMemAlloc.c | 194 +++++---- README.md | 1 + docs/.DS_Store | Bin 0 -> 6148 bytes docs/evaluation/evaluation.pdf | Bin 244742 -> 244742 bytes docs/evaluation/evaluation.tex | 24 +- docs/introduction/intro-plan.org | 45 ++ docs/introduction/introduction-plan.org | 0 docs/introduction/introduction.bbl | 59 +++ docs/introduction/introduction.bib | 426 +++++++++++++++++++ docs/introduction/introduction.org | 62 +++ docs/introduction/introduction.org~ | 62 +++ docs/introduction/introduction.pdf | Bin 0 -> 111098 bytes docs/introduction/introduction.tex | 95 +++++ dpdk/kernel/freebsd/Hugepage/BSDmakefile | 8 + dpdk/kernel/freebsd/Hugepage/Hugepage.c | 518 +++++++++++++++++++++++ dpdk/kernel/freebsd/Hugepage/meson.build | 4 + dpdk/kernel/freebsd/meson.build | 2 +- localpush.sh | 2 +- 19 files changed, 1412 insertions(+), 94 deletions(-) create mode 100644 README.md create mode 100644 docs/.DS_Store create mode 100644 docs/introduction/intro-plan.org create mode 100644 docs/introduction/introduction-plan.org create mode 100644 docs/introduction/introduction.bbl create mode 100644 docs/introduction/introduction.bib create mode 100644 docs/introduction/introduction.org create mode 100644 docs/introduction/introduction.org~ create mode 100644 docs/introduction/introduction.pdf create mode 100644 docs/introduction/introduction.tex create mode 100644 dpdk/kernel/freebsd/Hugepage/BSDmakefile create mode 100644 dpdk/kernel/freebsd/Hugepage/Hugepage.c create mode 100644 dpdk/kernel/freebsd/Hugepage/meson.build diff --git a/.vscode/settings.json b/.vscode/settings.json index 5616a14..dfd0690 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -55,7 +55,9 @@ "ratio": "cpp", "tuple": "cpp", "variant": "cpp", - "stddef.h": "c" + "stddef.h": "c", + "stdlib.h": "c", + "errno.h": "c" }, "C_Cpp.errorSquiggles": "disabled" } \ No newline at end of file diff --git a/KernelModule/customMemAlloc.c b/KernelModule/customMemAlloc.c index 8a67d90..28650ab 100644 --- a/KernelModule/customMemAlloc.c +++ b/KernelModule/customMemAlloc.c @@ -31,6 +31,27 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include + // added to print uint // 64 // #include @@ -78,6 +99,11 @@ static SYSCTL_NODE(_hw_contigmem, OID_AUTO, physaddr, CTLFLAG_RD, 0, MALLOC_DEFINE(M_CONTIGMEM, "customcontigmem", "customcontigmem(4) allocations"); +void *ptr; +int MallocCounter; + +#define MAXPAGESIZES 2 + /* * The offset in sysent where the syscall is allocated. @@ -120,79 +146,80 @@ static struct cdevsw contigmem_ops = { .d_close = contigmem_close, }; +static int +pagesizes(size_t ps[MAXPAGESIZES]) +{ + int pscnt; + + pscnt = getpagesizes(ps, MAXPAGESIZES); + // ATF_REQUIRE_MSG(pscnt != -1, "getpagesizes failed; errno=%d", errno); + // ATF_REQUIRE_MSG(ps[0] != 0, "psind 0 is %zu", ps[0]); + // ATF_REQUIRE_MSG(pscnt <= MAXPAGESIZES, "invalid pscnt %d", pscnt); + // if (pscnt == 1){ + // printf("pscnt is 1"); + // } + + // atf_tc_skip("no large page support"); + return (pscnt); +} + static int contigmem_load() { - // get page size - printf("%d FreeBSD page size \n",PAGE_SIZE); + size_t sz; + // Pre Allocate 1GB huge page + sz = 1073741824; - char index_string[8], description[32]; - int i, error = 0; - void *addr; + int error, fd, pscnt, pn; - if (contigmem_num_buffers > RTE_CONTIGMEM_MAX_NUM_BUFS) { - printf("%d buffers requested is greater than %d allowed\n", - contigmem_num_buffers, RTE_CONTIGMEM_MAX_NUM_BUFS); - error = EINVAL; - goto error; - } + size_t ps[MAXPAGESIZES]; - if (contigmem_buffer_size < PAGE_SIZE || - (contigmem_buffer_size & (contigmem_buffer_size - 1)) != 0) { - printf("buffer size 0x%lx is not greater than PAGE_SIZE and " - "power of two\n", contigmem_buffer_size); - error = EINVAL; - goto error; - } + size_t size[3]; - for (i = 0; i < contigmem_num_buffers; i++) { - addr = contigmalloc(contigmem_buffer_size, M_CONTIGMEM, M_ZERO, - 0, BUS_SPACE_MAXADDR, contigmem_buffer_size, 0); - if (addr == NULL) { - printf("contigmalloc failed for buffer %d\n", i); - error = ENOMEM; - goto error; - } + pn = getpagesizes(size, 3); + printf("page size is [%d]", size[2]); -#ifndef RTE_ARCH_ARM_PURECAP_HACK - printf("%2u: virt=%p phys=%p\n", i, addr, - (void *)pmap_kextract((vm_offset_t)addr)); -#endif + pscnt = pagesizes(ps); - mtx_init(&contigmem_buffers[i].mtx, "contigmem", NULL, MTX_DEF); - contigmem_buffers[i].addr = addr; - contigmem_buffers[i].refcnt = 0; + fd = shm_create_largepage(SHM_ANON, O_CREAT | O_RDWR, 1, SHM_LARGEPAGE_ALLOC_DEFAULT, 0); - snprintf(index_string, sizeof(index_string), "%d", i); - snprintf(description, sizeof(description), - "phys addr for buffer %d", i); - SYSCTL_ADD_PROC(NULL, - &SYSCTL_NODE_CHILDREN(_hw_contigmem, physaddr), OID_AUTO, - index_string, CTLTYPE_U64 | CTLFLAG_RD, - (void *)(uintptr_t)i, 0, contigmem_physaddr, "LU", - description); - } + if (fd < 0 && errno == ENOTTY) { + perror("sh_create_largepages"); + close(fd); + } + // if (fd < 0) + // perror("no large page supported"); + // exit(EXIT_FAILURE); + // if (fd < 0 && errno == ENOTTY) + // atf_tc_skip("no large page support"); + // ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; errno=%d", errno); - contigmem_cdev = make_dev_credf(0, &contigmem_ops, 0, NULL, UID_ROOT, - GID_WHEEL, 0600, "contigmem"); + if (ftruncate(fd, sz) < 0) { + perror("ftruncate"); + close(fd); + } + // if (error != 0 && errno == ENOMEM) + // /* + // * The test system might not have enough memory to accommodate + // * the request. + // */ + // atf_tc_skip("failed to allocate %zu-byte superpage", sz); + // ATF_REQUIRE_MSG(error == 0, "ftruncate failed; errno=%d", errno); + + ptr = mmap(NULL, sz, + PROT_READ|PROT_WRITE, MAP_SHARED,fd,0); + + // Added error handling + if(ptr == MAP_FAILED) + { + perror("mmap"); + exit(EXIT_FAILURE); + } + + MallocCounter = (int)sz; return 0; - -error: - for (i = 0; i < contigmem_num_buffers; i++) { - if (contigmem_buffers[i].addr != NULL) { - contigfree(contigmem_buffers[i].addr, - contigmem_buffer_size, M_CONTIGMEM); - contigmem_buffers[i].addr = NULL; - } - if (mtx_initialized(&contigmem_buffers[i].mtx)) - mtx_destroy(&contigmem_buffers[i].mtx); - } - - return error; - -// Want to design contig load to do nothing } static int @@ -350,36 +377,45 @@ static struct cdev_pager_ops contigmem_cdev_pager_ops = { }; static int -contigmem_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t size, + (struct cdev *cdev, vm_ooffset_t *offset, vm_size_t size, struct vm_object **obj, int nprot) { // Testing if this is called when file is opened printf("contigmem_mmap_single called \n"); - struct contigmem_vm_handle *vmh; - uint64_t buffer_index; + // struct contigmem_vm_handle *vmh; + // uint64_t buffer_index; - /* - * The buffer index is encoded in the offset. Divide the offset by - * PAGE_SIZE to get the index of the buffer requested by the user - * app. - */ - buffer_index = *offset / PAGE_SIZE; - if (buffer_index >= contigmem_num_buffers) - return EINVAL; + // /* + // * The buffer index is encoded in the offset. Divide the offset by + // * PAGE_SIZE to get the index of the buffer requested by the user + // * app. + // */ + // buffer_index = *offset / PAGE_SIZE; + // if (buffer_index >= contigmem_num_buffers) + // return EINVAL; - if (size > contigmem_buffer_size) - return EINVAL; + // if (size > contigmem_buffer_size) + // return EINVAL; - vmh = malloc(sizeof(*vmh), M_CONTIGMEM, M_NOWAIT | M_ZERO); - if (vmh == NULL) - return ENOMEM; - vmh->buffer_index = buffer_index; + // vmh = malloc(sizeof(*vmh), M_CONTIGMEM, M_NOWAIT | M_ZERO); + // if (vmh == NULL) + // return ENOMEM; + // vmh->buffer_index = buffer_index; - *offset = (vm_ooffset_t)vtophys(contigmem_buffers[buffer_index].addr); - *obj = cdev_pager_allocate(vmh, OBJT_DEVICE, &contigmem_cdev_pager_ops, - size, nprot, *offset, curthread->td_ucred); + // *offset = (vm_ooffset_t)vtophys(contigmem_buffers[buffer_index].addr); + // *obj = cdev_pager_allocate(vmh, OBJT_DEVICE, &contigmem_cdev_pager_ops, + // size, nprot, *offset, curthread->td_ucred); + + size = __builtin_align_up(size, _Alignof(max_align_t)); + + // printf("%d \n", sz); + // printf("%d Malloc counter\n", MallocCounter); + + MallocCounter -= size; + obj = &ptr[MallocCounter]; + obj = cheri_setbounds(obj, sz); return 0; } diff --git a/README.md b/README.md new file mode 100644 index 0000000..dd68b04 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# CHERI Huge page memory allocator diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7ecf7dc145e38dd10958a7c5753c6af951fef326 GIT binary patch literal 6148 zcmeHK%}xR_5S{|cA~E5hiQbxcC2=``Azn6!FW?$IsKMPpbmO`uu)u+k>|I~T7x8(V zX}d-O9=sSMGs*O8=VzOK-E>+25S>ZC0Z;<~2bHi;!Dfw+pL9hE))%#?d%+-FHzambSLbPT8qCcmAWA`Du_& z#+_hvL!(Qj;xO+A;Z-!4^=f-(DoKMV8H{v7)E{8T?RAv&)vTi?Nq?+!edBN{PNi2n zoX=01t-5Tx?xHT|?Uq}Y4Y%1`EGo|a(edd;?, which .", (5) "It overcomes these problems by .". (6) "It performs .". +(7) "The contributions of this paper are...". + +"leading to increased TLB misses and subsequent performance bottlenecks" - this would be better if you could quantify this +and cite a paper that reports this number. "E.g. 40% increased TLB misses resulting in 25% slowdowns [CITE]". + +General comment: the "WHY?" you are doing this question is unclear from the introduction. And you need to get to the +"WHY?" question much earlier, i.e. there is too much verbose discussion huge pages and TLB and CHERI. + +The *key* "WHY?" paraphrase you've written is: + +"In this context, the integration of huge pages into memory management strategies alongside capability-based +addressing in architectures like CHERI offers a compelling synergy. By optimizing TLB utilization through the +utilization of huge pages and leveraging the security features of capability-based addressing, significant +performance improvements can be realized." + +But there are several important problems with this paragraph: + +1) It comes too late in the introduction, it should be stated much earlier. + +2) Avoid wordy phrases like "compelling synergy" and long words like "leveraging". + +3) "significant performance improvements can be realized" is far too non-committal! If the "WHY?" is "performance", +then this needs to be really (really) clear: state how existing huge pages + TLB approach suffer performance issues; +state why exactly your technique will outperform existing huge pages + TLB approaches; state what performance metric +you are referring to; state; then state that they "*are* realised" and give the performance numbers to back up this claim. diff --git a/docs/introduction/introduction-plan.org b/docs/introduction/introduction-plan.org new file mode 100644 index 0000000..e69de29 diff --git a/docs/introduction/introduction.bbl b/docs/introduction/introduction.bbl new file mode 100644 index 0000000..633988c --- /dev/null +++ b/docs/introduction/introduction.bbl @@ -0,0 +1,59 @@ +% Generated by IEEEtran.bst, version: 1.14 (2015/08/26) +\begin{thebibliography}{1} +\providecommand{\url}[1]{#1} +\csname url@samestyle\endcsname +\providecommand{\newblock}{\relax} +\providecommand{\bibinfo}[2]{#2} +\providecommand{\BIBentrySTDinterwordspacing}{\spaceskip=0pt\relax} +\providecommand{\BIBentryALTinterwordstretchfactor}{4} +\providecommand{\BIBentryALTinterwordspacing}{\spaceskip=\fontdimen2\font plus +\BIBentryALTinterwordstretchfactor\fontdimen3\font minus + \fontdimen4\font\relax} +\providecommand{\BIBforeignlanguage}[2]{{% +\expandafter\ifx\csname l@#1\endcsname\relax +\typeout{** WARNING: IEEEtran.bst: No hyphenation pattern has been}% +\typeout{** loaded for the language `#1'. Using the pattern for}% +\typeout{** the default language instead.}% +\else +\language=\csname l@#1\endcsname +\fi +#2}} +\providecommand{\BIBdecl}{\relax} +\BIBdecl + +\bibitem{mittal_survey_2017} +\BIBentryALTinterwordspacing +S.~Mittal, ``A survey of techniques for architecting {TLBs},'' vol.~29, no.~10, + p. e4061, \_eprint: https://onlinelibrary.wiley.com/doi/pdf/10.1002/cpe.4061. + [Online]. Available: + \url{https://onlinelibrary.wiley.com/doi/abs/10.1002/cpe.4061} +\BIBentrySTDinterwordspacing + +\bibitem{panwar_hawkeye_2019} +\BIBentryALTinterwordspacing +A.~Panwar, S.~Bansal, and K.~Gopinath, ``{HawkEye}: Efficient fine-grained {OS} + support for huge pages,'' in \emph{Proceedings of the Twenty-Fourth + International Conference on Architectural Support for Programming Languages + and Operating Systems}.\hskip 1em plus 0.5em minus 0.4em\relax {ACM}, pp. + 347--360. [Online]. Available: + \url{https://dl.acm.org/doi/10.1145/3297858.3304064} +\BIBentrySTDinterwordspacing + +\bibitem{woodruff_cheri_2014} +\BIBentryALTinterwordspacing +J.~Woodruff, R.~N. Watson, D.~Chisnall, S.~W. Moore, J.~Anderson, B.~Davis, + B.~Laurie, P.~G. Neumann, R.~Norton, and M.~Roe, ``The {CHERI} capability + model: revisiting {RISC} in an age of risk,'' vol.~42, no.~3, pp. 457--468. + [Online]. Available: \url{https://doi.org/10.1145/2678373.2665740} +\BIBentrySTDinterwordspacing + +\bibitem{woodruff_cheri_2019} +\BIBentryALTinterwordspacing +J.~Woodruff, A.~Joannou, H.~Xia, A.~Fox, R.~M. Norton, D.~Chisnall, B.~Davis, + K.~Gudka, N.~W. Filardo, A.~T. Markettos, M.~Roe, P.~G. Neumann, R.~N.~M. + Watson, and S.~W. Moore, ``{CHERI} concentrate: Practical compressed + capabilities,'' vol.~68, no.~10, pp. 1455--1469. [Online]. Available: + \url{https://ieeexplore.ieee.org/document/8703061/} +\BIBentrySTDinterwordspacing + +\end{thebibliography} diff --git a/docs/introduction/introduction.bib b/docs/introduction/introduction.bib new file mode 100644 index 0000000..6f05496 --- /dev/null +++ b/docs/introduction/introduction.bib @@ -0,0 +1,426 @@ + +@article{navarro_practical_nodate, + title = {Practical, transparent operating system support for superpages}, + abstract = {Most general-purpose processors provide support for memory pages of large sizes, called superpages. Superpages enable each entry in the translation lookaside buffer ({TLB}) to map a large physical memory region into a virtual address space. This dramatically increases {TLB} coverage, reduces {TLB} misses, and promises performance improvements for many applications. However, supporting superpages poses several challenges to the operating system, in terms of superpage allocation and promotion tradeoffs, fragmentation control, etc. We analyze these issues, and propose the design of an effective superpage management system. We implement it in {FreeBSD} on the Alpha {CPU}, and evaluate it on real workloads and benchmarks. We obtain substantial performance benefits, often exceeding 30\%; these benefits are sustained even under stressful workload scenarios.}, + author = {Navarro, Juan}, + langid = {english}, + file = {Navarro - Practical, transparent operating system support fo.pdf:/Users/akilan/Zotero/storage/9RBYAPGM/Navarro - Practical, transparent operating system support fo.pdf:application/pdf}, +} + +@inproceedings{panwar_hawkeye_2019, + location = {Providence {RI} {USA}}, + title = {{HawkEye}: Efficient Fine-grained {OS} Support for Huge Pages}, + isbn = {978-1-4503-6240-5}, + url = {https://dl.acm.org/doi/10.1145/3297858.3304064}, + doi = {10.1145/3297858.3304064}, + shorttitle = {{HawkEye}}, + eventtitle = {{ASPLOS} '19: Architectural Support for Programming Languages and Operating Systems}, + pages = {347--360}, + booktitle = {Proceedings of the Twenty-Fourth International Conference on Architectural Support for Programming Languages and Operating Systems}, + publisher = {{ACM}}, + author = {Panwar, Ashish and Bansal, Sorav and Gopinath, K.}, + urldate = {2024-05-27}, + date = {2019-04-04}, + langid = {english}, + file = {Full Text PDF:/Users/akilan/Zotero/storage/VQLCKYCA/Panwar et al. - 2019 - HawkEye Efficient Fine-grained OS Support for Hug.pdf:application/pdf}, +} + +@inproceedings{karakostas_redundant_2015, + location = {Portland Oregon}, + title = {Redundant memory mappings for fast access to large memories}, + isbn = {978-1-4503-3402-0}, + url = {https://dl.acm.org/doi/10.1145/2749469.2749471}, + doi = {10.1145/2749469.2749471}, + abstract = {Page-based virtual memory improves programmer productivity, security, and memory utilization, but incurs performance overheads due to costly page table walks after {TLB} misses. This overhead can reach 50\% for modern workloads that access increasingly vast memory with stagnating {TLB} sizes. To reduce the overhead of virtual memory, this paper proposes Redundant Memory Mappings ({RMM}), which leverage ranges of pages and provides an efficient, alternative representation of many virtual-to-physical mappings. We define a range be a subset of process’s pages that are virtually and physically contiguous. {RMM} translates each range with a single range table entry, enabling a modest number of entries to translate most of the process’s address space. {RMM} operates in parallel with standard paging and uses a software range table and hardware range {TLB} with arbitrarily large reach. We modify the operating system to automatically detect ranges and to increase their likelihood with eager page allocation. {RMM} is thus transparent to applications. We prototype {RMM} software in Linux and emulate the hardware. {RMM} performs substantially better than paging alone and huge pages, and improves a wider variety of workloads than direct segments (one range per program), reducing the overhead of virtual memory to less than 1\% on average.}, + eventtitle = {{ISCA} '15: The 42nd Annual International Symposium on Computer Architecture}, + pages = {66--78}, + booktitle = {Proceedings of the 42nd Annual International Symposium on Computer Architecture}, + publisher = {{ACM}}, + author = {Karakostas, Vasileios and Gandhi, Jayneel and Ayar, Furkan and Cristal, Adrián and Hill, Mark D. and {McKinley}, Kathryn S. and Nemirovsky, Mario and Swift, Michael M. and Ünsal, Osman}, + urldate = {2024-05-27}, + date = {2015-06-13}, + langid = {english}, + file = {Karakostas et al. - 2015 - Redundant memory mappings for fast access to large.pdf:/Users/akilan/Zotero/storage/8JECES24/Karakostas et al. - 2015 - Redundant memory mappings for fast access to large.pdf:application/pdf}, +} + +@article{chen_flexpointer_2023, + title = {{FlexPointer}: Fast Address Translation Based on Range {TLB} and Tagged Pointers}, + volume = {20}, + issn = {1544-3566, 1544-3973}, + url = {https://dl.acm.org/doi/10.1145/3579854}, + doi = {10.1145/3579854}, + shorttitle = {{FlexPointer}}, + abstract = {Page-based virtual memory relies on {TLBs} to accelerate the address translation. Nowadays, the gap between application workloads and the capacity of {TLB} continues to grow, bringing many costly {TLB} misses and making the {TLB} a performance bottleneck. Previous studies seek to narrow the gap by exploiting the contiguity of physical pages. One promising solution is to group pages that are both virtually and physically contiguous into a memory range. Recording range translations can greatly increase the {TLB} reach, but ranges are also hard to index because they have arbitrary bounds. The processor has to compare against all the boundaries to determine which range an address falls in, which restricts the usage of memory ranges. + In this article, we propose a tagged-pointer-based scheme, {FlexPointer}, to solve the range indexing problem. The core insight of {FlexPointer} is that large memory objects are rare, so we can create memory ranges based on such objects and assign each of them a unique {ID}. With the range {ID} integrated into pointers, we can index the range {TLB} with {IDs} and greatly simplify its structure. Moreover, because the {ID} is stored in the unused bits of a pointer and is not manipulated by the address generation, we can shift the range lookup to an earlier stage, working in parallel with the address generation. According to our trace-based simulation results, {FlexPointer} can reduce nearly all the L1 {TLB} misses, and page walks for a variety of memory-intensive workloads. Compared with a 4K-page baseline system, {FlexPointer} shows a 14\% performance improvement on average and up to 2.8x speedup in the best case. For other workloads, {FlexPointer} shows no performance degradation.}, + pages = {1--24}, + number = {2}, + journaltitle = {{ACM} Transactions on Architecture and Code Optimization}, + shortjournal = {{ACM} Trans. Archit. Code Optim.}, + author = {Chen, Dongwei and Tong, Dong and Yang, Chun and Yi, Jiangfang and Cheng, Xu}, + urldate = {2024-05-27}, + date = {2023-06-30}, + langid = {english}, + file = {Full Text PDF:/Users/akilan/Zotero/storage/L9XGZDFK/Chen et al. - 2023 - FlexPointer Fast Address Translation Based on Ran.pdf:application/pdf}, +} + +@article{woodruff_cheri_2019, + title = {{CHERI} Concentrate: Practical Compressed Capabilities}, + volume = {68}, + rights = {https://ieeexplore.ieee.org/Xplorehelp/downloads/license-information/{IEEE}.html}, + issn = {0018-9340, 1557-9956, 2326-3814}, + url = {https://ieeexplore.ieee.org/document/8703061/}, + doi = {10.1109/TC.2019.2914037}, + shorttitle = {{CHERI} Concentrate}, + abstract = {We present {CHERI} Concentrate, a new fat-pointer compression scheme applied to {CHERI}, the most developed capability-pointer system at present. Capability fat pointers are a primary candidate to enforce fine-grained and non-bypassable security properties in future computer systems, although increased pointer size can severely affect performance. Thus, several proposals for capability compression have been suggested elsewhere that do not support legacy instruction sets, ignore features critical to the existing software base, and also introduce design inefficiencies to {RISC}-style processor pipelines. {CHERI} Concentrate improves on the state-of-the-art region-encoding efficiency, solves important pipeline problems, and eases semantic restrictions of compressed encoding, allowing it to protect a full legacy software stack. We present the first quantitative analysis of compiled capability code, which we use to guide the design of the encoding format. We analyze and extend logic from the open-source {CHERI} prototype processor design on {FPGA} to demonstrate encoding efficiency, minimize delay of pointer arithmetic, and eliminate additional load-to-use delay. To verify correctness of our proposed high-performance logic, we present a {HOL}4 machine-checked proof of the decode and pointer-modify operations. Finally, we measure a 50\% to 75\% reduction in L2 misses for many compiled C-language benchmarks running under a commodity operating system using compressed 128-bit and 64-bit formats, demonstrating both compatibility with and increased performance over the uncompressed, 256-bit format.}, + pages = {1455--1469}, + number = {10}, + journaltitle = {{IEEE} Transactions on Computers}, + shortjournal = {{IEEE} Trans. Comput.}, + author = {Woodruff, Jonathan and Joannou, Alexandre and Xia, Hongyan and Fox, Anthony and Norton, Robert M. and Chisnall, David and Davis, Brooks and Gudka, Khilan and Filardo, Nathaniel W. and Markettos, A. Theodore and Roe, Michael and Neumann, Peter G. and Watson, Robert N. M. and Moore, Simon W.}, + urldate = {2024-05-27}, + date = {2019-10-01}, + langid = {english}, + file = {Woodruff et al. - 2019 - CHERI Concentrate Practical Compressed Capabiliti.pdf:/Users/akilan/Zotero/storage/3SZUIWQ5/Woodruff et al. - 2019 - CHERI Concentrate Practical Compressed Capabiliti.pdf:application/pdf}, +} + +@online{noauthor_capability-based_nodate, + title = {Capability-Based Computer Systems}, + url = {https://homes.cs.washington.edu/~levy/capabook/}, + urldate = {2024-06-07}, + file = {Capability-Based Computer Systems:/Users/akilan/Zotero/storage/IAAG6ZF3/capabook.html:text/html}, +} + +@article{woodruff_cheri_2014, + title = {The {CHERI} capability model: revisiting {RISC} in an age of risk}, + volume = {42}, + issn = {0163-5964}, + url = {https://doi.org/10.1145/2678373.2665740}, + doi = {10.1145/2678373.2665740}, + shorttitle = {The {CHERI} capability model}, + abstract = {Motivated by contemporary security challenges, we reevaluate and refine capability-based addressing for the {RISC} era. We present {CHERI}, a hybrid capability model that extends the 64-bit {MIPS} {ISA} with byte-granularity memory protection. We demonstrate that {CHERI} enables language memory model enforcement and fault isolation in hardware rather than software, and that the {CHERI} mechanisms are easily adopted by existing programs for efficient in-program memory safety. In contrast to past capability models, {CHERI} complements, rather than replaces, the ubiquitous page-based protection mechanism, providing a migration path towards deconflating data-structure protection and {OS} memory management. Furthermore, {CHERI} adheres to a strict {RISC} philosophy: it maintains a load-store architecture and requires only singlecycle instructions, and supplies protection primitives to the compiler, language runtime, and operating system. We demonstrate a mature {FPGA} implementation that runs the {FreeBSD} operating system with a full range of software and an open-source application suite compiled with an extended {LLVM} to use {CHERI} memory protection. A limit study compares published memory safety mechanisms in terms of instruction count and memory overheads. The study illustrates that {CHERI} is performance-competitive even while providing assurance and greater flexibility with simpler hardware}, + pages = {457--468}, + number = {3}, + journaltitle = {{ACM} {SIGARCH} Computer Architecture News}, + shortjournal = {{SIGARCH} Comput. Archit. News}, + author = {Woodruff, Jonathan and Watson, Robert N.M. and Chisnall, David and Moore, Simon W. and Anderson, Jonathan and Davis, Brooks and Laurie, Ben and Neumann, Peter G. and Norton, Robert and Roe, Michael}, + urldate = {2024-06-07}, + date = {2014-06-14}, +} + +@article{miller_towards_nodate, + title = {Towards a Unified Approach to Access Control and Concurrency Control}, + author = {Miller, Mark Samuel}, + langid = {english}, + file = {Miller - Towards a Unified Approach to Access Control and Co.pdf:/Users/akilan/Zotero/storage/7METVAKG/Miller - Towards a Unified Approach to Access Control and Co.pdf:application/pdf}, +} + +@inproceedings{curtsinger_coz_2015, + title = {Coz: Finding Code that Counts with Causal Profiling}, + url = {http://arxiv.org/abs/1608.03676}, + doi = {10.1145/2815400.2815409}, + shorttitle = {Coz}, + abstract = {Improving performance is a central concern for software developers. To locate optimization opportunities, developers rely on software profilers. However, these profilers only report where programs spent their time: optimizing that code may have no impact on performance. Past profilers thus both waste developer time and make it difficult for them to uncover significant optimization opportunities.}, + pages = {184--197}, + booktitle = {Proceedings of the 25th Symposium on Operating Systems Principles}, + author = {Curtsinger, Charlie and Berger, Emery D.}, + urldate = {2024-06-07}, + date = {2015-10-04}, + langid = {english}, + eprinttype = {arxiv}, + eprint = {1608.03676 [cs]}, + keywords = {C.4, Computer Science - Performance, D.4.8}, + file = {Curtsinger and Berger - 2015 - Coz Finding Code that Counts with Causal Profilin.pdf:/Users/akilan/Zotero/storage/QTFQXVHE/Curtsinger and Berger - 2015 - Coz Finding Code that Counts with Causal Profilin.pdf:application/pdf}, +} + + @online{noauthor_benchmark_nodate, + title = {Benchmark {ABI} - {CheriBSD} 23.11 new features tutorial}, + url = {https://www.cheribsd.org/tutorial/23.11/benchmark/index.html}, + urldate = {2024-06-07}, + file = {Benchmark ABI - CheriBSD 23.11 new features tutorial:/Users/akilan/Zotero/storage/9BDKUW28/index.html:text/html}, + } + +@inproceedings{zhu_research_2018, + location = {Taipei, Taiwan}, + title = {Research and Implementation of High Performance Traffic Processing Based on Intel {DPDK}}, + isbn = {978-1-5386-9403-9}, + url = {https://ieeexplore.ieee.org/document/8701793/}, + doi = {10.1109/PAAP.2018.00018}, + eventtitle = {2018 9th International Symposium on Parallel Architectures, Algorithms and Programming ({PAAP})}, + pages = {62--68}, + booktitle = {2018 9th International Symposium on Parallel Architectures, Algorithms and Programming ({PAAP})}, + publisher = {{IEEE}}, + author = {Zhu, Wenjun and Li, Peng and Luo, Baozhou and Xu, He and Zhang, Yujie}, + urldate = {2024-06-07}, + date = {2018-12}, +} + +@article{bi_dpdk-based_2016, + title = {{DPDK}-based Improvement of Packet Forwarding}, + volume = {7}, + rights = {© Owned by the authors, published by {EDP} Sciences, 2016}, + issn = {2271-2097}, + url = {https://www.itm-conferences.org/articles/itmconf/abs/2016/02/itmconf_ita2016_01009/itmconf_ita2016_01009.html}, + doi = {10.1051/itmconf/20160701009}, + abstract = {Reel-time processing of packets occupies a significant position in the field of computer network security. With theexplosive growth of the backbone link rate,which is consistent with Gilder's law, many bottlenecks of server performance leave the real-time data stream unprocessed.Thus, we proposedto take use of {DPDK}(Data Plan Development Kit) framework to achieve an intelligent {NIC} packet forwarding system. During this research, we deeply analysis the forwarding process of packet in {DPDK} and improve its {DMA} mode.According to the results of experiment, the system greatly enhanced the performance of packet forwarding,and the throughput of forwarding 64-byet or random-length packets by 20Gbit {NIC} reaches13.3Gbps and 18.7Gbps(dual ports forwarding).}, + pages = {01009}, + journaltitle = {{ITM} Web of Conferences}, + shortjournal = {{ITM} Web Conf.}, + author = {Bi, Hao and Wang, Zhao-Hun}, + urldate = {2024-06-07}, + date = {2016}, + langid = {english}, + note = {Publisher: {EDP} Sciences}, + file = {Full Text PDF:/Users/akilan/Zotero/storage/LEVMJ983/Bi and Wang - 2016 - DPDK-based Improvement of Packet Forwarding.pdf:application/pdf}, +} + +@article{esswood_cherios_nodate, + title = {{CheriOS}: designing an untrusted single-address-space capability operating system utilising capability hardware and a minimal hypervisor}, + author = {Esswood, Lawrence G}, + langid = {english}, + file = {Esswood - CheriOS designing an untrusted single-address-spa.pdf:/Users/akilan/Zotero/storage/YGIBFTD5/Esswood - CheriOS designing an untrusted single-address-spa.pdf:application/pdf}, +} + +@book{wilkes_cambridge_1979, + location = {New York}, + title = {The Cambridge {CAP} computer and its operating system}, + isbn = {978-0-444-00357-7 978-0-444-00358-4}, + series = {The computer science library operating and programming systems series}, + pagetotal = {165}, + number = {6}, + publisher = {North Holland}, + author = {Wilkes, Maurice V. and Needham, Roger M.}, + date = {1979}, + langid = {english}, + file = {Wilkes and Needham - 1979 - The Cambridge CAP computer and its operating syste.pdf:/Users/akilan/Zotero/storage/VIQTWZS3/Wilkes and Needham - 1979 - The Cambridge CAP computer and its operating syste.pdf:application/pdf}, +} + +@article{fillo_mmachine_nodate, + title = {The M–Machine Multicomputer}, + author = {Fillo, Marco and Keckler, Stephen W and Dally, William J and Carter, Nicholas P and Chang, Andrew and Gurevich, Yevgeny and Lee, Whay S}, + langid = {english}, + file = {Fillo et al. - The M–Machine Multicomputer.pdf:/Users/akilan/Zotero/storage/LD95UQTM/Fillo et al. - The M–Machine Multicomputer.pdf:application/pdf}, +} + +@inproceedings{kwon_low-fat_2013, + location = {New York, {NY}, {USA}}, + title = {Low-fat pointers: compact encoding and efficient gate-level implementation of fat pointers for spatial safety and capability-based security}, + isbn = {978-1-4503-2477-9}, + url = {https://dl.acm.org/doi/10.1145/2508859.2516713}, + doi = {10.1145/2508859.2516713}, + series = {{CCS} '13}, + shorttitle = {Low-fat pointers}, + abstract = {Referencing outside the bounds of an array or buffer is a common source of bugs and security vulnerabilities in today's software. We can enforce spatial safety and eliminate these violations by inseparably associating bounds with every pointer (fat pointer) and checking these bounds on every memory access. By further adding hardware-managed tags to the pointer, we make them unforgeable. This, in turn, allows the pointers to be used as capabilities to facilitate fine-grained access control and fast security domain crossing. Dedicated checking hardware runs in parallel with the processor's normal datapath so that the checks do not slow down processor operation (0\% runtime overhead). To achieve the safety of fat pointers without increasing program state, we compactly encode approximate base and bound pointers along with exact address pointers for a 46b address space into one 64-bit word with a worst-case memory overhead of 3\%. We develop gate-level implementations of the logic for updating and validating these compact fat pointers and show that the hardware requirements are low and the critical paths for common operations are smaller than processor {ALU} operations. Specifically, we show that the fat-pointer check and update operations can run in a 4 ns clock cycle on a Virtex 6 (40nm) implementation while only using 1100 6-{LUTs} or about the area of a double-precision, floating-point adder.}, + pages = {721--732}, + booktitle = {Proceedings of the 2013 {ACM} {SIGSAC} conference on Computer \& communications security}, + publisher = {Association for Computing Machinery}, + author = {Kwon, Albert and Dhawan, Udit and Smith, Jonathan M. and Knight, Thomas F. and {DeHon}, Andre}, + urldate = {2024-06-18}, + date = {2013-11-04}, + keywords = {capabilities, fat pointer, memory safety, processor, security, spatial confinement}, + file = {Full Text PDF:/Users/akilan/Zotero/storage/CVVZYZS4/Kwon et al. - 2013 - Low-fat pointers compact encoding and efficient g.pdf:application/pdf}, +} + +@article{wulf_hydra_1974, + title = {{HYDRA}: the kernel of a multiprocessor operating system}, + volume = {17}, + issn = {0001-0782, 1557-7317}, + url = {https://dl.acm.org/doi/10.1145/355616.364017}, + doi = {10.1145/355616.364017}, + shorttitle = {{HYDRA}}, + abstract = {This paper describes the design philosophy of {HYDRA}—the kernel of an operating system for C.mmp, the Carnegie-Mellon Multi-Mini-Processor. This philosophy is realized through the introduction of a generalized notion of “resource,” both physical and virtual, called an “object.” Mechanisms are presented for dealing with objects, including the creation of new types, specification of new operations applicable to a given type, sharing, and protection of any reference to a given object against improper application of any of the operations defined with respect to that type of object. The mechanisms provide a coherent basis for extension of the system in two directions: the introduction of new facilities, and the creation of highly secure systems.}, + pages = {337--345}, + number = {6}, + journaltitle = {Communications of the {ACM}}, + shortjournal = {Commun. {ACM}}, + author = {Wulf, W. and Cohen, E. and Corwin, W. and Jones, A. and Levin, R. and Pierson, C. and Pollack, F.}, + urldate = {2024-06-18}, + date = {1974-06}, + langid = {english}, + file = {Full Text:/Users/akilan/Zotero/storage/EIRBNTVF/Wulf et al. - 1974 - HYDRA the kernel of a multiprocessor operating sy.pdf:application/pdf}, +} + +@article{hardy_keykos_1985, + title = {{KeyKOS} architecture}, + volume = {19}, + issn = {0163-5980}, + url = {https://dl.acm.org/doi/10.1145/858336.858337}, + doi = {10.1145/858336.858337}, + pages = {8--25}, + number = {4}, + journaltitle = {{ACM} {SIGOPS} Operating Systems Review}, + shortjournal = {{SIGOPS} Oper. Syst. Rev.}, + author = {Hardy, Norman}, + urldate = {2024-06-18}, + date = {1985-10-01}, + file = {Full Text PDF:/Users/akilan/Zotero/storage/QSYKM6QN/Hardy - 1985 - KeyKOS architecture.pdf:application/pdf}, +} + +@article{rashid_mach_nodate, + title = {Mach: A System Software Kernel}, + abstract = {The Mach operating system can be used as a system software kernel which can support a variety of operating system environments. Key elements of the Mach design which allow it to efficiently support system software include integrated virtual memory management and interprocess communication, multiple threads of control within one address space, support for transparent system trap callout and an object programming facility integrated with the Mach {IPC} mechanisms. Mach is currently available both from {CMU} and commercially on a wide range of uniprocessor and multiprocessor hardware.}, + author = {Rashid, Richard and Julin, Daniel and Orr, Douglas and Sanzi, Richard and Baron, Robert and Forin, Alessandro and Golub, David and Jones, Michael}, + langid = {english}, + file = {Rashid et al. - Mach A System Software Kernel.pdf:/Users/akilan/Zotero/storage/UHLILYH9/Rashid et al. - Mach A System Software Kernel.pdf:application/pdf}, +} + +@inproceedings{baumann_multikernel_2009, + location = {Big Sky Montana {USA}}, + title = {The multikernel: a new {OS} architecture for scalable multicore systems}, + isbn = {978-1-60558-752-3}, + url = {https://dl.acm.org/doi/10.1145/1629575.1629579}, + doi = {10.1145/1629575.1629579}, + shorttitle = {The multikernel}, + abstract = {Commodity computer systems contain more and more processor cores and exhibit increasingly diverse architectural tradeoffs, including memory hierarchies, interconnects, instruction sets and variants, and {IO} configurations. Previous high-performance computing systems have scaled in specific cases, but the dynamic nature of modern client and server workloads, coupled with the impossibility of statically optimizing an {OS} for all workloads and hardware variants pose serious challenges for operating system structures.}, + eventtitle = {{SOSP}09: {ACM} {SIGOPS} 22nd Symposium on Operating Systems Principles}, + pages = {29--44}, + booktitle = {Proceedings of the {ACM} {SIGOPS} 22nd symposium on Operating systems principles}, + publisher = {{ACM}}, + author = {Baumann, Andrew and Barham, Paul and Dagand, Pierre-Evariste and Harris, Tim and Isaacs, Rebecca and Peter, Simon and Roscoe, Timothy and Schüpbach, Adrian and Singhania, Akhilesh}, + urldate = {2024-06-18}, + date = {2009-10-11}, + langid = {english}, + file = {Baumann et al. - 2009 - The multikernel a new OS architecture for scalabl.pdf:/Users/akilan/Zotero/storage/4BVCRZN6/Baumann et al. - 2009 - The multikernel a new OS architecture for scalabl.pdf:application/pdf}, +} + +@article{watson_capsicum_nodate, + title = {Capsicum: practical capabilities for {UNIX}}, + abstract = {Capsicum is a lightweight operating system capability and sandbox framework planned for inclusion in {FreeBSD} 9. Capsicum extends, rather than replaces, {UNIX} {APIs}, providing new kernel primitives (sandboxed capability mode and capabilities) and a userspace sandbox {API}. These tools support compartmentalisation of monolithic {UNIX} applications into logical applications, an increasingly common goal supported poorly by discretionary and mandatory access control. We demonstrate our approach by adapting core {FreeBSD} utilities and Google’s Chromium web browser to use Capsicum primitives, and compare the complexity and robustness of Capsicum with other sandboxing techniques.}, + author = {Watson, Robert N M and Anderson, Jonathan and Kennaway, Kris and Laurie, Ben}, + langid = {english}, + file = {Watson et al. - Capsicum practical capabilities for UNIX.pdf:/Users/akilan/Zotero/storage/IAFXHJ8H/Watson et al. - Capsicum practical capabilities for UNIX.pdf:application/pdf}, +} + +@online{noauthor_department_nodate, + title = {Department of Computer Science and Technology: {CheriBSD}}, + url = {https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/cheribsd.html}, + urldate = {2024-06-18}, + file = {Department of Computer Science and Technology\: CheriBSD:/Users/akilan/Zotero/storage/3XQJWCXD/cheribsd.html:text/html}, +} + +@online{noauthor_msrc-security-researchpapers2020security_nodate, + title = {{MSRC}-Security-Research/papers/2020/Security analysis of {CHERI} {ISA}.pdf at master · microsoft/{MSRC}-Security-Research}, + url = {https://github.com/microsoft/MSRC-Security-Research/blob/master/papers/2020/Security%20analysis%20of%20CHERI%20ISA.pdf}, + abstract = {Security Research from the Microsoft Security Response Center ({MSRC}) - microsoft/{MSRC}-Security-Research}, + titleaddon = {{GitHub}}, + urldate = {2024-06-18}, + langid = {english}, + file = {Snapshot:/Users/akilan/Zotero/storage/ENF2KYRT/Security analysis of CHERI ISA.html:text/html}, +} + +@inproceedings{zaliva_formal_2024, + location = {La Jolla {CA} {USA}}, + title = {Formal Mechanised Semantics of {CHERI} C: Capabilities, Undefined Behaviour, and Provenance}, + isbn = {9798400703720}, + url = {https://dl.acm.org/doi/10.1145/3617232.3624859}, + doi = {10.1145/3617232.3624859}, + shorttitle = {Formal Mechanised Semantics of {CHERI} C}, + abstract = {Memory safety issues are a persistent source of security vulnerabilities, with conventional architectures and the C codebase chronically prone to exploitable errors. The {CHERI} research project has shown how one can provide radically improved security for that existing codebase with minimal modification, using unforgeable hardware capabilities in place of machine-word pointers in {CHERI} dialects of C, implemented as adaptions of Clang/{LLVM} and {GCC}. {CHERI} was first prototyped as extensions of {MIPS} and {RISC}-V; it is currently being evaluated by Arm and others with the Arm Morello experimental architecture, processor, and platform, to explore its potential for mass-market adoption, and by Microsoft in their {CHERIoT} design for embedded cores.}, + eventtitle = {{ASPLOS} '24: 29th {ACM} International Conference on Architectural Support for Programming Languages and Operating Systems, Volume 1}, + pages = {181--196}, + booktitle = {Proceedings of the 29th {ACM} International Conference on Architectural Support for Programming Languages and Operating Systems, Volume 1}, + publisher = {{ACM}}, + author = {Zaliva, Vadim and Memarian, Kayvan and Almeida, Ricardo and Clarke, Jessica and Davis, Brooks and Richardson, Alexander and Chisnall, David and Campbell, Brian and Stark, Ian and Watson, Robert N. M. and Sewell, Peter}, + urldate = {2024-06-18}, + date = {2024-04-27}, + langid = {english}, + file = {Zaliva et al. - 2024 - Formal Mechanised Semantics of CHERI C Capabiliti.pdf:/Users/akilan/Zotero/storage/8Y2CRHBS/Zaliva et al. - 2024 - Formal Mechanised Semantics of CHERI C Capabiliti.pdf:application/pdf}, +} + +@article{watson_cheri_nodate, + title = {{CHERI} C/C++ Programming Guide}, + abstract = {This document is a brief introduction to the {CHERI} C/C++ programming languages. We explain the principles underlying these language variants, and their grounding in {CHERI}’s multiple architectural instantiations: {CHERI}-{MIPS}, {CHERI}-{RISC}-V, and Arm’s Morello. We describe the most commonly encountered differences between these dialects and C/C++ on conventional architectures, and where existing software may require minor changes. We document new compiler warnings and errors that may be experienced compiling code with the {CHERI} Clang/{LLVM} compiler, and suggest how they may be addressed through typically minor source-code changes. We explain how modest language extensions allow selected software, such as memory allocators, to further refine permissions and bounds on pointers. This guidance is based on our experience adapting the {FreeBSD} operating-system userspace, and applications such as {PostgreSQL} and {WebKit}, to run in a {CHERI} C/C++ capability-based programming environment. We conclude by recommending further reading.}, + author = {Watson, Robert N M and Richardson, Alexander and Davis, Brooks and Baldwin, John and Chisnall, David and Clarke, Jessica and Filardo, Nathaniel and Moore, Simon W and Napierala, Edward and Sewell, Peter and Neumann, Peter G}, + langid = {english}, + file = {Watson et al. - CHERI CC++ Programming Guide.pdf:/Users/akilan/Zotero/storage/WHGQXE8P/Watson et al. - CHERI CC++ Programming Guide.pdf:application/pdf}, +} + +@article{esswood_cherios_nodate-1, + title = {{CheriOS}: designing an untrusted single-address-space capability operating system utilising capability hardware and a minimal hypervisor}, + author = {Esswood, Lawrence G}, + langid = {english}, + file = {Esswood - CheriOS designing an untrusted single-address-spa.pdf:/Users/akilan/Zotero/storage/3IVKGYZ5/Esswood - CheriOS designing an untrusted single-address-spa.pdf:application/pdf}, +} + +@online{noauthor_architecture_nodate, + title = {The Architecture  of the Burroughs B-5000}, + url = {https://www.smecc.org/The%20Architecture%20%20of%20the%20Burroughs%20B-5000.htm}, + urldate = {2024-06-18}, + file = {The Architecture  of the Burroughs B-5000:/Users/akilan/Zotero/storage/ELNL8VBQ/The Architecture of the Burroughs B-5000.html:text/html}, +} + +@article{dennis_programming_1966, + title = {Programming semantics for multiprogrammed computations}, + volume = {9}, + issn = {0001-0782, 1557-7317}, + url = {https://dl.acm.org/doi/10.1145/365230.365252}, + doi = {10.1145/365230.365252}, + abstract = {The semantics are defined for a number of meta-instructions which perform operations essential to the writing of programs in multiprogrammed computer systems. These meta-instructions relate to parallel processing, protecting of separate computations, program debugging, and the sharing among users of memory segments and other computing objects, the names of which are hierarchically structured. The language sophistication contemplated is midway between an assembly language and an advanced algebraic language.}, + pages = {143--155}, + number = {3}, + journaltitle = {Communications of the {ACM}}, + shortjournal = {Commun. {ACM}}, + author = {Dennis, Jack B. and Van Horn, Earl C.}, + urldate = {2024-06-18}, + date = {1966-03}, + langid = {english}, + file = {Full Text:/Users/akilan/Zotero/storage/6MLX2U8V/Dennis and Van Horn - 1966 - Programming semantics for multiprogrammed computat.pdf:application/pdf}, +} + +@article{watson_capability_nodate, + title = {Capability Hardware Enhanced {RISC} Instructions: {CHERI} Instruction-Set Architecture (Version 8)}, + abstract = {This technical report describes {CHERI} {ISAv}8, the eighth version of the {CHERI} architecture being developed by {SRI} International and the University of Cambridge. This design captures ten years of research, development, experimentation, refinement, formal analysis, and validation through hardware and software implementation.}, + author = {Watson, Robert N M and Neumann, Peter G and Woodruff, Jonathan and Roe, Michael and Almatary, Hesham and Anderson, Jonathan and Baldwin, John and Barnes, Graeme and Chisnall, David and Clarke, Jessica and Davis, Brooks and Eisen, Lee and Filardo, Nathaniel Wesley and Grisenthwaite, Richard and Joannou, Alexandre and Laurie, Ben and Markettos, A Theodore and Moore, Simon W and Murdoch, Steven J and Nienhuis, Kyndylan and Norton, Robert and Richardson, Alexander and Rugg, Peter and Sewell, Peter and Son, Stacey and Xia, Hongyan}, + langid = {english}, + file = {Watson et al. - Capability Hardware Enhanced RISC Instructions CH.pdf:/Users/akilan/Zotero/storage/R9T374YS/Watson et al. - Capability Hardware Enhanced RISC Instructions CH.pdf:application/pdf}, +} + +@online{noauthor_-it-yourself_nodate, + title = {Do-It-Yourself Virtual Memory Translation {\textbar} {ACM} {SIGARCH} Computer Architecture News}, + url = {https://dl.acm.org/doi/10.1145/3140659.3080209}, + urldate = {2024-06-18}, +} + +@online{noauthor_osdi_nodate, + title = {{OSDI} Symposia {\textbar} {USENIX}}, + url = {https://www.usenix.org/conferences/byname/179}, + urldate = {2024-06-19}, + file = {OSDI Symposia | USENIX:/Users/akilan/Zotero/storage/VI7YCLJV/179.html:text/html}, +} + +@article{mittal_survey_2017, + title = {A survey of techniques for architecting {TLBs}}, + volume = {29}, + rights = {Copyright © 2016 John Wiley \& Sons, Ltd.}, + issn = {1532-0634}, + url = {https://onlinelibrary.wiley.com/doi/abs/10.1002/cpe.4061}, + doi = {10.1002/cpe.4061}, + abstract = {Translation lookaside buffer ({TLB}) caches virtual to physical address translation information and is used in systems ranging from embedded devices to high-end servers. Because {TLB} is accessed very frequently and a {TLB} miss is extremely costly, prudent management of {TLB} is important for improving performance and energy efficiency of processors. In this paper, we present a survey of techniques for architecting and managing {TLBs}. We characterize the techniques across several dimensions to highlight their similarities and distinctions. We believe that this paper will be useful for chip designers, computer architects, and system engineers.}, + pages = {e4061}, + number = {10}, + journaltitle = {Concurrency and Computation: Practice and Experience}, + author = {Mittal, Sparsh}, + urldate = {2024-06-24}, + date = {2017}, + langid = {english}, + note = {\_eprint: https://onlinelibrary.wiley.com/doi/pdf/10.1002/cpe.4061}, + keywords = {classification, power management, prefetching, Review, superpage, {TLB}, virtual cache, workload characterization}, + file = {Snapshot:/Users/akilan/Zotero/storage/JJ9H6B2H/cpe.html:text/html}, +} + +@inproceedings{lietar_snmalloc_2019, + location = {New York, {NY}, {USA}}, + title = {snmalloc: a message passing allocator}, + isbn = {978-1-4503-6722-6}, + url = {https://doi.org/10.1145/3315573.3329980}, + doi = {10.1145/3315573.3329980}, + series = {{ISMM} 2019}, + shorttitle = {snmalloc}, + abstract = {snmalloc is an implementation of malloc aimed at workloads in which objects are typically deallocated by a different thread than the one that had allocated them. We use the term producer/consumer for such workloads. snmalloc uses a novel message passing scheme which returns deallocated objects to the originating allocator in batches without taking any locks. It also uses a novel bump pointer-free list data structure with which just 64-bits of meta-data are sufficient for each 64 {KiB} slab. On such producer/consumer benchmarks our approach performs better than existing allocators. Snmalloc is available at {\textless}a href="https://github.com/Microsoft/snmalloc"{\textgreater}https://github.com/Microsoft/snmalloc{\textless}/a{\textgreater}.}, + pages = {122--135}, + booktitle = {Proceedings of the 2019 {ACM} {SIGPLAN} International Symposium on Memory Management}, + publisher = {Association for Computing Machinery}, + author = {Liétar, Paul and Butler, Theodore and Clebsch, Sylvan and Drossopoulou, Sophia and Franco, Juliana and Parkinson, Matthew J. and Shamis, Alex and Wintersteiger, Christoph M. and Chisnall, David}, + urldate = {2024-06-23}, + date = {2019-06-23}, + keywords = {Memory allocation, message passing}, +} diff --git a/docs/introduction/introduction.org b/docs/introduction/introduction.org new file mode 100644 index 0000000..d238691 --- /dev/null +++ b/docs/introduction/introduction.org @@ -0,0 +1,62 @@ +* Introduction +In computing, achieving high performance is an ongoing challenge, especially as +applications handle increasingly complex workloads. Memory management is a key factor +in performance, where efficient use of resources is essential. Translation Lookaside +Buffers (TLBs) are crucial in this context, speeding up memory access by caching recent +memory address translations. A TLB, a specialised cache in the memory management unit (MMU), +reduces the time required to convert virtual addresses to physical ones. When a program accesses +data in memory, the MMU first checks the TLB for a matching entry, avoiding the slower process of +consulting page tables. However, as applications grow larger and more complex, the fixed size of +TLBs often cannot keep up, leading to more TLB misses and performance slowdowns\cite{mittal_survey_2017}. +To tackle this issue, researchers have explored new solutions, including the use of +huge pages\cite{panwar_hawkeye_2019}. + +Huge pages, also known as large pages, allow for the allocation of memory in significantly larger chunks +compared to traditional small pages. By reducing the number of TLB entries needed to access a given amount +of memory, Huge pages offer a potential avenue for optimising TLB utilisation by reducing the number +of entries needed to map large memory regions. This not only decreases the frequency of +TLB misses but also lowers the overhead associated with address translation. By minimising +these bottlenecks, huge pages can improve system performance in several ways, such as speeding +up memory-intensive applications, reducing latency in data access, and enhancing throughput for +workloads that rely heavily on large datasets. + +Simultaneously, advancements in hardware-level security, such as the Capability Hardware Enhanced RISC Instructions (CHERI) +\cite{woodruff_cheri_2014} architecture, present additional opportunities for performance enhancement. CHERI's capability-based addressing approach not +only strengthens system security by tightly controlling memory access but also opens avenues for optimising memory management +operations. By integrating CHERI’s compressed\cite{woodruff_cheri_2019} encoded bounds with the use of huge pages, it becomes possible to track and manage +large, physically contiguous memory blocks more efficiently. This combination reduces TLB pressure by minimising the number of +entries required to map extensive memory regions, thereby decreasing TLB misses and improving address translation performance. +Furthermore, it accelerates memory-intensive tasks by reducing the overhead associated with managing fragmented or non-contiguous +memory allocations. The contributions for the following paper are as follows: + +- **Fat-pointer Based Range Addresses**: Introduces fat-pointers that include memory bounds, allowing + efficient tracking and management of physically contiguous memory regions. + +- **Custom Memory Allocation with Huge Pages**: Proposes a custom `mmap` function and + kernel module for allocating huge pages of physically contiguous memory, reducing the need for traditional + TLB entries and improving efficiency. + +- **Novel Memory Allocation Algorithms**: Provides new algorithms for allocating and freeing + physically contiguous memory, integrating huge pages with CHERI’s capability-based bounds for enhanced memory management. + +- **CHERI’s Capability-based Optimization**: Demonstrates how CHERI's architecture can be + used to optimize memory allocation by encoding memory bounds directly within pointers, reducing TLB reliance. + +Through comprehensive evaluation, including micro and macro benchmarks, we demonstrate the allocator’s ability +to reduce TLB misses by up to 90%, yielding significant improvements in wall clock runtimes for memory-intensive +applications. While its impact on larger, computation-heavy workloads is less pronounced, +the proposed allocator shows strong potential for advancing memory management in scenarios requiring +high memory throughput and low translation overhead. The following below are research questions +we are addressing: + +1. How does the utilization of bounds for tracking memory allocations, in addition to security purposes, affect the + run times and Translation Lookaside Buffer (TLB) miss rates in modern computing systems? + +2. How does the implementation of bounds for seeking through physically contiguous memory influence the complexity and + efficiency of standard memory allocators, particularly those with advanced features such as transparent + huge pages, and what are the implications for system performance in terms of execution speed, memory access + latency, and resource utilization? + +\bibliographystyle{IEEEtran} +\bibliography{introduction.bib} + diff --git a/docs/introduction/introduction.org~ b/docs/introduction/introduction.org~ new file mode 100644 index 0000000..e1dfe09 --- /dev/null +++ b/docs/introduction/introduction.org~ @@ -0,0 +1,62 @@ +* Introduction +In computing, achieving high performance is an ongoing challenge, especially as +applications handle increasingly complex workloads. Memory management is a key factor +in performance, where efficient use of resources is essential. Translation Lookaside +Buffers (TLBs) are crucial in this context, speeding up memory access by caching recent +memory address translations. A TLB, a specialised cache in the memory management unit (MMU), +reduces the time required to convert virtual addresses to physical ones. When a program accesses +data in memory, the MMU first checks the TLB for a matching entry, avoiding the slower process of +consulting page tables. However, as applications grow larger and more complex, the fixed size of +TLBs often cannot keep up, leading to more TLB misses and performance slowdowns\cite{mittal_survey_2017}. +To tackle this issue, researchers have explored new solutions, including the use of +huge pages\cite{panwar_hawkeye_2019}. + +Huge pages, also known as large pages, allow for the allocation of memory in significantly larger chunks +compared to traditional small pages. By reducing the number of TLB entries needed to access a given amount +of memory, Huge pages offer a potential avenue for optimising TLB utilisation by reducing the number +of entries needed to map large memory regions. This not only decreases the frequency of +TLB misses but also lowers the overhead associated with address translation. By minimising +these bottlenecks, huge pages can improve system performance in several ways, such as speeding +up memory-intensive applications, reducing latency in data access, and enhancing throughput for +workloads that rely heavily on large datasets. + +Simultaneously, advancements in hardware-level security, such as the Capability Hardware Enhanced RISC Instructions (CHERI) +architecture, present additional opportunities for performance enhancement. CHERI's capability-based addressing approach not +only strengthens system security by tightly controlling memory access but also opens avenues for optimising memory management +operations. By integrating CHERI’s compressed encoded bounds with the use of huge pages, it becomes possible to track and manage +large, physically contiguous memory blocks more efficiently. This combination reduces TLB pressure by minimising the number of +entries required to map extensive memory regions, thereby decreasing TLB misses and improving address translation performance. +Furthermore, it accelerates memory-intensive tasks by reducing the overhead associated with managing fragmented or non-contiguous +memory allocations. The contributions for the following paper are as follows: + +- **Fat-pointer Based Range Addresses**: Introduces fat-pointers that include memory bounds, allowing + efficient tracking and management of physically contiguous memory regions. + +- **Custom Memory Allocation with Huge Pages**: Proposes a custom `mmap` function and + kernel module for allocating huge pages of physically contiguous memory, reducing the need for traditional + TLB entries and improving efficiency. + +- **Novel Memory Allocation Algorithms**: Provides new algorithms for allocating and freeing + physically contiguous memory, integrating huge pages with CHERI’s capability-based bounds for enhanced memory management. + +- **CHERI’s Capability-based Optimization**: Demonstrates how CHERI's architecture can be + used to optimize memory allocation by encoding memory bounds directly within pointers, reducing TLB reliance. + +Through comprehensive evaluation, including micro and macro benchmarks, we demonstrate the allocator’s ability +to reduce TLB misses by up to 90%, yielding significant improvements in wall clock runtimes for memory-intensive +applications. While its impact on larger, computation-heavy workloads is less pronounced, +the proposed allocator shows strong potential for advancing memory management in scenarios requiring +high memory throughput and low translation overhead. The following below are research questions +we are addressing: + +1. How does the utilization of bounds for tracking memory allocations, in addition to security purposes, affect the + run times and Translation Lookaside Buffer (TLB) miss rates in modern computing systems? + +2. How does the implementation of bounds for seeking through physically contiguous memory influence the complexity and + efficiency of standard memory allocators, particularly those with advanced features such as transparent + huge pages, and what are the implications for system performance in terms of execution speed, memory access + latency, and resource utilization? + +\bibliographystyle{IEEEtran} +\bibliography{introduction.bib} + diff --git a/docs/introduction/introduction.pdf b/docs/introduction/introduction.pdf new file mode 100644 index 0000000000000000000000000000000000000000..07fcc50f6beb8d966d945a4ffdda7bdb31f7e0c5 GIT binary patch literal 111098 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

>c1$3mQ~9gmSrxN|4C=I`RQpn9 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 literal 0 HcmV?d00001 diff --git a/docs/introduction/introduction.tex b/docs/introduction/introduction.tex new file mode 100644 index 0000000..3612639 --- /dev/null +++ b/docs/introduction/introduction.tex @@ -0,0 +1,95 @@ +% Created 2025-01-20 Mon 13:33 +% Intended LaTeX compiler: pdflatex +\documentclass[11pt]{article} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{graphicx} +\usepackage{longtable} +\usepackage{wrapfig} +\usepackage{rotating} +\usepackage[normalem]{ulem} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{capt-of} +\usepackage{hyperref} +\author{Akilan} +\date{\today} +\title{} +\hypersetup{ + pdfauthor={Akilan}, + pdftitle={}, + pdfkeywords={}, + pdfsubject={}, + pdfcreator={Emacs 29.1 (Org mode 9.6.6)}, + pdflang={English}} +\begin{document} + +\tableofcontents + +\section{Introduction} +\label{sec:org01b31aa} +In computing, achieving high performance is an ongoing challenge, especially as +applications handle increasingly complex workloads. Memory management is a key factor +in performance, where efficient use of resources is essential. Translation Lookaside +Buffers (TLBs) are crucial in this context, speeding up memory access by caching recent +memory address translations. A TLB, a specialised cache in the memory management unit (MMU), +reduces the time required to convert virtual addresses to physical ones. When a program accesses +data in memory, the MMU first checks the TLB for a matching entry, avoiding the slower process of +consulting page tables. However, as applications grow larger and more complex, the fixed size of +TLBs often cannot keep up, leading to more TLB misses and performance slowdowns\cite{mittal_survey_2017}. +To tackle this issue, researchers have explored new solutions, including the use of +huge pages\cite{panwar_hawkeye_2019}. + +Huge pages, also known as large pages, allow for the allocation of memory in significantly larger chunks +compared to traditional small pages. By reducing the number of TLB entries needed to access a given amount +of memory, Huge pages offer a potential avenue for optimising TLB utilisation by reducing the number +of entries needed to map large memory regions. This not only decreases the frequency of +TLB misses but also lowers the overhead associated with address translation. By minimising +these bottlenecks, huge pages can improve system performance in several ways, such as speeding +up memory-intensive applications, reducing latency in data access, and enhancing throughput for +workloads that rely heavily on large datasets. + +Simultaneously, advancements in hardware-level security, such as the Capability Hardware Enhanced RISC Instructions (CHERI) +\cite{woodruff_cheri_2014} architecture, present additional opportunities for performance enhancement. CHERI's capability-based addressing approach not +only strengthens system security by tightly controlling memory access but also opens avenues for optimising memory management +operations. By integrating CHERI’s compressed\cite{woodruff_cheri_2019} encoded bounds with the use of huge pages, it becomes possible to track and manage +large, physically contiguous memory blocks more efficiently. This combination reduces TLB pressure by minimising the number of +entries required to map extensive memory regions, thereby decreasing TLB misses and improving address translation performance. +Furthermore, it accelerates memory-intensive tasks by reducing the overhead associated with managing fragmented or non-contiguous +memory allocations. The contributions for the following paper are as follows: + +\begin{itemize} +\item \textbf{\textbf{Fat-pointer Based Range Addresses}}: Introduces fat-pointers that include memory bounds, allowing +efficient tracking and management of physically contiguous memory regions. + +\item \textbf{\textbf{Custom Memory Allocation with Huge Pages}}: Proposes a custom `mmap` function and +kernel module for allocating huge pages of physically contiguous memory, reducing the need for traditional +TLB entries and improving efficiency. + +\item \textbf{\textbf{Novel Memory Allocation Algorithms}}: Provides new algorithms for allocating and freeing +physically contiguous memory, integrating huge pages with CHERI’s capability-based bounds for enhanced memory management. + +\item \textbf{\textbf{CHERI’s Capability-based Optimization}}: Demonstrates how CHERI's architecture can be +used to optimize memory allocation by encoding memory bounds directly within pointers, reducing TLB reliance. +\end{itemize} + +Through comprehensive evaluation, including micro and macro benchmarks, we demonstrate the allocator’s ability +to reduce TLB misses by up to 90\%, yielding significant improvements in wall clock runtimes for memory-intensive +applications. While its impact on larger, computation-heavy workloads is less pronounced, +the proposed allocator shows strong potential for advancing memory management in scenarios requiring +high memory throughput and low translation overhead. The following below are research questions +we are addressing: + +\begin{enumerate} +\item How does the utilization of bounds for tracking memory allocations, in addition to security purposes, affect the +run times and Translation Lookaside Buffer (TLB) miss rates in modern computing systems? + +\item How does the implementation of bounds for seeking through physically contiguous memory influence the complexity and +efficiency of standard memory allocators, particularly those with advanced features such as transparent +huge pages, and what are the implications for system performance in terms of execution speed, memory access +latency, and resource utilization? +\end{enumerate} + +\bibliographystyle{IEEEtran} +\bibliography{introduction.bib} +\end{document} \ No newline at end of file diff --git a/dpdk/kernel/freebsd/Hugepage/BSDmakefile b/dpdk/kernel/freebsd/Hugepage/BSDmakefile new file mode 100644 index 0000000..71b36a8 --- /dev/null +++ b/dpdk/kernel/freebsd/Hugepage/BSDmakefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# + +KMOD= Hugepage +SRCS= Hugepage.c device_if.h bus_if.h + +.include \ No newline at end of file diff --git a/dpdk/kernel/freebsd/Hugepage/Hugepage.c b/dpdk/kernel/freebsd/Hugepage/Hugepage.c new file mode 100644 index 0000000..f9d440f --- /dev/null +++ b/dpdk/kernel/freebsd/Hugepage/Hugepage.c @@ -0,0 +1,518 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +// #include +#include + +#include +#include +#include +// #include + +// #include +// #include +#include +#include +// #include +// #include +// #include + + +// #include +// #include +// #include + +// added to print uint +// 64 +// #include + +struct contigmem_buffer { + void *addr; + int refcnt; + struct mtx mtx; +}; + +struct contigmem_vm_handle { + int buffer_index; +}; + +static int contigmem_load(void); +static int contigmem_unload(void); +static int contigmem_physaddr(SYSCTL_HANDLER_ARGS); + +static d_mmap_single_t contigmem_mmap_single; +static d_open_t contigmem_open; +static d_close_t contigmem_close; + +static int contigmem_num_buffers = RTE_CONTIGMEM_DEFAULT_NUM_BUFS; +static int64_t contigmem_buffer_size = RTE_CONTIGMEM_DEFAULT_BUF_SIZE; + +static eventhandler_tag contigmem_eh_tag; +static struct contigmem_buffer contigmem_buffers[RTE_CONTIGMEM_MAX_NUM_BUFS]; +static struct cdev *contigmem_cdev = NULL; +static int contigmem_refcnt; + +TUNABLE_INT("hw.contigmem.num_buffers", &contigmem_num_buffers); +TUNABLE_QUAD("hw.contigmem.buffer_size", &contigmem_buffer_size); + +static SYSCTL_NODE(_hw, OID_AUTO, contigmem, CTLFLAG_RD, 0, "contigmem"); + +SYSCTL_INT(_hw_contigmem, OID_AUTO, num_buffers, CTLFLAG_RD, + &contigmem_num_buffers, 0, "Number of contigmem buffers allocated"); +SYSCTL_QUAD(_hw_contigmem, OID_AUTO, buffer_size, CTLFLAG_RD, + &contigmem_buffer_size, 0, "Size of each contiguous buffer"); +SYSCTL_INT(_hw_contigmem, OID_AUTO, num_references, CTLFLAG_RD, + &contigmem_refcnt, 0, "Number of references to contigmem"); + +static SYSCTL_NODE(_hw_contigmem, OID_AUTO, physaddr, CTLFLAG_RD, 0, + "physaddr"); + +MALLOC_DEFINE(M_CONTIGMEM, "customcontigmem", "customcontigmem(4) allocations"); + +void *ptr; +int MallocCounter; + +#define MAXPAGESIZES 2 + + +/* + * The offset in sysent where the syscall is allocated. + */ +static int offset = NO_SYSCALL; + +static int contigmem_modevent(module_t mod, int type, void *arg) +{ + int error = 0; + + switch (type) { + case MOD_LOAD: + error = contigmem_load(); + break; + case MOD_UNLOAD: + error = contigmem_unload(); + break; + default: + break; + } + + return error; +} + +moduledata_t contigmem_mod = { + "contigmem", + (modeventhand_t)contigmem_modevent, + 0 +}; + +DECLARE_MODULE(contigmem, contigmem_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); +MODULE_VERSION(contigmem, 1); + +static struct cdevsw contigmem_ops = { + .d_name = "contigmem", + .d_version = D_VERSION, + .d_flags = D_TRACKCLOSE, + .d_mmap_single = contigmem_mmap_single, + .d_open = contigmem_open, + .d_close = contigmem_close, +}; + +static int +pagesizes(size_t ps[MAXPAGESIZES]) +{ + int pscnt; + + pscnt = getpagesizes(ps, MAXPAGESIZES); + // ATF_REQUIRE_MSG(pscnt != -1, "getpagesizes failed; errno=%d", errno); + // ATF_REQUIRE_MSG(ps[0] != 0, "psind 0 is %zu", ps[0]); + // ATF_REQUIRE_MSG(pscnt <= MAXPAGESIZES, "invalid pscnt %d", pscnt); + // if (pscnt == 1){ + // printf("pscnt is 1"); + // } + + // atf_tc_skip("no large page support"); + return (pscnt); +} + +static int +contigmem_load() +{ + + size_t sz; + // Pre Allocate 1GB huge page + sz = 1073741824; + + int error, fd, pscnt, pn; + + size_t ps[MAXPAGESIZES]; + + size_t size[3]; + + pn = getpagesizes(size, 3); + printf("page size is [%d]", size[2]); + + pscnt = pagesizes(ps); + + fd = shm_create_largepage(SHM_ANON, O_CREAT | O_RDWR, 1, SHM_LARGEPAGE_ALLOC_DEFAULT, 0); + + if (fd < 0 && errno == ENOTTY) { + // perror("sh_create_largepages"); + close(fd); + } + // if (fd < 0) + // perror("no large page supported"); + // exit(EXIT_FAILURE); + // if (fd < 0 && errno == ENOTTY) + // atf_tc_skip("no large page support"); + // ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; errno=%d", errno); + + if (ftruncate(fd, sz) < 0) { + // perror("ftruncate"); + close(fd); + } + // if (error != 0 && errno == ENOMEM) + // /* + // * The test system might not have enough memory to accommodate + // * the request. + // */ + // atf_tc_skip("failed to allocate %zu-byte superpage", sz); + // ATF_REQUIRE_MSG(error == 0, "ftruncate failed; errno=%d", errno); + + ptr = mmap(NULL, sz, + PROT_READ|PROT_WRITE, MAP_SHARED,fd,0); + + // Added error handling + if(ptr == MAP_FAILED) + { + // perror("mmap"); + exit(EXIT_FAILURE); + } + + MallocCounter = (int)sz; + + return 0; +} + +static int +contigmem_unload() +{ + // int i; + + // if (contigmem_refcnt > 0) + // return EBUSY; + + // if (contigmem_cdev != NULL) + // destroy_dev(contigmem_cdev); + + // if (contigmem_eh_tag != NULL) + // EVENTHANDLER_DEREGISTER(process_exit, contigmem_eh_tag); + + // for (i = 0; i < RTE_CONTIGMEM_MAX_NUM_BUFS; i++) { + // if (contigmem_buffers[i].addr != NULL) + // contigfree(contigmem_buffers[i].addr, + // contigmem_buffer_size, M_CONTIGMEM); + // if (mtx_initialized(&contigmem_buffers[i].mtx)) + // mtx_destroy(&contigmem_buffers[i].mtx); + // } + + // printf("free called \n"); + + // get bounds from + + // printf("free len %d \n", len); + + // Free the entire huge page + + munmap(ptr, 1073741824); + + + return 0; +} + +static int +contigmem_physaddr(SYSCTL_HANDLER_ARGS) +{ + uint64_t physaddr; + int index = (int)(uintptr_t)arg1; + + physaddr = (uint64_t)vtophys(contigmem_buffers[index].addr); + return sysctl_handle_64(oidp, &physaddr, 0, req); +} + +static int +contigmem_open(struct cdev *cdev, int fflags, int devtype, + struct thread *td) +{ + + printf("Contigmem opened \n"); + + atomic_add_int(&contigmem_refcnt, 1); + + return 0; +} + +static int +contigmem_close(struct cdev *cdev, int fflags, int devtype, + struct thread *td) +{ + + atomic_subtract_int(&contigmem_refcnt, 1); + + return 0; +} + +static int +contigmem_cdev_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, + vm_ooffset_t foff, struct ucred *cred, u_short *color) +{ + struct contigmem_vm_handle *vmh = handle; + struct contigmem_buffer *buf; + + buf = &contigmem_buffers[vmh->buffer_index]; + + atomic_add_int(&contigmem_refcnt, 1); + + mtx_lock(&buf->mtx); + if (buf->refcnt == 0) + memset(buf->addr, 0, contigmem_buffer_size); + buf->refcnt++; + mtx_unlock(&buf->mtx); + + return 0; +} + +static void +contigmem_cdev_pager_dtor(void *handle) +{ + struct contigmem_vm_handle *vmh = handle; + struct contigmem_buffer *buf; + + buf = &contigmem_buffers[vmh->buffer_index]; + + mtx_lock(&buf->mtx); + buf->refcnt--; + mtx_unlock(&buf->mtx); + + free(vmh, M_CONTIGMEM); + + atomic_subtract_int(&contigmem_refcnt, 1); +} + +static int +contigmem_cdev_pager_fault(vm_object_t object, vm_ooffset_t offset, int prot, + vm_page_t *mres) +{ + vm_paddr_t paddr; + vm_page_t m_paddr, page; + vm_memattr_t memattr, memattr1; + + memattr = object->memattr; + + VM_OBJECT_WUNLOCK(object); + + paddr = offset; + + m_paddr = vm_phys_paddr_to_vm_page(paddr); + if (m_paddr != NULL) { + memattr1 = pmap_page_get_memattr(m_paddr); + if (memattr1 != memattr) + memattr = memattr1; + } + + if (((*mres)->flags & PG_FICTITIOUS) != 0) { + /* + * If the passed in result page is a fake page, update it with + * the new physical address. + */ + page = *mres; + VM_OBJECT_WLOCK(object); + vm_page_updatefake(page, paddr, memattr); + } else { + /* + * Replace the passed in reqpage page with our own fake page and + * free up the original page. + */ + page = vm_page_getfake(paddr, memattr); + VM_OBJECT_WLOCK(object); +#if __FreeBSD__ >= 13 + vm_page_replace(page, object, (*mres)->pindex, *mres); +#else + vm_page_t mret = vm_page_replace(page, object, (*mres)->pindex); + KASSERT(mret == *mres, + ("invalid page replacement, old=%p, ret=%p", *mres, mret)); + vm_page_lock(mret); + vm_page_free(mret); + vm_page_unlock(mret); +#endif + *mres = page; + } + + page->valid = VM_PAGE_BITS_ALL; + + return VM_PAGER_OK; +} + +static struct cdev_pager_ops contigmem_cdev_pager_ops = { + .cdev_pg_ctor = contigmem_cdev_pager_ctor, + .cdev_pg_dtor = contigmem_cdev_pager_dtor, + .cdev_pg_fault = contigmem_cdev_pager_fault, +}; + +static int + (struct cdev *cdev, vm_ooffset_t *offset, vm_size_t size, + struct vm_object **obj, int nprot) +{ + + // Testing if this is called when file is opened + printf("contigmem_mmap_single called \n"); + + // struct contigmem_vm_handle *vmh; + // uint64_t buffer_index; + + // /* + // * The buffer index is encoded in the offset. Divide the offset by + // * PAGE_SIZE to get the index of the buffer requested by the user + // * app. + // */ + // buffer_index = *offset / PAGE_SIZE; + // if (buffer_index >= contigmem_num_buffers) + // return EINVAL; + + // if (size > contigmem_buffer_size) + // return EINVAL; + + // vmh = malloc(sizeof(*vmh), M_CONTIGMEM, M_NOWAIT | M_ZERO); + // if (vmh == NULL) + // return ENOMEM; + // vmh->buffer_index = buffer_index; + + // *offset = (vm_ooffset_t)vtophys(contigmem_buffers[buffer_index].addr); + // *obj = cdev_pager_allocate(vmh, OBJT_DEVICE, &contigmem_cdev_pager_ops, + // size, nprot, *offset, curthread->td_ucred); + + size = __builtin_align_up(size, _Alignof(max_align_t)); + + // printf("%d \n", sz); + // printf("%d Malloc counter\n", MallocCounter); + + MallocCounter -= size; + obj = &ptr[MallocCounter]; + obj = cheri_setbounds(obj, sz); + + return 0; +} + + +// SAMPLE SYSCALL IMPLEMENTATION +// /*- +// * SPDX-License-Identifier: BSD-2-Clause +// * +// * Copyright (c) 1999 Assar Westerlund +// * 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. +// * +// * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +// */ + +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// /* +// * The function for implementing the syscall. +// */ +// static int +// hello(struct thread *td, void *arg) +// { + +// printf("hello kernel\n"); +// return (0); +// } + +// /* +// * The `sysent' for the new syscall +// */ +// static struct sysent hello_sysent = { +// .sy_narg = 0, +// .sy_call = hello +// }; + +// /* +// * The offset in sysent where the syscall is allocated. +// */ +// static int offset = NO_SYSCALL; + +// /* +// * The function called at load/unload. +// */ +// static int +// load(struct module *module, int cmd, void *arg) +// { +// int error = 0; + +// switch (cmd) { +// case MOD_LOAD : +// printf("syscall loaded at %d\n", offset); +// break; +// case MOD_UNLOAD : +// printf("syscall unloaded from %d\n", offset); +// break; +// default : +// error = EOPNOTSUPP; +// break; +// } +// return (error); +// } + +// SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL); \ No newline at end of file diff --git a/dpdk/kernel/freebsd/Hugepage/meson.build b/dpdk/kernel/freebsd/Hugepage/meson.build new file mode 100644 index 0000000..1d5227e --- /dev/null +++ b/dpdk/kernel/freebsd/Hugepage/meson.build @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2017 Intel Corporation + +sources = files('Hugepage.c') \ No newline at end of file diff --git a/dpdk/kernel/freebsd/meson.build b/dpdk/kernel/freebsd/meson.build index e903f85..f092181 100644 --- a/dpdk/kernel/freebsd/meson.build +++ b/dpdk/kernel/freebsd/meson.build @@ -2,7 +2,7 @@ #SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2018 Intel Corporation -kmods = ['contigmem', 'nic_uio'] +kmods = ['Hugepage', 'nic_uio'] # for building kernel modules, we use kernel build system using make, as # with Linux. We have a skeleton BSDmakefile, which pulls many of its diff --git a/localpush.sh b/localpush.sh index 9d1feea..6f3e9b1 100644 --- a/localpush.sh +++ b/localpush.sh @@ -2,5 +2,5 @@ files=`find . -newermt "-3600 secs" | sed 's|^./||'` for file in $files do - sshpass -p "" scp "$file" "akilan@192.168.0.10:/home/akilan/Alloc-Test/CHERI-Allocator/$file" + scp -P 40515 "$file" "akilan@217.76.63.222:/home/akilan/Alloc-Test/CHERI-Allocator/$file" done