├── LDD3 ├── README ├── helloworld │ ├── Makefile │ ├── Module.symvers │ ├── helloworld.c │ └── modules.order └── scull_simple │ ├── Makefile │ ├── main.c │ ├── scull.h │ ├── scull.init │ ├── scull_load │ └── scull_unload ├── README ├── keyboard ├── LICENSE ├── Makefile ├── README ├── keyboardInt.c ├── keyboardInt.h ├── keyboard_mapping.h ├── keyboard_stats_load └── keyboard_stats_unload ├── proc_desc ├── Makefile ├── proc_desc.c ├── proc_desc.h ├── proc_desc_load └── proc_desc_unload └── random_notes.txt /LDD3/README: -------------------------------------------------------------------------------- 1 | This directory contains edited code from 'Linux Device Drivers' by Alessandro Rubini 2 | and Jonathan Corbet, published by by O'Reilly & Associates. 3 | 4 | I have edited to code to make it more understandable because they have clubbed many 5 | pieces together in one module. 6 | -------------------------------------------------------------------------------- /LDD3/helloworld/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # To build modules outside of the kernel tree, we run "make" 3 | # in the kernel source tree; the Makefile these then includes this 4 | # Makefile once again. 5 | # This conditional selects whether we are being included from the 6 | # kernel Makefile or not. 7 | ifeq ($(KERNELRELEASE),) 8 | 9 | # Assume the source tree is where the running kernel was built 10 | # You should set KERNELDIR in the environment if it's elsewhere 11 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 12 | # The current directory is passed to sub-makes as argument 13 | PWD := $(shell pwd) 14 | 15 | modules: 16 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 17 | 18 | modules_install: 19 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 20 | 21 | clean: 22 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 23 | 24 | .PHONY: modules modules_install clean 25 | 26 | else 27 | # called from kernel build system: just declare what our modules are 28 | obj-m := helloworld.o 29 | 30 | endif 31 | 32 | 33 | -------------------------------------------------------------------------------- /LDD3/helloworld/Module.symvers: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigith/Linux-Device-Drivers/8b9b8be034b6f11acc240dfe7c1410cb84a00e47/LDD3/helloworld/Module.symvers -------------------------------------------------------------------------------- /LDD3/helloworld/helloworld.c: -------------------------------------------------------------------------------- 1 | /* 2 | * helloworld.c -- simple 'Hello World' module 3 | * 4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet 5 | * Copyright (C) 2001 O'Reilly & Associates 6 | * Copyright (C) 2011 Vigith Maurice 7 | * 8 | * The source code in this file can be freely used, adapted, 9 | * and redistributed in source or binary form, so long as an 10 | * acknowledgment appears in derived source files. The citation 11 | * should list that the code comes from the book "Linux Device 12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published 13 | * by O'Reilly & Associates. No warranty is attached; 14 | * we cannot take responsibility for errors or fitness for use. 15 | * 16 | */ 17 | 18 | 19 | #include 20 | #include 21 | 22 | MODULE_LICENSE("Dual BSD/GPL"); 23 | 24 | static int __init hello_init(void) { 25 | printk(KERN_ALERT "Hello World\n"); 26 | } 27 | 28 | static void __exit hello_exit(void) { 29 | printk(KERN_ALERT "Goodbye World\n"); 30 | } 31 | 32 | module_init(hello_init); 33 | module_exit(hello_exit); 34 | -------------------------------------------------------------------------------- /LDD3/helloworld/modules.order: -------------------------------------------------------------------------------- 1 | kernel//media/sf_linux/lkp/helloworld/helloworld.ko 2 | -------------------------------------------------------------------------------- /LDD3/scull_simple/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(KERNELRELEASE),) 2 | # call from kernel build system 3 | 4 | scull-objs := main.o 5 | 6 | obj-m := scull.o 7 | 8 | else 9 | 10 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 11 | PWD := $(shell pwd) 12 | 13 | modules: 14 | $(MAKE) -C $(KERNELDIR) M=$(PWD) 15 | 16 | endif 17 | 18 | 19 | 20 | clean: 21 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.order *.symvers 22 | 23 | depend .depend dep: 24 | $(CC) $(EXTRA_CFLAGS) -M *.c > .depend 25 | 26 | 27 | ifeq (.depend,$(wildcard .depend)) 28 | include .depend 29 | endif 30 | 31 | -------------------------------------------------------------------------------- /LDD3/scull_simple/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c -- the bare scull char module 3 | * 4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet 5 | * Copyright (C) 2001 O'Reilly & Associates 6 | * Copyright (C) 2011 Vigith Maurice 7 | * 8 | * The source code in this file can be freely used, adapted, 9 | * and redistributed in source or binary form, so long as an 10 | * acknowledgment appears in derived source files. The citation 11 | * should list that the code comes from the book "Linux Device 12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published 13 | * by O'Reilly & Associates. No warranty is attached; 14 | * we cannot take responsibility for errors or fitness for use. 15 | * 16 | */ 17 | 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include /* printk() */ 24 | #include /* kmalloc() */ 25 | #include /* everything... */ 26 | #include /* error codes */ 27 | #include /* size_t */ 28 | 29 | #include /* O_ACCMODE */ 30 | #include 31 | #include 32 | 33 | #include /* cli(), *_flags */ 34 | #include /* copy_*_user */ 35 | 36 | #include "scull.h" /* local definitions */ 37 | 38 | /* 39 | * Our parameters which can be set at load time. 40 | */ 41 | 42 | int scull_major = SCULL_MAJOR; 43 | int scull_minor = 0; 44 | int scull_nr_devs = SCULL_NR_DEVS; /* number of bare scull devices */ 45 | int scull_quantum = SCULL_QUANTUM; 46 | int scull_qset = SCULL_QSET; 47 | 48 | module_param(scull_major, int, S_IRUGO); 49 | module_param(scull_minor, int, S_IRUGO); 50 | module_param(scull_nr_devs, int, S_IRUGO); 51 | module_param(scull_quantum, int, S_IRUGO); 52 | module_param(scull_qset, int, S_IRUGO); 53 | 54 | MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet, Vigith Maurice"); 55 | MODULE_LICENSE("Dual BSD/GPL"); 56 | 57 | struct scull_dev *scull_devices; /* allocated in scull_init_module */ 58 | 59 | 60 | /* 61 | * Empty out the scull device; must be called with the device 62 | * semaphore held. 63 | */ 64 | int scull_trim(struct scull_dev *dev) 65 | { 66 | struct scull_qset *next, *dptr; 67 | int qset = dev->qset; /* "dev" is not-null */ 68 | int i; 69 | 70 | for (dptr = dev->data; dptr; dptr = next) { /* all the list items */ 71 | if (dptr->data) { 72 | for (i = 0; i < qset; i++) 73 | kfree(dptr->data[i]); 74 | kfree(dptr->data); 75 | dptr->data = NULL; 76 | } 77 | next = dptr->next; 78 | kfree(dptr); 79 | } 80 | dev->size = 0; 81 | dev->quantum = scull_quantum; 82 | dev->qset = scull_qset; 83 | dev->data = NULL; 84 | return 0; 85 | } 86 | 87 | 88 | 89 | /* 90 | * Open and close 91 | */ 92 | 93 | int scull_open(struct inode *inode, struct file *filp) 94 | { 95 | struct scull_dev *dev; /* device information */ 96 | 97 | dev = container_of(inode->i_cdev, struct scull_dev, cdev); 98 | filp->private_data = dev; /* for other methods */ 99 | 100 | /* now trim to 0 the length of the device if open was write-only */ 101 | if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) { 102 | if (down_interruptible(&dev->sem)) 103 | return -ERESTARTSYS; 104 | scull_trim(dev); /* ignore errors */ 105 | up(&dev->sem); 106 | } 107 | return 0; /* success */ 108 | } 109 | 110 | int scull_release(struct inode *inode, struct file *filp) 111 | { 112 | return 0; 113 | } 114 | /* 115 | * Follow the list 116 | */ 117 | struct scull_qset *scull_follow(struct scull_dev *dev, int n) 118 | { 119 | struct scull_qset *qs = dev->data; 120 | 121 | /* Allocate first qset explicitly if need be */ 122 | if (! qs) { 123 | qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL); 124 | if (qs == NULL) 125 | return NULL; /* Never mind */ 126 | memset(qs, 0, sizeof(struct scull_qset)); 127 | } 128 | 129 | /* Then follow the list */ 130 | while (n--) { 131 | if (!qs->next) { 132 | qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL); 133 | if (qs->next == NULL) 134 | return NULL; /* Never mind */ 135 | memset(qs->next, 0, sizeof(struct scull_qset)); 136 | } 137 | qs = qs->next; 138 | continue; 139 | } 140 | return qs; 141 | } 142 | 143 | /* 144 | * Data management: read and write 145 | */ 146 | 147 | ssize_t scull_read(struct file *filp, char __user *buf, size_t count, 148 | loff_t *f_pos) 149 | { 150 | struct scull_dev *dev = filp->private_data; 151 | struct scull_qset *dptr; /* the first listitem */ 152 | int quantum = dev->quantum, qset = dev->qset; 153 | int itemsize = quantum * qset; /* how many bytes in the listitem */ 154 | int item, s_pos, q_pos, rest; 155 | ssize_t retval = 0; 156 | 157 | if (down_interruptible(&dev->sem)) 158 | return -ERESTARTSYS; 159 | if (*f_pos >= dev->size) 160 | goto out; 161 | if (*f_pos + count > dev->size) 162 | count = dev->size - *f_pos; 163 | 164 | /* find listitem, qset index, and offset in the quantum */ 165 | item = (long)*f_pos / itemsize; 166 | rest = (long)*f_pos % itemsize; 167 | s_pos = rest / quantum; q_pos = rest % quantum; 168 | 169 | /* follow the list up to the right position (defined elsewhere) */ 170 | dptr = scull_follow(dev, item); 171 | 172 | if (dptr == NULL || !dptr->data || ! dptr->data[s_pos]) 173 | goto out; /* don't fill holes */ 174 | 175 | /* read only up to the end of this quantum */ 176 | if (count > quantum - q_pos) 177 | count = quantum - q_pos; 178 | 179 | if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) { 180 | retval = -EFAULT; 181 | goto out; 182 | } 183 | *f_pos += count; 184 | retval = count; 185 | 186 | out: 187 | up(&dev->sem); 188 | return retval; 189 | } 190 | 191 | ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, 192 | loff_t *f_pos) 193 | { 194 | struct scull_dev *dev = filp->private_data; 195 | struct scull_qset *dptr; 196 | int quantum = dev->quantum, qset = dev->qset; 197 | int itemsize = quantum * qset; 198 | int item, s_pos, q_pos, rest; 199 | ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ 200 | 201 | if (down_interruptible(&dev->sem)) 202 | return -ERESTARTSYS; 203 | 204 | /* find listitem, qset index and offset in the quantum */ 205 | item = (long)*f_pos / itemsize; 206 | rest = (long)*f_pos % itemsize; 207 | s_pos = rest / quantum; q_pos = rest % quantum; 208 | 209 | /* follow the list up to the right position */ 210 | dptr = scull_follow(dev, item); 211 | if (dptr == NULL) 212 | goto out; 213 | if (!dptr->data) { 214 | dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL); 215 | if (!dptr->data) 216 | goto out; 217 | memset(dptr->data, 0, qset * sizeof(char *)); 218 | } 219 | if (!dptr->data[s_pos]) { 220 | dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); 221 | if (!dptr->data[s_pos]) 222 | goto out; 223 | } 224 | /* write only up to the end of this quantum */ 225 | if (count > quantum - q_pos) 226 | count = quantum - q_pos; 227 | 228 | if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) { 229 | retval = -EFAULT; 230 | goto out; 231 | } 232 | *f_pos += count; 233 | retval = count; 234 | 235 | /* update the size */ 236 | if (dev->size < *f_pos) 237 | dev->size = *f_pos; 238 | 239 | out: 240 | up(&dev->sem); 241 | return retval; 242 | } 243 | 244 | 245 | /* 246 | * The "extended" operations -- only seek 247 | */ 248 | 249 | loff_t scull_llseek(struct file *filp, loff_t off, int whence) 250 | { 251 | struct scull_dev *dev = filp->private_data; 252 | loff_t newpos; 253 | 254 | switch(whence) { 255 | case 0: /* SEEK_SET */ 256 | newpos = off; 257 | break; 258 | 259 | case 1: /* SEEK_CUR */ 260 | newpos = filp->f_pos + off; 261 | break; 262 | 263 | case 2: /* SEEK_END */ 264 | newpos = dev->size + off; 265 | break; 266 | 267 | default: /* can't happen */ 268 | return -EINVAL; 269 | } 270 | if (newpos < 0) return -EINVAL; 271 | filp->f_pos = newpos; 272 | return newpos; 273 | } 274 | 275 | 276 | 277 | struct file_operations scull_fops = { 278 | .owner = THIS_MODULE, 279 | .llseek = scull_llseek, 280 | .read = scull_read, 281 | .write = scull_write, 282 | .open = scull_open, 283 | .release = scull_release, 284 | }; 285 | 286 | /* 287 | * Finally, the module stuff 288 | */ 289 | 290 | /* 291 | * The cleanup function is used to handle initialization failures as well. 292 | * Thefore, it must be careful to work correctly even if some of the items 293 | * have not been initialized 294 | */ 295 | void scull_cleanup_module(void) 296 | { 297 | int i; 298 | dev_t devno = MKDEV(scull_major, scull_minor); 299 | 300 | /* Get rid of our char dev entries */ 301 | if (scull_devices) { 302 | for (i = 0; i < scull_nr_devs; i++) { 303 | scull_trim(scull_devices + i); 304 | cdev_del(&scull_devices[i].cdev); 305 | } 306 | kfree(scull_devices); 307 | } 308 | 309 | /* cleanup_module is never called if registering failed */ 310 | unregister_chrdev_region(devno, scull_nr_devs); 311 | 312 | } 313 | 314 | 315 | /* 316 | * Set up the char_dev structure for this device. 317 | */ 318 | static void scull_setup_cdev(struct scull_dev *dev, int index) 319 | { 320 | int err, devno = MKDEV(scull_major, scull_minor + index); 321 | 322 | cdev_init(&dev->cdev, &scull_fops); 323 | dev->cdev.owner = THIS_MODULE; 324 | dev->cdev.ops = &scull_fops; /* not sure what is this doing here!!, this is OLD STYLE */ 325 | err = cdev_add (&dev->cdev, devno, 1); 326 | /* Fail gracefully if need be */ 327 | if (err) 328 | printk(KERN_NOTICE "Error %d adding scull%d", err, index); 329 | } 330 | 331 | 332 | int scull_init_module(void) 333 | { 334 | int result, i; 335 | dev_t dev = 0; 336 | 337 | /* 338 | * Get a range of minor numbers to work with, asking for a dynamic 339 | * major unless directed otherwise at load time. 340 | */ 341 | if (scull_major) { 342 | dev = MKDEV(scull_major, scull_minor); 343 | result = register_chrdev_region(dev, scull_nr_devs, "scull"); 344 | } else { 345 | result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, 346 | "scull"); 347 | scull_major = MAJOR(dev); 348 | } 349 | if (result < 0) { 350 | printk(KERN_WARNING "scull: can't get major %d\n", scull_major); 351 | return result; 352 | } 353 | 354 | /* 355 | * allocate the devices -- we can't have them static, as the number 356 | * can be specified at load time 357 | */ 358 | scull_devices = kmalloc(scull_nr_devs * sizeof(struct scull_dev), GFP_KERNEL); 359 | if (!scull_devices) { 360 | result = -ENOMEM; 361 | goto fail; /* Make this more graceful */ 362 | } 363 | memset(scull_devices, 0, scull_nr_devs * sizeof(struct scull_dev)); 364 | 365 | /* Initialize each device. */ 366 | for (i = 0; i < scull_nr_devs; i++) { 367 | scull_devices[i].quantum = scull_quantum; 368 | scull_devices[i].qset = scull_qset; 369 | init_MUTEX(&scull_devices[i].sem); 370 | scull_setup_cdev(&scull_devices[i], i); 371 | } 372 | 373 | return 0; /* succeed */ 374 | 375 | fail: 376 | scull_cleanup_module(); 377 | return result; 378 | } 379 | 380 | module_init(scull_init_module); 381 | module_exit(scull_cleanup_module); 382 | 383 | -------------------------------------------------------------------------------- /LDD3/scull_simple/scull.h: -------------------------------------------------------------------------------- 1 | /* 2 | * scull.h -- definitions for the char module 3 | * 4 | * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet 5 | * Copyright (C) 2001 O'Reilly & Associates 6 | * Copyright (C) 2011 Vigith Maurice 7 | * 8 | * The source code in this file can be freely used, adapted, 9 | * and redistributed in source or binary form, so long as an 10 | * acknowledgment appears in derived source files. The citation 11 | * should list that the code comes from the book "Linux Device 12 | * Drivers" by Alessandro Rubini and Jonathan Corbet, published 13 | * by O'Reilly & Associates. No warranty is attached; 14 | * we cannot take responsibility for errors or fitness for use. 15 | * 16 | */ 17 | 18 | #ifndef _SCULL_H_ 19 | #define _SCULL_H_ 20 | 21 | 22 | #ifndef SCULL_MAJOR 23 | #define SCULL_MAJOR 0 /* dynamic major by default */ 24 | #endif 25 | 26 | #ifndef SCULL_NR_DEVS 27 | #define SCULL_NR_DEVS 4 /* scull0 through scull3 */ 28 | #endif 29 | 30 | 31 | /* 32 | * The bare device is a variable-length region of memory. 33 | * Use a linked list of indirect blocks. 34 | * 35 | * "scull_dev->data" points to an array of pointers, each 36 | * pointer refers to a memory area of SCULL_QUANTUM bytes. 37 | * 38 | * The array (quantum-set) is SCULL_QSET long. 39 | */ 40 | #ifndef SCULL_QUANTUM 41 | #define SCULL_QUANTUM 4000 42 | #endif 43 | 44 | #ifndef SCULL_QSET 45 | #define SCULL_QSET 1000 46 | #endif 47 | 48 | 49 | 50 | /* 51 | * Representation of scull quantum sets. 52 | */ 53 | struct scull_qset { 54 | void **data; 55 | struct scull_qset *next; 56 | }; 57 | 58 | struct scull_dev { 59 | struct scull_qset *data; /* Pointer to first quantum set */ 60 | int quantum; /* the current quantum size */ 61 | int qset; /* the current array size */ 62 | unsigned long size; /* amount of data stored here */ 63 | unsigned int access_key; /* used by sculluid and scullpriv */ 64 | struct semaphore sem; /* mutual exclusion semaphore */ 65 | struct cdev cdev; /* Char device structure */ 66 | }; 67 | 68 | /* 69 | * Split minors in two parts 70 | */ 71 | #define TYPE(minor) (((minor) >> 4) & 0xf) /* high nibble */ 72 | #define NUM(minor) ((minor) & 0xf) /* low nibble */ 73 | 74 | 75 | /* 76 | * The different configurable parameters 77 | */ 78 | extern int scull_major; /* main.c */ 79 | extern int scull_nr_devs; 80 | extern int scull_quantum; 81 | extern int scull_qset; 82 | 83 | 84 | /* 85 | * Prototypes for shared functions 86 | */ 87 | 88 | int scull_trim(struct scull_dev *dev); 89 | ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); 90 | ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); 91 | loff_t scull_llseek(struct file *filp, loff_t off, int whence); 92 | 93 | 94 | #endif /* _SCULL_H_ */ 95 | 96 | -------------------------------------------------------------------------------- /LDD3/scull_simple/scull.init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Sample init script for the a driver module 3 | 4 | DEVICE="scull" 5 | SECTION="misc" 6 | 7 | # The list of filenames and minor numbers: $PREFIX is prefixed to all names 8 | PREFIX="scull" 9 | FILES=" 0 0 1 1 2 2 3 3 priv 16 10 | pipe0 32 pipe1 33 pipe2 34 pipe3 35 11 | single 48 uid 64 wuid 80" 12 | 13 | INSMOD=/sbin/insmod; # use /sbin/modprobe if you prefer 14 | 15 | function device_specific_post_load () { 16 | true; # fill at will 17 | } 18 | function device_specific_pre_unload () { 19 | true; # fill at will 20 | } 21 | 22 | # Everything below this line should work unchanged for any char device. 23 | # Obviously, however, no options on the command line: either in 24 | # /etc/${DEVICE}.conf or /etc/modules.conf (if modprobe is used) 25 | 26 | # Optional configuration file: format is 27 | # owner 28 | # group 29 | # mode 30 | # options 31 | CFG=/etc/${DEVICE}.conf 32 | 33 | # kernel version, used to look for modules 34 | KERNEL=`uname -r` 35 | 36 | #FIXME: it looks like there is no misc section. Where should it be? 37 | MODDIR="/lib/modules/${KERNEL}/kernel/drivers/${SECTION}" 38 | if [ ! -d $MODDIR ]; then MODDIR="/lib/modules/${KERNEL}/${SECTION}"; fi 39 | 40 | # Root or die 41 | if [ "$(id -u)" != "0" ] 42 | then 43 | echo "You must be root to load or unload kernel modules" 44 | exit 1 45 | fi 46 | 47 | # Read configuration file 48 | if [ -r $CFG ]; then 49 | OWNER=`awk "\\$1==\"owner\" {print \\$2}" $CFG` 50 | GROUP=`awk "\\$1==\"group\" {print \\$2}" $CFG` 51 | MODE=`awk "\\$1==\"mode\" {print \\$2}" $CFG` 52 | # The options string may include extra blanks or only blanks 53 | OPTIONS=`sed -n '/^options / s/options //p' $CFG` 54 | fi 55 | 56 | 57 | # Create device files 58 | function create_files () { 59 | cd /dev 60 | local devlist="" 61 | local file 62 | while true; do 63 | if [ $# -lt 2 ]; then break; fi 64 | file="${DEVICE}$1" 65 | mknod $file c $MAJOR $2 66 | devlist="$devlist $file" 67 | shift 2 68 | done 69 | if [ -n "$OWNER" ]; then chown $OWNER $devlist; fi 70 | if [ -n "$GROUP" ]; then chgrp $GROUP $devlist; fi 71 | if [ -n "$MODE" ]; then chmod $MODE $devlist; fi 72 | } 73 | 74 | # Remove device files 75 | function remove_files () { 76 | cd /dev 77 | local devlist="" 78 | local file 79 | while true; do 80 | if [ $# -lt 2 ]; then break; fi 81 | file="${DEVICE}$1" 82 | devlist="$devlist $file" 83 | shift 2 84 | done 85 | rm -f $devlist 86 | } 87 | 88 | # Load and create files 89 | function load_device () { 90 | 91 | if [ -f $MODDIR/$DEVICE.o ]; then 92 | devpath=$MODDIR/$DEVICE.o 93 | else if [ -f ./$DEVICE.o ]; then 94 | devpath=./$DEVICE.o 95 | else 96 | devpath=$DEVICE; # let insmod/modprobe guess 97 | fi; fi 98 | if [ "$devpath" != "$DEVICE" ]; then 99 | echo -n " (loading file $devpath)" 100 | fi 101 | 102 | if $INSMOD $devpath $OPTIONS; then 103 | MAJOR=`awk "\\$2==\"$DEVICE\" {print \\$1}" /proc/devices` 104 | remove_files $FILES 105 | create_files $FILES 106 | device_specific_post_load 107 | else 108 | echo " FAILED!" 109 | fi 110 | } 111 | 112 | # Unload and remove files 113 | function unload_device () { 114 | device_specific_pre_unload 115 | /sbin/rmmod $DEVICE 116 | remove_files $FILES 117 | } 118 | 119 | 120 | case "$1" in 121 | start) 122 | echo -n "Loading $DEVICE" 123 | load_device 124 | echo "." 125 | ;; 126 | stop) 127 | echo -n "Unloading $DEVICE" 128 | unload_device 129 | echo "." 130 | ;; 131 | force-reload|restart) 132 | echo -n "Reloading $DEVICE" 133 | unload_device 134 | load_device 135 | echo "." 136 | ;; 137 | *) 138 | echo "Usage: $0 {start|stop|restart|force-reload}" 139 | exit 1 140 | esac 141 | 142 | exit 0 143 | -------------------------------------------------------------------------------- /LDD3/scull_simple/scull_load: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | module="scull" 4 | device="scull" 5 | mode="664" 6 | 7 | # Group: since distributions do it differently, look for wheel or use staff 8 | if grep -q '^staff:' /etc/group; then 9 | group="staff" 10 | else 11 | group="wheel" 12 | fi 13 | 14 | # invoke insmod with all arguments we got 15 | # and use a pathname, as insmod doesn't look in . by default 16 | /sbin/insmod ./$module.ko $* || exit 1 17 | 18 | # retrieve major number 19 | major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices) 20 | 21 | # Remove stale nodes and replace them, then give gid and perms 22 | # Usually the script is shorter, it's scull that has several devices in it. 23 | 24 | rm -f /dev/${device}[0-3] 25 | mknod /dev/${device}0 c $major 0 26 | mknod /dev/${device}1 c $major 1 27 | mknod /dev/${device}2 c $major 2 28 | mknod /dev/${device}3 c $major 3 29 | ln -sf ${device}0 /dev/${device} 30 | chgrp $group /dev/${device}[0-3] 31 | chmod $mode /dev/${device}[0-3] 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /LDD3/scull_simple/scull_unload: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | module="scull" 4 | device="scull" 5 | 6 | # invoke rmmod with all arguments we got 7 | /sbin/rmmod $module $* || exit 1 8 | 9 | # Remove stale nodes 10 | 11 | rm -f /dev/${device} /dev/${device}[0-3] 12 | 13 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | "LDD3" contains linux kernel code from 'Linux Device Drivers' by Alessandro Rubini 2 | and Jonathan Corbet, published by by O'Reilly & Associates. I have edited most of 3 | them (without changing the code logic) to make it much more simpler. 4 | -------------------------------------------------------------------------------- /keyboard/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Vigith's Beer Bottle License 3 | ---------------------------- 4 | 5 | If you like this code (don't have to be useful though), next time when you meet me, 6 | you can get me a beer (and for those who don't drink, get me a donut). 7 | 8 | This code is your code, do whatever you want to do with it, BUT if things go bad because 9 | of this code I will shamelessly refute the authorship of this code :-). 10 | 11 | 12 | SERIOUSLY!, I am not a proper kernel hacker, just a random guy who likes poking "the kernel". 13 | This code is not efficient and is not guaranteed to work in a concurrent system (it worked for 14 | me somehow :-). Patches are welcome! 15 | 16 | -vim 17 | Vigith Maurice 18 | www.vigith.com 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /keyboard/Makefile: -------------------------------------------------------------------------------- 1 | 2 | obj-m += keyboardInt.o 3 | 4 | all: 5 | @echo ">>" Compiling the Source $< 6 | @echo ".." $< 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 8 | 9 | header: 10 | @echo ">>" Creating Keyboard Mapping Header File $< 11 | @echo ".." $< 12 | $(shell echo 'dumpkeys | perl -lne "BEGIN {print qq!// Please DO-NOT edit this file manually (a hardware specific file).\n// This is generated by the Makefile.\n// Read License Agreement before using.\n// Author: Vigith Maurice \n\n!; print qq!struct keyboard_stat {\n char str[10];\n char hex[4];\n int dec;\n long int count_p;\n long int count_r;\n} keyboard_stats[] = {\n { \"DUMMY\", \"0\", 0, 0, 0 }, !}; if (m!^keycode\s+(\d+)\s+=\s+(.*?)\s+!) {printf qq! { \"%s\", \"%x\", %d, 0, 0 },\n!, substr(\$$2,0,10),\$$1,\$$1; \$$count++ } END { \$$count++; print qq!};\n\nint SCAN_CODES = \$$count;! }" > keyboard_mapping.h' $<) 13 | @echo ".." $< 14 | 15 | 16 | clean: 17 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 18 | -------------------------------------------------------------------------------- /keyboard/README: -------------------------------------------------------------------------------- 1 | 2 | ########## 3 | # README # 4 | ########## 5 | 6 | Purpose 7 | ------- 8 | To help understand which is the most commonly 'pressed' and 'released' key in 9 | the keyboard. Holding a key down will generate 'pressed' events more so, count 10 | of pressing need not be equal to release count. (This code works only for ps/2 11 | keyboards, not usb which generates interrupt in different IRQ line.) 12 | 13 | How To Use 14 | ---------- 15 | Please don't proceed if you see any error in the below steps. 16 | 17 | 0. 0rth Law (as in thermodynamics) 18 | cat LICENSE 19 | 20 | 1. compile 21 | a. create the header files 22 | $ make header 23 | 24 | ( 25 | sometimes the above may not work, as it won't be able to get 26 | file descriptor. please run as sudo 27 | $ sudo make header 28 | ) 29 | 30 | b. compile the source 31 | $ make 32 | 33 | 2. Insert the module into kernel and setup the system 34 | $ keyboard_stats_load 35 | 36 | 3. Read the statistics 37 | $ cat /dev/keyboard_stats 38 | 39 | 4. Remove the module and system 40 | $ keyboard_stats_unload 41 | 42 | 5. Cleaning the dir 43 | $ make clean 44 | 45 | DEBUGGING 46 | --------- 47 | Mail the author or read /var/log/messages and try your luck 48 | by setting the scancodes etc. 49 | 50 | Misc 51 | ---- 52 | I wrote this code because few of my keys are more shiny than others 53 | and i had to find out why!! :-) 54 | 55 | Bugs 56 | ---- 57 | In my MAC VM, some keys were not working, like arrow keys! 58 | 59 | Author 60 | ------ 61 | Vigith Maurice (www.vigith.com) 62 | 63 | -------------------------------------------------------------------------------- /keyboard/keyboardInt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include /* kmalloc() */ 4 | #include 5 | #include 6 | #include 7 | #include /* everything... */ 8 | #include /* character device */ 9 | 10 | #include /* strcat */ 11 | #include /* cli(), *_flags */ 12 | #include /* copy_*_user */ 13 | 14 | #include "keyboardInt.h" 15 | #include "keyboard_mapping.h" 16 | 17 | int major = K_MAJOR; 18 | int minor = 0; 19 | struct keyboard_stats_dev *k_dev; 20 | 21 | /* Spin lock */ 22 | DEFINE_SPINLOCK(mr_lock); 23 | 24 | /* Tasklets for BH */ 25 | void keyboard_tasklet_bh(unsigned long); 26 | /* PROTO: DECLARE_TASKLET(name, function, data); */ 27 | DECLARE_TASKLET(keyboard_tasklet, keyboard_tasklet_bh, 0); 28 | 29 | void keyboard_tasklet_bh(unsigned long hits) { 30 | int binary; 31 | unsigned char scode; /* tmp scancode */ 32 | char *bin, *tmp; 33 | 34 | /* GFP_ATOMIC is compulsory as this won't sleep */ 35 | bin= kmalloc(sizeof(unsigned char) * 1, GFP_ATOMIC); /* pid is read a a string */ 36 | tmp = kmalloc(sizeof(unsigned char) * 1, GFP_ATOMIC); /* needed for simple_strtol */ 37 | 38 | /* save the scan code */ 39 | spin_lock(&mr_lock); 40 | scode = scancode; 41 | spin_unlock(&mr_lock); 42 | 43 | /* since no TASKLETs run together, i don't have to worry about locks here */ 44 | sprintf(bin, "%d", scancode); 45 | binary = simple_strtol(bin, &tmp, 10); 46 | 47 | /* save the key press/release stat */ 48 | if (scancode & 0x80) { 49 | binary -= 128; /* key release - 128 is key press */ 50 | keyboard_stats[binary].count_r += 1; 51 | } else { 52 | keyboard_stats[binary].count_p += 1; 53 | } 54 | 55 | /* Please don't UNCOMMENT this block, in interrupt context printk can be blocked and put a system to a serious unstable state. 56 | ('coz, interrupt state can't wake up becuase it has no process context and need_schedule() func won't be called (long story, read LINUX DEVICE DRIVERS 3rd ed). 57 | I tested in a VM box, where there are no other activities were taking place and rebooting was not at-all a problem :-) 58 | // printk(KERN_INFO "You pressed [%x] [%d] [%s] (%lu %lu)\n", scancode, scancode, scancode & 0x80 ? "Released" : "Pressed", keyboard_stats[binary].count_r, keyboard_stats[binary].count_p); 59 | */ 60 | 61 | return; 62 | } 63 | 64 | /* This function services keyboard interrupts */ 65 | irq_handler_t irq_handler (int irq, void *dev_id, struct pt_regs *regs) { 66 | 67 | /* 68 | Read keyboard status. 69 | Obtain a spin lock and update scancode. 70 | */ 71 | spin_lock(&mr_lock); 72 | scancode = inb (0x60); 73 | spin_unlock(&mr_lock); 74 | 75 | /* schedule the tasklet */ 76 | tasklet_schedule(&keyboard_tasklet); 77 | 78 | return (irq_handler_t) IRQ_HANDLED; 79 | } 80 | 81 | /* 82 | * 'open' system call 83 | */ 84 | int k_dev_open(struct inode *inode, struct file *filp) { 85 | struct keyboard_stats_dev *dev; /* our device (cdev), which contains 'cdev' */ 86 | 87 | /* takes a pointer to a field of type container_field, within a structure of 88 | type container_type, and returns a pointer to the containing structure. 89 | This is for getting the parent keyboard_stats_dev struct from cdev which is 90 | encapsulated inside keyboard_stats_dev. (we don't need dev, but incase for future! */ 91 | dev = container_of(inode->i_cdev, struct keyboard_stats_dev, cdev); 92 | /* for easier access, else we will have to call container_of everytime */ 93 | filp->private_data = dev; 94 | 95 | /* we are planning only for O_RDONLY, so no special handler for O_WRONLY 96 | what will you write to the stats file? :-) */ 97 | 98 | return 0; 99 | } 100 | 101 | /* 102 | * Read from the device (write to userspace), 'read' syscall 103 | */ 104 | ssize_t k_dev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { 105 | struct keyboard_stats_dev *dev = filp->private_data; /* we had stored 'dev' in private_data, else use container_of */ 106 | ssize_t retval = 0; 107 | char tmp[256]; /* tmp space for sprintf to put the keyboard stats */ 108 | int i = 0; 109 | char sep = '\t'; 110 | 111 | /* acquire lock for concurrency */ 112 | if(down_interruptible(&dev->sem)) 113 | return -ERESTARTSYS; 114 | 115 | /* We expect all calls to be full requests, not partial ones (ie, not using offsets), yeah lazy Maurice, bad hack :-) */ 116 | if (*f_pos != 0) { 117 | goto out; 118 | } 119 | 120 | dev->stat_str[0] = '\0'; 121 | 122 | /* Populate the stats string! */ 123 | sprintf(tmp, "\t\tKey Name (Release Count\tPress Count)\n"); 124 | strcat(dev->stat_str, tmp); 125 | for (i=1; i<=SCAN_CODES;) { 126 | sprintf(tmp, "%10s (%lu %lu)%c", keyboard_stats[i].str, keyboard_stats[i].count_r, keyboard_stats[i].count_p, sep); 127 | strcat(dev->stat_str, tmp); 128 | if (++i % 3 == 0) { 129 | sep = '\n'; 130 | continue; 131 | } 132 | sep = '\t'; 133 | } 134 | 135 | /* write pd_str to userspace */ 136 | if (copy_to_user(buf, dev->stat_str, strlen(dev->stat_str))) { 137 | retval = -EFAULT; 138 | goto out; 139 | } 140 | 141 | *f_pos = strlen(dev->stat_str); 142 | retval = strlen(dev->stat_str); 143 | 144 | out: 145 | up(&dev->sem); 146 | return retval; 147 | } 148 | 149 | 150 | /* 151 | * 'close' system call 152 | */ 153 | int k_dev_release(struct inode *inode, struct file *filp) { 154 | struct keyboard_stats_dev *dev; /* our device (cdev), which contains 'cdev' */ 155 | 156 | /* get the device */ 157 | dev = container_of(inode->i_cdev, struct keyboard_stats_dev, cdev); 158 | 159 | return 0; 160 | } 161 | 162 | 163 | /* 164 | * setting up the file operations for k_dev 165 | */ 166 | struct file_operations k_fops = { 167 | .owner = THIS_MODULE, 168 | .open = k_dev_open, 169 | .read = k_dev_read, 170 | .release = k_dev_release, 171 | }; 172 | 173 | 174 | /* 175 | * Device Setup for Keyboard Stats Device 176 | */ 177 | int k_dev_setup(struct keyboard_stats_dev *dev) { 178 | int err; 179 | dev_t devno = MKDEV(major, minor); 180 | 181 | /* device registration, could have done static registration too! */ 182 | cdev_init(&dev->cdev, &k_fops); 183 | dev->cdev.ops = &k_fops; 184 | dev->cdev.owner = THIS_MODULE; 185 | 186 | /* tells the kernel about the registration */ 187 | err = cdev_add(&dev->cdev, devno, 1); 188 | 189 | if (err) { 190 | printk(KERN_WARNING "Error during setting up 'keyboard_stats'\n"); 191 | return err; 192 | } 193 | 194 | /* k_dev string space */ 195 | dev->stat_str = kmalloc(sizeof(char) * K_STR_SIZE, GFP_KERNEL); 196 | memset(dev->stat_str, 0, sizeof(char) * K_STR_SIZE); 197 | 198 | return 0; 199 | } 200 | 201 | 202 | /* Initialize the module and Register the IRQ handler */ 203 | static int __init keybrd_int_register(void) { 204 | int result = -1; 205 | dev_t dev = 0; 206 | 207 | /* register the character device 208 | (dev_t *dev, firstminor, count, name); 209 | */ 210 | result = alloc_chrdev_region(&dev, minor, 1, "keyboard_stats"); 211 | if (result < 0) { 212 | major = MAJOR(dev); 213 | printk(KERN_WARNING "keyboard_stats: can't get major %d\n", major); 214 | return result; 215 | } 216 | 217 | major = MAJOR(dev); 218 | 219 | /* allocate the devices */ 220 | /* GFP_KERNEL is the flag to use in process context code when it is safe to sleep. The 221 | kernel will do whatever it has to do to obtain the memory requested by the caller. */ 222 | k_dev = kmalloc(1 * sizeof(struct keyboard_stats_dev), GFP_KERNEL); 223 | 224 | 225 | /* setup each device */ 226 | init_MUTEX(&(k_dev->sem)); /* addr of sem */ 227 | result = k_dev_setup(k_dev); /* TODO: catch error and do good cleanup */ 228 | if (result) 229 | return result; 230 | 231 | printk(KERN_INFO "Inserted Module 'keyboard_stats' [%d]\n", major); 232 | 233 | /* Request IRQ 1, the keyboard IRQ */ 234 | result = request_irq (1, (irq_handler_t) irq_handler, IRQF_SHARED, "keyboard_stats", (void *)(irq_handler)); 235 | if (result) 236 | printk(KERN_INFO "can't get shared interrupt for keyboard\n"); 237 | 238 | return result; 239 | } 240 | 241 | /* Remove the interrupt handler and the device file */ 242 | static void __exit keybrd_int_unregister(void) { 243 | dev_t devno = MKDEV(major, minor); 244 | 245 | free_irq(1, (void *)(irq_handler)); /* i can't pass NULL, this is a shared interrupt handler! */ 246 | 247 | /* free the memory we acquired */ 248 | /* clean the keyboard_stats_dev string space */ 249 | kfree(k_dev->stat_str); 250 | cdev_del(&(k_dev->cdev)); 251 | 252 | /* clean the device sctructure */ 253 | kfree(k_dev); 254 | 255 | unregister_chrdev_region(devno, 1); 256 | printk(KERN_INFO "Removed Module 'keyboard_stats' [%d]\n", MAJOR(devno)); 257 | } 258 | 259 | MODULE_LICENSE ("GPL"); 260 | MODULE_AUTHOR("Vigith Maurice"); 261 | module_init(keybrd_int_register); 262 | module_exit(keybrd_int_unregister); 263 | 264 | 265 | -------------------------------------------------------------------------------- /keyboard/keyboardInt.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _KEYBOARD_STATS_ 3 | #define _KEYBOARD_STATS_ 4 | 5 | #ifndef KYBRD_MAJOR 6 | #define K_MAJOR 0 /* dynamic major number */ 7 | #endif 8 | 9 | #ifndef KYBRD_STR_SIZE 10 | #define K_STR_SIZE 1024*4*4 /* data size that is to be printed out */ 11 | #endif 12 | 13 | /* our device structure */ 14 | struct keyboard_stats_dev { 15 | char *stat_str; /* string that would be shown to user */ 16 | struct semaphore sem; /* mutual exclusion semaphore */ 17 | struct cdev cdev; /* Char device structure */ 18 | }; 19 | 20 | /* scan code */ 21 | static unsigned char scancode; 22 | 23 | #endif /* _KEYBOARD_STATS_ */ 24 | -------------------------------------------------------------------------------- /keyboard/keyboard_mapping.h: -------------------------------------------------------------------------------- 1 | // Please DO-NOT edit this file manually (a hardware specific file). 2 | // This is generated by the Makefile. 3 | // Read License Agreement before using. 4 | // Author: Vigith Maurice 5 | 6 | 7 | struct keyboard_stat { 8 | char str[10]; 9 | char hex[4]; 10 | int dec; 11 | long int count_p; 12 | long int count_r; 13 | } keyboard_stats[] = { 14 | { "DUMMY", "0", 0, 0, 0 }, 15 | { "Escape", "1", 1, 0, 0 }, 16 | { "one", "2", 2, 0, 0 }, 17 | { "two", "3", 3, 0, 0 }, 18 | { "three", "4", 4, 0, 0 }, 19 | { "four", "5", 5, 0, 0 }, 20 | { "five", "6", 6, 0, 0 }, 21 | { "six", "7", 7, 0, 0 }, 22 | { "seven", "8", 8, 0, 0 }, 23 | { "eight", "9", 9, 0, 0 }, 24 | { "nine", "a", 10, 0, 0 }, 25 | { "zero", "b", 11, 0, 0 }, 26 | { "minus", "c", 12, 0, 0 }, 27 | { "equal", "d", 13, 0, 0 }, 28 | { "Delete", "e", 14, 0, 0 }, 29 | { "Tab", "f", 15, 0, 0 }, 30 | { "+q", "10", 16, 0, 0 }, 31 | { "+w", "11", 17, 0, 0 }, 32 | { "+e", "12", 18, 0, 0 }, 33 | { "+r", "13", 19, 0, 0 }, 34 | { "+t", "14", 20, 0, 0 }, 35 | { "+y", "15", 21, 0, 0 }, 36 | { "+u", "16", 22, 0, 0 }, 37 | { "+i", "17", 23, 0, 0 }, 38 | { "+o", "18", 24, 0, 0 }, 39 | { "+p", "19", 25, 0, 0 }, 40 | { "bracketlef", "1a", 26, 0, 0 }, 41 | { "bracketrig", "1b", 27, 0, 0 }, 42 | { "Return", "1c", 28, 0, 0 }, 43 | { "Control", "1d", 29, 0, 0 }, 44 | { "+a", "1e", 30, 0, 0 }, 45 | { "+s", "1f", 31, 0, 0 }, 46 | { "+d", "20", 32, 0, 0 }, 47 | { "+f", "21", 33, 0, 0 }, 48 | { "+g", "22", 34, 0, 0 }, 49 | { "+h", "23", 35, 0, 0 }, 50 | { "+j", "24", 36, 0, 0 }, 51 | { "+k", "25", 37, 0, 0 }, 52 | { "+l", "26", 38, 0, 0 }, 53 | { "semicolon", "27", 39, 0, 0 }, 54 | { "apostrophe", "28", 40, 0, 0 }, 55 | { "grave", "29", 41, 0, 0 }, 56 | { "Shift", "2a", 42, 0, 0 }, 57 | { "backslash", "2b", 43, 0, 0 }, 58 | { "+z", "2c", 44, 0, 0 }, 59 | { "+x", "2d", 45, 0, 0 }, 60 | { "+c", "2e", 46, 0, 0 }, 61 | { "+v", "2f", 47, 0, 0 }, 62 | { "+b", "30", 48, 0, 0 }, 63 | { "+n", "31", 49, 0, 0 }, 64 | { "+m", "32", 50, 0, 0 }, 65 | { "comma", "33", 51, 0, 0 }, 66 | { "period", "34", 52, 0, 0 }, 67 | { "slash", "35", 53, 0, 0 }, 68 | { "Shift", "36", 54, 0, 0 }, 69 | { "KP_Multipl", "37", 55, 0, 0 }, 70 | { "Alt", "38", 56, 0, 0 }, 71 | { "space", "39", 57, 0, 0 }, 72 | { "CtrlL_Lock", "3a", 58, 0, 0 }, 73 | { "F1", "3b", 59, 0, 0 }, 74 | { "F2", "3c", 60, 0, 0 }, 75 | { "F3", "3d", 61, 0, 0 }, 76 | { "F4", "3e", 62, 0, 0 }, 77 | { "F5", "3f", 63, 0, 0 }, 78 | { "F6", "40", 64, 0, 0 }, 79 | { "F7", "41", 65, 0, 0 }, 80 | { "F8", "42", 66, 0, 0 }, 81 | { "F9", "43", 67, 0, 0 }, 82 | { "F10", "44", 68, 0, 0 }, 83 | { "Num_Lock", "45", 69, 0, 0 }, 84 | { "Scroll_Loc", "46", 70, 0, 0 }, 85 | { "KP_7", "47", 71, 0, 0 }, 86 | { "KP_8", "48", 72, 0, 0 }, 87 | { "KP_9", "49", 73, 0, 0 }, 88 | { "KP_Subtrac", "4a", 74, 0, 0 }, 89 | { "KP_4", "4b", 75, 0, 0 }, 90 | { "KP_5", "4c", 76, 0, 0 }, 91 | { "KP_6", "4d", 77, 0, 0 }, 92 | { "KP_Add", "4e", 78, 0, 0 }, 93 | { "KP_1", "4f", 79, 0, 0 }, 94 | { "KP_2", "50", 80, 0, 0 }, 95 | { "KP_3", "51", 81, 0, 0 }, 96 | { "KP_0", "52", 82, 0, 0 }, 97 | { "KP_Period", "53", 83, 0, 0 }, 98 | { "Last_Conso", "54", 84, 0, 0 }, 99 | { "less", "56", 86, 0, 0 }, 100 | { "F11", "57", 87, 0, 0 }, 101 | { "F12", "58", 88, 0, 0 }, 102 | { "KP_Enter", "60", 96, 0, 0 }, 103 | { "Control", "61", 97, 0, 0 }, 104 | { "KP_Divide", "62", 98, 0, 0 }, 105 | { "Alt", "64", 100, 0, 0 }, 106 | { "Break", "65", 101, 0, 0 }, 107 | { "Find", "66", 102, 0, 0 }, 108 | { "Up", "67", 103, 0, 0 }, 109 | { "Prior", "68", 104, 0, 0 }, 110 | { "Left", "69", 105, 0, 0 }, 111 | { "Right", "6a", 106, 0, 0 }, 112 | { "Select", "6b", 107, 0, 0 }, 113 | { "Down", "6c", 108, 0, 0 }, 114 | { "Next", "6d", 109, 0, 0 }, 115 | { "Insert", "6e", 110, 0, 0 }, 116 | { "Remove", "6f", 111, 0, 0 }, 117 | { "Macro", "70", 112, 0, 0 }, 118 | { "F13", "71", 113, 0, 0 }, 119 | { "F14", "72", 114, 0, 0 }, 120 | { "Help", "73", 115, 0, 0 }, 121 | { "Do", "74", 116, 0, 0 }, 122 | { "F17", "75", 117, 0, 0 }, 123 | { "KP_MinPlus", "76", 118, 0, 0 }, 124 | { "Pause", "77", 119, 0, 0 }, 125 | { "Alt", "7d", 125, 0, 0 }, 126 | { "Alt", "7e", 126, 0, 0 }, 127 | { "nul", "80", 128, 0, 0 }, 128 | { "nul", "81", 129, 0, 0 }, 129 | { "nul", "82", 130, 0, 0 }, 130 | { "nul", "83", 131, 0, 0 }, 131 | { "nul", "84", 132, 0, 0 }, 132 | { "nul", "85", 133, 0, 0 }, 133 | { "nul", "86", 134, 0, 0 }, 134 | { "nul", "87", 135, 0, 0 }, 135 | { "nul", "88", 136, 0, 0 }, 136 | { "nul", "89", 137, 0, 0 }, 137 | { "nul", "8a", 138, 0, 0 }, 138 | { "nul", "8b", 139, 0, 0 }, 139 | { "nul", "8c", 140, 0, 0 }, 140 | { "nul", "8d", 141, 0, 0 }, 141 | { "nul", "8e", 142, 0, 0 }, 142 | { "nul", "8f", 143, 0, 0 }, 143 | { "nul", "90", 144, 0, 0 }, 144 | { "nul", "91", 145, 0, 0 }, 145 | { "nul", "92", 146, 0, 0 }, 146 | { "nul", "93", 147, 0, 0 }, 147 | { "nul", "94", 148, 0, 0 }, 148 | { "nul", "95", 149, 0, 0 }, 149 | { "nul", "96", 150, 0, 0 }, 150 | { "nul", "97", 151, 0, 0 }, 151 | { "nul", "98", 152, 0, 0 }, 152 | { "nul", "99", 153, 0, 0 }, 153 | { "nul", "9a", 154, 0, 0 }, 154 | { "nul", "9b", 155, 0, 0 }, 155 | { "nul", "9c", 156, 0, 0 }, 156 | { "nul", "9d", 157, 0, 0 }, 157 | { "nul", "9e", 158, 0, 0 }, 158 | { "nul", "9f", 159, 0, 0 }, 159 | { "nul", "a0", 160, 0, 0 }, 160 | { "nul", "a1", 161, 0, 0 }, 161 | { "nul", "a2", 162, 0, 0 }, 162 | { "nul", "a3", 163, 0, 0 }, 163 | { "nul", "a4", 164, 0, 0 }, 164 | { "nul", "a5", 165, 0, 0 }, 165 | { "nul", "a6", 166, 0, 0 }, 166 | { "nul", "a7", 167, 0, 0 }, 167 | { "nul", "a8", 168, 0, 0 }, 168 | { "nul", "a9", 169, 0, 0 }, 169 | { "nul", "aa", 170, 0, 0 }, 170 | { "nul", "ab", 171, 0, 0 }, 171 | { "nul", "ac", 172, 0, 0 }, 172 | { "nul", "ad", 173, 0, 0 }, 173 | { "nul", "ae", 174, 0, 0 }, 174 | { "nul", "af", 175, 0, 0 }, 175 | { "nul", "b0", 176, 0, 0 }, 176 | { "nul", "b1", 177, 0, 0 }, 177 | { "nul", "b2", 178, 0, 0 }, 178 | { "nul", "b3", 179, 0, 0 }, 179 | { "nul", "b4", 180, 0, 0 }, 180 | { "nul", "b5", 181, 0, 0 }, 181 | { "nul", "b6", 182, 0, 0 }, 182 | { "nul", "b7", 183, 0, 0 }, 183 | { "nul", "b8", 184, 0, 0 }, 184 | { "nul", "b9", 185, 0, 0 }, 185 | { "nul", "ba", 186, 0, 0 }, 186 | { "nul", "bb", 187, 0, 0 }, 187 | { "nul", "bc", 188, 0, 0 }, 188 | { "nul", "bd", 189, 0, 0 }, 189 | { "nul", "be", 190, 0, 0 }, 190 | { "nul", "bf", 191, 0, 0 }, 191 | { "nul", "c0", 192, 0, 0 }, 192 | { "nul", "c1", 193, 0, 0 }, 193 | { "nul", "c2", 194, 0, 0 }, 194 | { "nul", "c3", 195, 0, 0 }, 195 | { "nul", "c4", 196, 0, 0 }, 196 | { "nul", "c5", 197, 0, 0 }, 197 | { "nul", "c6", 198, 0, 0 }, 198 | { "nul", "c7", 199, 0, 0 }, 199 | { "nul", "c8", 200, 0, 0 }, 200 | { "nul", "c9", 201, 0, 0 }, 201 | { "nul", "ca", 202, 0, 0 }, 202 | { "nul", "cb", 203, 0, 0 }, 203 | { "nul", "cc", 204, 0, 0 }, 204 | { "nul", "cd", 205, 0, 0 }, 205 | { "nul", "ce", 206, 0, 0 }, 206 | { "nul", "cf", 207, 0, 0 }, 207 | { "nul", "d0", 208, 0, 0 }, 208 | { "nul", "d1", 209, 0, 0 }, 209 | { "nul", "d2", 210, 0, 0 }, 210 | { "nul", "d3", 211, 0, 0 }, 211 | { "nul", "d4", 212, 0, 0 }, 212 | { "nul", "d5", 213, 0, 0 }, 213 | { "nul", "d6", 214, 0, 0 }, 214 | { "nul", "d7", 215, 0, 0 }, 215 | { "nul", "d8", 216, 0, 0 }, 216 | { "nul", "d9", 217, 0, 0 }, 217 | { "nul", "da", 218, 0, 0 }, 218 | { "nul", "db", 219, 0, 0 }, 219 | { "nul", "dc", 220, 0, 0 }, 220 | { "nul", "dd", 221, 0, 0 }, 221 | { "nul", "de", 222, 0, 0 }, 222 | { "nul", "df", 223, 0, 0 }, 223 | { "nul", "e0", 224, 0, 0 }, 224 | { "nul", "e1", 225, 0, 0 }, 225 | { "nul", "e2", 226, 0, 0 }, 226 | { "nul", "e3", 227, 0, 0 }, 227 | { "nul", "e4", 228, 0, 0 }, 228 | { "nul", "e5", 229, 0, 0 }, 229 | { "nul", "e6", 230, 0, 0 }, 230 | { "nul", "e7", 231, 0, 0 }, 231 | { "nul", "e8", 232, 0, 0 }, 232 | { "nul", "e9", 233, 0, 0 }, 233 | { "nul", "ea", 234, 0, 0 }, 234 | { "nul", "eb", 235, 0, 0 }, 235 | { "nul", "ec", 236, 0, 0 }, 236 | { "nul", "ed", 237, 0, 0 }, 237 | { "nul", "ee", 238, 0, 0 }, 238 | { "nul", "ef", 239, 0, 0 }, 239 | { "nul", "f0", 240, 0, 0 }, 240 | { "nul", "f1", 241, 0, 0 }, 241 | { "nul", "f2", 242, 0, 0 }, 242 | { "nul", "f3", 243, 0, 0 }, 243 | { "nul", "f4", 244, 0, 0 }, 244 | { "nul", "f5", 245, 0, 0 }, 245 | { "nul", "f6", 246, 0, 0 }, 246 | { "nul", "f7", 247, 0, 0 }, 247 | { "nul", "f8", 248, 0, 0 }, 248 | { "nul", "f9", 249, 0, 0 }, 249 | { "nul", "fa", 250, 0, 0 }, 250 | { "nul", "fb", 251, 0, 0 }, 251 | { "nul", "fc", 252, 0, 0 }, 252 | { "nul", "fd", 253, 0, 0 }, 253 | { "nul", "fe", 254, 0, 0 }, 254 | { "nul", "ff", 255, 0, 0 }, 255 | }; 256 | 257 | int SCAN_CODES = 241; 258 | -------------------------------------------------------------------------------- /keyboard/keyboard_stats_load: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | module="keyboardInt" 4 | device="keyboard_stats" 5 | mode="664" 6 | 7 | 8 | # Group: since distributions do it differently, look for wheel or use staff 9 | if grep -q '^staff:' /etc/group; then 10 | group="staff" 11 | else 12 | group="wheel" 13 | fi 14 | 15 | 16 | # invoke insmod with all arguments we got 17 | # and use a pathname, as insmod doesn't look in . by default 18 | /sbin/insmod ./$module.ko $* || exit 1 19 | 20 | 21 | # retrieve major number 22 | major=$(awk "\$2==\"$device\" {print \$1}" /proc/devices) 23 | 24 | 25 | # Remove stale nodes and replace them, then give gid and perms 26 | rm -f /dev/${device} 27 | mknod /dev/${device} c $major 0 # create device file 28 | chgrp $group /dev/${device} 29 | chmod $mode /dev/${device} 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /keyboard/keyboard_stats_unload: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | module="keyboardInt" 4 | device="keyboard_stats" 5 | 6 | 7 | # invoke rmmod with all arguments we got 8 | /sbin/rmmod $module $* || exit 1 9 | 10 | 11 | # Remove stale nodes 12 | rm -f /dev/${device} 13 | -------------------------------------------------------------------------------- /proc_desc/Makefile: -------------------------------------------------------------------------------- 1 | 2 | # To build modules outside of the kernel tree, we run "make" 3 | # in the kernel source tree; the Makefile these then includes this 4 | # Makefile once again. 5 | # This conditional selects whether we are being included from the 6 | # kernel Makefile or not. 7 | ifeq ($(KERNELRELEASE),) 8 | 9 | # Assume the source tree is where the running kernel was built 10 | # You should set KERNELDIR in the environment if it's elsewhere 11 | KERNELDIR ?= /lib/modules/$(shell uname -r)/build 12 | # The current directory is passed to sub-makes as argument 13 | PWD := $(shell pwd) 14 | 15 | modules: 16 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules 17 | 18 | modules_install: 19 | $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install 20 | 21 | clean: 22 | rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers *.order 23 | 24 | .PHONY: modules modules_install clean 25 | 26 | else 27 | # called from kernel build system: just declare what our modules are 28 | obj-m := proc_desc.o 29 | 30 | endif 31 | 32 | 33 | -------------------------------------------------------------------------------- /proc_desc/proc_desc.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include /* printk() */ 7 | #include /* kmalloc() */ 8 | #include /* everything... */ 9 | #include /* error codes */ 10 | #include /* size_t */ 11 | #include /* current and everything */ 12 | 13 | #include /* O_ACCMODE */ 14 | #include 15 | #include 16 | 17 | #include /* cli(), *_flags */ 18 | #include /* copy_*_user */ 19 | 20 | #include "proc_desc.h" 21 | 22 | MODULE_AUTHOR("Vigith Maurice"); 23 | MODULE_LICENSE("Dual BSD/GPL"); 24 | 25 | int pd_major = PD_MAJOR; 26 | int pd_minor = 0; 27 | int pd_nr = PD_NR; 28 | 29 | struct pd_dev *pd_device; 30 | 31 | 32 | /* 33 | * 'open' system call 34 | */ 35 | int pd_open(struct inode *inode, struct file *filp) { 36 | struct pd_dev *dev; /* our device, which contains 'cdev' */ 37 | 38 | 39 | /* takes a pointer to a field of type container_field, within a structure of 40 | type container_type, and returns a pointer to the containing structure */ 41 | dev = container_of(inode->i_cdev, struct pd_dev, cdev); 42 | /* for easier access, else we will have to call container_of everytime */ 43 | filp->private_data = dev; 44 | 45 | /* if file is opened for write, clean the data */ 46 | if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) { 47 | 48 | /* acquire a lock */ 49 | if (down_interruptible(&dev->sem)) /* return error, if we can't */ 50 | return -ERESTARTSYS; 51 | 52 | kfree(dev->pd->pd_str); /* remove the pd_str allocated, we don't need it in O_WRONLY */ 53 | 54 | up(&dev->sem); /* release the lock */ 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | /* 61 | * Read from the device (write to userspace) 62 | */ 63 | ssize_t pd_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { 64 | struct pd_dev *dev = filp->private_data; /* we had stored 'dev' in private_data, else use container_of */ 65 | ssize_t retval = 0; 66 | 67 | struct task_struct *task; 68 | short int flag = 0; 69 | 70 | /* acquire lock for concurrency */ 71 | if(down_interruptible(&dev->sem)) 72 | return -ERESTARTSYS; 73 | 74 | /* this is not a first time request, we already satisfied the callee earlier 75 | * (it would have been better to see the total size of struct and decide whether 76 | * this second request is legitimate, eg users can use read with len) 77 | */ 78 | if (*f_pos != 0) { 79 | goto out; 80 | } 81 | 82 | /* if nothing is written to the device file, we can't fetch any task_struct */ 83 | if (dev->pd->pid == -1) { 84 | /* write the data to pd_str */ 85 | sprintf(dev->pd->pd_str, "Please write a pid to the device file\n"); 86 | } else { 87 | for_each_process(task) { 88 | if (task->pid == dev->pd->pid) { 89 | flag = 1; 90 | sprintf(dev->pd->pd_str, "Requested Pid: [%d] Current Pid: [%d] Comm: [%s]\n", 91 | dev->pd->pid, current->pid, task->comm); 92 | } 93 | } 94 | if (!flag) 95 | printk(KERN_ALERT "Pid [%d] doesn't seem to be in pid list!\n", dev->pd->pid); 96 | } 97 | 98 | /* write pd_str to userspace */ 99 | if (copy_to_user(buf, dev->pd->pd_str, strlen(dev->pd->pd_str))) { 100 | retval = -EFAULT; 101 | goto out; 102 | } 103 | 104 | *f_pos = strlen(dev->pd->pd_str); 105 | retval = strlen(dev->pd->pd_str); 106 | 107 | out: 108 | up(&dev->sem); 109 | return retval; 110 | } 111 | 112 | /* 113 | * 'write' system call, when user writes to the device file 114 | */ 115 | ssize_t pd_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { 116 | struct pd_dev *dev = filp->private_data; /* we had stored 'dev' in private_data, else use container_of */ 117 | ssize_t retval = -ENOMEM; 118 | char *spid, *estr; 119 | pid_t ipid; 120 | 121 | spid = kmalloc(sizeof(pid_t) * 1, GFP_KERNEL); /* pid is read a a string */ 122 | estr = kmalloc(sizeof(pid_t) * 1, GFP_KERNEL); /* needed for simple_strtol */ 123 | memset(spid, 0, sizeof(pid_t) * 1); 124 | 125 | /* get a lock */ 126 | if(down_interruptible(&dev->sem)) 127 | return -ERESTARTSYS; /* use -EINTR if there will be inconsistency if the call to function is made again */ 128 | 129 | if (count > 100) 130 | count = 100; 131 | 132 | /* write the pid to spid */ 133 | if(copy_from_user(spid, buf, count)) { 134 | retval = -EFAULT; 135 | goto out; 136 | } 137 | spid[count-1] = '\0'; /* i don't have to do this because of memset! */ 138 | 139 | // string to long 140 | ipid = simple_strtol(spid, &estr, 10); /* 10 says, use decimal base */ 141 | dev->pd->pid = ipid; 142 | 143 | /* update the file_pointer with new position */ 144 | *f_pos = count; 145 | retval = count; 146 | 147 | out: 148 | up(&dev->sem); 149 | return retval; 150 | } 151 | 152 | 153 | /* 154 | * setting up the file operations 155 | */ 156 | struct file_operations pd_fops = { 157 | .owner = THIS_MODULE, 158 | .open = pd_open, 159 | .read = pd_read, 160 | .write = pd_write, 161 | }; 162 | 163 | 164 | /* 165 | * Device Setup for each individual device 166 | */ 167 | int pd_dev_setup(struct pd_dev *dev, int nr) { 168 | int err; 169 | dev_t devno = MKDEV(pd_major, pd_minor + nr); 170 | 171 | /* device registration, non-static for device specific registration */ 172 | cdev_init(&dev->cdev, &pd_fops); 173 | dev->cdev.ops = &pd_fops; 174 | dev->cdev.owner = THIS_MODULE; 175 | 176 | /* tells the kernel about the registration */ 177 | err = cdev_add(&dev->cdev, devno, 1); 178 | 179 | if (err) { 180 | printk(KERN_WARNING "Error during setting up 'proc_desc' device no [%d]\n", nr); 181 | return err; 182 | } 183 | 184 | /* create the 'pd' space */ 185 | dev->pd = kmalloc(sizeof(struct pd_data) * 1, GFP_KERNEL); 186 | /* pd string space */ 187 | dev->pd->pd_str = kmalloc(sizeof(char) * PD_STR_SIZE, GFP_KERNEL); 188 | memset(dev->pd->pd_str, 0, sizeof(char) * PD_STR_SIZE); 189 | 190 | /* initialize the PID to -1, else if read is first we should say PID is not valid */ 191 | dev->pd->pid = -1; 192 | 193 | return 0; 194 | } 195 | 196 | /* 197 | * Initialization Module Code, called during module insertion 198 | */ 199 | static int __init pd_init_module(void) { 200 | int result = -1; 201 | int i; 202 | dev_t dev = 0; 203 | 204 | /* register the character device */ 205 | result = alloc_chrdev_region(&dev, pd_minor, pd_nr, "proc_desc"); 206 | if (result < 0) { 207 | pd_major = MAJOR(dev); 208 | printk(KERN_WARNING "proc_desc: can't get major %d\n", pd_major); 209 | return result; 210 | } 211 | 212 | pd_major = MAJOR(dev); 213 | 214 | /* allocate the devices */ 215 | /* GFP_KERNEL is the flag to use in process context code when it is safe to sleep. The 216 | kernel will do whatever it has to do to obtain the memory requested by the caller. */ 217 | pd_device = kmalloc(pd_nr * sizeof(struct pd_dev), GFP_KERNEL); 218 | 219 | 220 | /* setup each device */ 221 | for (i=0; ipd_str); 241 | /* free the pd_data first, else pointer to be it will be lost */ 242 | kfree(pd_device[i].pd); 243 | /* unregister the character device */ 244 | cdev_del(&pd_device[i].cdev); 245 | } 246 | 247 | /* clean the device sctructure */ 248 | kfree(pd_device); 249 | 250 | unregister_chrdev_region(devno, pd_nr); 251 | printk(KERN_INFO "Removed Module 'pd_dev' [%d]\n", MAJOR(devno)); 252 | } 253 | 254 | module_init(pd_init_module); 255 | module_exit(pd_exit_module); 256 | -------------------------------------------------------------------------------- /proc_desc/proc_desc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _PROC_DESC_H_ 3 | #define _PROC_DESC_H_ 4 | 5 | #ifndef PD_MAJOR 6 | #define PD_MAJOR 0 /* dynamic major number */ 7 | #endif 8 | 9 | #ifndef PD_NR 10 | #define PD_NR 1 11 | #endif 12 | 13 | #ifndef PD_STR_SIZE 14 | #define PD_STR_SIZE 1024 15 | #endif 16 | 17 | /* Storage of a PID and its 'task_struct' */ 18 | struct pd_data { 19 | pid_t pid; /* pid corresponding to below task_struct */ 20 | char *pd_str; /* pointer to task_struct */ 21 | }; 22 | 23 | /* our device structure */ 24 | struct pd_dev { 25 | struct pd_data *pd; 26 | struct semaphore sem; /* mutual exclusion semaphore */ 27 | struct cdev cdev; /* Char device structure */ 28 | }; 29 | 30 | 31 | #endif /* _PROC_DESC_H_ */ 32 | -------------------------------------------------------------------------------- /proc_desc/proc_desc_load: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | module="proc_desc" 4 | device="proc_desc" 5 | mode="664" 6 | device_nr=1 7 | 8 | 9 | # Group: since distributions do it differently, look for wheel or use staff 10 | if grep -q '^staff:' /etc/group; then 11 | group="staff" 12 | else 13 | group="wheel" 14 | fi 15 | 16 | 17 | # invoke insmod with all arguments we got 18 | # and use a pathname, as insmod doesn't look in . by default 19 | /sbin/insmod ./$module.ko $* || exit 1 20 | 21 | 22 | # retrieve major number 23 | major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices) 24 | 25 | 26 | # Remove stale nodes and replace them, then give gid and perms 27 | for((i=0; i. The process descriptor contains all the information about 50 | a specific process (contains open files, the process’s address space, 51 | pending signals, the process’s state, and much more) 52 | 53 | 54 | page 52: 55 | ------- 56 | Each task’s thread_info structure is allocated at the end of its stack.The task element 57 | of the structure is a pointer to the task’s actual task_struct. 58 | 59 | 60 | page 54: 61 | ------- 62 | TASK_RUNNING—The process is runnable; it is either currently running or on a run- 63 | queue waiting to run. this is the only possible state for a process executing in user-space; 64 | 65 | TASK_INTERRUPTIBLE—The process is sleeping (that is, it is blocked), waiting for 66 | some condition to exist. When this condition exists, the kernel sets the process’s 67 | state to TASK_RUNNING.The process also awakes prematurely and becomes runnable 68 | if it receives a signal. 69 | 70 | 71 | page 55: 72 | ------- 73 | TASK_UNINTERRUPTIBLE—This state is identical to TASK_INTERRUPTIBLE except 74 | that it does not wake up and become runnable if it receives a signal. 75 | 76 | __TASK_STOPPED—Process execution has stopped; the task is not running nor is it 77 | eligible to run.This occurs if the task receives the SIGSTOP, SIGTSTP, SIGTTIN,or 78 | SIGTTOU signal or if it receives any signal while it is being debugged. 79 | 80 | QUESTION: to which queue is a processed moved when it receives SIGSTOP? 81 | 82 | page 56: 83 | ------- 84 | All processes are descendants of the init process, whose PID is one.The kernel starts 85 | init in the last step of the boot process.The init process, in turn, reads the system 86 | initscripts and executes more programs, eventually completing the boot process. 87 | The relationship between processes is stored in the process descriptor. Each task_struct 88 | has a pointer to the parent’s task_struct, named parent, and a list of children, named 89 | children. 90 | 91 | 92 | page 59: 93 | ------- 94 | The fork(), vfork(), and __clone() library calls all invoke the clone() system call with the 95 | requisite flags.The clone() system call, in turn, calls do_fork(). do_fork() calls copy_process(). 96 | Back in do_fork(), if copy_process() returns successfully, the new child is woken up 97 | and run. Deliberately, the kernel runs the child process first. In the common case of the 98 | child simply calling exec() immediately, this eliminates any copy-on-write overhead that 99 | would occur if the parent ran first and began writing to the address space. 100 | 101 | READ: forking, do_fork() and copy_process(). 102 | 103 | 104 | page 60: 105 | ------- 106 | The vfork()system call has the same effect as fork(), except that the page table entries 107 | of the parent process are not copied. Instead, the child executes as the sole thread in the 108 | parent’s address space, and the parent is blocked until the child either calls exec() or exits. 109 | The child is not allowed to write to the address space. 110 | 111 | 112 | page 61: 113 | ------- 114 | Each thread has a unique task_struct and appears to the kernel as a normal process— 115 | threads just happen to share resources, such as an address space, with other processes. 116 | 117 | QUESTION: does each thread has a PID or how is it managed in Linux? 118 | 119 | Threads are created the same as normal tasks, with the exception that the clone() system 120 | call is passed flags corresponding to the specific resources to be shared: 121 | clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0); 122 | 123 | In contrast, a normal fork() can be implemented as clone(SIGCHLD, 0); 124 | And vfork() is implemented as clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0); 125 | 126 | QUESTION: what is an idle task? 127 | 128 | 129 | page 62: 130 | ------- 131 | The significant difference between kernel threads and normal processes is that 132 | kernel threads do not have an address space. (Their mm pointer, which points at their 133 | address space, is NULL.) They operate only in kernel-space and do not context switch into 134 | user-space. Kernel threads, however, are schedulable and preemptable, the same as normal 135 | processes. 136 | 137 | 138 | page 63: 139 | ------- 140 | a kernel thread can be created only by another kernel 141 | thread.The kernel handles this automatically by forking all new kernel threads off of the 142 | kthreadd kernel process. 143 | 144 | When a process terminates, the kernel releases 145 | the resources owned by the process and notifies the child’s parent of its demise. 146 | 147 | 148 | page 64: 149 | ------- 150 | READ: do_exit(). 151 | 152 | after do_exit, all objects associated with the task (assuming the task was the sole user) 153 | are freed.The task is not runnable (and no longer has an address space in which to run) 154 | and is in the EXIT_ZOMBIE exit state.The only memory it occupies is its kernel stack, the 155 | thread_info structure, and the task_struct structure.The task exists solely to provide 156 | information to its parent.After the parent retrieves the information, or notifies the kernel 157 | that it is uninterested, the remaining memory held by the process is freed and returned to 158 | the system for use. 159 | 160 | After do_exit() completes, the process descriptor for the terminated process still exists, 161 | but the process is a zombie and is unable to run. this enables the system to 162 | obtain information about a child process after it has terminated. 163 | 164 | 165 | page 65: 166 | ------- 167 | After the parent has obtained information on its terminated child, or signified to the kernel that it 168 | does not care, the child’s task_struct is deallocated. 169 | 170 | The wait() family of functions are implemented via a single (and complicated) system 171 | call, wait4().The standard behavior is to suspend execution of the calling task until one 172 | of its children exits, at which time the function returns with the PID of the exited child. 173 | Additionally, a pointer is provided to the function that on return holds the exit code of 174 | the terminated child. 175 | 176 | READ: release_task() 177 | 178 | QUESTION: how is process group and exit() related along with zombies? 179 | 180 | If a parent exits before its children, some mechanism must exist to reparent any child tasks 181 | to a new process, or else parentless terminated processes would forever remain zombies, 182 | wasting system memory.The solution is to reparent a task’s children on exit to either 183 | another process in the current thread group or, if that fails, the init process. 184 | 185 | 186 | page 67: 187 | ------- 188 | When a task is ptraced, it is temporarily reparented to the debug- 189 | ging process.When the task’s parent exits, however, it must be reparented along with its 190 | other siblings. The solution is simply to keep a separate list of a process’s children 191 | being ptraced—reducing the search for one’s children from every process to just two rela- 192 | tively small lists. 193 | With the process successfully reparented, there is no risk of stray zombie processes.The 194 | init process routinely calls wait() on its children, cleaning up any zombies assigned to it. 195 | 196 | QUESTION: ptrace() and parenting, why should it make debugging process as parent ? 197 | 198 | 199 | 200 | Chapter 4, Process Scheduling 201 | ============================= 202 | 203 | page 68: 204 | ------- 205 | Multitasking operating systems come in two flavors: cooperative multitasking and 206 | preemptive multitasking. 207 | In preemptive multitasking, the scheduler decides when a process is to 208 | cease running and a new process is to begin running. involuntarily 209 | suspending a running process is called preemption. 210 | in cooperative multitasking, a process does not stop running until it voluntary 211 | decides to do so.The act of a process voluntarily suspending itself is called yielding. 212 | 213 | page 69: 214 | ------- 215 | although the O(1) scheduler was ideal for large server workloads—which 216 | lack interactive processes—it performed below par on desktop systems, 217 | 218 | page 70: 219 | ------- 220 | A scheduler policy for processor-bound processes, therefore, 221 | tends to run such processes less frequently but for longer durations. 222 | 223 | page 71: 224 | ------- 225 | The Linux kernel implements two separate priority ranges.The first is the nice value, a 226 | number from –20 to +19 with a default of 0. Larger nice values correspond to a lower 227 | priority—you are being “nice” to the other processes on the system. 228 | The second range is the real-time priority.The values are configurable, but by default 229 | range from 0 to 99, inclusive. Opposite from nice values, higher real-time priority values 230 | correspond to a greater priority. 231 | 232 | page 73: 233 | ------- 234 | The Linux scheduler is modular, enabling different algorithms to schedule different types 235 | of processes.This modularity is called scheduler classes. Scheduler classes enable different, 236 | pluggable algorithms to coexist, scheduling their own types of processes. Each scheduler 237 | class has a priority.The base scheduler code, which is defined in kernel/sched.c, iterates 238 | over each scheduler class in order of priority.The highest priority scheduler class that has 239 | a runnable process wins, selecting who runs next. 240 | 241 | page 74: 242 | ------- 243 | Process Scheduling in Unix Systems (whole section is interesting) 244 | 245 | Indeed, given 246 | that high nice value (low priority) processes tend to be background, processor-intensive 247 | tasks, while normal priority processes tend to be foreground user tasks, this timeslice 248 | allotment is exactly backward from ideal! ==> MEANS high nice value makes processor-intensive 249 | tasks background and user tasks foreground. (it should be such that user processes should be 250 | background and come foreground during any events?) 251 | 252 | page 75: 253 | ------- 254 | old unix schedulrs assign absolute timeslices to nice value yields 255 | a constant switching rate but variable fairness. 256 | CFS yields constant fairness but a variable switching rate. 257 | 258 | page 76: 259 | ------- 260 | CFS sets a target for its approximation of the “infinitely small scheduling 261 | duration in perfect multitasking.This target is called the targeted latency. 262 | 263 | Instead of using the nice value to calculate a timeslice, CFS uses the nice value to weight the propor- 264 | tion of processor a process is to receive: Higher valued (lower priority) processes receive a 265 | fractional weight relative to the default nice value, whereas lower valued (higher priority) 266 | processes receive a larger weight. 267 | 268 | CFS imposes a floor on the timeslice assigned to each 269 | process.This floor is called the minimum granularity. 270 | 271 | page 77: 272 | ------- 273 | the proportion of processor time that any process receives is determined 274 | only by the relative difference in niceness between it and the other runnable processes. 275 | The nice values, instead of yielding additive increases to timeslices, yield geometric differ- 276 | ences.The absolute timeslice allotted any nice value is not an absolute number, but a 277 | given proportion of the processor. CFS is called a fair scheduler because it gives each 278 | process a fair share—a proportion—of the processor’s time.As mentioned, note that CFS 279 | isn’t perfectly fair, because it only approximates perfect multitasking, but it can place a 280 | lower bound on latency of n for n runnable processes on the unfairness. 281 | 282 | page 78: 283 | ------- 284 | The vruntime variable stores the virtual runtime of a process, which is the actual runtime 285 | (the amount of time spent running) normalized (or weighted) by the number of runnable 286 | processes. CFS uses vruntime to account for how long a process has run and thus how much 287 | longer it ought to run (function update_curr() does this). 288 | 289 | 290 | page 79: 291 | ------- 292 | update_curr() is invoked periodically by the system timer and also whenever a 293 | process becomes runnable or blocks, becoming unrunnable. In this manner, vruntime is 294 | an accurate measure of the runtime of a given process and an indicator of what process 295 | should run next. 296 | 297 | page 80: 298 | ------- 299 | when CFS is deciding what process to run next, it picks the process with the smallest vruntime. 300 | 301 | page 84: 302 | ------- 303 | schedule() is generic with 304 | respect to scheduler classes.That is, it finds the highest priority scheduler class with a 305 | runnable process and asks it what to run next. 306 | 307 | page 89: 308 | ------- 309 | Context switching, the switching from one runnable task to another, is handled by the 310 | context_switch()function defined in kernel/sched.c. It is called by schedule() 311 | when a new process has been selected to run. It does two basic jobs: 312 | 1. Calls switch_mm(), which is declared in , to switch the vir- 313 | tual memory mapping from the previous process’s to that of the new process. 314 | 2. Calls switch_to(), declared in , to switch the processor state from 315 | the previous process’s to the current’s.This involves saving and restoring stack infor- 316 | mation and the processor registers and any other architecture-specific state that 317 | must be managed and restored on a per-process basis. 318 | 319 | the kernel provides the need_resched flag to signify whether a reschedule should be performed 320 | .This flag is set by scheduler_tick() when a process should be preempted, and 321 | by try_to_wake_up() when a process that has a higher priority than the currently run- 322 | ning process is awakened.The kernel checks the flag, sees that it is set, and calls schedule() 323 | to switch to a new process.The flag is a message to the kernel that the scheduler should be 324 | invoked as soon as possible because another process deserves to run. 325 | 326 | Upon returning to user-space or returning from an interrupt, the need_resched flag is 327 | checked. If it is set, the kernel invokes the scheduler before continuing. 328 | The flag is per-process, and not simply global, because it is faster to access a value in 329 | the process descriptor (because of the speed of current and high probability of it being 330 | cache hot) than a global variable. (need_resched is a special flag variable inside the 331 | thread_info structure). 332 | 333 | page 90: 334 | ------- 335 | In short, user preemption can occur 336 | 1. When returning to user-space from a system call 337 | 2. When returning to user-space from an interrupt handler 338 | 339 | So when is it safe to reschedule? The kernel can preempt a task running in the kernel 340 | so long as it does not hold a lock.That is, locks are used as markers of regions of nonpre- 341 | emptibility. Because the kernel is SMP-safe, if a lock is not held, the current code is reen- 342 | trant and capable of being preempted. 343 | 344 | The first change in supporting kernel preemption was the addition of a preemption 345 | counter, preempt_count, to each process's thread_info.This counter begins at zero and 346 | increments once for each lock that is acquired and decrements once for each lock that is 347 | released.When the counter is zero, the kernel is preemptible. Upon return from interrupt, 348 | if returning to kernel-space, the kernel checks the values of need_resched and 349 | preempt_count. If need_resched is set and preempt_count is zero, then a more impor- 350 | tant task is runnable, and it is safe to preempt.Thus, the scheduler is invoked. If 351 | preempt_count is nonzero, a lock is held, and it is unsafe to reschedule. In that case, the 352 | interrupt returns as usual to the currently executing task.When all the locks that the cur- 353 | rent task is holding are released, preempt_count returns to zero.At that time, the unlock 354 | code checks whether need_resched is set. If so, the scheduler is invoked. Kernel preemption can 355 | also occur explicitly, when a task in the kernel blocks or explicitly calls schedule(). 356 | 357 | page 91: 358 | ------ 359 | Kernel preemption can occur 360 | 1. When an interrupt handler exits, before returning to kernel-space 361 | 2. When kernel code becomes preemptible again 362 | 3. If a task in the kernel explicitly calls 363 | schedule() 364 | 4. If a task in the kernel blocks (which results in a call to 365 | schedule()) 366 | 367 | Real-Time Scheduling Policies (READ WHOLE SECTION) 368 | 369 | 370 | will "a + b" invoke any system calls? --------------------------------------------------------------------------------