...
 
Commits (17)
......@@ -562,6 +562,7 @@ scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \
init-y := init/
drivers-y := drivers/ sound/ firmware/
net-y := net/
foobar-y := foobar/
libs-y := lib/
core-y := usr/
virt-y := virt/
......@@ -899,7 +900,7 @@ core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/
vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
$(core-y) $(core-m) $(drivers-y) $(drivers-m) \
$(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y)))
$(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y) $(foobar-y)))
vmlinux-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \
$(init-) $(core-) $(drivers-) $(net-) $(libs-) $(virt-))))
......@@ -908,6 +909,7 @@ init-y := $(patsubst %/, %/built-in.o, $(init-y))
core-y := $(patsubst %/, %/built-in.o, $(core-y))
drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y))
net-y := $(patsubst %/, %/built-in.o, $(net-y))
foobar-y := $(patsubst %/, %/built-in.o, $(foobar-y))
libs-y1 := $(patsubst %/, %/lib.a, $(libs-y))
libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y))
libs-y := $(libs-y1) $(libs-y2)
......@@ -915,7 +917,7 @@ virt-y := $(patsubst %/, %/built-in.o, $(virt-y))
# Externally visible symbols (used by link-vmlinux.sh)
export KBUILD_VMLINUX_INIT := $(head-y) $(init-y)
export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) $(virt-y)
export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) $(virt-y) $(foobar-y)
export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds
export LDFLAGS_vmlinux
# used by scripts/pacmage/Makefile
......
PMFS Introduction
Lightweight Capabiltiy Domains (LCDs) Introduction
=================
PMFS is a file system for persistent memory. The file system is optimized to be
lightweight and efficient in providing access to persistent memory that is
directly accessible via CPU load/store instructions. It manages the persistent
memory directly and avoids the block driver layer and page cache layer and thus
provides synchronous reads and writes to persistent area. It supports all the
existing POSIX style file system APIs so that the applications need not be
modified to use this file system. In addition, PMFS provides support for huge
pages to minimize TLB entry usage and speed up virtual address lookup. PMFS's
mmap interface can map a file's data directly into the process's address space
without any intermediate buffering. This file system has been validated using
DRAM to emulate persistent memory. Hence, PMFS also provides an option to load
the file system from a disk-based file into memory during mount and save the
file system from memory into the disk-based file during unmount. PMFS also
guarantees consistent and durable updates to the file system meta-data against
arbitrary system and power failures. PMFS uses journaling (undo log) to provide
consistent updates to meta-data.
Configuring PMFS
================
PMFS uses a physically contiguous area of DRAM (which is not used by the
kernel) as the file system space. To make sure that the kernel doesn't use a
certain contiguous physical memory area you can boot the kernel with 'memmap'
kernel command line option. For more information on this, please see
Documentation/kernel-parameters.txt.
For example, adding 'memmap=2G$4G' to the kernel boot parameters will reserve
2G of memory, starting at 4G. (You may have to escape the $ so it isn't
interpreted by GRUB 2, if you use that as your boot loader.)
After the OS has booted, you can initialize PMFS during mount command by
passing 'init=' mount option.
For example,
<pre>#mount -t pmfs -o physaddr=0x100000000,init=2G none /mnt/pmfs</pre>
The above command will create a PMFS file system in the 2GB region starting at
0x100000000 (4GB) and mount it at /mnt/pmfs. There are many other mount time
options supported by pmfs. Some of the main options include:
wprotect: This option protects pmfs from stray writes (e.g., because of kernel
bugs). It makes sure that the file system is mapped read-only into the kernel
and makes it writable only for a brief period when writing to it. (EXPERIMENTAL,
Use with Caution).
jsize: This option specifies the journal size. Default is 4MB.
hugemmap: This option enables support for using huge pages in memory-mapped
files.
backing: This option specifies a disk based file which should be used as a
persistent backing store for pmfs during mount and unmount.
<pre>#mount -t pmfs -o physaddr=0x100000000,init=2G,backing="/data/pmfs.img" none /mnt/pmfs</pre>
The above example initializes a 2GB PMFS and during unmount it saves the file
system into a file /data/pmfs.img
<pre>#mount -t pmfs -o physaddr=0x100000000,backing="/data/pmfs.img" none /mnt/pmfs</pre>
The above example loads the PMFS from /data/pmfs.img during mount and saves
the file system to /data/pmfs.img during unmount.
backing_opt: This option specifies how the backing file should be used. It can
have 2 values;
1: This value means that PMFS will not be loaded from the backing file during
mount. It is either created using 'init=' option, or the pre-existing file
system in the memory is used.
2: This value means that the PMFS will not be stored to the backing file during
unmount.
If backing_opt is not specified, PMFS will load the file system from backing
file (if init= option is not specified) during mount and store the file system
to the backing file during unmount.
<pre>#mount -t pmfs -o physaddr=0x100000000,backing="/data/pmfs.img",backing_opt=2 none /mnt/pmfs</pre>
The above example loads the PMFS from /data/pmfs.img during mount but does not
save the file system to /data/pmfs.img during unmount.
<pre>#mount -t pmfs -o physaddr=0x100000000,backing="/data/pmfs.img",backing_opt=1 none /mnt/pmfs</pre>
The above example assumes that there is a PMFS already present at the specified
physical address (create during an earlier mount). It uses that same PMFS
instead of loading it from /data/pmfs.img. It, however, saves the file system
to /data/pmfs.img during unmount.
For full list of options, please refer to the source code.
Using Huge Pages with PMFS
==========================
PMFS supports the use of huge-pages through the fallocate(), and ftruncate()
system calls. These functions set the file size and also provide PMFS with a
hint about what data-block size to use (fallocate() also pre-allocates the
data-blocks). For example, if we set the file size below 2MB, 4KB blocksize is
used. If we set the file size between >= 2MB but < 1GB, 2MB block size is used,
and if we set the file size >= 1GB, 1GB block-size is used. fallocate() or
ftruncate() should be called on a empty file (size 0) for the block-size hint
to be applied properly. So, a good way to use Huge Pages in PMFS is to open a
new file through the open() system call, and call fallocate() or ftruncate() to
set the file size and block-size hint. Remember, that it is only a hint, so if
PMFS can't find enough free blocks of a particular size, it will try to use
smaller block-size. If the block-size hint is not set, default 4KB block-size
will be used for file's data-blocks.
Current Limitations
===================
* PMFS uses a memory region not used by the kernel. Hence the memory needs to
be reserved by using the memmap= option or using BIOS ACPI tables.
* Because of multiple blocksize support, PMFS supports multiple max file
sizes. For example, if the file's block size is 4KB, the file can grow up to
512 GB in size, if blocksize is 2MB, file can grow up to 256 TB, and if the
blocksize is 1GB, the file can grow up to 128 PB.
* PMFS does not currently support extended attributes.
* PMFS currently only works with x86_64 kernels.
Contributing
============
Please send bug reports/comments/feedback to the PMFS development
list: linux-pmfs@lists.infradead.org
You are also encouraged to subscribe to the mailing list
by sending an email with the Subject line **subscribe** to
linux-pmfs-request@lists.infradead.org.
We prefer pull requests as patches sent to the mailing list.
Also feel free to join us on the IRC channel #pmfs on irc.oftc.net.
......@@ -2776,3 +2776,5 @@ source "crypto/Kconfig"
source "arch/x86/kvm/Kconfig"
source "lib/Kconfig"
source "foobar/Kconfig"
......@@ -202,4 +202,5 @@ source "drivers/hwtracing/intel_th/Kconfig"
source "drivers/fpga/Kconfig"
source "drivers/foobar/Kconfig"
endmenu
......@@ -173,3 +173,4 @@ obj-$(CONFIG_STM) += hwtracing/stm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_NVMEM) += nvmem/
obj-$(CONFIG_FPGA) += fpga/
obj-$(CONFIG_FOOBAR) += foobar/
menuconfig FOOBARDEVICES
depends on FOOBAR
bool "Foobar device support"
---help---
Foobar device driver support
If unsure, say Y.
if FOOBARDEVICES
config FOOBAR_DUMMY
tristate "Dummy foobar driver support"
---help---
Foobar dummy device driver.
To compile this driver as a module, choose M here: the module
will be called dummy.
endif # FOOBARDEVICES
obj-$(CONFIG_FOOBAR_DUMMY) += dummy.o
/* dummy.c: a dummy foobar driver */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/foobar_device.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#define DRV_NAME "foobardummy"
#define DRV_VERSION "1.0"
static int dummy_dev_init(struct foobar_device *dev)
{
dev->dstats = kmalloc(sizeof(struct foo_stats), GFP_KERNEL);
if (!dev->dstats)
return -ENOMEM;
return 0;
}
static void dummy_dev_uninit(struct foobar_device *dev)
{
kfree(dev->dstats);
}
static const struct foobar_device_ops dummy_foobardev_ops = {
.init = dummy_dev_init,
.uninit = dummy_dev_uninit,
};
int numdummies = 0;
/* Number of dummy devices to be set up by this module. */
module_param(numdummies, int, 0);
MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
struct foobar_device *dev_dummy;
static int __init dummy_init_module(void)// the entry point to the dummy device driver
{
int err;
dev_dummy = alloc_foobardev(0, "dummy0");
if (!dev_dummy)
return -ENOMEM;
dev_dummy->foobardev_ops = &dummy_foobardev_ops;
dev_dummy->features = FOOBAR_PRIV_ALLOC;
dev_dummy->flags = FOO_LOOPBACK;
err = register_foobar(dev_dummy);//the call to dev.c fn to register dummy
if (err < 0)
goto err;
return 0;
err:
free_foobardev(dev_dummy);// free the foobar device if an error code is received
return err;
}
static void __exit dummy_cleanup_module(void)
{
unregister_foobar(dev_dummy);
}
module_init(dummy_init_module);
module_exit(dummy_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module foobar() {
projection <struct foobar_device> foobar_device_init {
// ...
}
projection <struct foobar_device> foobar_device_uninit {
// ...
}
projection <struct foobar_device_ops> foobar_device_ops_register_foobar {
//
// Here we have the projections for foobar_device_ops's fields.
//
// Since these fields are function pointers, which the dummy
// device registers with the kernel subsystem we have the rpc
// keyword accompanying the projection definitions of these
// function pointers.
// The directions are "in" since we are registering functions
// from the callee side to the caller side.
// Caller is non-isolated kernel
rpc [in] int (*init)(projection foobar_device_init *dev);
// Caller is non-isolated kernel
rpc [in] void (*uninit)(projection foobar_device_uninit *dev);
}
projection <struct foobar_device> foobar_device_register_foobar {
// "features" is both read and written inside register_foobar()
unsigned long [in,out] features;
unsigned long [in,out] hw_features;
unsigned long [out] wanted_features;
// Here the [in] direction is derrived from the global [in]
// direction of the foobar_device_register_foobar projection, i.e.,
// it's used as [in] with the register_foobar() function
unsigned int flags;
// Attribute & keyword info for foobar_device_ops field:
// projection - Since "foobar_device_ops" is a structure, it
// also needs to be accompanied with the projection keyword.
//
// alloc(callee) - Also, it would need to be allocated in the
// callee side, because it already exists on the caller side
// and will be used on the callee side
projection foobar_device_ops_register_foobar [alloc(callee)] *foobar_device_ops;
}
//
// Caller side is isolated foobar subsystem
//
rpc int register_foobar(projection foobar_device_register_foobar *dev);
projection <struct foobar_device> foobar_device_unregister_foobar {
}
rpc void unregister_foobar(projection foobar_device_unregister_foobar *dev);
projection <struct foobar_device> foobar_device_alloc_foobardev {
int id;
char name[32];
}
// By default
//
// - all scalar types are [in], e.g., id below
//
// - simple char * (we assume that these are strings if no other
// qualifiers are passed, e.g., for a buffer we need char [out,
// len(...)]*buf
//
// - Return values are "out", i.e., we assume an implicit [out] below, e.g.,
// [out, alloc(caller)], but we don't have to write it since it's a return
// value and we can derive the "out"
//
// - [alloc(caller)] we cannot derive since it can be "bind"
//
rpc projection foobar_device_alloc_foobardev [alloc(caller)] *alloc_foobardev(int id, char *name);
projection <struct foobar_device> foobar_device_free_foobardev {
}
rpc void free_foobardev(projection foobar_device_free_foobardev [dealloc(caller)] *dev);
// We also want to support scopes - in this way you can conveniently
// use the same variable names that would be invisible to the rest of
// the idl.
//{
// projection <struct foobar_device> foobar_device {};
// rpc void free_foobardev(projection foobar_device [dealloc(caller)] *dev);
//}
}
#
# Foobar config
#
menuconfig FOOBAR
bool "Foobar support"
---help---
Toy subsystem for working with kernel static analysis
#
# Makefile for the linux foobar
#
obj-$(CONFIG_FOOBAR) := dev.o
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/foobar_device.h>
#include <linux/slab.h>
#include <linux/err.h>
int register_foobar(struct foobar_device *dev)
{
int ret;
/*
Access info for members of foobar_device structure in this function:
hw_features : read and write
features : read and write
wanted_features: write
*/
dev->hw_features |= FOOBAR_IRQ_DELAY;
dev->features |= FOOBAR_SOFTIRQ_ENABLE;
dev->wanted_features = dev->features & dev->hw_features; //Initial val of wanted_features does not matter.
if (dev->flags & FOO_LOOPBACK)
dev->hw_features |= FOOBAR_ZERO_COPY;
/* Init, if this function is available */
if (dev->foobardev_ops->init) {
ret = dev->foobardev_ops->init(dev);
if (ret) {
if (ret > 0)
ret = -EIO;
goto out;
}
}
printk("%s, foobar registered\n", __func__);
out:
return ret;
}
EXPORT_SYMBOL(register_foobar);
void unregister_foobar(struct foobar_device *dev)
{
/* uninit, if this function is available */
if (dev->foobardev_ops->uninit) {
dev->foobardev_ops->uninit(dev);
}
printk("%s, foobar unregistered\n", __func__);
}
EXPORT_SYMBOL(unregister_foobar);
struct foobar_device *alloc_foobardev(int id, const char* name)
{
struct foobar_device *dev = kmalloc(sizeof(struct foobar_device), GFP_KERNEL);
strncpy(dev->name, name, sizeof(dev->name));
dev->id = id;
return dev;
}
EXPORT_SYMBOL(alloc_foobardev);
void free_foobardev(struct foobar_device *dev)
{
kfree(dev);
}
EXPORT_SYMBOL(free_foobardev);
#ifndef _FOOBAR_DEVICE_H
#define _FOOBAR_DEVICE_H
#include <linux/types.h>
typedef u64 foobar_features_t;
/* features */
#define FOOBAR_IRQ_DELAY (1 << 10)
#define FOOBAR_SOFTIRQ_ENABLE (1 << 11)
#define FOOBAR_ZERO_COPY (1 << 12)
#define FOOBAR_PRIV_ALLOC (1 << 13)
/* flags */
#define FOO_LOOPBACK 4
struct foobar_device;
struct foobar_device_ops {
int (*init)(struct foobar_device *dev);
void (*uninit)(struct foobar_device *dev);
};
struct foo_stats {
unsigned num_tx_packets;
unsigned num_rx_packets;
};
struct foobar_device {
char name[32];
unsigned long id;
unsigned long mem_end;
unsigned long mem_start;
unsigned long base_addr;
int irq;
unsigned long state;
unsigned int flags;
unsigned int priv_flags;
struct foo_stats *dstats;
foobar_features_t features;
foobar_features_t hw_features;
foobar_features_t wanted_features;
const struct foobar_device_ops *foobardev_ops;
};
int register_foobar(struct foobar_device *dev);
void unregister_foobar(struct foobar_device *dev);
struct foobar_device *alloc_foobardev(int id, const char* name);
void free_foobardev(struct foobar_device *dev);
#endif /* _FOOBAR_DEVICE_H */
Subproject commit 58432a5225b4c53bc670f92895a1926d93110083
Subproject commit 0850a11612b57e5a7c43adcbb746ebb48f22f132
Subproject commit 56deb16191e604464c1cafd07cecdce95d3e97c5
Subproject commit 8b465a57488421eefedddca9a197d2e1f136651d
......@@ -27,3 +27,4 @@ obj-m += llvm_example/
obj-m += ioremap/
obj-m += ixgbe/
obj-m += nullnet/
obj-m += foobar/
......@@ -57,3 +57,7 @@ ixgbe/net_klcd nonisolated
nullnet/boot nonisolated
nullnet/dummy_lcd isolated
nullnet/net_klcd nonisolated
foobar/boot nonisolated
foobar/dummy_lcd isolated
foobar/foobar_klcd nonisolated
obj-$(LCD_CONFIG_BUILD_FOOBAR_BOOT) += boot/
obj-$(LCD_CONFIG_BUILD_FOOBAR_DUMMY_LCD) += dummy_lcd/
obj-$(LCD_CONFIG_BUILD_FOOBAR_FOOBAR_KLCD) += foobar_klcd/
obj-m += lcd_test_mod_foobar_boot.o
lcd_test_mod_foobar_boot-y += main.o
ccflags-y += $(NONISOLATED_CFLAGS)
/*
* boot.c - non-isolated kernel module, does setup
* when fake minix and vfs are to be launched
* in isolated containers
*/
#include <lcd_config/pre_hook.h>
#include <liblcd/liblcd.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
#include "../foobar_glue_helper.h"
#include <lcd_config/post_hook.h>
cptr_t foobar_klcd, dummy_lcd;
struct lcd_create_ctx *dummy_ctx;
cptr_t net_chnl;
cptr_t net_chnl_domain_cptr, dummy_chnl_domain_cptr;
static int boot_main(void)
{
int ret;
/*
* Enter lcd mode
*/
ret = lcd_enter();
if (ret) {
LIBLCD_ERR("lcd enter failed");
goto fail1;
}
/* ---------- Create vfs channel ---------- */
ret = lcd_create_sync_endpoint(&net_chnl);
if (ret) {
LIBLCD_ERR("lcd create sync endpoint");
goto fail2;
}
/* ---------- Create LCDs ---------- */
ret = lcd_create_module_klcd(LCD_DIR("foobar/foobar_klcd"),
"lcd_test_mod_foobar_foobar_klcd",
&foobar_klcd);
if (ret) {
LIBLCD_ERR("failed to create net klcd");
goto fail3;
}
ret = lcd_create_module_lcd(LCD_DIR("foobar/dummy_lcd"),
"lcd_test_mod_foobar_dummy_lcd",
&dummy_lcd,
&dummy_ctx);
if (ret) {
LIBLCD_ERR("failed to create dummy lcd");
goto fail4;
}
ret = cptr_alloc(lcd_to_boot_cptr_cache(dummy_ctx),
&dummy_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("alloc cptr");
goto fail5;
}
ret = lcd_cap_grant(dummy_lcd, net_chnl, dummy_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("grant");
goto fail6;
}
/* ---------- Set up boot info ---------- */
// HACK: But WTF is this?
net_chnl_domain_cptr = __cptr(3);
ret = lcd_cap_grant(foobar_klcd, net_chnl, net_chnl_domain_cptr);
if (ret) {
LIBLCD_ERR("grant");
goto fail7;
}
lcd_to_boot_info(dummy_ctx)->cptrs[0] = dummy_chnl_domain_cptr;
/* ---------- RUN! ---------- */
LIBLCD_MSG("starting foobar subsystem...");
ret = lcd_run(foobar_klcd);
if (ret) {
LIBLCD_ERR("failed to start foobar klcd");
goto fail8;
}
LIBLCD_MSG("starting dummy foobar device...");
ret = lcd_run(dummy_lcd);
if (ret) {
LIBLCD_ERR("failed to start dummy lcd");
goto fail9;
}
/*
* Wait for 4 seconds
*/
//msleep(100000);
/*
* Tear everything down
*/
ret = 0;
// return
goto fail1;
/* The destroy's will free up everything ... */
fail9:
fail8:
fail7:
lcd_cap_delete(dummy_lcd);
lcd_destroy_create_ctx(dummy_ctx);
fail6:
fail5:
fail4:
//lcd_cap_delete(foobar_klcd);
lcd_destroy_module_klcd(foobar_klcd, "lcd_test_mod_foobar_foobar_klcd");
fail3:
fail2:
lcd_exit(0); /* will free endpoints */
fail1:
return ret;
}
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int shutdown = 0;
int boot_lcd_thread(void *data)
{
static unsigned once = 0;
int ret;
while (!kthread_should_stop()) {
if (!once) {
LCD_MAIN({
ret = boot_main();
});
}
once = 1;
wait_event_interruptible(wq, shutdown != 0);
}
msleep(2000);
LIBLCD_MSG("Exiting thread");
lcd_destroy_module_klcd(foobar_klcd,
"lcd_test_mod_foobar_foobar_klcd");
if (current->lcd)
lcd_cap_delete(dummy_lcd);
if (dummy_ctx)
lcd_destroy_create_ctx(dummy_ctx);
lcd_exit(0);
return 0;
}
struct task_struct *boot_task;
static int boot_init(void)
{
LIBLCD_MSG("%s: entering", __func__);
boot_task = kthread_create(boot_lcd_thread, NULL, "boot_lcd_thread");
if (!IS_ERR(boot_task))
wake_up_process(boot_task);
return 0;
}
static void boot_exit(void)
{
/* nothing to do */
if (!IS_ERR(boot_task)) {
LIBLCD_MSG("%s: exiting", __func__);
shutdown = 1;
wake_up_interruptible(&wq);
kthread_stop(boot_task);
}
}
module_init(boot_init);
module_exit(boot_exit);
MODULE_LICENSE("GPL");
obj-m += lcd_test_mod_foobar_dummy_lcd.o
lcd_test_mod_foobar_dummy_lcd-y += main.o
# Original code
lcd_test_mod_foobar_dummy_lcd-y += dummy.o
lcd_test_mod_foobar_dummy_lcd-y += $(LIBLCD)
# glue code
lcd_test_mod_foobar_dummy_lcd-y += $(addprefix glue/, foobar_caller.o \
foobar_caller_dispatch.o )
lcd_test_mod_foobar_dummy_lcd-y += $(addprefix ../, foobar_glue_helper.o)
ccflags-y += $(ISOLATED_CFLAGS)
/* dummy.c: a dummy foobar driver */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/foobar_device.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#define DRV_NAME "foobardummy"
#define DRV_VERSION "1.0"
int dummy_dev_init(struct foobar_device *dev)
{
dev->dstats = kmalloc(sizeof(struct foo_stats), GFP_KERNEL);
if (!dev->dstats)
return -ENOMEM;
return 0;
}
void dummy_dev_uninit(struct foobar_device *dev)
{
kfree(dev->dstats);
}
static const struct foobar_device_ops dummy_foobardev_ops = {
.init = dummy_dev_init,
.uninit = dummy_dev_uninit,
};
int numdummies = 0;
/* Number of dummy devices to be set up by this module. */
module_param(numdummies, int, 0);
MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
struct foobar_device *dev_dummy;
int dummy_init_module(void)// the entry point to the dummy device driver
{
int err;
dev_dummy = alloc_foobardev(0, "dummy0");
if (!dev_dummy)
return -ENOMEM;
dev_dummy->foobardev_ops = &dummy_foobardev_ops;
dev_dummy->features = FOOBAR_PRIV_ALLOC;
dev_dummy->flags = FOO_LOOPBACK;
err = register_foobar(dev_dummy);//the call to dev.c fn to register dummy
if (err < 0)
goto err;
return 0;
err:
free_foobardev(dev_dummy);// free the foobar device if an error code is received
return err;
}
void dummy_cleanup_module(void)
{
unregister_foobar(dev_dummy);
}
#ifndef LCD_ISOLATE
module_init(dummy_init_module);
module_exit(dummy_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
#endif
#ifndef __FOOBAR_CALLER_H__
#define __FOOBAR_CALLER_H__
#include "../foobar_glue_helper.h"
void dispatch_sync_loop(void);
int dispatch_async_loop(struct thc_channel *_channel,
struct fipc_message *message,
struct glue_cspace *cspace,
struct cptr sync_ep);
int glue_foobar_init(void);
void glue_foobar_exit(void);
int init_callee(struct fipc_message *_request,
struct thc_channel *_channel,
struct glue_cspace *cspace,
struct cptr sync_ep);
int uninit_callee(struct fipc_message *_request,
struct thc_channel *_channel,
struct glue_cspace *cspace,
struct cptr sync_ep);
#endif
#include "../foobar_caller.h"
__maybe_unused static struct cptr c;
struct glue_cspace *foobar_cspace;
extern struct thc_channel *foobar_async;
extern struct lcd_sync_channel_group *ch_grp;
int dummy_dev_init(struct foobar_device *dev);
void dummy_dev_uninit(struct foobar_device *dev);
int glue_foobar_init(void)
{
int ret;
ret = glue_cap_init();
if (ret) {
LIBLCD_ERR("cap init");
goto fail1;
}
ret = glue_cap_create(&foobar_cspace);
if (ret) {
LIBLCD_ERR("cap create");
goto fail2;
}
return 0;
fail2:
glue_cap_exit();
fail1:
return ret;
}
void glue_foobar_exit(void)
{
glue_cap_destroy(foobar_cspace);
glue_cap_exit();
}
int register_foobar(struct foobar_device *dev)
{
int ret;
struct fipc_message *_request;
struct fipc_message *_response;
int func_ret = 0;
ret = async_msg_blocking_send_start(foobar_async,
&_request);
if (ret) {
LIBLCD_ERR("failed to get a send slot");
goto fail_async;
}
async_msg_set_fn_type(_request,
REGISTER_FOOBAR);
fipc_set_reg4(_request,
dev->features);
fipc_set_reg5(_request,
dev->hw_features);
fipc_set_reg6(_request,
dev->flags);
ret = thc_ipc_call(foobar_async,
_request,
&_response);
if (ret) {
LIBLCD_ERR("thc_ipc_call");
goto fail_ipc;
}
func_ret = fipc_get_reg1(_response);
fipc_recv_msg_end(thc_channel_to_fipc(foobar_async),
_response);
return func_ret;
fail_async:
fail_ipc:
return ret;
}
void unregister_foobar(struct foobar_device *dev)
{
int ret;
struct fipc_message *_request;
struct fipc_message *_response;
ret = async_msg_blocking_send_start(foobar_async,
&_request);
if (ret) {
LIBLCD_ERR("failed to get a send slot");
goto fail_async;
}
async_msg_set_fn_type(_request,
UNREGISTER_FOOBAR);
ret = thc_ipc_call(foobar_async,
_request,
&_response);
if (ret) {
LIBLCD_ERR("thc_ipc_call");
goto fail_ipc;
}
fipc_recv_msg_end(thc_channel_to_fipc(foobar_async),
_response);
return;
fail_async:
fail_ipc:
return;
}
struct foobar_device *alloc_foobardev(int id,
const char *name)
{
struct foobar_device_container *func_ret_container = NULL;
int ret;
struct fipc_message *_request;
struct fipc_message *_response;
struct foobar_device *func_ret = NULL;
func_ret_container = kzalloc(sizeof( struct foobar_device_container ),
GFP_KERNEL);
if (!func_ret_container) {
LIBLCD_ERR("kzalloc");
goto fail_alloc;
}
func_ret = &func_ret_container->foobar_device;
ret = glue_cap_insert_foobar_device_type(foobar_cspace,
func_ret_container,
&func_ret_container->my_ref);
if (ret) {
LIBLCD_ERR("lcd insert");
goto fail_insert;
}
ret = async_msg_blocking_send_start(foobar_async,
&_request);
if (ret) {
LIBLCD_ERR("failed to get a send slot");
goto fail_async;
}
async_msg_set_fn_type(_request,
ALLOC_FOOBARDEV);
fipc_set_reg1(_request,
id);
// fipc_set_reg2(_request,
// name);
fipc_set_reg4(_request,
func_ret_container->my_ref.cptr);
// fipc_set_reg5(_request,
// func_ret->id);
// fipc_set_reg6(_request,
// func_ret->name);
ret = thc_ipc_call(foobar_async,
_request,
&_response);
if (ret) {
LIBLCD_ERR("thc_ipc_call");
goto fail_ipc;
}
func_ret_container->other_ref.cptr = fipc_get_reg2(_response);
fipc_recv_msg_end(thc_channel_to_fipc(foobar_async),
_response);
return func_ret;
fail_alloc:
fail_insert:
fail_async:
fail_ipc:
return func_ret;
}
void free_foobardev(struct foobar_device *dev)
{
int ret;
struct fipc_message *_request;
struct fipc_message *_response;
ret = async_msg_blocking_send_start(foobar_async,
&_request);
if (ret) {
LIBLCD_ERR("failed to get a send slot");
goto fail_async;
}
async_msg_set_fn_type(_request,
FREE_FOOBARDEV);
ret = thc_ipc_call(foobar_async,
_request,
&_response);
if (ret) {
LIBLCD_ERR("thc_ipc_call");
goto fail_ipc;
}
fipc_recv_msg_end(thc_channel_to_fipc(foobar_async),
_response);
return;
fail_async:
fail_ipc:
return;
}
int init_callee(struct fipc_message *_request,
struct thc_channel *_channel,
struct glue_cspace *cspace,
struct cptr sync_ep)
{
struct foobar_device *dev = NULL;
int ret = 0;
struct fipc_message *_response;
unsigned int request_cookie;
int func_ret = 0;
request_cookie = thc_get_request_cookie(_request);
fipc_recv_msg_end(thc_channel_to_fipc(_channel),
_request);
dev = kzalloc(sizeof( *dev ),
GFP_KERNEL);
if (!dev) {
LIBLCD_ERR("kzalloc");
goto fail_alloc;
}
func_ret = dummy_dev_init(dev);
if (async_msg_blocking_send_start(_channel,
&_response)) {
LIBLCD_ERR("error getting response msg");
return -EIO;
}
fipc_set_reg1(_response,
func_ret);
thc_ipc_reply(_channel,
request_cookie,
_response);
fail_alloc:
return ret;
}
int uninit_callee(struct fipc_message *_request,
struct thc_channel *_channel,
struct glue_cspace *cspace,
struct cptr sync_ep)
{
struct foobar_device *dev = NULL;
int ret = 0;
struct fipc_message *_response;
unsigned int request_cookie;
request_cookie = thc_get_request_cookie(_request);
fipc_recv_msg_end(thc_channel_to_fipc(_channel),
_request);
dev = kzalloc(sizeof( *dev ),
GFP_KERNEL);
if (!dev) {
LIBLCD_ERR("kzalloc");
goto fail_alloc;
}
dummy_dev_uninit(dev);
if (async_msg_blocking_send_start(_channel,
&_response)) {
LIBLCD_ERR("error getting response msg");
return -EIO;
}
thc_ipc_reply(_channel,
request_cookie,
_response);
fail_alloc:
return ret;
}
#include <lcd_config/pre_hook.h>
#include <liblcd/liblcd.h>
#include "../foobar_caller.h"
#include <lcd_config/post_hook.h>
#define trace(x) LIBLCD_MSG(#x)
int dispatch_async_loop(struct thc_channel *_channel,
struct fipc_message *message,
struct glue_cspace *cspace,
struct cptr sync_ep)
{
int fn_type;
fn_type = async_msg_get_fn_type(message);
switch (fn_type) {
case INIT:
trace(INIT);
return init_callee(message,
_channel,
cspace,
sync_ep);
case UNINIT:
trace(UNINIT);
return uninit_callee(message,
_channel,
cspace,
sync_ep);
default:
LIBLCD_ERR("unexpected function label: %d",
fn_type);
return -EINVAL;
}
return 0;
}
/*
* main.c - runs when dummy lcd boots
*/
#include <lcd_config/pre_hook.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <liblcd/liblcd.h>
#include <liblcd/sync_ipc_poll.h>
#include "./foobar_caller.h"
#include <lcd_config/post_hook.h>
cptr_t foobar_register_channel;
struct thc_channel *foobar_async;
extern struct glue_cspace *foobar_cspace;
cptr_t foobar_sync_endpoint;
int dummy_done = 0;
int dummy_init_module(void);
void dummy_cleanup_module(void);
struct thc_channel_group ch_grp;
static void main_and_loop(void)
{
int ret;
int stop = 0;
struct fipc_message *msg;
DO_FINISH(
ASYNC(
ret = dummy_init_module();
if (ret) {
LIBLCD_ERR("dummy register failed");
stop = 1;
} else {
LIBLCD_MSG("SUCCESSFULLY REGISTERED DUMMY!");
}
);
/* By the time we hit this loop, the async channel
* will be set up (the awe running init_dummy_fs above
* will not yield until it tries to use the async
* channel). */
while (!stop && !dummy_done) {
struct thc_channel_group_item* curr_item;
/*
* Do one async receive
*/
ret = thc_poll_recv_group(&ch_grp, &curr_item, &msg);
if (likely(ret)) {
if (ret == -EWOULDBLOCK) {
cpu_relax();
continue;
} else {
LIBLCD_ERR("async recv failed");
stop = 1; /* stop */
}
}
ASYNC(
ret = dispatch_async_loop(curr_item->channel,
msg,
foobar_cspace,
foobar_sync_endpoint);
if (ret) {
LIBLCD_ERR("async dispatch failed");
stop = 1;
}
);
}
LIBLCD_MSG("FOOBAR DUMMY EXITED DISPATCH LOOP");
);
LIBLCD_MSG("EXITED DUMMY DO_FINISH");
return;
}
static int __noreturn dummy_lcd_init(void)
{
int r = 0;
printk("LCD enter \n");
r = lcd_enter();
if (r)
goto fail1;
/*
* Get the foobar channel cptr from boot info
*/
foobar_register_channel = lcd_get_boot_info()->cptrs[0];
printk("foobar reg channel %lu\n", foobar_register_channel.cptr);
/*
* Initialize foobar glue
*/
r = glue_foobar_init();
if (r) {
LIBLCD_ERR("foobar init");
goto fail2;
}
thc_channel_group_init(&ch_grp);
/* RUN CODE / LOOP ---------------------------------------- */
main_and_loop();
/* DONE -------------------------------------------------- */
glue_foobar_exit();
lcd_exit(0); /* doesn't return */
fail2:
fail1:
lcd_exit(r);
}
static int __dummy_lcd_init(void)
{
int ret;
LIBLCD_MSG("%s: entering", __func__);
LCD_MAIN({
ret = dummy_lcd_init();
});
return ret;
}
static void __exit dummy_lcd_exit(void)
{
LIBLCD_MSG("%s: exiting", __func__);
return;
}
module_init(__dummy_lcd_init);
module_exit(dummy_lcd_exit);
MODULE_LICENSE("GPL");
#include <lcd_config/pre_hook.h>
#include <libcap.h>
#include <liblcd/liblcd.h>
#include <linux/slab.h>
#include "foobar_glue_helper.h"
#include <lcd_config/post_hook.h>
/* ------------------------------------------------------------ */
static struct cap_type_system *glue_libcap_type_system;
struct type_ops_id {
struct cap_type_ops ops;
cap_type_t libcap_type;
};
enum glue_type {
GLUE_TYPE_FOOBAR_DEVICE_CONTAINER,
GLUE_TYPE_FOOBAR_DEVICE_OPS_CONTAINER,
GLUE_NR_TYPES,
};
static int dummy_func(struct cspace *cspace, struct cnode *cnode,
void *object)
{
return 0;
}
static struct type_ops_id glue_libcap_type_ops[GLUE_NR_TYPES] = {
{
{
.name = "struct foobar_device",
.delete = dummy_func,
.revoke = dummy_func,
}
},
{
{
.name = "struct foobar_device_ops",
.delete = dummy_func,
.revoke = dummy_func,
}
},
};
int glue_cap_init(void)
{
int ret;
int i;
cap_type_t libcap_type;
/*
* Alloc and init microkernel type system
*/
ret = cap_type_system_alloc(&glue_libcap_type_system);
if (ret) {
LIBLCD_ERR("alloc glue type system failed");
goto fail1;
}
ret = cap_type_system_init(glue_libcap_type_system);
if (ret) {
LIBLCD_ERR("init glue type system failed");
goto fail2;
}
/*
* Add types
*/
for (i = 0; i < GLUE_NR_TYPES; i++) {
libcap_type = cap_register_private_type(
glue_libcap_type_system,
0,
&glue_libcap_type_ops[i].ops);
if (libcap_type == CAP_TYPE_ERR) {
LIBLCD_ERR("failed to register glue cap type %s",
glue_libcap_type_ops[i].ops.name);
ret = -EIO;
goto fail3;
}
glue_libcap_type_ops[i].libcap_type = libcap_type;
}
return 0;
fail3:
cap_type_system_destroy(glue_libcap_type_system);
fail2:
cap_type_system_free(glue_libcap_type_system);
glue_libcap_type_system = NULL;
fail1:
return ret;
}
int glue_cap_create(struct glue_cspace **cspace_out)
{
return glue_cspace_alloc_init(glue_libcap_type_system, cspace_out);
}
void glue_cap_destroy(struct glue_cspace *cspace)
{
glue_cspace_destroy_free(cspace);
}
void glue_cap_exit(void)
{
/*
* Destroy and free type system if necessary
*/
if (glue_libcap_type_system) {
cap_type_system_destroy(glue_libcap_type_system);
cap_type_system_free(glue_libcap_type_system);
glue_libcap_type_system = NULL;
}
}
int glue_cap_insert_foobar_device_type(struct glue_cspace *cspace,
struct foobar_device_container *foobar_device_container,
struct cptr *c_out)
{
return glue_cspace_insert(cspace,
foobar_device_container,
glue_libcap_type_ops[ GLUE_TYPE_FOOBAR_DEVICE_CONTAINER ].libcap_type,
c_out);
}
int glue_cap_lookup_foobar_device_type(struct glue_cspace *cspace,
struct cptr c,
struct foobar_device_container **foobar_device_container)
{
return glue_cspace_lookup(cspace,
c,
glue_libcap_type_ops[ GLUE_TYPE_FOOBAR_DEVICE_CONTAINER ].libcap_type,
( void ** )foobar_device_container);
}
int glue_cap_insert_foobar_device_ops_type(struct glue_cspace *cspace,
struct foobar_device_ops_container *foobar_device_ops_container,
struct cptr *c_out)
{
return glue_cspace_insert(cspace,
foobar_device_ops_container,
glue_libcap_type_ops[ GLUE_TYPE_FOOBAR_DEVICE_OPS_CONTAINER ].libcap_type,
c_out);
}
int glue_cap_lookup_foobar_device_ops_type(struct glue_cspace *cspace,
struct cptr c,
struct foobar_device_ops_container **foobar_device_ops_container)
{
return glue_cspace_lookup(cspace,
c,
glue_libcap_type_ops[ GLUE_TYPE_FOOBAR_DEVICE_OPS_CONTAINER ].libcap_type,
( void ** )foobar_device_ops_container);
}
#ifndef __FOOBAR_GLUE_HELPER_H__
#define __FOOBAR_GLUE_HELPER_H__
#include <linux/foobar_device.h>
#include <libcap.h>
#include <libfipc.h>
#include <thc_ipc.h>
#include <liblcd/glue_cspace.h>
#include <liblcd/liblcd.h>
#include <liblcd/sync_ipc_poll.h>
#include <linux/kthread.h>
enum dispatch_t {
REGISTER_FOOBAR,
UNREGISTER_FOOBAR,
ALLOC_FOOBARDEV,
FREE_FOOBARDEV,
INIT,
UNINIT,
TRIGGER_EXIT,
};
#define fipc_test_pause() asm volatile ( "pause\n": : :"memory" );
#define ASYNC_RPC_BUFFER_ORDER 12
struct foobar_device_container {
struct foobar_device foobar_device;
struct cptr other_ref;
struct cptr my_ref;
};
struct foobar_device_ops_container {
struct foobar_device_ops foobar_device_ops;
struct cptr other_ref;
struct cptr my_ref;
};
struct trampoline_hidden_args {
void *struct_container;
struct glue_cspace *cspace;
struct lcd_trampoline_handle *t_handle;
struct thc_channel *async_chnl;
struct cptr sync_ep;
};
int glue_cap_init(void);
int glue_cap_create(struct glue_cspace **cspace);
void glue_cap_destroy(struct glue_cspace *cspace);
void glue_cap_exit(void);
void glue_cap_remove(
struct glue_cspace *cspace,
cptr_t c);
int glue_cap_insert_foobar_device_type(struct glue_cspace *cspace,
struct foobar_device_container *foobar_device_container,
struct cptr *c_out);
int glue_cap_insert_foobar_device_ops_type(struct glue_cspace *cspace,
struct foobar_device_ops_container *foobar_device_ops_container,
struct cptr *c_out);
int glue_cap_lookup_foobar_device_type(struct glue_cspace *cspace,
struct cptr c,
struct foobar_device_container **foobar_device_container);
int glue_cap_lookup_foobar_device_ops_type(struct glue_cspace *cspace,
struct cptr c,
struct foobar_device_ops_container **foobar_device_ops_container);
static inline
int
async_msg_get_fn_type(struct fipc_message *msg)
{
return fipc_get_flags(msg) >> THC_RESERVED_MSG_FLAG_BITS;
}
static inline
void
async_msg_set_fn_type(struct fipc_message *msg, int type)
{
uint32_t flags = fipc_get_flags(msg);
/* ensure type is in range */
type &= (1 << (32 - THC_RESERVED_MSG_FLAG_BITS)) - 1;
/* erase old type */
flags &= ((1 << THC_RESERVED_MSG_FLAG_BITS) - 1);
/* install new type */
flags |= (type << THC_RESERVED_MSG_FLAG_BITS);
fipc_set_flags(msg, flags);
}
static inline
int
async_msg_blocking_send_start(struct thc_channel *chnl,
struct fipc_message **out)
{
int ret;
for (;;) {
/* Poll until we get a free slot or error */
ret = fipc_send_msg_start(thc_channel_to_fipc(chnl), out);
if (!ret || ret != -EWOULDBLOCK)
return ret;
cpu_relax();
if (kthread_should_stop())
return -EIO;
}
}
#endif
obj-m += lcd_test_mod_foobar_foobar_klcd.o
lcd_test_mod_foobar_foobar_klcd-y += main.o
# glue code
lcd_test_mod_foobar_foobar_klcd-y += $(addprefix glue/, foobar_callee.o \
foobar_callee_dispatch.o )
lcd_test_mod_foobar_foobar_klcd-y += $(addprefix ../, foobar_glue_helper.o)
cppflags-y += $(NONISOLATED_CFLAGS)
extra-y += glue/foobar_callee.lds
ldflags-y += -T $(LCD_TEST_MODULES_BUILD_DIR)/foobar/foobar_klcd/glue/foobar_callee.lds
ccflags-y += $(NONISOLATED_CFLAGS)