├── .gitignore ├── LICENSE ├── README.md ├── convenient.h ├── countem.sh ├── countem2.sh ├── foreach ├── prcs_show │ ├── Makefile │ ├── foreach.c │ └── rdtasks.c └── thrd_show │ ├── Makefile │ └── showthreads.c ├── helloworld_lkm ├── Makefile ├── Readme.md └── hello.c ├── kernel_build ├── explore_initrd.sh ├── git-clone-linux-kernel.sh └── kbuild.sh ├── ksync ├── counting │ ├── Makefile │ ├── counting_mt_5.1.c │ └── counting_singlethrd_5.1.c └── rcu_example │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── list_rcu_example.c │ └── list_rcu_example.txt ├── list ├── Makefile └── list.c ├── lkm ├── lkm_template ├── Makefile ├── README.md └── lkm_template.c ├── mm ├── allocsize_tests │ ├── kmalloc_test │ │ ├── Makefile │ │ └── kmalloc_test.c │ └── ksize_test │ │ ├── Makefile │ │ └── ksz_test.c ├── phymap_iomem │ ├── color.sh │ ├── common.sh │ ├── err_common.sh │ └── phymap_iomem.sh ├── slab_custom │ ├── Makefile │ └── slab_custom.c ├── vm_show_kernel_seg │ ├── Makefile │ ├── convenient.h │ ├── mk4arm │ └── vm_show_kernel_seg.c ├── vm_usermode │ ├── Makefile │ ├── common.sh │ ├── err_common.sh │ ├── gen_malloc_pgfault │ │ ├── gen_malloc_pgfault.c │ │ └── try_gen_malloc_pgfault.sh │ ├── hello.c │ ├── malloc_brk_test.c │ ├── mem_sequence.c │ ├── mmap │ │ ├── fileio_mmap │ │ │ ├── Makefile │ │ │ ├── Readme.txt │ │ │ ├── mmap_fileio.c │ │ │ ├── reg_fileio.c │ │ │ ├── restart_lib.h │ │ │ └── tst_fileio.sh │ │ └── mmap_simple │ │ │ ├── Makefile │ │ │ ├── mmap_simple.c │ │ │ └── restart_lib.h │ ├── oom_try │ │ ├── Makefile │ │ ├── oom-killer-try.c │ │ ├── rdpg_oom_try.c │ │ └── show_oom_score │ ├── ptr1.c │ ├── segv_pgfault.c │ ├── swap_stuff │ │ ├── common.sh │ │ ├── err_common.sh │ │ ├── swap_usage.sh │ │ └── toggle_swap.sh │ └── vm_user.c ├── vmallc │ ├── Makefile │ ├── Makefile.better │ ├── Makefile.simple │ └── vmallc.c └── xtras │ ├── malloc_brk_test.c │ ├── query_oom_score.sh │ ├── segv_pgfault.c │ ├── trick.c │ └── vm_vas │ └── vm_user.c ├── sched ├── cgroups │ └── cpu_eg │ │ ├── cpucg_test-arm32qemu.sh │ │ └── simp.sh ├── chrt_taskset.sh ├── core_running_what.sh ├── ftrace │ ├── ftrace1_generic.sh │ ├── ftrace_anycmd.sh │ └── ftrc.sh ├── query_all.sh ├── sched_pthrd_app │ ├── Makefile │ ├── libpk.h │ └── sched_pthrd.c └── show_runnable │ ├── Readme.txt │ ├── rq.sh │ ├── show_rq.sh │ ├── t1 │ ├── t2 │ ├── t3 │ └── task.sh ├── show_compile_flags ├── show_monolithic ├── Makefile └── show_monolithic.c ├── taskdtl ├── taskdtl.png ├── taskdtl_display.c ├── taskdtl_miscdrv │ ├── cr8devnode.sh │ └── run_taskdtl_miscdrv.sh └── taskdtl_raw │ ├── Makefile │ ├── run_taskdtl │ └── taskdtl.c └── vcpu_check ├── Makefile └── vcpu_check.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | dbconflict/ 55 | .*.swp 56 | gplshim*/ 57 | *.cache.mk 58 | *.tar* 59 | older*/ 60 | *.o.ur-safe 61 | *bkp/ 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kaiwan N Billimoria 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # L2_kernel_trg 2 | Source code plus utils : for the kaiwanTECH 'Linux Kernel Internals' corporate training sessions. 3 | 4 | ----------------------------------------------------------- 5 | A NOTE to participants of the training course(s) follows: 6 | ----------------------------------------------------------- 7 | 8 | Dear Participant, 9 | 10 | ******************************* PLEASE NOTE CAREFULLY *********************************** 11 | 12 | 1. These programs, utilities, source code found here are distributed in the hope that 13 | they will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 15 | Several (well, some) of the programs/drivers are still undergoing modifications 16 | and/or enhancements and must therefore be considered to be incomplete. 17 | 18 | 2. To be completely safe, you are *highly* recommended to back up your system 19 | before running this code - obviously, especially kernel modules and drivers 20 | (see point 1 above ;-) 21 | 22 | 3. Licensing: 23 | In a nutshell, the source code provided is licensed under the MIT License, 24 | keeping it simple and reusable with attribution. (IOW, you can certainly use 25 | the source code provided here; you must attribute the original source). 26 | VERY IMPORTANT :: 27 | Before using this source(s) in your project(s) / product(s), you *MUST* check 28 | with your organization's legal staff that it is appropriate to do so. 29 | 30 | [Courseware PDFs are *not* under the MIT License, they are to be kept 31 | confidential, non-distributable without consent, for your private internal 32 | use only]. 33 | 34 | ******************************************************************************* 35 | 36 | kaiwanTECH TRAINING COURSES :: 37 | http://bit.ly/ktcorp 38 | 39 | Hope this helps! As is often said with regard to Linux, 40 | "Above all, have fun!" 41 | 42 | Warm Regards, 43 | And all the very best, 44 | Kaiwan. 45 | < kaiwan -at- kaiwantech -dot- com > 46 | (c) kaiwanTECH 47 | 48 | COURSES: http://bit.ly/ktcorp 49 | -------------------------------------------------------------------------------- /countem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # countem.sh 3 | # *************************************************************** 4 | # * This program is part of the source code released for the book 5 | # * "Linux Kernel Programming", 2nd Ed 6 | # * (c) Author: Kaiwan N Billimoria 7 | # * Publisher: Packt 8 | # * GitHub repository: 9 | # * https://github.com/PacktPublishing/Linux-Kernel-Programming_2E 10 | # * 11 | # * From: Ch 6 : Kernel and Memory Management Internals Essentials 12 | # **************************************************************** 13 | # * Brief Description: 14 | # * Counts the total number of processes, user and kernel threads currently 15 | # * alive on the system, and thus calculates and shows the number of user 16 | # * and kernel mode stacks currently in existance. 17 | # * 18 | # * For details, please refer the book, Ch 6. 19 | # **************************************************************** 20 | set -euo pipefail 21 | [[ 0 -eq 1 ]] && { 22 | echo "System release info:" 23 | which lsb_release >/dev/null && lsb_release -a || true 24 | [[ -f /etc/issue ]] && cat /etc/issue 25 | [[ -f /etc/os-release ]] && cat /etc/os-release 26 | } 27 | 28 | # First capture the info into temp files 29 | TMPP=/tmp/.p 30 | TMPT=/tmp/.t 31 | ps -A > ${TMPP} 32 | ps -LAf > ${TMPT} 33 | 34 | total_prcs=$(wc -l ${TMPP}|awk '{print $1}') 35 | printf "1. Total # of processes alive = %9d\n" ${total_prcs} 36 | total_thrds=$(wc -l ${TMPT}|awk '{print $1}') 37 | printf "2. Total # of threads alive = %9d\n" ${total_thrds} 38 | # ps -LAf shows all kernel threads names (col 10) in square brackets; count 'em 39 | total_kthrds=$(cat ${TMPT}|awk '{print $10}'|grep "^\["|wc -l) 40 | printf "3. Total # of kernel threads alive = %9d\n" ${total_kthrds} 41 | printf " (each kthread will have a kernel-mode stack)\n" 42 | total_uthrds=$((${total_thrds}-${total_kthrds})) 43 | printf "4. Thus, total # of user mode threads = (2) - (3) = %9d\n" ${total_uthrds} 44 | printf " (each uthread will have both a user and kernel-mode stack)\n" 45 | printf "5. Thus, total # of kernel-mode stacks = (3) + (4)*2 = %9d\n" $((${total_kthrds}+(${total_uthrds}*2))) 46 | 47 | rm -f ${TMPP} ${TMPT} 48 | exit 0 49 | -------------------------------------------------------------------------------- /countem2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # countem.sh 3 | # *************************************************************** 4 | # * This program is part of the source code released for the book 5 | # * "Linux Kernel Programming", 2nd Ed 6 | # * (c) Author: Kaiwan N Billimoria 7 | # * Publisher: Packt 8 | # * GitHub repository: 9 | # * https://github.com/PacktPublishing/Linux-Kernel-Programming_2E 10 | # * 11 | # * From: Ch 6 : Kernel and Memory Management Internals Essentials 12 | # **************************************************************** 13 | # * Brief Description: 14 | # * [ADDED LATER] 15 | # * Counts the total number of processes, user and kernel threads currently 16 | # * alive on the system, and thus calculates and shows the number of user 17 | # * and kernel mode stacks currently in existance. 18 | # * 19 | # * For details, please refer the book, Ch 6. 20 | # **************************************************************** 21 | set -euo pipefail 22 | 23 | # First capture the info into temp files 24 | TMPP=/tmp/.p 25 | TMPT=/tmp/.t 26 | ps -A > ${TMPP} 27 | ps -LAf > ${TMPT} 28 | 29 | total_prcs=$(wc -l ${TMPP}|awk '{print $1}') 30 | printf "1. Total # of processes alive = %9d\n" ${total_prcs} 31 | total_thrds=$(wc -l ${TMPT}|awk '{print $1}') 32 | printf "2. Total # of threads alive = %9d\n" ${total_thrds} 33 | # ps -LAf shows all kernel threads names (col 10) in square brackets; count 'em 34 | total_kthrds=$(cat ${TMPT}|awk '{print $10}'|grep "^\["|wc -l) 35 | printf "3. Total # of kernel threads alive = %9d\n" ${total_kthrds} 36 | printf " (each kthread will have a kernel-mode stack)\n" 37 | total_uthrds=$((${total_thrds}-${total_kthrds})) 38 | printf "4. Thus, total # of user mode threads = (2) - (3) = %9d\n" ${total_uthrds} 39 | printf " (each uthread will have both a user and kernel-mode stack)\n" 40 | printf "5. Thus, total # of kernel-mode stacks = (3) + (4) = %9d\n" $((${total_kthrds}+${total_uthrds})) 41 | 42 | rm -f ${TMPP} ${TMPT} 43 | exit 0 44 | -------------------------------------------------------------------------------- /foreach/prcs_show/foreach.c: -------------------------------------------------------------------------------- 1 | /* 2 | * foreach.c 3 | * 4 | * Simple kernel program that - 5 | * -returns info about all *processes* (_not_ threads) on the task list 6 | * 7 | * Author: Kaiwan N Billimoria 8 | * Released under the terms of the MIT License. 9 | * https://en.wikipedia.org/wiki/MIT_License 10 | */ 11 | #define pr_fmt(fmt) "%s:%s():%d: " fmt, KBUILD_MODNAME, __func__, __LINE__ 12 | 13 | #include 14 | #include 15 | #include 16 | #include /* current, jiffies */ 17 | 18 | #include 19 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) 20 | #include /* for_each_xxx, ... */ 21 | #endif 22 | #include /* no_llseek */ 23 | #include 24 | #include /* copy_to_user() */ 25 | #include 26 | 27 | #define DRVNAME "foreach" 28 | #define MY_MAJOR 0 /* 0 => dynamic major number assignment */ 29 | #define MAXKBUF_LEN (20*1024) // 20Kb should do.... ? 30 | 31 | static int taskinfo_major = MY_MAJOR; 32 | 33 | static ssize_t taskinfo_read(struct file *filp, char __user *buf, size_t count, loff_t *offp) 34 | { 35 | struct task_struct *p; 36 | char *kbuf, tmp[128]; 37 | int numread = 0, num = 0; 38 | 39 | kbuf = kzalloc(MAXKBUF_LEN, GFP_KERNEL); 40 | if (!kbuf) 41 | return -ENOMEM; 42 | 43 | rcu_read_lock(); 44 | for_each_process(p) { 45 | memset(tmp, 0, 128); 46 | task_lock(p); 47 | get_task_struct(p); 48 | num = snprintf(tmp, 128, "\ 49 | %-16s|%7d|%7d|%7u|%7u\n", p->comm, p->tgid, p->pid, 50 | //p->uid, p->euid 51 | //current_uid().val, current_euid().val 52 | __kuid_val(p->cred->uid), __kuid_val(p->cred->euid) 53 | ); 54 | strncat(kbuf, tmp, num); 55 | numread += num; 56 | pr_debug("num=%d numread=%d tmp=%s\n", num, numread, tmp); 57 | 58 | /* latency reduction via explicit rescheduling in places that are safe */ 59 | if (cond_resched()) 60 | pr_debug("resched occured now\n"); 61 | 62 | put_task_struct(p); 63 | task_unlock(p); 64 | } // for_each_process loop... 65 | rcu_read_unlock(); 66 | 67 | //printk("\n\n%s\n", kbuf); 68 | 69 | #if 1 70 | if (copy_to_user(buf, kbuf, numread)) { 71 | pr_alert("copy_to_user failed..\n"); 72 | kfree(kbuf); 73 | return -EFAULT; 74 | } 75 | #endif 76 | kfree(kbuf); 77 | return count; 78 | } 79 | 80 | static ssize_t taskinfo_write(struct file *filp, const char __user *buf, 81 | size_t count, loff_t *offp) 82 | { 83 | pr_debug("write isn't supported. [fyi, process %s [pid %d], count=%ld]\n", 84 | current->comm, current->pid, count); 85 | return -ENOSYS; 86 | } 87 | 88 | /* Minor-specific open routines */ 89 | static const struct file_operations taskinfo_fops = { 90 | .llseek = no_llseek, 91 | .read = taskinfo_read, // do this with ioctl..better. 92 | .write = taskinfo_write, 93 | }; 94 | 95 | static int taskinfo_open(struct inode *inode, struct file *filp) 96 | { 97 | pr_debug("Device node with minor # %d being used\n", iminor(inode)); 98 | 99 | switch (iminor(inode)) { 100 | case 0: 101 | filp->f_op = &taskinfo_fops; 102 | break; 103 | default: 104 | return -ENXIO; 105 | } 106 | if (filp->f_op && filp->f_op->open) 107 | return filp->f_op->open(inode, filp); 108 | /* Minor-specific open : jumps to the 109 | * suitable entry point - the correct open() call if 110 | * one has been defined 111 | */ 112 | return 0; 113 | } 114 | 115 | /* Major-wide open routine */ 116 | static const struct file_operations taskinfoopen_fops = { 117 | .open = taskinfo_open, /* just a means to get at the real open */ 118 | }; 119 | 120 | /* 121 | * Register the char driver with the kernel. 122 | * 123 | * On 2.6 kernels, we could use the new alloc_register_chrdev() function; 124 | * here, we use the "classic" register_chrdev() API. 125 | */ 126 | static int __init taskinfo_init_module(void) 127 | { 128 | int result; 129 | 130 | pr_debug("taskinfo_major=%d\n", taskinfo_major); 131 | 132 | /* 133 | * Register the major, and accept a dynamic number. 134 | * The return value is the actual major # assigned. 135 | */ 136 | result = register_chrdev(taskinfo_major, DRVNAME, &taskinfoopen_fops); 137 | if (result < 0) { 138 | pr_debug("register_chrdev() failed trying to get taskinfo_major=%d\n", 139 | taskinfo_major); 140 | return result; 141 | } 142 | 143 | if (taskinfo_major == 0) 144 | taskinfo_major = result; /* dynamic */ 145 | pr_info("registered:: taskinfo_major=%d\n", taskinfo_major); 146 | 147 | return 0; /* success */ 148 | } 149 | 150 | static void __exit taskinfo_cleanup_module(void) 151 | { 152 | unregister_chrdev(taskinfo_major, DRVNAME); 153 | pr_info("Unregistered.\n"); 154 | } 155 | 156 | module_init(taskinfo_init_module); 157 | module_exit(taskinfo_cleanup_module); 158 | 159 | module_param(taskinfo_major, int, 0); /* 0 => param won't show up in sysfs, 160 | non-zero are mode (perms) */ 161 | MODULE_PARM_DESC(taskinfo_major, "Major number to attempt to use"); 162 | MODULE_AUTHOR("Kaiwan"); 163 | MODULE_DESCRIPTION("Simple module that returns task info to userspace"); 164 | MODULE_LICENSE("Dual MIT/GPL"); 165 | -------------------------------------------------------------------------------- /foreach/prcs_show/rdtasks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rd_tst.c 3 | * Test bed for demo drivers 4 | * 5 | * Author: Kaiwan N Billimoria 6 | * 7 | * 8 | * Released under the terms of the MIT License. 9 | * https://en.wikipedia.org/wiki/MIT_License 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define FLGS O_RDONLY 21 | #define DMODE 0 22 | #define SZ 1024 23 | 24 | void sig(int signum) 25 | { 26 | fprintf(stderr, "In sig: signum=%d\n", signum); 27 | } 28 | 29 | int main(int argc, char **argv) 30 | { 31 | int fd, n; 32 | struct sigaction act; 33 | char *buf = NULL; 34 | size_t num = 0; 35 | 36 | if (argc != 3) { 37 | fprintf(stderr, "Usage: %s device_file num_bytes_to_read\n", argv[0]); 38 | exit(1); 39 | } 40 | 41 | act.sa_handler = sig; 42 | act.sa_flags = SA_RESTART; 43 | sigemptyset(&act.sa_mask); 44 | if ((sigaction(SIGINT, &act, 0)) == -1) { 45 | perror("sigaction"), exit(1); 46 | } 47 | 48 | if ((fd = open(argv[1], FLGS, DMODE)) == -1) 49 | perror("open"), exit(1); 50 | printf("device opened: fd=%d\n", fd); 51 | 52 | num = atoi(argv[2]); 53 | if ((num < 0) || (num > INT_MAX)) { 54 | fprintf(stderr, "%s: number of bytes '%ld' invalid.\n", argv[0], num); 55 | close(fd); 56 | exit(1); 57 | } 58 | 59 | buf = malloc(num); 60 | if (!buf) { 61 | fprintf(stderr, "%s: out of memory!\n", argv[0]); 62 | close(fd); 63 | exit(1); 64 | } 65 | // test reading.. 66 | n = read(fd, buf, num); 67 | if (n < 0) { 68 | perror("read failed"); 69 | free(buf); 70 | close(fd); 71 | exit(1); 72 | } 73 | buf[n - 1] = '\0'; 74 | 75 | //buf[n]='\0'; 76 | /* 77 | Interesting! If the above line is compiled in, we get this error: 78 | *** glibc detected *** ./rd_tst: double free or corruption (!prev): 0x097e6008 *** 79 | ======= Backtrace: ========= 80 | /lib/libc.so.6(+0x6c501)[0x505501] 81 | /lib/libc.so.6(+0x6dd70)[0x506d70] 82 | ... 83 | 84 | Actually, there is a bug if we keep that line: a buffer overrun by 1 byte 85 | (valgrind caught it!) 86 | */ 87 | 88 | printf("%s: read %d bytes from %s\n", argv[0], n, argv[1]); 89 | printf("\ 90 | ----------------------------------------------------------------------\n\ 91 | Task Name | TGID | PID | RUID | EUID\n\ 92 | ----------------------------------------------------------------------\n"); 93 | close(fd); 94 | 95 | printf("%s\n", buf); 96 | 97 | free(buf); 98 | exit(0); 99 | } 100 | -------------------------------------------------------------------------------- /foreach/thrd_show/showthreads.c: -------------------------------------------------------------------------------- 1 | /* 2 | * showthreads.c 3 | * 4 | * Author: Kaiwan N Billimoria 5 | * MIT/GPL. 6 | */ 7 | //#define pr_fmt(fmt) "%s:%s():%d: " fmt, KBUILD_MODNAME, __func__, __LINE__ 8 | #include 9 | #include 10 | 11 | #include 12 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) 13 | #include 14 | #endif 15 | #include 16 | 17 | #define DRVNAME "showthreads" 18 | 19 | static void showthrds(void) 20 | { 21 | struct task_struct *g, *t; // 'g' : process ptr; 't': thread ptr ! 22 | char buf[256], tmp[128]; 23 | 24 | pr_info 25 | ("----------------------------------------------------------------------------\n" 26 | " TGID PID Thread Name # Threads\n" 27 | "----------------------------------------------------------------------------\n"); 28 | 29 | rcu_read_lock(); 30 | // do_each_thread(g, t) { 31 | /* the do_each_thread() { ... } while_each_thread() seems to throw a warning-treated-as-error: 32 | howthreads.c:30:9: error: implicit declaration of function ‘do_each_thread’; did you mean ‘for_each_thread’? [-Werror=implicit-function-declaration] 33 | 30 | do_each_thread(g, t) { 34 | | ^~~~~~~~~~~~~~ 35 | * ... 36 | * So lets just use the simpler form: for_each_process_thread() 37 | */ 38 | for_each_process_thread(g, t) { 39 | int nr_thrds = 1; 40 | 41 | task_lock(t); 42 | get_task_struct(t); 43 | 44 | snprintf(buf, 256, "%6d %6d ", g->tgid, t->pid); 45 | if (!g->mm) { // kernel thread 46 | snprintf(tmp, 128, "[%30s]", t->comm); 47 | } else { 48 | snprintf(tmp, 128, " %30s ", t->comm); 49 | } 50 | strncat(buf, tmp, 128); 51 | 52 | nr_thrds = get_nr_threads(g); 53 | // "main" thread of a multithread app? 54 | if (g->mm && (g->tgid == t->pid) && (nr_thrds > 1)) { 55 | snprintf(tmp, 128, " %4d", nr_thrds); 56 | strncat(buf, tmp, 128); 57 | } 58 | 59 | snprintf(tmp, 2, "\n"); 60 | strncat(buf, tmp, 2); 61 | pr_info("%s", buf); 62 | 63 | memset(buf, 0, sizeof(buf)); 64 | memset(tmp, 0, sizeof(tmp)); 65 | put_task_struct(t); 66 | task_unlock(t); 67 | } 68 | //while_each_thread(g, t); 69 | rcu_read_unlock(); 70 | } 71 | 72 | static int __init showthrds_init_module(void) 73 | { 74 | showthrds(); 75 | return 0; 76 | } 77 | 78 | static void __exit showthrds_cleanup_module(void) 79 | { 80 | pr_info("%s: unoaded.\n", KBUILD_MODNAME); 81 | } 82 | 83 | module_init(showthrds_init_module); 84 | module_exit(showthrds_cleanup_module); 85 | 86 | MODULE_AUTHOR("Kaiwan NB"); 87 | MODULE_DESCRIPTION("Displays all threads."); 88 | MODULE_LICENSE("GPL"); 89 | //MODULE_LICENSE("Dual GPL/MIT"); 90 | -------------------------------------------------------------------------------- /helloworld_lkm/Makefile: -------------------------------------------------------------------------------- 1 | # Simplest LKM Makefile 2 | MODNAME = hello 3 | 4 | #CC := gcc-12 5 | obj-m := $(MODNAME).o 6 | 7 | KDIR := /lib/modules/$(shell uname -r)/build 8 | PWD := $(shell pwd) 9 | 10 | all: module 11 | 12 | module: 13 | $(MAKE) -C $(KDIR) M=$(PWD) modules 14 | install: 15 | sudo $(MAKE) -C $(KDIR) M=$(PWD) modules_install 16 | sudo depmod 17 | clean: 18 | $(MAKE) -C $(KDIR) M=$(PWD) clean 19 | -------------------------------------------------------------------------------- /helloworld_lkm/Readme.md: -------------------------------------------------------------------------------- 1 | TIP 2 | On Ubuntu 22.04 or earlier, it's possible that the module build fails with this error: 3 | 4 | `gcc-11: error: unrecognized command-line option ‘-ftrivial-auto-var-init=zero’` 5 | 6 | It's a limitation within GCC ver 11; to fix it, install gcc-12, set CC to it in the Makefile and retry: 7 | 8 | `sudo apt install gcc-12` 9 | 10 | In the Makefile, add this line: 11 | 12 | `CC := gcc-12` 13 | 14 | `make` 15 | -------------------------------------------------------------------------------- /helloworld_lkm/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | MODULE_LICENSE("Dual MIT/GPL"); 5 | 6 | static int __init hello_init(void) 7 | { 8 | // printk(KERN_ALERT "Hello, LKM world\n"); 9 | pr_alert("Hello, LKM world\n"); 10 | 11 | #if 0 12 | return -ENOMEM; 13 | /* 14 | * If we do this, insmod fails immd with: 15 | * insmod: ERROR: could not insert module ./hello.ko: Cannot allocate memory 16 | * The cleanup/exit handler is *not* invoked 17 | */ 18 | #endif 19 | 20 | #if 1 21 | return 0; // success 22 | #endif 23 | } 24 | 25 | static void __exit hello_exit(void) 26 | { 27 | pr_alert("Goodbye, cruel world\n"); 28 | } 29 | 30 | module_init(hello_init); 31 | module_exit(hello_exit); 32 | -------------------------------------------------------------------------------- /kernel_build/explore_initrd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # initrd_xplore.sh 3 | # 4 | # Quick Description: 5 | # Extract a given initrd image. 6 | # 7 | # Kaiwan N Billimoria 8 | # kaiwan -at- kaiwantech -dot- com 9 | # kaiwanTECH 10 | # MIT License. 11 | name=$(basename $0) 12 | 13 | die() { 14 | echo 2>&1 "FATAL: ${name}: $@" ; exit 1 15 | } 16 | DEBUG=1 17 | decho() { 18 | [[ ${DEBUG} -eq 1 ]] && echo "$@" 19 | } 20 | 21 | # unpack_initramfs 22 | # Parameters: 23 | # $1 : initramfs source file (.cpio.gz) 24 | unpack_initramfs() 25 | { 26 | local TMPDIR=initrd_$$ 27 | local DEST=initrd_copy.img 28 | local DEST_DIR=initrd_content 29 | local TYPE 30 | 31 | mkdir -p ${TMPDIR} || exit 1 32 | cp $1 ${TMPDIR}/${DEST} || exit 1 33 | cd ${TMPDIR} 34 | 35 | file --brief ${DEST} |grep "^XZ" >/dev/null && { 36 | TYPE=xz 37 | mv ${DEST} ${DEST}.xz 38 | xz -d ${DEST}.gz 39 | decho "xz" 40 | } 41 | file --brief ${DEST} |grep -i -e "gzip|gz" >/dev/null && { 42 | TYPE=gzip 43 | mv ${DEST} ${DEST}.gz 44 | gzip -d ${DEST}.gz 45 | decho "gzip" 46 | } 47 | # If it's neither xz / gzip, assuming it's already cpio 48 | file --brief ${DEST} |grep -i "cpio" >/dev/null || die "not a supported image type : 49 | [$(file ${DEST})]" 50 | 51 | mkdir -p ${DEST_DIR} 52 | cd ${DEST_DIR} 53 | echo "[+] Extracting now ..." 54 | cpio -i < ../${DEST} || die "cpio failed to extract initrd image" 55 | echo "Result in ${TMPDIR}/${DEST_DIR}/" 56 | } 57 | 58 | ##### execution starts here ##### 59 | 60 | # args 61 | [ $# -ne 1 ] && { 62 | echo "Usage: ${name} initrd-img-file" 63 | exit 1 64 | } 65 | [ ! -f $1 ] && { 66 | echo "${name}: initrd-img-file $1 not found? Perms issue? Aborting..." 67 | exit 1 68 | } 69 | unpack_initramfs ${1} 70 | exit 0 71 | -------------------------------------------------------------------------------- /kernel_build/git-clone-linux-kernel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Ref: Kernel Hackers' Guide to git 3 | # http://linux.yyz.us/git-howto.html , 4 | # http://pradheepshrinivasan.github.io/2011/12/29/cloning-linux-next-tree-i-wanted-to-do/ 5 | # http://pradheepshrinivasan.github.io/2015/08/05/Tracking-current-in-linux-next/ 6 | name=$(basename $0) 7 | 8 | echo "${name}: !NOTE! You must specify whether you want to clone the: 9 | 'regular' kernel src tree (by setting REGULAR_TREE=1 and LINUX_NEXT_TREE=0 in this script), 10 | -or- 11 | 'linux-next' kernel src tree (by setting REGULAR_TREE=0 and LINUX_NEXT_TREE=1 in this script). 12 | 13 | Press [Enter] to continue, or ^C to exit ... 14 | [Enter] will cause the 'regular' kernel to be git clone'd 15 | " 16 | read x 17 | 18 | REGULAR_TREE=1 19 | LINUX_NEXT_TREE=0 # linux-next: working with the bleeding edge? 20 | 21 | if [ ${REGULAR_TREE} -eq 1 -a ${LINUX_NEXT_TREE} -eq 1 ] ; then 22 | echo "${name}: Both 'regular' and 'linux-next' can't be cloned, choose one of them pl.." 23 | exit 1 24 | fi 25 | if [ ${REGULAR_TREE} -eq 0 -a ${LINUX_NEXT_TREE} -eq 1 ] ; then 26 | [ $# -ne 1 ] && { 27 | echo "Working with linux-next:" 28 | echo "Usage: ${name} new-branch-to-work-under" 29 | exit 1 30 | } 31 | NEW_BRANCH=$1 32 | fi 33 | 34 | [ -d .git ] && { 35 | echo "${name}: whoops, this dir already has a .git working folder. Continue here or abort? 36 | [Enter] to continue, ^C to abort" 37 | read x 38 | } 39 | 40 | [ ${REGULAR_TREE} -eq 1 ] && { 41 | GITURL=https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 42 | echo "${name}: cloning 'regular' linux kernel now ... (this can take a while)..." 43 | echo "Running: time git clone ${GITURL}" 44 | time git clone ${GITURL} 45 | } 46 | # For 'regular': to update to latest: 47 | # git pull ${GITURL} 48 | # or just 49 | # git pull 50 | 51 | [ ${LINUX_NEXT_TREE} -eq 1 ] && { 52 | GITURL=git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git 53 | echo "${name}: cloning latest 'linux-next' linux kernel now ... (this can take a while)..." 54 | echo "Running: time git clone ${GITURL}" 55 | time git clone ${GITURL} 56 | cd linux-next || exit 1 57 | echo " Running: git checkout master" 58 | git checkout master 59 | echo " Running: git remote update" 60 | git remote update 61 | LATEST_TAG=$(git tag -l next-* | tail -n1) 62 | echo " Latest tag: ${LATEST_TAG}" 63 | echo " Running: git checkout -b ${NEW_BRANCH} ${LATEST_TAG}" 64 | git checkout -b ${NEW_BRANCH} ${LATEST_TAG} 65 | } 66 | 67 | echo "Done" 68 | # Could use 'gitk' to see git repos in a GUI 69 | # http://gitk.sourceforge.net/ 70 | # http://lostechies.com/joshuaflanagan/2010/09/03/use-gitk-to-understand-git/ 71 | -------------------------------------------------------------------------------- /kernel_build/kbuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # kbuild.sh 3 | # *************************************************************** 4 | # * This program is part of the source code released for the book 5 | # * "Linux Kernel Programming", 2nd Ed 6 | # * (c) Author: Kaiwan N Billimoria 7 | # * Publisher: Packt 8 | # * GitHub repository: 9 | # * https://github.com/PacktPublishing/Linux-Kernel-Programming_2E 10 | # * 11 | # * From: Ch 3 : Building the 6.x Linux Kernel from Source - Part 2 12 | # **************************************************************** 13 | # * Brief Description: 14 | # Simple kernel build script; minimally tested, YMMV! 15 | # **************************************************************** 16 | 17 | # Turn on Bash 'strict mode'! V useful to catch potential bugs/issues early. 18 | # ref: http://redsymbol.net/articles/unofficial-bash-strict-mode/ 19 | set -euo pipefail 20 | 21 | name=$(basename $0) 22 | LOG=kbuild_log 23 | 24 | CONFIGURE=0 25 | BUILD_INSTALL_MOD=ask 26 | 27 | die() 28 | { 29 | echo >&2 "$@" 30 | exit 1 31 | } 32 | 33 | # get_yn_reply 34 | # User's reply should be Y or N. 35 | # Returns: 36 | # 0 => user has answered 'Y' 37 | # 1 => user has answered 'N' 38 | get_yn_reply() 39 | { 40 | echo -n "Type Y or N please (followed by ENTER) : " 41 | local str="${@}" 42 | while true 43 | do 44 | echo ${str} 45 | read reply 46 | 47 | case "$reply" in 48 | y | yes | Y | YES ) return 0 49 | ;; 50 | n* | N* ) return 1 51 | ;; 52 | *) echo "What? Pl type Y / N" 53 | esac 54 | done 55 | } 56 | 57 | usage() 58 | { 59 | echo "Usage: ${name} [-c] path-to-kernel-src-tree-to-build 60 | -c : configure the kernel to a default state (via the 'localmodconfig' approach) 61 | NOTE: selecting this will OVERWRITE your existing .config !" 62 | } 63 | 64 | configure_kernel_localmodconfig() 65 | { 66 | lsmod > /tmp/lsmod.now 67 | echo "[+] make LSMOD=/tmp/lsmod.now localmodconfig" 68 | make LSMOD=/tmp/lsmod.now localmodconfig 69 | echo "[+] make oldconfig" 70 | make oldconfig # Update current config utilising a provided .config as base 71 | echo "[+] make menuconfig " 72 | # menuconfig and tee (w/ stderr too redirected) don't seem to get along.. 73 | stty sane 74 | make menuconfig && echo || die "menuconfig failed" 75 | ls -l .config 2>&1 | tee -a ${LOG} 76 | 77 | # Ensure config is sane; on recent Ubuntu (~ kernel ver >= 5.13), 78 | # SYSTEM_REVOCATION_KEYS being enabled causes the build to fail.. 79 | echo 80 | echo "[+] scripts/config --disable SYSTEM_REVOCATION_KEYS" 81 | scripts/config --disable SYSTEM_REVOCATION_KEYS 82 | } 83 | 84 | build_kernel() 85 | { 86 | local nproc=$(nproc) 87 | if [[ ${nproc} -le 64 ]] ; then 88 | JOBS=$(($(nproc)*2)) 89 | else 90 | JOBS=$(bc <<< "scale=0; (${nproc}*1.5)") 91 | JOBS=${JOBS::-2} # strip the .0 92 | fi 93 | 94 | echo 95 | date 96 | echo "[+] time make -j${JOBS}" 97 | time make -j${JOBS} && { 98 | echo 99 | date 100 | } || die "make *failed*" 101 | [[ ! -f arch/x86/boot/bzImage ]] && die "make *failed*? arch/x86/boot/bzImage not generated" || true 102 | } 103 | 104 | install_modules() 105 | { 106 | echo 107 | echo "[+] sudo make modules_install " 108 | sudo make modules_install || die "*Failed* modules install" 109 | } 110 | 111 | 112 | #--- 'main' 113 | [[ $# -lt 1 ]] && { 114 | usage ; exit 1 115 | } 116 | set +u 117 | if [[ ! -z "${ARCH}" ]] && [[ "${ARCH}" != "x86" ]] ; then 118 | echo "${name}: you seem to want to build the kernel for arch ${ARCH}" 119 | echo "This simple script currently supports only x86_64" 120 | exit 1 121 | fi 122 | set -u 123 | 124 | # Args processing 125 | if [[ $# -ge 1 ]] && [[ "$1" = "-h" ]] ; then 126 | usage ; exit 0 127 | fi 128 | [[ $# -eq 1 ]] && KSRC=$1 129 | [[ $# -eq 2 ]] && KSRC=$2 130 | if [[ $# -lt 2 ]] && [[ "$1" = "-c" ]] ; then 131 | usage ; exit 1 132 | fi 133 | cd ${KSRC} || exit 1 134 | 135 | rm -f ${LOG} 2>/dev/null 136 | ( 137 | date 138 | echo "[Logging to file ${LOG} ...]" 139 | echo "Version: $(head Makefile)" 140 | ) 2>&1 | tee -a ${LOG} 141 | 142 | if [[ $# -ge 2 ]] && [[ "$1" = "-c" ]] ; then 143 | CONFIGURE=1 144 | configure_kernel_localmodconfig 2>&1 | tee -a ${LOG} 145 | else 146 | ( 147 | echo "[-] Skipping kernel configure, using existing .config 148 | (Tip: pass -c if you want to configure the kernel to defaults)" 149 | [[ ! -f .config ]] && { 150 | echo "Fresh kernel (no .config), so running 'make oldconfig'" 151 | echo "[+] make oldconfig" 152 | make oldconfig # Update current config utilising a provided .config as base 153 | } || true 154 | ) 2>&1 | tee -a ${LOG} 155 | fi 156 | 157 | build_kernel 2>&1 | tee -a ${LOG} 158 | 159 | ( 160 | #--- Modules install? 161 | echo " 162 | Install kernel modules now?" 163 | set +e 164 | get_yn_reply 165 | stat=$? 166 | set -e 167 | if [[ ${stat} -eq 0 ]] ; then 168 | install_modules 169 | else 170 | echo "[-] Skipping kernel modules install step" 171 | fi 172 | 173 | echo 174 | echo "[+] sudo make install" 175 | sudo make install || die "*Failed*" 176 | echo " 177 | Done, reboot, select your new kernel from the bootloader menu & boot it 178 | (If not already done, you first need to configure GRUB to show the menu at boot)" 179 | date 180 | ) 2>&1 | tee -a ${LOG} 181 | exit 0 182 | -------------------------------------------------------------------------------- /ksync/counting/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | # A 'better' Makefile template for Linux Pthreads programming 3 | # 4 | # Besides the 'usual' targets to build production and debug versions of the 5 | # code and cleanup, we incorporate targets to do useful (and indeed required) 6 | # stuff like: 7 | # - prod_2part: build a '2-part' production target 'prod_2part'; it's 8 | # -O2, no debug symbolic info, strip-debug; 9 | # Excellent for production as it gives ability to debug as and when required! 10 | # - indent: adhering to (Linux kernel) coding style guidelines (indent+checkpatch) 11 | # - sa: static analysis target (via flawfinder, cppcheck) 12 | # - dynamic analysis target: via valgrind 13 | # - + code coverage via gcov 14 | # - a packaging (.tar.xz) target and 15 | # - a help target. 16 | # 17 | # You will require these utils installed: 18 | # indent, flawfinder, valgrind, kernel-headers package -or- simply the 19 | # checkpatch.pl script, gcov, tar; + libasan 20 | # 21 | # To get started, just type: 22 | # make help 23 | # 24 | # (c) 2020 Kaiwan N Billimoria, kaiwanTECH 25 | # License: MIT 26 | 27 | ## Pl check and keep or remove _dbg_[asan|ub|msan] targets 28 | ## (where is the program name) as desired. 29 | ALL := counting_singlethrd_5.1 counting_mt_5.1 30 | 31 | ### 32 | # Update as required 33 | # Simply replace the 'cr8ManyThrds' program name with your program name! 34 | # f.e. with sed: 35 | # sed --in-place "s/cr8ManyThrds/myprg/g" Makefile 36 | # Of course, if you have >1 C program to build, you must add it manually, 37 | # or better, keep one Makefile per program in separate directories. 38 | ### 39 | ALL_NM := counting_singlethrd_5.1 counting_singlethrd_5.1_dbg counting_mt_5.1 counting_mt_5.1_dbg 40 | 41 | CC=${CROSS_COMPILE}gcc 42 | CL=${CROSS_COMPILE}clang 43 | STRIP=${CROSS_COMPILE}strip 44 | 45 | PROD_OPTLEVEL=-O2 46 | # or -O3 or -Os 47 | CFLAGS=-Wall -UDEBUG ${PROD_OPTLEVEL} 48 | # Dynamic analysis includes the compiler itself! 49 | # Especially the powerful Address Sanitizer (ASAN) toolset 50 | CFLAGS_DBG=-g -ggdb -gdwarf-4 -O0 -Wall -Wextra -DDEBUG 51 | CFLAGS_DBG_ASAN=${CFLAGS_DBG} -fsanitize=address 52 | CFLAGS_DBG_UB=${CFLAGS_DBG} -fsanitize=undefined 53 | #CFLAGS_DBG_MSAN=${CFLAGS_DBG} -fsanitize=memory 54 | 55 | CFLAGS_GCOV=${CFLAGS_DBG} -fprofile-arcs -ftest-coverage 56 | 57 | # Required vars 58 | all: ${ALL} 59 | SRC_FILES := *.[ch] 60 | INDENT := indent 61 | FLAWFINDER := flawfinder 62 | CPPCHECK := cppcheck 63 | VALGRIND := valgrind 64 | # update as required 65 | PKG_NAME := cr8ManyThrds 66 | CHECKPATCH := ../../checkpatch.pl 67 | 68 | # Targets and their rules 69 | # Three types: 70 | # 1. 'regular' production target 'prod': -O2, no debug symbolic info, stripped 71 | # 2. '2-part' production target 'prod_2part': -O2, no debug symbolic info, strip-debug; 72 | # excellent for production as it gives ability to debug as and when required! 73 | # (internally invokes the 'debug' target as it requires the debug binary as well 74 | # 3. 'debug' target(s): -O0, debug symbolic info (-g -ggdb), not stripped 75 | counting_singlethrd_5.1: counting_singlethrd_5.1.c 76 | @echo 77 | @echo "--- building 'production'-ready target counting_singlethrd_5.1 (-O2, no debug, stripped) ---" 78 | @echo 79 | ${CC} ${CFLAGS} counting_singlethrd_5.1.c -o counting_singlethrd_5.1 -pthread 80 | ${STRIP} --strip-debug ./counting_singlethrd_5.1 81 | counting_mt_5.1: counting_mt_5.1.c 82 | @echo 83 | @echo "--- building 'production'-ready target counting_mt_5.1 (-O2, no debug, stripped) ---" 84 | @echo 85 | ${CC} ${CFLAGS} counting_mt_5.1.c -o counting_mt_5.1 -pthread 86 | ${STRIP} --strip-debug ./counting_mt_5.1 87 | 88 | 89 | #--------------- More (useful) targets! ------------------------------- 90 | 91 | # indent- "beautifies" C code - to conform to the the Linux kernel 92 | # coding style guidelines. 93 | # Note! original source file(s) is overwritten, so we back it up. 94 | # code-style : "wrapper" target over the following kernel code style targets 95 | code-style: 96 | make indent 97 | make checkpatch 98 | 99 | indent: ${SRC_FILES} 100 | make clean 101 | @echo 102 | @echo "--- applying Linux kernel code-style indentation with indent ---" 103 | @echo 104 | mkdir bkp 2> /dev/null; cp -f ${SRC_FILES} bkp/ 105 | ${INDENT} -linux ${SRC_FILES} 106 | 107 | checkpatch: 108 | make clean 109 | @echo 110 | @echo "--- applying Linux kernel code-style checking with checkpatch.pl ---" 111 | @echo 112 | ${CHECKPATCH} -f --no-tree --max-line-length=95 ${SRC_FILES} 113 | 114 | # sa : "wrapper" target over the following static analyzer targets 115 | sa: # static analysis 116 | make sa_flawfinder 117 | make sa_cppcheck 118 | 119 | # static analysis with flawfinder 120 | sa_flawfinder: 121 | make clean 122 | @echo 123 | @echo "--- static analysis with flawfinder ---" 124 | @echo 125 | ${FLAWFINDER} --neverignore --context *.[ch] 126 | 127 | # static analysis with cppcheck 128 | sa_cppcheck: 129 | make clean 130 | @echo 131 | @echo "--- static analysis with cppcheck ---" 132 | @echo 133 | ${CPPCHECK} -v --force --enable=all -i bkp/ --suppress=missingIncludeSystem . 134 | 135 | # dynamic analysis with valgrind 136 | valgrind: 137 | make debug 138 | @echo 139 | @echo "--- dynamic analysis with valgrind ---" 140 | @echo 141 | ${VALGRIND} --tool=memcheck --trace-children=yes ./cr8ManyThrds_dbg 142 | 143 | # Testing: line coverage with gcov(1) 144 | covg: 145 | @echo 146 | @echo "=== Code coverage with gcov ===" 147 | @echo 148 | ${CC} ${CFLAGS_GCOV} cr8ManyThrds.c -o cr8ManyThrds_gcov -pthread 149 | # update as required (param) 150 | ./cr8ManyThrds_gcov 5 151 | gcov ${SRC_FILES} 152 | @echo "Examine the *.c.gcov file(s)" 153 | 154 | # packaging 155 | package: 156 | @echo 157 | @echo "--- packaging ---" 158 | @echo 159 | rm -f ../${PKG_NAME}.tar.xz 160 | make clean 161 | tar caf ../${PKG_NAME}.tar.xz * 162 | ls -l ../${PKG_NAME}.tar.xz 163 | @echo "=== $(PKG_NAME).tar.xz package created ===" 164 | 165 | clean: 166 | @echo 167 | @echo "--- cleaning ---" 168 | @echo 169 | rm -vf ${ALL_NM} core* vgcore* *.o *~ *.c.gcov *.gcda *.gcno 170 | 171 | help: 172 | @echo '=== Makefile Help : additional targets available ===' 173 | @echo 174 | @echo 'TIP: type make to show all valid targets' 175 | @echo 176 | 177 | @echo 'Regular targets ::' 178 | @echo ' 1. 'prod' : regular production target: -O2, no debug symbolic info, stripped' 179 | @echo ' 2. 'debug' : -O0, debug symbolic info (-g -ggdb), not stripped' 180 | @echo ' 3. 'prod_2part': production target : -O2, no debug symbolic info, strip-debug; \ 181 | Excellent for production as it gives ability to debug as and when required! \ 182 | (shown as third option as it *requires* the 'debug' build' 183 | @echo 184 | @echo 'Doing a 'make' will build all three shown above.' 185 | 186 | @echo 187 | @echo '--- code style targets ---' 188 | @echo 'code-style : "wrapper" target over the following kernel code style targets' 189 | @echo ' indent : run the $(INDENT) utility on source file(s) to indent them as per the kernel code style' 190 | @echo ' checkpatch : run the kernel code style checker tool on source file(s)' 191 | 192 | @echo 193 | @echo '--- static analyzer targets ---' 194 | @echo 'sa : "wrapper" target over the following static analyzer targets' 195 | @echo ' sa_flawfinder : run the static analysis flawfinder tool on the source file(s)' 196 | @echo ' sa_cppcheck : run the static analysis cppcheck tool on the source file(s)' 197 | 198 | @echo 199 | @echo '--- dynamic analysis targets ---' 200 | @echo ' valgrind : run the dynamic analysis tool ($(VALGRIND)) on the binary executable' 201 | @echo ' covg : run the gcov code coverage tool on the source' 202 | 203 | @echo 204 | @echo '--- misc targets ---' 205 | @echo ' clean : cleanup - remove all the binaries, core files, etc' 206 | @echo ' package : tar and compress the source files into the dir above' 207 | @echo ' help : this 'help' target' 208 | -------------------------------------------------------------------------------- /ksync/counting/counting_mt_5.1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * counting_5.1.c 3 | * Src: Is Parallel Programming Hard, And, If So, What Can You Do About It? Paul McKenny 4 | * 5 | * (What does this v simple program intend to do? 6 | * Just this: spawn off many threads (the parameter you pass), and simply have EACH thread 7 | * increment a GLOBAL variable. that's it.) 8 | * 9 | * As explained in the book, this completely trivialized way of counting has a major pitfall: 10 | * counts are lost! 11 | * Eg. 12 | $ ./counting_5.1 29001 13 | 14 | counter val=28638 15 | * 16 | */ 17 | #define _POSIX_C_SOURCE 200112L /* or earlier: 199506L */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define MAX_THREADS 127000 // 50000 // arbitrary 26 | typedef unsigned int u32; 27 | typedef unsigned long u64; 28 | 29 | char gbuf[100]; 30 | unsigned long long counter = 0; 31 | 32 | static __inline__ void inc_count(void) 33 | { 34 | #if 1 35 | /* 36 | * To make this work, we need to recognize the critical section here and protect it; 37 | * here, we deliberately do nothing; the results speak for themselves - it's definitely wrong! 38 | */ 39 | counter++; 40 | #else 41 | /* Below: won't work here; need to do this in kernel-space of course */ 42 | WRITE_ONCE(counter, READ_ONCE(counter) + 1); 43 | #endif 44 | } 45 | 46 | static __inline__ unsigned long long read_count(void) 47 | { 48 | return counter; 49 | /* Below: won't work here; need to do this in kernel-space of course */ 50 | //return READ_ONCE(counter); 51 | } 52 | 53 | void *countup(void *threadnum) 54 | { 55 | sleep(1); // IMP! ...to simulate / generate concurrency... 56 | 57 | inc_count(); 58 | pthread_exit(NULL); 59 | } 60 | 61 | int main(int argc, char **argv) 62 | { 63 | pthread_t *threads; 64 | pthread_attr_t attr; 65 | int numthrds, i, ret; 66 | long t; 67 | void *stat = 0; 68 | 69 | if (argc != 2) { 70 | printf("Usage: %s num-threads-to-create (each thread counts up by 1)\n", argv[0]); 71 | exit(1); 72 | } 73 | numthrds = atoi(argv[1]); 74 | if ((numthrds <= 0) || (numthrds > MAX_THREADS)) { 75 | printf("%s: num-threads invalid (range: [1..MAX_THREADS(=%d)])\n", argv[0], MAX_THREADS); 76 | exit(1); 77 | } 78 | 79 | threads = malloc(sizeof(pthread_t) * numthrds); 80 | if (!threads) { 81 | printf("%s: out of memory!\n", argv[0]); 82 | exit(1); 83 | } 84 | 85 | /* Init the thread attribute structure to defaults */ 86 | pthread_attr_init(&attr); 87 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 88 | 89 | for (t = 0; t < numthrds; t++) { 90 | int rc; 91 | rc = pthread_create(&threads[t], &attr, countup, (void *)t); 92 | if (rc) { 93 | printf 94 | ("%s: Thrd # %ld: ERROR: return code from pthread_create() is %d\nstrerror() says: %s\n", 95 | argv[0], t, rc, strerror(rc)); 96 | perror("perror(): pthread_create failed"); 97 | exit(1); 98 | } 99 | } 100 | pthread_attr_destroy(&attr); 101 | //pause(); 102 | /* Thread join loop */ 103 | for (i = 0; i < numthrds; i++) { 104 | ret = pthread_join(threads[i], (void **)&stat); 105 | if (ret) 106 | printf("WARNING! [%d] pthread_join() failed! [%d]\n", i, ret); 107 | else { 108 | //printf(" Thread #%d successfully joined; it " 109 | // "terminated with status=%ld\n", i, (long)stat); 110 | if (stat == PTHREAD_CANCELED) 111 | printf(" : was CANCELED\n"); 112 | } 113 | } 114 | free(threads); 115 | 116 | printf("\ncounter val=%llu\n", read_count()); 117 | //printf("\nCOUNT= %llu\ncounter val=%llu\n", COUNT, read_count()); 118 | pthread_exit(NULL); 119 | } 120 | -------------------------------------------------------------------------------- /ksync/counting/counting_singlethrd_5.1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Src: Is Parallel Programming Hard, And, If So, What Can You Do About It? Paul McKenny 3 | * 4 | * (What does this v simple program intend to do? 5 | * Just this: have ONE thread - main() simply increment a GLOBAL variable a number of times 6 | * That's it.) 7 | * 8 | * The single-threaded version - this one - works fine! 9 | * Not so, the multithreaded one: see and try counting_5.1.c 10 | */ 11 | #include 12 | #include 13 | #include 14 | 15 | unsigned long long counter = 0; 16 | 17 | static __inline__ void inc_count(void) 18 | { 19 | counter++; 20 | //WRITE_ONCE(counter, READ_ONCE(counter) + 1); 21 | } 22 | 23 | static __inline__ unsigned long long read_count(void) 24 | { 25 | return counter; 26 | //return READ_ONCE(counter); 27 | } 28 | 29 | unsigned long long COUNT=1000000000L; // 10^9 // (10*1024*1024*1024)L; 30 | 31 | int main() 32 | { 33 | unsigned long long i; 34 | 35 | for (i = 0; i < COUNT; i++) 36 | inc_count(); 37 | printf("COUNT= %llu\ncounter val=%llu\n", COUNT, read_count()); 38 | exit(0); 39 | } 40 | -------------------------------------------------------------------------------- /ksync/rcu_example/README.md: -------------------------------------------------------------------------------- 1 | # https://github.com/jinb-park/rcu_example 2 | # rcu_example 3 | rcu example of linux kernel. tag : rcu, list rcu, linux kernel rcu, kernel rcu, read copy update, rcu example 4 | 5 | # author 6 | Jinbum Park 7 | -------------------------------------------------------------------------------- /ksync/rcu_example/list_rcu_example.c: -------------------------------------------------------------------------------- 1 | /* 2 | * list_rcu_example.c - list rcu sample module 3 | * https://github.com/jinb-park/rcu_example 4 | * 5 | * Copyright (C) 2016 Jinbum Park 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /** 30 | * struct book - a book 31 | * 32 | * @borrow: If it is 0, book is not borrowed. it is 1, book is borrowed. 33 | */ 34 | struct book { 35 | int id; 36 | char name[64]; 37 | char author[64]; 38 | int borrow; 39 | struct list_head node; 40 | struct rcu_head rcu; 41 | }; 42 | 43 | static LIST_HEAD(books); 44 | static spinlock_t books_lock; 45 | 46 | /** 47 | * callback function for async-reclaim 48 | * 49 | * call_rcu() : callback function is called when finish to wait every grace periods (async) 50 | * synchronize_rcu() : wait to finish every grace periods (sync) 51 | */ 52 | static void book_reclaim_callback(struct rcu_head *rcu) { 53 | struct book *b = container_of(rcu, struct book, rcu); 54 | 55 | /** 56 | * Why print preemt_count?? 57 | * 58 | * To check whether this callback is atomic context or not. 59 | * preempt_count here is more than 0. Because it is irq context. 60 | */ 61 | pr_info("callback free : %lx, preempt_count : 0x%x\n", 62 | (unsigned long)b, preempt_count()); 63 | kfree(b); 64 | } 65 | 66 | static void add_book(int id, const char *name, const char *author) { 67 | struct book *b; 68 | 69 | b = kzalloc(sizeof(struct book), GFP_KERNEL); 70 | if(!b) 71 | return; 72 | 73 | b->id = id; 74 | strncpy(b->name, name, sizeof(b->name)); 75 | strncpy(b->author, author, sizeof(b->author)); 76 | b->borrow = 0; 77 | 78 | /** 79 | * list_add_rcu 80 | * 81 | * add_node(writer - add) use spin_lock() 82 | */ 83 | spin_lock(&books_lock); 84 | list_add_rcu(&b->node, &books); 85 | spin_unlock(&books_lock); 86 | } 87 | 88 | static int borrow_book(int id, int async) { 89 | struct book *b = NULL; 90 | struct book *new_b = NULL; 91 | struct book *old_b = NULL; 92 | 93 | /** 94 | * updater 95 | * 96 | * (updater) require that alloc new node & copy, update new node & reclaim old node 97 | * list_replace_rcu() is used to do that. 98 | */ 99 | rcu_read_lock(); 100 | 101 | list_for_each_entry(b, &books, node) { 102 | if(b->id == id) { 103 | if(b->borrow) { 104 | rcu_read_unlock(); 105 | return -1; 106 | } 107 | 108 | old_b = b; 109 | break; 110 | } 111 | } 112 | 113 | if(!old_b) { 114 | rcu_read_unlock(); 115 | return -1; 116 | } 117 | 118 | new_b = kzalloc(sizeof(struct book), GFP_ATOMIC); 119 | if(!new_b) { 120 | rcu_read_unlock(); 121 | return -1; 122 | } 123 | 124 | memcpy(new_b, old_b, sizeof(struct book)); 125 | new_b->borrow = 1; 126 | 127 | spin_lock(&books_lock); 128 | list_replace_rcu(&old_b->node, &new_b->node); 129 | spin_unlock(&books_lock); 130 | 131 | rcu_read_unlock(); 132 | 133 | if(async) { 134 | call_rcu(&old_b->rcu, book_reclaim_callback); 135 | }else { 136 | synchronize_rcu(); 137 | kfree(old_b); 138 | } 139 | 140 | pr_info("borrow success %d, preempt_count : 0x%x\n", id, preempt_count()); 141 | return 0; 142 | } 143 | 144 | static int is_borrowed_book(int id) { 145 | struct book *b; 146 | 147 | /** 148 | * reader 149 | * 150 | * iteration(read) require rcu_read_lock(), rcu_read_unlock() 151 | * and use list_for_each_entry_rcu() 152 | */ 153 | rcu_read_lock(); 154 | list_for_each_entry_rcu(b, &books, node) { 155 | if(b->id == id) { 156 | rcu_read_unlock(); 157 | return b->borrow; 158 | } 159 | } 160 | rcu_read_unlock(); 161 | 162 | pr_err("not exist book\n"); 163 | return -1; 164 | } 165 | 166 | static int return_book(int id, int async) { 167 | struct book *b = NULL; 168 | struct book *new_b = NULL; 169 | struct book *old_b = NULL; 170 | 171 | /** 172 | * updater 173 | * 174 | * (updater) require that alloc new node & copy, update new node & reclaim old node 175 | * list_replace_rcu() is used to do that. 176 | */ 177 | rcu_read_lock(); 178 | 179 | list_for_each_entry(b, &books, node) { 180 | if(b->id == id) { 181 | if(!b->borrow) { 182 | rcu_read_unlock(); 183 | return -1; 184 | } 185 | 186 | old_b = b; 187 | break; 188 | } 189 | } 190 | 191 | if(!old_b) { 192 | rcu_read_unlock(); 193 | return -1; 194 | } 195 | 196 | new_b = kzalloc(sizeof(struct book), GFP_ATOMIC); 197 | if(!new_b) { 198 | rcu_read_unlock(); 199 | return -1; 200 | } 201 | 202 | memcpy(new_b, old_b, sizeof(struct book)); 203 | new_b->borrow = 0; 204 | 205 | spin_lock(&books_lock); 206 | list_replace_rcu(&old_b->node, &new_b->node); 207 | spin_unlock(&books_lock); 208 | 209 | rcu_read_unlock(); 210 | 211 | if(async) { 212 | call_rcu(&old_b->rcu, book_reclaim_callback); 213 | }else { 214 | synchronize_rcu(); 215 | kfree(old_b); 216 | } 217 | 218 | pr_info("return success %d, preempt_count : 0x%x\n", id, preempt_count()); 219 | return 0; 220 | } 221 | 222 | static void delete_book(int id, int async) { 223 | struct book *b; 224 | 225 | spin_lock(&books_lock); 226 | list_for_each_entry(b, &books, node) { 227 | if(b->id == id) { 228 | /** 229 | * list_del 230 | * 231 | * del_node(writer - delete) require locking mechanism. 232 | * we can choose 3 ways to lock. Use 'a' here. 233 | * 234 | * a. locking, 235 | * b. atomic operations, or 236 | * c. restricting updates to a single task. 237 | */ 238 | list_del_rcu(&b->node); 239 | spin_unlock(&books_lock); 240 | 241 | if(async) { 242 | call_rcu(&b->rcu, book_reclaim_callback); 243 | }else { 244 | synchronize_rcu(); 245 | kfree(b); 246 | } 247 | return; 248 | } 249 | } 250 | spin_unlock(&books_lock); 251 | 252 | pr_err("not exist book\n"); 253 | } 254 | 255 | static void print_book(int id) { 256 | struct book *b; 257 | 258 | rcu_read_lock(); 259 | list_for_each_entry_rcu(b, &books, node) { 260 | if(b->id == id) { 261 | /** 262 | * Why print address of "struct book *b"?? 263 | * 264 | * If b was updated, address of b must be different. 265 | * We can know whether b is updated or not by address. 266 | */ 267 | pr_info("id : %d, name : %s, author : %s, borrow : %d, addr : %lx\n", \ 268 | b->id, b->name, b->author, b->borrow, (unsigned long)b); 269 | rcu_read_unlock(); 270 | return; 271 | } 272 | } 273 | rcu_read_unlock(); 274 | 275 | pr_err("not exist book\n"); 276 | } 277 | 278 | static void test_example(int async) { 279 | add_book(0, "book1", "jb"); 280 | add_book(1, "book2", "jb"); 281 | 282 | print_book(0); 283 | print_book(1); 284 | 285 | pr_info("book1 borrow : %d\n", is_borrowed_book(0)); 286 | pr_info("book2 borrow : %d\n", is_borrowed_book(1)); 287 | 288 | borrow_book(0, async); 289 | borrow_book(1, async); 290 | 291 | print_book(0); 292 | print_book(1); 293 | 294 | return_book(0, async); 295 | return_book(1, async); 296 | 297 | print_book(0); 298 | print_book(1); 299 | 300 | delete_book(0, async); 301 | delete_book(1, async); 302 | 303 | print_book(0); 304 | print_book(1); 305 | } 306 | 307 | static int list_rcu_example_init(void) 308 | { 309 | spin_lock_init(&books_lock); 310 | 311 | test_example(0); 312 | test_example(1); 313 | return 0; 314 | } 315 | 316 | static void list_rcu_example_exit(void) 317 | { 318 | return; 319 | } 320 | 321 | module_init(list_rcu_example_init); 322 | module_exit(list_rcu_example_exit); 323 | MODULE_LICENSE("GPL"); 324 | -------------------------------------------------------------------------------- /ksync/rcu_example/list_rcu_example.txt: -------------------------------------------------------------------------------- 1 | https://github.com/jinb-park/rcu_example 2 | 3 | ================== 4 | list_rcu_example 5 | ================== 6 | 7 | Table of Contents: 8 | 9 | 1. book management system 10 | 2. mapping between rcu operation and book operation 11 | 12 | 13 | 14 | 1. book management system 15 | ============================== 16 | 17 | This example code is book management system by using rcu list. 18 | 19 | 20 | 21 | 2. mapping between book operation and rcu operation 22 | =========================================================== 23 | 24 | 25 | There are 5 book operations. and Each operations is mapped with a rcu operation. 26 | You can get information about implementation of each operation from source code. 27 | 28 | 1) add_book = RCU Updater 29 | 2) borrow_book = RCU Updater and Reclaimer 30 | 3) return_book = RCU Updater and Reclaimer 31 | 4) is_borrowed_book = RCU Reader 32 | 5) delete_book = RCU Updater and Reclaimer 33 | 34 | 35 | -------------------------------------------------------------------------------- /list/list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * list.c 3 | *************************************************************** 4 | * (c) Author: Kaiwan NB, kaiwanTECH 5 | **************************************************************** 6 | * Brief Description: 7 | * Basic usage of the Linux kernel's famous linked list functionality.. 8 | * Ref: https://www.kernel.org/doc/html/latest/core-api/kernel-api.html#list-management-functions 9 | * License: Dual MIT/GPL 10 | */ 11 | #define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | MODULE_AUTHOR("kaiwanTECH"); 20 | MODULE_DESCRIPTION("a simple Linux kernel linked list usage demo"); 21 | MODULE_LICENSE("Dual MIT/GPL"); // or whatever 22 | MODULE_VERSION("0.1"); 23 | 24 | LIST_HEAD(head_node); 25 | struct node { 26 | struct list_head list; /* first member should be this one; it has 27 | * the pointers to next and prev 28 | */ 29 | int ival1, ival2; 30 | s8 letter; 31 | }; 32 | 33 | static int add2tail(int v1, int v2, s8 achar) 34 | { 35 | struct node *mynode = NULL; 36 | 37 | mynode = kzalloc(sizeof(struct node), GFP_KERNEL); 38 | if (!mynode) 39 | return -ENOMEM; 40 | mynode->ival1 = v1; 41 | mynode->ival2 = v2; 42 | mynode->letter = achar; 43 | 44 | INIT_LIST_HEAD(&mynode->list); 45 | // void list_add_tail(struct list_head *new, struct list_head *head) 46 | list_add_tail(&mynode->list, &head_node); 47 | pr_info("Added a node (with letter '%c') to the list...\n", achar); 48 | 49 | return 0; 50 | } 51 | 52 | static void showlist(void) 53 | { 54 | //struct list_head *ptr; 55 | struct node *curr; 56 | 57 | if (list_empty(&head_node)) 58 | return; 59 | 60 | pr_info(" val1 | val2 | letter\n"); 61 | #if 0 62 | list_for_each(ptr, &head_node) { 63 | curr = list_entry(ptr, struct node, list); // wrapper over container_of() 64 | #else 65 | // simpler: internally invokes __container_of() to get the ptr to curr struct 66 | list_for_each_entry(curr, &head_node, list) { 67 | #endif 68 | pr_info("%9d %9d %c\n", 69 | curr->ival1, curr->ival2, curr->letter); 70 | } 71 | } 72 | 73 | /* Works, but is O(n) */ 74 | static void findinlist_letter(s8 char2locate) 75 | { 76 | struct node *curr; 77 | int i = 0; 78 | bool found = false; 79 | 80 | if (list_empty(&head_node)) 81 | return; 82 | 83 | pr_info("Searching list for letter '%c'...\n", char2locate); 84 | list_for_each_entry(curr, &head_node, list) { 85 | if (curr->letter == char2locate) { 86 | found = true; 87 | pr_info("found '%c' @ node #%d:\n" 88 | "%9d %9d _%c_\n", 89 | char2locate, i, curr->ival1, curr->ival2, curr->letter); 90 | } 91 | i++; 92 | } 93 | if (!found) 94 | pr_info("Didn't find '%c' in list\n", char2locate); 95 | } 96 | 97 | static void freelist(void) 98 | { 99 | struct node *curr; 100 | 101 | if (list_empty(&head_node)) 102 | return; 103 | 104 | pr_info("freeing list items...\n"); 105 | list_for_each_entry(curr, &head_node, list) 106 | kfree(curr); 107 | } 108 | 109 | static int __init list_init(void) 110 | { 111 | #if 0 112 | struct module mymod; 113 | #endif 114 | 115 | /* Add a few nodes to the tail of the list */ 116 | add2tail(1, 2, 'l'); 117 | add2tail(5, 1000, 'i'); 118 | add2tail(3, 1415, 's'); 119 | add2tail(jiffies, jiffies+msecs_to_jiffies(300), 't'); 120 | 121 | // display the list items 122 | showlist(); 123 | 124 | // search for some items in the list 125 | findinlist_letter('s'); 126 | findinlist_letter('z'); 127 | 128 | /* Iterate over all modules? 129 | * Fails as struct module is not available (!exported) to module authors! 130 | */ 131 | #if 0 132 | list_for_each_entry(module.list, THIS_MODULE, list) 133 | pr_info("module: %s\n", mymod->name); 134 | #endif 135 | 136 | return 0; /* success */ 137 | } 138 | 139 | static void __exit list_exit(void) 140 | { 141 | freelist(); 142 | pr_info("removed\n"); 143 | } 144 | 145 | module_init(list_init); 146 | module_exit(list_exit); 147 | -------------------------------------------------------------------------------- /lkm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # lkm : a silly kernel module dev - build, load, unload - helper wrapper script 3 | # License: MIT 4 | unset ARCH 5 | unset CROSS_COMPILE 6 | name=$(basename "${0}") 7 | 8 | #-------------- r u n c m d ------------------------------------------- 9 | # Display and run the provided command. 10 | # Parameter(s): the command to run 11 | runcmd() 12 | { 13 | local SEP="------------------------------" 14 | [ $# -eq 0 ] && return 15 | echo "${SEP} 16 | $* 17 | ${SEP}" 18 | eval "$@" 19 | [ $? -ne 0 ] && echo " ^--[FAILED]" 20 | } 21 | 22 | ### "main" here 23 | 24 | [ $# -ne 1 ] && { 25 | echo "Usage: ${name} name-of-kernel-module-file (without the .c)" 26 | exit 1 27 | } 28 | [[ "${1}" = *"."* ]] && { 29 | echo "Usage: ${name} name-of-kernel-module-file ONLY (do NOT put any extension)." 30 | exit 1 31 | } 32 | 33 | echo "Version info:" 34 | which lsb_release >/dev/null 2>&1 && { 35 | echo -n "Distro: " 36 | lsb_release -a 2>/dev/null |grep "Description" |awk -F':' '{print $2}' 37 | } 38 | echo -n "Kernel: " ; uname -r 39 | 40 | runcmd "sudo rmmod $1 2> /dev/null" 41 | #runcmd "make clean" 42 | runcmd "sudo dmesg -C" 43 | runcmd "make || exit 1" 44 | # TODO - the '|| exit 1' does not seem to work 45 | 46 | [ ! -f "$1".ko ] && { 47 | echo "[!] ${name}: $1.ko has not been built, aborting..." 48 | exit 1 49 | } 50 | 51 | runcmd "sudo insmod ./$1.ko && lsmod|grep $1" 52 | # Ubuntu 20.10 onward has enabled CONFIG_SECURITY_DMESG_RESTRICT ! That's good for security 53 | # So we need to 'sudo' dmesg; thanks to @gregbuchholz for pointing this out 54 | runcmd "sudo dmesg" 55 | exit 0 56 | -------------------------------------------------------------------------------- /lkm_template/README.md: -------------------------------------------------------------------------------- 1 | This source directory serves as a 'template' for Linux LKMs (Loadable Kernel 2 | Modules). Please do go through the files in it carefully and follow the 3 | conventions and style; particularly, see and follow the various Makefile 4 | targets. 5 | 6 | By 'follow', what we really mean is, use them! They help you perform key sanity 7 | checks on your code, via code-style checking, static and dynamic analysis tools. 8 | 9 | The output of the `make help` below shows the targets: 10 | 11 | ` 12 | $ make help 13 | === Makefile Help : additional targets available === 14 | 15 | TIP: Type make to show all valid targets 16 | FYI: KDIR=/lib/modules/6.5.6-200.fc38.x86_64/build ARCH= CROSS_COMPILE= ccflags-y="-UDEBUG -DDYNAMIC_DEBUG_MODULE" MYDEBUG=n DBG_STRIP=n 17 | 18 | --- usual kernel LKM targets --- 19 | typing "make" or "all" target : builds the kernel module object (the .ko) 20 | install : installs the kernel module(s) to INSTALL_MOD_PATH (default here: /lib/modules/6.5.6-200.fc38.x86_64/). 21 | : Takes care of performing debug-only symbols stripping iff MYDEBUG=n and not using module signature 22 | nsdeps : namespace dependencies resolution; for possibly importing namespaces 23 | clean : cleanup - remove all kernel objects, temp files/dirs, etc 24 | 25 | --- kernel code style targets --- 26 | code-style : "wrapper" target over the following kernel code style targets 27 | indent : run the indent utility on source file(s) to indent them as per the kernel code style 28 | checkpatch : run the kernel code style checker tool on source file(s) 29 | 30 | --- kernel static analyzer targets --- 31 | sa : "wrapper" target over the following kernel static analyzer targets 32 | sa_sparse : run the static analysis sparse tool on the source file(s) 33 | sa_gcc : run gcc with option -W1 ("Generally useful warnings") on the source file(s) 34 | sa_flawfinder : run the static analysis flawfinder tool on the source file(s) 35 | sa_cppcheck : run the static analysis cppcheck tool on the source file(s) 36 | TIP: use Coccinelle as well: https://www.kernel.org/doc/html/v6.1/dev-tools/coccinelle.html 37 | 38 | --- kernel dynamic analysis targets --- 39 | da_kasan : DUMMY target: this is to remind you to run your code with the dynamic analysis KASAN tool enabled; requires configuring the kernel with CONFIG_KASAN On, rebuild and boot it 40 | da_lockdep : DUMMY target: this is to remind you to run your code with the dynamic analysis LOCKDEP tool (for deep locking issues analysis) enabled; requires configuring the kernel with CONFIG_PROVE_LOCKING On, rebuild and boot it 41 | TIP: Best to build a debug kernel with several kernel debug config options turned On, boot via it and run all your test cases 42 | 43 | --- misc targets --- 44 | tarxz-pkg : tar and compress the LKM source files as a tar.xz into the dir above; allows one to transfer and build the module on another system 45 | TIP: When extracting, to extract into a directory with the same name as the tar file, do this: 46 | tar -xvf lkm_template.tar.xz --one-top-level 47 | help : this help target 48 | $` 49 | 50 | ----------------------------------------------------------------------- 51 | **TIP** 52 | On Ubuntu 22.04 or earlier, it's possible that the module build fails with this error: 53 | 54 | `gcc-11: error: unrecognized command-line option ‘-ftrivial-auto-var-init=zero’` 55 | 56 | It's a limitation within GCC ver 11; to fix it, install gcc-12, set CC to it in the Makefile and retry: 57 | 58 | `sudo apt install gcc-12` 59 | 60 | In the Makefile, add this line: 61 | 62 | `CC := gcc-12 ` 63 | 64 | and then rebuild... 65 | 66 | 67 | A few generic important rules / a quick Checklist for the Programmer 68 | ---------------------------------------------------------------------------------- 69 | DID YOU REMEMBER TO 70 | 71 | ✔ Rule #1 : Check all APIs for their failure case 72 | 73 | ✔ Rule #2 : Compile with warnings on (-Wall -Wextra) and eliminate all 74 | warnings as far as is possible 75 | 76 | ✔ Rule #3 : Never trust [user] input; validate it 77 | 78 | ✔ Rule #4 : Use assertions in your code 79 | 80 | ✔ Rule #5 : Eliminate unused (or dead) code from the codebase immediately 81 | 82 | ✔ Rule #6 : Test thoroughly; ideally, 100% code coverage is the objective. 83 | Take the time and trouble to learn to use these powerful kernel-space tools: 84 | memory checkers (KASAN, kernel memory leak detector, KCSAN, UBSAN, etc), 85 | static and dynamic analyzers, security checkers (checksec), fuzzers, etc 86 | 87 | ✔ Rule #7 : Do NOT Assume Anything 88 | (“ASSUME : makes an ASS out of U and ME” :-) ) 89 | 90 | Also see: 91 | LOW-LEVEL SOFTWARE DESIGN: https://kaiwantech.wordpress.com/2017/01/03/low-level-software-design/ 92 | 93 | 94 | ---------------------------------------------------------------------------------- 95 | FYI, the checkpatch.pl Perl script used here is part of the Linux kernel source; 96 | you can always download it from here: 97 | 98 | https://github.com/torvalds/linux/blob/master/scripts/checkpatch.pl 99 | ... or access it on your local system via 100 | 101 | ` ${KDIR}/scripts/checkpatch.pl` 102 | 103 | ; where `KDIR` is the location of your local kernel source tree (could even 104 | point to the kernel headers tree). 105 | -------------------------------------------------------------------------------- /lkm_template/lkm_template.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ch5/lkm_template/lkm_template.c 3 | *************************************************************** 4 | * This program is part of the source code released for the book 5 | * "Linux Kernel Programming" 2E 6 | * (c) Author: Kaiwan N Billimoria 7 | * Publisher: Packt 8 | * GitHub repository: 9 | * https://github.com/PacktPublishing/Linux-Kernel-Programming_2E 10 | * 11 | * From: Ch 5 : Writing Your First Kernel Module LKMs, Part 2 12 | **************************************************************** 13 | * Brief Description: 14 | * A very simple 'template' of sorts for a Loadable Kernel Module(s) (LKM). 15 | * Do take the time and trouble to study it via the book's Ch 5; don't ignore 16 | * it's 'better' Makefile ! 17 | * 18 | * For details, please refer the book, Ch 5. 19 | */ 20 | #define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__ 21 | 22 | #include 23 | #include 24 | 25 | MODULE_AUTHOR("Kaiwan N Billimoria"); 26 | MODULE_DESCRIPTION("a simple LKM template; do refer to the (better) Makefile as well"); 27 | MODULE_LICENSE("Dual MIT/GPL"); // or whatever 28 | MODULE_VERSION("0.2"); 29 | 30 | static int __init lkm_template_init(void) 31 | { 32 | pr_info("inserted\n"); 33 | return 0; /* success */ 34 | } 35 | 36 | static void __exit lkm_template_exit(void) 37 | { 38 | pr_info("removed\n"); 39 | } 40 | 41 | module_init(lkm_template_init); 42 | module_exit(lkm_template_exit); 43 | -------------------------------------------------------------------------------- /mm/allocsize_tests/kmalloc_test/kmalloc_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../../convenient.h" 5 | 6 | MODULE_LICENSE("Dual MIT/GPL"); 7 | 8 | static int __init kmt_init(void) 9 | { 10 | int num=100; 11 | void *p; 12 | while (1) { 13 | p = kmalloc(num, GFP_KERNEL); 14 | if (!p) { 15 | pr_alert("kmalloc fail, num=%d\n", num); 16 | return -ENOMEM; 17 | } 18 | num += 1000; 19 | pr_info("kmalloc(%7d) = %p\n", num, p); 20 | kfree(p); 21 | } 22 | return 0; // success 23 | } 24 | 25 | static void __exit kmt_exit(void) 26 | { 27 | pr_info("Goodbye\n"); 28 | } 29 | 30 | module_init(kmt_init); 31 | module_exit(kmt_exit); 32 | -------------------------------------------------------------------------------- /mm/allocsize_tests/ksize_test/ksz_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ksz_test.c 3 | * A quick kmalloc/ksize test; we allocate kernel RAM with kmalloc(), 4 | * starting with 100 bytes and incrementing this in a loop by 'stepsz' 5 | * bytes (you can vary it by passing it as a module parameter). 6 | * Thus, this kernel module clearly shows how kernel memory can get wasted 7 | * by using poorly thought-out amounts. 8 | * 9 | * Note- the kernel module will probably appear to fail on insmod with a 10 | * message similar to: 11 | # insmod ./ksz_test.ko 12 | insmod: ERROR: could not insert module ./ksz_test.ko: Cannot allocate memory 13 | # 14 | * This is expected- we stress the system asking for larger and larger chunks 15 | * of kernel direct-mapped RAM via the kmalloc, so ultimately it will fail. 16 | * 17 | * Please LOOK UP the kernel ring buffer via 'dmesg' to see the printk's! 18 | * 19 | * Author: Kaiwan NB, kaiwanTECH 20 | * License: Dual MIT/GPL 21 | */ 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | MODULE_LICENSE("Dual MIT/GPL"); 29 | MODULE_AUTHOR("Kaiwan NB, kaiwanTECH"); 30 | MODULE_DESCRIPTION 31 | ("A quick kmalloc/ksize test; shows how kernel memory can get wasted" 32 | " by using poorly thought-out amounts"); 33 | 34 | static int stepsz = 10000; 35 | module_param(stepsz, int, 0); 36 | MODULE_PARM_DESC(stepsz, 37 | "Number of bytes to increment each kmalloc attempt by (default=10000)"); 38 | 39 | const char *hdr = 40 | "[1] kmalloc(n) :[2]actual: wastage : %age\n" 41 | " bytes : bytes : [2-1] : waste\n"; 42 | 43 | static int __init kmt_init(void) 44 | { 45 | int num = 100, actual_alloc = 0; 46 | void *p; 47 | 48 | pr_info("context: %s:%d\n", current->comm, current->pid); 49 | pr_info("%s", hdr); 50 | 51 | while (1) { 52 | p = kmalloc(num, GFP_KERNEL); 53 | if (unlikely(!p)) { 54 | pr_alert("kmalloc fail, num=%d\n", num); 55 | return -ENOMEM; 56 | } 57 | actual_alloc = ksize(p); 58 | pr_info("kmalloc(%7d) : %7d : %7d : %3d%%\n", 59 | num, actual_alloc, actual_alloc - num, 60 | (((actual_alloc - num) * 100 / num))); 61 | kfree(p); 62 | num += stepsz; 63 | } 64 | return 0; // success 65 | } 66 | 67 | static void __exit kmt_exit(void) 68 | { 69 | pr_info("context: %s:%d\n", current->comm, current->pid); 70 | pr_info("Goodbye\n"); 71 | } 72 | 73 | module_init(kmt_init); 74 | module_exit(kmt_exit); 75 | -------------------------------------------------------------------------------- /mm/phymap_iomem/color.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #------------------------------------------------------------------ 3 | # color.sh 4 | # 5 | # Common convenience routines for color support in bash. 6 | # 7 | # (c) Kaiwan N Billimoria 8 | # kaiwan -at- kaiwantech -dot- com 9 | # MIT / GPL v2 10 | #------------------------------------------------------------------ 11 | # The SEALS Opensource Project 12 | # SEALS : Simple Embedded Arm Linux System 13 | # Maintainer : Kaiwan N Billimoria 14 | # kaiwan -at- kaiwantech -dot- com 15 | # Project URL: 16 | # https://github.com/kaiwan/seals 17 | 18 | #------------------- Colors!! Yay :-) ----------------------------------------- 19 | # Ref: https://stackoverflow.com/questions/5947742/how-to-change-the-output-color-of-echo-in-linux 20 | # [Ans by Drew Noakes] 21 | #--- Foreground Colors 22 | fg_black() { tput setaf 0 23 | } 24 | fg_red() { tput setaf 1 25 | } 26 | fg_green() { tput setaf 2 27 | } 28 | fg_yellow() { tput setaf 3 29 | } 30 | fg_blue() { tput setaf 4 31 | } 32 | fg_magenta() { tput setaf 5 33 | } 34 | fg_cyan() { tput setaf 6 35 | } 36 | fg_white() { tput setaf 7 37 | } 38 | fg_grey() { tput setaf 8 39 | } 40 | 41 | #--- Background Colors 42 | bg_white() { tput setab 7 43 | } 44 | bg_red() { tput setab 1 45 | } 46 | bg_green() { tput setab 2 47 | } 48 | bg_yellow() { tput setab 3 49 | } 50 | bg_blue() { tput setab 4 51 | } 52 | bg_cyan() { tput setab 6 53 | } 54 | 55 | #--- Text Attributes <-- NOK! 56 | #tb=$(tput bold) # bold 57 | #tsb=$(tput smso) # enter standout bold mode 58 | #trb=$(tput rmso) # exit standout bold mode 59 | #trev=$(tput rev) # reverse video 60 | #tdim=$(tput dim) # half-brightness 61 | #tBell=$(tput bel) # sound bell! 62 | 63 | #--- Composite text attribs [ta] <-- NOK! 64 | #taErr="${tb}${fg_red}${bg_white}${tBell}" 65 | #taTitle="${tb}${fg_black}${bg_yellow}" 66 | #taReg="" # 'regular' msgs 67 | #taBold="$(tput bold)" 68 | #taBold="${tb}" 69 | #taAbnormal="${fg_white}${bg_blue}" # 'Abnormal' msgs - error msgs,... 70 | #taDebug="${tdim}" 71 | 72 | # Reset text attributes to normal without clearing screen. 73 | color_reset() 74 | { 75 | tput sgr0 76 | } 77 | 78 | #--------------------- E c h o ---------------------------------------- 79 | # The _base_ echo/logging function. 80 | # Parameters: 81 | # $1 : a tag that speicifies the logging level 82 | # $2 ... $n : message to echo (to stdout and logfile) 83 | # 84 | # Logging Levels (from low->high 'criticality') are: 85 | # -------- -------- 86 | # LogLevel Function 87 | # -------- -------- 88 | # DDEBUG decho 89 | # INFO iecho 90 | # ALERT aecho [bold] 91 | # WARN wecho 92 | # CRIT cecho 93 | # TITL techo <-- exception: this is NOT really a loglevel, 94 | # it's a special display attribute 95 | # !WARNING! 96 | # Ensure you don't call any of the x[Ee]cho functions from here, as they 97 | # call this func and it becomes infinitely recursive. 98 | Echo() 99 | { 100 | local SEP=" " 101 | # echo "# = $# : params: $@" 102 | [ $# -eq 0 ] && return 1 103 | local numparams=$# 104 | local tag="${1}" 105 | [ ${numparams} -gt 1 ] && shift # get rid of the tag, so that we can access the txt msg 106 | 107 | # Prefix the logging level : debug/info/warn/critical 108 | local loglevel 109 | # maintaining 4-char strings for 'loglevel' alleviates the need for more 110 | # code with printf etc 111 | case "${tag}" in 112 | DDEBUG) loglevel="dbug" 113 | ;; 114 | INFO) loglevel="info" 115 | ;; 116 | ALERT) loglevel="alrt" 117 | ;; 118 | WARN) loglevel="warn" 119 | ;; 120 | CRIT) loglevel="crit" 121 | ;; 122 | TITL) loglevel="titl" 123 | ;; 124 | *) loglevel=" " 125 | ;; 126 | esac 127 | 128 | local dt_log="[$(date +%a_%d%b%Y_%T.%N)]" 129 | local dt_disp 130 | [ ${VERBOSE_MSG} -eq 1 ] && dt_disp=${dt} 131 | 132 | local msgpfx1_log="[${loglevel}]${SEP}${dt_log}" 133 | local msgpfx1_disp="${dt}" 134 | [ ${VERBOSE_MSG} -eq 1 ] && msgpfx1_disp="${msgpfx1_log}" 135 | 136 | local msgpfx2_log="${SEP}${name}:${FUNCNAME[ 1 ]}()${SEP}" 137 | local msgpfx2_disp 138 | [ ${VERBOSE_MSG} -eq 1 ] && msgpfx2_disp="${msgpfx2_log}" 139 | 140 | local msgtxt="$@" 141 | local msgfull_log="${msgpfx1_log}${msgpfx2_log}${msgtxt}" 142 | local msg_disp="${msgpfx1_disp}${SEP}${msgtxt}" 143 | [ ${VERBOSE_MSG} -eq 1 ] && msg_disp="${msgfull_log}" 144 | 145 | # lets log it first anyhow 146 | [ -f ${LOGFILE_COMMON} ] && echo "${msgfull_log}" >> ${LOGFILE_COMMON} 147 | 148 | if [ ${numparams} -eq 1 -o ${COLOR} -eq 0 ]; then # no color/text attribute 149 | [ ${DEBUG} -eq 1 ] && echo "${msgfull_log}" || echo "${msg_disp}" 150 | return 0 151 | fi 152 | 153 | #--- 'color' or text attrib present! 154 | fg_green 155 | echo -n "${msgpfx1_disp}${SEP}" 156 | [ ${DEBUG} -eq 1 -o ${VERBOSE_MSG} -eq 1 ] && { 157 | fg_blue 158 | echo -n "${msgpfx2_disp}" 159 | } 160 | color_reset # Reset to normal. 161 | 162 | case "${tag}" in 163 | DDEBUG) tput dim ; fg_red #fg_magenta 164 | ;; 165 | INFO) #tput # Deliberate: no special attribs for 'info' 166 | ;; 167 | ALERT) tput bold 168 | ;; 169 | WARN) fg_red ; bg_yellow ; tput bold 170 | ;; 171 | CRIT) fg_white ; bg_red ; tput bold 172 | ;; 173 | TITL) fg_black ; bg_yellow ; tput bold 174 | ;; 175 | esac 176 | echo "${msgtxt}" 177 | color_reset # Reset to normal. 178 | return 0 179 | } # end Echo() 180 | 181 | #--- Wrappers over Echo follow --- 182 | # Parameters: 183 | # $1 : message to echo (to stdout and logfile) 184 | 185 | #--------------------- d e c h o -------------------------------------- 186 | # DEBUG-level echo :-) 187 | decho() 188 | { 189 | [ ${DEBUG} -eq 1 ] && Echo DDEBUG "$1" 190 | } 191 | #--------------------- i e c h o --------------------------------------- 192 | # INFO-level / regular Color-echo. 193 | iecho () 194 | { 195 | Echo INFO "$1" 196 | } 197 | #--------------------- a e c h o --------------------------------------- 198 | # ALERT-level Color-echo. 199 | aecho () 200 | { 201 | Echo ALERT "$1" 202 | } 203 | #--------------------- w e c h o --------------------------------------- 204 | # WARN-level Color-echo. 205 | wecho () 206 | { 207 | Echo WARN "$1" 208 | } 209 | #--------------------- c e c h o --------------------------------------- 210 | # CRITical-level Color-echo. 211 | cecho () 212 | { 213 | Echo CRIT "$1" 214 | } 215 | 216 | #--------------------- t e c h o --------------------------------------- 217 | # Title Color-echo. 218 | techo () 219 | { 220 | Echo TITL "$1" 221 | } 222 | #--- 223 | 224 | # ShowTitle 225 | # Display a string in "title" form 226 | # Parameter(s): 227 | # $1 : String to display [required] 228 | ShowTitle() 229 | { 230 | techo "$1" 231 | } 232 | 233 | 234 | test_256() 235 | { 236 | for i in $(seq 0 255) 237 | do 238 | tput setab $i 239 | printf '%03d ' $i 240 | done 241 | color_reset 242 | } 243 | -------------------------------------------------------------------------------- /mm/phymap_iomem/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #------------------------------------------------------------------ 3 | # common.sh 4 | # 5 | # Common convenience routines 6 | # 7 | # (c) Kaiwan N Billimoria 8 | # kaiwan -at- kaiwantech -dot- com 9 | # MIT / GPL v2 10 | #------------------------------------------------------------------ 11 | # The SEALS Opensource Project 12 | # SEALS : Simple Embedded Arm Linux System 13 | # Maintainer : Kaiwan N Billimoria 14 | # kaiwan -at- kaiwantech -dot- com 15 | # Project URL: 16 | # https://github.com/kaiwan/seals 17 | 18 | export TOPDIR=$(pwd) 19 | ON=1 20 | OFF=0 21 | 22 | ### UPDATE for your box 23 | PFX=. 24 | source ${PFX}/err_common.sh || { 25 | echo "$name: could not source ${PFX}/err_common.sh, aborting..." 26 | exit 1 27 | } 28 | source ${PFX}/color.sh || { 29 | echo "$name: could not source ${PFX}/color.sh, aborting..." 30 | exit 1 31 | } 32 | 33 | # If we're not in a GUI (X Windows) display, abort (reqd for yad) 34 | check_gui() 35 | { 36 | which xdpyinfo > /dev/null 2>&1 || { 37 | FatalError "xdpyinfo (package x11-utils) does not seem to be installed. Aborting..." 38 | } 39 | xdpyinfo >/dev/null 2>&1 || { 40 | FatalError "Sorry, we're not running in a GUI display environment. Aborting..." 41 | } 42 | which xrandr > /dev/null 2>&1 || { 43 | FatalError "xrandr (package x11-server-utils) does not seem to be installed. Aborting..." 44 | } 45 | 46 | #--- Screen Resolution stuff 47 | res_w=$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f1) 48 | res_h=$(xrandr --current | grep '*' | uniq | awk '{print $1}' | cut -d 'x' -f2) 49 | centre_x=$((($res_w/3)+0)) 50 | centre_y=$((($res_h/3)-100)) 51 | CAL_WIDTH=$((($res_w/3)+200)) 52 | CAL_HT=$(($res_h/3)) 53 | } 54 | 55 | 56 | # genLogFilename 57 | # Generates a logfile name that includes the date/timestamp 58 | # Format: 59 | # ddMmmYYYY[_HHMMSS] 60 | # Parameter(s) 61 | # #$1 : String to prefix to log filename, null okay as well [required] 62 | # $1 : Include time component or not [required] 63 | # $1 = 0 : Don't include the time component (only date) in the log filename 64 | # $1 = 1 : include the time component in the log filename 65 | genLogFilename() 66 | { 67 | [ $1 -eq 0 ] && log_filename=$(date +%d%b%Y) 68 | [ $1 -eq 1 ] && log_filename=$(date +%d%b%Y_%H%M%S) 69 | echo ${log_filename} 70 | } 71 | 72 | # mysudo 73 | # Simple front end to gksudo/sudo 74 | # Parameter(s): 75 | # $1 : descriptive message 76 | # $2 ... $n : command to execute 77 | mysudo() 78 | { 79 | [ $# -lt 2 ] && { 80 | #echo "Usage: mysudo " 81 | return 82 | } 83 | local msg=$1 84 | shift 85 | local cmd="$@" 86 | aecho "${LOGNAME}: ${msg}" 87 | sudo --preserve-env sh -c "${cmd}" 88 | } 89 | 90 | # check_root_AIA 91 | # Check whether we are running as root user; if not, exit with failure! 92 | # Parameter(s): 93 | # None. 94 | # "AIA" = Abort If Absent :-) 95 | check_root_AIA() 96 | { 97 | if [ `id -u` -ne 0 ]; then 98 | Echo "Error: need to run as root! Aborting..." 99 | exit 1 100 | fi 101 | } 102 | 103 | # check_file_AIA 104 | # Check whether the file, passed as a parameter, exists; if not, exit with failure! 105 | # Parameter(s): 106 | # $1 : Pathname of file to check for existence. [required] 107 | # "AIA" = Abort If Absent :-) 108 | # Returns: 0 on success, 1 on failure 109 | check_file_AIA() 110 | { 111 | [ $# -ne 1 ] && return 1 112 | [ ! -f $1 ] && { 113 | Echo "Error: file \"$1\" does not exist. Aborting..." 114 | exit 1 115 | } 116 | } 117 | 118 | # check_folder_AIA 119 | # Check whether the directory, passed as a parameter, exists; if not, exit with failure! 120 | # Parameter(s): 121 | # $1 : Pathname of folder to check for existence. [required] 122 | # "AIA" = Abort If Absent :-) 123 | # Returns: 0 on success, 1 on failure 124 | check_folder_AIA() 125 | { 126 | [ $# -ne 1 ] && return 1 127 | [ ! -d $1 ] && { 128 | Echo "Error: folder \"$1\" does not exist. Aborting..." 129 | exit 1 130 | } 131 | } 132 | 133 | # check_folder_createIA 134 | # Check whether the directory, passed as a parameter, exists; if not, create it! 135 | # Parameter(s): 136 | # $1 : Pathname of folder to check for existence. [required] 137 | # "IA" = If Absent :-) 138 | # Returns: 0 on success, 1 on failure 139 | check_folder_createIA() 140 | { 141 | [ $# -ne 1 ] && return 1 142 | [ ! -d $1 ] && { 143 | Echo "Folder \"$1\" does not exist. Creating it..." 144 | mkdir -p $1 && return 0 || return 1 145 | } 146 | } 147 | 148 | 149 | # GetIP 150 | # Extract IP address from ifconfig output 151 | # Parameter(s): 152 | # $1 : name of network interface (string) 153 | # Returns: IPaddr on success, non-zero on failure 154 | GetIP() 155 | { 156 | [ $# -ne 1 ] && return 1 157 | ifconfig $1 >/dev/null 2>&1 || return 2 158 | ifconfig $1 |grep 'inet addr'|awk '{print $2}' |cut -f2 -d':' 159 | } 160 | 161 | # get_yn_reply 162 | # User's reply should be Y or N. 163 | # Returns: 164 | # 0 => user has answered 'Y' 165 | # 1 => user has answered 'N' 166 | get_yn_reply() 167 | { 168 | aecho -n "Type Y or N please (followed by ENTER) : " 169 | str="${@}" 170 | while true 171 | do 172 | aecho ${str} 173 | read reply 174 | 175 | case "$reply" in 176 | y | yes | Y | YES ) return 0 177 | ;; 178 | n* | N* ) return 1 179 | ;; 180 | *) aecho "What? Pl type Y / N" 181 | esac 182 | done 183 | } 184 | 185 | # MountPartition 186 | # Mounts the partition supplied as $1 187 | # Parameters: 188 | # $1 : device node of partition to mount 189 | # $2 : mount point 190 | # Returns: 191 | # 0 => mount successful 192 | # 1 => mount failed 193 | MountPartition() 194 | { 195 | [ $# -ne 2 ] && { 196 | aecho "MountPartition: parameter(s) missing!" 197 | return 1 198 | } 199 | 200 | DEVNODE=$1 201 | [ ! -b ${DEVNODE} ] && { 202 | aecho "MountPartition: device node $1 does not exist?" 203 | return 1 204 | } 205 | 206 | MNTPT=$2 207 | [ ! -d ${MNTPT} ] && { 208 | aecho "MountPartition: folder $2 does not exist?" 209 | return 1 210 | } 211 | 212 | mount |grep ${DEVNODE} >/dev/null || { 213 | #echo "The partition is not mounted, attempting to mount it now..." 214 | mount ${DEVNODE} -t auto ${MNTPT} || { 215 | wecho "Could not mount the '$2' partition!" 216 | return 1 217 | } 218 | } 219 | return 0 220 | } 221 | 222 | ## is_kernel_thread 223 | # Param: PID 224 | # Returns: 225 | # 1 if $1 is a kernel thread, 0 if not, 127 on failure. 226 | is_kernel_thread() 227 | { 228 | [ $# -ne 1 ] && { 229 | aecho "is_kernel_thread: parameter missing!" 1>&2 230 | return 127 231 | } 232 | 233 | prcs_name=$(ps aux |awk -v pid=$1 '$2 == pid {print $11}') 234 | #echo "prcs_name = ${prcs_name}" 235 | [ -z ${prcs_name} ] && { 236 | wecho "is_kernel_thread: could not obtain process name!" 1>&2 237 | return 127 238 | } 239 | 240 | firstchar=$(echo "${prcs_name:0:1}") 241 | #echo "firstchar = ${firstchar}" 242 | len=${#prcs_name} 243 | let len=len-1 244 | lastchar=$(echo "${prcs_name:${len}:1}") 245 | #echo "lastchar = ${lastchar}" 246 | [ ${firstchar} = "[" -a ${lastchar} = "]" ] && return 1 || return 0 247 | } 248 | 249 | #---------------- n u m t h r e a d s --------------------------------- 250 | # Given a process name, calculates the # of threads currently alive 251 | # within it _and_ other processes of the same name. 252 | # Params: 253 | # $1 = process name 254 | # Ret: # of threads curr alive in the given process 255 | # -the 'return' is an artifact; we echo the value; the caller is to 256 | # pick it up using the usual quoting technique. 257 | numthreads() 258 | { 259 | local pid nthrd total_thrds 260 | #for pidrec in $(ps -LA|egrep "^$1") 261 | # Loop over all processes by given name 262 | for pid in $(pgrep "$1") 263 | do 264 | #echo "pid: ${pid}" 265 | # get # threads within this pid 266 | nthrd=$(ls /proc/${pid}/task |wc -w) 267 | #echo "${pid}:${nthrd}" 268 | let total_thrds+=nthrd 269 | done 270 | echo "${total_thrds}" 271 | } # end numthreads() 272 | 273 | #------------------- p r _ s z _ h u m a n ---------------------------- 274 | # Prints given numeric KB value in MB, GB as required. 275 | # Requires: bc 276 | # Parameters: 277 | # $1 = label 278 | # $2 = size in KB 279 | # 280 | # TODO - on embedded systems it's unlikely 'bc' will be available; 281 | # must do without it.. 282 | pr_sz_human() 283 | { 284 | [ -z $2 ] && return 285 | which bc >/dev/null || return 286 | 287 | local szKB=$2 288 | local szMB=0 szGB=0 szTB=0 szPB=0 szEB=0 szZB=0 szYB=0 szBB=0 szGoB=0 289 | 290 | #echo "p1 = $1 ; p2 = $2 ; @ = $@" 291 | 292 | local verbose=0 293 | [ ${verbose} -eq 1 ] && { 294 | printf "%30s:%9s:%9s:%9s:%9s:%9s:%9s:%9s:%9s:%9s:%9s\n" " " "KB" "MB" "GB" "PB" "TB" "EB" "ZB" "YB" "BB" "GoB" 295 | } 296 | 297 | [ ${szKB} -ge 1024 ] && szMB=$(bc <<< "scale=2; ${szKB}/1024.0") # MB : megabytes : 10^6 298 | # !EMB: if we try and use simple bash arithmetic comparison, we get a 299 | # "integer expression expected" err; hence, use bc: 300 | if (( $(echo "${szMB} > 1024" |bc -l) )); then # GB : gigabytes : 10^9 301 | szGB=$(bc <<< "scale=2; ${szMB}/1024.0") 302 | fi 303 | if (( $(echo "${szGB} > 1024" |bc -l) )); then # TB : terabytes : 10^12 304 | szTB=$(bc <<< "scale=2; ${szGB}/1024.0") 305 | fi 306 | if (( $(echo "${szTB} > 1024" |bc -l) )); then # PB : petabytes : 10^15 307 | szPB=$(bc <<< "scale=2; ${szTB}/1024.0") 308 | fi 309 | if (( $(echo "${szPB} > 1024" |bc -l) )); then # EB : exabytes : 10^18 310 | szEB=$(bc <<< "scale=2; ${szPB}/1024.0") 311 | fi 312 | if (( $(echo "${szEB} > 1024" |bc -l) )); then # ZB : zettabytes : 10^21 313 | szZB=$(bc <<< "scale=2; ${szEB}/1024.0") 314 | fi 315 | if (( $(echo "${szZB} > 1024" |bc -l) )); then # YB : yottabytes : 10^24 316 | szYB=$(bc <<< "scale=2; ${szZB}/1024.0") 317 | fi 318 | if (( $(echo "${szYB} > 1024" |bc -l) )); then # BB : brontobytes : 10^27 319 | szBB=$(bc <<< "scale=2; ${szYB}/1024.0") 320 | fi 321 | if (( $(echo "${szBB} > 1024" |bc -l) )); then # GB [?] : geopbytes : 10^30 322 | szGoB=$(bc <<< "scale=2; ${szBB}/1024.0") 323 | fi 324 | 325 | printf "%-25s:%9ld" "$1" ${szKB} 326 | if (( $(echo "${szMB} > 0" |bc -l) )); then # print MB 327 | printf ":%9.2f" ${szMB} 328 | fi 329 | if (( $(echo "${szGB} > 0" |bc -l) )); then # print GB 330 | printf ":%9.2f" ${szGB} 331 | fi 332 | if (( $(echo "${szTB} > 0" |bc -l) )); then # print TB 333 | printf ":%9.2f" ${szTB} 334 | fi 335 | if (( $(echo "${szPB} > 0" |bc -l) )); then # print PB 336 | printf ":%9.2f" ${szPB} 337 | fi 338 | if (( $(echo "${szEB} > 0" |bc -l) )); then # print EB 339 | printf ":%9.2f" ${szEB} 340 | fi 341 | if (( $(echo "${szZB} > 0" |bc -l) )); then # print ZB 342 | printf ":%9.2f" ${szZB} 343 | fi 344 | if (( $(echo "${szYB} > 0" |bc -l) )); then # print YB 345 | printf ":%9.2f" ${szYB} 346 | fi 347 | if (( $(echo "${szBB} > 0" |bc -l) )); then # print BB 348 | printf ":%9.2f" ${szBB} 349 | fi 350 | if (( $(echo "${szGoB} > 0" |bc -l) )); then # print GoB 351 | printf ":%9.2f" ${szGoB} 352 | fi 353 | printf "\n" 354 | } 355 | -------------------------------------------------------------------------------- /mm/phymap_iomem/err_common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #------------------------------------------------------------------ 3 | # err_common.sh 4 | # 5 | # Common error handling routines. 6 | # 7 | # (c) Kaiwan N Billimoria 8 | # kaiwan -at- kaiwantech -dot- com 9 | # MIT / GPL v2 10 | #------------------------------------------------------------------ 11 | export TOPDIR=$(pwd) 12 | export VERBOSE_MSG=0 13 | export DEBUG=0 14 | # Replace with log filename 15 | export LOGFILE_COMMON=/dev/null 16 | export COLOR=1 17 | 18 | #--- Icons 19 | # src: /usr/share/icons/Humanity/actions/ 20 | ICON_NEXT=go-next 21 | ICON_BACK=go-previous 22 | ICON_YES=add #go-next 23 | ICON_NO=remove #gtk-remove 24 | ICON_ADD=add #gtk-add 25 | ICON_REGISTER=player_record 26 | ICON_SIGNIN=format-text-direction-ltr 27 | ICON_EXIT=stock_mark #system-log-out 28 | 29 | 30 | # QP 31 | # QuickPrint ;-) 32 | # Print timestamp, script name, line#. Useful for debugging. 33 | # [RELOOK / FIXME : not really useful as it doen't work as a true macro; 34 | # just prints _this_ script name, line#.] 35 | QP() 36 | { 37 | _ERR_HDR_FMT="%.23s %s[%s]: " 38 | _ERR_MSG_FMT="${_ERR_HDR_FMT}%s\n" 39 | [ ${COLOR} -eq 1 ] && fg_blue 40 | printf " QP: $_ERR_MSG_FMT" $(date +%F.%T.%N) " ${BASH_SOURCE[1]##*/}:${FUNCNAME[2]}" |tee -a ${LOGFILE_COMMON} 41 | dumpstack 42 | #printf " QP: $_ERR_MSG_FMT" $(date +%F.%T.%N) " ${BASH_SOURCE[1]##*/}:${BASH_LINENO[0]}" |tee -a ${LOGFILE_COMMON} 43 | [ ${COLOR} -eq 1 ] && color_reset 44 | unset _ERR_HDR_FMT 45 | unset _ERR_MSG_FMT 46 | } 47 | 48 | STACK_MAXDEPTH=32 # arbit? 49 | dumpstack() 50 | { 51 | #for frame in $(seq 1 $1) 52 | local frame=1 53 | local funcname 54 | 55 | ShowTitle " Stack Call-trace:" 56 | [ ${COLOR} -eq 1 ] && fg_blue 57 | while [ true ] 58 | do 59 | funcname=${FUNCNAME[${frame}]} 60 | printf " [frame #${frame}] ${BASH_SOURCE[${frame}]}:${funcname}:${BASH_LINENO[${frame}]}" 61 | #printf " [frame #${frame}] ${funcname}" 62 | [ ${frame} -ne 1 ] && printf "\n" || { 63 | [ ${COLOR} -eq 1 ] && fg_magenta 64 | printf " <-- top of stack\n" 65 | [ ${COLOR} -eq 1 ] && fg_blue 66 | } 67 | [ "${funcname}" = "main" ] && break # stop, reached 'main' 68 | [ ${frame} -ge ${STACK_MAXDEPTH} ] && break # just in case ... 69 | let frame=frame+1 70 | done |tee -a ${LOGFILE_COMMON} 71 | [ ${COLOR} -eq 1 ] && color_reset 72 | } 73 | 74 | # params: the error message 75 | cli_handle_error() 76 | { 77 | #QP 78 | if [ $# -lt 1 ] ; then 79 | cecho "FatalError :: " 80 | else 81 | cecho "FatalError :: $@" 82 | fi 83 | dumpstack 84 | [ ${COLOR} -eq 1 ] && color_reset 85 | exit 1 86 | } 87 | 88 | #--------------------- F a t a l E r r o r ---------------------------- 89 | # Exits with exit status 1 ! 90 | # Parameters: 91 | # $1 : error message [optional] 92 | FatalError() 93 | { 94 | local msgpre="Sorry, we've encountered a fatal error.\n\n" 95 | local errmsg="Details:\n$(date):${name}:${FUNCNAME[ 1 ]}()" 96 | local msgpost="\n\ 97 | If you feel this is a bug / issue, kindly report it here: 98 | ${SEALS_REPORT_ERROR_URL}\n 99 | Many thanks. 100 | " 101 | 102 | [ $# -ne 1 ] && { 103 | local msg="${msgpre}${errmsg}\n${msgpost}" 104 | } || { 105 | local msg="${msgpre}${errmsg}\n ${1}\n${msgpost}" 106 | } 107 | #cecho "Fatal Error! Details: ${errmsg} ${1}" 108 | 109 | local LN=$(echo "${MSG}" |wc -l) 110 | local calht=$(($LN*10)) 111 | 112 | local title=" FATAL ERROR!" 113 | yad --title="${title}" --image=dialog-warning --text="${msg}" \ 114 | --button="Close!${ICON_NO}:0" \ 115 | --wrap --text-align=center --button-layout=center --center \ 116 | --selectable-labels --no-escape --dialog-sep --sticky --on-top --skip-taskbar 2>/dev/null 117 | 118 | cli_handle_error "$@" 119 | exit 1 120 | } # end FatalError() 121 | 122 | # Prompt 123 | # Interactive: prompt the user to continue by pressing ENTER or 124 | # abort by pressing Ctrl-C 125 | # Parameter(s): 126 | # $1 : string to display (string) 127 | # $2 : string to display on signal trap [optional] 128 | Prompt() 129 | { 130 | local msg="*** User Abort detected! ***" 131 | 132 | trap 'wecho "${msg}" ; dumpstack ; color_reset ; exit 3' INT QUIT 133 | 134 | [ ${COLOR} -eq 1 ] && fg_magenta 135 | echo "Press ENTER to continue, or Ctrl-C to abort now..." 136 | read 137 | [ ${COLOR} -eq 1 ] && color_reset 138 | } # end Prompt() 139 | -------------------------------------------------------------------------------- /mm/phymap_iomem/phymap_iomem.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # phymap_iomem.sh 3 | # 4 | # Quick Description: 5 | # /proc/iomem describes the _physical_ address space, in effect, 6 | # it's a view of the physical memory map. 7 | # 8 | # Last Updated : 25july2017 9 | # Created : 25july2017 10 | # 11 | # Author: 12 | # Kaiwan N Billimoria 13 | # kaiwan -at- kaiwantech -dot- com 14 | # kaiwanTECH 15 | # 16 | # License: 17 | # MIT License. 18 | # 19 | name=$(basename $0) 20 | source ./common.sh || { 21 | echo "${name}: fatal: could not source common.sh , aborting..." 22 | exit 1 23 | } 24 | 25 | #[ $# -ne 1 ] && { 26 | # echo "Usage: ${name} " 27 | # exit 1 28 | #} 29 | 30 | export TMPF=/tmp/.$$ 31 | export PHYADDR_HEX=1 32 | export EMB=1 # simpler [no float point, etc] 33 | DEBUG=1 34 | 35 | ########### Functions follow ####################### 36 | 37 | #------------------------- d i s p ------------------------------------ 38 | # eg. disp ${numspc} ${pa_name} ${pa_start_dec} ${pa_end_dec} ${sz} 39 | # Params: 40 | # $1 : left indentation length 41 | # $2 : Region 42 | # $3 : start phy addr 43 | # $4 : end phy addr 44 | # $5 : size of region in bytes 45 | disp() 46 | { 47 | local sp=$(($1+1)) 48 | local fmtname=$((30-${sp})) 49 | local szKB=$(($5/1024)) 50 | local szMB=0 51 | local szGB=0 52 | 53 | [ ${PHYADDR_HEX} -eq 0 ] && { 54 | printf "%${sp}s%-${fmtname}s:%16d %16d [%9d" \ 55 | " " "${2}" "${3}" "${4}" ${szKB} 56 | } || { 57 | printf "%${sp}s%-${fmtname}s:%16lx %16lx [%9d" \ 58 | " " "${2}" "${3}" "${4}" ${szKB} 59 | } 60 | 61 | # Calculate sizes in MB and GB if required 62 | [ ${EMB} -eq 0 ] && { 63 | [ ${szKB} -ge 1024 ] && szMB=$(bc <<< "scale=2; ${szKB}/1024.0") 64 | # !EMB: if we try and use simple bash arithmetic comparison, we get a 65 | # "integer expression expected" err; hence, use bc: 66 | if (( $(echo "${szMB} > 1024" |bc -l) )); then 67 | szGB=$(bc <<< "scale=2; ${szMB}/1024.0") 68 | fi 69 | 70 | if (( $(echo "${szMB} > 0" |bc -l) )); then 71 | printf " %6.2f" ${szMB} 72 | fi 73 | if (( $(echo "${szGB} > 0" |bc -l) )); then 74 | printf " %4.2f" ${szGB} 75 | fi 76 | } || { # embedded sys: simpler 77 | [ ${szKB} -ge 1024 ] && szMB=$((${szKB}/1024)) 78 | [ ${szMB} -ge 1024 ] && szGB=$((${szMB}/1024)) 79 | [ ${szMB} -gt 0 ] && printf " %6d" ${szMB} 80 | [ ${szGB} -gt 0 ] && printf " %4d" ${szGB} 81 | } 82 | 83 | printf "]\n" 84 | } # end disp() 85 | 86 | #------------------- g e t _ r a n g e _ i n f o ---------------------- 87 | get_range_info() 88 | { 89 | # Get the range: start - end 90 | # -the first and last addresses! 91 | local par_start=$(head -n1 ${TMPF} |cut -d":" -f1) # |sed 's/ //') # par = phy addr range 92 | local start=$(echo "${par_start}" |cut -d"-" -f1) 93 | local par_end=$(tail -n1 ${TMPF} |cut -d":" -f1 |sed 's/ //') # par = phy addr range 94 | local end=$(echo "${par_end}" |cut -d"-" -f2) 95 | 96 | local start_dec=$(echo $((16#${start}))) 97 | local end_dec=$(echo $((16#${end}))) 98 | gTotalLen=$((end_dec-start_dec)) 99 | } # end get_range_info() 100 | 101 | #--- 102 | # We require a 2d array to hold: 103 | # col0 col1 104 | # row'n' [label],[size] 105 | # HOWEVER, bash only actually supports 1d array; we thus treat a simple 1d array 106 | # as a 2d array! 107 | # So we just populate a 1d array like this: 108 | # [val1] [val2] [val3] [val4] [val5][val6] [...] 109 | # but INTERPRET it as 2d like so: 110 | # ([val1],[val2]) ([val3],[val4]) ([val5],[val6]) [...] 111 | declare -a gArray 112 | gRow=0 113 | #--- 114 | 115 | showArray() 116 | { 117 | local i k 118 | echo "gRow = ${gRow}" 119 | for ((i=0; i<${gRow}; i+=2)) 120 | do 121 | printf "%s: " "${gArray[${i}]}" 122 | let k=i+1 123 | printf "%d\n" "${gArray[${k}]}" 124 | done 125 | } 126 | 127 | SCALE_FACTOR=50 128 | LIMIT_SCALE_SZ=10 129 | 130 | #---------------------- g r a p h i t --------------------------------- 131 | graphit() 132 | { 133 | local i k 134 | local label sz scaled_sz_fp scaled_sz_int 135 | local szKB=0 szMB=0 szGB=0 136 | local LIN="+------------------------------------+" 137 | local ELLIPSE_LIN="~ . . . . . . . . . . . . . . . . . ~" 138 | local oversized=1 139 | 140 | decho "len=${gTotalLen}" 141 | 142 | for ((i=0; i<${gRow}; i+=2)) 143 | do 144 | label=${gArray[${i}]} 145 | #printf "%s: " "${gArray[${i}]}" 146 | let k=i+1 147 | sz=${gArray[${k}]} 148 | #printf "%d\n" "${gArray[${k}]}" 149 | scaled_sz_fp=$(bc <<< "scale=9; (${sz}/${gTotalLen})*100*${SCALE_FACTOR}") 150 | 151 | #[ ${scaled_sz_fp} -lt 1 ] && scaled_sz_fp=1 152 | # Convert fp to int 153 | if (( $(echo "${scaled_sz_fp} < 1" |bc -l) )); then 154 | scaled_sz_int=1 155 | else 156 | scaled_sz_int=$(LC_ALL=C printf "%.0f" "${scaled_sz_fp}") 157 | fi 158 | 159 | szKB=$((${sz}/1024)) 160 | [ ${szKB} -ge 1024 ] && szMB=$((${szKB}/1024)) 161 | [ ${szMB} -ge 1024 ] && szGB=$((${szMB}/1024)) 162 | 163 | [ 0 -eq 1 ] && { 164 | printf "%s: %.6f: %d [%d KB" \ 165 | "${label}" "${scaled_sz_fp}" "${scaled_sz_int}" "${szKB}" 166 | [ ${szMB} -gt 0 ] && printf " %6d" ${szMB} 167 | [ ${szGB} -gt 0 ] && printf " %4d" ${szGB} 168 | printf "]\n" 169 | } 170 | 171 | #--- Drawing :-p ! 172 | fg_blue 173 | printf "%s\n" ${LIN} 174 | printf "|%-20s [%d KB] \n" ${label} ${szKB} 175 | # TODO - indentation of label 176 | # - pr addresses 177 | 178 | # draw the sides of the 'box' 179 | [ ${scaled_sz_int} -gt ${LIMIT_SCALE_SZ} ] && { 180 | scaled_sz_int=${LIMIT_SCALE_SZ} 181 | oversized=1 182 | } 183 | for ((x=0; x<${scaled_sz_int}; x++)) 184 | do 185 | printf "| |\n" 186 | if [ ${oversized} -eq 1 ] ; then 187 | [ ${x} -eq $(((LIMIT_SCALE_SZ-1)/2)) ] && printf "%s\n" "${ELLIPSE_LIN}" 188 | fi 189 | done 190 | 191 | #printf "%s\n" ${LIN} 192 | color_reset 193 | oversized=0 194 | done 195 | printf "%s\n" ${LIN} 196 | 197 | } # end graphit() 198 | 199 | #------------------ i n t e r p r e t _ i o m e m _ r e c ------------- 200 | # Interpret a 'line' from output of /proc/iomem ; 201 | # eg. looks like this 202 | # 00001000-00057fff : System RAM 203 | interpret_iomem_rec() 204 | { 205 | #echo "num=$# p=$@" 206 | local par=$(echo "${@}" |cut -d":" -f1) # par = phy addr range 207 | local pa_name=$(echo "${@}" |cut -d":" -f2) 208 | 209 | # pa_start: 210 | local pa_start=$(echo "${par}" |cut -d"-" -f1) 211 | # we need to count the indentation - the spaces on the left 212 | numspc=$(grep -o " " <<< ${pa_start} |wc -l) 213 | # ltrim: now get rid of the leading spaces 214 | local pa_start=$(echo "${pa_start}" |sed 's/^ *//') 215 | local pa_end=$(echo "${par}" |cut -d"-" -f2) 216 | 217 | local pa_start_dec=$(echo $((16#${pa_start}))) 218 | local pa_end_dec=$(echo $((16#${pa_end}))) 219 | local sz=$((pa_end_dec-pa_start_dec)) # in bytes 220 | 221 | # Populate the global array 222 | gArray[${gRow}]=${pa_name} 223 | let gRow=gRow+1 224 | gArray[${gRow}]=${sz} 225 | let gRow=gRow+1 226 | 227 | #disp ${numspc} ${pa_name} ${pa_start_dec} ${pa_end_dec} ${sz} 228 | } # end interpret_iomem_rec() 229 | 230 | HDR1=" /proc/iomem :: PHYSICAL ADDRESS SPACE" 231 | [ ${EMB} -eq 1 ] && HDR11=" [embedded ver]\n" || HDR11="\n" 232 | HDR2=" Region Phy Addr" 233 | [ ${PHYADDR_HEX} -eq 0 ] && HDR21=" [decimal]" || HDR21=" [hex]" 234 | HDR22=" Size\n" 235 | HDR3=" start - end : KB MB GB\n" 236 | gHDR="${HDR1}${HDR11}${HDR2}${HDR21}${HDR22}${HDR3}" 237 | 238 | 239 | arrtest() 240 | { 241 | declare -a arry 242 | local r=5 c=2 243 | 244 | for ((i=0; i/dev/null || { 273 | echo "${name}: bc package missing, pl install. Aborting..." 274 | exit 1 275 | } 276 | } 277 | 278 | sudo cat /proc/iomem > ${TMPF} 279 | get_range_info 280 | #exit 0 281 | 282 | export IFS=$'\n' 283 | local i=0 284 | printf "${gHDR}" 285 | 286 | local REC 287 | for REC in $(cat ${TMPF}) 288 | do 289 | #echo "REC: $REC" 290 | interpret_iomem_rec ${REC} 291 | let i=i+1 292 | #[ $i -ge 18 ] && break 293 | done 294 | 295 | #showArray 296 | graphit 297 | 298 | sudo rm -f ${TMPF} 299 | } # end start() 300 | 301 | ##### 'main' : execution starts here ##### 302 | 303 | start 304 | exit 0 305 | -------------------------------------------------------------------------------- /mm/slab_custom/slab_custom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * slab_custom.c 3 | * 4 | * Simple demo of creating a custom slab cache. 5 | * Notice how the kernel reuses an existing cache if your cache size is a 6 | * close-enough match! 7 | * Load this module & look up /proc/slabinfo .. 8 | * 9 | * (c) Kaiwan NB 10 | * License: MIT 11 | */ 12 | #define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include "../../convenient.h" 21 | 22 | #define DRVNAME "slab_custom" 23 | #define MYBUFSZ 350 //-- using size '350' seems to give us a new private slab cache 24 | 25 | static struct kmem_cache *my_cachep; 26 | 27 | struct MyStruct { 28 | u32 a, b, c; 29 | s8 *cptr; 30 | u16 valid; 31 | u8 intbuf[MYBUFSZ]; 32 | }; 33 | 34 | static void mycache_use(void) 35 | { 36 | void *object; 37 | 38 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39) 39 | pr_info("Cache name is %s\n", kmem_cache_name(my_cachep)); 40 | #else 41 | pr_info("[ker ver > 2.6.38 cache name deprecated...]\n"); 42 | #endif 43 | pr_info("Cache object size is %u\n", kmem_cache_size(my_cachep)); 44 | 45 | object = kmem_cache_alloc(my_cachep, GFP_KERNEL); 46 | 47 | memset(object, 0xae, sizeof(struct MyStruct)); 48 | print_hex_dump_bytes(" ", DUMP_PREFIX_ADDRESS, object, sizeof(struct MyStruct)); 49 | 50 | kmem_cache_free(my_cachep, object); 51 | } 52 | 53 | static void init_my_cache(void) 54 | { 55 | #if 0 56 | char *snum = "1002"; 57 | int n; 58 | 59 | // just for flawfinder etc demo :-p 60 | n = kstrtoint(snum, 0, &n); 61 | pr_info("n = %d, slen=%ld\n", n, strlen(snum)); 62 | /* 63 | slab_custom.c:60: [1] (buffer) strlen: 64 | Does not handle strings that are not \0-terminated; if given one it may 65 | perform an over-read (it could cause a crash if unprotected) (CWE-126). 66 | */ 67 | #endif 68 | 69 | pr_debug("sizeof(MyStruct) = %lu\n", sizeof(struct MyStruct)); 70 | /* 71 | * struct kmem_cache * 72 | * kmem_cache_create( const char *name, size_t size, size_t align, 73 | * unsigned long flags, 74 | * void (*ctor)(void*)); 75 | */ 76 | my_cachep = kmem_cache_create(DRVNAME, /* Name of slab cache */ 77 | sizeof(struct MyStruct), 0, /* Alignment */ 78 | SLAB_HWCACHE_ALIGN, /* Flags */ 79 | NULL); /* Constructor */ 80 | } 81 | 82 | static int slabsee_init(void) 83 | { 84 | init_my_cache(); 85 | mycache_use(); 86 | pr_info("initialized\n"); 87 | 88 | return 0; /* success */ 89 | } 90 | 91 | static void slabsee_exit(void) 92 | { 93 | kmem_cache_destroy(my_cachep); 94 | pr_info("removed\n"); 95 | } 96 | 97 | module_init(slabsee_init); 98 | module_exit(slabsee_exit); 99 | 100 | MODULE_LICENSE("MIT"); 101 | -------------------------------------------------------------------------------- /mm/vm_show_kernel_seg/mk4arm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DRV=vm_img 3 | echo "make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-" 4 | make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- 5 | 6 | #echo 7 | #echo "------------------------------------------------------" 8 | #echo "Insert SD card, ensure it's mounted & press [Enter]..." 9 | #read 10 | #cp -f $DRV.ko /media/BB_RFS/ ; sync ; umount /media/BB* 11 | #echo "Done." 12 | 13 | -------------------------------------------------------------------------------- /mm/vm_usermode/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | ALL := malloc_brk_test segv_pgfault vm_user 3 | CC := ${CROSS_COMPILE}gcc 4 | 5 | all: ${ALL} 6 | malloc_brk_test: malloc_brk_test.c 7 | ${CC} malloc_brk_test.c -g -O0 -o malloc_brk_test -Wall 8 | hello: hello.c 9 | ${CC} hello.c -o hello -Wall 10 | segv_pgfault: segv_pgfault.c 11 | ${CC} segv_pgfault.c -o segv_pgfault -Wall 12 | vm_user: vm_user.c 13 | ${CC} vm_user.c -o vm_user -Wall 14 | 15 | clean: 16 | rm -f *.o ${ALL} 17 | 18 | -------------------------------------------------------------------------------- /mm/vm_usermode/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #------------------------------------------------------------------ 3 | # common.sh 4 | # 5 | # Common convenience routines 6 | # 7 | # (c) Kaiwan N Billimoria 8 | # kaiwan -at- designergraphix -dot- com 9 | # GPL / LGPL 10 | # Last Updt: 29Dec2013 11 | #------------------------------------------------------------------ 12 | 13 | export TOPDIR=$(pwd) 14 | ON=1 15 | OFF=0 16 | 17 | ### UPDATE for your box 18 | source ./err_common.sh || { 19 | echo "$name: could not source err_common.sh, aborting..." 20 | exit 1 21 | } 22 | 23 | 24 | # DesktopNotify 25 | # Ubuntu desktop notify-send wrapper func 26 | # Parameter(s) 27 | # $1 : String to display in desktop notification message [required] 28 | function DesktopNotify() 29 | { 30 | # Ubuntu : notify-send ! 31 | [ $# -ne 1 ] && MSG="" || MSG="$1" 32 | notify-send --urgency=low "${MSG}" 33 | } 34 | 35 | 36 | # genLogFilename 37 | # Generates a logfile name that includes the date/timestamp 38 | # Format: 39 | # ddMmmYYYY[_HHMMSS] 40 | # Parameter(s) 41 | # #$1 : String to prefix to log filename, null okay as well [required] 42 | # $1 : Include time component or not [required] 43 | # $1 = 0 : Don't include the time component (only date) in the log filename 44 | # $1 = 1 : include the time component in the log filename 45 | genLogFilename() 46 | { 47 | [ $1 -eq 0 ] && log_filename=$(date +%d%b%Y) 48 | [ $1 -eq 1 ] && log_filename=$(date +%d%b%Y_%H%M%S) 49 | echo ${log_filename} 50 | } 51 | 52 | # Debug echo :-) 53 | decho() 54 | { 55 | Prompt "$@" 56 | } 57 | 58 | verbose=1 59 | # Echo 60 | # Echo string (with timestamp prefixed) to stdout and to Log file 61 | # if so specified. 62 | # Parameter(s): 63 | # $1 : String to display to stdout [required] 64 | # $2 : Log pathname to also append the $1 string to [optional] 65 | Echo() 66 | { 67 | #echo "# p = $#" 68 | [ $# -eq 0 ] && return 1 69 | [ ${verbose} -eq 1 ] && { 70 | echo -n "$(date) : " 71 | echo "$1" 72 | [ $# -ge 2 ] && { 73 | [ -f $2 -a -w $2 ] && { 74 | echo -n "$(date) : " >> $2 75 | echo "$1" >> $2 76 | } 77 | } 78 | } 79 | } 80 | 81 | 82 | # ShowTitle 83 | # Display a string in "title" form 84 | # Parameter(s): 85 | # $1 : String to display [required] 86 | # Returns: 0 on success, 1 on failure 87 | ShowTitle() 88 | { 89 | [ $# -ne 1 ] && return 1 90 | SEP='-------------------------------------------------------------------------------' 91 | echo $SEP 92 | echo $1 93 | echo $SEP 94 | } 95 | 96 | # check_root_AIA 97 | # Check whether we are running as root user; if not, exit with failure! 98 | # Parameter(s): 99 | # None. 100 | # "AIA" = Abort If Absent :-) 101 | check_root_AIA() 102 | { 103 | if [ `id -u` -ne 0 ]; then 104 | Echo "Error: need to run as root! Aborting..." 105 | exit 1 106 | fi 107 | } 108 | 109 | # check_file_AIA 110 | # Check whether the file, passed as a parameter, exists; if not, exit with failure! 111 | # Parameter(s): 112 | # $1 : Pathname of file to check for existence. [required] 113 | # "AIA" = Abort If Absent :-) 114 | # Returns: 0 on success, 1 on failure 115 | check_file_AIA() 116 | { 117 | [ $# -ne 1 ] && return 1 118 | [ ! -f $1 ] && { 119 | Echo "Error: file \"$1\" does not exist. Aborting..." 120 | exit 1 121 | } 122 | } 123 | 124 | # check_folder_AIA 125 | # Check whether the directory, passed as a parameter, exists; if not, exit with failure! 126 | # Parameter(s): 127 | # $1 : Pathname of folder to check for existence. [required] 128 | # "AIA" = Abort If Absent :-) 129 | # Returns: 0 on success, 1 on failure 130 | check_folder_AIA() 131 | { 132 | [ $# -ne 1 ] && return 1 133 | [ ! -d $1 ] && { 134 | Echo "Error: folder \"$1\" does not exist. Aborting..." 135 | exit 1 136 | } 137 | } 138 | 139 | # check_folder_createIA 140 | # Check whether the directory, passed as a parameter, exists; if not, create it! 141 | # Parameter(s): 142 | # $1 : Pathname of folder to check for existence. [required] 143 | # "IA" = If Absent :-) 144 | # Returns: 0 on success, 1 on failure 145 | check_folder_createIA() 146 | { 147 | [ $# -ne 1 ] && return 1 148 | [ ! -d $1 ] && { 149 | Echo "Folder \"$1\" does not exist. Creating it..." 150 | mkdir -p $1 && return 0 || return 1 151 | } 152 | } 153 | 154 | 155 | # GetIP 156 | # Extract IP address from ifconfig output 157 | # Parameter(s): 158 | # $1 : name of network interface (string) 159 | # Returns: IPaddr on success, non-zero on failure 160 | GetIP() 161 | { 162 | [ $# -ne 1 ] && return 1 163 | ifconfig $1 >/dev/null 2>&1 || return 2 164 | ifconfig $1 |grep 'inet addr'|awk '{print $2}' |cut -f2 -d':' 165 | } 166 | 167 | # get_yn_reply 168 | # User's reply should be Y or N. 169 | # Returns: 170 | # 0 => user has answered 'Y' 171 | # 1 => user has answered 'N' 172 | get_yn_reply() 173 | { 174 | echo -n "Type Y or N please (followed by ENTER) : " 175 | str="${@}" 176 | while true 177 | do 178 | echo ${str} 179 | read reply 180 | 181 | case "$reply" in 182 | y | yes | Y | YES ) return 0 183 | ;; 184 | n* | N* ) return 1 185 | ;; 186 | *) echo "What? Pl type Y / N" 187 | esac 188 | done 189 | } 190 | 191 | # MountPartition 192 | # Mounts the partition supplied as $1 193 | # Parameters: 194 | # $1 : device node of partition to mount 195 | # $2 : mount point 196 | # Returns: 197 | # 0 => mount successful 198 | # 1 => mount failed 199 | MountPartition() 200 | { 201 | [ $# -ne 2 ] && { 202 | echo "MountPartition: parameter(s) missing!" 203 | return 1 204 | } 205 | 206 | DEVNODE=$1 207 | [ ! -b ${DEVNODE} ] && { 208 | echo "MountPartition: device node $1 does not exist?" 209 | return 1 210 | } 211 | 212 | MNTPT=$2 213 | [ ! -d ${MNTPT} ] && { 214 | echo "MountPartition: folder $2 does not exist?" 215 | return 1 216 | } 217 | 218 | mount |grep ${DEVNODE} >/dev/null || { 219 | #echo "The partition is not mounted, attempting to mount it now..." 220 | mount ${DEVNODE} -t auto ${MNTPT} || { 221 | echo "Could not mount the '$2' partition!" 222 | return 1 223 | } 224 | } 225 | return 0 226 | } 227 | 228 | 229 | #------------------- Colors!! Yay :-) ----------------------------------------- 230 | # Ref: http://tldp.org/LDP/abs/html/colorizing.html 231 | black='\E[30;47m' 232 | red='\E[31;47m' 233 | green='\E[32;47m' 234 | yellow='\E[33;47m' 235 | blue='\E[34;47m' 236 | magenta='\E[35;47m' 237 | cyan='\E[36;47m' 238 | white='\E[37;47m' 239 | 240 | # Reset text attributes to normal without clearing screen. 241 | Reset() 242 | { 243 | tput sgr0 244 | } 245 | 246 | # !!! 247 | # Turn this ON for COLOR !!! 248 | # !!! 249 | COLOR=${OFF} 250 | #COLOR=${ON} 251 | 252 | # Color-echo. 253 | # Argument $1 = message 254 | # Argument $2 = color 255 | # Usage eg.: 256 | # cecho "This message is in blue!" $blue 257 | cecho () 258 | { 259 | local default_msg="No message passed." 260 | # Doesn't really need to be a local variable. 261 | [ ${COLOR} -eq 0 ] && { 262 | echo $1 263 | return 264 | } 265 | #echo "cecho: nump = $# : $@" 266 | 267 | message=${1:-$default_msg} # Defaults to default message. 268 | color=${2:-$black} # Defaults to black, if not specified. 269 | 270 | echo -e "$color" 271 | echo "$message" 272 | Reset # Reset to normal. 273 | 274 | return 275 | } 276 | #---------------------------------------------------------------------- 277 | 278 | 279 | ## is_kernel_thread 280 | # Param: PID 281 | # Returns: 282 | # 1 if $1 is a kernel thread, 0 if not, 127 on failure. 283 | is_kernel_thread() 284 | { 285 | [ $# -ne 1 ] && { 286 | echo "is_kernel_thread: parameter missing!" 1>&2 287 | return 127 288 | } 289 | 290 | prcs_name=$(ps aux |awk -v pid=$1 '$2 == pid {print $11}') 291 | #echo "prcs_name = ${prcs_name}" 292 | [ -z ${prcs_name} ] && { 293 | echo "is_kernel_thread: could not obtain process name!" 1>&2 294 | return 127 295 | } 296 | 297 | firstchar=$(echo "${prcs_name:0:1}") 298 | #echo "firstchar = ${firstchar}" 299 | len=${#prcs_name} 300 | let len=len-1 301 | lastchar=$(echo "${prcs_name:${len}:1}") 302 | #echo "lastchar = ${lastchar}" 303 | [ ${firstchar} = "[" -a ${lastchar} = "]" ] && return 1 || return 0 304 | } 305 | 306 | -------------------------------------------------------------------------------- /mm/vm_usermode/err_common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #------------------------------------------------------------------ 3 | # err_common.sh 4 | # 5 | # Common error handling routines. 6 | # 7 | # (c) Kaiwan N Billimoria 8 | # kaiwan -at- designergraphix -dot- com 9 | # GPL / LGPL 10 | # Last Updt: 31Mar2014 11 | #------------------------------------------------------------------ 12 | 13 | GUI_MODE=1 14 | export TOPDIR=$(pwd) 15 | ON=1 16 | OFF=0 17 | 18 | # "Returns" (actually echoes) 19 | # 1 => zenity present 20 | # 0 => zenity absent 21 | verify_zenity() 22 | { 23 | which zenity >/dev/null 2>&1 && echo -n 1 || echo -n 0 24 | } 25 | 26 | # QP 27 | # QuickPrint ;-) 28 | # Print timestamp, script name, line#. Useful for debugging. 29 | QP() 30 | { 31 | _ERR_HDR_FMT="%.23s %s[%s]: " 32 | _ERR_MSG_FMT="${_ERR_HDR_FMT}%s\n" 33 | printf "$_ERR_MSG_FMT" $(date +%F.%T.%N) ${BASH_SOURCE[1]##*/} ${BASH_LINENO[0]} 1>&2 #"${@}" 34 | unset _ERR_HDR_FMT 35 | unset _ERR_MSG_FMT 36 | } 37 | 38 | 39 | cli_handle_error() 40 | { 41 | echo -n "FatalError :: " 1>&2 42 | QP 43 | [ $# -lt 1 ] && exit -1 44 | echo "${@}" 1>&2 45 | exit -1 46 | } 47 | 48 | # FatalError 49 | # Display the error message string and exit -1. 50 | # Parameter(s): 51 | # $1 : Error string to display [required] 52 | # Returns: -1 (255) 53 | FatalError() 54 | { 55 | [ ${GUI_MODE} -eq 0 ] && { 56 | cli_handle_error $@ 57 | } || { # want GUI mode 58 | #n=$(verify_zenity) 59 | #echo "n=$n" 60 | #return 61 | [ $(verify_zenity) -eq 0 ] && { 62 | echo "FatalError :: !WARNING! zenity not installed?? " 63 | # fallback to non-gui err handling 64 | cli_handle_error $@ 65 | } 66 | } 67 | # gui err handling, zenity there; whew 68 | zenity --error --title="${name}: Error" --text="Fatal Error :: $@" 69 | cli_handle_error $@ 70 | exit -1 71 | } 72 | 73 | # Prompt 74 | # Interactive: prompt the user to continue by pressing ENTER or 75 | # abort by pressing Ctrl-C 76 | # Parameter(s): 77 | # $1 : string to display (string) 78 | Prompt() 79 | { 80 | [ $# -lt 1 ] && { 81 | echo "$0: Prompt function requires a string parameter!" 82 | return 1 83 | } 84 | echo "${@}" 85 | echo " Press ENTER to continue, Ctrl-C to abort now..." 86 | read 87 | } 88 | 89 | 90 | -------------------------------------------------------------------------------- /mm/vm_usermode/gen_malloc_pgfault/gen_malloc_pgfault.c: -------------------------------------------------------------------------------- 1 | /* 2 | * gen_malloc_pgfault.c 3 | * 4 | * When a process allocates a page with malloc(), it's only allocated 5 | * *virtually*. When it touches the memory (rd/wr), the MMU triggers a 6 | * page fault; the OS's fault handler is sophisticated: it figures out 7 | * that this is a legal access; thus it allocates physical memory (via 8 | * the buddy system allocator) and fixes up the paging tables (for current, 9 | * such that the vp -> pf ! 10 | * 11 | * This simple app emulates this malloc & touching of memory. 12 | * Try tracing the kernel - the page fault handler - via tracing tools like 13 | * ftrace. 14 | * 15 | * Author(s) : 16 | * Kaiwan N Billimoria 17 | * 18 | * 19 | * License(s): [L]GPL 20 | */ 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | /*---------------- Macros -------------------------------------------*/ 27 | 28 | 29 | /*---------------- Typedef's, constants, etc ------------------------*/ 30 | 31 | 32 | /*---------------- Functions ----------------------------------------*/ 33 | 34 | 35 | int main (int argc, char **argv) 36 | { 37 | char *p=0; 38 | 39 | p = malloc(getpagesize()); // typically 4k 40 | if (!p) { 41 | fprintf(stderr, "%s: out of memory!", argv[0]); 42 | exit(1); 43 | } 44 | *(p+200)='a'; 45 | 46 | free(p); 47 | exit (0); 48 | } 49 | -------------------------------------------------------------------------------- /mm/vm_usermode/gen_malloc_pgfault/try_gen_malloc_pgfault.sh: -------------------------------------------------------------------------------- 1 | ltrace -S ./gen_malloc_pgfault 2 | # -S shows system calls as well 3 | -------------------------------------------------------------------------------- /mm/vm_usermode/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | main() 3 | { 4 | printf("Hello, world\n"); 5 | pause(); 6 | } 7 | -------------------------------------------------------------------------------- /mm/vm_usermode/malloc_brk_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * malloc_brk_test.c 3 | 4 | Rationale: 5 | ---------- 6 | The first time a process does an malloc(8) : 7 | 8 | - the heap memory is not physically allocated yet, only virtually 9 | (remember, the kernel is a lazy guy!). 10 | - Thus, when attempting to map the virtual to physical address, the 11 | MMU faults; the kernel “realizes” this is a good fault and allocates 12 | a page farme from the slab cache (possibly via the buddy allocator). 13 | This is mapped into the faulting process’s heap.. 14 | - Another request is made, say: 15 | malloc(32); 16 | - Now, since the glibc memory manager (what we call malloc) now knows 17 | that a full page is available in the heap and only 8 bytes are actually 18 | used up, this request will not cause a brk() syscall to the kernel. This 19 | can be verified by checking the current break (using sbrk(0)). 20 | 21 | - Also, seeking to within a page of the 1st request will (probably) not cause 22 | a segfault! 23 | 24 | See below a program that helps us study how the system allocates memory 25 | dynamically to user-space applications via the usual malloc / calloc API. 26 | 27 | (c) Kaiwan NB. 28 | GPL v2. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | //#define USE_CALLOC 39 | #undef USE_CALLOC 40 | 41 | #define TRIES 5 42 | void *heap_ptr[TRIES]; 43 | void *init_brk; 44 | 45 | typedef unsigned int u32; 46 | 47 | static void alloctest(int index, size_t num) 48 | { 49 | void *p; 50 | 51 | #ifndef USE_CALLOC 52 | p = malloc(num); 53 | #else 54 | p = calloc(num, sizeof(char)); 55 | #endif 56 | if (!p) { 57 | printf("out of memory!\n"); 58 | exit(1); 59 | } 60 | 61 | heap_ptr[index] = p; // save ptr in order to free later.. 62 | #ifndef USE_CALLOC 63 | printf("\n%d: malloc", index); 64 | #else 65 | printf("\n%d: calloc", index); 66 | #endif 67 | printf("(%6u) successful. Heap pointer: %8p\n", num, p); 68 | printf("Current break: %8p [delta: %d]\n", sbrk(0), 69 | (sbrk(0) - init_brk)); 70 | 71 | malloc_stats(); 72 | } 73 | 74 | int main(int argc, char **argv) 75 | { 76 | int i; 77 | volatile char *q; 78 | 79 | init_brk = sbrk(0); 80 | printf("Current break: %8p\n", init_brk); 81 | alloctest(0, 8); 82 | 83 | //exit(0); 84 | 85 | q = heap_ptr[0]; 86 | *(q + 3000) = 'a'; /* "should" segfault but does (probably) not bcoz a *page* is alloced 87 | by the previous alloc, not just 8 bytes! See value of prg break 88 | compared to this pointer. 89 | */ 90 | printf 91 | ("\n### q=0x%08x. (q+3000) is the mem loc 0x%08x. Mem here is: 0x%08x\n", 92 | (unsigned int)q, (unsigned int)(q + 3000), 93 | (unsigned int)*(q + 3000)); 94 | /* 95 | Indeed valgrind points out the errors: 96 | 97 | $ valgrind --leak-check=full ./malloc_brk_test 98 | ... 99 | 0: malloc( 8) successful. Heap pointer: 0x41f7028 100 | Current break: 0x804b000 [delta: 0] 101 | ==31220== Invalid write of size 1 102 | ==31220== at 0x804863E: main (malloc_brk_test.c:80) 103 | ==31220== Address 0x41f7be0 is not stack'd, malloc'd or (recently) free'd 104 | ==31220== 105 | ==31220== Invalid read of size 1 106 | ==31220== at 0x804864A: main (malloc_brk_test.c:85) 107 | ==31220== Address 0x41f7be0 is not stack'd, malloc'd or (recently) free'd 108 | ==31220== 109 | 110 | ### q=0x041f7028. (q+3000) is the mem loc 0x041f7be0. Mem here is: 0x00000061 111 | ... 112 | */ 113 | 114 | #if 0 115 | *(q + 3000 + (sbrk(0) - init_brk)) = 'b'; /* *make* it segfault here by poking into a region 116 | just beyond what the kernel allocated */ 117 | #endif 118 | 119 | //pause(); 120 | //exit(0); 121 | 122 | alloctest(1, (getpagesize() - 8 - 5)); 123 | alloctest(2, 3); 124 | //exit(0); 125 | alloctest(3, (sbrk(0) - init_brk + 1000)); 126 | /* This (above) allocation request is a large one: ~132Kb. The 'mmap threshold' 127 | is (default) 128Kb; thus, this causes an mmap() to the process virtual address 128 | space, mapping in the virtually allocated region (which will later be mapped to 129 | physical page frames via the MMU page-faulting on application access to these memory regions! 130 | */ 131 | alloctest(4, 200000); 132 | 133 | for (i = 0; i < TRIES; i++) 134 | free(heap_ptr[i]); 135 | exit(0); 136 | } 137 | 138 | /* vi: ts=4 */ 139 | -------------------------------------------------------------------------------- /mm/vm_usermode/mem_sequence.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mem_sequence.c / ver 0x01 | (C)opyleft 2008 by oozie | http://blog.ooz.ie/ 3 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 | * Lists memory areas and their location in descending order. 5 | * 6 | * This program declares example variables in different memory locations, gets 7 | * their addresses, sorts them and prints a list in descending order. 8 | * 9 | * The program is considered free software; you can redistribute and/or modify 10 | * it under the terms of the GNU General Public License version 3 or any later 11 | * version, as published by the Free Software Foundation; If you do modify it, 12 | * please leave the information about the author unchanged. The full text of 13 | * latest GPL licence is available at http://www.gnu.org/licences/gpl.txt 14 | * 15 | * Src URL: 16 | * http://oozie.fm.interia.pl/src/mem_sequence.c 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #define MEM_TYPES 5 23 | 24 | #define STR_STACK "stack" 25 | #define STR_HEAP "heap" 26 | #define STR_BSS "bss" 27 | #define STR_CONST "const's" 28 | #define STR_CODE "code" 29 | 30 | const char const_example[] = "constant string"; 31 | 32 | /* 33 | * defining a 5-element memory structure consisting of a string describing 34 | * memory type {stack, heap, bss, consts, code} and a pointer to an example 35 | * definition. Each element of this array is 12 bytes large (char[8]+*int), 36 | * so the entire table is 60 bytes in size. 37 | */ 38 | 39 | struct memtype_ptr { 40 | int *ptr; 41 | char *str; 42 | }; 43 | 44 | struct memtype_ptr type_pointer[MEM_TYPES]; 45 | 46 | /* defining a global variable with predefined value (BSS) */ 47 | char bss_example[] = "A global variable"; 48 | 49 | /* mem_xchg() will be used later in print_sorted() function */ 50 | void mem_xchg(struct memtype_ptr *a, struct memtype_ptr *b) 51 | { 52 | struct memtype_ptr tmpmemptr; 53 | 54 | tmpmemptr.str = a->str; 55 | tmpmemptr.ptr = a->ptr; 56 | 57 | a->str = b->str; 58 | a->ptr = b->ptr; 59 | 60 | b->str = tmpmemptr.str; 61 | b->ptr = tmpmemptr.ptr; 62 | 63 | } 64 | 65 | /* void function print_sorted() contains a local variable "stack_example" */ 66 | void print_sorted(int *heap_example, int stack_example) 67 | { 68 | 69 | int i, j; 70 | 71 | /* 72 | * assigning all example variables to the memory type pointer table 73 | * in no particular order 74 | */ 75 | 76 | type_pointer[0].str = STR_HEAP; 77 | type_pointer[0].ptr = heap_example; 78 | 79 | type_pointer[1].str = STR_BSS; 80 | type_pointer[1].ptr = (int *)&bss_example; 81 | 82 | /* 83 | * the address of stack_example, which is a local variable 84 | * points us to the top of the stack 85 | */ 86 | 87 | type_pointer[2].str = STR_STACK; 88 | type_pointer[2].ptr = &stack_example; 89 | 90 | /* 91 | * the value of stack_example equals to the value of code_example 92 | */ 93 | 94 | type_pointer[3].str = STR_CODE; 95 | type_pointer[3].ptr = (int *)stack_example; 96 | 97 | type_pointer[4].str = STR_CONST; 98 | type_pointer[4].ptr = (int *)&const_example; 99 | 100 | /* buble-sorting the table in descending order */ 101 | j = MEM_TYPES; 102 | while (j--) 103 | for (i = 0; i < j; i++) 104 | if (type_pointer[i].ptr < type_pointer[i + 1].ptr) 105 | mem_xchg(&type_pointer[i], 106 | &type_pointer[i + 1]); 107 | 108 | /* printing the table */ 109 | for (i = 0; i < MEM_TYPES; i++) 110 | printf("%d.(0x%.8x) %s\n", i + 1, 111 | (int)type_pointer[i].ptr, type_pointer[i].str); 112 | 113 | return; 114 | } 115 | 116 | /* main */ 117 | int main(void) 118 | { 119 | 120 | int *dyn_allocated, code_example; 121 | 122 | /* getting the address of main() in memory */ 123 | code_example = (int)&main; 124 | 125 | /* allocating dynamic memory on the heap */ 126 | dyn_allocated = (int *)malloc(sizeof(int)); 127 | 128 | /* printing memory addresses in descending order */ 129 | print_sorted(dyn_allocated, code_example); 130 | getchar(); 131 | 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/fileio_mmap/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | ALL := reg_fileio mmap_fileio 3 | 4 | all: ${ALL} 5 | CB_FILES := *.[ch] 6 | 7 | reg_fileio: reg_fileio.c 8 | gcc reg_fileio.c -o reg_fileio -Wall 9 | mmap_fileio: mmap_fileio.c 10 | gcc mmap_fileio.c -o mmap_fileio -Wall #-DDEBUG 11 | 12 | # CB - C Beautifier ! uses indent- "beautifies" C code into the "Linux kernel style" 13 | # Note- original source file(s) is overwritten 14 | cb: ${CB_FILES} 15 | mkdir bkp 2> /dev/null; cp -f ${CB_FILES} bkp/ 16 | indent -nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0 -d0 -di1 -nfc1 -i8 -ip0 -l80 -lp -npcs -nprs -npsl -sai -saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts8 -il1 ${CB_FILES} 17 | clean: 18 | rm -f ${ALL} 19 | 20 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/fileio_mmap/Readme.txt: -------------------------------------------------------------------------------- 1 | 2 | $ ./tst_fileio.sh 30 3 | 7680+0 records in 4 | 7680+0 records out 5 | 31457280 bytes (31 MB) copied, 2.88546 s, 10.9 MB/s 6 | Regular file io test: 7 | 8 | real 0m0.052s 9 | user 0m0.000s 10 | sys 0m0.052s 11 | ./tst_fileio.sh: line 24: unalias: ls: not found 12 | -rw-rw-r-- 1 kaiwan kaiwan 31457280 Oct 7 17:03 /home/kaiwan/destfile 13 | -rw-rw-r-- 1 kaiwan kaiwan 31457280 Oct 7 17:03 /home/kaiwan/srcfile 14 | 7680+0 records in 15 | 7680+0 records out 16 | 31457280 bytes (31 MB) copied, 2.88693 s, 10.9 MB/s 17 | mmap-ed file io test: 18 | 19 | real 0m0.049s 20 | user 0m0.004s 21 | sys 0m0.044s 22 | ./tst_fileio.sh: line 42: unalias: ls: not found 23 | -rw-r--r-- 1 kaiwan kaiwan 31457280 Oct 7 17:03 /home/kaiwan/destfile 24 | -rw-rw-r-- 1 kaiwan kaiwan 31457280 Oct 7 17:03 /home/kaiwan/srcfile 25 | $ 26 | 27 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/fileio_mmap/mmap_fileio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mmap_fileio.c 3 | * 4 | * Strategy: mmap() both the src & dest files; 5 | * then (trivially) memcpy contents from src -> dest! 6 | * 7 | * History: 8 | * 9 | * Author(s) : Kaiwan Billimoria 10 | * License(s): [L]GPL v2 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "restart_lib.h" 22 | #include "../../../../convenient.h" 23 | 24 | /*---------------- Macros -------------------------------------------*/ 25 | 26 | /*---------------- Typedef's, constants, etc ------------------------*/ 27 | 28 | /*---------------- Functions ----------------------------------------*/ 29 | 30 | int main(int argc, char **argv) 31 | { 32 | int fd_from, fd_to; //, pgsz = getpagesize(); 33 | off_t len; 34 | struct stat sstat; 35 | void *data_src, *origptr, *data_dest; 36 | 37 | if (argc != 3) { 38 | fprintf(stderr, "Usage: %s source-file dest-file\n", argv[0]); 39 | exit(1); 40 | } 41 | 42 | fd_from = r_open2(argv[1], O_RDONLY); 43 | if (-1 == fd_from) { 44 | perror("open: src file"); 45 | exit(1); 46 | } 47 | 48 | fd_to = r_open3(argv[2], O_RDWR | O_CREAT, 49 | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 50 | if (-1 == fd_to) { 51 | perror("open: dest file"); 52 | exit(1); 53 | } 54 | 55 | // Query src file size 56 | if (stat(argv[1], &sstat) == -1) { 57 | perror("stat"); 58 | exit(1); 59 | } 60 | len = sstat.st_size; 61 | if (len == 0) { 62 | fprintf(stderr, 63 | "%s: source-file %s size is zero bytes, aborting...\n", 64 | argv[0], argv[1]); 65 | exit(1); 66 | } 67 | 68 | // Set the dest file to be as large as the source file.. 69 | lseek (fd_to, len-1, SEEK_SET); 70 | write (fd_to, "", 1); 71 | 72 | /* 73 | void *mmap(void *addr, size_t length, int prot, int flags, 74 | int fd, off_t offset); 75 | */ 76 | origptr = data_src = mmap(0, len, PROT_READ, MAP_PRIVATE, fd_from, 0); 77 | if (data_src == (void *)-1) { 78 | perror("mmap: to src file"); 79 | exit(1); 80 | } 81 | if (close(fd_from) == -1) 82 | perror ("close failed"); 83 | MSG("len=%ld data_src = %p\n", len, data_src); 84 | 85 | // Set up a shared file mapping as we want in-memory mods to propogate to the underlying file. 86 | data_dest = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd_to, 0); 87 | if (data_dest == (void *)-1) { 88 | perror("mmap: to dest file"); 89 | exit(1); 90 | } 91 | if (close(fd_to) == -1) 92 | perror ("close failed"); 93 | 94 | memcpy (data_dest, data_src, len); 95 | pause(); 96 | 97 | if (munmap(origptr, len) == -1) { 98 | perror("munmap"); 99 | exit(1); 100 | } 101 | if (close(fd_from) == -1) 102 | perror ("close/3 failed"); 103 | 104 | munmap(data_dest, len); 105 | if (close(fd_to) == -1) 106 | perror ("close/4 failed"); 107 | 108 | exit(0); 109 | } 110 | 111 | /* vi: ts=4 */ 112 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/fileio_mmap/reg_fileio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * reg_fileio.c 3 | * 4 | * History: 5 | * 6 | * Author(s) : 7 | * License(s): 8 | * 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "restart_lib.h" 18 | 19 | /*---------------- Macros -------------------------------------------*/ 20 | 21 | /*---------------- Typedef's, constants, etc ------------------------*/ 22 | 23 | /*---------------- Functions ----------------------------------------*/ 24 | 25 | int main(int argc, char **argv) 26 | { 27 | int fd_from, fd_to, n; 28 | 29 | if (argc != 3) { 30 | fprintf(stderr, "Usage: %s source-file dest-file\n", argv[0]); 31 | exit(1); 32 | } 33 | 34 | fd_from = r_open2(argv[1], O_RDONLY); 35 | if (-1 == fd_from) { 36 | perror("open: from file"); 37 | exit(1); 38 | } 39 | 40 | fd_to = 41 | r_open3(argv[2], O_WRONLY | O_CREAT, 42 | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 43 | if (-1 == fd_to) { 44 | perror("open: to file"); 45 | exit(1); 46 | } 47 | 48 | n = copyfile(fd_from, fd_to); 49 | printf("n = %d\n", n); 50 | 51 | close(fd_from); 52 | close(fd_to); 53 | exit(0); 54 | } 55 | 56 | /* vi: ts=4 */ 57 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/fileio_mmap/restart_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 'Restart' library. 3 | * 4 | * All functions below handle signals interrupting system calls, etc. 5 | * 6 | * Sourced directly from: 7 | * "UNIX Systems Programming", Robbins & Robbins. 8 | * All rights rest with the original authors. 9 | * 10 | * Very minor mods to have it work on 2.6 Linux -kaiwan. 11 | */ 12 | 13 | #ifndef __RESTART_LIB__ 14 | #define __RESTART_LIB__ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | //#include "restart.h" 24 | #define BLKSIZE PIPE_BUF 25 | #define MILLION 1000000L 26 | #define D_MILLION 1000000.0 27 | 28 | int readwrite(int fromfd, int tofd); 29 | int waitfdtimed(int fd, struct timeval end); 30 | 31 | /* Private functions */ 32 | 33 | static int gettimeout(struct timeval end, struct timeval *timeoutp) 34 | { 35 | gettimeofday(timeoutp, NULL); 36 | timeoutp->tv_sec = end.tv_sec - timeoutp->tv_sec; 37 | timeoutp->tv_usec = end.tv_usec - timeoutp->tv_usec; 38 | if (timeoutp->tv_usec >= MILLION) { 39 | timeoutp->tv_sec++; 40 | timeoutp->tv_usec -= MILLION; 41 | } 42 | if (timeoutp->tv_usec < 0) { 43 | timeoutp->tv_sec--; 44 | timeoutp->tv_usec += MILLION; 45 | } 46 | if ((timeoutp->tv_sec < 0) || 47 | ((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) { 48 | errno = ETIME; 49 | return -1; 50 | } 51 | return 0; 52 | } 53 | 54 | /* Restart versions of traditional functions */ 55 | 56 | int r_close(int fildes) 57 | { 58 | int retval; 59 | while (retval = close(fildes), retval == -1 && errno == EINTR) ; 60 | return retval; 61 | } 62 | 63 | int r_dup2(int fildes, int fildes2) 64 | { 65 | int retval; 66 | while (retval = dup2(fildes, fildes2), retval == -1 && errno == EINTR) ; 67 | return retval; 68 | } 69 | 70 | int r_open2(const char *path, int oflag) 71 | { 72 | int retval; 73 | while (retval = open(path, oflag), retval == -1 && errno == EINTR) ; 74 | return retval; 75 | } 76 | 77 | int r_open3(const char *path, int oflag, mode_t mode) 78 | { 79 | int retval; 80 | while (retval = open(path, oflag, mode), retval == -1 81 | && errno == EINTR) ; 82 | return retval; 83 | } 84 | 85 | ssize_t r_read(int fd, void *buf, size_t size) 86 | { 87 | ssize_t retval; 88 | while (retval = read(fd, buf, size), retval == -1 && errno == EINTR) ; 89 | return retval; 90 | } 91 | 92 | pid_t r_wait(int *stat_loc) 93 | { 94 | pid_t retval; 95 | while (((retval = wait(stat_loc)) == -1) && (errno == EINTR)) ; 96 | return retval; 97 | } 98 | 99 | pid_t r_waitpid(pid_t pid, int *stat_loc, int options) 100 | { 101 | pid_t retval; 102 | while (((retval = waitpid(pid, stat_loc, options)) == -1) && 103 | (errno == EINTR)) ; 104 | return retval; 105 | } 106 | 107 | ssize_t r_write(int fd, void *buf, size_t size) 108 | { 109 | char *bufp; 110 | size_t bytestowrite; 111 | ssize_t byteswritten; 112 | size_t totalbytes; 113 | 114 | for (bufp = buf, bytestowrite = size, totalbytes = 0; 115 | bytestowrite > 0; 116 | bufp += byteswritten, bytestowrite -= byteswritten) { 117 | byteswritten = write(fd, bufp, bytestowrite); 118 | if ((byteswritten) == -1 && (errno != EINTR)) 119 | return -1; 120 | if (byteswritten == -1) 121 | byteswritten = 0; 122 | totalbytes += byteswritten; 123 | } 124 | return totalbytes; 125 | } 126 | 127 | /* Utility functions */ 128 | 129 | struct timeval add2currenttime(double seconds) 130 | { 131 | struct timeval newtime; 132 | 133 | gettimeofday(&newtime, NULL); 134 | newtime.tv_sec += (int)seconds; 135 | newtime.tv_usec += (int)((seconds - (int)seconds) * D_MILLION + 0.5); 136 | if (newtime.tv_usec >= MILLION) { 137 | newtime.tv_sec++; 138 | newtime.tv_usec -= MILLION; 139 | } 140 | return newtime; 141 | } 142 | 143 | int copyfile(int fromfd, int tofd) 144 | { 145 | int bytesread; 146 | int totalbytes = 0; 147 | 148 | while ((bytesread = readwrite(fromfd, tofd)) > 0) 149 | totalbytes += bytesread; 150 | return totalbytes; 151 | } 152 | 153 | ssize_t readblock(int fd, void *buf, size_t size) 154 | { 155 | char *bufp; 156 | ssize_t bytesread; 157 | size_t bytestoread; 158 | size_t totalbytes; 159 | 160 | for (bufp = buf, bytestoread = size, totalbytes = 0; 161 | bytestoread > 0; bufp += bytesread, bytestoread -= bytesread) { 162 | bytesread = read(fd, bufp, bytestoread); 163 | if ((bytesread == 0) && (totalbytes == 0)) 164 | return 0; 165 | if (bytesread == 0) { 166 | errno = EINVAL; 167 | return -1; 168 | } 169 | if ((bytesread) == -1 && (errno != EINTR)) 170 | return -1; 171 | if (bytesread == -1) 172 | bytesread = 0; 173 | totalbytes += bytesread; 174 | } 175 | return totalbytes; 176 | } 177 | 178 | int readline(int fd, char *buf, int nbytes) 179 | { 180 | int numread = 0; 181 | int returnval; 182 | 183 | while (numread < nbytes - 1) { 184 | returnval = read(fd, buf + numread, 1); 185 | if ((returnval == -1) && (errno == EINTR)) 186 | continue; 187 | if ((returnval == 0) && (numread == 0)) 188 | return 0; 189 | if (returnval == 0) 190 | break; 191 | if (returnval == -1) 192 | return -1; 193 | numread++; 194 | if (buf[numread - 1] == '\n') { 195 | buf[numread] = '\0'; 196 | return numread; 197 | } 198 | } 199 | errno = EINVAL; 200 | return -1; 201 | } 202 | 203 | ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds) 204 | { 205 | struct timeval timedone; 206 | 207 | timedone = add2currenttime(seconds); 208 | if (waitfdtimed(fd, timedone) == -1) 209 | return (ssize_t) (-1); 210 | return r_read(fd, buf, nbyte); 211 | } 212 | 213 | int readwrite(int fromfd, int tofd) 214 | { 215 | char buf[BLKSIZE]; 216 | int bytesread; 217 | 218 | if ((bytesread = r_read(fromfd, buf, BLKSIZE)) < 0) 219 | return -1; 220 | if (bytesread == 0) 221 | return 0; 222 | if (r_write(tofd, buf, bytesread) < 0) 223 | return -1; 224 | return bytesread; 225 | } 226 | 227 | int readwriteblock(int fromfd, int tofd, char *buf, int size) 228 | { 229 | int bytesread; 230 | 231 | bytesread = readblock(fromfd, buf, size); 232 | if (bytesread != size) /* can only be 0 or -1 */ 233 | return bytesread; 234 | return r_write(tofd, buf, size); 235 | } 236 | 237 | int waitfdtimed(int fd, struct timeval end) 238 | { 239 | fd_set readset; 240 | int retval; 241 | struct timeval timeout; 242 | 243 | if ((fd < 0) || (fd >= FD_SETSIZE)) { 244 | errno = EINVAL; 245 | return -1; 246 | } 247 | FD_ZERO(&readset); 248 | FD_SET(fd, &readset); 249 | if (gettimeout(end, &timeout) == -1) 250 | return -1; 251 | while (((retval = select(fd + 1, &readset, NULL, NULL, &timeout)) == -1) 252 | && (errno == EINTR)) { 253 | if (gettimeout(end, &timeout) == -1) 254 | return -1; 255 | FD_ZERO(&readset); 256 | FD_SET(fd, &readset); 257 | } 258 | if (retval == 0) { 259 | errno = ETIME; 260 | return -1; 261 | } 262 | if (retval == -1) 263 | return -1; 264 | return 0; 265 | } 266 | #endif 267 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/fileio_mmap/tst_fileio.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ $# -ne 1 ] && { 4 | echo "Usage: $0 io-size-in-MB" 5 | exit 1 6 | } 7 | 8 | SRC=~/srcfile 9 | DEST=~/destfile 10 | 11 | let countKB=$1*1024/4 # because we're writing in units of 4KB @ a time.. 12 | 13 | rm -f ${SRC} 14 | rm -f ${DEST} 15 | sync 16 | 17 | dd if=/dev/urandom of=${SRC} bs=4k count=$countKB 18 | #ls -lh ${SRC} 19 | 20 | # regular file i/o (read/write syscalls) with 'cp' test 21 | echo "Regular file io test:" 22 | time cp ${SRC} ${DEST} 23 | 24 | unalias ls 2> /dev/null 25 | ls -l ${SRC} ${DEST} 26 | sleep 1 27 | diff ${SRC} ${DEST} || { 28 | echo "reg: diff failed!" 29 | exit 1 30 | } 31 | 32 | rm -f ${SRC} 33 | rm -f ${DEST} 34 | sync 35 | 36 | # mmap-ed file i/o with 'mmap_fileio' test 37 | dd if=/dev/urandom of=${SRC} bs=4k count=$countKB 38 | sleep 1 39 | 40 | echo "mmap-ed file io test:" 41 | time ./mmap_fileio ${SRC} ${DEST} 42 | unalias ls 2> /dev/null 43 | ls -l ${SRC} ${DEST} 44 | sleep 1 45 | diff ${SRC} ${DEST} || { 46 | echo "reg: diff failed!" 47 | exit 1 48 | } 49 | 50 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/mmap_simple/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | ALL := mmap_simple 3 | 4 | all: ${ALL} 5 | CB_FILES := *.[ch] 6 | 7 | mmap_simple: mmap_simple.c ../../../../convenient.h 8 | gcc mmap_simple.c -o mmap_simple -Os -Wall #-DDEBUG 9 | 10 | # CB - C Beautifier ! uses indent- "beautifies" C code into the "Linux kernel style" 11 | # Note- original source file(s) is overwritten 12 | cb: ${CB_FILES} 13 | mkdir bkp 2> /dev/null; cp -f ${CB_FILES} bkp/ 14 | indent -nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0 -d0 -di1 -nfc1 -i8 -ip0 -l80 -lp -npcs -nprs -npsl -sai -saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts8 -il1 ${CB_FILES} 15 | clean: 16 | rm -f ${ALL} 17 | 18 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/mmap_simple/mmap_simple.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mmap_simple.c 3 | * 4 | * mmap() a file and display the contents as asked. 5 | * Private file-mapped I/O. 6 | * 7 | * History: 8 | * 9 | * Author(s) : Kaiwan Billimoria 10 | * License(s): [L]GPL v2 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "restart_lib.h" 22 | #include "../../../../convenient.h" 23 | 24 | /*--------------- Function hex_dump() sourced from: 25 | http://www.alexonlinux.com/hex-dump-functions 26 | All rights rest with original author(s).---------------------- 27 | 28 | Added an start-offset and a 'verbose' parameter..(kaiwan). 29 | */ 30 | void hex_dump(unsigned char *data, int offset, int size, char *caption, int verbose) 31 | { 32 | int i; // index in data... 33 | int j; // index in line... 34 | char temp[8]; 35 | char buffer[128]; 36 | char *ascii; 37 | 38 | memset(buffer, 0, 128); 39 | 40 | if (verbose && caption) 41 | printf("---------> %s <--------- (%d bytes from %p)\n", caption, 42 | size, data); 43 | 44 | // Printing the ruler... 45 | printf 46 | (" +0 +4 +8 +c 0 4 8 c \n"); 47 | 48 | // Hex portion of the line is 8 (the padding) + 3 * 16 = 52 chars long 49 | // We add another four bytes padding and place the ASCII version... 50 | ascii = buffer + 58; 51 | memset(buffer, ' ', 58 + 16); 52 | 53 | sprintf(temp, "+%06d", offset); 54 | buffer[58 + 16] = '\n'; 55 | buffer[58 + 17] = '\0'; 56 | buffer[0] = '+'; 57 | 58 | // Set offset to initial offset 59 | buffer[1] = temp[1]; 60 | buffer[2] = temp[2]; 61 | buffer[3] = temp[3]; 62 | buffer[4] = temp[4]; 63 | buffer[5] = temp[5]; 64 | buffer[6] = temp[6]; 65 | 66 | for (i = 0, j = 0; i < size; i++, j++) { 67 | if (j == 16) { 68 | printf("%s", buffer); 69 | memset(buffer, ' ', 58 + 16); 70 | 71 | sprintf(temp, "+%06d", i+offset); // set offset to initial offset 72 | memcpy(buffer, temp, 7); 73 | 74 | j = 0; 75 | } 76 | 77 | sprintf(temp, "%02x", 0xff & data[i]); 78 | memcpy(buffer + 8 + (j * 3), temp, 2); 79 | if ((data[i] > 31) && (data[i] < 127)) 80 | ascii[j] = data[i]; 81 | else 82 | ascii[j] = '.'; 83 | } 84 | 85 | if (j != 0) 86 | printf("%s", buffer); 87 | } 88 | 89 | 90 | int main(int argc, char **argv) 91 | { 92 | int fd_from; 93 | off_t fsz, len, off = 0; 94 | struct stat sstat; 95 | void *data_src, *origptr; 96 | 97 | if (argc != 4) { 98 | fprintf(stderr, "Usage: %s source-file start_offset length\n", 99 | argv[0]); 100 | exit(1); 101 | } 102 | 103 | fd_from = r_open2(argv[1], O_RDONLY); 104 | if (-1 == fd_from) { 105 | perror("open: src file"); 106 | exit(1); 107 | } 108 | // Query src file size 109 | if (fstat(fd_from, &sstat) == -1) { 110 | perror("fstat"); 111 | exit(1); 112 | } 113 | fsz = sstat.st_size; 114 | if (0 == fsz) { 115 | fprintf(stderr, 116 | "%s: source-file %s size is zero bytes, aborting...\n", 117 | argv[0], argv[1]); 118 | exit(1); 119 | } 120 | 121 | len = atol(argv[3]); 122 | if (len <= 0) { 123 | fprintf(stderr, 124 | "%s: invalid length %ld, aborting...\n", argv[0], len); 125 | exit(1); 126 | } 127 | off = atol(argv[2]); 128 | if ((off < 0) || ((off+len) > fsz)) { 129 | fprintf(stderr, 130 | "%s: invalid offset or offset/length combination, aborting...\n", argv[0]); 131 | exit(1); 132 | } 133 | 134 | /* 135 | void *mmap(void *addr, size_t length, int prot, int flags, 136 | int fd, off_t offset); 137 | 138 | A private mapping (obtained by using the MAP_PRIVATE flag), will initialize 139 | the mapped memory to the file region being mapped; any modifications to the 140 | mapped region are _not_ carried through to the file, though. 141 | */ 142 | origptr = data_src = mmap(0, fsz, PROT_READ, MAP_PRIVATE, fd_from, 0); //off); 143 | if (data_src == MAP_FAILED) { // (void *)-1) { 144 | perror("mmap: to src file"); 145 | exit(1); 146 | } 147 | 148 | // void hex_dump(unsigned char *data, int offset, int size, char *caption, int verbose) 149 | hex_dump(data_src + off, off, len, "Data", 0); 150 | 151 | /* 152 | int msync(void *addr, size_t length, int flags); 153 | 154 | msync() flushes changes made to the in-core copy of a file that was 155 | mapped into memory using mmap(2) back to disk. Without use of this call there 156 | is no guarantee that changes are written back before munmap(2) is called. 157 | To be more precise, the part of the file that corresponds to the memory 158 | area starting at addr and having length length is updated. 159 | 160 | The flags argument may have the bits MS_ASYNC, MS_SYNC, and MS_INVALIDATE set, 161 | but not both MS_ASYNC and MS_SYNC. MS_ASYNC specifies that an update be scheduled, 162 | but the call returns immediately. MS_SYNC asks for an update and waits for it to complete. 163 | MS_INVALIDATE asks to invalidate other mappings of the same file (so that 164 | they can be updated with the fresh values just written). 165 | */ 166 | if (msync (origptr, len, MS_SYNC) < 0) // redundant here as we're calling munmap() immd .. 167 | perror("mysnc"); 168 | 169 | if (munmap(origptr, len) == -1) { 170 | perror("munmap"); 171 | exit(1); 172 | } 173 | close(fd_from); 174 | exit(0); 175 | } 176 | 177 | /* vi: ts=4 */ 178 | -------------------------------------------------------------------------------- /mm/vm_usermode/mmap/mmap_simple/restart_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 'Restart' library. 3 | * 4 | * All functions below handle signals interrupting system calls, etc. 5 | * 6 | * Sourced directly from: 7 | * "UNIX Systems Programming", Robbins & Robbins. 8 | * All rights rest with the original authors. 9 | * 10 | * Very minor mods to have it work on 2.6 Linux -kaiwan. 11 | */ 12 | 13 | #ifndef __RESTART_LIB__ 14 | #define __RESTART_LIB__ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | //#include "restart.h" 24 | #define BLKSIZE PIPE_BUF 25 | #define MILLION 1000000L 26 | #define D_MILLION 1000000.0 27 | 28 | int readwrite(int fromfd, int tofd); 29 | int waitfdtimed(int fd, struct timeval end); 30 | 31 | /* Private functions */ 32 | 33 | static int gettimeout(struct timeval end, struct timeval *timeoutp) 34 | { 35 | gettimeofday(timeoutp, NULL); 36 | timeoutp->tv_sec = end.tv_sec - timeoutp->tv_sec; 37 | timeoutp->tv_usec = end.tv_usec - timeoutp->tv_usec; 38 | if (timeoutp->tv_usec >= MILLION) { 39 | timeoutp->tv_sec++; 40 | timeoutp->tv_usec -= MILLION; 41 | } 42 | if (timeoutp->tv_usec < 0) { 43 | timeoutp->tv_sec--; 44 | timeoutp->tv_usec += MILLION; 45 | } 46 | if ((timeoutp->tv_sec < 0) || 47 | ((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) { 48 | errno = ETIME; 49 | return -1; 50 | } 51 | return 0; 52 | } 53 | 54 | /* Restart versions of traditional functions */ 55 | 56 | int r_close(int fildes) 57 | { 58 | int retval; 59 | while (retval = close(fildes), retval == -1 && errno == EINTR) ; 60 | return retval; 61 | } 62 | 63 | int r_dup2(int fildes, int fildes2) 64 | { 65 | int retval; 66 | while (retval = dup2(fildes, fildes2), retval == -1 && errno == EINTR) ; 67 | return retval; 68 | } 69 | 70 | int r_open2(const char *path, int oflag) 71 | { 72 | int retval; 73 | while (retval = open(path, oflag), retval == -1 && errno == EINTR) ; 74 | return retval; 75 | } 76 | 77 | int r_open3(const char *path, int oflag, mode_t mode) 78 | { 79 | int retval; 80 | while (retval = open(path, oflag, mode), retval == -1 81 | && errno == EINTR) ; 82 | return retval; 83 | } 84 | 85 | ssize_t r_read(int fd, void *buf, size_t size) 86 | { 87 | ssize_t retval; 88 | while (retval = read(fd, buf, size), retval == -1 && errno == EINTR) ; 89 | return retval; 90 | } 91 | 92 | pid_t r_wait(int *stat_loc) 93 | { 94 | pid_t retval; 95 | while (((retval = wait(stat_loc)) == -1) && (errno == EINTR)) ; 96 | return retval; 97 | } 98 | 99 | pid_t r_waitpid(pid_t pid, int *stat_loc, int options) 100 | { 101 | pid_t retval; 102 | while (((retval = waitpid(pid, stat_loc, options)) == -1) && 103 | (errno == EINTR)) ; 104 | return retval; 105 | } 106 | 107 | ssize_t r_write(int fd, void *buf, size_t size) 108 | { 109 | char *bufp; 110 | size_t bytestowrite; 111 | ssize_t byteswritten; 112 | size_t totalbytes; 113 | 114 | for (bufp = buf, bytestowrite = size, totalbytes = 0; 115 | bytestowrite > 0; 116 | bufp += byteswritten, bytestowrite -= byteswritten) { 117 | byteswritten = write(fd, bufp, bytestowrite); 118 | if ((byteswritten) == -1 && (errno != EINTR)) 119 | return -1; 120 | if (byteswritten == -1) 121 | byteswritten = 0; 122 | totalbytes += byteswritten; 123 | } 124 | return totalbytes; 125 | } 126 | 127 | /* Utility functions */ 128 | 129 | struct timeval add2currenttime(double seconds) 130 | { 131 | struct timeval newtime; 132 | 133 | gettimeofday(&newtime, NULL); 134 | newtime.tv_sec += (int)seconds; 135 | newtime.tv_usec += (int)((seconds - (int)seconds) * D_MILLION + 0.5); 136 | if (newtime.tv_usec >= MILLION) { 137 | newtime.tv_sec++; 138 | newtime.tv_usec -= MILLION; 139 | } 140 | return newtime; 141 | } 142 | 143 | int copyfile(int fromfd, int tofd) 144 | { 145 | int bytesread; 146 | int totalbytes = 0; 147 | 148 | while ((bytesread = readwrite(fromfd, tofd)) > 0) 149 | totalbytes += bytesread; 150 | return totalbytes; 151 | } 152 | 153 | ssize_t readblock(int fd, void *buf, size_t size) 154 | { 155 | char *bufp; 156 | ssize_t bytesread; 157 | size_t bytestoread; 158 | size_t totalbytes; 159 | 160 | for (bufp = buf, bytestoread = size, totalbytes = 0; 161 | bytestoread > 0; bufp += bytesread, bytestoread -= bytesread) { 162 | bytesread = read(fd, bufp, bytestoread); 163 | if ((bytesread == 0) && (totalbytes == 0)) 164 | return 0; 165 | if (bytesread == 0) { 166 | errno = EINVAL; 167 | return -1; 168 | } 169 | if ((bytesread) == -1 && (errno != EINTR)) 170 | return -1; 171 | if (bytesread == -1) 172 | bytesread = 0; 173 | totalbytes += bytesread; 174 | } 175 | return totalbytes; 176 | } 177 | 178 | int readline(int fd, char *buf, int nbytes) 179 | { 180 | int numread = 0; 181 | int returnval; 182 | 183 | while (numread < nbytes - 1) { 184 | returnval = read(fd, buf + numread, 1); 185 | if ((returnval == -1) && (errno == EINTR)) 186 | continue; 187 | if ((returnval == 0) && (numread == 0)) 188 | return 0; 189 | if (returnval == 0) 190 | break; 191 | if (returnval == -1) 192 | return -1; 193 | numread++; 194 | if (buf[numread - 1] == '\n') { 195 | buf[numread] = '\0'; 196 | return numread; 197 | } 198 | } 199 | errno = EINVAL; 200 | return -1; 201 | } 202 | 203 | ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds) 204 | { 205 | struct timeval timedone; 206 | 207 | timedone = add2currenttime(seconds); 208 | if (waitfdtimed(fd, timedone) == -1) 209 | return (ssize_t) (-1); 210 | return r_read(fd, buf, nbyte); 211 | } 212 | 213 | int readwrite(int fromfd, int tofd) 214 | { 215 | char buf[BLKSIZE]; 216 | int bytesread; 217 | 218 | if ((bytesread = r_read(fromfd, buf, BLKSIZE)) < 0) 219 | return -1; 220 | if (bytesread == 0) 221 | return 0; 222 | if (r_write(tofd, buf, bytesread) < 0) 223 | return -1; 224 | return bytesread; 225 | } 226 | 227 | int readwriteblock(int fromfd, int tofd, char *buf, int size) 228 | { 229 | int bytesread; 230 | 231 | bytesread = readblock(fromfd, buf, size); 232 | if (bytesread != size) /* can only be 0 or -1 */ 233 | return bytesread; 234 | return r_write(tofd, buf, size); 235 | } 236 | 237 | int waitfdtimed(int fd, struct timeval end) 238 | { 239 | fd_set readset; 240 | int retval; 241 | struct timeval timeout; 242 | 243 | if ((fd < 0) || (fd >= FD_SETSIZE)) { 244 | errno = EINVAL; 245 | return -1; 246 | } 247 | FD_ZERO(&readset); 248 | FD_SET(fd, &readset); 249 | if (gettimeout(end, &timeout) == -1) 250 | return -1; 251 | while (((retval = select(fd + 1, &readset, NULL, NULL, &timeout)) == -1) 252 | && (errno == EINTR)) { 253 | if (gettimeout(end, &timeout) == -1) 254 | return -1; 255 | FD_ZERO(&readset); 256 | FD_SET(fd, &readset); 257 | } 258 | if (retval == 0) { 259 | errno = ETIME; 260 | return -1; 261 | } 262 | if (retval == -1) 263 | return -1; 264 | return 0; 265 | } 266 | #endif 267 | -------------------------------------------------------------------------------- /mm/vm_usermode/oom_try/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | ALL := oom-killer-try rdpg_oom_try 3 | CC := ${CROSS_COMPILE}gcc 4 | 5 | all: ${ALL} 6 | oom-killer-try: oom-killer-try.c 7 | ${CC} oom-killer-try.c -o oom-killer-try -Wall 8 | rdpg_oom_try: rdpg_oom_try.c 9 | ${CC} rdpg_oom_try.c -o rdpg_oom_try -Wall 10 | 11 | debug: 12 | oom-killer-try-dbg: oom-killer-try.c 13 | ${CC} oom-killer-try.c -o oom-killer-try-dbg -Wall -O0 -DDEBUG -g -ggdb 14 | clean: 15 | rm -f *.o ${ALL} 16 | -------------------------------------------------------------------------------- /mm/vm_usermode/oom_try/show_oom_score: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Displays running processes in descending order of OOM score 3 | # Src: https://dev.to/rrampage/surviving-the-linux-oom-killer-2ki9 4 | printf 'PID\tOOM Score\tOOM Adj\tCommand\n' 5 | while read -r pid comm 6 | do 7 | [ -f /proc/$pid/oom_score ] && [ $(cat /proc/$pid/oom_score) != 0 ] && 8 | printf '%d\t%d\t\t%d\t%s\n' "$pid" "$(cat /proc/$pid/oom_score)" "$(cat /proc/$pid/oom_score_adj)" "$comm" 9 | done < <(ps -e -o pid= -o comm=) | sort -k 2nr 10 | -------------------------------------------------------------------------------- /mm/vm_usermode/ptr1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int *gp = (int *)0x42000; 5 | int g = 0x42; 6 | 7 | int main() 8 | { 9 | int loc = 0x1; 10 | 11 | printf("&gp = %p, &g=%p &loc=%p\n", gp, &g, &loc); 12 | #if 0 13 | printf("val = %x\n", *gp); // segfaults; ptrs have no memory 14 | #endif 15 | pause(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /mm/vm_usermode/segv_pgfault.c: -------------------------------------------------------------------------------- 1 | /* 2 | * segv_pgfault.c 3 | * 4 | * Make a usermode process segfault by accessing invalid user/kernel-space addresses.. 5 | * This in turn will have the MMU trigger an exception condition (Data Abort on 6 | * ARM), which will lead to the OS's page fault handler being invoked. *It* will 7 | * determine the actual fault (minor or major, good or bad) and, in this case, being 8 | * a usermode 'bad' fault, will send SIGSEGV to 'current'! 9 | * 10 | * Author(s) : Kaiwan NB 11 | * License(s): [L]GPL 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /*---------------- Typedef's, constants, etc ------------------------*/ 24 | typedef unsigned int u32; 25 | typedef long unsigned int u64; 26 | 27 | /*---------------- Macros -------------------------------------------*/ 28 | #if __x86_64__ /* 64-bit; __x86_64__ works for gcc */ 29 | #define ADDR_TYPE u64 30 | #define ADDR_FMT "%016lx" 31 | static u64 rubbish_uaddr = 0x100000L; 32 | static u64 rubbish_kaddr = 0xffff0a8700100000L; 33 | #else 34 | #define ADDR_TYPE u32 35 | #define ADDR_FMT "%08lx" 36 | static u32 rubbish_uaddr = 0x100000L; 37 | static u32 rubbish_kaddr = 0xd0100000L; 38 | #endif 39 | 40 | 41 | /*---------------- Functions ----------------------------------------*/ 42 | static void myfault(int signum, siginfo_t * siginfo, void *rest) 43 | { 44 | static int c = 0; 45 | 46 | printf("*** %s: [%d] received signal %d. errno=%d\n" 47 | " Cause/Origin: (si_code=%d): ", 48 | __func__, ++c, signum, siginfo->si_errno, siginfo->si_code); 49 | 50 | switch (siginfo->si_code) { 51 | case SI_USER: 52 | printf("user\n"); 53 | break; 54 | case SI_KERNEL: 55 | printf("kernel\n"); 56 | break; 57 | case SI_QUEUE: 58 | printf("queue\n"); 59 | break; 60 | case SI_TIMER: 61 | printf("timer\n"); 62 | break; 63 | case SI_MESGQ: 64 | printf("mesgq\n"); 65 | break; 66 | case SI_ASYNCIO: 67 | printf("async io\n"); 68 | break; 69 | case SI_SIGIO: 70 | printf("sigio\n"); 71 | break; 72 | case SI_TKILL: 73 | printf("t[g]kill\n"); 74 | break; 75 | // other poss values si_code can have for SIGSEGV 76 | case SEGV_MAPERR: 77 | printf("SEGV_MAPERR: address not mapped to object\n"); 78 | break; 79 | case SEGV_ACCERR: 80 | printf("SEGV_ACCERR: invalid permissions for mapped object\n"); 81 | break; 82 | default: 83 | printf("-none-\n"); 84 | } 85 | printf(" Faulting addr=0x" ADDR_FMT "\n", (ADDR_TYPE) siginfo->si_addr); 86 | 87 | #if 1 88 | exit (1); 89 | #else 90 | abort(); 91 | #endif 92 | } 93 | 94 | static void usage(char *nm) 95 | { 96 | fprintf(stderr, "Usage: %s u|k r|w\n" 97 | "u => user mode\n" 98 | "k => kernel mode\n" 99 | " r => read attempt\n" " w => write attempt\n", nm); 100 | } 101 | 102 | 103 | int main(int argc, char **argv) 104 | { 105 | struct sigaction act; 106 | 107 | if (argc != 3) { 108 | usage(argv[0]); 109 | exit(1); 110 | } 111 | //act.sa_handler = myfault; 112 | act.sa_sigaction = myfault; 113 | act.sa_flags = SA_RESTART | SA_SIGINFO; 114 | sigemptyset(&act.sa_mask); 115 | if (sigaction(SIGSEGV, &act, 0) == -1) { 116 | perror("sigaction"); 117 | exit(1); 118 | } 119 | 120 | if ((tolower(argv[1][0]) == 'u') && tolower(argv[2][0] == 'r')) { 121 | ADDR_TYPE *uptr = (ADDR_TYPE *) rubbish_uaddr; // arbitrary userspace virtual addr 122 | printf 123 | ("Attempting to read contents of arbitrary usermode va uptr = 0x" ADDR_FMT ":\n", 124 | (ADDR_TYPE) uptr); 125 | printf("*uptr = 0x" ADDR_FMT "\n", *uptr); // just reading 126 | } else if ((tolower(argv[1][0]) == 'u') && tolower(argv[2][0] == 'w')) { 127 | ADDR_TYPE *uptr = (ADDR_TYPE *) & main; 128 | printf 129 | ("Attempting to write into arbitrary usermode va uptr (&main actually) = 0x" ADDR_FMT ":\n", 130 | (ADDR_TYPE) uptr); 131 | *uptr = 40; // writing 132 | } else if ((tolower(argv[1][0]) == 'k') && tolower(argv[2][0] == 'r')) { 133 | ADDR_TYPE *kptr = (ADDR_TYPE *) rubbish_kaddr; // arbitrary kernel virtual addr 134 | printf 135 | ("Attempting to read contents of arbitrary kernel va kptr = 0x" ADDR_FMT ":\n", 136 | (ADDR_TYPE) kptr); 137 | printf("*kptr = 0x" ADDR_FMT "\n", *kptr); // just reading 138 | } else if ((tolower(argv[1][0]) == 'k') && tolower(argv[2][0] == 'w')) { 139 | ADDR_TYPE *kptr = (ADDR_TYPE *) rubbish_kaddr; // arbitrary kernel virtual addr 140 | printf 141 | ("Attempting to write into arbitrary kernel va kptr = 0x" ADDR_FMT ":\n", 142 | (ADDR_TYPE) kptr); 143 | *kptr = 0x62; // writing 144 | } else 145 | usage(argv[0]); 146 | exit(0); 147 | } 148 | 149 | /* vi: ts=4 */ 150 | -------------------------------------------------------------------------------- /mm/vm_usermode/swap_stuff/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #------------------------------------------------------------------ 3 | # common.sh 4 | # 5 | # Common convenience routines 6 | # 7 | # (c) Kaiwan N Billimoria 8 | # kaiwan -at- designergraphix -dot- com 9 | # GPL / LGPL 10 | # Last Updt: 29Dec2013 11 | #------------------------------------------------------------------ 12 | 13 | export TOPDIR=$(pwd) 14 | ON=1 15 | OFF=0 16 | 17 | ### UPDATE for your box 18 | source ./err_common.sh || { 19 | echo "$name: could not source err_common.sh, aborting..." 20 | exit 1 21 | } 22 | 23 | 24 | # DesktopNotify 25 | # Ubuntu desktop notify-send wrapper func 26 | # Parameter(s) 27 | # $1 : String to display in desktop notification message [required] 28 | function DesktopNotify() 29 | { 30 | # Ubuntu : notify-send ! 31 | [ $# -ne 1 ] && MSG="" || MSG="$1" 32 | notify-send --urgency=low "${MSG}" 33 | } 34 | 35 | 36 | # genLogFilename 37 | # Generates a logfile name that includes the date/timestamp 38 | # Format: 39 | # ddMmmYYYY[_HHMMSS] 40 | # Parameter(s) 41 | # #$1 : String to prefix to log filename, null okay as well [required] 42 | # $1 : Include time component or not [required] 43 | # $1 = 0 : Don't include the time component (only date) in the log filename 44 | # $1 = 1 : include the time component in the log filename 45 | genLogFilename() 46 | { 47 | [ $1 -eq 0 ] && log_filename=$(date +%d%b%Y) 48 | [ $1 -eq 1 ] && log_filename=$(date +%d%b%Y_%H%M%S) 49 | echo ${log_filename} 50 | } 51 | 52 | # Debug echo :-) 53 | decho() 54 | { 55 | Prompt "$@" 56 | } 57 | 58 | verbose=1 59 | # Echo 60 | # Echo string (with timestamp prefixed) to stdout and to Log file 61 | # if so specified. 62 | # Parameter(s): 63 | # $1 : String to display to stdout [required] 64 | # $2 : Log pathname to also append the $1 string to [optional] 65 | Echo() 66 | { 67 | #echo "# p = $#" 68 | [ $# -eq 0 ] && return 1 69 | [ ${verbose} -eq 1 ] && { 70 | echo -n "$(date) : " 71 | echo "$1" 72 | [ $# -ge 2 ] && { 73 | [ -f $2 -a -w $2 ] && { 74 | echo -n "$(date) : " >> $2 75 | echo "$1" >> $2 76 | } 77 | } 78 | } 79 | } 80 | 81 | 82 | # ShowTitle 83 | # Display a string in "title" form 84 | # Parameter(s): 85 | # $1 : String to display [required] 86 | # Returns: 0 on success, 1 on failure 87 | ShowTitle() 88 | { 89 | [ $# -ne 1 ] && return 1 90 | SEP='-------------------------------------------------------------------------------' 91 | echo $SEP 92 | echo $1 93 | echo $SEP 94 | } 95 | 96 | # check_root_AIA 97 | # Check whether we are running as root user; if not, exit with failure! 98 | # Parameter(s): 99 | # None. 100 | # "AIA" = Abort If Absent :-) 101 | check_root_AIA() 102 | { 103 | if [ `id -u` -ne 0 ]; then 104 | Echo "Error: need to run as root! Aborting..." 105 | exit 1 106 | fi 107 | } 108 | 109 | # check_file_AIA 110 | # Check whether the file, passed as a parameter, exists; if not, exit with failure! 111 | # Parameter(s): 112 | # $1 : Pathname of file to check for existence. [required] 113 | # "AIA" = Abort If Absent :-) 114 | # Returns: 0 on success, 1 on failure 115 | check_file_AIA() 116 | { 117 | [ $# -ne 1 ] && return 1 118 | [ ! -f $1 ] && { 119 | Echo "Error: file \"$1\" does not exist. Aborting..." 120 | exit 1 121 | } 122 | } 123 | 124 | # check_folder_AIA 125 | # Check whether the directory, passed as a parameter, exists; if not, exit with failure! 126 | # Parameter(s): 127 | # $1 : Pathname of folder to check for existence. [required] 128 | # "AIA" = Abort If Absent :-) 129 | # Returns: 0 on success, 1 on failure 130 | check_folder_AIA() 131 | { 132 | [ $# -ne 1 ] && return 1 133 | [ ! -d $1 ] && { 134 | Echo "Error: folder \"$1\" does not exist. Aborting..." 135 | exit 1 136 | } 137 | } 138 | 139 | # check_folder_createIA 140 | # Check whether the directory, passed as a parameter, exists; if not, create it! 141 | # Parameter(s): 142 | # $1 : Pathname of folder to check for existence. [required] 143 | # "IA" = If Absent :-) 144 | # Returns: 0 on success, 1 on failure 145 | check_folder_createIA() 146 | { 147 | [ $# -ne 1 ] && return 1 148 | [ ! -d $1 ] && { 149 | Echo "Folder \"$1\" does not exist. Creating it..." 150 | mkdir -p $1 && return 0 || return 1 151 | } 152 | } 153 | 154 | 155 | # GetIP 156 | # Extract IP address from ifconfig output 157 | # Parameter(s): 158 | # $1 : name of network interface (string) 159 | # Returns: IPaddr on success, non-zero on failure 160 | GetIP() 161 | { 162 | [ $# -ne 1 ] && return 1 163 | ifconfig $1 >/dev/null 2>&1 || return 2 164 | ifconfig $1 |grep 'inet addr'|awk '{print $2}' |cut -f2 -d':' 165 | } 166 | 167 | # get_yn_reply 168 | # User's reply should be Y or N. 169 | # Returns: 170 | # 0 => user has answered 'Y' 171 | # 1 => user has answered 'N' 172 | get_yn_reply() 173 | { 174 | echo -n "Type Y or N please (followed by ENTER) : " 175 | str="${@}" 176 | while true 177 | do 178 | echo ${str} 179 | read reply 180 | 181 | case "$reply" in 182 | y | yes | Y | YES ) return 0 183 | ;; 184 | n* | N* ) return 1 185 | ;; 186 | *) echo "What? Pl type Y / N" 187 | esac 188 | done 189 | } 190 | 191 | # MountPartition 192 | # Mounts the partition supplied as $1 193 | # Parameters: 194 | # $1 : device node of partition to mount 195 | # $2 : mount point 196 | # Returns: 197 | # 0 => mount successful 198 | # 1 => mount failed 199 | MountPartition() 200 | { 201 | [ $# -ne 2 ] && { 202 | echo "MountPartition: parameter(s) missing!" 203 | return 1 204 | } 205 | 206 | DEVNODE=$1 207 | [ ! -b ${DEVNODE} ] && { 208 | echo "MountPartition: device node $1 does not exist?" 209 | return 1 210 | } 211 | 212 | MNTPT=$2 213 | [ ! -d ${MNTPT} ] && { 214 | echo "MountPartition: folder $2 does not exist?" 215 | return 1 216 | } 217 | 218 | mount |grep ${DEVNODE} >/dev/null || { 219 | #echo "The partition is not mounted, attempting to mount it now..." 220 | mount ${DEVNODE} -t auto ${MNTPT} || { 221 | echo "Could not mount the '$2' partition!" 222 | return 1 223 | } 224 | } 225 | return 0 226 | } 227 | 228 | 229 | #------------------- Colors!! Yay :-) ----------------------------------------- 230 | # Ref: http://tldp.org/LDP/abs/html/colorizing.html 231 | black='\E[30;47m' 232 | red='\E[31;47m' 233 | green='\E[32;47m' 234 | yellow='\E[33;47m' 235 | blue='\E[34;47m' 236 | magenta='\E[35;47m' 237 | cyan='\E[36;47m' 238 | white='\E[37;47m' 239 | 240 | # Reset text attributes to normal without clearing screen. 241 | Reset() 242 | { 243 | tput sgr0 244 | } 245 | 246 | # !!! 247 | # Turn this ON for COLOR !!! 248 | # !!! 249 | COLOR=${OFF} 250 | #COLOR=${ON} 251 | 252 | # Color-echo. 253 | # Argument $1 = message 254 | # Argument $2 = color 255 | # Usage eg.: 256 | # cecho "This message is in blue!" $blue 257 | cecho () 258 | { 259 | local default_msg="No message passed." 260 | # Doesn't really need to be a local variable. 261 | [ ${COLOR} -eq 0 ] && { 262 | echo $1 263 | return 264 | } 265 | #echo "cecho: nump = $# : $@" 266 | 267 | message=${1:-$default_msg} # Defaults to default message. 268 | color=${2:-$black} # Defaults to black, if not specified. 269 | 270 | echo -e "$color" 271 | echo "$message" 272 | Reset # Reset to normal. 273 | 274 | return 275 | } 276 | #---------------------------------------------------------------------- 277 | 278 | 279 | ## is_kernel_thread 280 | # Param: PID 281 | # Returns: 282 | # 1 if $1 is a kernel thread, 0 if not, 127 on failure. 283 | is_kernel_thread() 284 | { 285 | [ $# -ne 1 ] && { 286 | echo "is_kernel_thread: parameter missing!" 1>&2 287 | return 127 288 | } 289 | 290 | prcs_name=$(ps aux |awk -v pid=$1 '$2 == pid {print $11}') 291 | #echo "prcs_name = ${prcs_name}" 292 | [ -z ${prcs_name} ] && { 293 | echo "is_kernel_thread: could not obtain process name!" 1>&2 294 | return 127 295 | } 296 | 297 | firstchar=$(echo "${prcs_name:0:1}") 298 | #echo "firstchar = ${firstchar}" 299 | len=${#prcs_name} 300 | let len=len-1 301 | lastchar=$(echo "${prcs_name:${len}:1}") 302 | #echo "lastchar = ${lastchar}" 303 | [ ${firstchar} = "[" -a ${lastchar} = "]" ] && return 1 || return 0 304 | } 305 | 306 | -------------------------------------------------------------------------------- /mm/vm_usermode/swap_stuff/err_common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #------------------------------------------------------------------ 3 | # err_common.sh 4 | # 5 | # Common error handling routines. 6 | # 7 | # (c) Kaiwan N Billimoria 8 | # kaiwan -at- designergraphix -dot- com 9 | # GPL / LGPL 10 | # Last Updt: 31Mar2014 11 | #------------------------------------------------------------------ 12 | 13 | GUI_MODE=1 14 | export TOPDIR=$(pwd) 15 | ON=1 16 | OFF=0 17 | 18 | # "Returns" (actually echoes) 19 | # 1 => zenity present 20 | # 0 => zenity absent 21 | verify_zenity() 22 | { 23 | which zenity >/dev/null 2>&1 && echo -n 1 || echo -n 0 24 | } 25 | 26 | # QP 27 | # QuickPrint ;-) 28 | # Print timestamp, script name, line#. Useful for debugging. 29 | QP() 30 | { 31 | _ERR_HDR_FMT="%.23s %s[%s]: " 32 | _ERR_MSG_FMT="${_ERR_HDR_FMT}%s\n" 33 | printf "$_ERR_MSG_FMT" $(date +%F.%T.%N) ${BASH_SOURCE[1]##*/} ${BASH_LINENO[0]} 1>&2 #"${@}" 34 | unset _ERR_HDR_FMT 35 | unset _ERR_MSG_FMT 36 | } 37 | 38 | 39 | cli_handle_error() 40 | { 41 | echo -n "FatalError :: " 1>&2 42 | QP 43 | [ $# -lt 1 ] && exit -1 44 | echo "${@}" 1>&2 45 | exit -1 46 | } 47 | 48 | # FatalError 49 | # Display the error message string and exit -1. 50 | # Parameter(s): 51 | # $1 : Error string to display [required] 52 | # Returns: -1 (255) 53 | FatalError() 54 | { 55 | [ ${GUI_MODE} -eq 0 ] && { 56 | cli_handle_error $@ 57 | } || { # want GUI mode 58 | #n=$(verify_zenity) 59 | #echo "n=$n" 60 | #return 61 | [ $(verify_zenity) -eq 0 ] && { 62 | echo "FatalError :: !WARNING! zenity not installed?? " 63 | # fallback to non-gui err handling 64 | cli_handle_error $@ 65 | } 66 | } 67 | # gui err handling, zenity there; whew 68 | zenity --error --title="${name}: Error" --text="Fatal Error :: $@" 69 | cli_handle_error $@ 70 | exit -1 71 | } 72 | 73 | # Prompt 74 | # Interactive: prompt the user to continue by pressing ENTER or 75 | # abort by pressing Ctrl-C 76 | # Parameter(s): 77 | # $1 : string to display (string) 78 | Prompt() 79 | { 80 | [ $# -lt 1 ] && { 81 | echo "$0: Prompt function requires a string parameter!" 82 | return 1 83 | } 84 | echo "${@}" 85 | echo " Press ENTER to continue, Ctrl-C to abort now..." 86 | read 87 | } 88 | 89 | 90 | -------------------------------------------------------------------------------- /mm/vm_usermode/swap_stuff/swap_usage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # swap_usage.sh 3 | # 4 | # Quick Description: 5 | # 6 | # 7 | # Last Updated : 8 | # Created : 14 Nov 2014 9 | # 10 | # Author: 11 | # Kaiwan N Billimoria 12 | # kaiwan -at- kaiwantech -dot- com 13 | # kaiwanTECH 14 | # 15 | # License: 16 | # GPL / LGPL 17 | # 18 | name=$(basename $0) 19 | source ./common.sh || { 20 | echo "$name: could not source common.sh , aborting..." 21 | exit 1 22 | } 23 | 24 | SLPTM_MIN=1 25 | tm=0 26 | ########### Functions follow ####################### 27 | 28 | 29 | 30 | main() 31 | { 32 | SLPTM_SEC=$((SLPTM_MIN*60)) 33 | while [ true ] 34 | do 35 | # date 36 | swapKB=$(free |grep "^Swap" |awk '{print $3}') 37 | echo "${tm} ${swapKB}" 38 | tm=$((${tm}+1)) # cumulative time elapsed in minutes 39 | sleep ${SLPTM_SEC} 40 | done 41 | 42 | } 43 | 44 | ##### execution starts here ##### 45 | 46 | main 47 | exit 0 48 | -------------------------------------------------------------------------------- /mm/vm_usermode/swap_stuff/toggle_swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Scott Severance 3 | # http://askubuntu.com/questions/1357/how-to-empty-swap-if-there-is-free-ram 4 | # Small enhancements: Kaiwan NB, Nov14. 5 | 6 | export name=$(basename $0) 7 | source ./common.sh || { 8 | echo "$name: could not source common.sh , aborting..." 9 | exit 1 10 | } 11 | 12 | export SWAP_THRESHOLD_MB=175 13 | 14 | function getData() 15 | { 16 | free_data="$(free)" 17 | mem_data="$(echo "$free_data" | grep 'Mem:')" 18 | free_mem="$(echo "$mem_data" | awk '{print $4}')" 19 | buffers="$(echo "$mem_data" | awk '{print $6}')" 20 | cache="$(echo "$mem_data" | awk '{print $7}')" 21 | total_free=$((free_mem + buffers + cache)) 22 | used_swap="$(echo "$free_data" | grep 'Swap:' | awk '{print $3}')" 23 | } 24 | 25 | ## The messages 26 | MSG_SWAPOFF_ATTEMPT="${name} :: Swap usage high [${SWAP_THRESHOLD_MB} MB], attempting swapoff -a now..." 27 | MSG_SWAP_FREED="${name} :: Freed SWAP : Free memory: $total_free kB ($((total_free / 1024)) MB). \ 28 | Used swap: $used_swap kB ($((used_swap / 1024)) MB)" 29 | MSG_SWAPOFF_FAILED="${name} :: Swap usage high [${SWAP_THRESHOLD_MB} MB], swapoff -a cmd failed" 30 | ## 31 | 32 | #function DesktopNotify() 33 | #{ 34 | # # Ubuntu : notify-send ! 35 | # [ $# -ne 1 ] && MSG="" || MSG="$1" 36 | # notify-send --urgency=low "${MSG}" 37 | #} 38 | 39 | function toggleSwap() 40 | { 41 | if [[ $used_swap -lt $total_free ]]; then 42 | # Add a condition: 43 | # only free swap if above a threshold - knb 44 | USED_SWAP_MB=$((${used_swap}/1024)) 45 | if [[ ${USED_SWAP_MB} -ge ${SWAP_THRESHOLD_MB} ]]; then 46 | DesktopNotify "${MSG_SWAPOFF_ATTEMPT}" 47 | sudo swapoff -a && DesktopNotify "${MSG_SWAP_FREED}" || DesktopNotify "${MSG_SWAPOFF_FAILED}" 48 | sudo swapon -a 49 | fi 50 | else 51 | echo "Not enough free memory. Exiting." 52 | exit 1 53 | fi 54 | } 55 | 56 | TMOUT_MIN=5 57 | function main() 58 | { 59 | while [ true ] 60 | do 61 | getData 62 | toggleSwap 63 | sleep $((${TMOUT_MIN}*60)) 64 | done 65 | } 66 | 67 | [ $(id -u) -ne 0 ] && { 68 | echo "$name: need to run as root (sudo)" 69 | exit 1 70 | } 71 | DesktopNotify "${name} : starting...(timeout interval: ${TMOUT_MIN} min)" 72 | main 73 | 74 | -------------------------------------------------------------------------------- /mm/vm_usermode/vm_user.c: -------------------------------------------------------------------------------- 1 | /* 2 | * vm_user.c 3 | * Show approx process VAS by printing appropriate addresses.. 4 | * For 32-bit and 64-bit systems. 5 | * kaiwanTECH 6 | */ 7 | #include 8 | #include 9 | #include 10 | 11 | typedef unsigned int u32; 12 | typedef long unsigned int u64; 13 | 14 | int g=5, u; 15 | 16 | int main(int argc, char **argv) 17 | { 18 | int local; 19 | char *heapptr = malloc(100); 20 | 21 | // OS bits 22 | // for cpu use 'lscpu' 23 | printf("wordsize : %d\n", __WORDSIZE); 24 | 25 | if (__WORDSIZE == 32) { 26 | printf("&main = 0x%08x &g = 0x%08x &u = 0x%08x &heapptr = 0x%08x &loc = 0x%08x\n", 27 | (u32)main, (u32)&g, (u32)&u, (u32)heapptr, (u32)&local); 28 | } else if (__WORDSIZE == 64) { 29 | printf("&main = 0x%016lx &g = 0x%016lx &u = 0x%016lx &heapptr = 0x%016lx &loc = 0x%016lx\n", 30 | (u64)main, (u64)&g, (u64)&u, (u64)heapptr, (u64)&local); 31 | } 32 | 33 | free(heapptr); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /mm/vmallc/Makefile.simple: -------------------------------------------------------------------------------- 1 | # Simplest LKM Makefile 2 | MODNAME = vmallc 3 | 4 | obj-m := $(MODNAME).o 5 | 6 | KDIR := /lib/modules/$(shell uname -r)/build 7 | PWD := $(shell pwd) 8 | 9 | all: module 10 | 11 | module: 12 | $(MAKE) -C $(KDIR) M=$(PWD) modules 13 | clean: 14 | $(MAKE) -C $(KDIR) M=$(PWD) clean 15 | -------------------------------------------------------------------------------- /mm/vmallc/vmallc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | MODULE_LICENSE("Dual MIT/GPL"); 7 | 8 | static void *vp; 9 | static int __init hello_init(void) 10 | { 11 | vp = vmalloc(8*PAGE_SIZE); 12 | //memset(vp, 0, 8*1024*1024); 13 | return 0; // success 14 | } 15 | 16 | static void __exit hello_exit(void) 17 | { 18 | vfree(vp); 19 | pr_info("%s removed\n", KBUILD_MODNAME); 20 | } 21 | 22 | module_init(hello_init); 23 | module_exit(hello_exit); 24 | -------------------------------------------------------------------------------- /mm/xtras/malloc_brk_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * malloc_brk_test.c 3 | 4 | Rationale: 5 | ---------- 6 | The first time a process does an malloc(8) : 7 | 8 | - the heap memory is not physically allocated yet, only virtually 9 | (remember, the kernel is a lazy guy!). 10 | - Thus, when attempting to map the virtual to physical address, the 11 | MMU faults; the kernel “realizes” this is a good fault and allocates 12 | a page farme from the slab cache (possibly via the buddy allocator). 13 | This is mapped into the faulting process’s heap.. 14 | - Another request is made, say: 15 | malloc(32); 16 | - Now, since the glibc memory manager (what we call malloc) now knows 17 | that a full page is available in the heap and only 8 bytes are actually 18 | used up, this request will not cause a brk() syscall to the kernel. This 19 | can be verified by checking the current break (using sbrk(0)). 20 | 21 | - Also, seeking to within a page of the 1st request will (probably) not cause 22 | a segfault! 23 | 24 | See below a program that helps us study how the system allocates memory 25 | dynamically to user-space applications via the usual malloc / calloc API. 26 | 27 | (c) Kaiwan NB. 28 | GPL v2. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | //#define USE_CALLOC 39 | #undef USE_CALLOC 40 | 41 | #define TRIES 5 42 | void *heap_ptr[TRIES]; 43 | void *init_brk; 44 | 45 | typedef unsigned int u32; 46 | 47 | static void alloctest(int index, size_t num) 48 | { 49 | void *p; 50 | 51 | #ifndef USE_CALLOC 52 | p = malloc(num); 53 | #else 54 | p = calloc(num, sizeof(char)); 55 | #endif 56 | if (!p) { 57 | printf("out of memory!\n"); 58 | exit(1); 59 | } 60 | 61 | heap_ptr[index] = p; // save ptr in order to free later.. 62 | #ifndef USE_CALLOC 63 | printf("\n%d: malloc", index); 64 | #else 65 | printf("\n%d: calloc", index); 66 | #endif 67 | printf("(%6u) successful. Heap pointer: %8p\n", num, p); 68 | printf("Current break: %8p [delta: %d]\n", sbrk(0), 69 | (sbrk(0) - init_brk)); 70 | 71 | malloc_stats(); 72 | } 73 | 74 | int main(int argc, char **argv) 75 | { 76 | int i; 77 | volatile char *q; 78 | 79 | init_brk = sbrk(0); 80 | printf("Current break: %8p\n", init_brk); 81 | alloctest(0, 8); 82 | 83 | //exit(0); 84 | 85 | q = heap_ptr[0]; 86 | *(q + 3000) = 'a'; /* "should" segfault but does (probably) not bcoz a *page* is alloced 87 | by the previous alloc, not just 8 bytes! See value of prg break 88 | compared to this pointer. 89 | */ 90 | printf 91 | ("\n### q=0x%08x. (q+3000) is the mem loc 0x%08x. Mem here is: 0x%08x\n", 92 | (unsigned int)q, (unsigned int)(q + 3000), 93 | (unsigned int)*(q + 3000)); 94 | /* 95 | Indeed valgrind points out the errors: 96 | 97 | $ valgrind --leak-check=full ./malloc_brk_test 98 | ... 99 | 0: malloc( 8) successful. Heap pointer: 0x41f7028 100 | Current break: 0x804b000 [delta: 0] 101 | ==31220== Invalid write of size 1 102 | ==31220== at 0x804863E: main (malloc_brk_test.c:80) 103 | ==31220== Address 0x41f7be0 is not stack'd, malloc'd or (recently) free'd 104 | ==31220== 105 | ==31220== Invalid read of size 1 106 | ==31220== at 0x804864A: main (malloc_brk_test.c:85) 107 | ==31220== Address 0x41f7be0 is not stack'd, malloc'd or (recently) free'd 108 | ==31220== 109 | 110 | ### q=0x041f7028. (q+3000) is the mem loc 0x041f7be0. Mem here is: 0x00000061 111 | ... 112 | */ 113 | 114 | #if 0 115 | *(q + 3000 + (sbrk(0) - init_brk)) = 'b'; /* *make* it segfault here by poking into a region 116 | just beyond what the kernel allocated */ 117 | #endif 118 | 119 | //pause(); 120 | //exit(0); 121 | 122 | alloctest(1, (getpagesize() - 8 - 5)); 123 | alloctest(2, 3); 124 | //exit(0); 125 | alloctest(3, (sbrk(0) - init_brk + 1000)); 126 | /* This (above) allocation request is a large one: ~132Kb. The 'mmap threshold' 127 | is (default) 128Kb; thus, this causes an mmap() to the process virtual address 128 | space, mapping in the virtually allocated region (which will later be mapped to 129 | physical page frames via the MMU page-faulting on application access to these memory regions! 130 | */ 131 | alloctest(4, 200000); 132 | 133 | for (i = 0; i < TRIES; i++) 134 | free(heap_ptr[i]); 135 | exit(0); 136 | } 137 | 138 | /* vi: ts=4 */ 139 | -------------------------------------------------------------------------------- /mm/xtras/query_oom_score.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | IFS=$'\n' 4 | for token in $(ps -eo pid,comm) 5 | do 6 | echo "${token}" 7 | pid=$(echo "${token}" |awk '{print $1}' |xargs echo) 8 | name=$(echo "${token}"|awk '{print $2}' |xargs echo) 9 | echo "PID: ${pid} nm: ${name}" 10 | #cat /proc/${cleanpid}/oom_score 11 | #cat /proc/${cleanpid}/oom_score_adj 12 | echo 13 | done 14 | 15 | -------------------------------------------------------------------------------- /mm/xtras/segv_pgfault.c: -------------------------------------------------------------------------------- 1 | /* 2 | * segv_pgfault.c 3 | * 4 | * Make a usermode process segfault by accessing invalid user/kernel-space addresses.. 5 | * This in turn will have the MMU trigger an exception condition (Data Abort on 6 | * ARM), which will lead to the OS's page fault handler being invoked. *It* will 7 | * determine the actual fault (minor or major, good or bad) and, in this case, being 8 | * a usermode 'bad' fault, will send SIGSEGV to 'current'! 9 | * 10 | * Author(s) : Kaiwan NB 11 | * License(s): MIT 12 | */ 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | /*---------------- Typedef's, constants, etc ------------------------*/ 22 | typedef unsigned int u32; 23 | typedef long unsigned int u64; 24 | 25 | /*---------------- Macros -------------------------------------------*/ 26 | #if __x86_64__ /* 64-bit; __x86_64__ works for gcc */ 27 | #define ADDR_TYPE u64 28 | #define ADDR_FMT "%016lx" 29 | static u64 rubbish_uaddr = 0x100000L; 30 | static u64 rubbish_kaddr = 0xffff0a8700100000L; 31 | #else 32 | #define ADDR_TYPE u32 33 | #define ADDR_FMT "%08lx" 34 | static u32 rubbish_uaddr = 0x100000L; 35 | static u32 rubbish_kaddr = 0xd0100000L; 36 | #endif 37 | 38 | 39 | /*---------------- Functions ----------------------------------------*/ 40 | static void myfault(int signum, siginfo_t * siginfo, void *rest) 41 | { 42 | static int c = 0; 43 | 44 | printf("*** %s: [%d] received signal %d. errno=%d\n" 45 | " Cause/Origin: (si_code=%d): ", 46 | __func__, ++c, signum, siginfo->si_errno, siginfo->si_code); 47 | 48 | switch (siginfo->si_code) { 49 | case SI_USER: 50 | printf("user\n"); 51 | break; 52 | case SI_KERNEL: 53 | printf("kernel\n"); 54 | break; 55 | case SI_QUEUE: 56 | printf("queue\n"); 57 | break; 58 | case SI_TIMER: 59 | printf("timer\n"); 60 | break; 61 | case SI_MESGQ: 62 | printf("mesgq\n"); 63 | break; 64 | case SI_ASYNCIO: 65 | printf("async io\n"); 66 | break; 67 | case SI_SIGIO: 68 | printf("sigio\n"); 69 | break; 70 | case SI_TKILL: 71 | printf("t[g]kill\n"); 72 | break; 73 | // other poss values si_code can have for SIGSEGV 74 | case SEGV_MAPERR: 75 | printf("SEGV_MAPERR: address not mapped to object\n"); 76 | break; 77 | case SEGV_ACCERR: 78 | printf("SEGV_ACCERR: invalid permissions for mapped object\n"); 79 | break; 80 | default: 81 | printf("-none-\n"); 82 | } 83 | printf(" Faulting addr=0x" ADDR_FMT "\n", (ADDR_TYPE) siginfo->si_addr); 84 | 85 | #if 1 86 | exit (1); 87 | #else 88 | abort(); 89 | #endif 90 | } 91 | 92 | static void usage(char *nm) 93 | { 94 | fprintf(stderr, "Usage: %s u|k r|w\n" 95 | "u => user mode\n" 96 | "k => kernel mode\n" 97 | " r => read attempt\n" " w => write attempt\n", nm); 98 | } 99 | 100 | 101 | int main(int argc, char **argv) 102 | { 103 | struct sigaction act; 104 | 105 | if (argc != 3) { 106 | usage(argv[0]); 107 | exit(1); 108 | } 109 | //act.sa_handler = myfault; 110 | act.sa_sigaction = myfault; 111 | act.sa_flags = SA_RESTART | SA_SIGINFO; 112 | sigemptyset(&act.sa_mask); 113 | if (sigaction(SIGSEGV, &act, 0) == -1) { 114 | perror("sigaction"); 115 | exit(1); 116 | } 117 | 118 | if ((tolower(argv[1][0]) == 'u') && tolower(argv[2][0] == 'r')) { 119 | ADDR_TYPE *uptr = (ADDR_TYPE *) rubbish_uaddr; // arbitrary userspace virtual addr 120 | printf 121 | ("Attempting to read contents of arbitrary usermode va uptr = 0x" ADDR_FMT ":\n", 122 | (ADDR_TYPE) uptr); 123 | printf("*uptr = 0x" ADDR_FMT "\n", *uptr); // just reading 124 | } else if ((tolower(argv[1][0]) == 'u') && tolower(argv[2][0] == 'w')) { 125 | ADDR_TYPE *uptr = (ADDR_TYPE *) & main; 126 | printf 127 | ("Attempting to write into arbitrary usermode va uptr (&main actually) = 0x" ADDR_FMT ":\n", 128 | (ADDR_TYPE) uptr); 129 | *uptr = 40; // writing 130 | } else if ((tolower(argv[1][0]) == 'k') && tolower(argv[2][0] == 'r')) { 131 | ADDR_TYPE *kptr = (ADDR_TYPE *) rubbish_kaddr; // arbitrary kernel virtual addr 132 | printf 133 | ("Attempting to read contents of arbitrary kernel va kptr = 0x" ADDR_FMT ":\n", 134 | (ADDR_TYPE) kptr); 135 | printf("*kptr = 0x" ADDR_FMT "\n", *kptr); // just reading 136 | } else if ((tolower(argv[1][0]) == 'k') && tolower(argv[2][0] == 'w')) { 137 | ADDR_TYPE *kptr = (ADDR_TYPE *) rubbish_kaddr; // arbitrary kernel virtual addr 138 | printf 139 | ("Attempting to write into arbitrary kernel va kptr = 0x" ADDR_FMT ":\n", 140 | (ADDR_TYPE) kptr); 141 | *kptr = 0x62; // writing 142 | } else 143 | usage(argv[0]); 144 | exit(0); 145 | } 146 | 147 | /* vi: ts=4 */ 148 | -------------------------------------------------------------------------------- /mm/xtras/trick.c: -------------------------------------------------------------------------------- 1 | /* 2 | * src: http://vulnfactory.org/blog/2013/02/06/a-linux-memory-trick/ 3 | * 4 | It 'should' segfault. Once it does, look up dmesg: 5 | 6 | "... deliberately causes an access violation on a mapped kernel address, 7 | resulting in an error code of 5 (a read violation from user mode on a 8 | present page). The second invocation causes an access violation on an 9 | unmapped kernel address, resulting in an error code of 4 (a read 10 | violation from user mode on a non-present page). ..." 11 | */ 12 | #include 13 | #include 14 | 15 | int main(int argc, char **argv) 16 | { 17 | int *ptr, foo; 18 | if (argc ==1) { 19 | fprintf(stderr,"Usage: %s kernel|user-va\n", argv[0]); 20 | exit(1); 21 | } 22 | ptr = (int *)strtoul(argv[1], NULL, 16); 23 | foo = *ptr; 24 | } 25 | -------------------------------------------------------------------------------- /mm/xtras/vm_vas/vm_user.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef unsigned int u32; 6 | typedef long unsigned int u64; 7 | 8 | int g=5, u; 9 | 10 | int main(int argc, char **argv) 11 | { 12 | int local; 13 | char *heapptr = malloc(100); 14 | 15 | // OS bits 16 | // for cpu use 'lscpu' 17 | //printf("wordsize : %d\n", __WORDSIZE); 18 | 19 | if (__WORDSIZE == 32) { 20 | printf("32-bit: &main = 0x%08x &g = 0x%08x &u = 0x%08x &heapptr = 0x%08x &loc = 0x%08x\n", 21 | (u32)main, (u32)&g, (u32)&u, (u32)heapptr, (u32)&local); 22 | } else if (__WORDSIZE == 64) { 23 | printf("64-bit: &main = 0x%016lx &g = 0x%016lx &u = %016lx &heapptr = 0x%016lx &loc = 0x%016lx\n", 24 | (u64)main, (u64)&g, (u64)&u, (u64)heapptr, (u64)&local); 25 | } 26 | 27 | free(heapptr); 28 | return 0; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /sched/cgroups/cpu_eg/cpucg_test-arm32qemu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # A quick test case for (CPU) CGroups. 3 | # cpucg_test.sh 4 | # (c) Kaiwan NB, kaiwanTECH 5 | # 6 | CGMNT=cgroup #cgroupfs 7 | OUT1=1stjob.txt 8 | OUT2=2ndjob.txt 9 | 10 | cpu_resctrl_try() 11 | { 12 | echo "[+] Running j1 and j2 now ..." 13 | #--- Run a job j1 14 | rm -f j1 15 | ln -sf ${TD}/simp.sh j1 16 | ./j1 1 >${OUT1} & 17 | j1pid=$(ps -A|grep j1|head -n1|awk '{print $1}') 18 | 19 | #--- Create a group called 'g1', put j1 there making cpu share v small 20 | rm -rf ${CGMNT}/cpu/g1 21 | mkdir ${CGMNT}/cpu/g1 22 | echo ${j1pid} > ${CGMNT}/cpu/g1/tasks 23 | echo 52 > ${CGMNT}/cpu/g1/cpu.shares # ~5% 24 | 25 | #--- Run a job j2 26 | rm -f j2 27 | ln -sf ${TD}/simp.sh j2 28 | ./j2 500 >${OUT2} & 29 | j2pid=$(ps -A|grep j2|head -n1|awk '{print $1}') 30 | #--- Create a group called 'g2', put j2 there making cpu share large 31 | rm -rf ${CGMNT}/cpu/g2 32 | mkdir ${CGMNT}/cpu/g2 33 | echo ${j2pid} > ${CGMNT}/cpu/g2/tasks 34 | echo 3096 > ${CGMNT}/cpu/g2/cpu.shares # ~75% 35 | 36 | } 37 | 38 | setup_cgs() 39 | { 40 | # Already setup? 41 | mount |grep '${CGMNT}' > /dev/null && return 42 | #mount |grep 'type cgroup' > /dev/null && return 43 | 44 | echo 45 | echo "[+] ---Setup and mount Cgroup fs's ..." 46 | [ ! -d ${CGMNT} ] && mkdir ${CGMNT} 47 | 48 | # bash array support not available in ash! 49 | for d in ${CGMNT}/cpu ${CGMNT}/cpuacct ${CGMNT}/cpuset ${CGMNT}/freezer 50 | do 51 | db=$(basename $d) 52 | #echo "${db}" 53 | [ ! -d $db ] && mkdir $db 2>/dev/null 54 | mcmd="mount -t cgroup -o ${db} none ./${CGMNT}/${db}" 55 | echo "${mcmd}" 56 | eval ${mcmd} || { 57 | echo "mount failed, aborting..." 58 | rm -rf ${CGMNT}; rmdir ${db} 59 | exit 1 60 | } 61 | done 62 | mount |grep ${CGMNT} 63 | cd ${TD} 64 | 65 | # Kill any stale instances of job1 and job2 66 | j1pid=$(ps -A|grep j1|head -n1|awk '{print $1}') 67 | [ ! -z ${j1pid} ] && kill ${j1pid} 68 | j2pid=$(ps -A|grep j2|head -n1|awk '{print $1}') 69 | [ ! -z ${j2pid} ] && kill ${j2pid} 70 | rm -f ${OUT1} ${OUT2} 71 | } 72 | 73 | 74 | ### "main" here 75 | 76 | [ $(id -u) -ne 0 ] && { 77 | echo "$0: need root." 78 | exit 1 79 | } 80 | echo "[+] ---Cgroup kernel support:" 81 | [ -f /proc/config.gz ] && { 82 | zcat /proc/config.gz |grep -i cgroup || { 83 | echo "$0: Cgroup support not builtin to kernel?? Aborting..." 84 | exit 1 85 | } 86 | } 87 | 88 | TD=$(pwd) 89 | 90 | setup_cgs 91 | cpu_resctrl_try 92 | -------------------------------------------------------------------------------- /sched/cgroups/cpu_eg/simp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 1st param is starting # 3 | [ $# -ne 1 ] && { 4 | echo "Usage: $0 " 5 | exit 1 6 | } 7 | max=9999 8 | [ $1 -ge $max ] && { 9 | echo "Param $1 >= max ($max)" 10 | exit 1 11 | } 12 | 13 | delay_loop() 14 | { 15 | for x in $(seq 1 10); do 16 | for y in $(seq 1 200); do 17 | z=$(((y+10000)*x/y)) 18 | done 19 | done 20 | } 21 | 22 | i=$1 23 | while [ $i -le $max ] 24 | do 25 | echo -n "$i " 26 | i=$((i+1)) 27 | delay_loop 28 | done 29 | 30 | -------------------------------------------------------------------------------- /sched/chrt_taskset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Display sched policy & priority of all processes 3 | 4 | which chrt || { 5 | echo "'chrt' not installed?" 6 | exit 1 7 | } 8 | which taskset || { 9 | echo "'taskset' not installed?" 10 | exit 1 11 | } 12 | 13 | for p in $(ps -A|awk '{print $1}') 14 | do 15 | chrt -p $p 16 | taskset -p $p 17 | echo 18 | done 19 | 20 | -------------------------------------------------------------------------------- /sched/core_running_what.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # core_running_what.sh 3 | name=$(basename $0) 4 | 5 | # Show thread(s) running on cpu core 'n' - func c'n' 6 | function c0() 7 | { 8 | ps -eLF |awk '{ if($5==0) print $0}' 9 | } 10 | function c1() 11 | { 12 | ps -eLF |awk '{ if($5==1) print $0}' 13 | } 14 | function c2() 15 | { 16 | ps -eLF |awk '{ if($5==2) print $0}' 17 | } 18 | function c3() 19 | { 20 | ps -eLF |awk '{ if($5==3) print $0}' 21 | } 22 | 23 | # "main" .. 24 | echo "Run this script as 25 | source ${name} 26 | and then run the builtin functions 'c0', 'c1', 'c2', ... 27 | to see which threads are running on which core." 28 | -------------------------------------------------------------------------------- /sched/ftrace/ftrace1_generic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Ftrace demo via a bash script 3 | # We ftrace a 'sleep 1' 4 | # 5 | # (c) Kaiwan NB, kaiwanTECH 6 | # May16 7 | 8 | reset_ftrc() 9 | { 10 | echo 0 > tracing_on 11 | echo nop > current_tracer 12 | echo 1 > options/latency-format 13 | echo 0 > options/context-info 14 | echo 0 > options/userstacktrace 15 | echo 0 > tracing_max_latency # reset 16 | 17 | echo "" > set_ftrace_filter 18 | echo "" > set_ftrace_notrace 19 | echo "" > set_ftrace_pid 20 | echo 2048 > buffer_size_kb 21 | } 22 | 23 | init_ftrc() 24 | { 25 | echo function_graph > current_tracer 26 | echo 1 > options/latency-format 27 | echo 1 > options/context-info 28 | echo funcgraph-proc > trace_options 29 | echo 1 > options/userstacktrace 30 | 31 | echo "" > set_ftrace_filter 32 | echo "" > set_ftrace_notrace 33 | echo "" > set_ftrace_pid 34 | echo 20480 > buffer_size_kb 35 | } 36 | 37 | PFX=/sys/kernel/debug 38 | TRC=${PFX}/tracing 39 | TMPFILE=/tmp/trc.txt 40 | 41 | ## "main" here 42 | [ `id -u` -ne 0 ] && { 43 | echo "Need to be root." 44 | exit 1 45 | } 46 | 47 | echo "Checking for ftrace support ..." 48 | mount | grep debugfs > /dev/null 2>&1 || { 49 | echo "debugfs not mounted? Pl mount the debugfs filesystem & retry. Aborting..." 50 | exit 1 51 | } 52 | TRC=$(mount|grep debugfs |awk '{print $3}') 53 | [ ! -d ${TRC} ] && { 54 | echo "\"${TRC}\" not present? Aborting..." 55 | exit 2 56 | } 57 | 58 | TRC=${TRC}/tracing 59 | cd ${TRC} || exit 3 60 | echo "ftrace ok, init ..." 61 | reset_ftrc 62 | init_ftrc 63 | #echo "Available tracers:" 64 | #cat available_tracers 65 | 66 | echo "Running ..." 67 | 68 | # trace 69 | 70 | echo 1 > tracing_on ; sleep 1 ; echo 0 > tracing_on 71 | cp trace ${TMPFILE} 72 | 73 | echo "Done. Trace file in ${TMPFILE}" 74 | ls -lh ${TMPFILE} 75 | reset_ftrc 76 | -------------------------------------------------------------------------------- /sched/ftrace/ftrace_anycmd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ftrace1.sh 3 | # A simple demo of using the powerful kernel ftrace facility. 4 | # The program the user passes is ftrace-d; BUT, it's simplistic: 5 | # whatever else is running at the time is traced as well. 6 | # 7 | # Kaiwan NB, kaiwanTECH, May16. 8 | # License: MIT 9 | name=$(basename $0) 10 | TRC_FILE=/tmp/trc.txt 11 | 12 | reset_ftrc() 13 | { 14 | echo 0 > tracing_on 15 | echo nop > current_tracer 16 | echo 1 > options/latency-format 17 | echo 0 > options/context-info 18 | echo 0 > options/userstacktrace 19 | echo 0 > tracing_max_latency # reset 20 | 21 | echo "" > set_ftrace_filter 22 | echo "" > set_ftrace_notrace 23 | echo "" > set_ftrace_pid 24 | echo 2048 > buffer_size_kb 25 | } 26 | 27 | init_ftrc() 28 | { 29 | echo function_graph > current_tracer 30 | echo 1 > options/latency-format 31 | echo 1 > options/context-info 32 | echo funcgraph-proc > trace_options 33 | echo 1 > options/userstacktrace 34 | 35 | echo "" > set_ftrace_filter 36 | echo "" > set_ftrace_notrace 37 | echo "" > set_ftrace_pid 38 | echo 20480 > buffer_size_kb 39 | } 40 | 41 | 42 | ## "main" here 43 | [ `id -u` -ne 0 ] && { 44 | echo "${name}: Need to be root." 45 | exit 1 46 | } 47 | echo "Checking for ftrace support ..." 48 | mount | grep debugfs > /dev/null 2>&1 || { 49 | echo "${name}: debugfs not mounted? Aborting..." 50 | exit 1 51 | } 52 | [ ! -d /sys/kernel/debug ] && { 53 | echo "${name}: /sys/kernel/debug not mounted as debugfs? Aborting..." 54 | exit 2 55 | } 56 | [ $# -lt 1 ] && { 57 | echo "Usage: ${name} program-to-ftrace 58 | Eg. sudo ./${name} ps -LA 59 | [NOTE: other stuff running _also_ gets ftraced (this is non-exclusive). 60 | If you'd prefer _only_ tracing a particular process, it's easier to setup 61 | with trace-cmd]" 62 | exit 3 63 | } 64 | 65 | cd /sys/kernel/debug/tracing || exit 3 66 | echo "${name}: ftrace ok, init ..." 67 | reset_ftrc 68 | init_ftrc 69 | #echo "Available tracers:" 70 | #cat available_tracers 71 | 72 | echo "${name}: Running \"$@\" as user ${SUDO_USER}:" 73 | 74 | #--- perform the ftrace 75 | echo 1 > tracing_on ; sudo -u ${SUDO_USER} "$@" ; echo 0 > tracing_on 76 | #echo 1 > tracing_on ; eval "$@" ; echo 0 > tracing_on 77 | #echo 1 > tracing_on ; sleep 1 ; echo 0 > tracing_on 78 | #--- 79 | echo "${name}: Setting up ${TRC_FILE}, pl wait ..." 80 | cp trace ${TRC_FILE} 81 | echo "${name}: Done. Trace file in ${TRC_FILE}" 82 | ls -lh ${TRC_FILE} 83 | 84 | ########################################### 85 | # TIP: 86 | # filter out everything else by: 87 | grep "^ [0-9]).*" ${TRC_FILE} 88 | # NOTE: the process-name is truncated to just 7 chars, so don't use 89 | # any more than 7 in the grep regex! 90 | ########################################### 91 | 92 | reset_ftrc 93 | exit 0 94 | -------------------------------------------------------------------------------- /sched/ftrace/ftrc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ftrc.sh 3 | # Simple wrapper to use kernel ftrace facility. 4 | 5 | trap 'echo 0 > ${PFX}/tracing_on ; popd > /dev/null' INT QUIT 6 | 7 | name=$(basename $0) 8 | PFX=/sys/kernel/debug/tracing 9 | TRACE_INTERVAL=5 10 | 11 | if [ `id -u` -ne 0 ]; then 12 | echo "$name: need to be root." 13 | exit 1 14 | fi 15 | 16 | if [ $# -ne 1 ]; then 17 | echo "Usage: $name ftrace-interval-in-sec" 18 | exit 1 19 | fi 20 | TRACE_INTERVAL=$1 21 | 22 | pushd . >/dev/null 23 | cd ${PFX} 24 | 25 | echo "Select tracer from the list:" 26 | cat ${PFX}/available_tracers 27 | read tracer 28 | echo "tracer = $tracer" 29 | #TODO- validity check 30 | echo "${tracer}" > ${PFX}/current_tracer 31 | 32 | echo -n "[current_tracer] Current Tracer is: " 33 | cat ${PFX}/current_tracer 34 | echo "[trace_options] Current Trace Options are: " 35 | cat ${PFX}/trace_options 36 | echo 37 | 38 | if [ ${tracer} == "function_graph" ]; then 39 | echo "[set_graph_function] Current function(s) traced are: " 40 | cat /sys/kernel/debug/tracing/set_graph_function 41 | echo "Type in your own functions (space-separated); [Enter] keeps default: " 42 | read graph_funcs 43 | if [ -n "${graph_funcs}" ]; then 44 | for func in ${graph_funcs} 45 | do 46 | echo "function: $func" 47 | echo "$func" >> /sys/kernel/debug/tracing/set_graph_function 48 | done 49 | echo 50 | echo "New graph-traced functions are:" 51 | cat /sys/kernel/debug/tracing/set_graph_function 52 | fi 53 | fi 54 | 55 | 56 | echo -n "Confirm Trace options above and START trace? [Y/n]: " 57 | read reply 58 | if [[ $reply == "n" ]] || [[ $reply == "N" ]]; then 59 | echo "$name: aborting now..." 60 | exit 1 61 | fi 62 | echo 63 | echo "Will now ftrace for $TRACE_INTERVAL seconds..." 64 | echo "To manually Stop, ^C" 65 | echo 66 | echo "Starting trace now..." 67 | echo 1 > ${PFX}/tracing_on 68 | 69 | sleep $TRACE_INTERVAL 70 | echo 0 > ${PFX}/tracing_on 71 | 72 | #tail -f ${PFX}/trace >> /tmp/ftrace_log.txt 73 | cat ${PFX}/trace > /tmp/ftrace_log.txt 74 | popd > /dev/null 75 | 76 | -------------------------------------------------------------------------------- /sched/query_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Query the scheduling attributes (policy and RT (static) priority) of 3 | # all processes currently alive on the system. 4 | # Just a simple wrapper around chrt. 5 | # 6 | # Tip: Pipe this o/p to grep for FIFO / RR tasks.. 7 | # Also note that a multithreaded process shows up as several same PIDs 8 | # (resolve these using ps -eLf - to see actual PIDs of threads). 9 | 10 | for p in `ps -A -To pid` 11 | do 12 | # ps -A|grep $p|awk '{print $4}' 13 | chrt -p $p 14 | taskset -p $p 15 | done 16 | 17 | -------------------------------------------------------------------------------- /sched/sched_pthrd_app/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for sched_pthread 2 | sched_pthrd: sched_pthrd.c 3 | gcc sched_pthrd.c -o sched_pthrd -Wall -O0 -pthread 4 | sudo setcap CAP_SYS_NICE+eip ./sched_pthrd 5 | getcap ./sched_pthrd 6 | clean: 7 | rm -fv sched_pthrd 8 | -------------------------------------------------------------------------------- /sched/sched_pthrd_app/libpk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * libpk.h 3 | * 4 | * Small collection of common routines for pthread programs; 5 | * 6 | * Routines/macros: 7 | * 8 | * 1. DELAY_LOOP 9 | * 10 | * Last updated: Dec 2003 11 | * kaiwan 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include // HZ 19 | 20 | static inline void beep(int what) 21 | { 22 | char buf[2]; 23 | buf[0] = (char)(what); 24 | buf[1] = '\0'; 25 | write(STDOUT_FILENO, buf, 1); 26 | } 27 | 28 | /* 29 | * @val : ASCII value to print 30 | * @loop_count : times to loop around 31 | */ 32 | #define DELAY_LOOP(val,loop_count) \ 33 | { \ 34 | int c=0;\ 35 | unsigned int for_index,inner_index; \ 36 | double x; \ 37 | for(for_index=0;for_index 7 | #include 8 | #include 9 | #include 10 | #include "libpk.h" 11 | 12 | #define DEBUG 1 // 0 to switch off messages 13 | #ifdef DEBUG 14 | #define MSG(string, args...) fprintf(stderr, "%s:%s : " string, __FILE__, __FUNCTION__, ##args) 15 | #else 16 | #define MSG(string, args...) 17 | #endif 18 | 19 | void *thrd_p2(void *msg) 20 | { 21 | struct sched_param p; 22 | /* The structure used is defined in linux/sched.h as: 23 | * struct sched_param { 24 | * int sched_priority; 25 | * }; 26 | */ 27 | 28 | printf(" RT Thread p2 (LWP %d) here in function thrd_p2\n\ 29 | setting sched policy to SCHED_FIFO and RT priority to %ld in 2 seconds..\n", 30 | getpid(), (long)msg); 31 | sleep(2); 32 | 33 | /* pthread_setschedparam(3) internally becomes the syscall 34 | * sched_setscheduler(2) (or sched_setattr(2)). 35 | */ 36 | p.sched_priority = (long)msg; 37 | if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &p)) 38 | perror("pthread_setschedparam"); 39 | 40 | puts(" p2: working"); 41 | DELAY_LOOP('2', 350); 42 | 43 | puts(" p2: exiting.."); 44 | pthread_exit(NULL); 45 | } 46 | 47 | void *thrd_p3(void *msg) 48 | { 49 | struct sched_param p; 50 | /* The structure used is defined in linux/sched.h as: 51 | * struct sched_param { 52 | * int sched_priority; 53 | * }; 54 | */ 55 | long pri = (long)msg; 56 | 57 | pri += 10; 58 | printf(" RT Thread p3 (LWP %d) here in function thrd_p3\n" 59 | " setting sched policy to SCHED_FIFO and RT priority HIGHER to %ld in 4 seconds..\n", 60 | getpid(), pri); 61 | 62 | /* pthread_setschedparam(3) internally becomes the syscall 63 | * sched_setscheduler(2) (or sched_setattr(2)). 64 | */ 65 | p.sched_priority = pri; 66 | if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &p)) 67 | perror("pthread_setschedparam"); 68 | sleep(4); 69 | 70 | puts(" p3: working"); 71 | DELAY_LOOP('3', 210); 72 | 73 | puts(" p3: exiting.."); 74 | pthread_exit(NULL); 75 | } 76 | 77 | int main(int argc, char **argv) 78 | { 79 | pthread_t p2, p3; 80 | int r, min, max; 81 | long rt_pri=1; 82 | 83 | if (argc == 1) 84 | fprintf(stderr, "Usage: %s realtime-priority\n", 85 | argv[0]), exit(1); 86 | min = sched_get_priority_min(SCHED_FIFO); 87 | if (min == -1) { 88 | perror("sched_get_priority_min failure"); 89 | exit(1); 90 | } 91 | max = sched_get_priority_max(SCHED_FIFO); 92 | if (max == -1) { 93 | perror("sched_get_priority_max failure"); 94 | exit(1); 95 | } 96 | MSG("SCHED_FIFO priority range is %d to %d\n", min, max); 97 | 98 | rt_pri = atoi(argv[1]); 99 | if ((rt_pri < min) || (rt_pri > (max - 10))) { 100 | fprintf(stderr, 101 | "%s: Priority value passed (%ld) out of range [%d-%d].\n", 102 | argv[0], rt_pri, min, (max - 10)); 103 | exit(1); 104 | } 105 | 106 | printf("\nNote: to create true RT threads, you need to run this \ 107 | program as superuser\n"); 108 | printf("main thread (%d): now creating realtime pthread p2..\n", 109 | getpid()); 110 | r = pthread_create(&p2, // thread id 111 | NULL, // thread attributes (use default) 112 | thrd_p2, // function to execute 113 | (void *)rt_pri); // argument to function 114 | if (r) 115 | perror("pthread creation"), exit(1); 116 | 117 | printf("main thread (%d): now creating realtime pthread p3..\n", 118 | getpid()); 119 | r = pthread_create(&p3, // thread id 120 | NULL, // thread attributes (use default) 121 | thrd_p3, // function to execute 122 | (void *)rt_pri); // argument to function 123 | if (r) 124 | perror("pthread creation"), exit(1); 125 | 126 | DELAY_LOOP('m', 400); 127 | pthread_exit(NULL); 128 | } 129 | 130 | // end sched_pthrd.c 131 | -------------------------------------------------------------------------------- /sched/show_runnable/Readme.txt: -------------------------------------------------------------------------------- 1 | show_runnable/rq.sh 2 | 3 | Simple shell script that helps us see the CFS runqueues being manipulated... 4 | 5 | Usage: 6 | ------ 7 | 8 | $ ./rq.sh 9 | Usage: ./rq.sh 0|1 10 | 0 => show Only our three runnable/running processes t1, t2, t3 11 | 1 => show system-wide runnable/running processes 12 | $ ./rq.sh 0 13 | 14 | task PID tree-key switches prio exec-runtime sum-exec sum-sleep Task Group 15 | ------------------------------------------------------------------------------------------------------------------------------------- 16 | R t3 1987 1239609.260059 646 120 1239609.260059 74.800633 435.434613 0 /autogroup-329 17 | R t3 1987 1240177.646328 1007 120 1240177.646328 117.246375 646.382100 0 /autogroup-329 18 | R t3 1987 1241311.855841 1728 120 1241311.855841 202.644682 1068.813948 0 /autogroup-329 19 | R t3 1987 1241875.994656 2087 120 1241875.994656 245.283156 1279.982995 0 /autogroup-329 20 | R t2 1986 1242439.905870 2447 120 1242439.905870 287.107495 1490.694039 0 /autogroup-329 21 | R t3 1987 1243571.227588 3170 120 1243571.227588 372.996689 1912.998723 0 /autogroup-329 22 | R t2 1986 1244135.974022 3526 120 1244135.974022 414.978844 2124.373590 0 /autogroup-329 23 | R t3 1987 1245839.032275 4610 120 1245839.032275 542.043246 2759.386630 0 /autogroup-329 24 | ^C$ 25 | 26 | 27 | Notice how the 3rd column, which is 'tree-key', which is actually the 28 | se->vruntime, changes. It's _not_ necessarily a monotonically increasing value. 29 | 30 | -------------------------------------------------------------------------------- /sched/show_runnable/rq.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | trap 'pkill t1; pkill t2; pkill t3' INT QUIT EXIT 3 | 4 | [ $# -ne 1 ] && { 5 | echo "Usage: $0 0|1 6 | 0 => show Only our three runnable/running processes t1, t2, t3 7 | 1 => show system-wide runnable/running processes " 8 | exit 1 9 | } 10 | SCHED_FILE=/sys/kernel/debug/sched/debug 11 | [[ $(id -u) -ne 0 ]] && { 12 | echo "need root to view ${SCHED_FILE}" ; exit 1 13 | } 14 | 15 | taskset -c 02 ./t1 a > /dev/null & 16 | taskset -c 02 ./t2 a > /dev/null & 17 | taskset -c 02 ./t3 a > /dev/null & 18 | 19 | HDR=" 20 | task PID tree-key switches prio exec-runtime sum-exec sum-sleep Task Group 21 | -------------------------------------------------------------------------------------------------------------------------------------" 22 | echo "${HDR}" 23 | [ $1 -eq 0 ] && ./show_rq.sh |grep "t[1-3]" || [ $1 -eq 1 ] && ./show_rq.sh 24 | 25 | -------------------------------------------------------------------------------- /sched/show_runnable/show_rq.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | SCHED_FILE=/sys/kernel/debug/sched/debug 3 | DELAYSEC=.25 4 | [[ $(id -u) -ne 0 ]] && { 5 | echo "need root to view ${SCHED_FILE}" ; exit 1 6 | } 7 | while [ true ] 8 | do 9 | egrep '^ *R ' ${SCHED_FILE} # show only runnable/running 10 | #egrep '^R ' /proc/sched_debug # show only runnable/running 11 | sleep $DELAYSEC 12 | done 13 | 14 | #egrep -A4 'tree-key' /proc/sched_debug |egrep -v 'task.*PID.*tree|----------|cpu#.' 15 | -------------------------------------------------------------------------------- /sched/show_runnable/t1: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: $0 char-to-display" 5 | exit 1 6 | fi 7 | 8 | echo "PID: $$" 9 | echo 10 | while [ true ] 11 | do 12 | echo -n $1 13 | #usleep 1000 14 | # do some junk, spend some time... 15 | for i in `seq 1 500` 16 | do 17 | tmp=$(($i+5)) 18 | done 19 | done 20 | 21 | -------------------------------------------------------------------------------- /sched/show_runnable/t2: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: $0 char-to-display" 5 | exit 1 6 | fi 7 | 8 | echo "PID: $$" 9 | echo 10 | while [ true ] 11 | do 12 | echo -n $1 13 | #usleep 1000 14 | # do some junk, spend some time... 15 | for i in `seq 1 500` 16 | do 17 | tmp=$(($i+5)) 18 | done 19 | done 20 | 21 | -------------------------------------------------------------------------------- /sched/show_runnable/t3: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: $0 char-to-display" 5 | exit 1 6 | fi 7 | 8 | echo "PID: $$" 9 | echo 10 | while [ true ] 11 | do 12 | echo -n $1 13 | #usleep 1000 14 | # do some junk, spend some time... 15 | for i in `seq 1 500` 16 | do 17 | tmp=$(($i+5)) 18 | done 19 | done 20 | 21 | -------------------------------------------------------------------------------- /sched/show_runnable/task.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: $0 char-to-display" 5 | exit 1 6 | fi 7 | 8 | echo "PID: $$" 9 | echo 10 | while [ true ] 11 | do 12 | echo -n $1 13 | #usleep 1000 14 | # do some junk, spend some time... 15 | for i in `seq 1 500` 16 | do 17 | tmp=$(($i+5)) 18 | done 19 | done 20 | 21 | -------------------------------------------------------------------------------- /show_compile_flags: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # show_compile_flags 3 | # 4 | # Notes: from my LKD book: 5 | # ... 6 | # Further, and very useful, you can leverage readelf(1) to determine the 7 | # DWARF format debug information embedded within the binary Executable 8 | # and Linker Format (ELF) file. This can be particularly useful to figure out 9 | # exactly which compiler flags your binary executable or kernel module has been 10 | # built with. You can do so like this: 11 | # readelf --debug-dump | grep producer 12 | # 13 | # Note that this technique typically works only when debug info is enabled; 14 | # further, when working with a different target architecture (for example, ARM), 15 | # you'll need to run that toolchain's version: ${CROSS_COMPILE}readelf. 16 | name=$(basename $0) 17 | set -euo pipefail 18 | 19 | [ $# -ne 1 ] && { 20 | echo "Usage: ${name} ELF-file (executable or module)" 21 | exit 1 22 | } 23 | echo -n "Current kernel has CONFIG_DEBUG_INFO=y ? " 24 | ans=$(grep -w CONFIG_DEBUG_INFO /boot/config-$(uname -r) |cut -d'=' -f2) 25 | [ "${ans}" = "y" ] && echo "yes" || echo "no" 26 | echo 27 | readelf --debug-dump $1 | grep producer 28 | 29 | -------------------------------------------------------------------------------- /show_monolithic/show_monolithic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // for current 4 | 5 | MODULE_LICENSE("Dual MIT/GPL"); 6 | 7 | static int __init hello_init(void) 8 | { 9 | pr_alert("init: Process context :: %s PID %d\n", 10 | current->comm, current->pid); 11 | #if 0 12 | dump_stack(); 13 | #endif 14 | return 0; // success 15 | } 16 | 17 | static void __exit hello_exit(void) 18 | { 19 | pr_alert("exit: Process context :: %s PID %d\n", 20 | current->comm, current->pid); 21 | #if 0 22 | dump_stack(); 23 | #endif 24 | } 25 | 26 | module_init(hello_init); 27 | module_exit(hello_exit); 28 | 29 | -------------------------------------------------------------------------------- /taskdtl/taskdtl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaiwan/L2_kernel_trg/9af35bd2efa7c21688eb9998df010993e3114477/taskdtl/taskdtl.png -------------------------------------------------------------------------------- /taskdtl/taskdtl_miscdrv/cr8devnode.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # cr8devnode.sh 3 | # Simple utility script to create the device node for the miscdrv_rdwr 'misc' 4 | # class device driver 5 | name=$(basename $0) 6 | OURMODNAME="taskdtl_miscdrv" 7 | DEVNODE=/dev/taskdtl 8 | 9 | MAJOR=10 # misc class is always major # 10 10 | unalias dmesg 2>/dev/null 11 | MINOR=$(sudo dmesg |grep "${OURMODNAME}\:minor\=" |cut -d"=" -f2) 12 | [ -z "${MINOR}" ] && { 13 | echo "${name}: failed to retrieve the minor #, aborting ..." 14 | exit 1 15 | } 16 | echo "minor number is ${MINOR}" 17 | 18 | sudo rm -f ${DEVNODE} # rm any stale instance 19 | sudo mknod ${DEVNODE} c ${MAJOR} ${MINOR} 20 | sudo chmod 0666 ${DEVNODE} 21 | ls -l ${DEVNODE} 22 | exit 0 23 | -------------------------------------------------------------------------------- /taskdtl/taskdtl_miscdrv/run_taskdtl_miscdrv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | name=$(basename $0) 3 | KMOD=taskdtlv2 4 | 5 | display_all() 6 | { 7 | echo "${name}: WARNING! displaying ALL threads task structure details can 8 | result in the kernel log buffer getting overwritten (and it will take a while)" 9 | 10 | i=1 11 | IFS=$'\n' 12 | for rec in $(ps -LA) 13 | do 14 | [ $i -eq 1 ] && { # skip ps's header 15 | let i=i+1 16 | continue 17 | } 18 | 19 | # 'grok' & extract it, and ... 20 | #pid=$(echo "${rec}" |awk '{print $1}') 21 | tid=$(echo "${rec}" |awk '{print $2}') 22 | echo "${i} :: TID = ${tid}" 23 | 24 | sudo bash -c "echo ${tid} > /dev/taskdtl" 25 | let i=i+1 26 | done 27 | sudo dmesg 28 | } 29 | 30 | ### "main" here 31 | [ $# -ne 1 ] && { 32 | echo "Usage: ${name} {PID} | all 33 | If the parameter is the PID of a process (or thread), that entity's task structure 34 | details will be displayed 35 | If the parameter is 'all', this will display the task structure details of all 36 | threads currently alive" 37 | exit 1 38 | } 39 | [ ! -w /dev/taskdtl ] && { 40 | echo "${name}: device node /dev/taskdtl does not exist or not writeable? trying via creator script..." 41 | ./cr8devnode.sh || exit 1 42 | } 43 | lsmod | grep -q ${KMOD} || { 44 | echo "${name}: kernel module \"${KMOD}\" not installed? inserting..." 45 | sudo rmmod ${KMOD} 46 | sudo dmesg -C 47 | sudo insmod ${KMOD}.ko 48 | } 49 | 50 | [ "$1" = "all" ] && { 51 | display_all 52 | exit 0 53 | } 54 | sudo bash -c "echo $1 > /dev/taskdtl" 55 | sudo dmesg 56 | -------------------------------------------------------------------------------- /taskdtl/taskdtl_raw/run_taskdtl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | KMOD=taskdtl 3 | [ $# -ne 1 ] && { 4 | echo "Usage: $0 PID" 5 | exit 1 6 | } 7 | sudo rmmod ${KMOD} 8 | sudo dmesg -C 9 | sudo insmod ${KMOD}.ko pid=$1 10 | sudo dmesg 11 | -------------------------------------------------------------------------------- /vcpu_check/vcpu_check.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ch5/timer_simple/timer_simple.c 3 | *************************************************************** 4 | * This program is part of the source code released for the book 5 | * "Linux Kernel Programming - Part 2" 6 | * (c) Author: Kaiwan N Billimoria 7 | * Publisher: Packt 8 | * GitHub repository: 9 | * https://github.com/PacktPublishing/Linux-Kernel-Programming-Part-2 10 | * 11 | * From: Ch 5 : Timers, kernel threads and more 12 | **************************************************************** 13 | * Brief Description: 14 | * A demo of a simple kernel timer in action. We make use of the from_timer() 15 | * to be able to access data from within the callback, and setup the timer to 16 | * keep expiring until our 'data' variable hits zero. 17 | * 18 | * For details, please refer the book, Ch 5. 19 | */ 20 | #define pr_fmt(fmt) "%s:%s(): " fmt, KBUILD_MODNAME, __func__ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "../convenient.h" 28 | 29 | #define INITIAL_VALUE 120 30 | 31 | MODULE_AUTHOR("Kaiwan N Billimoria"); 32 | MODULE_DESCRIPTION("A simple LKM to demo a (repeating) kernel timer"); 33 | MODULE_LICENSE("Dual MIT/GPL"); // or whatever 34 | MODULE_VERSION("0.1"); 35 | 36 | static struct st_ctx { 37 | struct timer_list tmr; 38 | int data; 39 | } ctx; 40 | static unsigned long exp_ms = 10; 41 | 42 | /* 43 | * ding() - our timer's callback function! 44 | */ 45 | static void ding(struct timer_list *timer) 46 | { 47 | struct st_ctx *priv = from_timer(priv, timer, tmr); 48 | /* from_timer() is in fact a wrapper around the well known 49 | * container_of() macro! This allows us to retrieve access to our 50 | * 'parent' driver context structure 51 | */ 52 | struct task_struct *p, *t; 53 | //u64 t1, t2; 54 | 55 | // Whoops! Bugfix- decrement even if DEBUG is off... 56 | //priv->data--; 57 | //pr_debug("timed out... data=%d\n", priv->data); 58 | 59 | //t1 = ktime_get_real_ns(); 60 | for_each_process_thread(p, t) { 61 | //PRINT_CTX(t); 62 | if (t->flags & PF_VCPU) { 63 | PRINT_CTX(t); 64 | pr_info("*** PF_VCPU set ***\n"); 65 | } 66 | /* else 67 | pr_info("%s:%d: PF_VCPU unset\n", t->comm, t->pid); 68 | */ 69 | } 70 | //t2 = ktime_get_real_ns(); 71 | //SHOW_DELTA(t2, t1); 72 | 73 | /* until countdown done, fire it again! */ 74 | //if (priv->data) 75 | mod_timer(&priv->tmr, jiffies + msecs_to_jiffies(exp_ms)); 76 | } 77 | 78 | static int __init timer_simple_init(void) 79 | { 80 | ctx.data = INITIAL_VALUE; 81 | 82 | /* Initialize our kernel timer */ 83 | ctx.tmr.expires = jiffies + msecs_to_jiffies(exp_ms); 84 | ctx.tmr.flags = 0; 85 | timer_setup(&ctx.tmr, ding, 0); 86 | 87 | pr_info("timer set to expire in %ld ms\n", exp_ms); 88 | add_timer(&ctx.tmr); /* Arm it; lets get going! */ 89 | 90 | return 0; /* success */ 91 | } 92 | 93 | static void __exit timer_simple_exit(void) 94 | { 95 | // Wait for possible timeouts to complete... and then delete the timer 96 | del_timer_sync(&ctx.tmr); 97 | pr_info("removed\n"); 98 | } 99 | 100 | module_init(timer_simple_init); 101 | module_exit(timer_simple_exit); 102 | --------------------------------------------------------------------------------