diff --git a/README.md b/README.md index fc57870..8da6509 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,19 @@ We have not managed to track this problem down yet, but the following workaround This started happening when we switched to building QEMU through Buildroot, and has not been observed on later Ubuntu. +## Filesystem persistency + +The root filesystem is persistent across: + + ./runqemu + ./runqemu + +However, when you do: + + ./run + +it gets overwritten by a fresh filesystem and you lose all changes. + ## Text mode Show serial output of QEMU directly on the current terminal, without opening a QEMU window: diff --git a/kernel_module/README.md b/kernel_module/README.md index 8913db3..99b099c 100644 --- a/kernel_module/README.md +++ b/kernel_module/README.md @@ -9,24 +9,26 @@ 1. [panic](panic.c) 1. [params](params.c) 1. [fops](fops.c) - 1. [ioctl](ioctl.c) - 1. [poll](poll.c) - 1. [anonymous_inode](anonymous_inode.c) + 1. [ioctl](ioctl.c) + 1. [poll](poll.c) + 1. [anonymous_inode](anonymous_inode.c) + 1. [seq_file](seq_file.c) + 1. [seq_file_single](seq_file_inode.c) 1. Asynchronous - 1. [workqueue](workqueue.c) - 1. [sleep](sleep.c) - 1. [kthread](kthread.c) - 1. [kthreads](kthreads.c) - 1. [schedule](schedule.c) - 1. [timer](timer.c) - 1. [work_from_work](work_from_work.c) + 1. [workqueue](workqueue.c) + 1. [sleep](sleep.c) + 1. [kthread](kthread.c) + 1. [kthreads](kthreads.c) + 1. [schedule](schedule.c) + 1. [timer](timer.c) + 1. [work_from_work](work_from_work.c) 1. [irq](irq.c) 1. Module dependencies - 1. [dep](dep.c) - 1. [dep2](dep2.c) + 1. [dep](dep.c) + 1. [dep2](dep2.c) 1. [character_device](character_device.c) 1. Hardware device drivers - 1. [pci_min](pci_min.c) - 1. [pci](pci.c) - 1. [platform_device](platform_device.c) + 1. [pci_min](pci_min.c) + 1. [pci](pci.c) + 1. [platform_device](platform_device.c) 1. [user](user/) diff --git a/kernel_module/fops.c b/kernel_module/fops.c index beb01d9..b0dd3bb 100644 --- a/kernel_module/fops.c +++ b/kernel_module/fops.c @@ -20,7 +20,7 @@ Here we use debugfs. #include /* copy_from_user, copy_to_user */ #include #include /* EFAULT */ -#include +#include /* file_operations */ #include /* min */ #include #include /* printk */ diff --git a/kernel_module/hello.c b/kernel_module/hello.c index 1b65f24..9e43c53 100644 --- a/kernel_module/hello.c +++ b/kernel_module/hello.c @@ -15,13 +15,13 @@ MODULE_LICENSE("GPL"); static int myinit(void) { - printk(KERN_INFO "hello init\n"); + pr_info("hello init\n"); return 0; } static void myexit(void) { - printk(KERN_INFO "hello exit\n"); + pr_info("hello exit\n"); } module_init(myinit) diff --git a/kernel_module/hello2.c b/kernel_module/hello2.c index 1fbbf43..e643a97 100644 --- a/kernel_module/hello2.c +++ b/kernel_module/hello2.c @@ -11,13 +11,13 @@ MODULE_LICENSE("GPL"); static int myinit(void) { - printk(KERN_INFO "hello2 init\n"); + pr_info("hello2 init\n"); return 0; } static void myexit(void) { - printk(KERN_INFO "hello2 exit\n"); + pr_info("hello2 exit\n"); } module_init(myinit) diff --git a/kernel_module/seq_file.c b/kernel_module/seq_file.c new file mode 100644 index 0000000..fea041b --- /dev/null +++ b/kernel_module/seq_file.c @@ -0,0 +1,90 @@ +/* +Adapted from: http://allskyee.blogspot.co.uk/2011/12/proc-seqfile-write.html + +Writting trivial read fops is repetitive and error prone. + +The seq_file API makes the process much easier for those trivial cases. + +There is not write version however, as writes are more complex: +https://stackoverflow.com/questions/30710517/how-to-implement-a-writable-proc-file-by-using-seq-file-in-a-driver-module +*/ + +#include /* copy_from_user, copy_to_user */ +#include +#include /* EFAULT */ +#include +#include +#include /* pr_info */ +#include /* seq_read, seq_lseek, single_release */ +#include /* S_IRUSR */ + +MODULE_LICENSE("GPL"); + +static struct dentry *debugfs_file; + +static void * next(struct seq_file *s, void *v, loff_t *pos) +{ + pr_info("next\n"); + (*(unsigned long *)v)++; + (*pos)++; + return *pos < 3 ? v : NULL; +} + +static void * start(struct seq_file *s, loff_t *pos) +{ + static unsigned long counter = 0; + + pr_info("start pos = %llx\n", (unsigned long long)*pos); + if (*pos == 0) { + return &counter; + } else { + *pos = 0; + return NULL; + } +} + +static int show(struct seq_file *s, void *v) +{ + pr_info("show\n"); + seq_printf(s, "%lx\n", *(unsigned long *)v); + return 0; +} + +static void stop(struct seq_file *s, void *v) +{ + pr_info("stop\n"); +} + +static struct seq_operations my_seq_ops = { + .next = next, + .show = show, + .start = start, + .stop = stop, +}; + +static int open(struct inode *inode, struct file *file) +{ + return seq_open(file, &my_seq_ops); +} + +static struct file_operations fops = { + .owner = THIS_MODULE, + .llseek = seq_lseek, + .open = open, + .read = seq_read, + .release = seq_release +}; + +static int myinit(void) +{ + debugfs_file = debugfs_create_file("lkmc_seq_file", S_IRUSR | S_IWUSR, NULL, NULL, &fops); + return 0; +} + +static void myexit(void) +{ + debugfs_remove(debugfs_file); +} + +module_init(myinit) +module_exit(myexit) diff --git a/kernel_module/seq_file_single.c b/kernel_module/seq_file_single.c new file mode 100644 index 0000000..d70ba6d --- /dev/null +++ b/kernel_module/seq_file_single.c @@ -0,0 +1,49 @@ +/* +For single reads, single_open is an even more convenient version of seq_file. +*/ + +#include /* copy_from_user, copy_to_user */ +#include +#include /* EFAULT */ +#include +#include +#include /* pr_info */ +#include /* seq_read, seq_lseek, single_release */ +#include /* S_IRUSR */ + +MODULE_LICENSE("GPL"); + +static struct dentry *debugfs_file; + +static int show(struct seq_file *m, void *v) +{ + seq_printf(m, "abcd\n"); + return 0; +} + +static int open(struct inode *inode, struct file *file) +{ + return single_open(file, show, NULL); +} + +static const struct file_operations fops = { + .llseek = seq_lseek, + .open = open, + .owner = THIS_MODULE, + .read = seq_read, + .release = single_release, +}; + +static int myinit(void) +{ + debugfs_file = debugfs_create_file("lkmc_seq_file", S_IRUSR | S_IWUSR, NULL, NULL, &fops); + return 0; +} + +static void myexit(void) +{ + debugfs_remove(debugfs_file); +} + +module_init(myinit) +module_exit(myexit) diff --git a/rootfs_overlay/seq_file.sh b/rootfs_overlay/seq_file.sh new file mode 100755 index 0000000..c08b3e2 --- /dev/null +++ b/rootfs_overlay/seq_file.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +set -ex + +insmod /seq_file.ko +cd /sys/kernel/debug + +cat 'lkmc_seq_file' +# => 0 +# => 1 +# => 2 + +cat 'lkmc_seq_file' +# => 3 +# => 4 +# => 5 + +# TODO understand, why does this print nothing? +dd if='lkmc_seq_file' bs=1 count=2 skip=2 diff --git a/rootfs_overlay/seq_file_single.sh b/rootfs_overlay/seq_file_single.sh new file mode 100755 index 0000000..9a93533 --- /dev/null +++ b/rootfs_overlay/seq_file_single.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -ex +insmod /seq_file_single.ko +cd /sys/kernel/debug +cat 'lkmc_seq_file_single' +# => abcd +dd if='lkmc_seq_file_single' bs=1 skip=2 +# => cd