changes from v1:
- Patch 01/11 ("sysctl: make some functions unstatic to access by arch/lib"):
* add prefix ctl_table_ to newly publiced functions (commented by Joe Perches)
- Patch 08/11 ("lib: other kernel glue layer code"):
* significantly reduce glue codes (stubs) (commented by Richard Weinberger)
- Others
* adapt to linux-4.0.0
* detect make dependency by Kbuild .cmd files
patchset history
-----------------
[v1] : https://lkml.org/lkml/2015/3/24/254
This is an introduction of library operating system (LibOS) for Linux.
Our objective is to build the kernel network stack as a shared library
that can be linked to by userspace programs to provide network stack
personalization and testing facilities, and allow researchers to more
easily simulate complex network topologies of linux routers/hosts.
Although the architecture itself can virtualize various things, the
current design only focuses on the network stack. You can benefit
network stack feature such as TCP, UDP, SCTP, DCCP (IPv4 and IPv6),
Mobie IPv6, Multipath TCP (IPv4/IPv6, out-of-tree at the present
moment), and netlink with various userspace applications (quagga,
iproute2, iperf, wget, and thttpd).
== What is LibOS ? ==
The library exposes an entry point as API, which is lib_init(), in
order to connect userspace applications to the (userspace-version)
kernel network stack. The clock source, virtual struct net_device, and
scheduler are provided by caller while kernel resource like system
calls is provided by callee.
Once the LibOS is initialized via the API, userspace applications with
POSIX socket can use the system calls defined in LibOS by replacing
from the original socket-related symbols to the LibOS-specific
one. Then application can benefit the network stack of LibOS without
involving the host network stack.
Currently, there are two users of LibOS: Network Stack in Userspace
(NUSE) and ns-3 network simulatior with Direct Code Execution
(DCE). These codes are managed at an external repository(*1).
== How to use it ? ==
to build the library,
% make {defconfig,menuconfig} ARCH=lib
then, build it.
% make library ARCH=lib
You will see liblinux-$(KERNELVERSION).so in the top directory.
== More information ==
The crucial difference between UML (user-mode linux) and this approach
is that we allow multiple network stack instances to co-exist within a
single process with dlmopen(3) like linking for easy debugging.
These patches are also available on this branch:
git://github.com/libos-nuse/net-next-nuse.git for-asm-upstream
For further information, here is a slideset presented at the last
netdev0.1 conference.
http://www.slideshare.net/hajimetazaki/library-operating-system-for-linux-netdev01
I would appreciate any kind of your feedback regarding to upstream
this feature.
*1 https://github.com/libos-nuse/linux-libos-tools
Hajime Tazaki (11):
sysctl: make some functions unstatic to access by arch/lib
slab: add private memory allocator header for arch/lib
lib: public headers and API implementations for userspace programs
lib: memory management (kernel glue code)
lib: time handling (kernel glue code)
lib: context and scheduling handling (kernel glue code)
lib: sysctl handling (kernel glue code)
lib: other kernel glue layer code
lib: asm-generic files
lib: libos build scripts and documentation
lib: tools used for test scripts
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 8 +
arch/lib/Kconfig | 121 +++++++
arch/lib/Makefile | 251 +++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/capability.c | 47 +++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/filemap.c | 32 ++
arch/lib/fs.c | 70 ++++
arch/lib/generate-linker-script.py | 50 +++
arch/lib/glue.c | 283 +++++++++++++++
arch/lib/hrtimer.c | 122 +++++++
arch/lib/include/asm/Kbuild | 57 +++
arch/lib/include/asm/atomic.h | 50 +++
arch/lib/include/asm/barrier.h | 8 +
arch/lib/include/asm/bitsperlong.h | 12 +
arch/lib/include/asm/current.h | 7 +
arch/lib/include/asm/elf.h | 10 +
arch/lib/include/asm/hardirq.h | 8 +
arch/lib/include/asm/page.h | 14 +
arch/lib/include/asm/pgtable.h | 30 ++
arch/lib/include/asm/processor.h | 19 +
arch/lib/include/asm/ptrace.h | 4 +
arch/lib/include/asm/segment.h | 6 +
arch/lib/include/asm/sembuf.h | 4 +
arch/lib/include/asm/shmbuf.h | 4 +
arch/lib/include/asm/shmparam.h | 4 +
arch/lib/include/asm/sigcontext.h | 6 +
arch/lib/include/asm/slab.h | 21 ++
arch/lib/include/asm/stat.h | 4 +
arch/lib/include/asm/statfs.h | 4 +
arch/lib/include/asm/swab.h | 7 +
arch/lib/include/asm/thread_info.h | 36 ++
arch/lib/include/asm/uaccess.h | 14 +
arch/lib/include/asm/unistd.h | 4 +
arch/lib/include/sim-assert.h | 23 ++
arch/lib/include/sim-init.h | 134 +++++++
arch/lib/include/sim-printf.h | 13 +
arch/lib/include/sim-types.h | 53 +++
arch/lib/include/sim.h | 51 +++
arch/lib/include/uapi/asm/byteorder.h | 6 +
arch/lib/lib-device.c | 187 ++++++++++
arch/lib/lib-socket.c | 410 +++++++++++++++++++++
arch/lib/lib.c | 294 +++++++++++++++
arch/lib/lib.h | 21 ++
arch/lib/modules.c | 36 ++
arch/lib/pid.c | 29 ++
arch/lib/print.c | 56 +++
arch/lib/proc.c | 34 ++
arch/lib/processor.mk | 7 +
arch/lib/random.c | 53 +++
arch/lib/sched.c | 406 +++++++++++++++++++++
arch/lib/slab.c | 203 +++++++++++
arch/lib/softirq.c | 108 ++++++
arch/lib/sysctl.c | 270 ++++++++++++++
arch/lib/sysfs.c | 83 +++++
arch/lib/tasklet-hrtimer.c | 57 +++
arch/lib/tasklet.c | 76 ++++
arch/lib/time.c | 144 ++++++++
arch/lib/timer.c | 238 +++++++++++++
arch/lib/vmscan.c | 26 ++
arch/lib/workqueue.c | 242 +++++++++++++
fs/proc/proc_sysctl.c | 36 +-
include/linux/slab.h | 12 +
tools/testing/libos/.gitignore | 6 +
tools/testing/libos/Makefile | 38 ++
tools/testing/libos/README | 15 +
tools/testing/libos/bisect.sh | 10 +
tools/testing/libos/dce-test.sh | 23 ++
tools/testing/libos/nuse-test.sh | 57 +++
71 files changed, 5608 insertions(+), 17 deletions(-)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/defconfig
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100755 arch/lib/generate-linker-script.py
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/slab.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/processor.mk
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/slab.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/sysctl.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
create mode 100644 arch/lib/vmscan.c
create mode 100644 arch/lib/workqueue.c
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
--
2.1.0
libos (arch/lib) emulates a sysctl-like interface by a function call of
userspace by enumerating sysctl tree from sysctl_table_root. It requires
to be publicly accessible to this symbol and related functions.
Signed-off-by: Hajime Tazaki <[email protected]>
---
fs/proc/proc_sysctl.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index f92d5dd..56feec7 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -35,7 +35,7 @@ static struct ctl_table root_table[] = {
},
{ }
};
-static struct ctl_table_root sysctl_table_root = {
+struct ctl_table_root sysctl_table_root = {
.default_set.dir.header = {
{{.count = 1,
.nreg = 1,
@@ -77,8 +77,9 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2)
}
/* Called under sysctl_lock */
-static struct ctl_table *find_entry(struct ctl_table_header **phead,
- struct ctl_dir *dir, const char *name, int namelen)
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen)
{
struct ctl_table_header *head;
struct ctl_table *entry;
@@ -300,7 +301,7 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
struct ctl_table *entry;
spin_lock(&sysctl_lock);
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (entry && use_table(head))
*phead = head;
else
@@ -321,7 +322,7 @@ static struct ctl_node *first_usable_entry(struct rb_node *node)
return NULL;
}
-static void first_entry(struct ctl_dir *dir,
+void ctl_table_first_entry(struct ctl_dir *dir,
struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = NULL;
@@ -339,7 +340,7 @@ static void first_entry(struct ctl_dir *dir,
*pentry = entry;
}
-static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = *phead;
struct ctl_table *entry = *pentry;
@@ -670,7 +671,8 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
pos = 2;
- for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
if (!scan(h, entry, &pos, file, ctx)) {
sysctl_head_finish(h);
break;
@@ -828,7 +830,7 @@ static struct ctl_dir *find_subdir(struct ctl_dir *dir,
struct ctl_table_header *head;
struct ctl_table *entry;
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (!entry)
return ERR_PTR(-ENOENT);
if (!S_ISDIR(entry->mode))
@@ -924,13 +926,13 @@ failed:
return subdir;
}
-static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
{
struct ctl_dir *parent;
const char *procname;
if (!dir->header.parent)
return &set->dir;
- parent = xlate_dir(set, dir->header.parent);
+ parent = ctl_table_xlate_dir(set, dir->header.parent);
if (IS_ERR(parent))
return parent;
procname = dir->header.ctl_table[0].procname;
@@ -951,13 +953,13 @@ static int sysctl_follow_link(struct ctl_table_header **phead,
spin_lock(&sysctl_lock);
root = (*pentry)->data;
set = lookup_header_set(root, namespaces);
- dir = xlate_dir(set, (*phead)->parent);
+ dir = ctl_table_xlate_dir(set, (*phead)->parent);
if (IS_ERR(dir))
ret = PTR_ERR(dir);
else {
const char *procname = (*pentry)->procname;
head = NULL;
- entry = find_entry(&head, dir, procname, strlen(procname));
+ entry = ctl_table_find_entry(&head, dir, procname, strlen(procname));
ret = -ENOENT;
if (entry && use_table(head)) {
unuse_table(*phead);
@@ -1069,7 +1071,7 @@ static bool get_links(struct ctl_dir *dir,
/* Are there links available for every entry in table? */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
if (!link)
return false;
if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
@@ -1082,7 +1084,7 @@ static bool get_links(struct ctl_dir *dir,
/* The checks passed. Increase the registration count on the links */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
head->nreg++;
}
return true;
@@ -1098,7 +1100,7 @@ static int insert_links(struct ctl_table_header *head)
if (head->set == root_set)
return 0;
- core_parent = xlate_dir(root_set, head->parent);
+ core_parent = ctl_table_xlate_dir(root_set, head->parent);
if (IS_ERR(core_parent))
return 0;
@@ -1479,7 +1481,7 @@ static void put_links(struct ctl_table_header *header)
if (header->set == root_set)
return;
- core_parent = xlate_dir(root_set, parent);
+ core_parent = ctl_table_xlate_dir(root_set, parent);
if (IS_ERR(core_parent))
return;
@@ -1488,7 +1490,7 @@ static void put_links(struct ctl_table_header *header)
struct ctl_table *link;
const char *name = entry->procname;
- link = find_entry(&link_head, core_parent, name, strlen(name));
+ link = ctl_table_find_entry(&link_head, core_parent, name, strlen(name));
if (link &&
((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
(S_ISLNK(link->mode) && (link->data == root)))) {
--
2.1.0
add header includion for CONFIG_LIB to wrap kmalloc and co. This will
bring malloc(3) based allocator used by arch/lib.
Signed-off-by: Hajime Tazaki <[email protected]>
---
include/linux/slab.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 9a139b6..6914e1f 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -205,6 +205,14 @@ size_t ksize(const void *);
#endif
#endif
+#ifdef CONFIG_LIB
+#define KMALLOC_SHIFT_MAX 30
+#define KMALLOC_SHIFT_HIGH PAGE_SHIFT
+#ifndef KMALLOC_SHIFT_LOW
+#define KMALLOC_SHIFT_LOW 3
+#endif
+#endif
+
/* Maximum allocatable size */
#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_MAX)
/* Maximum size for which we actually use a slab cache */
@@ -350,6 +358,9 @@ kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
}
#endif
+#ifdef CONFIG_LIB
+#include <asm/slab.h>
+#else
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{
unsigned int order = get_order(size);
@@ -428,6 +439,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
}
return __kmalloc(size, flags);
}
+#endif
/*
* Determine size used for the nth kmalloc cache.
--
2.1.0
userspace programs access via public API, lib_init(), with passed
arguments struct SimImported and struct SimExported.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
arch/lib/include/sim-assert.h | 23 +++
arch/lib/include/sim-init.h | 134 ++++++++++++++
arch/lib/include/sim-printf.h | 13 ++
arch/lib/include/sim-types.h | 53 ++++++
arch/lib/include/sim.h | 51 ++++++
arch/lib/lib-device.c | 187 +++++++++++++++++++
arch/lib/lib-socket.c | 410 ++++++++++++++++++++++++++++++++++++++++++
arch/lib/lib.c | 294 ++++++++++++++++++++++++++++++
arch/lib/lib.h | 21 +++
9 files changed, 1186 insertions(+)
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
diff --git a/arch/lib/include/sim-assert.h b/arch/lib/include/sim-assert.h
new file mode 100644
index 0000000..974122c
--- /dev/null
+++ b/arch/lib/include/sim-assert.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_ASSERT_H
+#define SIM_ASSERT_H
+
+#include "sim-printf.h"
+
+#define lib_assert(v) { \
+ while (!(v)) { \
+ lib_printf("Assert failed %s:%u \"" #v "\"\n", \
+ __FILE__, __LINE__); \
+ char *p = 0; \
+ *p = 1; \
+ } \
+ }
+
+
+#endif /* SIM_ASSERT_H */
diff --git a/arch/lib/include/sim-init.h b/arch/lib/include/sim-init.h
new file mode 100644
index 0000000..e871a59
--- /dev/null
+++ b/arch/lib/include/sim-init.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_INIT_H
+#define SIM_INIT_H
+
+#include <linux/socket.h>
+#include "sim-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _IO_FILE;
+typedef struct _IO_FILE FILE;
+
+struct SimExported {
+ struct SimTask *(*task_create)(void *priv, unsigned long pid);
+ void (*task_destroy)(struct SimTask *task);
+ void *(*task_get_private)(struct SimTask *task);
+
+ int (*sock_socket)(int domain, int type, int protocol,
+ struct SimSocket **socket);
+ int (*sock_close)(struct SimSocket *socket);
+ ssize_t (*sock_recvmsg)(struct SimSocket *socket, struct msghdr *msg,
+ int flags);
+ ssize_t (*sock_sendmsg)(struct SimSocket *socket,
+ const struct msghdr *msg, int flags);
+ int (*sock_getsockname)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_getpeername)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_bind)(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen);
+ int (*sock_connect)(struct SimSocket *socket,
+ const struct sockaddr *name, int namelen,
+ int flags);
+ int (*sock_listen)(struct SimSocket *socket, int backlog);
+ int (*sock_shutdown)(struct SimSocket *socket, int how);
+ int (*sock_accept)(struct SimSocket *socket,
+ struct SimSocket **newSocket, int flags);
+ int (*sock_ioctl)(struct SimSocket *socket, int request, char *argp);
+ int (*sock_setsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ const void *optval, int optlen);
+ int (*sock_getsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ void *optval, int *optlen);
+
+ void (*sock_poll)(struct SimSocket *socket, void *ret);
+ void (*sock_pollfreewait)(void *polltable);
+
+ struct SimDevice *(*dev_create)(const char *ifname, void *priv,
+ enum SimDevFlags flags);
+ void (*dev_destroy)(struct SimDevice *dev);
+ void *(*dev_get_private)(struct SimDevice *task);
+ void (*dev_set_address)(struct SimDevice *dev,
+ unsigned char buffer[6]);
+ void (*dev_set_mtu)(struct SimDevice *dev, int mtu);
+ struct SimDevicePacket (*dev_create_packet)(struct SimDevice *dev,
+ int size);
+ void (*dev_rx)(struct SimDevice *dev, struct SimDevicePacket packet);
+
+ void (*sys_iterate_files)(const struct SimSysIterator *iter);
+ int (*sys_file_read)(const struct SimSysFile *file, char *buffer,
+ int size, int offset);
+ int (*sys_file_write)(const struct SimSysFile *file,
+ const char *buffer, int size, int offset);
+};
+
+struct SimImported {
+ int (*vprintf)(struct SimKernel *kernel, const char *str,
+ va_list args);
+ void *(*malloc)(struct SimKernel *kernel, unsigned long size);
+ void (*free)(struct SimKernel *kernel, void *buffer);
+ void *(*memcpy)(struct SimKernel *kernel, void *dst, const void *src,
+ unsigned long size);
+ void *(*memset)(struct SimKernel *kernel, void *dst, char value,
+ unsigned long size);
+ int (*atexit)(struct SimKernel *kernel, void (*function)(void));
+ int (*access)(struct SimKernel *kernel, const char *pathname,
+ int mode);
+ char *(*getenv)(struct SimKernel *kernel, const char *name);
+ int (*mkdir)(struct SimKernel *kernel, const char *pathname,
+ mode_t mode);
+ int (*open)(struct SimKernel *kernel, const char *pathname, int flags);
+ int (*__fxstat)(struct SimKernel *kernel, int ver, int fd, void *buf);
+ int (*fseek)(struct SimKernel *kernel, FILE *stream, long offset,
+ int whence);
+ void (*setbuf)(struct SimKernel *kernel, FILE *stream, char *buf);
+ FILE *(*fdopen)(struct SimKernel *kernel, int fd, const char *mode);
+ long (*ftell)(struct SimKernel *kernel, FILE *stream);
+ int (*fclose)(struct SimKernel *kernel, FILE *fp);
+ size_t (*fread)(struct SimKernel *kernel, void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+ size_t (*fwrite)(struct SimKernel *kernel, const void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+
+ unsigned long (*random)(struct SimKernel *kernel);
+ void *(*event_schedule_ns)(struct SimKernel *kernel, __u64 ns,
+ void (*fn)(void *context), void *context,
+ void (*pre_fn)(void));
+ void (*event_cancel)(struct SimKernel *kernel, void *event);
+ __u64 (*current_ns)(struct SimKernel *kernel);
+
+ struct SimTask *(*task_start)(struct SimKernel *kernel,
+ void (*callback)(void *),
+ void *context);
+ void (*task_wait)(struct SimKernel *kernel);
+ struct SimTask *(*task_current)(struct SimKernel *kernel);
+ int (*task_wakeup)(struct SimKernel *kernel, struct SimTask *task);
+ void (*task_yield)(struct SimKernel *kernel);
+
+ void (*dev_xmit)(struct SimKernel *kernel, struct SimDevice *dev,
+ unsigned char *data, int len);
+ void (*signal_raised)(struct SimKernel *kernel, struct SimTask *task,
+ int sig);
+ void (*poll_event)(int flag, void *context);
+};
+
+typedef void (*SimInit)(struct SimExported *, const struct SimImported *,
+ struct SimKernel *kernel);
+void sim_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_INIT_H */
diff --git a/arch/lib/include/sim-printf.h b/arch/lib/include/sim-printf.h
new file mode 100644
index 0000000..2bf8245
--- /dev/null
+++ b/arch/lib/include/sim-printf.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_PRINTF_H
+#define SIM_PRINTF_H
+
+void lib_printf(const char *str, ...);
+
+#endif /* SIM_PRINTF_H */
diff --git a/arch/lib/include/sim-types.h b/arch/lib/include/sim-types.h
new file mode 100644
index 0000000..d50b99b
--- /dev/null
+++ b/arch/lib/include/sim-types.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_TYPES_H
+#define SIM_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBOS_API_VERSION 2
+
+struct SimTask;
+struct SimDevice;
+struct SimSocket;
+struct SimKernel;
+struct SimSysFile;
+
+enum SimDevFlags {
+ SIM_DEV_NOARP = (1 << 0),
+ SIM_DEV_POINTTOPOINT = (1 << 1),
+ SIM_DEV_MULTICAST = (1 << 2),
+ SIM_DEV_BROADCAST = (1 << 3),
+};
+
+struct SimDevicePacket {
+ void *buffer;
+ void *token;
+};
+
+enum SimSysFileFlags {
+ SIM_SYS_FILE_READ = 1 << 0,
+ SIM_SYS_FILE_WRITE = 1 << 1,
+};
+
+struct SimSysIterator {
+ void (*report_start_dir)(const struct SimSysIterator *iter,
+ const char *dirname);
+ void (*report_end_dir)(const struct SimSysIterator *iter);
+ void (*report_file)(const struct SimSysIterator *iter,
+ const char *filename,
+ int flags, struct SimSysFile *file);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_TYPES_H */
diff --git a/arch/lib/include/sim.h b/arch/lib/include/sim.h
new file mode 100644
index 0000000..b30d7e8
--- /dev/null
+++ b/arch/lib/include/sim.h
@@ -0,0 +1,51 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_H
+#define SIM_H
+
+#include <stdarg.h>
+#include <linux/types.h>
+
+#include "sim-types.h"
+
+/* API called from within linux kernel. Forwards to SimImported. */
+int lib_vprintf(const char *str, va_list args);
+void *lib_malloc(unsigned long size);
+void lib_free(void *buffer);
+void *lib_memcpy(void *dst, const void *src, unsigned long size);
+void *lib_memset(void *dst, char value, unsigned long size);
+unsigned long lib_random(void);
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context),
+ void *context);
+void lib_event_cancel(void *event);
+__u64 lib_current_ns(void);
+
+struct SimTask *lib_task_start(void (*callback) (void *), void *context);
+void lib_task_wait(void);
+void lib_task_yield(void);
+struct SimTask *lib_task_current(void);
+/* returns 1 if task was woken up, 0 if it was already running. */
+int lib_task_wakeup(struct SimTask *task);
+struct SimTask *lib_task_create(void *priv, unsigned long pid);
+void lib_task_destroy(struct SimTask *task);
+void *lib_task_get_private(struct SimTask *task);
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len);
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size);
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet);
+
+void lib_signal_raised(struct SimTask *task, int sig);
+
+void lib_poll_event(int flag, void *context);
+void lib_softirq_wakeup(void);
+void lib_update_jiffies(void);
+void *lib_dev_get_private(struct SimDevice *);
+void lib_proc_net_initialize(void);
+
+#endif /* SIM_H */
diff --git a/arch/lib/lib-device.c b/arch/lib/lib-device.c
new file mode 100644
index 0000000..1efa6460
--- /dev/null
+++ b/arch/lib/lib-device.c
@@ -0,0 +1,187 @@
+/*
+ * virtual net_device feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ethtool.h>
+
+struct SimDevice {
+ struct net_device dev;
+ void *priv;
+};
+
+static netdev_tx_t
+kernel_dev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ int err;
+
+ netif_stop_queue(dev);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ err = skb_checksum_help(skb);
+ if (unlikely(err)) {
+ pr_err("checksum error (%d)\n", err);
+ return 0;
+ }
+ }
+
+ lib_dev_xmit((struct SimDevice *)dev, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static u32 always_on(struct net_device *dev)
+{
+ return 1;
+}
+
+
+static const struct ethtool_ops lib_ethtool_ops = {
+ .get_link = always_on,
+};
+
+static const struct net_device_ops lib_dev_ops = {
+ .ndo_start_xmit = kernel_dev_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static void lib_dev_setup(struct net_device *dev)
+{
+ dev->mtu = (16 * 1024) + 20 + 20 + 12;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_ETHER;
+ dev->flags = 0;
+ /* dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; */
+ dev->features = 0
+ | NETIF_F_HIGHDMA
+ | NETIF_F_NETNS_LOCAL;
+ /* disabled NETIF_F_TSO NETIF_F_SG NETIF_F_FRAGLIST NETIF_F_LLTX */
+ dev->ethtool_ops = &lib_ethtool_ops;
+ dev->header_ops = ð_header_ops;
+ dev->netdev_ops = &lib_dev_ops;
+ dev->destructor = &free_netdev;
+}
+
+
+struct SimDevice *lib_dev_create(const char *ifname, void *priv,
+ enum SimDevFlags flags)
+{
+ int err;
+ struct SimDevice *dev =
+ (struct SimDevice *)alloc_netdev(sizeof(struct SimDevice),
+ ifname, NET_NAME_UNKNOWN,
+ &lib_dev_setup);
+ ether_setup((struct net_device *)dev);
+
+ if (flags & SIM_DEV_NOARP)
+ dev->dev.flags |= IFF_NOARP;
+ if (flags & SIM_DEV_POINTTOPOINT)
+ dev->dev.flags |= IFF_POINTOPOINT;
+ if (flags & SIM_DEV_MULTICAST)
+ dev->dev.flags |= IFF_MULTICAST;
+ if (flags & SIM_DEV_BROADCAST) {
+ dev->dev.flags |= IFF_BROADCAST;
+ memset(dev->dev.broadcast, 0xff, 6);
+ }
+ dev->priv = priv;
+ err = register_netdev(&dev->dev);
+ return dev;
+}
+void lib_dev_destroy(struct SimDevice *dev)
+{
+ unregister_netdev(&dev->dev);
+ /* XXX */
+ free_netdev(&dev->dev);
+}
+void *lib_dev_get_private(struct SimDevice *dev)
+{
+ return dev->priv;
+}
+
+void lib_dev_set_mtu(struct SimDevice *dev, int mtu)
+{
+ /* called by ns-3 to synchronize the kernel mtu with */
+ /* the simulation mtu */
+ dev->dev.mtu = mtu;
+}
+
+static int lib_ndo_change_mtu(struct net_device *dev,
+ int new_mtu)
+{
+ /* called by kernel to change the mtu when the user */
+ /* asks for it. */
+ /* XXX should forward the set call to ns-3 and wait for */
+ /* ns-3 to notify of the change in the function above */
+ /* but I am way too tired to do this now. */
+ return 0;
+}
+
+void lib_dev_set_address(struct SimDevice *dev, unsigned char buffer[6])
+{
+ /* called by ns-3 to synchronize the kernel address with */
+ /* the simulation address. */
+ struct sockaddr sa;
+
+ sa.sa_family = dev->dev.type;
+ lib_memcpy(&sa.sa_data, buffer, 6);
+ dev->dev.netdev_ops->ndo_set_mac_address(&dev->dev, &sa);
+ /* Note that we don't call dev_set_mac_address (&dev->dev, &sa); */
+ /* because this function expects to be called from within */
+ /* the netlink layer so, it expects to hold */
+ /* the netlink lock during the execution of the associated notifiers */
+}
+static int get_hack_size(int size)
+{
+ /* Note: this hack is coming from nsc */
+ /* Bit of a hack... */
+ /* Note that the size allocated here effects the offered window
+ somewhat. I've got this heuristic here to try and match up with
+ what we observe on the emulation network and by looking at the
+ driver code of the eepro100. In both cases we allocate enough
+ space for our packet, which is the important thing. The amount
+ of slack at the end can make linux decide the grow the window
+ differently. This is quite subtle, but the code in question is
+ in the tcp_grow_window function. It checks skb->truesize, which
+ is the size of the skbuff allocated for the incoming data
+ packet -- what we are allocating right now! */
+ if (size < 1200)
+ return size + 36;
+ else if (size <= 1500)
+ return 1536;
+ else
+ return size + 36;
+}
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size)
+{
+ struct SimDevicePacket packet;
+ int len = get_hack_size(size);
+ struct sk_buff *skb = __dev_alloc_skb(len, __GFP_WAIT);
+
+ packet.token = skb;
+ packet.buffer = skb_put(skb, len);
+ return packet;
+}
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet)
+{
+ struct sk_buff *skb = packet.token;
+ struct net_device *dev = &device->dev;
+
+ skb->protocol = eth_type_trans(skb, dev);
+ /* Do the TCP checksum (FIXME: should be configurable) */
+ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ netif_rx(skb);
+}
diff --git a/arch/lib/lib-socket.c b/arch/lib/lib-socket.c
new file mode 100644
index 0000000..d9be5fc
--- /dev/null
+++ b/arch/lib/lib-socket.c
@@ -0,0 +1,410 @@
+/*
+ * socket feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/net.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/inet_connection_sock.h>
+
+struct SimSocket {};
+
+static struct iovec *copy_iovec(const struct iovec *input, int len)
+{
+ int size = sizeof(struct iovec) * len;
+ struct iovec *output = lib_malloc(size);
+
+ if (!output)
+ return NULL;
+ lib_memcpy(output, input, size);
+ return output;
+}
+
+int lib_sock_socket(int domain, int type, int protocol,
+ struct SimSocket **socket)
+{
+ struct socket **kernel_socket = (struct socket **)socket;
+ int flags;
+
+ /* from net/socket.c */
+ flags = type & ~SOCK_TYPE_MASK;
+ if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ return -EINVAL;
+ type &= SOCK_TYPE_MASK;
+
+ int retval = sock_create(domain, type, protocol, kernel_socket);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ struct file *fp = lib_malloc(sizeof(struct file));
+ (*kernel_socket)->file = fp;
+ fp->f_cred = lib_malloc(sizeof(struct cred));
+ return retval;
+}
+int lib_sock_close(struct SimSocket *socket)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+
+ sock_release(kernel_socket);
+ return 0;
+}
+static size_t iov_size(const struct user_msghdr *msg)
+{
+ size_t i;
+ size_t size = 0;
+
+ for (i = 0; i < msg->msg_iovlen; i++)
+ size += msg->msg_iov[i].iov_len;
+ return size;
+}
+ssize_t lib_sock_recvmsg(struct SimSocket *socket,
+ struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct msghdr msg_sys;
+ struct cmsghdr *user_cmsgh = msg->msg_control;
+ size_t user_cmsghlen = msg->msg_controllen;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, READ,
+ msg->msg_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_recvmsg(kernel_socket, &msg_sys, iov_size(msg), flags);
+
+ msg->msg_name = msg_sys.msg_name;
+ msg->msg_namelen = msg_sys.msg_namelen;
+ msg->msg_control = user_cmsgh;
+ msg->msg_controllen = user_cmsghlen - msg_sys.msg_controllen;
+ return retval;
+}
+ssize_t lib_sock_sendmsg(struct SimSocket *socket,
+ const struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct iovec *kernel_iov = copy_iovec(msg->msg_iov, msg->msg_iovlen);
+ struct msghdr msg_sys;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, WRITE,
+ kernel_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_sendmsg(kernel_socket, &msg_sys);
+ lib_free(kernel_iov);
+ return retval;
+}
+int lib_sock_getsockname(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 0);
+
+ return retval;
+}
+int lib_sock_getpeername(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 1);
+
+ return retval;
+}
+int lib_sock_bind(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ int retval =
+ sock->ops->bind(sock, (struct sockaddr *)&address, namelen);
+ return retval;
+}
+int lib_sock_connect(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen, int flags)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ sock->file->f_flags = flags;
+ int retval = sock->ops->connect(sock, (struct sockaddr *)&address,
+ namelen, flags);
+ return retval;
+}
+int lib_sock_listen(struct SimSocket *socket, int backlog)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->listen(sock, backlog);
+
+ return retval;
+}
+int lib_sock_shutdown(struct SimSocket *socket, int how)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->shutdown(sock, how);
+
+ return retval;
+}
+int lib_sock_accept(struct SimSocket *socket, struct SimSocket **new_socket,
+ int flags)
+{
+ struct socket *sock, *newsock;
+ int err;
+
+ sock = (struct socket *)socket;
+
+ /* the fields do not matter here. If we could, */
+ /* we would call sock_alloc but it's not exported. */
+ err = sock_create_lite(0, 0, 0, &newsock);
+ if (err < 0)
+ return err;
+ newsock->type = sock->type;
+ newsock->ops = sock->ops;
+
+ err = sock->ops->accept(sock, newsock, flags);
+ if (err < 0) {
+ sock_release(newsock);
+ return err;
+ }
+ *new_socket = (struct SimSocket *)newsock;
+ return 0;
+}
+int lib_sock_ioctl(struct SimSocket *socket, int request, char *argp)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sock *sk;
+ struct net *net;
+ int err;
+
+ sk = sock->sk;
+ net = sock_net(sk);
+
+ err = sock->ops->ioctl(sock, request, (long)argp);
+
+ /*
+ * If this ioctl is unknown try to hand it down
+ * to the NIC driver.
+ */
+ if (err == -ENOIOCTLCMD)
+ err = dev_ioctl(net, request, argp);
+ return err;
+}
+int lib_sock_setsockopt(struct SimSocket *socket, int level, int optname,
+ const void *optval, int optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ char *coptval = (char *)optval;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_setsockopt(sock, level, optname, coptval, optlen);
+ else
+ err = sock->ops->setsockopt(sock, level, optname, coptval,
+ optlen);
+ return err;
+}
+int lib_sock_getsockopt(struct SimSocket *socket, int level, int optname,
+ void *optval, int *optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_getsockopt(sock, level, optname, optval, optlen);
+ else
+ err =
+ sock->ops->getsockopt(sock, level, optname, optval,
+ optlen);
+ return err;
+}
+
+int lib_sock_canrecv(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct inet_connection_sock *icsk;
+
+ switch (sock->sk->sk_state) {
+ case TCP_CLOSE:
+ if (SOCK_STREAM == sock->sk->sk_type)
+ return 1;
+ case TCP_ESTABLISHED:
+ return sock->sk->sk_receive_queue.qlen > 0;
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV:
+ case TCP_LAST_ACK:
+ case TCP_CLOSING:
+ return 0;
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_TIME_WAIT:
+ case TCP_CLOSE_WAIT:
+ return 1;
+ case TCP_LISTEN:
+ {
+ icsk = inet_csk(sock->sk);
+ return !reqsk_queue_empty(&icsk->icsk_accept_queue);
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+int lib_sock_cansend(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+
+ return sock_writeable(sock->sk);
+}
+
+/**
+ * Struct used to pass pool table context between DCE and Kernel and back from
+ * Kernel to DCE
+ *
+ * When calling sock_poll we provide in ret field the wanted eventmask, and in
+ * the opaque field the DCE poll table
+ *
+ * if a corresponding event occurs later, the PollEvent will be called by kernel
+ * with the DCE poll table in context variable, then we will able to wake up the
+ * thread blocked in poll call.
+ *
+ * Back from sock_poll method the kernel change ret field with the response from
+ * poll return of the corresponding kernel socket, and in opaque field there is
+ * a reference to the kernel poll table we will use this reference to remove us
+ * from the file wait queue when ending the DCE poll call or when ending the DCE
+ * process which is currently polling.
+ *
+ */
+struct poll_table_ref {
+ int ret;
+ void *opaque;
+};
+
+/* Because the poll main loop code is in NS3/DCE we have only on entry
+ in our kernel poll table */
+struct lib_ptable_entry {
+ wait_queue_t wait;
+ wait_queue_head_t *wait_address;
+ int eventMask; /* Poll wanted event mask. */
+ void *opaque; /* Pointeur to DCE poll table */
+};
+
+static int lib_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)wait->private;
+
+ /* Filter only wanted events */
+ if (key && !((unsigned long)key & entry->eventMask))
+ return 0;
+
+ lib_poll_event((unsigned long)key, entry->opaque);
+ return 1;
+}
+
+static void lib_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table *p)
+{
+ struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)
+ lib_malloc(sizeof(struct lib_ptable_entry));
+ struct poll_table_ref *fromDCE = (struct poll_table_ref *)pwq->table;
+
+ if (!entry)
+ return;
+
+ entry->opaque = fromDCE->opaque; /* Copy DCE poll table reference */
+ entry->eventMask = fromDCE->ret; /* Copy poll mask of wanted events. */
+
+ pwq->table = (struct poll_table_page *)entry;
+
+ init_waitqueue_func_entry(&entry->wait, lib_pollwake);
+ entry->wait.private = entry;
+ entry->wait_address = wait_address;
+ add_wait_queue(wait_address, &entry->wait);
+}
+
+void dce_poll_initwait(struct poll_wqueues *pwq)
+{
+ init_poll_funcptr(&pwq->pt, lib_pollwait);
+ pwq->polling_task = current;
+ pwq->triggered = 0;
+ pwq->error = 0;
+ pwq->table = NULL;
+ pwq->inline_index = 0;
+}
+
+/* call poll on socket ... */
+void lib_sock_poll(struct SimSocket *socket, struct poll_table_ref *ret)
+{
+ struct socket *sock = (struct socket *)socket;
+ /* Provide a fake file structure */
+ struct file zero;
+ poll_table *pwait = 0;
+ struct poll_wqueues *ptable = 0;
+
+ lib_memset(&zero, 0, sizeof(struct file));
+
+ if (ret->opaque) {
+ ptable =
+ (struct poll_wqueues *)lib_malloc(sizeof(struct
+ poll_wqueues));
+ if (!ptable)
+ return;
+
+ dce_poll_initwait(ptable);
+
+ pwait = &(ptable->pt);
+ /* Pass the DCE pool table to lib_pollwait function */
+ ptable->table = (struct poll_table_page *)ret;
+ }
+
+ ret->ret = sock->ops->poll(&zero, sock, pwait);
+ /* Pass back the kernel poll table to DCE in order to DCE to */
+ /* remove from wait queue */
+ /* using lib_sock_pollfreewait method below */
+ ret->opaque = ptable;
+}
+
+void lib_sock_pollfreewait(void *polltable)
+{
+ struct poll_wqueues *ptable = (struct poll_wqueues *)polltable;
+
+ if (ptable && ptable->table) {
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)ptable->table;
+ remove_wait_queue(entry->wait_address, &entry->wait);
+ lib_free(entry);
+ }
+ lib_free(ptable);
+}
+
+
+
+
diff --git a/arch/lib/lib.c b/arch/lib/lib.c
new file mode 100644
index 0000000..52d638e
--- /dev/null
+++ b/arch/lib/lib.c
@@ -0,0 +1,294 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/init.h> /* initcall_t */
+#include <linux/kernel.h> /* SYSTEM_BOOTING */
+#include <linux/sched.h> /* struct task_struct */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <drivers/base/base.h>
+#include <linux/idr.h>
+#include <linux/rcupdate.h>
+#include "sim-init.h"
+#include "sim.h"
+
+enum system_states system_state = SYSTEM_BOOTING;
+/* glues */
+struct task_struct init_task;
+
+struct SimImported g_imported;
+
+
+#define RETURN_void(rettype, v) \
+ ({ \
+ (v); \
+ lib_softirq_wakeup(); \
+ })
+
+#define RETURN_nvoid(rettype, v) \
+ ({ \
+ rettype x = (v); \
+ lib_softirq_wakeup(); \
+ x; \
+ })
+
+#define FORWARDER1(name, type, rettype, t0) \
+ extern rettype name(t0); \
+ static rettype name ## _forwarder(t0 v0) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0))); \
+ }
+
+#define FORWARDER2(name, type, rettype, t0, t1) \
+ extern rettype name(t0, t1); \
+ static rettype name ## _forwarder(t0 v0, t1 v1) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1))); \
+ }
+#define FORWARDER3(name, type, rettype, t0, t1, t2) \
+ extern rettype name(t0, t1, t2); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER5(name, type, rettype, t0, t1, t2, t3, t4) \
+ extern rettype name(t0, t1, t2, t3, t4); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3, t4 v4) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3, v4))); \
+ }
+
+FORWARDER3(lib_dev_create, nvoid, struct SimDevice *, const char *, void *,
+ enum SimDevFlags);
+FORWARDER1(lib_dev_destroy, void, void, struct SimDevice *);
+FORWARDER2(lib_dev_set_address, void, void, struct SimDevice *,
+ unsigned char *);
+FORWARDER2(lib_dev_set_mtu, void, void, struct SimDevice *, int);
+FORWARDER2(lib_dev_create_packet, nvoid, struct SimDevicePacket,
+ struct SimDevice *, int);
+FORWARDER2(lib_dev_rx, void, void, struct SimDevice *, struct SimDevicePacket);
+
+FORWARDER4(lib_sock_socket, nvoid, int, int, int, int, struct SimSocket **);
+FORWARDER1(lib_sock_close, nvoid, int, struct SimSocket *);
+FORWARDER3(lib_sock_recvmsg, nvoid, ssize_t, struct SimSocket *,
+ struct msghdr *, int);
+FORWARDER3(lib_sock_sendmsg, nvoid, ssize_t, struct SimSocket *,
+ const struct msghdr *, int);
+FORWARDER3(lib_sock_getsockname, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_getpeername, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_bind, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int);
+FORWARDER4(lib_sock_connect, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int, int);
+FORWARDER2(lib_sock_listen, nvoid, int, struct SimSocket *, int);
+FORWARDER2(lib_sock_shutdown, nvoid, int, struct SimSocket *, int);
+FORWARDER3(lib_sock_accept, nvoid, int, struct SimSocket *,
+ struct SimSocket **, int);
+FORWARDER3(lib_sock_ioctl, nvoid, int, struct SimSocket *, int, char *);
+FORWARDER5(lib_sock_setsockopt, nvoid, int, struct SimSocket *, int, int,
+ const void *, int);
+FORWARDER5(lib_sock_getsockopt, nvoid, int, struct SimSocket *, int, int,
+ void *, int *);
+
+FORWARDER2(lib_sock_poll, void, void, struct SimSocket *, void *);
+FORWARDER1(lib_sock_pollfreewait, void, void, void *);
+
+FORWARDER1(lib_sys_iterate_files, void, void, const struct SimSysIterator *);
+FORWARDER4(lib_sys_file_read, nvoid, int, const struct SimSysFile *, char *,
+ int, int);
+FORWARDER4(lib_sys_file_write, nvoid, int, const struct SimSysFile *,
+ const char *, int, int);
+
+struct SimKernel *g_kernel;
+
+void lib_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel)
+{
+ /* make sure we can call the callbacks */
+ g_imported = *imported;
+ g_kernel = kernel;
+ exported->task_create = lib_task_create;
+ exported->task_destroy = lib_task_destroy;
+ exported->task_get_private = lib_task_get_private;
+ exported->sock_socket = lib_sock_socket_forwarder;
+ exported->sock_close = lib_sock_close_forwarder;
+ exported->sock_recvmsg = lib_sock_recvmsg_forwarder;
+ exported->sock_sendmsg = lib_sock_sendmsg_forwarder;
+ exported->sock_getsockname = lib_sock_getsockname_forwarder;
+ exported->sock_getpeername = lib_sock_getpeername_forwarder;
+ exported->sock_bind = lib_sock_bind_forwarder;
+ exported->sock_connect = lib_sock_connect_forwarder;
+ exported->sock_listen = lib_sock_listen_forwarder;
+ exported->sock_shutdown = lib_sock_shutdown_forwarder;
+ exported->sock_accept = lib_sock_accept_forwarder;
+ exported->sock_ioctl = lib_sock_ioctl_forwarder;
+ exported->sock_setsockopt = lib_sock_setsockopt_forwarder;
+ exported->sock_getsockopt = lib_sock_getsockopt_forwarder;
+
+ exported->sock_poll = lib_sock_poll_forwarder;
+ exported->sock_pollfreewait = lib_sock_pollfreewait_forwarder;
+
+ exported->dev_create = lib_dev_create_forwarder;
+ exported->dev_destroy = lib_dev_destroy_forwarder;
+ exported->dev_get_private = lib_dev_get_private;
+ exported->dev_set_address = lib_dev_set_address_forwarder;
+ exported->dev_set_mtu = lib_dev_set_mtu_forwarder;
+ exported->dev_create_packet = lib_dev_create_packet_forwarder;
+ exported->dev_rx = lib_dev_rx_forwarder;
+
+ exported->sys_iterate_files = lib_sys_iterate_files_forwarder;
+ exported->sys_file_write = lib_sys_file_write_forwarder;
+ exported->sys_file_read = lib_sys_file_read_forwarder;
+
+ pr_notice("%s", linux_banner);
+
+ rcu_init();
+
+ /* in drivers/base/core.c (called normally by drivers/base/init.c) */
+ devices_init();
+ /* in lib/idr.c (called normally by init/main.c) */
+ idr_init_cache();
+ vfs_caches_init(totalram_pages);
+
+ lib_proc_net_initialize();
+
+ /* and, then, call the normal initcalls */
+ initcall_t *call;
+ extern initcall_t __initcall_start[], __initcall_end[];
+
+ call = __initcall_start;
+ do {
+ (*call)();
+ call++;
+ } while (call < __initcall_end);
+
+ /* finally, put the system in RUNNING state. */
+ system_state = SYSTEM_RUNNING;
+}
+
+int lib_vprintf(const char *str, va_list args)
+{
+ return g_imported.vprintf(g_kernel, str, args);
+}
+void *lib_malloc(unsigned long size)
+{
+ return g_imported.malloc(g_kernel, size);
+}
+void lib_free(void *buffer)
+{
+ return g_imported.free(g_kernel, buffer);
+}
+void *lib_memcpy(void *dst, const void *src, unsigned long size)
+{
+ return g_imported.memcpy(g_kernel, dst, src, size);
+}
+void *lib_memset(void *dst, char value, unsigned long size)
+{
+ return g_imported.memset(g_kernel, dst, value, size);
+}
+unsigned long lib_random(void)
+{
+ return g_imported.random(g_kernel);
+}
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context), void *context)
+{
+ return g_imported.event_schedule_ns(g_kernel, ns, fn, context,
+ lib_update_jiffies);
+}
+void lib_event_cancel(void *event)
+{
+ return g_imported.event_cancel(g_kernel, event);
+}
+__u64 lib_current_ns(void)
+{
+ return g_imported.current_ns(g_kernel);
+}
+struct SimTaskTrampolineContext {
+ void (*callback)(void *);
+ void *context;
+};
+static void lib_task_start_trampoline(void *context)
+{
+ /* we use this trampoline solely for the purpose of executing
+ lib_update_jiffies prior to calling the callback. */
+ struct SimTaskTrampolineContext *ctx = context;
+ void (*callback)(void *) = ctx->callback;
+ void *callback_context = ctx->context;
+
+ lib_free(ctx);
+ lib_update_jiffies();
+ callback(callback_context);
+}
+struct SimTask *lib_task_start(void (*callback) (void *), void *context)
+{
+ struct SimTaskTrampolineContext *ctx =
+ lib_malloc(sizeof(struct SimTaskTrampolineContext));
+
+ if (!ctx)
+ return NULL;
+ ctx->callback = callback;
+ ctx->context = context;
+ return g_imported.task_start(g_kernel, &lib_task_start_trampoline, ctx);
+}
+void lib_task_wait(void)
+{
+ rcu_sched_qs();
+ g_imported.task_wait(g_kernel);
+ lib_update_jiffies();
+}
+struct SimTask *lib_task_current(void)
+{
+ return g_imported.task_current(g_kernel);
+}
+int lib_task_wakeup(struct SimTask *task)
+{
+ return g_imported.task_wakeup(g_kernel, task);
+}
+void lib_task_yield(void)
+{
+ rcu_idle_enter();
+ g_imported.task_yield(g_kernel);
+ rcu_idle_exit();
+ lib_update_jiffies();
+}
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len)
+{
+ return g_imported.dev_xmit(g_kernel, dev, data, len);
+}
+
+void lib_signal_raised(struct SimTask *task, int sig)
+{
+ g_imported.signal_raised(g_kernel, task, sig);
+}
+
+void lib_poll_event(int flag, void *context)
+{
+ g_imported.poll_event(flag, context);
+}
diff --git a/arch/lib/lib.h b/arch/lib/lib.h
new file mode 100644
index 0000000..abf2a26
--- /dev/null
+++ b/arch/lib/lib.h
@@ -0,0 +1,21 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#ifndef LIB_H
+#define LIB_H
+
+#include <linux/sched.h>
+
+struct SimTask {
+ struct list_head head;
+ struct task_struct kernel_task;
+ void *private;
+};
+
+#endif /* LIB_H */
--
2.1.0
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/slab.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 203 insertions(+)
create mode 100644 arch/lib/slab.c
diff --git a/arch/lib/slab.c b/arch/lib/slab.c
new file mode 100644
index 0000000..a08f736
--- /dev/null
+++ b/arch/lib/slab.c
@@ -0,0 +1,203 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/page-flags.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+
+/* glues */
+struct kmem_cache *files_cachep;
+
+void kfree(const void *p)
+{
+ unsigned long start;
+
+ if (p == 0)
+ return;
+ start = (unsigned long)p;
+ start -= sizeof(size_t);
+ lib_free((void *)start);
+}
+size_t ksize(const void *p)
+{
+ size_t *psize = (size_t *)p;
+
+ psize--;
+ return *psize;
+}
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ void *p = lib_malloc(size + sizeof(size));
+ unsigned long start;
+
+ if (!p)
+ return NULL;
+
+ if (p != 0 && (flags & __GFP_ZERO))
+ lib_memset(p, 0, size + sizeof(size));
+ lib_memcpy(p, &size, sizeof(size));
+ start = (unsigned long)p;
+ return (void *)(start + sizeof(size));
+}
+
+void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller)
+{
+ return kmalloc(size, flags);
+}
+
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+
+ if (!new_size) {
+ kfree(p);
+ return ZERO_SIZE_PTR;
+ }
+
+ ret = __kmalloc(new_size, flags);
+ if (ret && p != ret)
+ kfree(p);
+
+ return ret;
+}
+
+struct kmem_cache *
+kmem_cache_create(const char *name, size_t size, size_t align,
+ unsigned long flags, void (*ctor)(void *))
+{
+ struct kmem_cache *cache = kmalloc(sizeof(struct kmem_cache), flags);
+
+ if (!cache)
+ return NULL;
+ cache->name = name;
+ cache->size = size;
+ cache->align = align;
+ cache->flags = flags;
+ cache->ctor = ctor;
+ return cache;
+}
+void kmem_cache_destroy(struct kmem_cache *cache)
+{
+ kfree(cache);
+}
+int kmem_cache_shrink(struct kmem_cache *cache)
+{
+ return 1;
+}
+const char *kmem_cache_name(struct kmem_cache *cache)
+{
+ return cache->name;
+}
+void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags)
+{
+ void *p = kmalloc(cache->size, flags);
+
+ if (p == 0)
+ return NULL;
+ if (cache->ctor)
+ (cache->ctor)(p);
+ return p;
+
+}
+void kmem_cache_free(struct kmem_cache *cache, void *p)
+{
+ kfree(p);
+}
+
+struct page *
+__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist, nodemask_t *nodemask)
+{
+ void *p;
+ struct page *page;
+ unsigned long pointer;
+
+ /* typically, called from networking code by alloc_page or */
+ /* directly with an order = 0. */
+ if (order)
+ return NULL;
+ p = lib_malloc(sizeof(struct page) + (1 << PAGE_SHIFT));
+ page = (struct page *)p;
+
+ atomic_set(&page->_count, 1);
+ page->flags = 0;
+ pointer = (unsigned long)page;
+ pointer += sizeof(struct page);
+ page->virtual = (void *)pointer;
+ return page;
+}
+void __free_pages(struct page *page, unsigned int order)
+{
+ /* typically, called from networking code by __free_page */
+ lib_assert(order == 0);
+ lib_free(page);
+}
+
+void put_page(struct page *page)
+{
+ if (atomic_dec_and_test(&page->_count))
+ lib_free(page);
+}
+unsigned long get_zeroed_page(gfp_t gfp_mask)
+{
+ return __get_free_pages(gfp_mask | __GFP_ZERO, 0);
+}
+
+void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
+{
+ return alloc_pages(gfp_mask, get_order(size));
+}
+
+unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
+{
+ int size = (1 << order) * PAGE_SIZE;
+ void *p = kmalloc(size, gfp_mask);
+
+ return (unsigned long)p;
+}
+void free_pages(unsigned long addr, unsigned int order)
+{
+ if (addr != 0)
+ kfree((void *)addr);
+}
+
+void *vmalloc(unsigned long size)
+{
+ return lib_malloc(size);
+}
+void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
+{
+ return kmalloc(size, gfp_mask);
+}
+void vfree(const void *addr)
+{
+ lib_free((void *)addr);
+}
+void *vmalloc_node(unsigned long size, int node)
+{
+ return lib_malloc(size);
+}
+void vmalloc_sync_all(void)
+{
+}
+void *__alloc_percpu(size_t size, size_t align)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+void free_percpu(void __percpu *ptr)
+{
+ kfree(ptr);
+}
+void *__alloc_bootmem_nopanic(unsigned long size,
+ unsigned long align,
+ unsigned long goal)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
--
2.1.0
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/hrtimer.c | 122 +++++++++++++++++++++++
arch/lib/tasklet-hrtimer.c | 57 +++++++++++
arch/lib/time.c | 144 +++++++++++++++++++++++++++
arch/lib/timer.c | 238 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 561 insertions(+)
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
diff --git a/arch/lib/hrtimer.c b/arch/lib/hrtimer.c
new file mode 100644
index 0000000..4565b59
--- /dev/null
+++ b/arch/lib/hrtimer.c
@@ -0,0 +1,122 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/hrtimer.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * hrtimer_init - initialize a timer to the given clock
+ * @timer: the timer to be initialized
+ * @clock_id: the clock to be used
+ * @mode: timer mode abs/rel
+ */
+void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
+{
+ memset(timer, 0, sizeof(*timer));
+}
+static void trampoline(void *context)
+{
+ struct hrtimer *timer = context;
+ enum hrtimer_restart restart = timer->function(timer);
+
+ if (restart == HRTIMER_RESTART) {
+ void *event =
+ lib_event_schedule_ns(ktime_to_ns(timer->_softexpires),
+ &trampoline, timer);
+ timer->base = event;
+ } else {
+ /* mark as completed. */
+ timer->base = 0;
+ }
+}
+/**
+ * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
+ * @timer: the timer to be added
+ * @tim: expiry time
+ * @delta_ns: "slack" range for the timer
+ * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
+ *
+ * Returns:
+ * 0 on success
+ * 1 when the timer was active
+ */
+int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns,
+ const enum hrtimer_mode mode,
+ int wakeup)
+{
+ int ret = hrtimer_cancel(timer);
+ s64 ns = ktime_to_ns(tim);
+ void *event;
+
+ if (mode == HRTIMER_MODE_ABS)
+ ns -= lib_current_ns();
+ timer->_softexpires = ns_to_ktime(ns);
+ event = lib_event_schedule_ns(ns, &trampoline, timer);
+ timer->base = event;
+ return ret;
+}
+/**
+ * hrtimer_try_to_cancel - try to deactivate a timer
+ * @timer: hrtimer to stop
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ * -1 when the timer is currently excuting the callback function and
+ * cannot be stopped
+ */
+int hrtimer_try_to_cancel(struct hrtimer *timer)
+{
+ /* Note: we cannot return -1 from this function.
+ see comment in hrtimer_cancel. */
+ if (timer->base == 0)
+ /* timer was not active yet */
+ return 1;
+ lib_event_cancel(timer->base);
+ timer->base = 0;
+ return 0;
+}
+/**
+ * hrtimer_cancel - cancel a timer and wait for the handler to finish.
+ * @timer: the timer to be cancelled
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ */
+int hrtimer_cancel(struct hrtimer *timer)
+{
+ /* Note: because we assume a uniprocessor non-interruptible */
+ /* system when running in the kernel, we know that the timer */
+ /* is not running when we execute this code, so, know that */
+ /* try_to_cancel cannot return -1 and we don't need to retry */
+ /* the cancel later to wait for the handler to finish. */
+ int ret = hrtimer_try_to_cancel(timer);
+
+ lib_assert(ret >= 0);
+ return ret;
+}
+int
+hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
+}
+int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, delta_ns, mode, 1);
+}
+
+int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
+{
+ *tp = ns_to_timespec(1);
+ return 0;
+}
diff --git a/arch/lib/tasklet-hrtimer.c b/arch/lib/tasklet-hrtimer.c
new file mode 100644
index 0000000..fef4902
--- /dev/null
+++ b/arch/lib/tasklet-hrtimer.c
@@ -0,0 +1,57 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
+{
+ struct tasklet_hrtimer *ttimer =
+ container_of(timer, struct tasklet_hrtimer, timer);
+
+ tasklet_schedule(&ttimer->tasklet);
+ return HRTIMER_NORESTART;
+}
+static void __tasklet_hrtimer_trampoline(unsigned long data)
+{
+ struct tasklet_hrtimer *ttimer = (void *)data;
+ enum hrtimer_restart restart;
+
+ restart = ttimer->function(&ttimer->timer);
+ if (restart != HRTIMER_NORESTART)
+ hrtimer_restart(&ttimer->timer);
+}
+/**
+ * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
+ * @ttimer: tasklet_hrtimer which is initialized
+ * @function: hrtimer callback function which gets called from softirq context
+ * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
+ * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
+ */
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+ enum hrtimer_restart (*function)(struct hrtimer *),
+ clockid_t which_clock, enum hrtimer_mode mode)
+{
+ hrtimer_init(&ttimer->timer, which_clock, mode);
+ ttimer->timer.function = __hrtimer_tasklet_trampoline;
+ tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
+ (unsigned long)ttimer);
+ ttimer->function = function;
+}
+
+void __tasklet_hi_schedule(struct tasklet_struct *t)
+{
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ void *event =
+ lib_event_schedule_ns(0, (void *)&t->func, (void *)t->data);
+ t->next = event;
+}
diff --git a/arch/lib/time.c b/arch/lib/time.c
new file mode 100644
index 0000000..b54be75
--- /dev/null
+++ b/arch/lib/time.c
@@ -0,0 +1,144 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/time.h>
+#include <linux/errno.h>
+#include <linux/timex.h>
+#include <linux/ktime.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+unsigned long volatile jiffies = INITIAL_JIFFIES;
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+struct timespec xtime;
+seqlock_t xtime_lock;
+/* accessed from wrap_clock from do_sys_settimeofday.
+ We don't call the latter so we should never access this variable. */
+struct timespec wall_to_monotonic;
+
+uint64_t ns_to_jiffies(uint64_t ns)
+{
+ do_div(ns, (1000000000 / HZ));
+ return ns;
+}
+
+void lib_update_jiffies(void)
+{
+ jiffies = ns_to_jiffies(lib_current_ns());
+ jiffies_64 = ns_to_jiffies(lib_current_ns());
+}
+
+struct timespec current_kernel_time(void)
+{
+ u64 ns = lib_current_ns();
+ struct timespec spec = ns_to_timespec(ns);
+
+ return spec;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ u64 ns = lib_current_ns();
+
+ *tv = ns_to_timeval(ns);
+}
+
+int do_adjtimex(struct timex *timex)
+{
+ lib_assert(false);
+ return -EPERM;
+}
+ktime_t ktime_get(void)
+{
+ u64 ns = lib_current_ns();
+
+ return ns_to_ktime(ns);
+}
+ktime_t ktime_get_with_offset(enum tk_offsets offs)
+{
+ /* FIXME */
+ return ktime_get();
+}
+
+/* copied from kernel/time/hrtimeer.c */
+#if BITS_PER_LONG < 64
+/*
+ * Divide a ktime value by a nanosecond value
+ */
+u64 __ktime_divns(const ktime_t kt, s64 div)
+{
+ u64 dclc;
+ int sft = 0;
+
+ dclc = ktime_to_ns(kt);
+ /* Make sure the divisor is less than 2^32: */
+ while (div >> 32) {
+ sft++;
+ div >>= 1;
+ }
+ dclc >>= sft;
+ do_div(dclc, (unsigned long)div);
+
+ return dclc;
+}
+#endif /* BITS_PER_LONG >= 64 */
+
+void update_xtime_cache(u64 nsec)
+{
+}
+unsigned long get_seconds(void)
+{
+ u64 ns = lib_current_ns();
+
+ do_div(ns, 1000000000);
+ return ns;
+}
+static unsigned long
+round_jiffies_common(unsigned long j,
+ bool force_up)
+{
+ int rem;
+ unsigned long original = j;
+
+ rem = j % HZ;
+ if (rem < HZ / 4 && !force_up) /* round down */
+ j = j - rem;
+ else /* round up */
+ j = j - rem + HZ;
+ if (j <= jiffies) /* rounding ate our timeout entirely; */
+ return original;
+ return j;
+}
+unsigned long round_jiffies(unsigned long j)
+{
+ return round_jiffies_common(j, false);
+}
+unsigned long round_jiffies_relative(unsigned long j)
+{
+ unsigned long j0 = jiffies;
+
+ /* Use j0 because jiffies might change while we run */
+ return round_jiffies_common(j + j0, false) - j0;
+}
+unsigned long round_jiffies_up(unsigned long j)
+{
+ return round_jiffies_common(j, true);
+}
+static void msleep_trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+void msleep(unsigned int msecs)
+{
+ lib_event_schedule_ns(((__u64)msecs) * 1000000, &msleep_trampoline,
+ lib_task_current());
+ lib_task_wait();
+}
diff --git a/arch/lib/timer.c b/arch/lib/timer.c
new file mode 100644
index 0000000..87d2283
--- /dev/null
+++ b/arch/lib/timer.c
@@ -0,0 +1,238 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * init_timer_key - initialize a timer
+ * @timer: the timer to be initialized
+ * @name: name of the timer
+ * @key: lockdep class key of the fake lock used for tracking timer
+ * sync lock dependencies
+ *
+ * init_timer_key() must be done to a timer prior calling *any* of the
+ * other timer functions.
+ */
+void init_timer_key(struct timer_list *timer,
+ unsigned int flags,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * Note: name and key are used for debugging. We ignore them
+ * unconditionally.
+ * Note: we do not initialize the lockdep map either because we
+ * don't care.
+ * and, finally, we never care about the base field either.
+ *
+ * So, for now, we have a timer which is marked as "not started"
+ * thanks to its entry.next field set to NULL (timer_pending
+ * will return 0)
+ */
+ timer->entry.next = NULL;
+ timer->base = 0;
+}
+
+struct list_head g_expired_events = LIST_HEAD_INIT(g_expired_events);
+struct list_head g_pending_events = LIST_HEAD_INIT(g_pending_events);
+
+static void run_timer_softirq(struct softirq_action *h)
+{
+ while (!list_empty(&g_expired_events)) {
+ struct timer_list *timer = list_first_entry(&g_expired_events,
+ struct timer_list,
+ entry);
+ void (*fn)(unsigned long);
+ unsigned long data;
+
+ fn = timer->function;
+ data = timer->data;
+ lib_assert(timer->base == 0);
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ fn(data);
+ }
+ }
+}
+
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
+}
+static void timer_trampoline(void *context)
+{
+ struct timer_list *timer;
+
+ ensure_softirq_opened();
+ timer = context;
+ timer->base = 0;
+ if (timer->entry.prev != LIST_POISON2)
+ list_del(&timer->entry);
+ list_add_tail(&timer->entry, &g_expired_events);
+ raise_softirq(TIMER_SOFTIRQ);
+}
+/**
+ * add_timer - start a timer
+ * @timer: the timer to be added
+ *
+ * The kernel will do a ->function(->data) callback from the
+ * timer interrupt at the ->expires point in the future. The
+ * current time is 'jiffies'.
+ *
+ * The timer's ->expires, ->function (and if the handler uses it, ->data)
+ * fields must be set prior calling this function.
+ *
+ * Timers with an ->expires field in the past will be executed in the next
+ * timer tick.
+ */
+void add_timer(struct timer_list *timer)
+{
+ __u64 delay_ns = 0;
+
+ lib_assert(!timer_pending(timer));
+ if (timer->expires <= jiffies)
+ delay_ns = (1000000000 / HZ); /* next tick. */
+ else
+ delay_ns =
+ ((__u64)timer->expires *
+ (1000000000 / HZ)) - lib_current_ns();
+ void *event = lib_event_schedule_ns(delay_ns, &timer_trampoline, timer);
+ /* store the external event in the base field */
+ /* to be able to retrieve it from del_timer */
+ timer->base = event;
+ /* finally, store timer in list of pending events. */
+ list_add_tail(&timer->entry, &g_pending_events);
+}
+/**
+ * del_timer - deactive a timer.
+ * @timer: the timer to be deactivated
+ *
+ * del_timer() deactivates a timer - this works on both active and inactive
+ * timers.
+ *
+ * The function returns whether it has deactivated a pending timer or not.
+ * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
+ * active timer returns 1.)
+ */
+int del_timer(struct timer_list *timer)
+{
+ int retval;
+
+ if (timer->entry.next == 0)
+ return 0;
+ if (timer->base != 0) {
+ lib_event_cancel(timer->base);
+ retval = 1;
+ } else
+ retval = 0;
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ }
+ return retval;
+}
+
+/* ////////////////////// */
+
+void init_timer_deferrable_key(struct timer_list *timer,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * From lwn.net:
+ * Timers which are initialized in this fashion will be
+ * recognized as deferrable by the kernel. They will not
+ * be considered when the kernel makes its "when should
+ * the next timer interrupt be?" decision. When the system
+ * is busy these timers will fire at the scheduled time. When
+ * things are idle, instead, they will simply wait until
+ * something more important wakes up the processor.
+ *
+ * Note: Our implementation of deferrable timers uses
+ * non-deferrable timers for simplicity.
+ */
+ init_timer_key(timer, 0, name, key);
+}
+/**
+ * add_timer_on - start a timer on a particular CPU
+ * @timer: the timer to be added
+ * @cpu: the CPU to start it on
+ *
+ * This is not very scalable on SMP. Double adds are not possible.
+ */
+void add_timer_on(struct timer_list *timer, int cpu)
+{
+ /* we ignore the cpu: we have only one. */
+ add_timer(timer);
+}
+/**
+ * mod_timer - modify a timer's timeout
+ * @timer: the timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer() is a more efficient way to update the expire field of an
+ * active timer (if the timer is inactive it will be activated)
+ *
+ * mod_timer(timer, expires) is equivalent to:
+ *
+ * del_timer(timer); timer->expires = expires; add_timer(timer);
+ *
+ * Note that if there are multiple unserialized concurrent users of the
+ * same timer, then mod_timer() is the only safe way to modify the timeout,
+ * since add_timer() cannot modify an already running timer.
+ *
+ * The function returns whether it has modified a pending timer or not.
+ * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
+ * active timer returns 1.)
+ */
+int mod_timer(struct timer_list *timer, unsigned long expires)
+{
+ int ret;
+
+ /* common optimization stolen from kernel */
+ if (timer_pending(timer) && timer->expires == expires)
+ return 1;
+
+ ret = del_timer(timer);
+ timer->expires = expires;
+ add_timer(timer);
+ return ret;
+}
+/**
+ * mod_timer_pending - modify a pending timer's timeout
+ * @timer: the pending timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer_pending() is the same for pending timers as mod_timer(),
+ * but will not re-activate and modify already deleted timers.
+ *
+ * It is useful for unserialized use of timers.
+ */
+int mod_timer_pending(struct timer_list *timer, unsigned long expires)
+{
+ if (timer_pending(timer))
+ return 0;
+ return mod_timer(timer, expires);
+}
+
+int mod_timer_pinned(struct timer_list *timer, unsigned long expires)
+{
+ if (timer->expires == expires && timer_pending(timer))
+ return 1;
+
+ return mod_timer(timer, expires);
+}
--
2.1.0
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sched.c | 406 +++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/softirq.c | 108 ++++++++++++++
arch/lib/tasklet.c | 76 ++++++++++
arch/lib/workqueue.c | 242 ++++++++++++++++++++++++++++++
4 files changed, 832 insertions(+)
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/workqueue.c
diff --git a/arch/lib/sched.c b/arch/lib/sched.c
new file mode 100644
index 0000000..98a568a
--- /dev/null
+++ b/arch/lib/sched.c
@@ -0,0 +1,406 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/nsproxy.h>
+#include <linux/hash.h>
+#include <net/net_namespace.h>
+#include "lib.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+/**
+ called by wait_event macro:
+ - prepare_to_wait
+ - schedule
+ - finish_wait
+ */
+
+struct SimTask *lib_task_create(void *private, unsigned long pid)
+{
+ struct SimTask *task = lib_malloc(sizeof(struct SimTask));
+ struct cred *cred;
+ struct nsproxy *ns;
+ struct user_struct *user;
+ struct thread_info *info;
+ struct pid *kpid;
+
+ if (!task)
+ return NULL;
+ memset(task, 0, sizeof(struct SimTask));
+ cred = lib_malloc(sizeof(struct cred));
+ if (!cred)
+ return NULL;
+ /* XXX: we could optimize away this allocation by sharing it
+ for all tasks */
+ ns = lib_malloc(sizeof(struct nsproxy));
+ if (!ns)
+ return NULL;
+ user = lib_malloc(sizeof(struct user_struct));
+ if (!user)
+ return NULL;
+ info = alloc_thread_info(&task->kernel_task);
+ if (!info)
+ return NULL;
+ kpid = lib_malloc(sizeof(struct pid));
+ if (!kpid)
+ return NULL;
+ kpid->numbers[0].nr = pid;
+ cred->fsuid = make_kuid(current_user_ns(), 0);
+ cred->fsgid = make_kgid(current_user_ns(), 0);
+ cred->user = user;
+ atomic_set(&cred->usage, 1);
+ info->task = &task->kernel_task;
+ info->preempt_count = 0;
+ info->flags = 0;
+ atomic_set(&ns->count, 1);
+ ns->uts_ns = 0;
+ ns->ipc_ns = 0;
+ ns->mnt_ns = 0;
+ ns->pid_ns_for_children = 0;
+ ns->net_ns = &init_net;
+ task->kernel_task.cred = cred;
+ task->kernel_task.pid = pid;
+ task->kernel_task.pids[PIDTYPE_PID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_PGID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_SID].pid = kpid;
+ task->kernel_task.nsproxy = ns;
+ task->kernel_task.stack = info;
+ /* this is a hack. */
+ task->kernel_task.group_leader = &task->kernel_task;
+ task->private = private;
+ return task;
+}
+void lib_task_destroy(struct SimTask *task)
+{
+ lib_free((void *)task->kernel_task.nsproxy);
+ lib_free((void *)task->kernel_task.cred);
+ lib_free((void *)task->kernel_task.cred->user);
+ free_thread_info(task->kernel_task.stack);
+ lib_free(task);
+}
+void *lib_task_get_private(struct SimTask *task)
+{
+ return task->private;
+}
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+ struct SimTask *task = lib_task_start((void (*)(void *))fn, arg);
+
+ return task->kernel_task.pid;
+}
+
+struct task_struct *get_current(void)
+{
+ struct SimTask *lib_task = lib_task_current();
+
+ return &lib_task->kernel_task;
+}
+
+struct thread_info *current_thread_info(void)
+{
+ return task_thread_info(get_current());
+}
+struct thread_info *alloc_thread_info(struct task_struct *task)
+{
+ return lib_malloc(sizeof(struct thread_info));
+}
+void free_thread_info(struct thread_info *ti)
+{
+ lib_free(ti);
+}
+
+
+void __put_task_struct(struct task_struct *t)
+{
+ lib_free(t);
+}
+
+void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ list_add(&wait->task_list, &q->task_list);
+}
+void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait->task_list, &q->task_list);
+}
+void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ if (wait->task_list.prev != LIST_POISON2)
+ list_del(&wait->task_list);
+}
+void
+prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ if (list_empty(&wait->task_list))
+ list_add_tail(&wait->task_list, &q->task_list);
+ set_current_state(state);
+}
+void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue(q, wait);
+ set_current_state(state);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ set_current_state(TASK_RUNNING);
+ if (!list_empty(&wait->task_list))
+ list_del_init(&wait->task_list);
+}
+int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync,
+ void *key)
+{
+ int ret = default_wake_function(wait, mode, sync, key);
+
+ if (ret && (wait->task_list.prev != LIST_POISON2))
+ list_del_init(&wait->task_list);
+
+ return ret;
+}
+
+int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ wait->flags |= WQ_FLAG_WOKEN;
+ return default_wake_function(wait, mode, sync, key);
+}
+
+void __init_waitqueue_head(wait_queue_head_t *q, const char *name,
+ struct lock_class_key *k)
+{
+ INIT_LIST_HEAD(&q->task_list);
+}
+/**
+ * wait_for_completion: - waits for completion of a task
+ * @x: holds the state of this particular completion
+ *
+ * This waits to be signaled for completion of a specific task. It is NOT
+ * interruptible and there is no timeout.
+ *
+ * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
+ * and interrupt capability. Also see complete().
+ */
+void wait_for_completion(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+}
+unsigned long wait_for_completion_timeout(struct completion *x,
+ unsigned long timeout)
+{
+ if (!x->done) {
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ wait.flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait.task_list, &x->wait.task_list);
+ do
+ timeout = schedule_timeout(timeout);
+ while (!x->done && timeout);
+ if (wait.task_list.prev != LIST_POISON2)
+ list_del(&wait.task_list);
+
+ if (!x->done)
+ return timeout;
+ }
+ x->done--;
+ return timeout ? : 1;
+}
+
+/**
+ * __wake_up - wake up threads blocked on a waitqueue.
+ * @q: the waitqueue
+ * @mode: which threads
+ * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ * @key: is directly passed to the wakeup function
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
+ */
+void __wake_up(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ wait_queue_t *curr, *next;
+
+ list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
+ unsigned flags = curr->flags;
+
+ if (curr->func(curr, mode, 0, key) &&
+ (flags & WQ_FLAG_EXCLUSIVE) &&
+ !--nr_exclusive)
+ break;
+ }
+}
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ __wake_up(q, mode, nr_exclusive, key);
+}
+int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
+ void *key)
+{
+ struct task_struct *task = (struct task_struct *)curr->private;
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+__sched int bit_wait(struct wait_bit_key *word)
+{
+ if (signal_pending_state(current->state, current))
+ return 1;
+ schedule();
+ return 0;
+}
+int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
+{
+ struct wait_bit_key *key = arg;
+ struct wait_bit_queue *wait_bit
+ = container_of(wait, struct wait_bit_queue, wait);
+
+ if (wait_bit->key.flags != key->flags ||
+ wait_bit->key.bit_nr != key->bit_nr ||
+ test_bit(key->bit_nr, key->flags))
+ return 0;
+ else
+ return autoremove_wake_function(wait, mode, sync, key);
+}
+void __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
+{
+ struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
+ if (waitqueue_active(wq))
+ __wake_up(wq, TASK_NORMAL, 1, &key);
+}
+void wake_up_bit(void *word, int bit)
+{
+ /* FIXME */
+ return;
+ __wake_up_bit(bit_waitqueue(word, bit), word, bit);
+}
+wait_queue_head_t *bit_waitqueue(void *word, int bit)
+{
+ const int shift = BITS_PER_LONG == 32 ? 5 : 6;
+ const struct zone *zone = page_zone(virt_to_page(word));
+ unsigned long val = (unsigned long)word << shift | bit;
+
+ return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
+}
+
+
+void schedule(void)
+{
+ lib_task_wait();
+}
+
+static void trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+
+signed long schedule_timeout(signed long timeout)
+{
+ u64 ns;
+ struct SimTask *self;
+
+ if (timeout == MAX_SCHEDULE_TIMEOUT) {
+ lib_task_wait();
+ return MAX_SCHEDULE_TIMEOUT;
+ }
+ lib_assert(timeout >= 0);
+ ns = ((__u64)timeout) * (1000000000 / HZ);
+ self = lib_task_current();
+ lib_event_schedule_ns(ns, &trampoline, self);
+ lib_task_wait();
+ /* we know that we are always perfectly on time. */
+ return 0;
+}
+
+signed long schedule_timeout_uninterruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+signed long schedule_timeout_interruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+
+void yield(void)
+{
+ lib_task_yield();
+}
+
+void complete_all(struct completion *x)
+{
+ x->done += UINT_MAX / 2;
+ __wake_up(&x->wait, TASK_NORMAL, 0, 0);
+}
+void complete(struct completion *x)
+{
+ x->done++;
+ __wake_up(&x->wait, TASK_NORMAL, 1, 0);
+}
+
+long wait_for_completion_interruptible_timeout(
+ struct completion *x, unsigned long timeout)
+{
+ return wait_for_completion_timeout(x, timeout);
+}
+int wait_for_completion_interruptible(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+ return 0;
+}
+int wake_up_process(struct task_struct *tsk)
+{
+ struct SimTask *lib_task =
+ container_of(tsk, struct SimTask, kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+int _cond_resched(void)
+{
+ /* we never schedule to decrease latency. */
+ return 0;
+}
+int idle_cpu(int cpu)
+{
+ /* we are never idle: we call this from rcutiny.c and the answer */
+ /* does not matter, really. */
+ return 0;
+}
+
+unsigned long long __attribute__((weak)) sched_clock(void)
+{
+ return (unsigned long long)(jiffies - INITIAL_JIFFIES)
+ * (NSEC_PER_SEC / HZ);
+}
+
+u64 local_clock(void)
+{
+ return sched_clock();
+}
+
+void __sched schedule_preempt_disabled(void)
+{
+}
+
+void resched_cpu(int cpu)
+{
+ rcu_sched_qs();
+}
diff --git a/arch/lib/softirq.c b/arch/lib/softirq.c
new file mode 100644
index 0000000..3f6363a
--- /dev/null
+++ b/arch/lib/softirq.c
@@ -0,0 +1,108 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim-init.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+
+static struct softirq_action softirq_vec[NR_SOFTIRQS];
+static struct SimTask *g_softirq_task = 0;
+static int g_n_raises = 0;
+
+void lib_softirq_wakeup(void)
+{
+ g_n_raises++;
+ lib_task_wakeup(g_softirq_task);
+}
+
+static void softirq_task_function(void *context)
+{
+ while (true) {
+ do_softirq();
+ g_n_raises--;
+ if (g_n_raises == 0 || local_softirq_pending() == 0) {
+ g_n_raises = 0;
+ lib_task_wait();
+ }
+ }
+}
+
+static void ensure_task_created(void)
+{
+ if (g_softirq_task != 0)
+ return;
+ g_softirq_task = lib_task_start(&softirq_task_function, 0);
+}
+
+void open_softirq(int nr, void (*action)(struct softirq_action *))
+{
+ ensure_task_created();
+ softirq_vec[nr].action = action;
+}
+#define MAX_SOFTIRQ_RESTART 10
+
+void do_softirq(void)
+{
+ __u32 pending;
+ int max_restart = MAX_SOFTIRQ_RESTART;
+ struct softirq_action *h;
+
+ pending = local_softirq_pending();
+
+restart:
+ /* Reset the pending bitmask before enabling irqs */
+ set_softirq_pending(0);
+
+ local_irq_enable();
+
+ h = softirq_vec;
+
+ do {
+ if (pending & 1)
+ h->action(h);
+ h++;
+ pending >>= 1;
+ } while (pending);
+
+ local_irq_disable();
+
+ pending = local_softirq_pending();
+ if (pending && --max_restart)
+ goto restart;
+}
+void raise_softirq_irqoff(unsigned int nr)
+{
+ __raise_softirq_irqoff(nr);
+
+ lib_softirq_wakeup();
+}
+void __raise_softirq_irqoff(unsigned int nr)
+{
+ /* trace_softirq_raise(nr); */
+ or_softirq_pending(1UL << nr);
+}
+int __cond_resched_softirq(void)
+{
+ /* tell the caller that we did not need to re-schedule. */
+ return 0;
+}
+void raise_softirq(unsigned int nr)
+{
+ /* copy/paste from kernel/softirq.c */
+ unsigned long flags;
+
+ local_irq_save(flags);
+ raise_softirq_irqoff(nr);
+ local_irq_restore(flags);
+}
+
+void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
+{
+}
diff --git a/arch/lib/tasklet.c b/arch/lib/tasklet.c
new file mode 100644
index 0000000..6cc68f4
--- /dev/null
+++ b/arch/lib/tasklet.c
@@ -0,0 +1,76 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void tasklet_init(struct tasklet_struct *t,
+ void (*func)(unsigned long), unsigned long data)
+{
+ t->next = NULL;
+ t->state = 0;
+ atomic_set(&t->count, 0);
+ t->func = func;
+ t->data = data;
+}
+
+void tasklet_kill(struct tasklet_struct *t)
+{
+ /* theoretically, called from user context */
+ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
+ do
+ lib_task_yield();
+ while (test_bit(TASKLET_STATE_SCHED, &t->state));
+ }
+ clear_bit(TASKLET_STATE_SCHED, &t->state);
+}
+struct tasklet_struct *g_sched_events = NULL;
+static void run_tasklet_softirq(struct softirq_action *h)
+{
+ /* while (!list_empty (&g_sched_events)) */
+ /* { */
+ struct tasklet_struct *tasklet = g_sched_events;
+
+ if (atomic_read(&tasklet->count) == 0) {
+ /* this tasklet is enabled so, we run it. */
+ test_and_clear_bit(TASKLET_STATE_SCHED, &tasklet->state);
+ tasklet->func(tasklet->data);
+ }
+ /* } */
+}
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TASKLET_SOFTIRQ, run_tasklet_softirq);
+}
+static void trampoline(void *context)
+{
+ ensure_softirq_opened();
+ struct tasklet_struct *tasklet = context;
+ /* allow the tasklet to re-schedule itself */
+ lib_assert(tasklet->next != 0);
+ tasklet->next = 0;
+ g_sched_events = tasklet;
+ raise_softirq(TASKLET_SOFTIRQ);
+}
+void __tasklet_schedule(struct tasklet_struct *t)
+{
+ void *event;
+
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ event = lib_event_schedule_ns(0, &trampoline, t);
+ t->next = event;
+}
diff --git a/arch/lib/workqueue.c b/arch/lib/workqueue.c
new file mode 100644
index 0000000..bd0e9c5
--- /dev/null
+++ b/arch/lib/workqueue.c
@@ -0,0 +1,242 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+/* copy from kernel/workqueue.c */
+typedef unsigned long mayday_mask_t;
+struct workqueue_struct {
+ unsigned int flags; /* W: WQ_* flags */
+ union {
+ struct cpu_workqueue_struct __percpu *pcpu;
+ struct cpu_workqueue_struct *single;
+ unsigned long v;
+ } cpu_wq; /* I: cwq's */
+ struct list_head list; /* W: list of all workqueues */
+
+ struct mutex flush_mutex; /* protects wq flushing */
+ int work_color; /* F: current work color */
+ int flush_color; /* F: current flush color */
+ atomic_t nr_cwqs_to_flush; /* flush in progress */
+ struct wq_flusher *first_flusher; /* F: first flusher */
+ struct list_head flusher_queue; /* F: flush waiters */
+ struct list_head flusher_overflow; /* F: flush overflow list */
+
+ mayday_mask_t mayday_mask; /* cpus requesting rescue */
+ struct worker *rescuer; /* I: rescue worker */
+
+ int nr_drainers; /* W: drain in progress */
+ int saved_max_active; /* W: saved cwq max_active */
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map lockdep_map;
+#endif
+ char name[]; /* I: workqueue name */
+};
+
+struct wq_barrier {
+ struct SimTask *waiter;
+ struct workqueue_struct wq;
+};
+
+static void
+workqueue_function(void *context)
+{
+ struct workqueue_struct *wq = context;
+
+ while (true) {
+ lib_task_wait();
+ while (!list_empty(&wq->list)) {
+ struct work_struct *work =
+ list_first_entry(&wq->list, struct work_struct,
+ entry);
+ work_func_t f = work->func;
+
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ f(work);
+ }
+ }
+ }
+}
+
+static struct SimTask *workqueue_task(struct workqueue_struct *wq)
+{
+ struct wq_barrier *barr = container_of(wq, struct wq_barrier, wq);
+
+ if (barr->waiter == 0)
+ barr->waiter = lib_task_start(&workqueue_function, wq);
+ return barr->waiter;
+}
+
+static int flush_entry(struct workqueue_struct *wq, struct list_head *prev)
+{
+ int active = 0;
+
+ if (!list_empty(&wq->list)) {
+ active = 1;
+ lib_task_wakeup(workqueue_task(wq));
+ /* XXX: should wait for completion? but this will block
+ and init won't return.. */
+ /* lib_task_wait (); */
+ }
+
+ return active;
+}
+
+void delayed_work_timer_fn(unsigned long data)
+{
+ struct delayed_work *dwork = (struct delayed_work *)data;
+ struct work_struct *work = &dwork->work;
+
+ list_add_tail(&work->entry, &dwork->wq->list);
+ lib_task_wakeup(workqueue_task(dwork->wq));
+}
+
+bool queue_work_on(int cpu, struct workqueue_struct *wq,
+ struct work_struct *work)
+{
+ int ret = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ list_add_tail(&work->entry, &wq->list);
+ lib_task_wakeup(workqueue_task(wq));
+ ret = 1;
+ }
+ return ret;
+}
+
+void flush_scheduled_work(void)
+{
+ flush_entry(system_wq, system_wq->list.prev);
+}
+bool flush_work(struct work_struct *work)
+{
+ return flush_entry(system_wq, &work->entry);
+}
+void flush_workqueue(struct workqueue_struct *wq)
+{
+ flush_entry(wq, wq->list.prev);
+}
+bool cancel_work_sync(struct work_struct *work)
+{
+ int retval = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)))
+ /* work was not yet queued */
+ return 0;
+ if (!list_empty(&work->entry)) {
+ /* work was queued. now unqueued. */
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ retval = 1;
+ }
+ }
+ return retval;
+}
+bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ int ret = 0;
+ struct timer_list *timer = &dwork->timer;
+ struct work_struct *work = &dwork->work;
+
+ if (delay == 0)
+ return queue_work(wq, work);
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ lib_assert(!timer_pending(timer));
+ dwork->wq = wq;
+ /* This stores cwq for the moment, for the timer_fn */
+ timer->expires = jiffies + delay;
+ timer->data = (unsigned long)dwork;
+ timer->function = delayed_work_timer_fn;
+ add_timer(timer);
+ ret = 1;
+ }
+ return ret;
+}
+bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ del_timer(&dwork->timer);
+ __clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&dwork->work));
+ return queue_delayed_work(wq, dwork, delay);
+}
+bool cancel_delayed_work(struct delayed_work *dwork)
+{
+ del_timer(&dwork->timer);
+ return cancel_work_sync(&dwork->work);
+}
+
+struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
+ unsigned int flags,
+ int max_active,
+ struct lock_class_key *key,
+ const char *lock_name, ...)
+{
+ va_list args, args1;
+ struct wq_barrier *barr;
+ struct workqueue_struct *wq;
+ size_t namelen;
+
+ /* determine namelen, allocate wq and format name */
+ va_start(args, lock_name);
+ va_copy(args1, args);
+ namelen = vsnprintf(NULL, 0, fmt, args) + 1;
+
+ barr = kzalloc(sizeof(*barr) + namelen, GFP_KERNEL);
+ if (!barr)
+ goto err;
+ barr->waiter = 0;
+ wq = &barr->wq;
+
+ vsnprintf(wq->name, namelen, fmt, args1);
+ va_end(args);
+ va_end(args1);
+
+ max_active = max_active ? : WQ_DFL_ACTIVE;
+ /* init wq */
+ wq->flags = flags;
+ wq->saved_max_active = max_active;
+ mutex_init(&wq->flush_mutex);
+ atomic_set(&wq->nr_cwqs_to_flush, 0);
+ INIT_LIST_HEAD(&wq->flusher_queue);
+ INIT_LIST_HEAD(&wq->flusher_overflow);
+
+ lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
+ INIT_LIST_HEAD(&wq->list);
+
+ /* start waiter task */
+ workqueue_task(wq);
+ return wq;
+err:
+ if (barr)
+ kfree(barr);
+ return NULL;
+}
+
+struct workqueue_struct *system_wq __read_mostly;
+struct workqueue_struct *system_power_efficient_wq __read_mostly;
+/* from linux/workqueue.h */
+#define system_nrt_wq __system_nrt_wq()
+
+static int __init init_workqueues(void)
+{
+ system_wq = alloc_workqueue("events", 0, 0);
+ system_power_efficient_wq = alloc_workqueue("events_power_efficient",
+ WQ_POWER_EFFICIENT, 0);
+ return 0;
+}
+early_initcall(init_workqueues);
--
2.1.0
This interacts with fs/proc_fs.c for sysctl-like interface accessed via
lib_init() API.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sysctl.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 270 insertions(+)
create mode 100644 arch/lib/sysctl.c
diff --git a/arch/lib/sysctl.c b/arch/lib/sysctl.c
new file mode 100644
index 0000000..5f08f9f
--- /dev/null
+++ b/arch/lib/sysctl.c
@@ -0,0 +1,270 @@
+/*
+ * sysctl wrapper for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/mman.h>
+#include <linux/ratelimit.h>
+#include <linux/proc_fs.h>
+#include "sim-assert.h"
+#include "sim-types.h"
+
+int drop_caches_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_writeback_centisecs_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int scan_unevictable_handler(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int sched_rt_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int sysctl_overcommit_memory = OVERCOMMIT_GUESS;
+int sysctl_overcommit_ratio = 50;
+int sysctl_panic_on_oom = 0;
+int sysctl_oom_dump_tasks = 0;
+int sysctl_oom_kill_allocating_task = 0;
+int sysctl_nr_trim_pages = 0;
+int sysctl_drop_caches = 0;
+int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES - 1] = { 32 };
+unsigned int sysctl_sched_child_runs_first = 0;
+unsigned int sysctl_sched_compat_yield = 0;
+unsigned int sysctl_sched_rt_period = 1000000;
+int sysctl_sched_rt_runtime = 950000;
+
+int vm_highmem_is_dirtyable;
+unsigned long vm_dirty_bytes = 0;
+int vm_dirty_ratio = 20;
+int dirty_background_ratio = 10;
+unsigned int dirty_expire_interval = 30 * 100;
+unsigned int dirty_writeback_interval = 5 * 100;
+unsigned long dirty_background_bytes = 0;
+int percpu_pagelist_fraction = 0;
+int panic_timeout = 0;
+int panic_on_oops = 0;
+int printk_delay_msec = 0;
+int panic_on_warn = 0;
+DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
+
+#define RESERVED_PIDS 300
+int pid_max = PID_MAX_DEFAULT;
+int pid_max_min = RESERVED_PIDS + 1;
+int pid_max_max = PID_MAX_LIMIT;
+int min_free_kbytes = 1024;
+int max_threads = 100;
+int laptop_mode = 0;
+
+#define DEFAULT_MESSAGE_LOGLEVEL 4
+#define MINIMUM_CONSOLE_LOGLEVEL 1
+#define DEFAULT_CONSOLE_LOGLEVEL 7
+int console_printk[4] = {
+ DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
+ DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
+ MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
+ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
+};
+
+int print_fatal_signals = 0;
+unsigned int core_pipe_limit = 0;
+int core_uses_pid = 0;
+int vm_swappiness = 60;
+int nr_pdflush_threads = 0;
+unsigned long scan_unevictable_pages = 0;
+int suid_dumpable = 0;
+int page_cluster = 0;
+int block_dump = 0;
+int C_A_D = 0;
+#include <linux/nsproxy.h>
+struct nsproxy init_nsproxy;
+#include <linux/reboot.h>
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
+unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
+
+int pdflush_proc_obsolete(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return nr_pdflush_threads;
+}
+#include <linux/fs.h>
+
+/**
+ * Honestly, I don't understand half of that code.
+ * It was modeled after fs/proc/proc_sysctl.c proc_sys_readdir
+ *
+ * Me either ;) (Hajime, Jan 2013)
+ */
+
+/* from proc_sysctl.c (XXX) */
+extern struct ctl_table_root sysctl_table_root;
+void ctl_table_first_entry(struct ctl_dir *dir,
+ struct ctl_table_header **phead, struct ctl_table **pentry);
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry);
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen);
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir);
+/* for init_net (XXX, should be fixed) */
+#include <net/net_namespace.h>
+
+static void iterate_table_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table *entry;
+
+ for (entry = head->ctl_table; entry->procname; entry++) {
+ bool may_read = (head->ctl_table->mode & MAY_READ);
+ bool may_write = (head->ctl_table->mode & MAY_WRITE);
+ int flags = 0;
+
+ flags |= may_read ? SIM_SYS_FILE_READ : 0;
+ flags |= may_write ? SIM_SYS_FILE_WRITE : 0;
+ iter->report_file(iter, entry->procname, flags,
+ (struct SimSysFile *)entry);
+ }
+}
+
+
+static void iterate_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table_header *h = NULL;
+ struct ctl_table *entry;
+ struct ctl_dir *ctl_dir;
+
+ ctl_dir = container_of(head, struct ctl_dir, header);
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
+ struct ctl_dir *dir;
+ int ret;
+ const char *procname;
+
+ /* copy from sysctl_follow_link () */
+ if (S_ISLNK(entry->mode)) {
+ dir = ctl_table_xlate_dir(&init_net.sysctls, h->parent);
+ if (IS_ERR(dir)) {
+ ret = PTR_ERR(dir);
+ lib_assert(false);
+ } else {
+ procname = entry->procname;
+ h = NULL;
+ entry =
+ ctl_table_find_entry(&h, dir, procname,
+ strlen(procname));
+ ret = -ENOENT;
+ }
+ }
+
+ if (S_ISDIR(entry->mode)) {
+ iter->report_start_dir(iter, entry->procname);
+ iterate_recursive(iter, h);
+ iter->report_end_dir(iter);
+ } else
+ iterate_table_recursive(iter, h);
+ }
+
+}
+
+
+void lib_sys_iterate_files(const struct SimSysIterator *iter)
+{
+ struct ctl_table_header *root =
+ &sysctl_table_root.default_set.dir.header;
+
+ iterate_recursive(iter, root);
+}
+
+int lib_sys_file_read(const struct SimSysFile *file, char *buffer, int size,
+ int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 0, buffer, &result, &ppos);
+ return result;
+}
+int lib_sys_file_write(const struct SimSysFile *file, const char *buffer,
+ int size, int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 1, (char *)buffer, &result, &ppos);
+ return result;
+}
--
2.1.0
These files are used to provide the same function calls so that other
network stack code keeps untouched.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Christoph Paasch <[email protected]>
---
arch/lib/capability.c | 47 +++++++++
arch/lib/filemap.c | 32 ++++++
arch/lib/fs.c | 70 +++++++++++++
arch/lib/glue.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/modules.c | 36 +++++++
arch/lib/pid.c | 29 ++++++
arch/lib/print.c | 56 ++++++++++
arch/lib/proc.c | 34 ++++++
arch/lib/random.c | 53 ++++++++++
arch/lib/sysfs.c | 83 +++++++++++++++
arch/lib/vmscan.c | 26 +++++
11 files changed, 749 insertions(+)
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/vmscan.c
diff --git a/arch/lib/capability.c b/arch/lib/capability.c
new file mode 100644
index 0000000..7054fea
--- /dev/null
+++ b/arch/lib/capability.c
@@ -0,0 +1,47 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "linux/capability.h"
+
+struct sock;
+struct sk_buff;
+
+int file_caps_enabled = 0;
+
+bool capable(int cap)
+{
+ switch (cap) {
+ case CAP_NET_RAW:
+ case CAP_NET_BIND_SERVICE:
+ case CAP_NET_ADMIN:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int cap_netlink_recv(struct sk_buff *skb, int cap)
+{
+ return 0;
+}
+
+int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+ return 0;
+}
+bool ns_capable(struct user_namespace *ns, int cap)
+{
+ return true;
+}
+bool file_ns_capable(const struct file *file, struct user_namespace *ns,
+ int cap)
+{
+ return true;
+}
diff --git a/arch/lib/filemap.c b/arch/lib/filemap.c
new file mode 100644
index 0000000..ce424ff
--- /dev/null
+++ b/arch/lib/filemap.c
@@ -0,0 +1,32 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/fs.h>
+
+
+ssize_t generic_file_aio_read(struct kiocb *a, const struct iovec *b,
+ unsigned long c, loff_t d)
+{
+ lib_assert(false);
+
+ return 0;
+}
+
+int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return -ENOSYS;
+}
+
+ssize_t
+generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+ return 0;
+}
diff --git a/arch/lib/fs.c b/arch/lib/fs.c
new file mode 100644
index 0000000..324e10b
--- /dev/null
+++ b/arch/lib/fs.c
@@ -0,0 +1,70 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <fs/mount.h>
+
+#include "sim-assert.h"
+
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock);
+unsigned int dirtytime_expire_interval;
+
+void __init mnt_init(void)
+{
+}
+
+/* Implementation taken from vfs_kern_mount from linux/namespace.c */
+struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
+{
+ static struct mount local_mnt;
+ static int count = 0;
+ struct mount *mnt = &local_mnt;
+ struct dentry *root = 0;
+
+ /* XXX */
+ if (count != 0) return &local_mnt.mnt;
+ count++;
+
+ memset(mnt, 0, sizeof(struct mount));
+ if (!type)
+ return ERR_PTR(-ENODEV);
+ int flags = MS_KERNMOUNT;
+ char *name = (char *)type->name;
+
+ if (flags & MS_KERNMOUNT)
+ mnt->mnt.mnt_flags = MNT_INTERNAL;
+
+ root = type->mount(type, flags, name, data);
+ if (IS_ERR(root))
+ return ERR_CAST(root);
+
+ mnt->mnt.mnt_root = root;
+ mnt->mnt.mnt_sb = root->d_sb;
+ mnt->mnt_mountpoint = mnt->mnt.mnt_root;
+ mnt->mnt_parent = mnt;
+ /* DCE is monothreaded , so we do not care of lock here */
+ list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
+
+ return &mnt->mnt;
+}
+void inode_wait_for_writeback(struct inode *inode)
+{
+}
+void truncate_inode_pages_final(struct address_space *mapping)
+{
+}
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
+
+unsigned int nr_free_buffer_pages(void)
+{
+ return 1024;
+}
diff --git a/arch/lib/glue.c b/arch/lib/glue.c
new file mode 100644
index 0000000..928040d
--- /dev/null
+++ b/arch/lib/glue.c
@@ -0,0 +1,283 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <linux/types.h> /* loff_t */
+#include <linux/errno.h> /* ESPIPE */
+#include <linux/pagemap.h> /* PAGE_CACHE_SIZE */
+#include <linux/limits.h> /* NAME_MAX */
+#include <linux/statfs.h> /* struct kstatfs */
+#include <linux/bootmem.h> /* HASHDIST_DEFAULT */
+#include <linux/utsname.h>
+#include <linux/binfmts.h>
+#include <linux/init_task.h>
+#include <linux/sched/rt.h>
+#include <linux/backing-dev.h>
+#include <stdarg.h>
+#include "sim-assert.h"
+#include "sim.h"
+#include "lib.h"
+
+
+struct pipe_buffer;
+struct file;
+struct pipe_inode_info;
+struct wait_queue_t;
+struct kernel_param;
+struct super_block;
+struct tvec_base {};
+
+/* defined in sched.c, used in net/sched/em_meta.c */
+unsigned long avenrun[3];
+/* defined in mm/page_alloc.c, used in net/xfrm/xfrm_hash.c */
+int hashdist = HASHDIST_DEFAULT;
+/* defined in mm/page_alloc.c */
+struct pglist_data __refdata contig_page_data;
+/* defined in linux/mmzone.h mm/memory.c */
+struct page *mem_map = 0;
+/* used during boot. */
+struct tvec_base boot_tvec_bases;
+/* used by sysinfo in kernel/timer.c */
+int nr_threads = 0;
+/* not very useful in mm/vmstat.c */
+atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
+
+/* XXX: used in network stack ! */
+unsigned long num_physpages = 0;
+unsigned long totalram_pages = 0;
+
+/* XXX figure out initial value */
+unsigned int interrupt_pending = 0;
+static unsigned long g_irqflags = 0;
+static unsigned long local_irqflags = 0;
+int overflowgid = 0;
+int overflowuid = 0;
+int fs_overflowgid = 0;
+int fs_overflowuid = 0;
+unsigned long sysctl_overcommit_kbytes __read_mostly;
+DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
+static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
+
+struct backing_dev_info noop_backing_dev_info = {
+ .name = "noop",
+ .capabilities = 0,
+};
+
+/* from rt.c */
+int sched_rr_timeslice = RR_TIMESLICE;
+/* from main.c */
+bool initcall_debug;
+bool static_key_initialized __read_mostly = false;
+unsigned long __start_rodata, __end_rodata;
+
+unsigned long arch_local_save_flags(void)
+{
+ return local_irqflags;
+}
+void arch_local_irq_restore(unsigned long flags)
+{
+ local_irqflags = flags;
+}
+
+
+unsigned long long nr_context_switches(void)
+{
+ /* we just need to return >0 to avoid the warning
+ in kernel/rcupdate.c */
+ return 1;
+}
+
+
+long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long start, unsigned long nr_pages,
+ int write, int force, struct page **pages,
+ struct vm_area_struct **vmas)
+{
+ /* in practice, this function is never called. It's linked in because */
+ /* we link in get_user_pages_fast which is included only because it */
+ /* is located in mm/util.c */
+ lib_assert(false);
+ return 0;
+}
+
+
+void dump_stack(void)
+{
+ /* we assert to make sure that we catch whoever calls dump_stack */
+ lib_assert(false);
+}
+
+
+void lib_printf(const char *str, ...)
+{
+ va_list args;
+
+ va_start(args, str);
+ lib_vprintf(str, args);
+ va_end(args);
+}
+
+#include <linux/vmalloc.h>
+#include <linux/kmemleak.h>
+
+static unsigned long __meminitdata nr_kernel_pages = 8192;
+static unsigned long __meminitdata nr_all_pages = 81920;
+/*
+ * allocate a large system hash table from bootmem
+ * - it is assumed that the hash table must contain an exact power-of-2
+ * quantity of entries
+ * - limit is the number of hash buckets, not the total allocation size
+ */
+void *__init alloc_large_system_hash(const char *tablename,
+ unsigned long bucketsize,
+ unsigned long numentries,
+ int scale,
+ int flags,
+ unsigned int *_hash_shift,
+ unsigned int *_hash_mask,
+ unsigned long low_limit,
+ unsigned long high_limit)
+{
+ unsigned long long max = high_limit;
+ unsigned long log2qty, size;
+ void *table = NULL;
+
+ /* allow the kernel cmdline to have a say */
+ if (!numentries) {
+ /* round applicable memory size up to nearest megabyte */
+ numentries = nr_kernel_pages;
+ numentries += (1UL << (20 - PAGE_SHIFT)) - 1;
+ numentries >>= 20 - PAGE_SHIFT;
+ numentries <<= 20 - PAGE_SHIFT;
+
+ /* limit to 1 bucket per 2^scale bytes of low memory */
+ if (scale > PAGE_SHIFT)
+ numentries >>= (scale - PAGE_SHIFT);
+ else
+ numentries <<= (PAGE_SHIFT - scale);
+
+ /* Make sure we've got at least a 0-order allocation.. */
+ if (unlikely(flags & HASH_SMALL)) {
+ /* Makes no sense without HASH_EARLY */
+ WARN_ON(!(flags & HASH_EARLY));
+ if (!(numentries >> *_hash_shift)) {
+ numentries = 1UL << *_hash_shift;
+ BUG_ON(!numentries);
+ }
+ } else if (unlikely((numentries * bucketsize) < PAGE_SIZE))
+ numentries = PAGE_SIZE / bucketsize;
+ }
+ numentries = roundup_pow_of_two(numentries);
+
+ /* limit allocation size to 1/16 total memory by default */
+ if (max == 0) {
+ max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
+ do_div(max, bucketsize);
+ }
+
+ if (numentries > max)
+ numentries = max;
+
+ log2qty = ilog2(numentries);
+
+ do {
+ size = bucketsize << log2qty;
+ if (flags & HASH_EARLY)
+ table = alloc_bootmem_nopanic(size);
+ else if (hashdist)
+ table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
+ else {
+ /*
+ * If bucketsize is not a power-of-two, we may free
+ * some pages at the end of hash table which
+ * alloc_pages_exact() automatically does
+ */
+ if (get_order(size) < MAX_ORDER) {
+ table = alloc_pages_exact(size, GFP_ATOMIC);
+ kmemleak_alloc(table, size, 1, GFP_ATOMIC);
+ }
+ }
+ } while (!table && size > PAGE_SIZE && --log2qty);
+
+ if (!table)
+ panic("Failed to allocate %s hash table\n", tablename);
+
+ pr_info("%s hash table entries: %d (order: %d, %lu bytes)\n",
+ tablename,
+ (1U << log2qty),
+ ilog2(size) - PAGE_SHIFT,
+ size);
+
+ if (_hash_shift)
+ *_hash_shift = log2qty;
+ if (_hash_mask)
+ *_hash_mask = (1 << log2qty) - 1;
+
+ return table;
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ /* This function is called from the ip layer to get information about
+ the amount of memory in the system and make some educated guesses
+ about some default buffer sizes. We pick a value which ensures
+ small buffers. */
+ val->totalram = 0;
+}
+int slab_is_available(void)
+{
+ /* called from kernel/param.c. */
+ return 1;
+}
+
+/* used from kern_ptr_validate from mm/util.c which is never called */
+void *high_memory = 0;
+
+
+
+void async_synchronize_full(void)
+{
+ /* called from drivers/base/ *.c */
+ /* there is nothing to do, really. */
+}
+
+int send_sig(int signal, struct task_struct *task, int x)
+{
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ lib_signal_raised((struct SimTask *)lib_task, signal);
+ /* lib_assert (false); */
+ return 0;
+}
+unsigned long get_taint(void)
+{
+ /* never tainted. */
+ return 0;
+}
+void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
+{
+}
+struct pid *cad_pid = 0;
+
+void add_device_randomness(const void *buf, unsigned int size)
+{
+}
+
+int sched_rr_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ return 0;
+}
+
+void on_each_cpu_mask(const struct cpumask *mask,
+ smp_call_func_t func, void *info, bool wait)
+{
+}
diff --git a/arch/lib/modules.c b/arch/lib/modules.c
new file mode 100644
index 0000000..ca43fdc
--- /dev/null
+++ b/arch/lib/modules.c
@@ -0,0 +1,36 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-assert.h"
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+
+int modules_disabled = 0;
+char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
+
+static struct module_version_attribute g_empty_attr_buffer;
+/* we make the array empty by default because, really, we don't need */
+/* to look at the builtin params */
+const struct kernel_param __start___param[] = {{0}} ;
+const struct kernel_param __stop___param[] = {{0}} ;
+const struct module_version_attribute *__start___modver[] = {
+ &g_empty_attr_buffer};
+const struct module_version_attribute *__stop___modver[] = {
+ &g_empty_attr_buffer};
+
+struct module_attribute module_uevent;
+struct ctl_table usermodehelper_table[] = {};
+
+int __request_module(bool wait, const char *fmt, ...)
+{
+ /* we really should never be trying to load modules that way. */
+ /* lib_assert (false); */
+ return 0;
+}
diff --git a/arch/lib/pid.c b/arch/lib/pid.c
new file mode 100644
index 0000000..00cf7b6
--- /dev/null
+++ b/arch/lib/pid.c
@@ -0,0 +1,29 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/pid.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void put_pid(struct pid *pid)
+{
+}
+pid_t pid_vnr(struct pid *pid)
+{
+ return pid_nr(pid);
+}
+struct task_struct *find_task_by_vpid(pid_t nr)
+{
+ lib_assert(false);
+ return 0;
+}
+struct pid *find_get_pid(int nr)
+{
+ lib_assert(false);
+ return 0;
+}
diff --git a/arch/lib/print.c b/arch/lib/print.c
new file mode 100644
index 0000000..09b1bb5
--- /dev/null
+++ b/arch/lib/print.c
@@ -0,0 +1,56 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <stdarg.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int dmesg_restrict = 1;
+
+/* from lib/vsprintf.c */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+int printk(const char *fmt, ...)
+{
+ va_list args;
+ static char buf[256];
+ int value;
+
+ va_start(args, fmt);
+ value = vsnprintf(buf, 256, printk_skip_level(fmt), args);
+ lib_printf("<%c>%s", printk_get_level(fmt), buf);
+ va_end(args);
+ return value;
+}
+void panic(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+ lib_assert(false);
+}
+
+void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+
+ printk("%s:%d -- ", file, line);
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+}
+
+void warn_slowpath_null(const char *file, int line)
+{
+ printk("%s:%d -- ", file, line);
+}
+
diff --git a/arch/lib/proc.c b/arch/lib/proc.c
new file mode 100644
index 0000000..5507730
--- /dev/null
+++ b/arch/lib/proc.c
@@ -0,0 +1,34 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2014 Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/fs.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <net/net_namespace.h>
+#include "sim-types.h"
+#include "sim-assert.h"
+#include "fs/proc/internal.h" /* XXX */
+
+struct proc_dir_entry;
+static char proc_root_data[sizeof(struct proc_dir_entry) + 4];
+
+static struct proc_dir_entry *proc_root_sim =
+ (struct proc_dir_entry *)proc_root_data;
+
+void lib_proc_net_initialize(void)
+{
+ proc_root_sim->parent = proc_root_sim;
+ strcpy(proc_root_sim->name, "net");
+ proc_root_sim->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ proc_root_sim->subdir = RB_ROOT;
+ init_net.proc_net = proc_root_sim;
+ init_net.proc_net_stat = proc_mkdir("stat", proc_root_sim);
+}
+
diff --git a/arch/lib/random.c b/arch/lib/random.c
new file mode 100644
index 0000000..9fbb8bf
--- /dev/null
+++ b/arch/lib/random.c
@@ -0,0 +1,53 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include <linux/random.h>
+
+u32 random32(void)
+{
+ return lib_random();
+}
+
+void get_random_bytes(void *buf, int nbytes)
+{
+ char *p = (char *)buf;
+ int i;
+
+ for (i = 0; i < nbytes; i++)
+ p[i] = lib_random();
+}
+void srandom32(u32 entropy)
+{
+}
+
+u32 prandom_u32(void)
+{
+ return lib_random();
+}
+void prandom_seed(u32 entropy)
+{
+}
+
+void prandom_bytes(void *buf, size_t bytes)
+{
+ return get_random_bytes(buf, bytes);
+}
+
+#include <linux/sysctl.h>
+
+static int nothing;
+struct ctl_table random_table[] = {
+ {
+ .procname = "nothing",
+ .data = ¬hing,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ }
+};
diff --git a/arch/lib/sysfs.c b/arch/lib/sysfs.c
new file mode 100644
index 0000000..2def2ca
--- /dev/null
+++ b/arch/lib/sysfs.c
@@ -0,0 +1,83 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int sysfs_create_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+ return 0;
+}
+void sysfs_remove_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+}
+int sysfs_create_dir(struct kobject *kobj)
+{
+ return 0;
+}
+int sysfs_create_link(struct kobject *kobj, struct kobject *target,
+ const char *name)
+{
+ return 0;
+}
+int sysfs_move_dir(struct kobject *kobj,
+ struct kobject *new_parent_kobj)
+{
+ return 0;
+}
+void sysfs_remove_dir(struct kobject *kobj)
+{
+}
+void sysfs_remove_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+}
+int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
+{
+ return 0;
+}
+int __must_check sysfs_create_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return 0;
+}
+int sysfs_create_groups(struct kobject *kobj,
+ const struct attribute_group **groups)
+{
+ return 0;
+}
+int sysfs_schedule_callback(struct kobject *kobj,
+ void (*func)(
+ void *), void *data, struct module *owner)
+{
+ return 0;
+}
+void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
+ const char *name)
+{
+}
+void sysfs_exit_ns(enum kobj_ns_type type, const void *tag)
+{
+}
+void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
+{
+}
+int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
+{
+ kobj->sd = lib_malloc(sizeof(struct kernfs_node));
+ return 0;
+}
+int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
+ const void *ns)
+{
+ return 0;
+}
diff --git a/arch/lib/vmscan.c b/arch/lib/vmscan.c
new file mode 100644
index 0000000..3132f66
--- /dev/null
+++ b/arch/lib/vmscan.c
@@ -0,0 +1,26 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/shrinker.h>
+
+/*
+ * Add a shrinker callback to be called from the vm
+ */
+int register_shrinker(struct shrinker *shrinker)
+{
+ return 0;
+}
+
+/*
+ * Remove one
+ */
+void unregister_shrinker(struct shrinker *shrinker)
+{
+}
+
--
2.1.0
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/include/asm/Kbuild | 57 +++++++++++++++++++++++++++++++++++
arch/lib/include/asm/atomic.h | 50 ++++++++++++++++++++++++++++++
arch/lib/include/asm/barrier.h | 8 +++++
arch/lib/include/asm/bitsperlong.h | 12 ++++++++
arch/lib/include/asm/current.h | 7 +++++
arch/lib/include/asm/elf.h | 10 ++++++
arch/lib/include/asm/hardirq.h | 8 +++++
arch/lib/include/asm/page.h | 14 +++++++++
arch/lib/include/asm/pgtable.h | 30 ++++++++++++++++++
arch/lib/include/asm/processor.h | 19 ++++++++++++
arch/lib/include/asm/ptrace.h | 4 +++
arch/lib/include/asm/segment.h | 6 ++++
arch/lib/include/asm/sembuf.h | 4 +++
arch/lib/include/asm/shmbuf.h | 4 +++
arch/lib/include/asm/shmparam.h | 4 +++
arch/lib/include/asm/sigcontext.h | 6 ++++
arch/lib/include/asm/slab.h | 21 +++++++++++++
arch/lib/include/asm/stat.h | 4 +++
arch/lib/include/asm/statfs.h | 4 +++
arch/lib/include/asm/swab.h | 7 +++++
arch/lib/include/asm/thread_info.h | 36 ++++++++++++++++++++++
arch/lib/include/asm/uaccess.h | 14 +++++++++
arch/lib/include/asm/unistd.h | 4 +++
arch/lib/include/uapi/asm/byteorder.h | 6 ++++
24 files changed, 339 insertions(+)
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/slab.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
diff --git a/arch/lib/include/asm/Kbuild b/arch/lib/include/asm/Kbuild
new file mode 100644
index 0000000..c647b1c
--- /dev/null
+++ b/arch/lib/include/asm/Kbuild
@@ -0,0 +1,57 @@
+generic-y += auxvec.h
+generic-y += bitops.h
+generic-y += bug.h
+generic-y += cache.h
+generic-y += cacheflush.h
+generic-y += checksum.h
+generic-y += cputime.h
+generic-y += cmpxchg.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += exec.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += io.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq.h
+generic-y += irqflags.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += linkage.h
+generic-y += local.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += mmu.h
+generic-y += mmu_context.h
+generic-y += module.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += preempt.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += setup.h
+generic-y += signal.h
+generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += string.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += timex.h
+generic-y += tlbflush.h
+generic-y += types.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += unaligned.h
diff --git a/arch/lib/include/asm/atomic.h b/arch/lib/include/asm/atomic.h
new file mode 100644
index 0000000..41a49285
--- /dev/null
+++ b/arch/lib/include/asm/atomic.h
@@ -0,0 +1,50 @@
+#ifndef _ASM_SIM_ATOMIC_H
+#define _ASM_SIM_ATOMIC_H
+
+#include <linux/types.h>
+
+#if !defined(CONFIG_64BIT)
+typedef struct {
+ volatile long long counter;
+} atomic64_t;
+#endif
+
+#define ATOMIC64_INIT(i) { (i) }
+
+#define atomic64_read(v) (*(volatile long *)&(v)->counter)
+void atomic64_add(long i, atomic64_t *v);
+static inline void atomic64_sub(long i, atomic64_t *v)
+{
+ v->counter -= i;
+}
+static inline void atomic64_inc(atomic64_t *v)
+{
+ v->counter++;
+}
+int atomic64_sub_and_test(long i, atomic64_t *v);
+#define atomic64_dec(v) atomic64_sub(1LL, (v))
+int atomic64_dec_and_test(atomic64_t *v);
+int atomic64_inc_and_test(atomic64_t *v);
+int atomic64_add_negative(long i, atomic64_t *v);
+/* long atomic64_add_return(long i, atomic64_t *v); */
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+ v->counter += i;
+ return v->counter;
+}
+static inline void atomic64_set(atomic64_t *v, long i)
+{
+ v->counter = i;
+}
+long atomic64_sub_return(long i, atomic64_t *v);
+long atomic64_inc_return(atomic64_t *v);
+long atomic64_dec_return(atomic64_t *v);
+long atomic64_cmpxchg(atomic64_t *v, long old, long new);
+long atomic64_xchg(atomic64_t *v, long new);
+int atomic64_add_unless(atomic64_t *v, long a, long u);
+int atomic64_inc_is_not_zero(atomic64_t *v);
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+
+#include <asm-generic/atomic.h>
+
+#endif /* _ASM_SIM_ATOMIC_H */
diff --git a/arch/lib/include/asm/barrier.h b/arch/lib/include/asm/barrier.h
new file mode 100644
index 0000000..47adcc6
--- /dev/null
+++ b/arch/lib/include/asm/barrier.h
@@ -0,0 +1,8 @@
+#include <asm-generic/barrier.h>
+
+#undef smp_store_release
+#define smp_store_release(p, v) \
+ do { \
+ smp_mb(); \
+ ACCESS_ONCE(*p) = (v); \
+ } while (0)
diff --git a/arch/lib/include/asm/bitsperlong.h b/arch/lib/include/asm/bitsperlong.h
new file mode 100644
index 0000000..c7592f9
--- /dev/null
+++ b/arch/lib/include/asm/bitsperlong.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_SIM_BITSPERLONG_H
+#define _ASM_SIM_BITSPERLONG_H
+
+#ifdef CONFIG_64BIT
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif /* CONFIG_64BIT */
+
+#define __BITS_PER_LONG BITS_PER_LONG
+
+#endif /* _ASM_SIM_BITSPERLONG_H */
diff --git a/arch/lib/include/asm/current.h b/arch/lib/include/asm/current.h
new file mode 100644
index 0000000..62489cd
--- /dev/null
+++ b/arch/lib/include/asm/current.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_CURRENT_H
+#define _ASM_SIM_CURRENT_H
+
+struct task_struct *get_current(void);
+#define current get_current()
+
+#endif /* _ASM_SIM_CURRENT_H */
diff --git a/arch/lib/include/asm/elf.h b/arch/lib/include/asm/elf.h
new file mode 100644
index 0000000..a7396c9
--- /dev/null
+++ b/arch/lib/include/asm/elf.h
@@ -0,0 +1,10 @@
+#ifndef _ASM_SIM_ELF_H
+#define _ASM_SIM_ELF_H
+
+#if defined(CONFIG_64BIT)
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+
+#endif /* _ASM_SIM_ELF_H */
diff --git a/arch/lib/include/asm/hardirq.h b/arch/lib/include/asm/hardirq.h
new file mode 100644
index 0000000..47d47f9
--- /dev/null
+++ b/arch/lib/include/asm/hardirq.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_SIM_HARDIRQ_H
+#define _ASM_SIM_HARDIRQ_H
+
+extern unsigned int interrupt_pending;
+
+#define local_softirq_pending() (interrupt_pending)
+
+#endif /* _ASM_SIM_HARDIRQ_H */
diff --git a/arch/lib/include/asm/page.h b/arch/lib/include/asm/page.h
new file mode 100644
index 0000000..8c0aa74
--- /dev/null
+++ b/arch/lib/include/asm/page.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_PAGE_H
+#define _ASM_SIM_PAGE_H
+
+typedef struct {} pud_t;
+
+#define THREAD_ORDER 1
+#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+
+#define WANT_PAGE_VIRTUAL 1
+
+#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
+
+#endif /* _ASM_SIM_PAGE_H */
diff --git a/arch/lib/include/asm/pgtable.h b/arch/lib/include/asm/pgtable.h
new file mode 100644
index 0000000..ce599c8
--- /dev/null
+++ b/arch/lib/include/asm/pgtable.h
@@ -0,0 +1,30 @@
+#ifndef _ASM_SIM_PGTABLE_H
+#define _ASM_SIM_PGTABLE_H
+
+#define PAGE_KERNEL ((pgprot_t) {0 })
+
+#define arch_start_context_switch(prev) do {} while (0)
+
+#define kern_addr_valid(addr)(1)
+#define pte_file(pte)(1)
+/* Encode and de-code a swap entry */
+#define __swp_type(x) (((x).val >> 5) & 0x1f)
+#define __swp_offset(x) ((x).val >> 11)
+#define __swp_entry(type, offset) \
+ ((swp_entry_t) {((type) << 5) | ((offset) << 11) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) {pte_val((pte)) })
+#define __swp_entry_to_pte(x) ((pte_t) {(x).val })
+#define pmd_page(pmd) (struct page *)(pmd_val(pmd) & PAGE_MASK)
+#define pgtable_cache_init() do { } while (0)
+
+static inline int pte_swp_soft_dirty(pte_t pte)
+{
+ return 0;
+}
+
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+ return pte;
+}
+
+#endif /* _ASM_SIM_PGTABLE_H */
diff --git a/arch/lib/include/asm/processor.h b/arch/lib/include/asm/processor.h
new file mode 100644
index 0000000..b673ee0
--- /dev/null
+++ b/arch/lib/include/asm/processor.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_SIM_PROCESSOR_H
+#define _ASM_SIM_PROCESSOR_H
+
+struct thread_struct {};
+
+#define cpu_relax()
+#define cpu_relax_lowlatency() cpu_relax()
+#define KSTK_ESP(tsk) (0)
+
+void *current_text_addr(void);
+
+#define TASK_SIZE ((~(long)0))
+
+#define thread_saved_pc(x) (unsigned long)0
+#define task_pt_regs(t) NULL
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+#endif /* _ASM_SIM_PROCESSOR_H */
diff --git a/arch/lib/include/asm/ptrace.h b/arch/lib/include/asm/ptrace.h
new file mode 100644
index 0000000..ddd9708
--- /dev/null
+++ b/arch/lib/include/asm/ptrace.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_PTRACE_H
+#define _ASM_SIM_PTRACE_H
+
+#endif /* _ASM_SIM_PTRACE_H */
diff --git a/arch/lib/include/asm/segment.h b/arch/lib/include/asm/segment.h
new file mode 100644
index 0000000..e056922
--- /dev/null
+++ b/arch/lib/include/asm/segment.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SEGMENT_H
+#define _ASM_SIM_SEGMENT_H
+
+typedef struct { int seg; } mm_segment_t;
+
+#endif /* _ASM_SIM_SEGMENT_H */
diff --git a/arch/lib/include/asm/sembuf.h b/arch/lib/include/asm/sembuf.h
new file mode 100644
index 0000000..d64927b
--- /dev/null
+++ b/arch/lib/include/asm/sembuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SEMBUF_H
+#define _ASM_SIM_SEMBUF_H
+
+#endif /* _ASM_SIM_SEMBUF_H */
diff --git a/arch/lib/include/asm/shmbuf.h b/arch/lib/include/asm/shmbuf.h
new file mode 100644
index 0000000..42d0a71
--- /dev/null
+++ b/arch/lib/include/asm/shmbuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMBUF_H
+#define _ASM_SIM_SHMBUF_H
+
+#endif /* _ASM_SIM_SHMBUF_H */
diff --git a/arch/lib/include/asm/shmparam.h b/arch/lib/include/asm/shmparam.h
new file mode 100644
index 0000000..3410f1b
--- /dev/null
+++ b/arch/lib/include/asm/shmparam.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMPARAM_H
+#define _ASM_SIM_SHMPARAM_H
+
+#endif /* _ASM_SIM_SHMPARAM_H */
diff --git a/arch/lib/include/asm/sigcontext.h b/arch/lib/include/asm/sigcontext.h
new file mode 100644
index 0000000..230b4b5
--- /dev/null
+++ b/arch/lib/include/asm/sigcontext.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SIGCONTEXT_H
+#define _ASM_SIM_SIGCONTEXT_H
+
+struct sigcontext {};
+
+#endif /* _ASM_SIM_SIGCONTEXT_H */
diff --git a/arch/lib/include/asm/slab.h b/arch/lib/include/asm/slab.h
new file mode 100644
index 0000000..a3f5d19
--- /dev/null
+++ b/arch/lib/include/asm/slab.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_SIM_SLAB_H
+#define _ASM_SIM_SLAB_H
+
+
+struct kmem_cache {
+ unsigned int object_size;
+ const char *name;
+ size_t size;
+ size_t align;
+ unsigned long flags;
+ void (*ctor)(void *);
+};
+
+void *__kmalloc(size_t size, gfp_t flags);
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+static __always_inline void *kmalloc(size_t size, gfp_t flags)
+{
+ return __kmalloc(size, flags);
+}
+
+#endif /* _ASM_SIM_SLAB_H */
diff --git a/arch/lib/include/asm/stat.h b/arch/lib/include/asm/stat.h
new file mode 100644
index 0000000..80fa2cb
--- /dev/null
+++ b/arch/lib/include/asm/stat.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STAT_H
+#define _ASM_SIM_STAT_H
+
+#endif /* _ASM_SIM_STAT_H */
diff --git a/arch/lib/include/asm/statfs.h b/arch/lib/include/asm/statfs.h
new file mode 100644
index 0000000..881ce51
--- /dev/null
+++ b/arch/lib/include/asm/statfs.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STATFS_H
+#define _ASM_SIM_STATFS_H
+
+#endif /* _ASM_SIM_STATFS_H */
diff --git a/arch/lib/include/asm/swab.h b/arch/lib/include/asm/swab.h
new file mode 100644
index 0000000..d81376a
--- /dev/null
+++ b/arch/lib/include/asm/swab.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_SWAB_H
+#define _ASM_SIM_SWAB_H
+
+#include <linux/types.h>
+
+
+#endif /* _ASM_SIM_SWAB_H */
diff --git a/arch/lib/include/asm/thread_info.h b/arch/lib/include/asm/thread_info.h
new file mode 100644
index 0000000..ec316c6
--- /dev/null
+++ b/arch/lib/include/asm/thread_info.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_SIM_THREAD_INFO_H
+#define _ASM_SIM_THREAD_INFO_H
+
+#define TIF_NEED_RESCHED 1
+#define TIF_SIGPENDING 2
+#define TIF_MEMDIE 5
+
+struct thread_info {
+ __u32 flags;
+ int preempt_count;
+ struct task_struct *task;
+ struct restart_block restart_block;
+};
+
+struct thread_info *current_thread_info(void);
+struct thread_info *alloc_thread_info(struct task_struct *task);
+void free_thread_info(struct thread_info *ti);
+
+#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+}
+static inline void clear_restore_sigmask(void)
+{
+}
+static inline bool test_restore_sigmask(void)
+{
+ return true;
+}
+static inline bool test_and_clear_restore_sigmask(void)
+{
+ return true;
+}
+
+#endif /* _ASM_SIM_THREAD_INFO_H */
diff --git a/arch/lib/include/asm/uaccess.h b/arch/lib/include/asm/uaccess.h
new file mode 100644
index 0000000..74f973b
--- /dev/null
+++ b/arch/lib/include/asm/uaccess.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_UACCESS_H
+#define _ASM_SIM_UACCESS_H
+
+#define KERNEL_DS ((mm_segment_t) {0 })
+#define USER_DS ((mm_segment_t) {0 })
+#define get_fs() KERNEL_DS
+#define get_ds() USER_DS
+#define set_fs(x) do {} while ((x.seg) != (x.seg))
+
+#define __access_ok(addr, size) (1)
+
+#include <asm-generic/uaccess.h>
+
+#endif /* _ASM_SIM_UACCESS_H */
diff --git a/arch/lib/include/asm/unistd.h b/arch/lib/include/asm/unistd.h
new file mode 100644
index 0000000..6b482b4
--- /dev/null
+++ b/arch/lib/include/asm/unistd.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_UNISTD_H
+#define _ASM_SIM_UNISTD_H
+
+#endif /* _ASM_SIM_UNISTD_H */
diff --git a/arch/lib/include/uapi/asm/byteorder.h b/arch/lib/include/uapi/asm/byteorder.h
new file mode 100644
index 0000000..b13a7a8
--- /dev/null
+++ b/arch/lib/include/uapi/asm/byteorder.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_BYTEORDER_H
+#define _ASM_X86_BYTEORDER_H
+
+#include <linux/byteorder/little_endian.h>
+
+#endif /* _ASM_X86_BYTEORDER_H */
--
2.1.0
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 8 +
arch/lib/Kconfig | 121 +++++++
arch/lib/Makefile | 251 +++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/generate-linker-script.py | 50 +++
arch/lib/processor.mk | 7 +
9 files changed, 1288 insertions(+)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/defconfig
create mode 100755 arch/lib/generate-linker-script.py
create mode 100644 arch/lib/processor.mk
diff --git a/Documentation/virtual/libos-howto.txt b/Documentation/virtual/libos-howto.txt
new file mode 100644
index 0000000..fbf7946
--- /dev/null
+++ b/Documentation/virtual/libos-howto.txt
@@ -0,0 +1,144 @@
+Library operating system (libos) version of Linux
+=================================================
+
+* Overview
+
+New hardware independent architecture 'arch/lib', configured by
+CONFIG_LIB gives you two features.
+
+- network stack in userspace (NUSE)
+ NUSE will give you a personalized network stack for each application
+ without replacing host operating system.
+
+- network simulator integration, which is called Direct Code Execution (DCE)
+ DCE will give us a network simulation environment with Linux network stack
+ to investigate the detail behavior protocol implementation with a flexible
+ network configuration. This is also useful for the testing environment.
+
+(- more abstracted implementation of underlying platform will be a future
+ direction (e.g., rump hypercall))
+
+In both features, Linux kernel network stack is running on top of
+userspace application with a linked or dynamically loaded library.
+
+They have their own, isolated network stack from host operating system
+so they are configured different IP addresses as other virtualization
+methods do.
+
+
+* How different with others ?
+
+- User-mode Linux (UML)
+
+UML is a way to execute Linux kernel code as a userspace
+application. It is completely isolated from host kernel but can host
+arbitrary userspace applications on top of UML.
+
+- namespace / container
+
+Container technologies with namespace brings a process-level isolation
+to host multiple network entities but shares the kernel among
+processes, which prevents to introduce new features implemented in
+kernel space.
+
+
+* How to build it ?
+
+configuration of arch/lib follows a standard configuration of kernel.
+
+ make defconfig ARCH=lib
+
+or
+
+ make menuconfig ARCH=lib
+
+then you can build a set of libraries for libos.
+
+ make library ARCH=lib
+
+This will give you a shared library file liblinux-$(KERNELVERSION).so
+in the top directory.
+
+* Hello world
+
+you may first need to configure a configuration file, named
+'nuse.conf' so that the library version of network stack can know what
+kind of IP configuration should be used. There is an example file
+at arch/lib/nuse.conf.sample: you may copy and modify it for your purpose.
+
+ sudo NUSECONF=nuse.conf ./nuse ping http://www.google.com
+
+
+
+* Example use cases
+- regression test with Direct Code Execution (DCE)
+
+'make test' by DCE gives a test platform for networking code, with the
+help of network simulator facilities like link delay/bandwidth/drop
+configurations, large network topology with userspace routing protocol
+daemons, etc.
+
+An interesting feature is the determinism of any test executions. A
+test script always gives same results in every execution if there is
+no modification on test target code.
+
+For the first step, you need to obtain network simulator
+environment. 'make testbin' does all the stuff for the preparation.
+
+% make testbin -C tools/testing/libos
+
+Then, you can 'make test' for your code.
+
+% make test ARCH=lib
+
+ PASS: TestSuite netlink-socket
+ PASS: TestSuite process-manager
+ PASS: TestSuite dce-cradle
+ PASS: TestSuite dce-mptcp
+ PASS: TestSuite dce-umip
+ PASS: TestSuite dce-quagga
+ PASS: Example dce-tcp-simple
+ PASS: Example dce-udp-simple
+
+
+- userspace network stack (NUSE)
+
+an application can use its own network stack, distinct from host network stack
+in order to personalize any network feature to the application specific one.
+The 'nuse' wrapper script, based on LD_PRELOAD technique, carefully replaces
+socket API and redirects system calls to the network stack library, provided by
+this framework.
+
+the network stack can be used with any kind of raw-socket like
+technologies such as Intel DPDK, netmap, etc.
+
+
+
+* Files / External Repository
+
+The kernel source tree (i.e., arch/lib) only contains a shared part of
+applications (NUSE/DCE). Pure userspace part is managed at a different
+repository, called Linux-libos-tools: it is automatically downloaded
+during make library.
+
+ https://github.com/libos-nuse/linux-libos-tools
+
+
+* More information
+- [email protected] (LibOS in general and NUSE related questions)
+- [email protected] (ns-3 related questions)
+- articles, slides
+ Experimentation Tools for Networking Research (Lacage, 2010)
+ http://cutebugs.net/files/thesis.pdf
+ Direct code execution: revisiting library OS architecture for reproducible
+ network experiments (Tazaki et al., 2013)
+ http://dx.doi.org/10.1145/2535372.2535374
+ Library Operating System with Mainline Linux Network Stack (Tazaki et al., 2015)
+ https://www.netdev01.org/docs/netdev01-tazaki-libos.pdf (slides)
+
+
+* Authors
+ Mathieu Lacage <[email protected]>
+ Hajime Tazaki <[email protected]>
+ Frederic Urbani <[email protected]>
+ Ryo Nakamura <[email protected]>
diff --git a/MAINTAINERS b/MAINTAINERS
index 3589d67..ae88290 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5699,6 +5699,15 @@ M: Sasha Levin <[email protected]>
S: Maintained
F: tools/lib/lockdep/
+LIBRARY OS (LIBOS)
+M: Hajime Tazaki <[email protected]>
+L: [email protected]
+W: http://libos-nuse.github.io/
+S: Maintained
+F: Documentation/virtual/libos-howto.txt
+F: arch/lib/
+F: tools/testing/libos/
+
LINUX FOR IBM pSERIES (RS/6000)
M: Paul Mackerras <[email protected]>
W: http://www.ibm.com/linux/ltc/projects/ppc
diff --git a/arch/lib/.gitignore b/arch/lib/.gitignore
new file mode 100644
index 0000000..9f48573
--- /dev/null
+++ b/arch/lib/.gitignore
@@ -0,0 +1,8 @@
+linker.lds
+autoconf.h
+objs.mk
+timeconst.h
+hz.bc
+crc32table.h
+*.d
+tools
diff --git a/arch/lib/Kconfig b/arch/lib/Kconfig
new file mode 100644
index 0000000..eb7dede
--- /dev/null
+++ b/arch/lib/Kconfig
@@ -0,0 +1,121 @@
+menuconfig LIB
+ bool "LibOS-specific options"
+ def_bool n
+ select PROC_FS
+ select PROC_SYSCTL
+ select SYSCTL
+ select SYSFS
+ help
+ The 'lib' architecture is a library (user-mode) version of
+ the linux kernel that includes only its network stack and is
+ used within the userspace application, and ns-3 simulator.
+ For more information, about ns-3, see http://www.nsnam.org.
+
+config EXPERIMENTAL
+ def_bool y
+
+config MMU
+ def_bool n
+config FPU
+ def_bool n
+config SMP
+ def_bool n
+
+config ARCH
+ string
+ option env="ARCH"
+
+config KTIME_SCALAR
+ def_bool y
+
+config MODULES
+ def_bool y
+ option modules
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+config PRINTK
+ def_bool y
+
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+config GENERIC_FIND_NEXT_BIT
+ def_bool y
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+config NO_HZ
+ def_bool y
+
+config BASE_FULL
+ def_bool n
+
+config SELECT_MEMORY_MODEL
+ def_bool n
+
+config FLAT_NODE_MEM_MAP
+ def_bool n
+
+config PAGEFLAGS_EXTENDED
+ def_bool n
+
+config VIRT_TO_BUS
+ def_bool n
+
+config HAS_DMA
+ def_bool n
+
+config HZ
+ int
+ default 250
+
+config TINY_RCU
+ def_bool y
+
+config HZ_250
+ def_bool y
+
+config BASE_SMALL
+ int
+ default 1
+
+config SPLIT_PTLOCK_CPUS
+ int
+ default 1
+
+config FLATMEM
+ def_bool y
+
+config SYSCTL
+ def_bool y
+
+config PROC_FS
+ def_bool y
+
+config SYSFS
+ def_bool y
+
+config PROC_SYSCTL
+ def_bool y
+
+config NETDEVICES
+ def_bool y
+
+source "net/Kconfig"
+
+source "drivers/base/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+
diff --git a/arch/lib/Makefile b/arch/lib/Makefile
new file mode 100644
index 0000000..624c2ef
--- /dev/null
+++ b/arch/lib/Makefile
@@ -0,0 +1,251 @@
+ARCH_DIR := arch/lib
+SRCDIR=$(dir $(firstword $(MAKEFILE_LIST)))
+DCE_TESTDIR=$(srctree)/tools/testing/libos/
+KBUILD_KCONFIG := arch/$(ARCH)/Kconfig
+
+CC = gcc
+GCCVERSIONGTEQ48 := $(shell expr `gcc -dumpversion` \>= 4.8)
+ifeq "$(GCCVERSIONGTEQ48)" "1"
+ NO_TREE_LOOP_OPT += -fno-tree-loop-distribute-patterns
+endif
+
+
+-include $(ARCH_DIR)/objs.mk
+-include $(srctree)/.config
+include $(srctree)/scripts/Kbuild.include
+include $(ARCH_DIR)/processor.mk
+
+# targets
+LIBOS_TOOLS=$(ARCH_DIR)/tools
+LIBOS_GIT_REPO=git://github.com/libos-nuse/linux-libos-tools
+KERNEL_LIB=liblinux-$(KERNELVERSION).so
+
+ALL_OBJS=$(OBJS) $(KERNEL_LIB) $(modules) $(all-obj-for-clean)
+
+# auto generated files
+AUTOGENS=$(CRC32TABLE) $(COMPILE_H) $(BOUNDS_H) $(ARCH_DIR)/timeconst.h $(ARCH_DIR)/linker.lds
+COMPILE_H=$(srctree)/include/generated/compile.h
+BOUNDS_H=$(srctree)/include/generated/bounds.h
+
+# from lib/Makefile
+CRC32TABLE = $(ARCH_DIR)/crc32table.h
+hostprogs-y := $(srctree)/lib/gen_crc32table
+clean-files := crc32table.h
+
+# sources and objects
+LIB_SRC=\
+lib.c lib-device.c lib-socket.c random.c softirq.c time.c \
+timer.c hrtimer.c sched.c workqueue.c \
+print.c slab.c tasklet.c tasklet-hrtimer.c \
+glue.c fs.c sysctl.c proc.c sysfs.c \
+capability.c pid.c modules.c filemap.c vmscan.c
+
+LIB_OBJ=$(addprefix $(ARCH_DIR)/,$(addsuffix .o,$(basename $(LIB_SRC))))
+LIB_DEPS=$(addprefix $(ARCH_DIR)/.,$(addsuffix .o.cmd,$(basename $(LIB_SRC))))
+-include $(LIB_DEPS)
+
+DEPENDS=$(addprefix $(ARCH_DIR)/.,\
+ $(addsuffix .d,$(basename $(LIB_SRC)))\
+ )
+
+# options
+COV?=no
+cov_yes=-fprofile-arcs -ftest-coverage
+cov_no=
+covl_yes=-fprofile-arcs
+covl_no=
+OPT?=yes
+opt_yes=-O3 -fomit-frame-pointer $(NO_TREE_LOOP_OPT)
+opt_no=-O0
+PIC?=yes
+pic_yes=-fpic -DPIC
+pic_no=-mcmodel=large
+PIC_CFLAGS=$(pic_$(PIC))
+
+# flags
+CFLAGS_USPACE= \
+ -Wp,-MD,$(depfile) $(opt_$(OPT)) -g3 -Wall -Wstrict-prototypes -Wno-trigraphs \
+ -fno-inline -fno-strict-aliasing -fno-common \
+ -fno-delete-null-pointer-checks -fno-builtin \
+ -fno-stack-protector -Wno-unused -Wno-pointer-sign \
+ $(PIC_CFLAGS) -D_DEBUG $(cov_$(COV)) -I$(ARCH_DIR)/include
+
+CFLAGS+= \
+ $(CFLAGS_USPACE) -nostdinc -D__KERNEL__ -iwithprefix $(srctree)/include \
+ -DKBUILD_BASENAME=\"clnt\" -DKBUILD_MODNAME=\"nsc\" -DMODVERSIONS \
+ -DEXPORT_SYMTAB \
+ -U__FreeBSD__ -D__linux__=1 -Dlinux=1 -D__linux=1 \
+ -DCONFIG_DEFAULT_HOSTNAME=\"lib\" \
+ -I$(ARCH_DIR)/include/generated/uapi \
+ -I$(ARCH_DIR)/include/generated \
+ -I$(srctree)/include -I$(ARCH_DIR)/include/uapi \
+ -I$(srctree)/include/uapi -I$(srctree)/include/generated/uapi \
+ -include $(srctree)/include/linux/kconfig.h \
+ -I$(ARCH_DIR) -I.
+
+ifeq ($(PROCESSOR_SIZE),64)
+CFLAGS+= -DCONFIG_64BIT
+endif
+
+LDFLAGS += -shared -nodefaultlibs -g3 -Wl,-O1 -Wl,-T$(ARCH_DIR)/linker.lds $(covl_$(COV))
+
+# targets
+
+modules:=
+all-obj-for-clean:=
+
+all: library modules
+
+# note: the directory order below matters to ensure that we match the kernel order
+dirs=kernel/ kernel/time/ kernel/rcu/ kernel/locking/ kernel/bpf/ mm/ fs/ fs/proc/ crypto/ lib/ drivers/base/ drivers/net/ net/ init/
+empty:=
+space:= $(empty) $(empty)
+colon:= :
+comma= ,
+kernel/_to_keep=notifier.o params.o sysctl.o \
+rwsem.o semaphore.o kfifo.o cred.o user.o groups.o ksysfs.o
+kernel/time/_to_keep=time.o
+kernel/rcu_to_keep=rcu/srcu.o rcu/pdate.o rcu/tiny.o
+kernel/locking_to_keep=locking/mutex.o
+kernel/bpf_to_keep=bpf/core.o
+mm/_to_keep=util.o list_lru.o
+crypto/_to_keep=aead.o ahash.o shash.o api.o algapi.o cipher.o compress.o proc.o \
+crc32c_generic.o
+drivers/base/_to_keep=class.o core.o bus.o dd.o driver.o devres.o module.o map.o
+drivers/net/_to_keep=loopback.o
+lib/_to_keep=klist.o kobject.o kref.o hweight.o int_sqrt.o checksum.o \
+find_last_bit.o find_next_bit.o bitmap.o nlattr.o idr.o libcrc32c.o \
+ctype.o string.o kasprintf.o rbtree.o sha1.o textsearch.o vsprintf.o \
+rwsem-spinlock.o scatterlist.o ratelimit.o hexdump.o dec_and_lock.o \
+div64.o dynamic_queue_limits.o md5.o kstrtox.o iovec.o lockref.o crc32.o \
+rhashtable.o iov_iter.o cmdline.o kobject_uevent.o
+fs/_to_keep=read_write.o libfs.o namei.o filesystems.o file.o file_table.o \
+dcache.o inode.o pipe.o char_dev.o splice.o no-block.o seq_file.o super.o \
+fcntl.o coredump.o
+fs/proc/_to_keep=proc_sysctl.o proc_net.o root.o generic.o inode.o
+init/_to_keep=version.o
+
+quiet_cmd_objsmk = OBJS-MK $@
+ cmd_objsmk = \
+ for i in 1; do \
+ $(foreach d,$(dirs), \
+ $(MAKE) -i -s -f $< srcdir=$(srctree)/$(d) \
+ objdir=$(srctree)/$(d) \
+ config=$(srctree)/.config \
+ to_keep=$(subst $(space),$(colon),$($(d)_to_keep)) print;) \
+ done > $@
+
+$(ARCH_DIR)/objs.mk: $(ARCH_DIR)/Makefile.print $(srctree)/.config $(ARCH_DIR)/Makefile
+ +$(call if_changed,objsmk)
+
+quiet_cmd_timeconst = GEN $@
+ cmd_timeconst = echo "hz=$(CONFIG_HZ)" > $(ARCH_DIR)/hz.bc ; \
+ bc $(ARCH_DIR)/hz.bc kernel/time/timeconst.bc > $@
+$(ARCH_DIR)/timeconst.h: $(srctree)/.config
+ $(call if_changed,timeconst)
+
+quiet_cmd_linker = GEN $@
+ cmd_linker = ld -shared --verbose | ./$^ > $@
+$(ARCH_DIR)/linker.lds: $(ARCH_DIR)/generate-linker-script.py
+ $(call if_changed,linker)
+
+quiet_cmd_crc32src = GEN $@
+ cmd_crc32src = $(MAKE) -f $(srctree)/Makefile silentoldconfig ; \
+ cc $^ -o $@
+$(srctree)/lib/gen_crc32table: $(srctree)/lib/gen_crc32table.c
+ $(call if_changed,crc32src)
+
+quiet_cmd_crc32 = GEN $@
+ cmd_crc32 = $< > $@
+
+$(CRC32TABLE): $(srctree)/lib/gen_crc32table
+ $(call if_changed,crc32)
+
+# copied from init/Makefile
+ chk_compile.h = :
+ quiet_chk_compile.h = echo ' CHK $@'
+silent_chk_compile.h = :
+$(COMPILE_H): include/generated/utsrelease.h asm-generic $(version_h)
+ @$($(quiet)chk_compile.h)
+ +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
+ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)"
+
+# crafted from $(srctree)/Kbuild
+quiet_cmd_lib_bounds = GEN $@
+define cmd_lib_bounds
+ (set -e; \
+ echo "#ifndef GENERATED_BOUNDS_H"; \
+ echo "#define GENERATED_BOUNDS_H"; \
+ echo ""; \
+ echo "#define NR_PAGEFLAGS (__NR_PAGEFLAGS)"; \
+ echo "#define MAX_NR_ZONES (__MAX_NR_ZONES)"; \
+ echo ""; \
+ echo "#endif /* GENERATED_BOUNDS_H */") > $@
+endef
+
+$(BOUNDS_H):
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,lib_bounds)
+
+
+KERNEL_BUILTIN=$(addprefix $(srctree)/,$(addsuffix builtin.o,$(dirs)))
+OBJS=$(LIB_OBJ) $(foreach builtin,$(KERNEL_BUILTIN),$(if $($(builtin)),$($(builtin))))
+export OBJS KERNEL_LIB COV covl_yes covl_no
+
+quiet_cmd_cc = CC $@
+ cmd_cc = mkdir -p $(dir $@); \
+ $(CC) $(CFLAGS) -c $< -o $@
+quiet_cmd_linkko = KO $@
+ cmd_linkko = $(CC) -shared -o $@ -nostdlib $^
+quiet_cmd_builtin = BUILTIN $@
+ cmd_builtin = mkdir -p $(dir $(srctree)/$@); rm -f $(srctree)/$@; \
+ if test -n "$($(srctree)/$@)"; then for f in $($(srctree)/$@); \
+ do $(AR) Tcru $@ $$f; done; else $(AR) Tcru $@; fi
+
+%/builtin.o:
+ $(call if_changed,builtin)
+%.ko:%.o
+ $(call if_changed,linkko)
+%.o:%.c
+ $(call if_changed_dep,cc)
+
+library: $(KERNEL_LIB) $(LIBOS_TOOLS)
+modules: $(modules)
+
+$(LIBOS_TOOLS): $(KERNEL_LIB) Makefile FORCE
+ $(Q) if [ ! -d "$@" ]; then \
+ git clone $(LIBOS_GIT_REPO) $@ ;\
+ fi
+ $(Q) $(MAKE) -C $(LIBOS_TOOLS)
+
+install: modules library
+
+install-dir:
+
+$(KERNEL_LIB): $(ARCH_DIR)/objs.mk $(AUTOGENS) $(OBJS)
+ $(call if_changed,linklib)
+
+quiet_cmd_linklib = LIB $@
+ cmd_linklib = $(CC) -Wl,--whole-archive $(OBJS) $(LDFLAGS) -o $@; \
+ ln -s -f $(KERNEL_LIB) liblinux.so
+
+quiet_cmd_clean = CLEAN $@
+ cmd_clean = for f in $(foreach m,$(modules),$($(m))) ; do rm -f $$f 2>/dev/null; done ; \
+ for f in $(ALL_OBJS); do rm -f $$f; done 2>/dev/null ;\
+ rm -rf $(AUTOGENS) $(ARCH_DIR)/objs.mk 2>/dev/null ;\
+ if [ -d $(LIBOS_TOOLS) ]; then $(MAKE) -C $(LIBOS_TOOLS) clean ; fi
+
+archclean:
+ $(call if_changed,clean)
+
+.%.d:%.c $(srctree)/.config
+ $(Q) set -e; $(CC) -MM -MT $(<:.c=.o) $(CFLAGS) $< > $@
+
+deplib: $(DEPENDS)
+ -include $(DEPENDS)
+
+test:
+ $(Q) $(MAKE) -C $(DCE_TESTDIR)/
+
+.PHONY : clean deplib
+
diff --git a/arch/lib/Makefile.print b/arch/lib/Makefile.print
new file mode 100644
index 0000000..40e6db0
--- /dev/null
+++ b/arch/lib/Makefile.print
@@ -0,0 +1,45 @@
+# inherit $(objdir) $(config) $(srcdir) $(to_keep) from command-line
+
+include $(config)
+include $(srcdir)Makefile
+
+# fix minor nits for make version dependencies
+ifeq (3.82,$(firstword $(sort $(MAKE_VERSION) 3.82)))
+ SEPARATOR=
+else
+ SEPARATOR=/
+endif
+
+to_keep_list=$(subst :, ,$(to_keep))
+obj-y += $(lib-y)
+obj-m += $(lib-m)
+subdirs := $(filter %/, $(obj-y) $(obj-m))
+subdirs-y := $(filter %/, $(obj-y))
+subdirs-m := $(filter %/, $(obj-m))
+tmp1-obj-y=$(patsubst %/,%/builtin.o,$(obj-y))
+tmp1-obj-m=$(filter-out $(subdirs-m),$(obj-m))
+tmp2-obj-y=$(foreach m,$(tmp1-obj-y), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp2-obj-m=$(foreach m,$(tmp1-obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp3-obj-y=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-y)),$(tmp2-obj-y))
+tmp3-obj-m=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-m)),$(tmp2-obj-m))
+final-obj-y=$(tmp3-obj-y)
+final-obj-m=$(tmp3-obj-m)
+
+print: $(final-obj-m) $(subdirs)
+ @if test $(if $(final-obj-y),1); then \
+ echo -n $(objdir)builtin.o; echo -n "="; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n $(objdir)builtin.o; echo -n ": "; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n "-include "; echo $(addprefix $(objdir).,$(addsuffix ".cmd", $(final-obj-y))); \
+ echo -n "all-obj-for-clean+="; echo $(addprefix $(objdir),$(final-obj-y)) $(objdir)builtin.o; \
+ fi
+$(final-obj-m):
+ @echo -n "modules+="; echo $(addprefix $(objdir),$(@:.o=.ko))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n ": "
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n "="
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+$(subdirs):
+ @$(MAKE) -s -f $(firstword $(MAKEFILE_LIST)) objdir=$(objdir)$@$(SEPARATOR) config=$(config) srcdir=$(srcdir)$@$(SEPARATOR) to_keep=$(to_keep) print 2>/dev/null
+
+.PHONY : core
+.NOTPARALLEL : print $(subdirs) $(final-obj-m)
diff --git a/arch/lib/defconfig b/arch/lib/defconfig
new file mode 100644
index 0000000..9307e6f
--- /dev/null
+++ b/arch/lib/defconfig
@@ -0,0 +1,653 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux Kernel Configuration
+#
+CONFIG_LIB=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+# CONFIG_SMP is not set
+CONFIG_KTIME_SCALAR=y
+CONFIG_MODULES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_PRINTK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_NO_HZ=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_SELECT_MEMORY_MODEL is not set
+# CONFIG_FLAT_NODE_MEM_MAP is not set
+# CONFIG_PAGEFLAGS_EXTENDED is not set
+# CONFIG_VIRT_TO_BUS is not set
+# CONFIG_HAS_DMA is not set
+CONFIG_HZ=250
+CONFIG_TINY_RCU=y
+CONFIG_HZ_250=y
+CONFIG_BASE_SMALL=1
+CONFIG_SPLIT_PTLOCK_CPUS=1
+CONFIG_FLATMEM=y
+CONFIG_SYSCTL=y
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IP_TUNNEL=y
+CONFIG_NET_IPGRE=y
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_NET_IPVTI is not set
+CONFIG_NET_UDP_TUNNEL=m
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+# CONFIG_GENEVE is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_INET_UDP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+CONFIG_TCP_CONG_HSTCP=y
+CONFIG_TCP_CONG_HYBLA=y
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=y
+CONFIG_TCP_CONG_LP=y
+CONFIG_TCP_CONG_VENO=y
+CONFIG_TCP_CONG_YEAH=y
+CONFIG_TCP_CONG_ILLINOIS=y
+CONFIG_TCP_CONG_DCTCP=y
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_HYBLA is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_VENO is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_DCTCP is not set
+CONFIG_DEFAULT_RENO=y
+CONFIG_DEFAULT_TCP_CONG="reno"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+# CONFIG_IPV6_VTI is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=y
+# CONFIG_IPV6_GRE is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=m
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_ACCT=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_LOG_COMMON=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+CONFIG_NETFILTER_NETLINK_QUEUE_CT=y
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_NF_NAT_PROTO_DCCP=y
+CONFIG_NF_NAT_PROTO_UDPLITE=y
+CONFIG_NF_NAT_PROTO_SCTP=y
+CONFIG_NF_NAT_AMANDA=y
+CONFIG_NF_NAT_FTP=y
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_TFTP is not set
+CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_TABLES=y
+CONFIG_NF_TABLES_INET=y
+CONFIG_NFT_EXTHDR=y
+CONFIG_NFT_META=y
+CONFIG_NFT_CT=y
+CONFIG_NFT_RBTREE=y
+CONFIG_NFT_HASH=y
+CONFIG_NFT_COUNTER=y
+CONFIG_NFT_LOG=y
+CONFIG_NFT_LIMIT=y
+CONFIG_NFT_MASQ=y
+# CONFIG_NFT_REDIR is not set
+CONFIG_NFT_NAT=y
+# CONFIG_NFT_QUEUE is not set
+# CONFIG_NFT_REJECT is not set
+# CONFIG_NFT_REJECT_INET is not set
+# CONFIG_NFT_COMPAT is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+# CONFIG_NETFILTER_XT_SET is not set
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_NAT=y
+CONFIG_NETFILTER_XT_TARGET_NETMAP=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_RATEEST=y
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=y
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+CONFIG_NETFILTER_XT_MATCH_L2TP=m
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+CONFIG_IP_SET=y
+CONFIG_IP_SET_MAX=256
+# CONFIG_IP_SET_BITMAP_IP is not set
+# CONFIG_IP_SET_BITMAP_IPMAC is not set
+# CONFIG_IP_SET_BITMAP_PORT is not set
+# CONFIG_IP_SET_HASH_IP is not set
+# CONFIG_IP_SET_HASH_IPMARK is not set
+# CONFIG_IP_SET_HASH_IPPORT is not set
+# CONFIG_IP_SET_HASH_IPPORTIP is not set
+# CONFIG_IP_SET_HASH_IPPORTNET is not set
+# CONFIG_IP_SET_HASH_MAC is not set
+# CONFIG_IP_SET_HASH_NETPORTNET is not set
+# CONFIG_IP_SET_HASH_NET is not set
+# CONFIG_IP_SET_HASH_NETNET is not set
+# CONFIG_IP_SET_HASH_NETPORT is not set
+# CONFIG_IP_SET_HASH_NETIFACE is not set
+# CONFIG_IP_SET_LIST_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_NF_LOG_ARP is not set
+CONFIG_NF_LOG_IPV4=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_CHAIN_ROUTE_IPV4=y
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NFT_REJECT_IPV4 is not set
+# CONFIG_NF_TABLES_ARP is not set
+# CONFIG_NF_NAT_IPV4 is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_NF_TABLES_IPV6=y
+# CONFIG_NFT_CHAIN_ROUTE_IPV6 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NFT_REJECT_IPV6 is not set
+CONFIG_NF_LOG_IPV6=y
+# CONFIG_NF_NAT_IPV6 is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+
+#
+# DECnet: Netfilter Configuration
+#
+# CONFIG_DECNET_NF_GRABULATOR is not set
+# CONFIG_NF_TABLES_BRIDGE is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_IP_DCCP=y
+CONFIG_INET_DCCP_DIAG=y
+
+#
+# DCCP CCIDs Configuration
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+CONFIG_IP_SCTP=y
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE=y
+# CONFIG_SCTP_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_COOKIE_HMAC_SHA1 is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_L2TP=m
+# CONFIG_L2TP_V3 is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_VLAN_8021Q_MVRP is not set
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_PHONET=m
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_HSR is not set
+# CONFIG_NET_SWITCHDEV is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_GW=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_DEV=m
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_SJA1000=m
+# CONFIG_CAN_SJA1000_ISA is not set
+CONFIG_CAN_SJA1000_PLATFORM=m
+# CONFIG_CAN_C_CAN is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_CC770 is not set
+# CONFIG_CAN_SOFTING is not set
+CONFIG_CAN_DEBUG_DEVICES=y
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+
+#
+# Dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_BT=m
+CONFIG_BT_BREDR=y
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_LE=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+CONFIG_WIMAX=m
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_RFKILL=m
+# CONFIG_NET_9P is not set
+CONFIG_CAIF=m
+CONFIG_CAIF_DEBUG=y
+CONFIG_CAIF_NETDEV=m
+# CONFIG_CAIF_USB is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_MCRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+CONFIG_CRYPTO_CRCT10DIF=m
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_IO=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
diff --git a/arch/lib/generate-linker-script.py b/arch/lib/generate-linker-script.py
new file mode 100755
index 0000000..db3d7f8
--- /dev/null
+++ b/arch/lib/generate-linker-script.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+import re
+
+def linker_script(reading, writing):
+ delim = re.compile('^==')
+ end_of_ro = re.compile('^ *.gcc_except_table[^:]*:[ ]*ONLY_IF_RW')
+ skipping = True
+ for line in reading.readlines():
+ if delim.search (line) is not None:
+ if skipping:
+ skipping = False
+ continue
+ else:
+ skipping = True
+ if skipping:
+ continue
+ m = end_of_ro.search(line)
+ if m is not None:
+ skipping = False
+ initcall = """
+ /* taken from kernel script*/
+ . = ALIGN (CONSTANT (MAXPAGESIZE));
+ .initcall.init : AT(ADDR(.initcall.init)) {
+ __initcall_start = .;
+ *(.initcallearly.init)
+ *(.initcall0.init)
+ *(.initcall0s.init)
+ *(.initcall1.init)
+ *(.initcall1s.init)
+ *(.initcall2.init)
+ *(.initcall2s.init)
+ *(.initcall3.init)
+ *(.initcall3s.init)
+ *(.initcall4.init)
+ *(.initcall4s.init)
+ *(.initcall5.init)
+ *(.initcall5s.init)
+ *(.initcall6.init)
+ *(.initcall6s.init)
+ *(.initcall7.init)
+ *(.initcall7s.init)
+ __initcall_end = .;
+ }
+"""
+ writing.write (initcall)
+ writing.write(line)
+
+import sys
+linker_script (sys.stdin, sys.stdout)
diff --git a/arch/lib/processor.mk b/arch/lib/processor.mk
new file mode 100644
index 0000000..7331528
--- /dev/null
+++ b/arch/lib/processor.mk
@@ -0,0 +1,7 @@
+PROCESSOR=$(shell uname -m)
+PROCESSOR_x86_64=64
+PROCESSOR_i686=32
+PROCESSOR_i586=32
+PROCESSOR_i386=32
+PROCESSOR_i486=32
+PROCESSOR_SIZE=$(PROCESSOR_$(PROCESSOR))
--
2.1.0
These auxiliary files are used for make test ARCH=lib.
Signed-off-by: Hajime Tazaki <[email protected]>
---
tools/testing/libos/.gitignore | 6 +++++
tools/testing/libos/Makefile | 38 +++++++++++++++++++++++++++
tools/testing/libos/README | 15 +++++++++++
tools/testing/libos/bisect.sh | 10 +++++++
tools/testing/libos/dce-test.sh | 23 ++++++++++++++++
tools/testing/libos/nuse-test.sh | 57 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 149 insertions(+)
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
diff --git a/tools/testing/libos/.gitignore b/tools/testing/libos/.gitignore
new file mode 100644
index 0000000..57a74a0
--- /dev/null
+++ b/tools/testing/libos/.gitignore
@@ -0,0 +1,6 @@
+*.pcap
+files-*
+bake
+buildtop
+core
+exitprocs
diff --git a/tools/testing/libos/Makefile b/tools/testing/libos/Makefile
new file mode 100644
index 0000000..3da25429
--- /dev/null
+++ b/tools/testing/libos/Makefile
@@ -0,0 +1,38 @@
+ADD_PARAM?=
+
+all: test
+
+bake:
+ hg clone http://code.nsnam.org/bake
+
+check_pkgs:
+ @./bake/bake.py check | grep Bazaar | grep OK || (echo "bzr is missing" && ./bake/bake.py check)
+ @./bake/bake.py check | grep autoreconf | grep OK || (echo "autotools is missing" && ./bake/bake.py check && exit 1)
+
+testbin: bake check_pkgs
+ @cp ../../../arch/lib/tools/bakeconf-linux.xml bake/bakeconf.xml
+ @mkdir -p buildtop/build/bin_dce
+ cd buildtop ; \
+ ../bake/bake.py configure -e dce-linux-inkernel $(BAKECONF_PARAMS)
+ cd buildtop ; \
+ ../bake/bake.py show --enabledTree | grep -v -E "pygoocanvas|graphviz|python-dev" | grep Missing && (echo "required packages are missing") || echo ""
+ cd buildtop ; \
+ ../bake/bake.py download ; \
+ ../bake/bake.py update ; \
+ ../bake/bake.py build
+
+test:
+ @./dce-test.sh ADD_PARAM=$(ADD_PARAM)
+
+test-valgrind:
+ @./dce-test.sh -g ADD_PARAM=$(ADD_PARAM)
+
+test-fault-injection:
+ @./dce-test.sh -f ADD_PARAM=$(ADD_PARAM)
+
+clean:
+# @rm -rf buildtop
+ @rm -f *.pcap
+ @rm -rf files-*
+ @rm -f exitprocs
+ @rm -f core
diff --git a/tools/testing/libos/README b/tools/testing/libos/README
new file mode 100644
index 0000000..51ac5a5
--- /dev/null
+++ b/tools/testing/libos/README
@@ -0,0 +1,15 @@
+
+- bisect.sh
+a sample script to bisect an issue of network stack code with the help
+of LibOS (and ns-3 network simulator). This was used to detect the issue
+for the following patch.
+
+http://patchwork.ozlabs.org/patch/436351/
+
+- dce-test.sh
+a test script invoked by 'make test ARCH=lib'. The contents of test
+scenario are implemented as test suites of ns-3 network simulator.
+
+- nuse-test.sh
+a simple test script for Network Stack in Userspace (NUSE).
+
diff --git a/tools/testing/libos/bisect.sh b/tools/testing/libos/bisect.sh
new file mode 100755
index 0000000..9377ac3
--- /dev/null
+++ b/tools/testing/libos/bisect.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+git merge origin/nuse --no-commit
+make clean ARCH=lib
+make library ARCH=lib OPT=no
+make test ARCH=lib ADD_PARAM=" -s dce-umip"
+RET=$?
+git reset --hard
+
+exit $RET
diff --git a/tools/testing/libos/dce-test.sh b/tools/testing/libos/dce-test.sh
new file mode 100755
index 0000000..e81e2d8
--- /dev/null
+++ b/tools/testing/libos/dce-test.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+#set -x
+export LD_LOG=symbol-fail
+#VERBOSE="-v"
+VALGRIND=""
+FAULT_INJECTION=""
+
+if [ "$1" = "-g" ] ; then
+ VALGRIND="-g"
+# Not implemneted yet.
+#elif [ "$1" = "-f" ] ; then
+# FAULT_INJECTION="-f"
+fi
+
+# FIXME
+#export NS_ATTRIBUTE_DEFAULT='ns3::DceManagerHelper::LoaderFactory=ns3::\
+#DlmLoaderFactory[];ns3::TaskManager::FiberManagerType=UcontextFiberManager'
+
+cd buildtop/source/ns-3-dce
+LD_LIBRARY_PATH=${srctree} ./test.py -n ${VALGRIND} ${FAULT_INJECTION}\
+ ${VERBOSE} ${ADD_PARAM}
diff --git a/tools/testing/libos/nuse-test.sh b/tools/testing/libos/nuse-test.sh
new file mode 100755
index 0000000..198e7e4
--- /dev/null
+++ b/tools/testing/libos/nuse-test.sh
@@ -0,0 +1,57 @@
+#!/bin/bash -e
+
+LIBOS_TOOLS=arch/lib/tools
+
+IFNAME=`ip route |grep default | awk '{print $5}'`
+GW=`ip route |grep default | awk '{print $3}'`
+#XXX
+IPADDR=`echo $GW | sed -r "s/([0-9]+\.[0-9]+\.[0-9]+\.)([0-9]+)$/\1\`expr \2 + 10\`/"`
+
+# ip route
+# ip address
+# ip link
+
+NUSE_CONF=/tmp/nuse.conf
+
+cat > ${NUSE_CONF} << ENDCONF
+
+interface ${IFNAME}
+ address ${IPADDR}
+ netmask 255.255.255.0
+ macaddr 00:01:01:01:01:02
+ viftype RAW
+
+route
+ network 0.0.0.0
+ netmask 0.0.0.0
+ gateway ${GW}
+
+ENDCONF
+
+cd ${LIBOS_TOOLS}
+sudo NUSECONF=${NUSE_CONF} ./nuse ping 127.0.0.1 -c 2
+
+# rump test
+sudo NUSECONF=${NUSE_CONF} ./nuse sleep 5 &
+
+sleep 2
+PID_SLEEP=`/bin/ls -ltr /tmp/rump-server-nuse.* | tail -1 | awk '{print $9}' | sed -e "s/.*rump-server-nuse\.//g" | sed "s/=//"`
+RUMP_URL=unix:///tmp/rump-server-nuse.$PID_SLEEP
+# ls -ltr /tmp/*
+
+sudo chmod 777 /tmp/rump-server-nuse.$PID_SLEEP
+LD_PRELOAD=./libnuse-hijack.so RUMPHIJACK=socket=all \
+ RUMP_SERVER=$RUMP_URL ip addr show
+
+wait %1
+
+if [ "$1" == "--extended" ] ; then
+sudo NUSECONF=${NUSE_CONF} ./nuse ping ${GW} -c 2
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 2000 -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 8 -u -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse dig http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse host http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse nslookup http://www.google.com
+#sudo NUSECONF=${NUSE_CONF} ./nuse nc http://www.google.com 80
+sudo NUSECONF=${NUSE_CONF} ./nuse wget http://www.google.com -O -
+fi
--
2.1.0
On Fri, 17 Apr 2015, Hajime Tazaki wrote:
> add header includion for CONFIG_LIB to wrap kmalloc and co. This will
> bring malloc(3) based allocator used by arch/lib.
Maybe add another allocator insteadl? SLLB which implements memory
management using malloc()?
Am 17.04.2015 um 14:17 schrieb Christoph Lameter:
> On Fri, 17 Apr 2015, Hajime Tazaki wrote:
>
>> add header includion for CONFIG_LIB to wrap kmalloc and co. This will
>> bring malloc(3) based allocator used by arch/lib.
>
> Maybe add another allocator insteadl? SLLB which implements memory
> management using malloc()?
Yeah, that's a good idea.
Hajime, another question, do you really want a malloc/free backend?
I'm not a mm expert, but does malloc() behave exactly as the kernel
counter parts?
In UML we allocate a big file on the host side, mmap() it and give this mapping
to the kernel as physical memory such that any kernel allocator can work with it.
Thanks,
//richard
Hi Christoph, Richard,
At Fri, 17 Apr 2015 14:44:35 +0200,
Richard Weinberger wrote:
>
> Am 17.04.2015 um 14:17 schrieb Christoph Lameter:
> > On Fri, 17 Apr 2015, Hajime Tazaki wrote:
> >
> >> add header includion for CONFIG_LIB to wrap kmalloc and co. This will
> >> bring malloc(3) based allocator used by arch/lib.
> >
> > Maybe add another allocator insteadl? SLLB which implements memory
> > management using malloc()?
>
> Yeah, that's a good idea.
first, my bad, I should be more precise on the commit message.
the patch with 04/11 patch is used _not_ only malloc(3) but
also any allocator registered by our entry API, lib_init().
for NUSE case, we use malloc(3) but for DCE (ns-3) case, we
use our own allocator, which manages the (virtual) process
running on network simulator.
if these externally configurable memory allocator are point
of interest in Linux kernel, maybe adding another allocator
into mm/ is interesting but I'm not sure. what do you think ?
btw, what does stand for SLLB ? (just curious)
> Hajime, another question, do you really want a malloc/free backend?
> I'm not a mm expert, but does malloc() behave exactly as the kernel
> counter parts?
as stated above, A1) yes, we need our own allocator, and A2)
yes as NUSE proofed, it behaves fine.
> In UML we allocate a big file on the host side, mmap() it and give this mapping
> to the kernel as physical memory such that any kernel allocator can work with it.
libos doesn't virtualize a physical memory but provide
allocator functions returning memory block on a request
instead.
-- Hajime
Am 17.04.2015 um 17:02 schrieb Hajime Tazaki:
>
> Hi Christoph, Richard,
>
> At Fri, 17 Apr 2015 14:44:35 +0200,
> Richard Weinberger wrote:
>>
>> Am 17.04.2015 um 14:17 schrieb Christoph Lameter:
>>> On Fri, 17 Apr 2015, Hajime Tazaki wrote:
>>>
>>>> add header includion for CONFIG_LIB to wrap kmalloc and co. This will
>>>> bring malloc(3) based allocator used by arch/lib.
>>>
>>> Maybe add another allocator insteadl? SLLB which implements memory
>>> management using malloc()?
>>
>> Yeah, that's a good idea.
>
> first, my bad, I should be more precise on the commit message.
>
> the patch with 04/11 patch is used _not_ only malloc(3) but
> also any allocator registered by our entry API, lib_init().
>
> for NUSE case, we use malloc(3) but for DCE (ns-3) case, we
> use our own allocator, which manages the (virtual) process
> running on network simulator.
>
> if these externally configurable memory allocator are point
> of interest in Linux kernel, maybe adding another allocator
> into mm/ is interesting but I'm not sure. what do you think ?
This is the idea behind SLLB.
> btw, what does stand for SLLB ? (just curious)
SLUB is the unqueued SLAB and SLLB is the library SLAB. :D
>> Hajime, another question, do you really want a malloc/free backend?
>> I'm not a mm expert, but does malloc() behave exactly as the kernel
>> counter parts?
>
> as stated above, A1) yes, we need our own allocator, and A2)
> yes as NUSE proofed, it behaves fine.
Okay.
>> In UML we allocate a big file on the host side, mmap() it and give this mapping
>> to the kernel as physical memory such that any kernel allocator can work with it.
>
> libos doesn't virtualize a physical memory but provide
> allocator functions returning memory block on a request
> instead.
Makes sense. I thought maybe it can help you reducing the code
footprint.
Thanks,
//richard
At Fri, 17 Apr 2015 17:08:22 +0200,
Richard Weinberger wrote:
> >>>> add header includion for CONFIG_LIB to wrap kmalloc and co. This will
> >>>> bring malloc(3) based allocator used by arch/lib.
> >>>
> >>> Maybe add another allocator insteadl? SLLB which implements memory
> >>> management using malloc()?
> >>
> >> Yeah, that's a good idea.
> >
> > first, my bad, I should be more precise on the commit message.
> >
> > the patch with 04/11 patch is used _not_ only malloc(3) but
> > also any allocator registered by our entry API, lib_init().
> >
> > for NUSE case, we use malloc(3) but for DCE (ns-3) case, we
> > use our own allocator, which manages the (virtual) process
> > running on network simulator.
> >
> > if these externally configurable memory allocator are point
> > of interest in Linux kernel, maybe adding another allocator
> > into mm/ is interesting but I'm not sure. what do you think ?
>
> This is the idea behind SLLB.
>
> > btw, what does stand for SLLB ? (just curious)
>
> SLUB is the unqueued SLAB and SLLB is the library SLAB. :D
thanks.
I will be back with SLLB and give v3 patches soon.
-- Hajime
On Fri, 17 Apr 2015, Richard Weinberger wrote:
> SLUB is the unqueued SLAB and SLLB is the library SLAB. :D
Good that this convention is now so broadly known that I did not even
have to explain what it meant. But I think you can give it any name you
want. SLLB was just a way to tersely state how this is going to integrate
into the overall scheme of things.
changes from v2:
- Patch 02/11 ("slab: add private memory allocator header for arch/lib")
* add new allocator named SLIB (Library Allocator): Patch 04/11 is integrated
to 02 (commented by Christoph Lameter)
- Overall
* rewrite commit log messages
changes from v1:
- Patch 01/11 ("sysctl: make some functions unstatic to access by arch/lib"):
* add prefix ctl_table_ to newly publiced functions (commented by Joe Perches)
- Patch 08/11 ("lib: other kernel glue layer code"):
* significantly reduce glue codes (stubs) (commented by Richard Weinberger)
- Others
* adapt to linux-4.0.0
* detect make dependency by Kbuild .cmd files
patchset history
-----------------
[v2] : https://lkml.org/lkml/2015/4/17/140
[v1] : https://lkml.org/lkml/2015/3/24/254
This is an introduction of library operating system (LibOS) for Linux.
Our objective is to build the kernel network stack as a shared library
that can be linked to by userspace programs to provide network stack
personalization and testing facilities, and allow researchers to more
easily simulate complex network topologies of linux routers/hosts.
Although the architecture itself can virtualize various things, the
current design only focuses on the network stack. You can benefit
network stack feature such as TCP, UDP, SCTP, DCCP (IPv4 and IPv6),
Mobie IPv6, Multipath TCP (IPv4/IPv6, out-of-tree at the present
moment), and netlink with various userspace applications (quagga,
iproute2, iperf, wget, and thttpd).
== What is LibOS ? ==
The library exposes an entry point as API, which is lib_init(), in
order to connect userspace applications to the (userspace-version)
kernel network stack. The clock source, virtual struct net_device, and
scheduler are provided by caller while kernel resource like system
calls is provided by callee.
Once the LibOS is initialized via the API, userspace applications with
POSIX socket can use the system calls defined in LibOS by replacing
from the original socket-related symbols to the LibOS-specific
one. Then application can benefit the network stack of LibOS without
involving the host network stack.
Currently, there are two users of LibOS: Network Stack in Userspace
(NUSE) and ns-3 network simulatior with Direct Code Execution
(DCE). These codes are managed at an external repository(*1).
== How to use it ? ==
to build the library,
% make {defconfig,menuconfig} ARCH=lib
then, build it.
% make library ARCH=lib
You will see liblinux-$(KERNELVERSION).so in the top directory.
== More information ==
The crucial difference between UML (user-mode linux) and this approach
is that we allow multiple network stack instances to co-exist within a
single process with dlmopen(3) like linking for easy debugging.
These patches are also available on this branch:
git://github.com/libos-nuse/net-next-nuse.git for-asm-upstream-v3
For further information, here is a slideset presented at the last
netdev0.1 conference.
http://www.slideshare.net/hajimetazaki/library-operating-system-for-linux-netdev01
I would appreciate any kind of your feedback regarding to upstream
this feature.
*1 https://github.com/libos-nuse/linux-libos-tools
Hajime Tazaki (10):
sysctl: make some functions unstatic to access by arch/lib
slab: add SLIB (Library memory allocator) for arch/lib
lib: public headers and API implementations for userspace programs
lib: time handling (kernel glue code)
lib: context and scheduling functions (kernel glue code) for libos
lib: sysctl handling (kernel glue code)
lib: other kernel glue layer code
lib: auxially files for auto-generated asm-generic files of libos
lib: libos build scripts and documentation
lib: tools used for test scripts
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 8 +
arch/lib/Kconfig | 124 +++++++
arch/lib/Makefile | 251 +++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/capability.c | 47 +++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/filemap.c | 32 ++
arch/lib/fs.c | 70 ++++
arch/lib/generate-linker-script.py | 50 +++
arch/lib/glue.c | 283 +++++++++++++++
arch/lib/hrtimer.c | 122 +++++++
arch/lib/include/asm/Kbuild | 57 +++
arch/lib/include/asm/atomic.h | 50 +++
arch/lib/include/asm/barrier.h | 8 +
arch/lib/include/asm/bitsperlong.h | 12 +
arch/lib/include/asm/current.h | 7 +
arch/lib/include/asm/elf.h | 10 +
arch/lib/include/asm/hardirq.h | 8 +
arch/lib/include/asm/page.h | 14 +
arch/lib/include/asm/pgtable.h | 30 ++
arch/lib/include/asm/processor.h | 19 +
arch/lib/include/asm/ptrace.h | 4 +
arch/lib/include/asm/segment.h | 6 +
arch/lib/include/asm/sembuf.h | 4 +
arch/lib/include/asm/shmbuf.h | 4 +
arch/lib/include/asm/shmparam.h | 4 +
arch/lib/include/asm/sigcontext.h | 6 +
arch/lib/include/asm/stat.h | 4 +
arch/lib/include/asm/statfs.h | 4 +
arch/lib/include/asm/swab.h | 7 +
arch/lib/include/asm/thread_info.h | 36 ++
arch/lib/include/asm/uaccess.h | 14 +
arch/lib/include/asm/unistd.h | 4 +
arch/lib/include/sim-assert.h | 23 ++
arch/lib/include/sim-init.h | 134 +++++++
arch/lib/include/sim-printf.h | 13 +
arch/lib/include/sim-types.h | 53 +++
arch/lib/include/sim.h | 51 +++
arch/lib/include/uapi/asm/byteorder.h | 6 +
arch/lib/lib-device.c | 187 ++++++++++
arch/lib/lib-socket.c | 410 +++++++++++++++++++++
arch/lib/lib.c | 294 +++++++++++++++
arch/lib/lib.h | 21 ++
arch/lib/modules.c | 36 ++
arch/lib/pid.c | 29 ++
arch/lib/print.c | 56 +++
arch/lib/proc.c | 34 ++
arch/lib/processor.mk | 7 +
arch/lib/random.c | 53 +++
arch/lib/sched.c | 406 +++++++++++++++++++++
arch/lib/softirq.c | 108 ++++++
arch/lib/sysctl.c | 270 ++++++++++++++
arch/lib/sysfs.c | 83 +++++
arch/lib/tasklet-hrtimer.c | 57 +++
arch/lib/tasklet.c | 76 ++++
arch/lib/time.c | 144 ++++++++
arch/lib/timer.c | 238 +++++++++++++
arch/lib/vmscan.c | 26 ++
arch/lib/workqueue.c | 242 +++++++++++++
fs/proc/proc_sysctl.c | 36 +-
include/linux/slab.h | 6 +-
include/linux/slib_def.h | 21 ++
init/Kconfig | 8 +
mm/Makefile | 1 +
mm/slab.h | 4 +
mm/slib.c | 205 +++++++++++
tools/testing/libos/.gitignore | 6 +
tools/testing/libos/Makefile | 38 ++
tools/testing/libos/README | 15 +
tools/testing/libos/bisect.sh | 10 +
tools/testing/libos/dce-test.sh | 23 ++
tools/testing/libos/nuse-test.sh | 57 +++
74 files changed, 5619 insertions(+), 18 deletions(-)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/defconfig
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100755 arch/lib/generate-linker-script.py
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/processor.mk
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/sysctl.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
create mode 100644 arch/lib/vmscan.c
create mode 100644 arch/lib/workqueue.c
create mode 100644 include/linux/slib_def.h
create mode 100644 mm/slib.c
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
--
2.1.0
libos (arch/lib) emulates a sysctl-like interface by a function call of
userspace by enumerating sysctl tree from sysctl_table_root. It requires
to be publicly accessible to this symbol and related functions.
Signed-off-by: Hajime Tazaki <[email protected]>
---
fs/proc/proc_sysctl.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index f92d5dd..56feec7 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -35,7 +35,7 @@ static struct ctl_table root_table[] = {
},
{ }
};
-static struct ctl_table_root sysctl_table_root = {
+struct ctl_table_root sysctl_table_root = {
.default_set.dir.header = {
{{.count = 1,
.nreg = 1,
@@ -77,8 +77,9 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2)
}
/* Called under sysctl_lock */
-static struct ctl_table *find_entry(struct ctl_table_header **phead,
- struct ctl_dir *dir, const char *name, int namelen)
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen)
{
struct ctl_table_header *head;
struct ctl_table *entry;
@@ -300,7 +301,7 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
struct ctl_table *entry;
spin_lock(&sysctl_lock);
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (entry && use_table(head))
*phead = head;
else
@@ -321,7 +322,7 @@ static struct ctl_node *first_usable_entry(struct rb_node *node)
return NULL;
}
-static void first_entry(struct ctl_dir *dir,
+void ctl_table_first_entry(struct ctl_dir *dir,
struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = NULL;
@@ -339,7 +340,7 @@ static void first_entry(struct ctl_dir *dir,
*pentry = entry;
}
-static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = *phead;
struct ctl_table *entry = *pentry;
@@ -670,7 +671,8 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
pos = 2;
- for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
if (!scan(h, entry, &pos, file, ctx)) {
sysctl_head_finish(h);
break;
@@ -828,7 +830,7 @@ static struct ctl_dir *find_subdir(struct ctl_dir *dir,
struct ctl_table_header *head;
struct ctl_table *entry;
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (!entry)
return ERR_PTR(-ENOENT);
if (!S_ISDIR(entry->mode))
@@ -924,13 +926,13 @@ failed:
return subdir;
}
-static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
{
struct ctl_dir *parent;
const char *procname;
if (!dir->header.parent)
return &set->dir;
- parent = xlate_dir(set, dir->header.parent);
+ parent = ctl_table_xlate_dir(set, dir->header.parent);
if (IS_ERR(parent))
return parent;
procname = dir->header.ctl_table[0].procname;
@@ -951,13 +953,13 @@ static int sysctl_follow_link(struct ctl_table_header **phead,
spin_lock(&sysctl_lock);
root = (*pentry)->data;
set = lookup_header_set(root, namespaces);
- dir = xlate_dir(set, (*phead)->parent);
+ dir = ctl_table_xlate_dir(set, (*phead)->parent);
if (IS_ERR(dir))
ret = PTR_ERR(dir);
else {
const char *procname = (*pentry)->procname;
head = NULL;
- entry = find_entry(&head, dir, procname, strlen(procname));
+ entry = ctl_table_find_entry(&head, dir, procname, strlen(procname));
ret = -ENOENT;
if (entry && use_table(head)) {
unuse_table(*phead);
@@ -1069,7 +1071,7 @@ static bool get_links(struct ctl_dir *dir,
/* Are there links available for every entry in table? */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
if (!link)
return false;
if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
@@ -1082,7 +1084,7 @@ static bool get_links(struct ctl_dir *dir,
/* The checks passed. Increase the registration count on the links */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
head->nreg++;
}
return true;
@@ -1098,7 +1100,7 @@ static int insert_links(struct ctl_table_header *head)
if (head->set == root_set)
return 0;
- core_parent = xlate_dir(root_set, head->parent);
+ core_parent = ctl_table_xlate_dir(root_set, head->parent);
if (IS_ERR(core_parent))
return 0;
@@ -1479,7 +1481,7 @@ static void put_links(struct ctl_table_header *header)
if (header->set == root_set)
return;
- core_parent = xlate_dir(root_set, parent);
+ core_parent = ctl_table_xlate_dir(root_set, parent);
if (IS_ERR(core_parent))
return;
@@ -1488,7 +1490,7 @@ static void put_links(struct ctl_table_header *header)
struct ctl_table *link;
const char *name = entry->procname;
- link = find_entry(&link_head, core_parent, name, strlen(name));
+ link = ctl_table_find_entry(&link_head, core_parent, name, strlen(name));
if (link &&
((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
(S_ISLNK(link->mode) && (link->data == root)))) {
--
2.1.0
add SLIB allocator for arch/lib (CONFIG_LIB) to wrap kmalloc and co.
This will bring user's own allocator of libos: malloc(3) etc.
Signed-off-by: Hajime Tazaki <[email protected]>
---
include/linux/slab.h | 6 +-
include/linux/slib_def.h | 21 +++++
init/Kconfig | 8 ++
mm/Makefile | 1 +
mm/slab.h | 4 +
mm/slib.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 244 insertions(+), 1 deletion(-)
create mode 100644 include/linux/slib_def.h
create mode 100644 mm/slib.c
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 9a139b6..b167daa 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -192,7 +192,7 @@ size_t ksize(const void *);
#endif
#endif
-#ifdef CONFIG_SLOB
+#if defined(CONFIG_SLOB) || defined(CONFIG_SLIB)
/*
* SLOB passes all requests larger than one page to the page allocator.
* No kmalloc array is necessary since objects of different sizes can
@@ -350,6 +350,9 @@ kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
}
#endif
+#ifdef CONFIG_SLIB
+#include <linux/slib_def.h>
+#else
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{
unsigned int order = get_order(size);
@@ -428,6 +431,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
}
return __kmalloc(size, flags);
}
+#endif /* CONFIG_SLIB */
/*
* Determine size used for the nth kmalloc cache.
diff --git a/include/linux/slib_def.h b/include/linux/slib_def.h
new file mode 100644
index 0000000..d9fe7d5
--- /dev/null
+++ b/include/linux/slib_def.h
@@ -0,0 +1,21 @@
+#ifndef _LINUX_SLLB_DEF_H
+#define _LINUX_SLLB_DEF_H
+
+
+struct kmem_cache {
+ unsigned int object_size;
+ const char *name;
+ size_t size;
+ size_t align;
+ unsigned long flags;
+ void (*ctor)(void *);
+};
+
+void *__kmalloc(size_t size, gfp_t flags);
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+static __always_inline void *kmalloc(size_t size, gfp_t flags)
+{
+ return __kmalloc(size, flags);
+}
+
+#endif /* _LINUX_SLLB_DEF_H */
diff --git a/init/Kconfig b/init/Kconfig
index 9afb971..8bdee98 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1695,6 +1695,14 @@ config SLOB
allocator. SLOB is generally more space efficient but
does not perform as well on large systems.
+config SLIB
+ bool "SLIB (Library Allocator)"
+ depends on LIB
+ help
+ SLIB replaces the slab allocator with a registered allocator
+ function via lib_init() used by libos (CONFIG_LIB). It usually
+ used malloc(3) or any allocators.
+
endchoice
config SLUB_CPU_PARTIAL
diff --git a/mm/Makefile b/mm/Makefile
index 4bf586e..8c66951 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
obj-$(CONFIG_SLOB) += slob.o
+obj-$(CONFIG_SLIB) += slib.o
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_KSM) += ksm.o
obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
diff --git a/mm/slab.h b/mm/slab.h
index 1cf40054..89c2319 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -37,6 +37,10 @@ struct kmem_cache {
#include <linux/slub_def.h>
#endif
+#ifdef CONFIG_SLIB
+#include <linux/slib_def.h>
+#endif
+
#include <linux/memcontrol.h>
/*
diff --git a/mm/slib.c b/mm/slib.c
new file mode 100644
index 0000000..37596862
--- /dev/null
+++ b/mm/slib.c
@@ -0,0 +1,205 @@
+/*
+ * Library Slab Allocator (SLIB)
+ *
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/page-flags.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/slib_def.h>
+
+/* glues */
+struct kmem_cache *files_cachep;
+
+void kfree(const void *p)
+{
+ unsigned long start;
+
+ if (p == 0)
+ return;
+ start = (unsigned long)p;
+ start -= sizeof(size_t);
+ lib_free((void *)start);
+}
+size_t ksize(const void *p)
+{
+ size_t *psize = (size_t *)p;
+
+ psize--;
+ return *psize;
+}
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ void *p = lib_malloc(size + sizeof(size));
+ unsigned long start;
+
+ if (!p)
+ return NULL;
+
+ if (p != 0 && (flags & __GFP_ZERO))
+ lib_memset(p, 0, size + sizeof(size));
+ lib_memcpy(p, &size, sizeof(size));
+ start = (unsigned long)p;
+ return (void *)(start + sizeof(size));
+}
+
+void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller)
+{
+ return kmalloc(size, flags);
+}
+
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+
+ if (!new_size) {
+ kfree(p);
+ return ZERO_SIZE_PTR;
+ }
+
+ ret = __kmalloc(new_size, flags);
+ if (ret && p != ret)
+ kfree(p);
+
+ return ret;
+}
+
+struct kmem_cache *
+kmem_cache_create(const char *name, size_t size, size_t align,
+ unsigned long flags, void (*ctor)(void *))
+{
+ struct kmem_cache *cache = kmalloc(sizeof(struct kmem_cache), flags);
+
+ if (!cache)
+ return NULL;
+ cache->name = name;
+ cache->size = size;
+ cache->align = align;
+ cache->flags = flags;
+ cache->ctor = ctor;
+ return cache;
+}
+void kmem_cache_destroy(struct kmem_cache *cache)
+{
+ kfree(cache);
+}
+int kmem_cache_shrink(struct kmem_cache *cache)
+{
+ return 1;
+}
+const char *kmem_cache_name(struct kmem_cache *cache)
+{
+ return cache->name;
+}
+void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags)
+{
+ void *p = kmalloc(cache->size, flags);
+
+ if (p == 0)
+ return NULL;
+ if (cache->ctor)
+ (cache->ctor)(p);
+ return p;
+
+}
+void kmem_cache_free(struct kmem_cache *cache, void *p)
+{
+ kfree(p);
+}
+
+struct page *
+__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist, nodemask_t *nodemask)
+{
+ void *p;
+ struct page *page;
+ unsigned long pointer;
+
+ /* typically, called from networking code by alloc_page or */
+ /* directly with an order = 0. */
+ if (order)
+ return NULL;
+ p = lib_malloc(sizeof(struct page) + (1 << PAGE_SHIFT));
+ page = (struct page *)p;
+
+ atomic_set(&page->_count, 1);
+ page->flags = 0;
+ pointer = (unsigned long)page;
+ pointer += sizeof(struct page);
+ page->virtual = (void *)pointer;
+ return page;
+}
+void __free_pages(struct page *page, unsigned int order)
+{
+ /* typically, called from networking code by __free_page */
+ lib_assert(order == 0);
+ lib_free(page);
+}
+
+void put_page(struct page *page)
+{
+ if (atomic_dec_and_test(&page->_count))
+ lib_free(page);
+}
+unsigned long get_zeroed_page(gfp_t gfp_mask)
+{
+ return __get_free_pages(gfp_mask | __GFP_ZERO, 0);
+}
+
+void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
+{
+ return alloc_pages(gfp_mask, get_order(size));
+}
+
+unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
+{
+ int size = (1 << order) * PAGE_SIZE;
+ void *p = kmalloc(size, gfp_mask);
+
+ return (unsigned long)p;
+}
+void free_pages(unsigned long addr, unsigned int order)
+{
+ if (addr != 0)
+ kfree((void *)addr);
+}
+
+void *vmalloc(unsigned long size)
+{
+ return lib_malloc(size);
+}
+void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
+{
+ return kmalloc(size, gfp_mask);
+}
+void vfree(const void *addr)
+{
+ lib_free((void *)addr);
+}
+void *vmalloc_node(unsigned long size, int node)
+{
+ return lib_malloc(size);
+}
+void vmalloc_sync_all(void)
+{
+}
+void *__alloc_percpu(size_t size, size_t align)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+void free_percpu(void __percpu *ptr)
+{
+ kfree(ptr);
+}
+void *__alloc_bootmem_nopanic(unsigned long size,
+ unsigned long align,
+ unsigned long goal)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
--
2.1.0
userspace programs which uses libos access via a public API, lib_init(),
with passed arguments struct SimImported and struct SimExported.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
arch/lib/include/sim-assert.h | 23 +++
arch/lib/include/sim-init.h | 134 ++++++++++++++
arch/lib/include/sim-printf.h | 13 ++
arch/lib/include/sim-types.h | 53 ++++++
arch/lib/include/sim.h | 51 ++++++
arch/lib/lib-device.c | 187 +++++++++++++++++++
arch/lib/lib-socket.c | 410 ++++++++++++++++++++++++++++++++++++++++++
arch/lib/lib.c | 294 ++++++++++++++++++++++++++++++
arch/lib/lib.h | 21 +++
9 files changed, 1186 insertions(+)
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
diff --git a/arch/lib/include/sim-assert.h b/arch/lib/include/sim-assert.h
new file mode 100644
index 0000000..974122c
--- /dev/null
+++ b/arch/lib/include/sim-assert.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_ASSERT_H
+#define SIM_ASSERT_H
+
+#include "sim-printf.h"
+
+#define lib_assert(v) { \
+ while (!(v)) { \
+ lib_printf("Assert failed %s:%u \"" #v "\"\n", \
+ __FILE__, __LINE__); \
+ char *p = 0; \
+ *p = 1; \
+ } \
+ }
+
+
+#endif /* SIM_ASSERT_H */
diff --git a/arch/lib/include/sim-init.h b/arch/lib/include/sim-init.h
new file mode 100644
index 0000000..e871a59
--- /dev/null
+++ b/arch/lib/include/sim-init.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_INIT_H
+#define SIM_INIT_H
+
+#include <linux/socket.h>
+#include "sim-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _IO_FILE;
+typedef struct _IO_FILE FILE;
+
+struct SimExported {
+ struct SimTask *(*task_create)(void *priv, unsigned long pid);
+ void (*task_destroy)(struct SimTask *task);
+ void *(*task_get_private)(struct SimTask *task);
+
+ int (*sock_socket)(int domain, int type, int protocol,
+ struct SimSocket **socket);
+ int (*sock_close)(struct SimSocket *socket);
+ ssize_t (*sock_recvmsg)(struct SimSocket *socket, struct msghdr *msg,
+ int flags);
+ ssize_t (*sock_sendmsg)(struct SimSocket *socket,
+ const struct msghdr *msg, int flags);
+ int (*sock_getsockname)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_getpeername)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_bind)(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen);
+ int (*sock_connect)(struct SimSocket *socket,
+ const struct sockaddr *name, int namelen,
+ int flags);
+ int (*sock_listen)(struct SimSocket *socket, int backlog);
+ int (*sock_shutdown)(struct SimSocket *socket, int how);
+ int (*sock_accept)(struct SimSocket *socket,
+ struct SimSocket **newSocket, int flags);
+ int (*sock_ioctl)(struct SimSocket *socket, int request, char *argp);
+ int (*sock_setsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ const void *optval, int optlen);
+ int (*sock_getsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ void *optval, int *optlen);
+
+ void (*sock_poll)(struct SimSocket *socket, void *ret);
+ void (*sock_pollfreewait)(void *polltable);
+
+ struct SimDevice *(*dev_create)(const char *ifname, void *priv,
+ enum SimDevFlags flags);
+ void (*dev_destroy)(struct SimDevice *dev);
+ void *(*dev_get_private)(struct SimDevice *task);
+ void (*dev_set_address)(struct SimDevice *dev,
+ unsigned char buffer[6]);
+ void (*dev_set_mtu)(struct SimDevice *dev, int mtu);
+ struct SimDevicePacket (*dev_create_packet)(struct SimDevice *dev,
+ int size);
+ void (*dev_rx)(struct SimDevice *dev, struct SimDevicePacket packet);
+
+ void (*sys_iterate_files)(const struct SimSysIterator *iter);
+ int (*sys_file_read)(const struct SimSysFile *file, char *buffer,
+ int size, int offset);
+ int (*sys_file_write)(const struct SimSysFile *file,
+ const char *buffer, int size, int offset);
+};
+
+struct SimImported {
+ int (*vprintf)(struct SimKernel *kernel, const char *str,
+ va_list args);
+ void *(*malloc)(struct SimKernel *kernel, unsigned long size);
+ void (*free)(struct SimKernel *kernel, void *buffer);
+ void *(*memcpy)(struct SimKernel *kernel, void *dst, const void *src,
+ unsigned long size);
+ void *(*memset)(struct SimKernel *kernel, void *dst, char value,
+ unsigned long size);
+ int (*atexit)(struct SimKernel *kernel, void (*function)(void));
+ int (*access)(struct SimKernel *kernel, const char *pathname,
+ int mode);
+ char *(*getenv)(struct SimKernel *kernel, const char *name);
+ int (*mkdir)(struct SimKernel *kernel, const char *pathname,
+ mode_t mode);
+ int (*open)(struct SimKernel *kernel, const char *pathname, int flags);
+ int (*__fxstat)(struct SimKernel *kernel, int ver, int fd, void *buf);
+ int (*fseek)(struct SimKernel *kernel, FILE *stream, long offset,
+ int whence);
+ void (*setbuf)(struct SimKernel *kernel, FILE *stream, char *buf);
+ FILE *(*fdopen)(struct SimKernel *kernel, int fd, const char *mode);
+ long (*ftell)(struct SimKernel *kernel, FILE *stream);
+ int (*fclose)(struct SimKernel *kernel, FILE *fp);
+ size_t (*fread)(struct SimKernel *kernel, void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+ size_t (*fwrite)(struct SimKernel *kernel, const void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+
+ unsigned long (*random)(struct SimKernel *kernel);
+ void *(*event_schedule_ns)(struct SimKernel *kernel, __u64 ns,
+ void (*fn)(void *context), void *context,
+ void (*pre_fn)(void));
+ void (*event_cancel)(struct SimKernel *kernel, void *event);
+ __u64 (*current_ns)(struct SimKernel *kernel);
+
+ struct SimTask *(*task_start)(struct SimKernel *kernel,
+ void (*callback)(void *),
+ void *context);
+ void (*task_wait)(struct SimKernel *kernel);
+ struct SimTask *(*task_current)(struct SimKernel *kernel);
+ int (*task_wakeup)(struct SimKernel *kernel, struct SimTask *task);
+ void (*task_yield)(struct SimKernel *kernel);
+
+ void (*dev_xmit)(struct SimKernel *kernel, struct SimDevice *dev,
+ unsigned char *data, int len);
+ void (*signal_raised)(struct SimKernel *kernel, struct SimTask *task,
+ int sig);
+ void (*poll_event)(int flag, void *context);
+};
+
+typedef void (*SimInit)(struct SimExported *, const struct SimImported *,
+ struct SimKernel *kernel);
+void sim_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_INIT_H */
diff --git a/arch/lib/include/sim-printf.h b/arch/lib/include/sim-printf.h
new file mode 100644
index 0000000..2bf8245
--- /dev/null
+++ b/arch/lib/include/sim-printf.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_PRINTF_H
+#define SIM_PRINTF_H
+
+void lib_printf(const char *str, ...);
+
+#endif /* SIM_PRINTF_H */
diff --git a/arch/lib/include/sim-types.h b/arch/lib/include/sim-types.h
new file mode 100644
index 0000000..d50b99b
--- /dev/null
+++ b/arch/lib/include/sim-types.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_TYPES_H
+#define SIM_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBOS_API_VERSION 2
+
+struct SimTask;
+struct SimDevice;
+struct SimSocket;
+struct SimKernel;
+struct SimSysFile;
+
+enum SimDevFlags {
+ SIM_DEV_NOARP = (1 << 0),
+ SIM_DEV_POINTTOPOINT = (1 << 1),
+ SIM_DEV_MULTICAST = (1 << 2),
+ SIM_DEV_BROADCAST = (1 << 3),
+};
+
+struct SimDevicePacket {
+ void *buffer;
+ void *token;
+};
+
+enum SimSysFileFlags {
+ SIM_SYS_FILE_READ = 1 << 0,
+ SIM_SYS_FILE_WRITE = 1 << 1,
+};
+
+struct SimSysIterator {
+ void (*report_start_dir)(const struct SimSysIterator *iter,
+ const char *dirname);
+ void (*report_end_dir)(const struct SimSysIterator *iter);
+ void (*report_file)(const struct SimSysIterator *iter,
+ const char *filename,
+ int flags, struct SimSysFile *file);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_TYPES_H */
diff --git a/arch/lib/include/sim.h b/arch/lib/include/sim.h
new file mode 100644
index 0000000..b30d7e8
--- /dev/null
+++ b/arch/lib/include/sim.h
@@ -0,0 +1,51 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_H
+#define SIM_H
+
+#include <stdarg.h>
+#include <linux/types.h>
+
+#include "sim-types.h"
+
+/* API called from within linux kernel. Forwards to SimImported. */
+int lib_vprintf(const char *str, va_list args);
+void *lib_malloc(unsigned long size);
+void lib_free(void *buffer);
+void *lib_memcpy(void *dst, const void *src, unsigned long size);
+void *lib_memset(void *dst, char value, unsigned long size);
+unsigned long lib_random(void);
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context),
+ void *context);
+void lib_event_cancel(void *event);
+__u64 lib_current_ns(void);
+
+struct SimTask *lib_task_start(void (*callback) (void *), void *context);
+void lib_task_wait(void);
+void lib_task_yield(void);
+struct SimTask *lib_task_current(void);
+/* returns 1 if task was woken up, 0 if it was already running. */
+int lib_task_wakeup(struct SimTask *task);
+struct SimTask *lib_task_create(void *priv, unsigned long pid);
+void lib_task_destroy(struct SimTask *task);
+void *lib_task_get_private(struct SimTask *task);
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len);
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size);
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet);
+
+void lib_signal_raised(struct SimTask *task, int sig);
+
+void lib_poll_event(int flag, void *context);
+void lib_softirq_wakeup(void);
+void lib_update_jiffies(void);
+void *lib_dev_get_private(struct SimDevice *);
+void lib_proc_net_initialize(void);
+
+#endif /* SIM_H */
diff --git a/arch/lib/lib-device.c b/arch/lib/lib-device.c
new file mode 100644
index 0000000..1efa6460
--- /dev/null
+++ b/arch/lib/lib-device.c
@@ -0,0 +1,187 @@
+/*
+ * virtual net_device feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ethtool.h>
+
+struct SimDevice {
+ struct net_device dev;
+ void *priv;
+};
+
+static netdev_tx_t
+kernel_dev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ int err;
+
+ netif_stop_queue(dev);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ err = skb_checksum_help(skb);
+ if (unlikely(err)) {
+ pr_err("checksum error (%d)\n", err);
+ return 0;
+ }
+ }
+
+ lib_dev_xmit((struct SimDevice *)dev, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static u32 always_on(struct net_device *dev)
+{
+ return 1;
+}
+
+
+static const struct ethtool_ops lib_ethtool_ops = {
+ .get_link = always_on,
+};
+
+static const struct net_device_ops lib_dev_ops = {
+ .ndo_start_xmit = kernel_dev_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static void lib_dev_setup(struct net_device *dev)
+{
+ dev->mtu = (16 * 1024) + 20 + 20 + 12;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_ETHER;
+ dev->flags = 0;
+ /* dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; */
+ dev->features = 0
+ | NETIF_F_HIGHDMA
+ | NETIF_F_NETNS_LOCAL;
+ /* disabled NETIF_F_TSO NETIF_F_SG NETIF_F_FRAGLIST NETIF_F_LLTX */
+ dev->ethtool_ops = &lib_ethtool_ops;
+ dev->header_ops = ð_header_ops;
+ dev->netdev_ops = &lib_dev_ops;
+ dev->destructor = &free_netdev;
+}
+
+
+struct SimDevice *lib_dev_create(const char *ifname, void *priv,
+ enum SimDevFlags flags)
+{
+ int err;
+ struct SimDevice *dev =
+ (struct SimDevice *)alloc_netdev(sizeof(struct SimDevice),
+ ifname, NET_NAME_UNKNOWN,
+ &lib_dev_setup);
+ ether_setup((struct net_device *)dev);
+
+ if (flags & SIM_DEV_NOARP)
+ dev->dev.flags |= IFF_NOARP;
+ if (flags & SIM_DEV_POINTTOPOINT)
+ dev->dev.flags |= IFF_POINTOPOINT;
+ if (flags & SIM_DEV_MULTICAST)
+ dev->dev.flags |= IFF_MULTICAST;
+ if (flags & SIM_DEV_BROADCAST) {
+ dev->dev.flags |= IFF_BROADCAST;
+ memset(dev->dev.broadcast, 0xff, 6);
+ }
+ dev->priv = priv;
+ err = register_netdev(&dev->dev);
+ return dev;
+}
+void lib_dev_destroy(struct SimDevice *dev)
+{
+ unregister_netdev(&dev->dev);
+ /* XXX */
+ free_netdev(&dev->dev);
+}
+void *lib_dev_get_private(struct SimDevice *dev)
+{
+ return dev->priv;
+}
+
+void lib_dev_set_mtu(struct SimDevice *dev, int mtu)
+{
+ /* called by ns-3 to synchronize the kernel mtu with */
+ /* the simulation mtu */
+ dev->dev.mtu = mtu;
+}
+
+static int lib_ndo_change_mtu(struct net_device *dev,
+ int new_mtu)
+{
+ /* called by kernel to change the mtu when the user */
+ /* asks for it. */
+ /* XXX should forward the set call to ns-3 and wait for */
+ /* ns-3 to notify of the change in the function above */
+ /* but I am way too tired to do this now. */
+ return 0;
+}
+
+void lib_dev_set_address(struct SimDevice *dev, unsigned char buffer[6])
+{
+ /* called by ns-3 to synchronize the kernel address with */
+ /* the simulation address. */
+ struct sockaddr sa;
+
+ sa.sa_family = dev->dev.type;
+ lib_memcpy(&sa.sa_data, buffer, 6);
+ dev->dev.netdev_ops->ndo_set_mac_address(&dev->dev, &sa);
+ /* Note that we don't call dev_set_mac_address (&dev->dev, &sa); */
+ /* because this function expects to be called from within */
+ /* the netlink layer so, it expects to hold */
+ /* the netlink lock during the execution of the associated notifiers */
+}
+static int get_hack_size(int size)
+{
+ /* Note: this hack is coming from nsc */
+ /* Bit of a hack... */
+ /* Note that the size allocated here effects the offered window
+ somewhat. I've got this heuristic here to try and match up with
+ what we observe on the emulation network and by looking at the
+ driver code of the eepro100. In both cases we allocate enough
+ space for our packet, which is the important thing. The amount
+ of slack at the end can make linux decide the grow the window
+ differently. This is quite subtle, but the code in question is
+ in the tcp_grow_window function. It checks skb->truesize, which
+ is the size of the skbuff allocated for the incoming data
+ packet -- what we are allocating right now! */
+ if (size < 1200)
+ return size + 36;
+ else if (size <= 1500)
+ return 1536;
+ else
+ return size + 36;
+}
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size)
+{
+ struct SimDevicePacket packet;
+ int len = get_hack_size(size);
+ struct sk_buff *skb = __dev_alloc_skb(len, __GFP_WAIT);
+
+ packet.token = skb;
+ packet.buffer = skb_put(skb, len);
+ return packet;
+}
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet)
+{
+ struct sk_buff *skb = packet.token;
+ struct net_device *dev = &device->dev;
+
+ skb->protocol = eth_type_trans(skb, dev);
+ /* Do the TCP checksum (FIXME: should be configurable) */
+ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ netif_rx(skb);
+}
diff --git a/arch/lib/lib-socket.c b/arch/lib/lib-socket.c
new file mode 100644
index 0000000..d9be5fc
--- /dev/null
+++ b/arch/lib/lib-socket.c
@@ -0,0 +1,410 @@
+/*
+ * socket feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/net.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/inet_connection_sock.h>
+
+struct SimSocket {};
+
+static struct iovec *copy_iovec(const struct iovec *input, int len)
+{
+ int size = sizeof(struct iovec) * len;
+ struct iovec *output = lib_malloc(size);
+
+ if (!output)
+ return NULL;
+ lib_memcpy(output, input, size);
+ return output;
+}
+
+int lib_sock_socket(int domain, int type, int protocol,
+ struct SimSocket **socket)
+{
+ struct socket **kernel_socket = (struct socket **)socket;
+ int flags;
+
+ /* from net/socket.c */
+ flags = type & ~SOCK_TYPE_MASK;
+ if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ return -EINVAL;
+ type &= SOCK_TYPE_MASK;
+
+ int retval = sock_create(domain, type, protocol, kernel_socket);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ struct file *fp = lib_malloc(sizeof(struct file));
+ (*kernel_socket)->file = fp;
+ fp->f_cred = lib_malloc(sizeof(struct cred));
+ return retval;
+}
+int lib_sock_close(struct SimSocket *socket)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+
+ sock_release(kernel_socket);
+ return 0;
+}
+static size_t iov_size(const struct user_msghdr *msg)
+{
+ size_t i;
+ size_t size = 0;
+
+ for (i = 0; i < msg->msg_iovlen; i++)
+ size += msg->msg_iov[i].iov_len;
+ return size;
+}
+ssize_t lib_sock_recvmsg(struct SimSocket *socket,
+ struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct msghdr msg_sys;
+ struct cmsghdr *user_cmsgh = msg->msg_control;
+ size_t user_cmsghlen = msg->msg_controllen;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, READ,
+ msg->msg_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_recvmsg(kernel_socket, &msg_sys, iov_size(msg), flags);
+
+ msg->msg_name = msg_sys.msg_name;
+ msg->msg_namelen = msg_sys.msg_namelen;
+ msg->msg_control = user_cmsgh;
+ msg->msg_controllen = user_cmsghlen - msg_sys.msg_controllen;
+ return retval;
+}
+ssize_t lib_sock_sendmsg(struct SimSocket *socket,
+ const struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct iovec *kernel_iov = copy_iovec(msg->msg_iov, msg->msg_iovlen);
+ struct msghdr msg_sys;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, WRITE,
+ kernel_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_sendmsg(kernel_socket, &msg_sys);
+ lib_free(kernel_iov);
+ return retval;
+}
+int lib_sock_getsockname(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 0);
+
+ return retval;
+}
+int lib_sock_getpeername(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 1);
+
+ return retval;
+}
+int lib_sock_bind(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ int retval =
+ sock->ops->bind(sock, (struct sockaddr *)&address, namelen);
+ return retval;
+}
+int lib_sock_connect(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen, int flags)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ sock->file->f_flags = flags;
+ int retval = sock->ops->connect(sock, (struct sockaddr *)&address,
+ namelen, flags);
+ return retval;
+}
+int lib_sock_listen(struct SimSocket *socket, int backlog)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->listen(sock, backlog);
+
+ return retval;
+}
+int lib_sock_shutdown(struct SimSocket *socket, int how)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->shutdown(sock, how);
+
+ return retval;
+}
+int lib_sock_accept(struct SimSocket *socket, struct SimSocket **new_socket,
+ int flags)
+{
+ struct socket *sock, *newsock;
+ int err;
+
+ sock = (struct socket *)socket;
+
+ /* the fields do not matter here. If we could, */
+ /* we would call sock_alloc but it's not exported. */
+ err = sock_create_lite(0, 0, 0, &newsock);
+ if (err < 0)
+ return err;
+ newsock->type = sock->type;
+ newsock->ops = sock->ops;
+
+ err = sock->ops->accept(sock, newsock, flags);
+ if (err < 0) {
+ sock_release(newsock);
+ return err;
+ }
+ *new_socket = (struct SimSocket *)newsock;
+ return 0;
+}
+int lib_sock_ioctl(struct SimSocket *socket, int request, char *argp)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sock *sk;
+ struct net *net;
+ int err;
+
+ sk = sock->sk;
+ net = sock_net(sk);
+
+ err = sock->ops->ioctl(sock, request, (long)argp);
+
+ /*
+ * If this ioctl is unknown try to hand it down
+ * to the NIC driver.
+ */
+ if (err == -ENOIOCTLCMD)
+ err = dev_ioctl(net, request, argp);
+ return err;
+}
+int lib_sock_setsockopt(struct SimSocket *socket, int level, int optname,
+ const void *optval, int optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ char *coptval = (char *)optval;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_setsockopt(sock, level, optname, coptval, optlen);
+ else
+ err = sock->ops->setsockopt(sock, level, optname, coptval,
+ optlen);
+ return err;
+}
+int lib_sock_getsockopt(struct SimSocket *socket, int level, int optname,
+ void *optval, int *optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_getsockopt(sock, level, optname, optval, optlen);
+ else
+ err =
+ sock->ops->getsockopt(sock, level, optname, optval,
+ optlen);
+ return err;
+}
+
+int lib_sock_canrecv(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct inet_connection_sock *icsk;
+
+ switch (sock->sk->sk_state) {
+ case TCP_CLOSE:
+ if (SOCK_STREAM == sock->sk->sk_type)
+ return 1;
+ case TCP_ESTABLISHED:
+ return sock->sk->sk_receive_queue.qlen > 0;
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV:
+ case TCP_LAST_ACK:
+ case TCP_CLOSING:
+ return 0;
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_TIME_WAIT:
+ case TCP_CLOSE_WAIT:
+ return 1;
+ case TCP_LISTEN:
+ {
+ icsk = inet_csk(sock->sk);
+ return !reqsk_queue_empty(&icsk->icsk_accept_queue);
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+int lib_sock_cansend(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+
+ return sock_writeable(sock->sk);
+}
+
+/**
+ * Struct used to pass pool table context between DCE and Kernel and back from
+ * Kernel to DCE
+ *
+ * When calling sock_poll we provide in ret field the wanted eventmask, and in
+ * the opaque field the DCE poll table
+ *
+ * if a corresponding event occurs later, the PollEvent will be called by kernel
+ * with the DCE poll table in context variable, then we will able to wake up the
+ * thread blocked in poll call.
+ *
+ * Back from sock_poll method the kernel change ret field with the response from
+ * poll return of the corresponding kernel socket, and in opaque field there is
+ * a reference to the kernel poll table we will use this reference to remove us
+ * from the file wait queue when ending the DCE poll call or when ending the DCE
+ * process which is currently polling.
+ *
+ */
+struct poll_table_ref {
+ int ret;
+ void *opaque;
+};
+
+/* Because the poll main loop code is in NS3/DCE we have only on entry
+ in our kernel poll table */
+struct lib_ptable_entry {
+ wait_queue_t wait;
+ wait_queue_head_t *wait_address;
+ int eventMask; /* Poll wanted event mask. */
+ void *opaque; /* Pointeur to DCE poll table */
+};
+
+static int lib_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)wait->private;
+
+ /* Filter only wanted events */
+ if (key && !((unsigned long)key & entry->eventMask))
+ return 0;
+
+ lib_poll_event((unsigned long)key, entry->opaque);
+ return 1;
+}
+
+static void lib_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table *p)
+{
+ struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)
+ lib_malloc(sizeof(struct lib_ptable_entry));
+ struct poll_table_ref *fromDCE = (struct poll_table_ref *)pwq->table;
+
+ if (!entry)
+ return;
+
+ entry->opaque = fromDCE->opaque; /* Copy DCE poll table reference */
+ entry->eventMask = fromDCE->ret; /* Copy poll mask of wanted events. */
+
+ pwq->table = (struct poll_table_page *)entry;
+
+ init_waitqueue_func_entry(&entry->wait, lib_pollwake);
+ entry->wait.private = entry;
+ entry->wait_address = wait_address;
+ add_wait_queue(wait_address, &entry->wait);
+}
+
+void dce_poll_initwait(struct poll_wqueues *pwq)
+{
+ init_poll_funcptr(&pwq->pt, lib_pollwait);
+ pwq->polling_task = current;
+ pwq->triggered = 0;
+ pwq->error = 0;
+ pwq->table = NULL;
+ pwq->inline_index = 0;
+}
+
+/* call poll on socket ... */
+void lib_sock_poll(struct SimSocket *socket, struct poll_table_ref *ret)
+{
+ struct socket *sock = (struct socket *)socket;
+ /* Provide a fake file structure */
+ struct file zero;
+ poll_table *pwait = 0;
+ struct poll_wqueues *ptable = 0;
+
+ lib_memset(&zero, 0, sizeof(struct file));
+
+ if (ret->opaque) {
+ ptable =
+ (struct poll_wqueues *)lib_malloc(sizeof(struct
+ poll_wqueues));
+ if (!ptable)
+ return;
+
+ dce_poll_initwait(ptable);
+
+ pwait = &(ptable->pt);
+ /* Pass the DCE pool table to lib_pollwait function */
+ ptable->table = (struct poll_table_page *)ret;
+ }
+
+ ret->ret = sock->ops->poll(&zero, sock, pwait);
+ /* Pass back the kernel poll table to DCE in order to DCE to */
+ /* remove from wait queue */
+ /* using lib_sock_pollfreewait method below */
+ ret->opaque = ptable;
+}
+
+void lib_sock_pollfreewait(void *polltable)
+{
+ struct poll_wqueues *ptable = (struct poll_wqueues *)polltable;
+
+ if (ptable && ptable->table) {
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)ptable->table;
+ remove_wait_queue(entry->wait_address, &entry->wait);
+ lib_free(entry);
+ }
+ lib_free(ptable);
+}
+
+
+
+
diff --git a/arch/lib/lib.c b/arch/lib/lib.c
new file mode 100644
index 0000000..52d638e
--- /dev/null
+++ b/arch/lib/lib.c
@@ -0,0 +1,294 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/init.h> /* initcall_t */
+#include <linux/kernel.h> /* SYSTEM_BOOTING */
+#include <linux/sched.h> /* struct task_struct */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <drivers/base/base.h>
+#include <linux/idr.h>
+#include <linux/rcupdate.h>
+#include "sim-init.h"
+#include "sim.h"
+
+enum system_states system_state = SYSTEM_BOOTING;
+/* glues */
+struct task_struct init_task;
+
+struct SimImported g_imported;
+
+
+#define RETURN_void(rettype, v) \
+ ({ \
+ (v); \
+ lib_softirq_wakeup(); \
+ })
+
+#define RETURN_nvoid(rettype, v) \
+ ({ \
+ rettype x = (v); \
+ lib_softirq_wakeup(); \
+ x; \
+ })
+
+#define FORWARDER1(name, type, rettype, t0) \
+ extern rettype name(t0); \
+ static rettype name ## _forwarder(t0 v0) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0))); \
+ }
+
+#define FORWARDER2(name, type, rettype, t0, t1) \
+ extern rettype name(t0, t1); \
+ static rettype name ## _forwarder(t0 v0, t1 v1) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1))); \
+ }
+#define FORWARDER3(name, type, rettype, t0, t1, t2) \
+ extern rettype name(t0, t1, t2); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER5(name, type, rettype, t0, t1, t2, t3, t4) \
+ extern rettype name(t0, t1, t2, t3, t4); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3, t4 v4) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3, v4))); \
+ }
+
+FORWARDER3(lib_dev_create, nvoid, struct SimDevice *, const char *, void *,
+ enum SimDevFlags);
+FORWARDER1(lib_dev_destroy, void, void, struct SimDevice *);
+FORWARDER2(lib_dev_set_address, void, void, struct SimDevice *,
+ unsigned char *);
+FORWARDER2(lib_dev_set_mtu, void, void, struct SimDevice *, int);
+FORWARDER2(lib_dev_create_packet, nvoid, struct SimDevicePacket,
+ struct SimDevice *, int);
+FORWARDER2(lib_dev_rx, void, void, struct SimDevice *, struct SimDevicePacket);
+
+FORWARDER4(lib_sock_socket, nvoid, int, int, int, int, struct SimSocket **);
+FORWARDER1(lib_sock_close, nvoid, int, struct SimSocket *);
+FORWARDER3(lib_sock_recvmsg, nvoid, ssize_t, struct SimSocket *,
+ struct msghdr *, int);
+FORWARDER3(lib_sock_sendmsg, nvoid, ssize_t, struct SimSocket *,
+ const struct msghdr *, int);
+FORWARDER3(lib_sock_getsockname, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_getpeername, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_bind, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int);
+FORWARDER4(lib_sock_connect, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int, int);
+FORWARDER2(lib_sock_listen, nvoid, int, struct SimSocket *, int);
+FORWARDER2(lib_sock_shutdown, nvoid, int, struct SimSocket *, int);
+FORWARDER3(lib_sock_accept, nvoid, int, struct SimSocket *,
+ struct SimSocket **, int);
+FORWARDER3(lib_sock_ioctl, nvoid, int, struct SimSocket *, int, char *);
+FORWARDER5(lib_sock_setsockopt, nvoid, int, struct SimSocket *, int, int,
+ const void *, int);
+FORWARDER5(lib_sock_getsockopt, nvoid, int, struct SimSocket *, int, int,
+ void *, int *);
+
+FORWARDER2(lib_sock_poll, void, void, struct SimSocket *, void *);
+FORWARDER1(lib_sock_pollfreewait, void, void, void *);
+
+FORWARDER1(lib_sys_iterate_files, void, void, const struct SimSysIterator *);
+FORWARDER4(lib_sys_file_read, nvoid, int, const struct SimSysFile *, char *,
+ int, int);
+FORWARDER4(lib_sys_file_write, nvoid, int, const struct SimSysFile *,
+ const char *, int, int);
+
+struct SimKernel *g_kernel;
+
+void lib_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel)
+{
+ /* make sure we can call the callbacks */
+ g_imported = *imported;
+ g_kernel = kernel;
+ exported->task_create = lib_task_create;
+ exported->task_destroy = lib_task_destroy;
+ exported->task_get_private = lib_task_get_private;
+ exported->sock_socket = lib_sock_socket_forwarder;
+ exported->sock_close = lib_sock_close_forwarder;
+ exported->sock_recvmsg = lib_sock_recvmsg_forwarder;
+ exported->sock_sendmsg = lib_sock_sendmsg_forwarder;
+ exported->sock_getsockname = lib_sock_getsockname_forwarder;
+ exported->sock_getpeername = lib_sock_getpeername_forwarder;
+ exported->sock_bind = lib_sock_bind_forwarder;
+ exported->sock_connect = lib_sock_connect_forwarder;
+ exported->sock_listen = lib_sock_listen_forwarder;
+ exported->sock_shutdown = lib_sock_shutdown_forwarder;
+ exported->sock_accept = lib_sock_accept_forwarder;
+ exported->sock_ioctl = lib_sock_ioctl_forwarder;
+ exported->sock_setsockopt = lib_sock_setsockopt_forwarder;
+ exported->sock_getsockopt = lib_sock_getsockopt_forwarder;
+
+ exported->sock_poll = lib_sock_poll_forwarder;
+ exported->sock_pollfreewait = lib_sock_pollfreewait_forwarder;
+
+ exported->dev_create = lib_dev_create_forwarder;
+ exported->dev_destroy = lib_dev_destroy_forwarder;
+ exported->dev_get_private = lib_dev_get_private;
+ exported->dev_set_address = lib_dev_set_address_forwarder;
+ exported->dev_set_mtu = lib_dev_set_mtu_forwarder;
+ exported->dev_create_packet = lib_dev_create_packet_forwarder;
+ exported->dev_rx = lib_dev_rx_forwarder;
+
+ exported->sys_iterate_files = lib_sys_iterate_files_forwarder;
+ exported->sys_file_write = lib_sys_file_write_forwarder;
+ exported->sys_file_read = lib_sys_file_read_forwarder;
+
+ pr_notice("%s", linux_banner);
+
+ rcu_init();
+
+ /* in drivers/base/core.c (called normally by drivers/base/init.c) */
+ devices_init();
+ /* in lib/idr.c (called normally by init/main.c) */
+ idr_init_cache();
+ vfs_caches_init(totalram_pages);
+
+ lib_proc_net_initialize();
+
+ /* and, then, call the normal initcalls */
+ initcall_t *call;
+ extern initcall_t __initcall_start[], __initcall_end[];
+
+ call = __initcall_start;
+ do {
+ (*call)();
+ call++;
+ } while (call < __initcall_end);
+
+ /* finally, put the system in RUNNING state. */
+ system_state = SYSTEM_RUNNING;
+}
+
+int lib_vprintf(const char *str, va_list args)
+{
+ return g_imported.vprintf(g_kernel, str, args);
+}
+void *lib_malloc(unsigned long size)
+{
+ return g_imported.malloc(g_kernel, size);
+}
+void lib_free(void *buffer)
+{
+ return g_imported.free(g_kernel, buffer);
+}
+void *lib_memcpy(void *dst, const void *src, unsigned long size)
+{
+ return g_imported.memcpy(g_kernel, dst, src, size);
+}
+void *lib_memset(void *dst, char value, unsigned long size)
+{
+ return g_imported.memset(g_kernel, dst, value, size);
+}
+unsigned long lib_random(void)
+{
+ return g_imported.random(g_kernel);
+}
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context), void *context)
+{
+ return g_imported.event_schedule_ns(g_kernel, ns, fn, context,
+ lib_update_jiffies);
+}
+void lib_event_cancel(void *event)
+{
+ return g_imported.event_cancel(g_kernel, event);
+}
+__u64 lib_current_ns(void)
+{
+ return g_imported.current_ns(g_kernel);
+}
+struct SimTaskTrampolineContext {
+ void (*callback)(void *);
+ void *context;
+};
+static void lib_task_start_trampoline(void *context)
+{
+ /* we use this trampoline solely for the purpose of executing
+ lib_update_jiffies prior to calling the callback. */
+ struct SimTaskTrampolineContext *ctx = context;
+ void (*callback)(void *) = ctx->callback;
+ void *callback_context = ctx->context;
+
+ lib_free(ctx);
+ lib_update_jiffies();
+ callback(callback_context);
+}
+struct SimTask *lib_task_start(void (*callback) (void *), void *context)
+{
+ struct SimTaskTrampolineContext *ctx =
+ lib_malloc(sizeof(struct SimTaskTrampolineContext));
+
+ if (!ctx)
+ return NULL;
+ ctx->callback = callback;
+ ctx->context = context;
+ return g_imported.task_start(g_kernel, &lib_task_start_trampoline, ctx);
+}
+void lib_task_wait(void)
+{
+ rcu_sched_qs();
+ g_imported.task_wait(g_kernel);
+ lib_update_jiffies();
+}
+struct SimTask *lib_task_current(void)
+{
+ return g_imported.task_current(g_kernel);
+}
+int lib_task_wakeup(struct SimTask *task)
+{
+ return g_imported.task_wakeup(g_kernel, task);
+}
+void lib_task_yield(void)
+{
+ rcu_idle_enter();
+ g_imported.task_yield(g_kernel);
+ rcu_idle_exit();
+ lib_update_jiffies();
+}
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len)
+{
+ return g_imported.dev_xmit(g_kernel, dev, data, len);
+}
+
+void lib_signal_raised(struct SimTask *task, int sig)
+{
+ g_imported.signal_raised(g_kernel, task, sig);
+}
+
+void lib_poll_event(int flag, void *context)
+{
+ g_imported.poll_event(flag, context);
+}
diff --git a/arch/lib/lib.h b/arch/lib/lib.h
new file mode 100644
index 0000000..abf2a26
--- /dev/null
+++ b/arch/lib/lib.h
@@ -0,0 +1,21 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#ifndef LIB_H
+#define LIB_H
+
+#include <linux/sched.h>
+
+struct SimTask {
+ struct list_head head;
+ struct task_struct kernel_task;
+ void *private;
+};
+
+#endif /* LIB_H */
--
2.1.0
timer related (internal) functions such as add_timer(),
do_gettimeofday() of kernel are trivially reimplemented
for libos. these eventually call the functions registered by lib_init()
API.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/hrtimer.c | 122 +++++++++++++++++++++++
arch/lib/tasklet-hrtimer.c | 57 +++++++++++
arch/lib/time.c | 144 +++++++++++++++++++++++++++
arch/lib/timer.c | 238 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 561 insertions(+)
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
diff --git a/arch/lib/hrtimer.c b/arch/lib/hrtimer.c
new file mode 100644
index 0000000..4565b59
--- /dev/null
+++ b/arch/lib/hrtimer.c
@@ -0,0 +1,122 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/hrtimer.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * hrtimer_init - initialize a timer to the given clock
+ * @timer: the timer to be initialized
+ * @clock_id: the clock to be used
+ * @mode: timer mode abs/rel
+ */
+void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
+{
+ memset(timer, 0, sizeof(*timer));
+}
+static void trampoline(void *context)
+{
+ struct hrtimer *timer = context;
+ enum hrtimer_restart restart = timer->function(timer);
+
+ if (restart == HRTIMER_RESTART) {
+ void *event =
+ lib_event_schedule_ns(ktime_to_ns(timer->_softexpires),
+ &trampoline, timer);
+ timer->base = event;
+ } else {
+ /* mark as completed. */
+ timer->base = 0;
+ }
+}
+/**
+ * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
+ * @timer: the timer to be added
+ * @tim: expiry time
+ * @delta_ns: "slack" range for the timer
+ * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
+ *
+ * Returns:
+ * 0 on success
+ * 1 when the timer was active
+ */
+int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns,
+ const enum hrtimer_mode mode,
+ int wakeup)
+{
+ int ret = hrtimer_cancel(timer);
+ s64 ns = ktime_to_ns(tim);
+ void *event;
+
+ if (mode == HRTIMER_MODE_ABS)
+ ns -= lib_current_ns();
+ timer->_softexpires = ns_to_ktime(ns);
+ event = lib_event_schedule_ns(ns, &trampoline, timer);
+ timer->base = event;
+ return ret;
+}
+/**
+ * hrtimer_try_to_cancel - try to deactivate a timer
+ * @timer: hrtimer to stop
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ * -1 when the timer is currently excuting the callback function and
+ * cannot be stopped
+ */
+int hrtimer_try_to_cancel(struct hrtimer *timer)
+{
+ /* Note: we cannot return -1 from this function.
+ see comment in hrtimer_cancel. */
+ if (timer->base == 0)
+ /* timer was not active yet */
+ return 1;
+ lib_event_cancel(timer->base);
+ timer->base = 0;
+ return 0;
+}
+/**
+ * hrtimer_cancel - cancel a timer and wait for the handler to finish.
+ * @timer: the timer to be cancelled
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ */
+int hrtimer_cancel(struct hrtimer *timer)
+{
+ /* Note: because we assume a uniprocessor non-interruptible */
+ /* system when running in the kernel, we know that the timer */
+ /* is not running when we execute this code, so, know that */
+ /* try_to_cancel cannot return -1 and we don't need to retry */
+ /* the cancel later to wait for the handler to finish. */
+ int ret = hrtimer_try_to_cancel(timer);
+
+ lib_assert(ret >= 0);
+ return ret;
+}
+int
+hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
+}
+int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, delta_ns, mode, 1);
+}
+
+int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
+{
+ *tp = ns_to_timespec(1);
+ return 0;
+}
diff --git a/arch/lib/tasklet-hrtimer.c b/arch/lib/tasklet-hrtimer.c
new file mode 100644
index 0000000..fef4902
--- /dev/null
+++ b/arch/lib/tasklet-hrtimer.c
@@ -0,0 +1,57 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
+{
+ struct tasklet_hrtimer *ttimer =
+ container_of(timer, struct tasklet_hrtimer, timer);
+
+ tasklet_schedule(&ttimer->tasklet);
+ return HRTIMER_NORESTART;
+}
+static void __tasklet_hrtimer_trampoline(unsigned long data)
+{
+ struct tasklet_hrtimer *ttimer = (void *)data;
+ enum hrtimer_restart restart;
+
+ restart = ttimer->function(&ttimer->timer);
+ if (restart != HRTIMER_NORESTART)
+ hrtimer_restart(&ttimer->timer);
+}
+/**
+ * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
+ * @ttimer: tasklet_hrtimer which is initialized
+ * @function: hrtimer callback function which gets called from softirq context
+ * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
+ * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
+ */
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+ enum hrtimer_restart (*function)(struct hrtimer *),
+ clockid_t which_clock, enum hrtimer_mode mode)
+{
+ hrtimer_init(&ttimer->timer, which_clock, mode);
+ ttimer->timer.function = __hrtimer_tasklet_trampoline;
+ tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
+ (unsigned long)ttimer);
+ ttimer->function = function;
+}
+
+void __tasklet_hi_schedule(struct tasklet_struct *t)
+{
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ void *event =
+ lib_event_schedule_ns(0, (void *)&t->func, (void *)t->data);
+ t->next = event;
+}
diff --git a/arch/lib/time.c b/arch/lib/time.c
new file mode 100644
index 0000000..b54be75
--- /dev/null
+++ b/arch/lib/time.c
@@ -0,0 +1,144 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/time.h>
+#include <linux/errno.h>
+#include <linux/timex.h>
+#include <linux/ktime.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+unsigned long volatile jiffies = INITIAL_JIFFIES;
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+struct timespec xtime;
+seqlock_t xtime_lock;
+/* accessed from wrap_clock from do_sys_settimeofday.
+ We don't call the latter so we should never access this variable. */
+struct timespec wall_to_monotonic;
+
+uint64_t ns_to_jiffies(uint64_t ns)
+{
+ do_div(ns, (1000000000 / HZ));
+ return ns;
+}
+
+void lib_update_jiffies(void)
+{
+ jiffies = ns_to_jiffies(lib_current_ns());
+ jiffies_64 = ns_to_jiffies(lib_current_ns());
+}
+
+struct timespec current_kernel_time(void)
+{
+ u64 ns = lib_current_ns();
+ struct timespec spec = ns_to_timespec(ns);
+
+ return spec;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ u64 ns = lib_current_ns();
+
+ *tv = ns_to_timeval(ns);
+}
+
+int do_adjtimex(struct timex *timex)
+{
+ lib_assert(false);
+ return -EPERM;
+}
+ktime_t ktime_get(void)
+{
+ u64 ns = lib_current_ns();
+
+ return ns_to_ktime(ns);
+}
+ktime_t ktime_get_with_offset(enum tk_offsets offs)
+{
+ /* FIXME */
+ return ktime_get();
+}
+
+/* copied from kernel/time/hrtimeer.c */
+#if BITS_PER_LONG < 64
+/*
+ * Divide a ktime value by a nanosecond value
+ */
+u64 __ktime_divns(const ktime_t kt, s64 div)
+{
+ u64 dclc;
+ int sft = 0;
+
+ dclc = ktime_to_ns(kt);
+ /* Make sure the divisor is less than 2^32: */
+ while (div >> 32) {
+ sft++;
+ div >>= 1;
+ }
+ dclc >>= sft;
+ do_div(dclc, (unsigned long)div);
+
+ return dclc;
+}
+#endif /* BITS_PER_LONG >= 64 */
+
+void update_xtime_cache(u64 nsec)
+{
+}
+unsigned long get_seconds(void)
+{
+ u64 ns = lib_current_ns();
+
+ do_div(ns, 1000000000);
+ return ns;
+}
+static unsigned long
+round_jiffies_common(unsigned long j,
+ bool force_up)
+{
+ int rem;
+ unsigned long original = j;
+
+ rem = j % HZ;
+ if (rem < HZ / 4 && !force_up) /* round down */
+ j = j - rem;
+ else /* round up */
+ j = j - rem + HZ;
+ if (j <= jiffies) /* rounding ate our timeout entirely; */
+ return original;
+ return j;
+}
+unsigned long round_jiffies(unsigned long j)
+{
+ return round_jiffies_common(j, false);
+}
+unsigned long round_jiffies_relative(unsigned long j)
+{
+ unsigned long j0 = jiffies;
+
+ /* Use j0 because jiffies might change while we run */
+ return round_jiffies_common(j + j0, false) - j0;
+}
+unsigned long round_jiffies_up(unsigned long j)
+{
+ return round_jiffies_common(j, true);
+}
+static void msleep_trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+void msleep(unsigned int msecs)
+{
+ lib_event_schedule_ns(((__u64)msecs) * 1000000, &msleep_trampoline,
+ lib_task_current());
+ lib_task_wait();
+}
diff --git a/arch/lib/timer.c b/arch/lib/timer.c
new file mode 100644
index 0000000..87d2283
--- /dev/null
+++ b/arch/lib/timer.c
@@ -0,0 +1,238 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * init_timer_key - initialize a timer
+ * @timer: the timer to be initialized
+ * @name: name of the timer
+ * @key: lockdep class key of the fake lock used for tracking timer
+ * sync lock dependencies
+ *
+ * init_timer_key() must be done to a timer prior calling *any* of the
+ * other timer functions.
+ */
+void init_timer_key(struct timer_list *timer,
+ unsigned int flags,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * Note: name and key are used for debugging. We ignore them
+ * unconditionally.
+ * Note: we do not initialize the lockdep map either because we
+ * don't care.
+ * and, finally, we never care about the base field either.
+ *
+ * So, for now, we have a timer which is marked as "not started"
+ * thanks to its entry.next field set to NULL (timer_pending
+ * will return 0)
+ */
+ timer->entry.next = NULL;
+ timer->base = 0;
+}
+
+struct list_head g_expired_events = LIST_HEAD_INIT(g_expired_events);
+struct list_head g_pending_events = LIST_HEAD_INIT(g_pending_events);
+
+static void run_timer_softirq(struct softirq_action *h)
+{
+ while (!list_empty(&g_expired_events)) {
+ struct timer_list *timer = list_first_entry(&g_expired_events,
+ struct timer_list,
+ entry);
+ void (*fn)(unsigned long);
+ unsigned long data;
+
+ fn = timer->function;
+ data = timer->data;
+ lib_assert(timer->base == 0);
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ fn(data);
+ }
+ }
+}
+
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
+}
+static void timer_trampoline(void *context)
+{
+ struct timer_list *timer;
+
+ ensure_softirq_opened();
+ timer = context;
+ timer->base = 0;
+ if (timer->entry.prev != LIST_POISON2)
+ list_del(&timer->entry);
+ list_add_tail(&timer->entry, &g_expired_events);
+ raise_softirq(TIMER_SOFTIRQ);
+}
+/**
+ * add_timer - start a timer
+ * @timer: the timer to be added
+ *
+ * The kernel will do a ->function(->data) callback from the
+ * timer interrupt at the ->expires point in the future. The
+ * current time is 'jiffies'.
+ *
+ * The timer's ->expires, ->function (and if the handler uses it, ->data)
+ * fields must be set prior calling this function.
+ *
+ * Timers with an ->expires field in the past will be executed in the next
+ * timer tick.
+ */
+void add_timer(struct timer_list *timer)
+{
+ __u64 delay_ns = 0;
+
+ lib_assert(!timer_pending(timer));
+ if (timer->expires <= jiffies)
+ delay_ns = (1000000000 / HZ); /* next tick. */
+ else
+ delay_ns =
+ ((__u64)timer->expires *
+ (1000000000 / HZ)) - lib_current_ns();
+ void *event = lib_event_schedule_ns(delay_ns, &timer_trampoline, timer);
+ /* store the external event in the base field */
+ /* to be able to retrieve it from del_timer */
+ timer->base = event;
+ /* finally, store timer in list of pending events. */
+ list_add_tail(&timer->entry, &g_pending_events);
+}
+/**
+ * del_timer - deactive a timer.
+ * @timer: the timer to be deactivated
+ *
+ * del_timer() deactivates a timer - this works on both active and inactive
+ * timers.
+ *
+ * The function returns whether it has deactivated a pending timer or not.
+ * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
+ * active timer returns 1.)
+ */
+int del_timer(struct timer_list *timer)
+{
+ int retval;
+
+ if (timer->entry.next == 0)
+ return 0;
+ if (timer->base != 0) {
+ lib_event_cancel(timer->base);
+ retval = 1;
+ } else
+ retval = 0;
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ }
+ return retval;
+}
+
+/* ////////////////////// */
+
+void init_timer_deferrable_key(struct timer_list *timer,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * From lwn.net:
+ * Timers which are initialized in this fashion will be
+ * recognized as deferrable by the kernel. They will not
+ * be considered when the kernel makes its "when should
+ * the next timer interrupt be?" decision. When the system
+ * is busy these timers will fire at the scheduled time. When
+ * things are idle, instead, they will simply wait until
+ * something more important wakes up the processor.
+ *
+ * Note: Our implementation of deferrable timers uses
+ * non-deferrable timers for simplicity.
+ */
+ init_timer_key(timer, 0, name, key);
+}
+/**
+ * add_timer_on - start a timer on a particular CPU
+ * @timer: the timer to be added
+ * @cpu: the CPU to start it on
+ *
+ * This is not very scalable on SMP. Double adds are not possible.
+ */
+void add_timer_on(struct timer_list *timer, int cpu)
+{
+ /* we ignore the cpu: we have only one. */
+ add_timer(timer);
+}
+/**
+ * mod_timer - modify a timer's timeout
+ * @timer: the timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer() is a more efficient way to update the expire field of an
+ * active timer (if the timer is inactive it will be activated)
+ *
+ * mod_timer(timer, expires) is equivalent to:
+ *
+ * del_timer(timer); timer->expires = expires; add_timer(timer);
+ *
+ * Note that if there are multiple unserialized concurrent users of the
+ * same timer, then mod_timer() is the only safe way to modify the timeout,
+ * since add_timer() cannot modify an already running timer.
+ *
+ * The function returns whether it has modified a pending timer or not.
+ * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
+ * active timer returns 1.)
+ */
+int mod_timer(struct timer_list *timer, unsigned long expires)
+{
+ int ret;
+
+ /* common optimization stolen from kernel */
+ if (timer_pending(timer) && timer->expires == expires)
+ return 1;
+
+ ret = del_timer(timer);
+ timer->expires = expires;
+ add_timer(timer);
+ return ret;
+}
+/**
+ * mod_timer_pending - modify a pending timer's timeout
+ * @timer: the pending timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer_pending() is the same for pending timers as mod_timer(),
+ * but will not re-activate and modify already deleted timers.
+ *
+ * It is useful for unserialized use of timers.
+ */
+int mod_timer_pending(struct timer_list *timer, unsigned long expires)
+{
+ if (timer_pending(timer))
+ return 0;
+ return mod_timer(timer, expires);
+}
+
+int mod_timer_pinned(struct timer_list *timer, unsigned long expires)
+{
+ if (timer->expires == expires && timer_pending(timer))
+ return 1;
+
+ return mod_timer(timer, expires);
+}
--
2.1.0
contexnt primitives of kernel such as soft interupts, scheduling,
tasklet are implemented for libos. these functions eventually call the
functions registered by lib_init() API as well.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sched.c | 406 +++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/softirq.c | 108 ++++++++++++++
arch/lib/tasklet.c | 76 ++++++++++
arch/lib/workqueue.c | 242 ++++++++++++++++++++++++++++++
4 files changed, 832 insertions(+)
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/workqueue.c
diff --git a/arch/lib/sched.c b/arch/lib/sched.c
new file mode 100644
index 0000000..98a568a
--- /dev/null
+++ b/arch/lib/sched.c
@@ -0,0 +1,406 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/nsproxy.h>
+#include <linux/hash.h>
+#include <net/net_namespace.h>
+#include "lib.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+/**
+ called by wait_event macro:
+ - prepare_to_wait
+ - schedule
+ - finish_wait
+ */
+
+struct SimTask *lib_task_create(void *private, unsigned long pid)
+{
+ struct SimTask *task = lib_malloc(sizeof(struct SimTask));
+ struct cred *cred;
+ struct nsproxy *ns;
+ struct user_struct *user;
+ struct thread_info *info;
+ struct pid *kpid;
+
+ if (!task)
+ return NULL;
+ memset(task, 0, sizeof(struct SimTask));
+ cred = lib_malloc(sizeof(struct cred));
+ if (!cred)
+ return NULL;
+ /* XXX: we could optimize away this allocation by sharing it
+ for all tasks */
+ ns = lib_malloc(sizeof(struct nsproxy));
+ if (!ns)
+ return NULL;
+ user = lib_malloc(sizeof(struct user_struct));
+ if (!user)
+ return NULL;
+ info = alloc_thread_info(&task->kernel_task);
+ if (!info)
+ return NULL;
+ kpid = lib_malloc(sizeof(struct pid));
+ if (!kpid)
+ return NULL;
+ kpid->numbers[0].nr = pid;
+ cred->fsuid = make_kuid(current_user_ns(), 0);
+ cred->fsgid = make_kgid(current_user_ns(), 0);
+ cred->user = user;
+ atomic_set(&cred->usage, 1);
+ info->task = &task->kernel_task;
+ info->preempt_count = 0;
+ info->flags = 0;
+ atomic_set(&ns->count, 1);
+ ns->uts_ns = 0;
+ ns->ipc_ns = 0;
+ ns->mnt_ns = 0;
+ ns->pid_ns_for_children = 0;
+ ns->net_ns = &init_net;
+ task->kernel_task.cred = cred;
+ task->kernel_task.pid = pid;
+ task->kernel_task.pids[PIDTYPE_PID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_PGID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_SID].pid = kpid;
+ task->kernel_task.nsproxy = ns;
+ task->kernel_task.stack = info;
+ /* this is a hack. */
+ task->kernel_task.group_leader = &task->kernel_task;
+ task->private = private;
+ return task;
+}
+void lib_task_destroy(struct SimTask *task)
+{
+ lib_free((void *)task->kernel_task.nsproxy);
+ lib_free((void *)task->kernel_task.cred);
+ lib_free((void *)task->kernel_task.cred->user);
+ free_thread_info(task->kernel_task.stack);
+ lib_free(task);
+}
+void *lib_task_get_private(struct SimTask *task)
+{
+ return task->private;
+}
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+ struct SimTask *task = lib_task_start((void (*)(void *))fn, arg);
+
+ return task->kernel_task.pid;
+}
+
+struct task_struct *get_current(void)
+{
+ struct SimTask *lib_task = lib_task_current();
+
+ return &lib_task->kernel_task;
+}
+
+struct thread_info *current_thread_info(void)
+{
+ return task_thread_info(get_current());
+}
+struct thread_info *alloc_thread_info(struct task_struct *task)
+{
+ return lib_malloc(sizeof(struct thread_info));
+}
+void free_thread_info(struct thread_info *ti)
+{
+ lib_free(ti);
+}
+
+
+void __put_task_struct(struct task_struct *t)
+{
+ lib_free(t);
+}
+
+void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ list_add(&wait->task_list, &q->task_list);
+}
+void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait->task_list, &q->task_list);
+}
+void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ if (wait->task_list.prev != LIST_POISON2)
+ list_del(&wait->task_list);
+}
+void
+prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ if (list_empty(&wait->task_list))
+ list_add_tail(&wait->task_list, &q->task_list);
+ set_current_state(state);
+}
+void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue(q, wait);
+ set_current_state(state);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ set_current_state(TASK_RUNNING);
+ if (!list_empty(&wait->task_list))
+ list_del_init(&wait->task_list);
+}
+int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync,
+ void *key)
+{
+ int ret = default_wake_function(wait, mode, sync, key);
+
+ if (ret && (wait->task_list.prev != LIST_POISON2))
+ list_del_init(&wait->task_list);
+
+ return ret;
+}
+
+int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ wait->flags |= WQ_FLAG_WOKEN;
+ return default_wake_function(wait, mode, sync, key);
+}
+
+void __init_waitqueue_head(wait_queue_head_t *q, const char *name,
+ struct lock_class_key *k)
+{
+ INIT_LIST_HEAD(&q->task_list);
+}
+/**
+ * wait_for_completion: - waits for completion of a task
+ * @x: holds the state of this particular completion
+ *
+ * This waits to be signaled for completion of a specific task. It is NOT
+ * interruptible and there is no timeout.
+ *
+ * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
+ * and interrupt capability. Also see complete().
+ */
+void wait_for_completion(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+}
+unsigned long wait_for_completion_timeout(struct completion *x,
+ unsigned long timeout)
+{
+ if (!x->done) {
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ wait.flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait.task_list, &x->wait.task_list);
+ do
+ timeout = schedule_timeout(timeout);
+ while (!x->done && timeout);
+ if (wait.task_list.prev != LIST_POISON2)
+ list_del(&wait.task_list);
+
+ if (!x->done)
+ return timeout;
+ }
+ x->done--;
+ return timeout ? : 1;
+}
+
+/**
+ * __wake_up - wake up threads blocked on a waitqueue.
+ * @q: the waitqueue
+ * @mode: which threads
+ * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ * @key: is directly passed to the wakeup function
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
+ */
+void __wake_up(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ wait_queue_t *curr, *next;
+
+ list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
+ unsigned flags = curr->flags;
+
+ if (curr->func(curr, mode, 0, key) &&
+ (flags & WQ_FLAG_EXCLUSIVE) &&
+ !--nr_exclusive)
+ break;
+ }
+}
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ __wake_up(q, mode, nr_exclusive, key);
+}
+int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
+ void *key)
+{
+ struct task_struct *task = (struct task_struct *)curr->private;
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+__sched int bit_wait(struct wait_bit_key *word)
+{
+ if (signal_pending_state(current->state, current))
+ return 1;
+ schedule();
+ return 0;
+}
+int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
+{
+ struct wait_bit_key *key = arg;
+ struct wait_bit_queue *wait_bit
+ = container_of(wait, struct wait_bit_queue, wait);
+
+ if (wait_bit->key.flags != key->flags ||
+ wait_bit->key.bit_nr != key->bit_nr ||
+ test_bit(key->bit_nr, key->flags))
+ return 0;
+ else
+ return autoremove_wake_function(wait, mode, sync, key);
+}
+void __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
+{
+ struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
+ if (waitqueue_active(wq))
+ __wake_up(wq, TASK_NORMAL, 1, &key);
+}
+void wake_up_bit(void *word, int bit)
+{
+ /* FIXME */
+ return;
+ __wake_up_bit(bit_waitqueue(word, bit), word, bit);
+}
+wait_queue_head_t *bit_waitqueue(void *word, int bit)
+{
+ const int shift = BITS_PER_LONG == 32 ? 5 : 6;
+ const struct zone *zone = page_zone(virt_to_page(word));
+ unsigned long val = (unsigned long)word << shift | bit;
+
+ return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
+}
+
+
+void schedule(void)
+{
+ lib_task_wait();
+}
+
+static void trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+
+signed long schedule_timeout(signed long timeout)
+{
+ u64 ns;
+ struct SimTask *self;
+
+ if (timeout == MAX_SCHEDULE_TIMEOUT) {
+ lib_task_wait();
+ return MAX_SCHEDULE_TIMEOUT;
+ }
+ lib_assert(timeout >= 0);
+ ns = ((__u64)timeout) * (1000000000 / HZ);
+ self = lib_task_current();
+ lib_event_schedule_ns(ns, &trampoline, self);
+ lib_task_wait();
+ /* we know that we are always perfectly on time. */
+ return 0;
+}
+
+signed long schedule_timeout_uninterruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+signed long schedule_timeout_interruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+
+void yield(void)
+{
+ lib_task_yield();
+}
+
+void complete_all(struct completion *x)
+{
+ x->done += UINT_MAX / 2;
+ __wake_up(&x->wait, TASK_NORMAL, 0, 0);
+}
+void complete(struct completion *x)
+{
+ x->done++;
+ __wake_up(&x->wait, TASK_NORMAL, 1, 0);
+}
+
+long wait_for_completion_interruptible_timeout(
+ struct completion *x, unsigned long timeout)
+{
+ return wait_for_completion_timeout(x, timeout);
+}
+int wait_for_completion_interruptible(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+ return 0;
+}
+int wake_up_process(struct task_struct *tsk)
+{
+ struct SimTask *lib_task =
+ container_of(tsk, struct SimTask, kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+int _cond_resched(void)
+{
+ /* we never schedule to decrease latency. */
+ return 0;
+}
+int idle_cpu(int cpu)
+{
+ /* we are never idle: we call this from rcutiny.c and the answer */
+ /* does not matter, really. */
+ return 0;
+}
+
+unsigned long long __attribute__((weak)) sched_clock(void)
+{
+ return (unsigned long long)(jiffies - INITIAL_JIFFIES)
+ * (NSEC_PER_SEC / HZ);
+}
+
+u64 local_clock(void)
+{
+ return sched_clock();
+}
+
+void __sched schedule_preempt_disabled(void)
+{
+}
+
+void resched_cpu(int cpu)
+{
+ rcu_sched_qs();
+}
diff --git a/arch/lib/softirq.c b/arch/lib/softirq.c
new file mode 100644
index 0000000..3f6363a
--- /dev/null
+++ b/arch/lib/softirq.c
@@ -0,0 +1,108 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim-init.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+
+static struct softirq_action softirq_vec[NR_SOFTIRQS];
+static struct SimTask *g_softirq_task = 0;
+static int g_n_raises = 0;
+
+void lib_softirq_wakeup(void)
+{
+ g_n_raises++;
+ lib_task_wakeup(g_softirq_task);
+}
+
+static void softirq_task_function(void *context)
+{
+ while (true) {
+ do_softirq();
+ g_n_raises--;
+ if (g_n_raises == 0 || local_softirq_pending() == 0) {
+ g_n_raises = 0;
+ lib_task_wait();
+ }
+ }
+}
+
+static void ensure_task_created(void)
+{
+ if (g_softirq_task != 0)
+ return;
+ g_softirq_task = lib_task_start(&softirq_task_function, 0);
+}
+
+void open_softirq(int nr, void (*action)(struct softirq_action *))
+{
+ ensure_task_created();
+ softirq_vec[nr].action = action;
+}
+#define MAX_SOFTIRQ_RESTART 10
+
+void do_softirq(void)
+{
+ __u32 pending;
+ int max_restart = MAX_SOFTIRQ_RESTART;
+ struct softirq_action *h;
+
+ pending = local_softirq_pending();
+
+restart:
+ /* Reset the pending bitmask before enabling irqs */
+ set_softirq_pending(0);
+
+ local_irq_enable();
+
+ h = softirq_vec;
+
+ do {
+ if (pending & 1)
+ h->action(h);
+ h++;
+ pending >>= 1;
+ } while (pending);
+
+ local_irq_disable();
+
+ pending = local_softirq_pending();
+ if (pending && --max_restart)
+ goto restart;
+}
+void raise_softirq_irqoff(unsigned int nr)
+{
+ __raise_softirq_irqoff(nr);
+
+ lib_softirq_wakeup();
+}
+void __raise_softirq_irqoff(unsigned int nr)
+{
+ /* trace_softirq_raise(nr); */
+ or_softirq_pending(1UL << nr);
+}
+int __cond_resched_softirq(void)
+{
+ /* tell the caller that we did not need to re-schedule. */
+ return 0;
+}
+void raise_softirq(unsigned int nr)
+{
+ /* copy/paste from kernel/softirq.c */
+ unsigned long flags;
+
+ local_irq_save(flags);
+ raise_softirq_irqoff(nr);
+ local_irq_restore(flags);
+}
+
+void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
+{
+}
diff --git a/arch/lib/tasklet.c b/arch/lib/tasklet.c
new file mode 100644
index 0000000..6cc68f4
--- /dev/null
+++ b/arch/lib/tasklet.c
@@ -0,0 +1,76 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void tasklet_init(struct tasklet_struct *t,
+ void (*func)(unsigned long), unsigned long data)
+{
+ t->next = NULL;
+ t->state = 0;
+ atomic_set(&t->count, 0);
+ t->func = func;
+ t->data = data;
+}
+
+void tasklet_kill(struct tasklet_struct *t)
+{
+ /* theoretically, called from user context */
+ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
+ do
+ lib_task_yield();
+ while (test_bit(TASKLET_STATE_SCHED, &t->state));
+ }
+ clear_bit(TASKLET_STATE_SCHED, &t->state);
+}
+struct tasklet_struct *g_sched_events = NULL;
+static void run_tasklet_softirq(struct softirq_action *h)
+{
+ /* while (!list_empty (&g_sched_events)) */
+ /* { */
+ struct tasklet_struct *tasklet = g_sched_events;
+
+ if (atomic_read(&tasklet->count) == 0) {
+ /* this tasklet is enabled so, we run it. */
+ test_and_clear_bit(TASKLET_STATE_SCHED, &tasklet->state);
+ tasklet->func(tasklet->data);
+ }
+ /* } */
+}
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TASKLET_SOFTIRQ, run_tasklet_softirq);
+}
+static void trampoline(void *context)
+{
+ ensure_softirq_opened();
+ struct tasklet_struct *tasklet = context;
+ /* allow the tasklet to re-schedule itself */
+ lib_assert(tasklet->next != 0);
+ tasklet->next = 0;
+ g_sched_events = tasklet;
+ raise_softirq(TASKLET_SOFTIRQ);
+}
+void __tasklet_schedule(struct tasklet_struct *t)
+{
+ void *event;
+
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ event = lib_event_schedule_ns(0, &trampoline, t);
+ t->next = event;
+}
diff --git a/arch/lib/workqueue.c b/arch/lib/workqueue.c
new file mode 100644
index 0000000..bd0e9c5
--- /dev/null
+++ b/arch/lib/workqueue.c
@@ -0,0 +1,242 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+/* copy from kernel/workqueue.c */
+typedef unsigned long mayday_mask_t;
+struct workqueue_struct {
+ unsigned int flags; /* W: WQ_* flags */
+ union {
+ struct cpu_workqueue_struct __percpu *pcpu;
+ struct cpu_workqueue_struct *single;
+ unsigned long v;
+ } cpu_wq; /* I: cwq's */
+ struct list_head list; /* W: list of all workqueues */
+
+ struct mutex flush_mutex; /* protects wq flushing */
+ int work_color; /* F: current work color */
+ int flush_color; /* F: current flush color */
+ atomic_t nr_cwqs_to_flush; /* flush in progress */
+ struct wq_flusher *first_flusher; /* F: first flusher */
+ struct list_head flusher_queue; /* F: flush waiters */
+ struct list_head flusher_overflow; /* F: flush overflow list */
+
+ mayday_mask_t mayday_mask; /* cpus requesting rescue */
+ struct worker *rescuer; /* I: rescue worker */
+
+ int nr_drainers; /* W: drain in progress */
+ int saved_max_active; /* W: saved cwq max_active */
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map lockdep_map;
+#endif
+ char name[]; /* I: workqueue name */
+};
+
+struct wq_barrier {
+ struct SimTask *waiter;
+ struct workqueue_struct wq;
+};
+
+static void
+workqueue_function(void *context)
+{
+ struct workqueue_struct *wq = context;
+
+ while (true) {
+ lib_task_wait();
+ while (!list_empty(&wq->list)) {
+ struct work_struct *work =
+ list_first_entry(&wq->list, struct work_struct,
+ entry);
+ work_func_t f = work->func;
+
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ f(work);
+ }
+ }
+ }
+}
+
+static struct SimTask *workqueue_task(struct workqueue_struct *wq)
+{
+ struct wq_barrier *barr = container_of(wq, struct wq_barrier, wq);
+
+ if (barr->waiter == 0)
+ barr->waiter = lib_task_start(&workqueue_function, wq);
+ return barr->waiter;
+}
+
+static int flush_entry(struct workqueue_struct *wq, struct list_head *prev)
+{
+ int active = 0;
+
+ if (!list_empty(&wq->list)) {
+ active = 1;
+ lib_task_wakeup(workqueue_task(wq));
+ /* XXX: should wait for completion? but this will block
+ and init won't return.. */
+ /* lib_task_wait (); */
+ }
+
+ return active;
+}
+
+void delayed_work_timer_fn(unsigned long data)
+{
+ struct delayed_work *dwork = (struct delayed_work *)data;
+ struct work_struct *work = &dwork->work;
+
+ list_add_tail(&work->entry, &dwork->wq->list);
+ lib_task_wakeup(workqueue_task(dwork->wq));
+}
+
+bool queue_work_on(int cpu, struct workqueue_struct *wq,
+ struct work_struct *work)
+{
+ int ret = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ list_add_tail(&work->entry, &wq->list);
+ lib_task_wakeup(workqueue_task(wq));
+ ret = 1;
+ }
+ return ret;
+}
+
+void flush_scheduled_work(void)
+{
+ flush_entry(system_wq, system_wq->list.prev);
+}
+bool flush_work(struct work_struct *work)
+{
+ return flush_entry(system_wq, &work->entry);
+}
+void flush_workqueue(struct workqueue_struct *wq)
+{
+ flush_entry(wq, wq->list.prev);
+}
+bool cancel_work_sync(struct work_struct *work)
+{
+ int retval = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)))
+ /* work was not yet queued */
+ return 0;
+ if (!list_empty(&work->entry)) {
+ /* work was queued. now unqueued. */
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ retval = 1;
+ }
+ }
+ return retval;
+}
+bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ int ret = 0;
+ struct timer_list *timer = &dwork->timer;
+ struct work_struct *work = &dwork->work;
+
+ if (delay == 0)
+ return queue_work(wq, work);
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ lib_assert(!timer_pending(timer));
+ dwork->wq = wq;
+ /* This stores cwq for the moment, for the timer_fn */
+ timer->expires = jiffies + delay;
+ timer->data = (unsigned long)dwork;
+ timer->function = delayed_work_timer_fn;
+ add_timer(timer);
+ ret = 1;
+ }
+ return ret;
+}
+bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ del_timer(&dwork->timer);
+ __clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&dwork->work));
+ return queue_delayed_work(wq, dwork, delay);
+}
+bool cancel_delayed_work(struct delayed_work *dwork)
+{
+ del_timer(&dwork->timer);
+ return cancel_work_sync(&dwork->work);
+}
+
+struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
+ unsigned int flags,
+ int max_active,
+ struct lock_class_key *key,
+ const char *lock_name, ...)
+{
+ va_list args, args1;
+ struct wq_barrier *barr;
+ struct workqueue_struct *wq;
+ size_t namelen;
+
+ /* determine namelen, allocate wq and format name */
+ va_start(args, lock_name);
+ va_copy(args1, args);
+ namelen = vsnprintf(NULL, 0, fmt, args) + 1;
+
+ barr = kzalloc(sizeof(*barr) + namelen, GFP_KERNEL);
+ if (!barr)
+ goto err;
+ barr->waiter = 0;
+ wq = &barr->wq;
+
+ vsnprintf(wq->name, namelen, fmt, args1);
+ va_end(args);
+ va_end(args1);
+
+ max_active = max_active ? : WQ_DFL_ACTIVE;
+ /* init wq */
+ wq->flags = flags;
+ wq->saved_max_active = max_active;
+ mutex_init(&wq->flush_mutex);
+ atomic_set(&wq->nr_cwqs_to_flush, 0);
+ INIT_LIST_HEAD(&wq->flusher_queue);
+ INIT_LIST_HEAD(&wq->flusher_overflow);
+
+ lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
+ INIT_LIST_HEAD(&wq->list);
+
+ /* start waiter task */
+ workqueue_task(wq);
+ return wq;
+err:
+ if (barr)
+ kfree(barr);
+ return NULL;
+}
+
+struct workqueue_struct *system_wq __read_mostly;
+struct workqueue_struct *system_power_efficient_wq __read_mostly;
+/* from linux/workqueue.h */
+#define system_nrt_wq __system_nrt_wq()
+
+static int __init init_workqueues(void)
+{
+ system_wq = alloc_workqueue("events", 0, 0);
+ system_power_efficient_wq = alloc_workqueue("events_power_efficient",
+ WQ_POWER_EFFICIENT, 0);
+ return 0;
+}
+early_initcall(init_workqueues);
--
2.1.0
This interacts with fs/proc_fs.c for sysctl-like interface registed via
lib_init() API.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sysctl.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 270 insertions(+)
create mode 100644 arch/lib/sysctl.c
diff --git a/arch/lib/sysctl.c b/arch/lib/sysctl.c
new file mode 100644
index 0000000..5f08f9f
--- /dev/null
+++ b/arch/lib/sysctl.c
@@ -0,0 +1,270 @@
+/*
+ * sysctl wrapper for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/mman.h>
+#include <linux/ratelimit.h>
+#include <linux/proc_fs.h>
+#include "sim-assert.h"
+#include "sim-types.h"
+
+int drop_caches_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_writeback_centisecs_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int scan_unevictable_handler(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int sched_rt_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int sysctl_overcommit_memory = OVERCOMMIT_GUESS;
+int sysctl_overcommit_ratio = 50;
+int sysctl_panic_on_oom = 0;
+int sysctl_oom_dump_tasks = 0;
+int sysctl_oom_kill_allocating_task = 0;
+int sysctl_nr_trim_pages = 0;
+int sysctl_drop_caches = 0;
+int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES - 1] = { 32 };
+unsigned int sysctl_sched_child_runs_first = 0;
+unsigned int sysctl_sched_compat_yield = 0;
+unsigned int sysctl_sched_rt_period = 1000000;
+int sysctl_sched_rt_runtime = 950000;
+
+int vm_highmem_is_dirtyable;
+unsigned long vm_dirty_bytes = 0;
+int vm_dirty_ratio = 20;
+int dirty_background_ratio = 10;
+unsigned int dirty_expire_interval = 30 * 100;
+unsigned int dirty_writeback_interval = 5 * 100;
+unsigned long dirty_background_bytes = 0;
+int percpu_pagelist_fraction = 0;
+int panic_timeout = 0;
+int panic_on_oops = 0;
+int printk_delay_msec = 0;
+int panic_on_warn = 0;
+DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
+
+#define RESERVED_PIDS 300
+int pid_max = PID_MAX_DEFAULT;
+int pid_max_min = RESERVED_PIDS + 1;
+int pid_max_max = PID_MAX_LIMIT;
+int min_free_kbytes = 1024;
+int max_threads = 100;
+int laptop_mode = 0;
+
+#define DEFAULT_MESSAGE_LOGLEVEL 4
+#define MINIMUM_CONSOLE_LOGLEVEL 1
+#define DEFAULT_CONSOLE_LOGLEVEL 7
+int console_printk[4] = {
+ DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
+ DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
+ MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
+ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
+};
+
+int print_fatal_signals = 0;
+unsigned int core_pipe_limit = 0;
+int core_uses_pid = 0;
+int vm_swappiness = 60;
+int nr_pdflush_threads = 0;
+unsigned long scan_unevictable_pages = 0;
+int suid_dumpable = 0;
+int page_cluster = 0;
+int block_dump = 0;
+int C_A_D = 0;
+#include <linux/nsproxy.h>
+struct nsproxy init_nsproxy;
+#include <linux/reboot.h>
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
+unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
+
+int pdflush_proc_obsolete(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return nr_pdflush_threads;
+}
+#include <linux/fs.h>
+
+/**
+ * Honestly, I don't understand half of that code.
+ * It was modeled after fs/proc/proc_sysctl.c proc_sys_readdir
+ *
+ * Me either ;) (Hajime, Jan 2013)
+ */
+
+/* from proc_sysctl.c (XXX) */
+extern struct ctl_table_root sysctl_table_root;
+void ctl_table_first_entry(struct ctl_dir *dir,
+ struct ctl_table_header **phead, struct ctl_table **pentry);
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry);
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen);
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir);
+/* for init_net (XXX, should be fixed) */
+#include <net/net_namespace.h>
+
+static void iterate_table_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table *entry;
+
+ for (entry = head->ctl_table; entry->procname; entry++) {
+ bool may_read = (head->ctl_table->mode & MAY_READ);
+ bool may_write = (head->ctl_table->mode & MAY_WRITE);
+ int flags = 0;
+
+ flags |= may_read ? SIM_SYS_FILE_READ : 0;
+ flags |= may_write ? SIM_SYS_FILE_WRITE : 0;
+ iter->report_file(iter, entry->procname, flags,
+ (struct SimSysFile *)entry);
+ }
+}
+
+
+static void iterate_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table_header *h = NULL;
+ struct ctl_table *entry;
+ struct ctl_dir *ctl_dir;
+
+ ctl_dir = container_of(head, struct ctl_dir, header);
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
+ struct ctl_dir *dir;
+ int ret;
+ const char *procname;
+
+ /* copy from sysctl_follow_link () */
+ if (S_ISLNK(entry->mode)) {
+ dir = ctl_table_xlate_dir(&init_net.sysctls, h->parent);
+ if (IS_ERR(dir)) {
+ ret = PTR_ERR(dir);
+ lib_assert(false);
+ } else {
+ procname = entry->procname;
+ h = NULL;
+ entry =
+ ctl_table_find_entry(&h, dir, procname,
+ strlen(procname));
+ ret = -ENOENT;
+ }
+ }
+
+ if (S_ISDIR(entry->mode)) {
+ iter->report_start_dir(iter, entry->procname);
+ iterate_recursive(iter, h);
+ iter->report_end_dir(iter);
+ } else
+ iterate_table_recursive(iter, h);
+ }
+
+}
+
+
+void lib_sys_iterate_files(const struct SimSysIterator *iter)
+{
+ struct ctl_table_header *root =
+ &sysctl_table_root.default_set.dir.header;
+
+ iterate_recursive(iter, root);
+}
+
+int lib_sys_file_read(const struct SimSysFile *file, char *buffer, int size,
+ int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 0, buffer, &result, &ppos);
+ return result;
+}
+int lib_sys_file_write(const struct SimSysFile *file, const char *buffer,
+ int size, int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 1, (char *)buffer, &result, &ppos);
+ return result;
+}
--
2.1.0
These files are used to provide the same function calls so that other
network stack code keeps untouched.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Christoph Paasch <[email protected]>
---
arch/lib/capability.c | 47 +++++++++
arch/lib/filemap.c | 32 ++++++
arch/lib/fs.c | 70 +++++++++++++
arch/lib/glue.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/modules.c | 36 +++++++
arch/lib/pid.c | 29 ++++++
arch/lib/print.c | 56 ++++++++++
arch/lib/proc.c | 34 ++++++
arch/lib/random.c | 53 ++++++++++
arch/lib/sysfs.c | 83 +++++++++++++++
arch/lib/vmscan.c | 26 +++++
11 files changed, 749 insertions(+)
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/vmscan.c
diff --git a/arch/lib/capability.c b/arch/lib/capability.c
new file mode 100644
index 0000000..7054fea
--- /dev/null
+++ b/arch/lib/capability.c
@@ -0,0 +1,47 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "linux/capability.h"
+
+struct sock;
+struct sk_buff;
+
+int file_caps_enabled = 0;
+
+bool capable(int cap)
+{
+ switch (cap) {
+ case CAP_NET_RAW:
+ case CAP_NET_BIND_SERVICE:
+ case CAP_NET_ADMIN:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int cap_netlink_recv(struct sk_buff *skb, int cap)
+{
+ return 0;
+}
+
+int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+ return 0;
+}
+bool ns_capable(struct user_namespace *ns, int cap)
+{
+ return true;
+}
+bool file_ns_capable(const struct file *file, struct user_namespace *ns,
+ int cap)
+{
+ return true;
+}
diff --git a/arch/lib/filemap.c b/arch/lib/filemap.c
new file mode 100644
index 0000000..ce424ff
--- /dev/null
+++ b/arch/lib/filemap.c
@@ -0,0 +1,32 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/fs.h>
+
+
+ssize_t generic_file_aio_read(struct kiocb *a, const struct iovec *b,
+ unsigned long c, loff_t d)
+{
+ lib_assert(false);
+
+ return 0;
+}
+
+int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return -ENOSYS;
+}
+
+ssize_t
+generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+ return 0;
+}
diff --git a/arch/lib/fs.c b/arch/lib/fs.c
new file mode 100644
index 0000000..324e10b
--- /dev/null
+++ b/arch/lib/fs.c
@@ -0,0 +1,70 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <fs/mount.h>
+
+#include "sim-assert.h"
+
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock);
+unsigned int dirtytime_expire_interval;
+
+void __init mnt_init(void)
+{
+}
+
+/* Implementation taken from vfs_kern_mount from linux/namespace.c */
+struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
+{
+ static struct mount local_mnt;
+ static int count = 0;
+ struct mount *mnt = &local_mnt;
+ struct dentry *root = 0;
+
+ /* XXX */
+ if (count != 0) return &local_mnt.mnt;
+ count++;
+
+ memset(mnt, 0, sizeof(struct mount));
+ if (!type)
+ return ERR_PTR(-ENODEV);
+ int flags = MS_KERNMOUNT;
+ char *name = (char *)type->name;
+
+ if (flags & MS_KERNMOUNT)
+ mnt->mnt.mnt_flags = MNT_INTERNAL;
+
+ root = type->mount(type, flags, name, data);
+ if (IS_ERR(root))
+ return ERR_CAST(root);
+
+ mnt->mnt.mnt_root = root;
+ mnt->mnt.mnt_sb = root->d_sb;
+ mnt->mnt_mountpoint = mnt->mnt.mnt_root;
+ mnt->mnt_parent = mnt;
+ /* DCE is monothreaded , so we do not care of lock here */
+ list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
+
+ return &mnt->mnt;
+}
+void inode_wait_for_writeback(struct inode *inode)
+{
+}
+void truncate_inode_pages_final(struct address_space *mapping)
+{
+}
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
+
+unsigned int nr_free_buffer_pages(void)
+{
+ return 1024;
+}
diff --git a/arch/lib/glue.c b/arch/lib/glue.c
new file mode 100644
index 0000000..928040d
--- /dev/null
+++ b/arch/lib/glue.c
@@ -0,0 +1,283 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <linux/types.h> /* loff_t */
+#include <linux/errno.h> /* ESPIPE */
+#include <linux/pagemap.h> /* PAGE_CACHE_SIZE */
+#include <linux/limits.h> /* NAME_MAX */
+#include <linux/statfs.h> /* struct kstatfs */
+#include <linux/bootmem.h> /* HASHDIST_DEFAULT */
+#include <linux/utsname.h>
+#include <linux/binfmts.h>
+#include <linux/init_task.h>
+#include <linux/sched/rt.h>
+#include <linux/backing-dev.h>
+#include <stdarg.h>
+#include "sim-assert.h"
+#include "sim.h"
+#include "lib.h"
+
+
+struct pipe_buffer;
+struct file;
+struct pipe_inode_info;
+struct wait_queue_t;
+struct kernel_param;
+struct super_block;
+struct tvec_base {};
+
+/* defined in sched.c, used in net/sched/em_meta.c */
+unsigned long avenrun[3];
+/* defined in mm/page_alloc.c, used in net/xfrm/xfrm_hash.c */
+int hashdist = HASHDIST_DEFAULT;
+/* defined in mm/page_alloc.c */
+struct pglist_data __refdata contig_page_data;
+/* defined in linux/mmzone.h mm/memory.c */
+struct page *mem_map = 0;
+/* used during boot. */
+struct tvec_base boot_tvec_bases;
+/* used by sysinfo in kernel/timer.c */
+int nr_threads = 0;
+/* not very useful in mm/vmstat.c */
+atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
+
+/* XXX: used in network stack ! */
+unsigned long num_physpages = 0;
+unsigned long totalram_pages = 0;
+
+/* XXX figure out initial value */
+unsigned int interrupt_pending = 0;
+static unsigned long g_irqflags = 0;
+static unsigned long local_irqflags = 0;
+int overflowgid = 0;
+int overflowuid = 0;
+int fs_overflowgid = 0;
+int fs_overflowuid = 0;
+unsigned long sysctl_overcommit_kbytes __read_mostly;
+DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
+static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
+
+struct backing_dev_info noop_backing_dev_info = {
+ .name = "noop",
+ .capabilities = 0,
+};
+
+/* from rt.c */
+int sched_rr_timeslice = RR_TIMESLICE;
+/* from main.c */
+bool initcall_debug;
+bool static_key_initialized __read_mostly = false;
+unsigned long __start_rodata, __end_rodata;
+
+unsigned long arch_local_save_flags(void)
+{
+ return local_irqflags;
+}
+void arch_local_irq_restore(unsigned long flags)
+{
+ local_irqflags = flags;
+}
+
+
+unsigned long long nr_context_switches(void)
+{
+ /* we just need to return >0 to avoid the warning
+ in kernel/rcupdate.c */
+ return 1;
+}
+
+
+long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long start, unsigned long nr_pages,
+ int write, int force, struct page **pages,
+ struct vm_area_struct **vmas)
+{
+ /* in practice, this function is never called. It's linked in because */
+ /* we link in get_user_pages_fast which is included only because it */
+ /* is located in mm/util.c */
+ lib_assert(false);
+ return 0;
+}
+
+
+void dump_stack(void)
+{
+ /* we assert to make sure that we catch whoever calls dump_stack */
+ lib_assert(false);
+}
+
+
+void lib_printf(const char *str, ...)
+{
+ va_list args;
+
+ va_start(args, str);
+ lib_vprintf(str, args);
+ va_end(args);
+}
+
+#include <linux/vmalloc.h>
+#include <linux/kmemleak.h>
+
+static unsigned long __meminitdata nr_kernel_pages = 8192;
+static unsigned long __meminitdata nr_all_pages = 81920;
+/*
+ * allocate a large system hash table from bootmem
+ * - it is assumed that the hash table must contain an exact power-of-2
+ * quantity of entries
+ * - limit is the number of hash buckets, not the total allocation size
+ */
+void *__init alloc_large_system_hash(const char *tablename,
+ unsigned long bucketsize,
+ unsigned long numentries,
+ int scale,
+ int flags,
+ unsigned int *_hash_shift,
+ unsigned int *_hash_mask,
+ unsigned long low_limit,
+ unsigned long high_limit)
+{
+ unsigned long long max = high_limit;
+ unsigned long log2qty, size;
+ void *table = NULL;
+
+ /* allow the kernel cmdline to have a say */
+ if (!numentries) {
+ /* round applicable memory size up to nearest megabyte */
+ numentries = nr_kernel_pages;
+ numentries += (1UL << (20 - PAGE_SHIFT)) - 1;
+ numentries >>= 20 - PAGE_SHIFT;
+ numentries <<= 20 - PAGE_SHIFT;
+
+ /* limit to 1 bucket per 2^scale bytes of low memory */
+ if (scale > PAGE_SHIFT)
+ numentries >>= (scale - PAGE_SHIFT);
+ else
+ numentries <<= (PAGE_SHIFT - scale);
+
+ /* Make sure we've got at least a 0-order allocation.. */
+ if (unlikely(flags & HASH_SMALL)) {
+ /* Makes no sense without HASH_EARLY */
+ WARN_ON(!(flags & HASH_EARLY));
+ if (!(numentries >> *_hash_shift)) {
+ numentries = 1UL << *_hash_shift;
+ BUG_ON(!numentries);
+ }
+ } else if (unlikely((numentries * bucketsize) < PAGE_SIZE))
+ numentries = PAGE_SIZE / bucketsize;
+ }
+ numentries = roundup_pow_of_two(numentries);
+
+ /* limit allocation size to 1/16 total memory by default */
+ if (max == 0) {
+ max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
+ do_div(max, bucketsize);
+ }
+
+ if (numentries > max)
+ numentries = max;
+
+ log2qty = ilog2(numentries);
+
+ do {
+ size = bucketsize << log2qty;
+ if (flags & HASH_EARLY)
+ table = alloc_bootmem_nopanic(size);
+ else if (hashdist)
+ table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
+ else {
+ /*
+ * If bucketsize is not a power-of-two, we may free
+ * some pages at the end of hash table which
+ * alloc_pages_exact() automatically does
+ */
+ if (get_order(size) < MAX_ORDER) {
+ table = alloc_pages_exact(size, GFP_ATOMIC);
+ kmemleak_alloc(table, size, 1, GFP_ATOMIC);
+ }
+ }
+ } while (!table && size > PAGE_SIZE && --log2qty);
+
+ if (!table)
+ panic("Failed to allocate %s hash table\n", tablename);
+
+ pr_info("%s hash table entries: %d (order: %d, %lu bytes)\n",
+ tablename,
+ (1U << log2qty),
+ ilog2(size) - PAGE_SHIFT,
+ size);
+
+ if (_hash_shift)
+ *_hash_shift = log2qty;
+ if (_hash_mask)
+ *_hash_mask = (1 << log2qty) - 1;
+
+ return table;
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ /* This function is called from the ip layer to get information about
+ the amount of memory in the system and make some educated guesses
+ about some default buffer sizes. We pick a value which ensures
+ small buffers. */
+ val->totalram = 0;
+}
+int slab_is_available(void)
+{
+ /* called from kernel/param.c. */
+ return 1;
+}
+
+/* used from kern_ptr_validate from mm/util.c which is never called */
+void *high_memory = 0;
+
+
+
+void async_synchronize_full(void)
+{
+ /* called from drivers/base/ *.c */
+ /* there is nothing to do, really. */
+}
+
+int send_sig(int signal, struct task_struct *task, int x)
+{
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ lib_signal_raised((struct SimTask *)lib_task, signal);
+ /* lib_assert (false); */
+ return 0;
+}
+unsigned long get_taint(void)
+{
+ /* never tainted. */
+ return 0;
+}
+void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
+{
+}
+struct pid *cad_pid = 0;
+
+void add_device_randomness(const void *buf, unsigned int size)
+{
+}
+
+int sched_rr_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ return 0;
+}
+
+void on_each_cpu_mask(const struct cpumask *mask,
+ smp_call_func_t func, void *info, bool wait)
+{
+}
diff --git a/arch/lib/modules.c b/arch/lib/modules.c
new file mode 100644
index 0000000..ca43fdc
--- /dev/null
+++ b/arch/lib/modules.c
@@ -0,0 +1,36 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-assert.h"
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+
+int modules_disabled = 0;
+char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
+
+static struct module_version_attribute g_empty_attr_buffer;
+/* we make the array empty by default because, really, we don't need */
+/* to look at the builtin params */
+const struct kernel_param __start___param[] = {{0}} ;
+const struct kernel_param __stop___param[] = {{0}} ;
+const struct module_version_attribute *__start___modver[] = {
+ &g_empty_attr_buffer};
+const struct module_version_attribute *__stop___modver[] = {
+ &g_empty_attr_buffer};
+
+struct module_attribute module_uevent;
+struct ctl_table usermodehelper_table[] = {};
+
+int __request_module(bool wait, const char *fmt, ...)
+{
+ /* we really should never be trying to load modules that way. */
+ /* lib_assert (false); */
+ return 0;
+}
diff --git a/arch/lib/pid.c b/arch/lib/pid.c
new file mode 100644
index 0000000..00cf7b6
--- /dev/null
+++ b/arch/lib/pid.c
@@ -0,0 +1,29 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/pid.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void put_pid(struct pid *pid)
+{
+}
+pid_t pid_vnr(struct pid *pid)
+{
+ return pid_nr(pid);
+}
+struct task_struct *find_task_by_vpid(pid_t nr)
+{
+ lib_assert(false);
+ return 0;
+}
+struct pid *find_get_pid(int nr)
+{
+ lib_assert(false);
+ return 0;
+}
diff --git a/arch/lib/print.c b/arch/lib/print.c
new file mode 100644
index 0000000..09b1bb5
--- /dev/null
+++ b/arch/lib/print.c
@@ -0,0 +1,56 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <stdarg.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int dmesg_restrict = 1;
+
+/* from lib/vsprintf.c */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+int printk(const char *fmt, ...)
+{
+ va_list args;
+ static char buf[256];
+ int value;
+
+ va_start(args, fmt);
+ value = vsnprintf(buf, 256, printk_skip_level(fmt), args);
+ lib_printf("<%c>%s", printk_get_level(fmt), buf);
+ va_end(args);
+ return value;
+}
+void panic(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+ lib_assert(false);
+}
+
+void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+
+ printk("%s:%d -- ", file, line);
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+}
+
+void warn_slowpath_null(const char *file, int line)
+{
+ printk("%s:%d -- ", file, line);
+}
+
diff --git a/arch/lib/proc.c b/arch/lib/proc.c
new file mode 100644
index 0000000..5507730
--- /dev/null
+++ b/arch/lib/proc.c
@@ -0,0 +1,34 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2014 Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/fs.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <net/net_namespace.h>
+#include "sim-types.h"
+#include "sim-assert.h"
+#include "fs/proc/internal.h" /* XXX */
+
+struct proc_dir_entry;
+static char proc_root_data[sizeof(struct proc_dir_entry) + 4];
+
+static struct proc_dir_entry *proc_root_sim =
+ (struct proc_dir_entry *)proc_root_data;
+
+void lib_proc_net_initialize(void)
+{
+ proc_root_sim->parent = proc_root_sim;
+ strcpy(proc_root_sim->name, "net");
+ proc_root_sim->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ proc_root_sim->subdir = RB_ROOT;
+ init_net.proc_net = proc_root_sim;
+ init_net.proc_net_stat = proc_mkdir("stat", proc_root_sim);
+}
+
diff --git a/arch/lib/random.c b/arch/lib/random.c
new file mode 100644
index 0000000..9fbb8bf
--- /dev/null
+++ b/arch/lib/random.c
@@ -0,0 +1,53 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include <linux/random.h>
+
+u32 random32(void)
+{
+ return lib_random();
+}
+
+void get_random_bytes(void *buf, int nbytes)
+{
+ char *p = (char *)buf;
+ int i;
+
+ for (i = 0; i < nbytes; i++)
+ p[i] = lib_random();
+}
+void srandom32(u32 entropy)
+{
+}
+
+u32 prandom_u32(void)
+{
+ return lib_random();
+}
+void prandom_seed(u32 entropy)
+{
+}
+
+void prandom_bytes(void *buf, size_t bytes)
+{
+ return get_random_bytes(buf, bytes);
+}
+
+#include <linux/sysctl.h>
+
+static int nothing;
+struct ctl_table random_table[] = {
+ {
+ .procname = "nothing",
+ .data = ¬hing,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ }
+};
diff --git a/arch/lib/sysfs.c b/arch/lib/sysfs.c
new file mode 100644
index 0000000..2def2ca
--- /dev/null
+++ b/arch/lib/sysfs.c
@@ -0,0 +1,83 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int sysfs_create_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+ return 0;
+}
+void sysfs_remove_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+}
+int sysfs_create_dir(struct kobject *kobj)
+{
+ return 0;
+}
+int sysfs_create_link(struct kobject *kobj, struct kobject *target,
+ const char *name)
+{
+ return 0;
+}
+int sysfs_move_dir(struct kobject *kobj,
+ struct kobject *new_parent_kobj)
+{
+ return 0;
+}
+void sysfs_remove_dir(struct kobject *kobj)
+{
+}
+void sysfs_remove_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+}
+int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
+{
+ return 0;
+}
+int __must_check sysfs_create_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return 0;
+}
+int sysfs_create_groups(struct kobject *kobj,
+ const struct attribute_group **groups)
+{
+ return 0;
+}
+int sysfs_schedule_callback(struct kobject *kobj,
+ void (*func)(
+ void *), void *data, struct module *owner)
+{
+ return 0;
+}
+void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
+ const char *name)
+{
+}
+void sysfs_exit_ns(enum kobj_ns_type type, const void *tag)
+{
+}
+void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
+{
+}
+int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
+{
+ kobj->sd = lib_malloc(sizeof(struct kernfs_node));
+ return 0;
+}
+int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
+ const void *ns)
+{
+ return 0;
+}
diff --git a/arch/lib/vmscan.c b/arch/lib/vmscan.c
new file mode 100644
index 0000000..3132f66
--- /dev/null
+++ b/arch/lib/vmscan.c
@@ -0,0 +1,26 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/shrinker.h>
+
+/*
+ * Add a shrinker callback to be called from the vm
+ */
+int register_shrinker(struct shrinker *shrinker)
+{
+ return 0;
+}
+
+/*
+ * Remove one
+ */
+void unregister_shrinker(struct shrinker *shrinker)
+{
+}
+
--
2.1.0
these files works as stubs in order to transparently run the other
kernel part (e.g., net/) on libos environment.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/include/asm/Kbuild | 57 +++++++++++++++++++++++++++++++++++
arch/lib/include/asm/atomic.h | 50 ++++++++++++++++++++++++++++++
arch/lib/include/asm/barrier.h | 8 +++++
arch/lib/include/asm/bitsperlong.h | 12 ++++++++
arch/lib/include/asm/current.h | 7 +++++
arch/lib/include/asm/elf.h | 10 ++++++
arch/lib/include/asm/hardirq.h | 8 +++++
arch/lib/include/asm/page.h | 14 +++++++++
arch/lib/include/asm/pgtable.h | 30 ++++++++++++++++++
arch/lib/include/asm/processor.h | 19 ++++++++++++
arch/lib/include/asm/ptrace.h | 4 +++
arch/lib/include/asm/segment.h | 6 ++++
arch/lib/include/asm/sembuf.h | 4 +++
arch/lib/include/asm/shmbuf.h | 4 +++
arch/lib/include/asm/shmparam.h | 4 +++
arch/lib/include/asm/sigcontext.h | 6 ++++
arch/lib/include/asm/stat.h | 4 +++
arch/lib/include/asm/statfs.h | 4 +++
arch/lib/include/asm/swab.h | 7 +++++
arch/lib/include/asm/thread_info.h | 36 ++++++++++++++++++++++
arch/lib/include/asm/uaccess.h | 14 +++++++++
arch/lib/include/asm/unistd.h | 4 +++
arch/lib/include/uapi/asm/byteorder.h | 6 ++++
23 files changed, 318 insertions(+)
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
diff --git a/arch/lib/include/asm/Kbuild b/arch/lib/include/asm/Kbuild
new file mode 100644
index 0000000..c647b1c
--- /dev/null
+++ b/arch/lib/include/asm/Kbuild
@@ -0,0 +1,57 @@
+generic-y += auxvec.h
+generic-y += bitops.h
+generic-y += bug.h
+generic-y += cache.h
+generic-y += cacheflush.h
+generic-y += checksum.h
+generic-y += cputime.h
+generic-y += cmpxchg.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += exec.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += io.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq.h
+generic-y += irqflags.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += linkage.h
+generic-y += local.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += mmu.h
+generic-y += mmu_context.h
+generic-y += module.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += preempt.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += setup.h
+generic-y += signal.h
+generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += string.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += timex.h
+generic-y += tlbflush.h
+generic-y += types.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += unaligned.h
diff --git a/arch/lib/include/asm/atomic.h b/arch/lib/include/asm/atomic.h
new file mode 100644
index 0000000..41a49285
--- /dev/null
+++ b/arch/lib/include/asm/atomic.h
@@ -0,0 +1,50 @@
+#ifndef _ASM_SIM_ATOMIC_H
+#define _ASM_SIM_ATOMIC_H
+
+#include <linux/types.h>
+
+#if !defined(CONFIG_64BIT)
+typedef struct {
+ volatile long long counter;
+} atomic64_t;
+#endif
+
+#define ATOMIC64_INIT(i) { (i) }
+
+#define atomic64_read(v) (*(volatile long *)&(v)->counter)
+void atomic64_add(long i, atomic64_t *v);
+static inline void atomic64_sub(long i, atomic64_t *v)
+{
+ v->counter -= i;
+}
+static inline void atomic64_inc(atomic64_t *v)
+{
+ v->counter++;
+}
+int atomic64_sub_and_test(long i, atomic64_t *v);
+#define atomic64_dec(v) atomic64_sub(1LL, (v))
+int atomic64_dec_and_test(atomic64_t *v);
+int atomic64_inc_and_test(atomic64_t *v);
+int atomic64_add_negative(long i, atomic64_t *v);
+/* long atomic64_add_return(long i, atomic64_t *v); */
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+ v->counter += i;
+ return v->counter;
+}
+static inline void atomic64_set(atomic64_t *v, long i)
+{
+ v->counter = i;
+}
+long atomic64_sub_return(long i, atomic64_t *v);
+long atomic64_inc_return(atomic64_t *v);
+long atomic64_dec_return(atomic64_t *v);
+long atomic64_cmpxchg(atomic64_t *v, long old, long new);
+long atomic64_xchg(atomic64_t *v, long new);
+int atomic64_add_unless(atomic64_t *v, long a, long u);
+int atomic64_inc_is_not_zero(atomic64_t *v);
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+
+#include <asm-generic/atomic.h>
+
+#endif /* _ASM_SIM_ATOMIC_H */
diff --git a/arch/lib/include/asm/barrier.h b/arch/lib/include/asm/barrier.h
new file mode 100644
index 0000000..47adcc6
--- /dev/null
+++ b/arch/lib/include/asm/barrier.h
@@ -0,0 +1,8 @@
+#include <asm-generic/barrier.h>
+
+#undef smp_store_release
+#define smp_store_release(p, v) \
+ do { \
+ smp_mb(); \
+ ACCESS_ONCE(*p) = (v); \
+ } while (0)
diff --git a/arch/lib/include/asm/bitsperlong.h b/arch/lib/include/asm/bitsperlong.h
new file mode 100644
index 0000000..c7592f9
--- /dev/null
+++ b/arch/lib/include/asm/bitsperlong.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_SIM_BITSPERLONG_H
+#define _ASM_SIM_BITSPERLONG_H
+
+#ifdef CONFIG_64BIT
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif /* CONFIG_64BIT */
+
+#define __BITS_PER_LONG BITS_PER_LONG
+
+#endif /* _ASM_SIM_BITSPERLONG_H */
diff --git a/arch/lib/include/asm/current.h b/arch/lib/include/asm/current.h
new file mode 100644
index 0000000..62489cd
--- /dev/null
+++ b/arch/lib/include/asm/current.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_CURRENT_H
+#define _ASM_SIM_CURRENT_H
+
+struct task_struct *get_current(void);
+#define current get_current()
+
+#endif /* _ASM_SIM_CURRENT_H */
diff --git a/arch/lib/include/asm/elf.h b/arch/lib/include/asm/elf.h
new file mode 100644
index 0000000..a7396c9
--- /dev/null
+++ b/arch/lib/include/asm/elf.h
@@ -0,0 +1,10 @@
+#ifndef _ASM_SIM_ELF_H
+#define _ASM_SIM_ELF_H
+
+#if defined(CONFIG_64BIT)
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+
+#endif /* _ASM_SIM_ELF_H */
diff --git a/arch/lib/include/asm/hardirq.h b/arch/lib/include/asm/hardirq.h
new file mode 100644
index 0000000..47d47f9
--- /dev/null
+++ b/arch/lib/include/asm/hardirq.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_SIM_HARDIRQ_H
+#define _ASM_SIM_HARDIRQ_H
+
+extern unsigned int interrupt_pending;
+
+#define local_softirq_pending() (interrupt_pending)
+
+#endif /* _ASM_SIM_HARDIRQ_H */
diff --git a/arch/lib/include/asm/page.h b/arch/lib/include/asm/page.h
new file mode 100644
index 0000000..8c0aa74
--- /dev/null
+++ b/arch/lib/include/asm/page.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_PAGE_H
+#define _ASM_SIM_PAGE_H
+
+typedef struct {} pud_t;
+
+#define THREAD_ORDER 1
+#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+
+#define WANT_PAGE_VIRTUAL 1
+
+#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
+
+#endif /* _ASM_SIM_PAGE_H */
diff --git a/arch/lib/include/asm/pgtable.h b/arch/lib/include/asm/pgtable.h
new file mode 100644
index 0000000..ce599c8
--- /dev/null
+++ b/arch/lib/include/asm/pgtable.h
@@ -0,0 +1,30 @@
+#ifndef _ASM_SIM_PGTABLE_H
+#define _ASM_SIM_PGTABLE_H
+
+#define PAGE_KERNEL ((pgprot_t) {0 })
+
+#define arch_start_context_switch(prev) do {} while (0)
+
+#define kern_addr_valid(addr)(1)
+#define pte_file(pte)(1)
+/* Encode and de-code a swap entry */
+#define __swp_type(x) (((x).val >> 5) & 0x1f)
+#define __swp_offset(x) ((x).val >> 11)
+#define __swp_entry(type, offset) \
+ ((swp_entry_t) {((type) << 5) | ((offset) << 11) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) {pte_val((pte)) })
+#define __swp_entry_to_pte(x) ((pte_t) {(x).val })
+#define pmd_page(pmd) (struct page *)(pmd_val(pmd) & PAGE_MASK)
+#define pgtable_cache_init() do { } while (0)
+
+static inline int pte_swp_soft_dirty(pte_t pte)
+{
+ return 0;
+}
+
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+ return pte;
+}
+
+#endif /* _ASM_SIM_PGTABLE_H */
diff --git a/arch/lib/include/asm/processor.h b/arch/lib/include/asm/processor.h
new file mode 100644
index 0000000..b673ee0
--- /dev/null
+++ b/arch/lib/include/asm/processor.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_SIM_PROCESSOR_H
+#define _ASM_SIM_PROCESSOR_H
+
+struct thread_struct {};
+
+#define cpu_relax()
+#define cpu_relax_lowlatency() cpu_relax()
+#define KSTK_ESP(tsk) (0)
+
+void *current_text_addr(void);
+
+#define TASK_SIZE ((~(long)0))
+
+#define thread_saved_pc(x) (unsigned long)0
+#define task_pt_regs(t) NULL
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+#endif /* _ASM_SIM_PROCESSOR_H */
diff --git a/arch/lib/include/asm/ptrace.h b/arch/lib/include/asm/ptrace.h
new file mode 100644
index 0000000..ddd9708
--- /dev/null
+++ b/arch/lib/include/asm/ptrace.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_PTRACE_H
+#define _ASM_SIM_PTRACE_H
+
+#endif /* _ASM_SIM_PTRACE_H */
diff --git a/arch/lib/include/asm/segment.h b/arch/lib/include/asm/segment.h
new file mode 100644
index 0000000..e056922
--- /dev/null
+++ b/arch/lib/include/asm/segment.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SEGMENT_H
+#define _ASM_SIM_SEGMENT_H
+
+typedef struct { int seg; } mm_segment_t;
+
+#endif /* _ASM_SIM_SEGMENT_H */
diff --git a/arch/lib/include/asm/sembuf.h b/arch/lib/include/asm/sembuf.h
new file mode 100644
index 0000000..d64927b
--- /dev/null
+++ b/arch/lib/include/asm/sembuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SEMBUF_H
+#define _ASM_SIM_SEMBUF_H
+
+#endif /* _ASM_SIM_SEMBUF_H */
diff --git a/arch/lib/include/asm/shmbuf.h b/arch/lib/include/asm/shmbuf.h
new file mode 100644
index 0000000..42d0a71
--- /dev/null
+++ b/arch/lib/include/asm/shmbuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMBUF_H
+#define _ASM_SIM_SHMBUF_H
+
+#endif /* _ASM_SIM_SHMBUF_H */
diff --git a/arch/lib/include/asm/shmparam.h b/arch/lib/include/asm/shmparam.h
new file mode 100644
index 0000000..3410f1b
--- /dev/null
+++ b/arch/lib/include/asm/shmparam.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMPARAM_H
+#define _ASM_SIM_SHMPARAM_H
+
+#endif /* _ASM_SIM_SHMPARAM_H */
diff --git a/arch/lib/include/asm/sigcontext.h b/arch/lib/include/asm/sigcontext.h
new file mode 100644
index 0000000..230b4b5
--- /dev/null
+++ b/arch/lib/include/asm/sigcontext.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SIGCONTEXT_H
+#define _ASM_SIM_SIGCONTEXT_H
+
+struct sigcontext {};
+
+#endif /* _ASM_SIM_SIGCONTEXT_H */
diff --git a/arch/lib/include/asm/stat.h b/arch/lib/include/asm/stat.h
new file mode 100644
index 0000000..80fa2cb
--- /dev/null
+++ b/arch/lib/include/asm/stat.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STAT_H
+#define _ASM_SIM_STAT_H
+
+#endif /* _ASM_SIM_STAT_H */
diff --git a/arch/lib/include/asm/statfs.h b/arch/lib/include/asm/statfs.h
new file mode 100644
index 0000000..881ce51
--- /dev/null
+++ b/arch/lib/include/asm/statfs.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STATFS_H
+#define _ASM_SIM_STATFS_H
+
+#endif /* _ASM_SIM_STATFS_H */
diff --git a/arch/lib/include/asm/swab.h b/arch/lib/include/asm/swab.h
new file mode 100644
index 0000000..d81376a
--- /dev/null
+++ b/arch/lib/include/asm/swab.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_SWAB_H
+#define _ASM_SIM_SWAB_H
+
+#include <linux/types.h>
+
+
+#endif /* _ASM_SIM_SWAB_H */
diff --git a/arch/lib/include/asm/thread_info.h b/arch/lib/include/asm/thread_info.h
new file mode 100644
index 0000000..ec316c6
--- /dev/null
+++ b/arch/lib/include/asm/thread_info.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_SIM_THREAD_INFO_H
+#define _ASM_SIM_THREAD_INFO_H
+
+#define TIF_NEED_RESCHED 1
+#define TIF_SIGPENDING 2
+#define TIF_MEMDIE 5
+
+struct thread_info {
+ __u32 flags;
+ int preempt_count;
+ struct task_struct *task;
+ struct restart_block restart_block;
+};
+
+struct thread_info *current_thread_info(void);
+struct thread_info *alloc_thread_info(struct task_struct *task);
+void free_thread_info(struct thread_info *ti);
+
+#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+}
+static inline void clear_restore_sigmask(void)
+{
+}
+static inline bool test_restore_sigmask(void)
+{
+ return true;
+}
+static inline bool test_and_clear_restore_sigmask(void)
+{
+ return true;
+}
+
+#endif /* _ASM_SIM_THREAD_INFO_H */
diff --git a/arch/lib/include/asm/uaccess.h b/arch/lib/include/asm/uaccess.h
new file mode 100644
index 0000000..74f973b
--- /dev/null
+++ b/arch/lib/include/asm/uaccess.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_UACCESS_H
+#define _ASM_SIM_UACCESS_H
+
+#define KERNEL_DS ((mm_segment_t) {0 })
+#define USER_DS ((mm_segment_t) {0 })
+#define get_fs() KERNEL_DS
+#define get_ds() USER_DS
+#define set_fs(x) do {} while ((x.seg) != (x.seg))
+
+#define __access_ok(addr, size) (1)
+
+#include <asm-generic/uaccess.h>
+
+#endif /* _ASM_SIM_UACCESS_H */
diff --git a/arch/lib/include/asm/unistd.h b/arch/lib/include/asm/unistd.h
new file mode 100644
index 0000000..6b482b4
--- /dev/null
+++ b/arch/lib/include/asm/unistd.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_UNISTD_H
+#define _ASM_SIM_UNISTD_H
+
+#endif /* _ASM_SIM_UNISTD_H */
diff --git a/arch/lib/include/uapi/asm/byteorder.h b/arch/lib/include/uapi/asm/byteorder.h
new file mode 100644
index 0000000..b13a7a8
--- /dev/null
+++ b/arch/lib/include/uapi/asm/byteorder.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_BYTEORDER_H
+#define _ASM_X86_BYTEORDER_H
+
+#include <linux/byteorder/little_endian.h>
+
+#endif /* _ASM_X86_BYTEORDER_H */
--
2.1.0
document and build scripts for libos architecture.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 8 +
arch/lib/Kconfig | 124 +++++++
arch/lib/Makefile | 251 +++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/generate-linker-script.py | 50 +++
arch/lib/processor.mk | 7 +
9 files changed, 1291 insertions(+)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/defconfig
create mode 100755 arch/lib/generate-linker-script.py
create mode 100644 arch/lib/processor.mk
diff --git a/Documentation/virtual/libos-howto.txt b/Documentation/virtual/libos-howto.txt
new file mode 100644
index 0000000..fbf7946
--- /dev/null
+++ b/Documentation/virtual/libos-howto.txt
@@ -0,0 +1,144 @@
+Library operating system (libos) version of Linux
+=================================================
+
+* Overview
+
+New hardware independent architecture 'arch/lib', configured by
+CONFIG_LIB gives you two features.
+
+- network stack in userspace (NUSE)
+ NUSE will give you a personalized network stack for each application
+ without replacing host operating system.
+
+- network simulator integration, which is called Direct Code Execution (DCE)
+ DCE will give us a network simulation environment with Linux network stack
+ to investigate the detail behavior protocol implementation with a flexible
+ network configuration. This is also useful for the testing environment.
+
+(- more abstracted implementation of underlying platform will be a future
+ direction (e.g., rump hypercall))
+
+In both features, Linux kernel network stack is running on top of
+userspace application with a linked or dynamically loaded library.
+
+They have their own, isolated network stack from host operating system
+so they are configured different IP addresses as other virtualization
+methods do.
+
+
+* How different with others ?
+
+- User-mode Linux (UML)
+
+UML is a way to execute Linux kernel code as a userspace
+application. It is completely isolated from host kernel but can host
+arbitrary userspace applications on top of UML.
+
+- namespace / container
+
+Container technologies with namespace brings a process-level isolation
+to host multiple network entities but shares the kernel among
+processes, which prevents to introduce new features implemented in
+kernel space.
+
+
+* How to build it ?
+
+configuration of arch/lib follows a standard configuration of kernel.
+
+ make defconfig ARCH=lib
+
+or
+
+ make menuconfig ARCH=lib
+
+then you can build a set of libraries for libos.
+
+ make library ARCH=lib
+
+This will give you a shared library file liblinux-$(KERNELVERSION).so
+in the top directory.
+
+* Hello world
+
+you may first need to configure a configuration file, named
+'nuse.conf' so that the library version of network stack can know what
+kind of IP configuration should be used. There is an example file
+at arch/lib/nuse.conf.sample: you may copy and modify it for your purpose.
+
+ sudo NUSECONF=nuse.conf ./nuse ping http://www.google.com
+
+
+
+* Example use cases
+- regression test with Direct Code Execution (DCE)
+
+'make test' by DCE gives a test platform for networking code, with the
+help of network simulator facilities like link delay/bandwidth/drop
+configurations, large network topology with userspace routing protocol
+daemons, etc.
+
+An interesting feature is the determinism of any test executions. A
+test script always gives same results in every execution if there is
+no modification on test target code.
+
+For the first step, you need to obtain network simulator
+environment. 'make testbin' does all the stuff for the preparation.
+
+% make testbin -C tools/testing/libos
+
+Then, you can 'make test' for your code.
+
+% make test ARCH=lib
+
+ PASS: TestSuite netlink-socket
+ PASS: TestSuite process-manager
+ PASS: TestSuite dce-cradle
+ PASS: TestSuite dce-mptcp
+ PASS: TestSuite dce-umip
+ PASS: TestSuite dce-quagga
+ PASS: Example dce-tcp-simple
+ PASS: Example dce-udp-simple
+
+
+- userspace network stack (NUSE)
+
+an application can use its own network stack, distinct from host network stack
+in order to personalize any network feature to the application specific one.
+The 'nuse' wrapper script, based on LD_PRELOAD technique, carefully replaces
+socket API and redirects system calls to the network stack library, provided by
+this framework.
+
+the network stack can be used with any kind of raw-socket like
+technologies such as Intel DPDK, netmap, etc.
+
+
+
+* Files / External Repository
+
+The kernel source tree (i.e., arch/lib) only contains a shared part of
+applications (NUSE/DCE). Pure userspace part is managed at a different
+repository, called Linux-libos-tools: it is automatically downloaded
+during make library.
+
+ https://github.com/libos-nuse/linux-libos-tools
+
+
+* More information
+- [email protected] (LibOS in general and NUSE related questions)
+- [email protected] (ns-3 related questions)
+- articles, slides
+ Experimentation Tools for Networking Research (Lacage, 2010)
+ http://cutebugs.net/files/thesis.pdf
+ Direct code execution: revisiting library OS architecture for reproducible
+ network experiments (Tazaki et al., 2013)
+ http://dx.doi.org/10.1145/2535372.2535374
+ Library Operating System with Mainline Linux Network Stack (Tazaki et al., 2015)
+ https://www.netdev01.org/docs/netdev01-tazaki-libos.pdf (slides)
+
+
+* Authors
+ Mathieu Lacage <[email protected]>
+ Hajime Tazaki <[email protected]>
+ Frederic Urbani <[email protected]>
+ Ryo Nakamura <[email protected]>
diff --git a/MAINTAINERS b/MAINTAINERS
index 3589d67..ae88290 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5699,6 +5699,15 @@ M: Sasha Levin <[email protected]>
S: Maintained
F: tools/lib/lockdep/
+LIBRARY OS (LIBOS)
+M: Hajime Tazaki <[email protected]>
+L: [email protected]
+W: http://libos-nuse.github.io/
+S: Maintained
+F: Documentation/virtual/libos-howto.txt
+F: arch/lib/
+F: tools/testing/libos/
+
LINUX FOR IBM pSERIES (RS/6000)
M: Paul Mackerras <[email protected]>
W: http://www.ibm.com/linux/ltc/projects/ppc
diff --git a/arch/lib/.gitignore b/arch/lib/.gitignore
new file mode 100644
index 0000000..9f48573
--- /dev/null
+++ b/arch/lib/.gitignore
@@ -0,0 +1,8 @@
+linker.lds
+autoconf.h
+objs.mk
+timeconst.h
+hz.bc
+crc32table.h
+*.d
+tools
diff --git a/arch/lib/Kconfig b/arch/lib/Kconfig
new file mode 100644
index 0000000..3dfa269
--- /dev/null
+++ b/arch/lib/Kconfig
@@ -0,0 +1,124 @@
+menuconfig LIB
+ bool "LibOS-specific options"
+ def_bool n
+ select PROC_FS
+ select PROC_SYSCTL
+ select SYSCTL
+ select SYSFS
+ help
+ The 'lib' architecture is a library (user-mode) version of
+ the linux kernel that includes only its network stack and is
+ used within the userspace application, and ns-3 simulator.
+ For more information, about ns-3, see http://www.nsnam.org.
+
+config EXPERIMENTAL
+ def_bool y
+
+config MMU
+ def_bool n
+config FPU
+ def_bool n
+config SMP
+ def_bool n
+
+config ARCH
+ string
+ option env="ARCH"
+
+config KTIME_SCALAR
+ def_bool y
+
+config MODULES
+ def_bool y
+ option modules
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+config PRINTK
+ def_bool y
+
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+config GENERIC_FIND_NEXT_BIT
+ def_bool y
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+config NO_HZ
+ def_bool y
+
+config BASE_FULL
+ def_bool n
+
+config SELECT_MEMORY_MODEL
+ def_bool n
+
+config FLAT_NODE_MEM_MAP
+ def_bool n
+
+config PAGEFLAGS_EXTENDED
+ def_bool n
+
+config VIRT_TO_BUS
+ def_bool n
+
+config HAS_DMA
+ def_bool n
+
+config HZ
+ int
+ default 250
+
+config TINY_RCU
+ def_bool y
+
+config HZ_250
+ def_bool y
+
+config BASE_SMALL
+ int
+ default 1
+
+config SPLIT_PTLOCK_CPUS
+ int
+ default 1
+
+config FLATMEM
+ def_bool y
+
+config SYSCTL
+ def_bool y
+
+config PROC_FS
+ def_bool y
+
+config SYSFS
+ def_bool y
+
+config PROC_SYSCTL
+ def_bool y
+
+config NETDEVICES
+ def_bool y
+
+config SLIB
+ def_bool y
+
+source "net/Kconfig"
+
+source "drivers/base/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+
diff --git a/arch/lib/Makefile b/arch/lib/Makefile
new file mode 100644
index 0000000..d8a0bf9
--- /dev/null
+++ b/arch/lib/Makefile
@@ -0,0 +1,251 @@
+ARCH_DIR := arch/lib
+SRCDIR=$(dir $(firstword $(MAKEFILE_LIST)))
+DCE_TESTDIR=$(srctree)/tools/testing/libos/
+KBUILD_KCONFIG := arch/$(ARCH)/Kconfig
+
+CC = gcc
+GCCVERSIONGTEQ48 := $(shell expr `gcc -dumpversion` \>= 4.8)
+ifeq "$(GCCVERSIONGTEQ48)" "1"
+ NO_TREE_LOOP_OPT += -fno-tree-loop-distribute-patterns
+endif
+
+
+-include $(ARCH_DIR)/objs.mk
+-include $(srctree)/.config
+include $(srctree)/scripts/Kbuild.include
+include $(ARCH_DIR)/processor.mk
+
+# targets
+LIBOS_TOOLS=$(ARCH_DIR)/tools
+LIBOS_GIT_REPO=git://github.com/libos-nuse/linux-libos-tools
+KERNEL_LIB=liblinux-$(KERNELVERSION).so
+
+ALL_OBJS=$(OBJS) $(KERNEL_LIB) $(modules) $(all-obj-for-clean)
+
+# auto generated files
+AUTOGENS=$(CRC32TABLE) $(COMPILE_H) $(BOUNDS_H) $(ARCH_DIR)/timeconst.h $(ARCH_DIR)/linker.lds
+COMPILE_H=$(srctree)/include/generated/compile.h
+BOUNDS_H=$(srctree)/include/generated/bounds.h
+
+# from lib/Makefile
+CRC32TABLE = $(ARCH_DIR)/crc32table.h
+hostprogs-y := $(srctree)/lib/gen_crc32table
+clean-files := crc32table.h
+
+# sources and objects
+LIB_SRC=\
+lib.c lib-device.c lib-socket.c random.c softirq.c time.c \
+timer.c hrtimer.c sched.c workqueue.c \
+print.c tasklet.c tasklet-hrtimer.c \
+glue.c fs.c sysctl.c proc.c sysfs.c \
+capability.c pid.c modules.c filemap.c vmscan.c
+
+LIB_OBJ=$(addprefix $(ARCH_DIR)/,$(addsuffix .o,$(basename $(LIB_SRC))))
+LIB_DEPS=$(addprefix $(ARCH_DIR)/.,$(addsuffix .o.cmd,$(basename $(LIB_SRC))))
+-include $(LIB_DEPS)
+
+DEPENDS=$(addprefix $(ARCH_DIR)/.,\
+ $(addsuffix .d,$(basename $(LIB_SRC)))\
+ )
+
+# options
+COV?=no
+cov_yes=-fprofile-arcs -ftest-coverage
+cov_no=
+covl_yes=-fprofile-arcs
+covl_no=
+OPT?=yes
+opt_yes=-O3 -fomit-frame-pointer $(NO_TREE_LOOP_OPT)
+opt_no=-O0
+PIC?=yes
+pic_yes=-fpic -DPIC
+pic_no=-mcmodel=large
+PIC_CFLAGS=$(pic_$(PIC))
+
+# flags
+CFLAGS_USPACE= \
+ -Wp,-MD,$(depfile) $(opt_$(OPT)) -g3 -Wall -Wstrict-prototypes -Wno-trigraphs \
+ -fno-inline -fno-strict-aliasing -fno-common \
+ -fno-delete-null-pointer-checks -fno-builtin \
+ -fno-stack-protector -Wno-unused -Wno-pointer-sign \
+ $(PIC_CFLAGS) -D_DEBUG $(cov_$(COV)) -I$(ARCH_DIR)/include
+
+CFLAGS+= \
+ $(CFLAGS_USPACE) -nostdinc -D__KERNEL__ -iwithprefix $(srctree)/include \
+ -DKBUILD_BASENAME=\"clnt\" -DKBUILD_MODNAME=\"nsc\" -DMODVERSIONS \
+ -DEXPORT_SYMTAB \
+ -U__FreeBSD__ -D__linux__=1 -Dlinux=1 -D__linux=1 \
+ -DCONFIG_DEFAULT_HOSTNAME=\"lib\" \
+ -I$(ARCH_DIR)/include/generated/uapi \
+ -I$(ARCH_DIR)/include/generated \
+ -I$(srctree)/include -I$(ARCH_DIR)/include/uapi \
+ -I$(srctree)/include/uapi -I$(srctree)/include/generated/uapi \
+ -include $(srctree)/include/linux/kconfig.h \
+ -I$(ARCH_DIR) -I.
+
+ifeq ($(PROCESSOR_SIZE),64)
+CFLAGS+= -DCONFIG_64BIT
+endif
+
+LDFLAGS += -shared -nodefaultlibs -g3 -Wl,-O1 -Wl,-T$(ARCH_DIR)/linker.lds $(covl_$(COV))
+
+# targets
+
+modules:=
+all-obj-for-clean:=
+
+all: library modules
+
+# note: the directory order below matters to ensure that we match the kernel order
+dirs=kernel/ kernel/time/ kernel/rcu/ kernel/locking/ kernel/bpf/ mm/ fs/ fs/proc/ crypto/ lib/ drivers/base/ drivers/net/ net/ init/
+empty:=
+space:= $(empty) $(empty)
+colon:= :
+comma= ,
+kernel/_to_keep=notifier.o params.o sysctl.o \
+rwsem.o semaphore.o kfifo.o cred.o user.o groups.o ksysfs.o
+kernel/time/_to_keep=time.o
+kernel/rcu_to_keep=rcu/srcu.o rcu/pdate.o rcu/tiny.o
+kernel/locking_to_keep=locking/mutex.o
+kernel/bpf_to_keep=bpf/core.o
+mm/_to_keep=util.o list_lru.o slib.o
+crypto/_to_keep=aead.o ahash.o shash.o api.o algapi.o cipher.o compress.o proc.o \
+crc32c_generic.o
+drivers/base/_to_keep=class.o core.o bus.o dd.o driver.o devres.o module.o map.o
+drivers/net/_to_keep=loopback.o
+lib/_to_keep=klist.o kobject.o kref.o hweight.o int_sqrt.o checksum.o \
+find_last_bit.o find_next_bit.o bitmap.o nlattr.o idr.o libcrc32c.o \
+ctype.o string.o kasprintf.o rbtree.o sha1.o textsearch.o vsprintf.o \
+rwsem-spinlock.o scatterlist.o ratelimit.o hexdump.o dec_and_lock.o \
+div64.o dynamic_queue_limits.o md5.o kstrtox.o iovec.o lockref.o crc32.o \
+rhashtable.o iov_iter.o cmdline.o kobject_uevent.o
+fs/_to_keep=read_write.o libfs.o namei.o filesystems.o file.o file_table.o \
+dcache.o inode.o pipe.o char_dev.o splice.o no-block.o seq_file.o super.o \
+fcntl.o coredump.o
+fs/proc/_to_keep=proc_sysctl.o proc_net.o root.o generic.o inode.o
+init/_to_keep=version.o
+
+quiet_cmd_objsmk = OBJS-MK $@
+ cmd_objsmk = \
+ for i in 1; do \
+ $(foreach d,$(dirs), \
+ $(MAKE) -i -s -f $< srcdir=$(srctree)/$(d) \
+ objdir=$(srctree)/$(d) \
+ config=$(srctree)/.config \
+ to_keep=$(subst $(space),$(colon),$($(d)_to_keep)) print;) \
+ done > $@
+
+$(ARCH_DIR)/objs.mk: $(ARCH_DIR)/Makefile.print $(srctree)/.config $(ARCH_DIR)/Makefile
+ +$(call if_changed,objsmk)
+
+quiet_cmd_timeconst = GEN $@
+ cmd_timeconst = echo "hz=$(CONFIG_HZ)" > $(ARCH_DIR)/hz.bc ; \
+ bc $(ARCH_DIR)/hz.bc kernel/time/timeconst.bc > $@
+$(ARCH_DIR)/timeconst.h: $(srctree)/.config
+ $(call if_changed,timeconst)
+
+quiet_cmd_linker = GEN $@
+ cmd_linker = ld -shared --verbose | ./$^ > $@
+$(ARCH_DIR)/linker.lds: $(ARCH_DIR)/generate-linker-script.py
+ $(call if_changed,linker)
+
+quiet_cmd_crc32src = GEN $@
+ cmd_crc32src = $(MAKE) -f $(srctree)/Makefile silentoldconfig ; \
+ cc $^ -o $@
+$(srctree)/lib/gen_crc32table: $(srctree)/lib/gen_crc32table.c
+ $(call if_changed,crc32src)
+
+quiet_cmd_crc32 = GEN $@
+ cmd_crc32 = $< > $@
+
+$(CRC32TABLE): $(srctree)/lib/gen_crc32table
+ $(call if_changed,crc32)
+
+# copied from init/Makefile
+ chk_compile.h = :
+ quiet_chk_compile.h = echo ' CHK $@'
+silent_chk_compile.h = :
+$(COMPILE_H): include/generated/utsrelease.h asm-generic $(version_h)
+ @$($(quiet)chk_compile.h)
+ +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
+ "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)"
+
+# crafted from $(srctree)/Kbuild
+quiet_cmd_lib_bounds = GEN $@
+define cmd_lib_bounds
+ (set -e; \
+ echo "#ifndef GENERATED_BOUNDS_H"; \
+ echo "#define GENERATED_BOUNDS_H"; \
+ echo ""; \
+ echo "#define NR_PAGEFLAGS (__NR_PAGEFLAGS)"; \
+ echo "#define MAX_NR_ZONES (__MAX_NR_ZONES)"; \
+ echo ""; \
+ echo "#endif /* GENERATED_BOUNDS_H */") > $@
+endef
+
+$(BOUNDS_H):
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,lib_bounds)
+
+
+KERNEL_BUILTIN=$(addprefix $(srctree)/,$(addsuffix builtin.o,$(dirs)))
+OBJS=$(LIB_OBJ) $(foreach builtin,$(KERNEL_BUILTIN),$(if $($(builtin)),$($(builtin))))
+export OBJS KERNEL_LIB COV covl_yes covl_no
+
+quiet_cmd_cc = CC $@
+ cmd_cc = mkdir -p $(dir $@); \
+ $(CC) $(CFLAGS) -c $< -o $@
+quiet_cmd_linkko = KO $@
+ cmd_linkko = $(CC) -shared -o $@ -nostdlib $^
+quiet_cmd_builtin = BUILTIN $@
+ cmd_builtin = mkdir -p $(dir $(srctree)/$@); rm -f $(srctree)/$@; \
+ if test -n "$($(srctree)/$@)"; then for f in $($(srctree)/$@); \
+ do $(AR) Tcru $@ $$f; done; else $(AR) Tcru $@; fi
+
+%/builtin.o:
+ $(call if_changed,builtin)
+%.ko:%.o
+ $(call if_changed,linkko)
+%.o:%.c
+ $(call if_changed_dep,cc)
+
+library: $(KERNEL_LIB) $(LIBOS_TOOLS)
+modules: $(modules)
+
+$(LIBOS_TOOLS): $(KERNEL_LIB) Makefile FORCE
+ $(Q) if [ ! -d "$@" ]; then \
+ git clone $(LIBOS_GIT_REPO) $@ ;\
+ fi
+ $(Q) $(MAKE) -C $(LIBOS_TOOLS)
+
+install: modules library
+
+install-dir:
+
+$(KERNEL_LIB): $(ARCH_DIR)/objs.mk $(AUTOGENS) $(OBJS)
+ $(call if_changed,linklib)
+
+quiet_cmd_linklib = LIB $@
+ cmd_linklib = $(CC) -Wl,--whole-archive $(OBJS) $(LDFLAGS) -o $@; \
+ ln -s -f $(KERNEL_LIB) liblinux.so
+
+quiet_cmd_clean = CLEAN $@
+ cmd_clean = for f in $(foreach m,$(modules),$($(m))) ; do rm -f $$f 2>/dev/null; done ; \
+ for f in $(ALL_OBJS); do rm -f $$f; done 2>/dev/null ;\
+ rm -rf $(AUTOGENS) $(ARCH_DIR)/objs.mk 2>/dev/null ;\
+ if [ -d $(LIBOS_TOOLS) ]; then $(MAKE) -C $(LIBOS_TOOLS) clean ; fi
+
+archclean:
+ $(call if_changed,clean)
+
+.%.d:%.c $(srctree)/.config
+ $(Q) set -e; $(CC) -MM -MT $(<:.c=.o) $(CFLAGS) $< > $@
+
+deplib: $(DEPENDS)
+ -include $(DEPENDS)
+
+test:
+ $(Q) $(MAKE) -C $(DCE_TESTDIR)/
+
+.PHONY : clean deplib
+
diff --git a/arch/lib/Makefile.print b/arch/lib/Makefile.print
new file mode 100644
index 0000000..40e6db0
--- /dev/null
+++ b/arch/lib/Makefile.print
@@ -0,0 +1,45 @@
+# inherit $(objdir) $(config) $(srcdir) $(to_keep) from command-line
+
+include $(config)
+include $(srcdir)Makefile
+
+# fix minor nits for make version dependencies
+ifeq (3.82,$(firstword $(sort $(MAKE_VERSION) 3.82)))
+ SEPARATOR=
+else
+ SEPARATOR=/
+endif
+
+to_keep_list=$(subst :, ,$(to_keep))
+obj-y += $(lib-y)
+obj-m += $(lib-m)
+subdirs := $(filter %/, $(obj-y) $(obj-m))
+subdirs-y := $(filter %/, $(obj-y))
+subdirs-m := $(filter %/, $(obj-m))
+tmp1-obj-y=$(patsubst %/,%/builtin.o,$(obj-y))
+tmp1-obj-m=$(filter-out $(subdirs-m),$(obj-m))
+tmp2-obj-y=$(foreach m,$(tmp1-obj-y), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp2-obj-m=$(foreach m,$(tmp1-obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp3-obj-y=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-y)),$(tmp2-obj-y))
+tmp3-obj-m=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-m)),$(tmp2-obj-m))
+final-obj-y=$(tmp3-obj-y)
+final-obj-m=$(tmp3-obj-m)
+
+print: $(final-obj-m) $(subdirs)
+ @if test $(if $(final-obj-y),1); then \
+ echo -n $(objdir)builtin.o; echo -n "="; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n $(objdir)builtin.o; echo -n ": "; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n "-include "; echo $(addprefix $(objdir).,$(addsuffix ".cmd", $(final-obj-y))); \
+ echo -n "all-obj-for-clean+="; echo $(addprefix $(objdir),$(final-obj-y)) $(objdir)builtin.o; \
+ fi
+$(final-obj-m):
+ @echo -n "modules+="; echo $(addprefix $(objdir),$(@:.o=.ko))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n ": "
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n "="
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+$(subdirs):
+ @$(MAKE) -s -f $(firstword $(MAKEFILE_LIST)) objdir=$(objdir)$@$(SEPARATOR) config=$(config) srcdir=$(srcdir)$@$(SEPARATOR) to_keep=$(to_keep) print 2>/dev/null
+
+.PHONY : core
+.NOTPARALLEL : print $(subdirs) $(final-obj-m)
diff --git a/arch/lib/defconfig b/arch/lib/defconfig
new file mode 100644
index 0000000..9307e6f
--- /dev/null
+++ b/arch/lib/defconfig
@@ -0,0 +1,653 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux Kernel Configuration
+#
+CONFIG_LIB=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+# CONFIG_SMP is not set
+CONFIG_KTIME_SCALAR=y
+CONFIG_MODULES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_PRINTK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_NO_HZ=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_SELECT_MEMORY_MODEL is not set
+# CONFIG_FLAT_NODE_MEM_MAP is not set
+# CONFIG_PAGEFLAGS_EXTENDED is not set
+# CONFIG_VIRT_TO_BUS is not set
+# CONFIG_HAS_DMA is not set
+CONFIG_HZ=250
+CONFIG_TINY_RCU=y
+CONFIG_HZ_250=y
+CONFIG_BASE_SMALL=1
+CONFIG_SPLIT_PTLOCK_CPUS=1
+CONFIG_FLATMEM=y
+CONFIG_SYSCTL=y
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IP_TUNNEL=y
+CONFIG_NET_IPGRE=y
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_NET_IPVTI is not set
+CONFIG_NET_UDP_TUNNEL=m
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+# CONFIG_GENEVE is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_INET_UDP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+CONFIG_TCP_CONG_HSTCP=y
+CONFIG_TCP_CONG_HYBLA=y
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=y
+CONFIG_TCP_CONG_LP=y
+CONFIG_TCP_CONG_VENO=y
+CONFIG_TCP_CONG_YEAH=y
+CONFIG_TCP_CONG_ILLINOIS=y
+CONFIG_TCP_CONG_DCTCP=y
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_HYBLA is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_VENO is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_DCTCP is not set
+CONFIG_DEFAULT_RENO=y
+CONFIG_DEFAULT_TCP_CONG="reno"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+# CONFIG_IPV6_VTI is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=y
+# CONFIG_IPV6_GRE is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=m
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_ACCT=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_LOG_COMMON=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+CONFIG_NETFILTER_NETLINK_QUEUE_CT=y
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_NF_NAT_PROTO_DCCP=y
+CONFIG_NF_NAT_PROTO_UDPLITE=y
+CONFIG_NF_NAT_PROTO_SCTP=y
+CONFIG_NF_NAT_AMANDA=y
+CONFIG_NF_NAT_FTP=y
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_TFTP is not set
+CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_TABLES=y
+CONFIG_NF_TABLES_INET=y
+CONFIG_NFT_EXTHDR=y
+CONFIG_NFT_META=y
+CONFIG_NFT_CT=y
+CONFIG_NFT_RBTREE=y
+CONFIG_NFT_HASH=y
+CONFIG_NFT_COUNTER=y
+CONFIG_NFT_LOG=y
+CONFIG_NFT_LIMIT=y
+CONFIG_NFT_MASQ=y
+# CONFIG_NFT_REDIR is not set
+CONFIG_NFT_NAT=y
+# CONFIG_NFT_QUEUE is not set
+# CONFIG_NFT_REJECT is not set
+# CONFIG_NFT_REJECT_INET is not set
+# CONFIG_NFT_COMPAT is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+# CONFIG_NETFILTER_XT_SET is not set
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_NAT=y
+CONFIG_NETFILTER_XT_TARGET_NETMAP=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_RATEEST=y
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=y
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+CONFIG_NETFILTER_XT_MATCH_L2TP=m
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+CONFIG_IP_SET=y
+CONFIG_IP_SET_MAX=256
+# CONFIG_IP_SET_BITMAP_IP is not set
+# CONFIG_IP_SET_BITMAP_IPMAC is not set
+# CONFIG_IP_SET_BITMAP_PORT is not set
+# CONFIG_IP_SET_HASH_IP is not set
+# CONFIG_IP_SET_HASH_IPMARK is not set
+# CONFIG_IP_SET_HASH_IPPORT is not set
+# CONFIG_IP_SET_HASH_IPPORTIP is not set
+# CONFIG_IP_SET_HASH_IPPORTNET is not set
+# CONFIG_IP_SET_HASH_MAC is not set
+# CONFIG_IP_SET_HASH_NETPORTNET is not set
+# CONFIG_IP_SET_HASH_NET is not set
+# CONFIG_IP_SET_HASH_NETNET is not set
+# CONFIG_IP_SET_HASH_NETPORT is not set
+# CONFIG_IP_SET_HASH_NETIFACE is not set
+# CONFIG_IP_SET_LIST_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_NF_LOG_ARP is not set
+CONFIG_NF_LOG_IPV4=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_CHAIN_ROUTE_IPV4=y
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NFT_REJECT_IPV4 is not set
+# CONFIG_NF_TABLES_ARP is not set
+# CONFIG_NF_NAT_IPV4 is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_NF_TABLES_IPV6=y
+# CONFIG_NFT_CHAIN_ROUTE_IPV6 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NFT_REJECT_IPV6 is not set
+CONFIG_NF_LOG_IPV6=y
+# CONFIG_NF_NAT_IPV6 is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+
+#
+# DECnet: Netfilter Configuration
+#
+# CONFIG_DECNET_NF_GRABULATOR is not set
+# CONFIG_NF_TABLES_BRIDGE is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_IP_DCCP=y
+CONFIG_INET_DCCP_DIAG=y
+
+#
+# DCCP CCIDs Configuration
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+CONFIG_IP_SCTP=y
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE=y
+# CONFIG_SCTP_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_COOKIE_HMAC_SHA1 is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_L2TP=m
+# CONFIG_L2TP_V3 is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_VLAN_8021Q_MVRP is not set
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_PHONET=m
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_HSR is not set
+# CONFIG_NET_SWITCHDEV is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_GW=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_DEV=m
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_SJA1000=m
+# CONFIG_CAN_SJA1000_ISA is not set
+CONFIG_CAN_SJA1000_PLATFORM=m
+# CONFIG_CAN_C_CAN is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_CC770 is not set
+# CONFIG_CAN_SOFTING is not set
+CONFIG_CAN_DEBUG_DEVICES=y
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+
+#
+# Dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_BT=m
+CONFIG_BT_BREDR=y
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_LE=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+CONFIG_WIMAX=m
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_RFKILL=m
+# CONFIG_NET_9P is not set
+CONFIG_CAIF=m
+CONFIG_CAIF_DEBUG=y
+CONFIG_CAIF_NETDEV=m
+# CONFIG_CAIF_USB is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_MCRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+CONFIG_CRYPTO_CRCT10DIF=m
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_IO=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
diff --git a/arch/lib/generate-linker-script.py b/arch/lib/generate-linker-script.py
new file mode 100755
index 0000000..db3d7f8
--- /dev/null
+++ b/arch/lib/generate-linker-script.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+import re
+
+def linker_script(reading, writing):
+ delim = re.compile('^==')
+ end_of_ro = re.compile('^ *.gcc_except_table[^:]*:[ ]*ONLY_IF_RW')
+ skipping = True
+ for line in reading.readlines():
+ if delim.search (line) is not None:
+ if skipping:
+ skipping = False
+ continue
+ else:
+ skipping = True
+ if skipping:
+ continue
+ m = end_of_ro.search(line)
+ if m is not None:
+ skipping = False
+ initcall = """
+ /* taken from kernel script*/
+ . = ALIGN (CONSTANT (MAXPAGESIZE));
+ .initcall.init : AT(ADDR(.initcall.init)) {
+ __initcall_start = .;
+ *(.initcallearly.init)
+ *(.initcall0.init)
+ *(.initcall0s.init)
+ *(.initcall1.init)
+ *(.initcall1s.init)
+ *(.initcall2.init)
+ *(.initcall2s.init)
+ *(.initcall3.init)
+ *(.initcall3s.init)
+ *(.initcall4.init)
+ *(.initcall4s.init)
+ *(.initcall5.init)
+ *(.initcall5s.init)
+ *(.initcall6.init)
+ *(.initcall6s.init)
+ *(.initcall7.init)
+ *(.initcall7s.init)
+ __initcall_end = .;
+ }
+"""
+ writing.write (initcall)
+ writing.write(line)
+
+import sys
+linker_script (sys.stdin, sys.stdout)
diff --git a/arch/lib/processor.mk b/arch/lib/processor.mk
new file mode 100644
index 0000000..7331528
--- /dev/null
+++ b/arch/lib/processor.mk
@@ -0,0 +1,7 @@
+PROCESSOR=$(shell uname -m)
+PROCESSOR_x86_64=64
+PROCESSOR_i686=32
+PROCESSOR_i586=32
+PROCESSOR_i386=32
+PROCESSOR_i486=32
+PROCESSOR_SIZE=$(PROCESSOR_$(PROCESSOR))
--
2.1.0
These auxiliary files are used for testing and debugging of net/ code
with libos. a simple test is implemented with make test ARCH=lib.
Signed-off-by: Hajime Tazaki <[email protected]>
---
tools/testing/libos/.gitignore | 6 +++++
tools/testing/libos/Makefile | 38 +++++++++++++++++++++++++++
tools/testing/libos/README | 15 +++++++++++
tools/testing/libos/bisect.sh | 10 +++++++
tools/testing/libos/dce-test.sh | 23 ++++++++++++++++
tools/testing/libos/nuse-test.sh | 57 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 149 insertions(+)
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
diff --git a/tools/testing/libos/.gitignore b/tools/testing/libos/.gitignore
new file mode 100644
index 0000000..57a74a0
--- /dev/null
+++ b/tools/testing/libos/.gitignore
@@ -0,0 +1,6 @@
+*.pcap
+files-*
+bake
+buildtop
+core
+exitprocs
diff --git a/tools/testing/libos/Makefile b/tools/testing/libos/Makefile
new file mode 100644
index 0000000..3da25429
--- /dev/null
+++ b/tools/testing/libos/Makefile
@@ -0,0 +1,38 @@
+ADD_PARAM?=
+
+all: test
+
+bake:
+ hg clone http://code.nsnam.org/bake
+
+check_pkgs:
+ @./bake/bake.py check | grep Bazaar | grep OK || (echo "bzr is missing" && ./bake/bake.py check)
+ @./bake/bake.py check | grep autoreconf | grep OK || (echo "autotools is missing" && ./bake/bake.py check && exit 1)
+
+testbin: bake check_pkgs
+ @cp ../../../arch/lib/tools/bakeconf-linux.xml bake/bakeconf.xml
+ @mkdir -p buildtop/build/bin_dce
+ cd buildtop ; \
+ ../bake/bake.py configure -e dce-linux-inkernel $(BAKECONF_PARAMS)
+ cd buildtop ; \
+ ../bake/bake.py show --enabledTree | grep -v -E "pygoocanvas|graphviz|python-dev" | grep Missing && (echo "required packages are missing") || echo ""
+ cd buildtop ; \
+ ../bake/bake.py download ; \
+ ../bake/bake.py update ; \
+ ../bake/bake.py build
+
+test:
+ @./dce-test.sh ADD_PARAM=$(ADD_PARAM)
+
+test-valgrind:
+ @./dce-test.sh -g ADD_PARAM=$(ADD_PARAM)
+
+test-fault-injection:
+ @./dce-test.sh -f ADD_PARAM=$(ADD_PARAM)
+
+clean:
+# @rm -rf buildtop
+ @rm -f *.pcap
+ @rm -rf files-*
+ @rm -f exitprocs
+ @rm -f core
diff --git a/tools/testing/libos/README b/tools/testing/libos/README
new file mode 100644
index 0000000..51ac5a5
--- /dev/null
+++ b/tools/testing/libos/README
@@ -0,0 +1,15 @@
+
+- bisect.sh
+a sample script to bisect an issue of network stack code with the help
+of LibOS (and ns-3 network simulator). This was used to detect the issue
+for the following patch.
+
+http://patchwork.ozlabs.org/patch/436351/
+
+- dce-test.sh
+a test script invoked by 'make test ARCH=lib'. The contents of test
+scenario are implemented as test suites of ns-3 network simulator.
+
+- nuse-test.sh
+a simple test script for Network Stack in Userspace (NUSE).
+
diff --git a/tools/testing/libos/bisect.sh b/tools/testing/libos/bisect.sh
new file mode 100755
index 0000000..9377ac3
--- /dev/null
+++ b/tools/testing/libos/bisect.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+git merge origin/nuse --no-commit
+make clean ARCH=lib
+make library ARCH=lib OPT=no
+make test ARCH=lib ADD_PARAM=" -s dce-umip"
+RET=$?
+git reset --hard
+
+exit $RET
diff --git a/tools/testing/libos/dce-test.sh b/tools/testing/libos/dce-test.sh
new file mode 100755
index 0000000..e81e2d8
--- /dev/null
+++ b/tools/testing/libos/dce-test.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+#set -x
+export LD_LOG=symbol-fail
+#VERBOSE="-v"
+VALGRIND=""
+FAULT_INJECTION=""
+
+if [ "$1" = "-g" ] ; then
+ VALGRIND="-g"
+# Not implemneted yet.
+#elif [ "$1" = "-f" ] ; then
+# FAULT_INJECTION="-f"
+fi
+
+# FIXME
+#export NS_ATTRIBUTE_DEFAULT='ns3::DceManagerHelper::LoaderFactory=ns3::\
+#DlmLoaderFactory[];ns3::TaskManager::FiberManagerType=UcontextFiberManager'
+
+cd buildtop/source/ns-3-dce
+LD_LIBRARY_PATH=${srctree} ./test.py -n ${VALGRIND} ${FAULT_INJECTION}\
+ ${VERBOSE} ${ADD_PARAM}
diff --git a/tools/testing/libos/nuse-test.sh b/tools/testing/libos/nuse-test.sh
new file mode 100755
index 0000000..198e7e4
--- /dev/null
+++ b/tools/testing/libos/nuse-test.sh
@@ -0,0 +1,57 @@
+#!/bin/bash -e
+
+LIBOS_TOOLS=arch/lib/tools
+
+IFNAME=`ip route |grep default | awk '{print $5}'`
+GW=`ip route |grep default | awk '{print $3}'`
+#XXX
+IPADDR=`echo $GW | sed -r "s/([0-9]+\.[0-9]+\.[0-9]+\.)([0-9]+)$/\1\`expr \2 + 10\`/"`
+
+# ip route
+# ip address
+# ip link
+
+NUSE_CONF=/tmp/nuse.conf
+
+cat > ${NUSE_CONF} << ENDCONF
+
+interface ${IFNAME}
+ address ${IPADDR}
+ netmask 255.255.255.0
+ macaddr 00:01:01:01:01:02
+ viftype RAW
+
+route
+ network 0.0.0.0
+ netmask 0.0.0.0
+ gateway ${GW}
+
+ENDCONF
+
+cd ${LIBOS_TOOLS}
+sudo NUSECONF=${NUSE_CONF} ./nuse ping 127.0.0.1 -c 2
+
+# rump test
+sudo NUSECONF=${NUSE_CONF} ./nuse sleep 5 &
+
+sleep 2
+PID_SLEEP=`/bin/ls -ltr /tmp/rump-server-nuse.* | tail -1 | awk '{print $9}' | sed -e "s/.*rump-server-nuse\.//g" | sed "s/=//"`
+RUMP_URL=unix:///tmp/rump-server-nuse.$PID_SLEEP
+# ls -ltr /tmp/*
+
+sudo chmod 777 /tmp/rump-server-nuse.$PID_SLEEP
+LD_PRELOAD=./libnuse-hijack.so RUMPHIJACK=socket=all \
+ RUMP_SERVER=$RUMP_URL ip addr show
+
+wait %1
+
+if [ "$1" == "--extended" ] ; then
+sudo NUSECONF=${NUSE_CONF} ./nuse ping ${GW} -c 2
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 2000 -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 8 -u -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse dig http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse host http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse nslookup http://www.google.com
+#sudo NUSECONF=${NUSE_CONF} ./nuse nc http://www.google.com 80
+sudo NUSECONF=${NUSE_CONF} ./nuse wget http://www.google.com -O -
+fi
--
2.1.0
Some random observations while I'm still trying to wrap my head around
all this (which might take quite some time).
On Sun, 2015-04-19 at 22:28 +0900, Hajime Tazaki wrote:
> --- /dev/null
> +++ b/arch/lib/Kconfig
> @@ -0,0 +1,124 @@
> +menuconfig LIB
> + bool "LibOS-specific options"
> + def_bool n
This is the start of the Kconfig parse for lib. (That would basically
still be true even if you didn't set KBUILD_KCONFIG, see below.) So why
not do something like all arches do:
config LIB
def_bool y
select [...]
Ie, why would someone want to build for ARCH=lib and still not set LIB?
> + select PROC_FS
> + select PROC_SYSCTL
> + select SYSCTL
> + select SYSFS
> + help
> + The 'lib' architecture is a library (user-mode) version of
> + the linux kernel that includes only its network stack and is
> + used within the userspace application, and ns-3 simulator.
> + For more information, about ns-3, see http://www.nsnam.org.
> +
> +config EXPERIMENTAL
> + def_bool y
Unneeded: removed treewide in, I think, 2014.
> +config MMU
> + def_bool n
Add empty line.
> +config FPU
> + def_bool n
Ditto.
> +config SMP
> + def_bool n
> +
> +config ARCH
> + string
> + option env="ARCH"
> +
> +config KTIME_SCALAR
> + def_bool y
This one is unused.
> +config MODULES
> + def_bool y
> + option modules
> +
> +config GENERIC_CSUM
> + def_bool y
> +
> +config GENERIC_BUG
> + def_bool y
> + depends on BUG
Add empty line here.
> +config PRINTK
> + def_bool y
> +
> +config RWSEM_GENERIC_SPINLOCK
> + def_bool y
> +
> +config GENERIC_FIND_NEXT_BIT
> + def_bool y
This one is unused too.
> +config GENERIC_HWEIGHT
> + def_bool y
> +
> +config TRACE_IRQFLAGS_SUPPORT
> + def_bool y
> +
> +config NO_HZ
> + def_bool y
> +
> +config BASE_FULL
> + def_bool n
> +
> +config SELECT_MEMORY_MODEL
> + def_bool n
> +
> +config FLAT_NODE_MEM_MAP
> + def_bool n
> +
> +config PAGEFLAGS_EXTENDED
> + def_bool n
> +
> +config VIRT_TO_BUS
> + def_bool n
> +
> +config HAS_DMA
> + def_bool n
> +
> +config HZ
> + int
> + default 250
> +
> +config TINY_RCU
> + def_bool y
> +
> +config HZ_250
> + def_bool y
> +
> +config BASE_SMALL
> + int
> + default 1
> +
> +config SPLIT_PTLOCK_CPUS
> + int
> + default 1
> +
> +config FLATMEM
> + def_bool y
> +
> +config SYSCTL
> + def_bool y
> +
> +config PROC_FS
> + def_bool y
> +
> +config SYSFS
> + def_bool y
> +
> +config PROC_SYSCTL
> + def_bool y
> +
> +config NETDEVICES
> + def_bool y
> +
> +config SLIB
> + def_bool y
You've also added SLIB to init/Kconfig in 02/10. But "make ARCH=lib
*config" will never visit init/Kconfig, will it? And, apparently, none
of SL[AOU]B are wanted for lib. So I think the entry for config SLIB in
that file can be dropped (as other arches will never see it because it
depends on LIB).
(Note that I haven't actually looked into all the Kconfig entries added
above. Perhaps I might do that. But I'm pretty sure most of the time all
I can say is: "I have no idea why this entry defaults to $VALUE".)
> +source "net/Kconfig"
> +
> +source "drivers/base/Kconfig"
> +
> +source "crypto/Kconfig"
> +
> +source "lib/Kconfig"
> +
> +
Trailing empty lines.
> diff --git a/arch/lib/Makefile b/arch/lib/Makefile
> new file mode 100644
> index 0000000..d8a0bf9
> --- /dev/null
> +++ b/arch/lib/Makefile
> @@ -0,0 +1,251 @@
> +ARCH_DIR := arch/lib
> +SRCDIR=$(dir $(firstword $(MAKEFILE_LIST)))
Do you use SRCDIR?
> +DCE_TESTDIR=$(srctree)/tools/testing/libos/
> +KBUILD_KCONFIG := arch/$(ARCH)/Kconfig
I think you copied this from arch/um/Makefile. But arch/um/ is, well,
special. Why should lib not start the kconfig parse in the file named
Kconfig? And if you want to start in arch/lib/Kconfig, it would be nice
to add a mainmenu (just like arch/x86/um/Kconfig does).
(I don't read Makefilese well enough to understand the rest of this
file. I think it's scary.)
> +
> +CC = gcc
> +GCCVERSIONGTEQ48 := $(shell expr `gcc -dumpversion` \>= 4.8)
> +ifeq "$(GCCVERSIONGTEQ48)" "1"
> + NO_TREE_LOOP_OPT += -fno-tree-loop-distribute-patterns
> +endif
> +
> +
> +-include $(ARCH_DIR)/objs.mk
> +-include $(srctree)/.config
> +include $(srctree)/scripts/Kbuild.include
> +include $(ARCH_DIR)/processor.mk
> +
> +# targets
> +LIBOS_TOOLS=$(ARCH_DIR)/tools
> +LIBOS_GIT_REPO=git://github.com/libos-nuse/linux-libos-tools
> +KERNEL_LIB=liblinux-$(KERNELVERSION).so
> +
> +ALL_OBJS=$(OBJS) $(KERNEL_LIB) $(modules) $(all-obj-for-clean)
> +
> +# auto generated files
> +AUTOGENS=$(CRC32TABLE) $(COMPILE_H) $(BOUNDS_H) $(ARCH_DIR)/timeconst.h $(ARCH_DIR)/linker.lds
> +COMPILE_H=$(srctree)/include/generated/compile.h
> +BOUNDS_H=$(srctree)/include/generated/bounds.h
> +
> +# from lib/Makefile
> +CRC32TABLE = $(ARCH_DIR)/crc32table.h
> +hostprogs-y := $(srctree)/lib/gen_crc32table
> +clean-files := crc32table.h
> +
> +# sources and objects
> +LIB_SRC=\
> +lib.c lib-device.c lib-socket.c random.c softirq.c time.c \
> +timer.c hrtimer.c sched.c workqueue.c \
> +print.c tasklet.c tasklet-hrtimer.c \
> +glue.c fs.c sysctl.c proc.c sysfs.c \
> +capability.c pid.c modules.c filemap.c vmscan.c
> +
> +LIB_OBJ=$(addprefix $(ARCH_DIR)/,$(addsuffix .o,$(basename $(LIB_SRC))))
> +LIB_DEPS=$(addprefix $(ARCH_DIR)/.,$(addsuffix .o.cmd,$(basename $(LIB_SRC))))
> +-include $(LIB_DEPS)
> +
> +DEPENDS=$(addprefix $(ARCH_DIR)/.,\
> + $(addsuffix .d,$(basename $(LIB_SRC)))\
> + )
> +
> +# options
> +COV?=no
> +cov_yes=-fprofile-arcs -ftest-coverage
> +cov_no=
> +covl_yes=-fprofile-arcs
> +covl_no=
> +OPT?=yes
> +opt_yes=-O3 -fomit-frame-pointer $(NO_TREE_LOOP_OPT)
> +opt_no=-O0
> +PIC?=yes
> +pic_yes=-fpic -DPIC
> +pic_no=-mcmodel=large
> +PIC_CFLAGS=$(pic_$(PIC))
> +
> +# flags
> +CFLAGS_USPACE= \
> + -Wp,-MD,$(depfile) $(opt_$(OPT)) -g3 -Wall -Wstrict-prototypes -Wno-trigraphs \
> + -fno-inline -fno-strict-aliasing -fno-common \
> + -fno-delete-null-pointer-checks -fno-builtin \
> + -fno-stack-protector -Wno-unused -Wno-pointer-sign \
> + $(PIC_CFLAGS) -D_DEBUG $(cov_$(COV)) -I$(ARCH_DIR)/include
> +
> +CFLAGS+= \
> + $(CFLAGS_USPACE) -nostdinc -D__KERNEL__ -iwithprefix $(srctree)/include \
> + -DKBUILD_BASENAME=\"clnt\" -DKBUILD_MODNAME=\"nsc\" -DMODVERSIONS \
> + -DEXPORT_SYMTAB \
> + -U__FreeBSD__ -D__linux__=1 -Dlinux=1 -D__linux=1 \
> + -DCONFIG_DEFAULT_HOSTNAME=\"lib\" \
> + -I$(ARCH_DIR)/include/generated/uapi \
> + -I$(ARCH_DIR)/include/generated \
> + -I$(srctree)/include -I$(ARCH_DIR)/include/uapi \
> + -I$(srctree)/include/uapi -I$(srctree)/include/generated/uapi \
> + -include $(srctree)/include/linux/kconfig.h \
> + -I$(ARCH_DIR) -I.
> +
> +ifeq ($(PROCESSOR_SIZE),64)
> +CFLAGS+= -DCONFIG_64BIT
> +endif
> +
> +LDFLAGS += -shared -nodefaultlibs -g3 -Wl,-O1 -Wl,-T$(ARCH_DIR)/linker.lds $(covl_$(COV))
> +
> +# targets
> +
> +modules:=
> +all-obj-for-clean:=
> +
> +all: library modules
> +
> +# note: the directory order below matters to ensure that we match the kernel order
> +dirs=kernel/ kernel/time/ kernel/rcu/ kernel/locking/ kernel/bpf/ mm/ fs/ fs/proc/ crypto/ lib/ drivers/base/ drivers/net/ net/ init/
> +empty:=
> +space:= $(empty) $(empty)
> +colon:= :
> +comma= ,
> +kernel/_to_keep=notifier.o params.o sysctl.o \
> +rwsem.o semaphore.o kfifo.o cred.o user.o groups.o ksysfs.o
> +kernel/time/_to_keep=time.o
> +kernel/rcu_to_keep=rcu/srcu.o rcu/pdate.o rcu/tiny.o
> +kernel/locking_to_keep=locking/mutex.o
> +kernel/bpf_to_keep=bpf/core.o
> +mm/_to_keep=util.o list_lru.o slib.o
> +crypto/_to_keep=aead.o ahash.o shash.o api.o algapi.o cipher.o compress.o proc.o \
> +crc32c_generic.o
> +drivers/base/_to_keep=class.o core.o bus.o dd.o driver.o devres.o module.o map.o
> +drivers/net/_to_keep=loopback.o
> +lib/_to_keep=klist.o kobject.o kref.o hweight.o int_sqrt.o checksum.o \
> +find_last_bit.o find_next_bit.o bitmap.o nlattr.o idr.o libcrc32c.o \
> +ctype.o string.o kasprintf.o rbtree.o sha1.o textsearch.o vsprintf.o \
> +rwsem-spinlock.o scatterlist.o ratelimit.o hexdump.o dec_and_lock.o \
> +div64.o dynamic_queue_limits.o md5.o kstrtox.o iovec.o lockref.o crc32.o \
> +rhashtable.o iov_iter.o cmdline.o kobject_uevent.o
> +fs/_to_keep=read_write.o libfs.o namei.o filesystems.o file.o file_table.o \
> +dcache.o inode.o pipe.o char_dev.o splice.o no-block.o seq_file.o super.o \
> +fcntl.o coredump.o
> +fs/proc/_to_keep=proc_sysctl.o proc_net.o root.o generic.o inode.o
> +init/_to_keep=version.o
> +
> +quiet_cmd_objsmk = OBJS-MK $@
> + cmd_objsmk = \
> + for i in 1; do \
> + $(foreach d,$(dirs), \
> + $(MAKE) -i -s -f $< srcdir=$(srctree)/$(d) \
> + objdir=$(srctree)/$(d) \
> + config=$(srctree)/.config \
> + to_keep=$(subst $(space),$(colon),$($(d)_to_keep)) print;) \
> + done > $@
> +
> +$(ARCH_DIR)/objs.mk: $(ARCH_DIR)/Makefile.print $(srctree)/.config $(ARCH_DIR)/Makefile
> + +$(call if_changed,objsmk)
> +
> +quiet_cmd_timeconst = GEN $@
> + cmd_timeconst = echo "hz=$(CONFIG_HZ)" > $(ARCH_DIR)/hz.bc ; \
> + bc $(ARCH_DIR)/hz.bc kernel/time/timeconst.bc > $@
> +$(ARCH_DIR)/timeconst.h: $(srctree)/.config
> + $(call if_changed,timeconst)
> +
> +quiet_cmd_linker = GEN $@
> + cmd_linker = ld -shared --verbose | ./$^ > $@
> +$(ARCH_DIR)/linker.lds: $(ARCH_DIR)/generate-linker-script.py
> + $(call if_changed,linker)
> +
> +quiet_cmd_crc32src = GEN $@
> + cmd_crc32src = $(MAKE) -f $(srctree)/Makefile silentoldconfig ; \
> + cc $^ -o $@
> +$(srctree)/lib/gen_crc32table: $(srctree)/lib/gen_crc32table.c
> + $(call if_changed,crc32src)
> +
> +quiet_cmd_crc32 = GEN $@
> + cmd_crc32 = $< > $@
> +
> +$(CRC32TABLE): $(srctree)/lib/gen_crc32table
> + $(call if_changed,crc32)
> +
> +# copied from init/Makefile
> + chk_compile.h = :
> + quiet_chk_compile.h = echo ' CHK $@'
> +silent_chk_compile.h = :
> +$(COMPILE_H): include/generated/utsrelease.h asm-generic $(version_h)
> + @$($(quiet)chk_compile.h)
> + +$(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \
> + "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)"
> +
> +# crafted from $(srctree)/Kbuild
> +quiet_cmd_lib_bounds = GEN $@
> +define cmd_lib_bounds
> + (set -e; \
> + echo "#ifndef GENERATED_BOUNDS_H"; \
> + echo "#define GENERATED_BOUNDS_H"; \
> + echo ""; \
> + echo "#define NR_PAGEFLAGS (__NR_PAGEFLAGS)"; \
> + echo "#define MAX_NR_ZONES (__MAX_NR_ZONES)"; \
> + echo ""; \
> + echo "#endif /* GENERATED_BOUNDS_H */") > $@
> +endef
> +
> +$(BOUNDS_H):
> + $(Q)mkdir -p $(dir $@)
> + $(call cmd,lib_bounds)
> +
> +
> +KERNEL_BUILTIN=$(addprefix $(srctree)/,$(addsuffix builtin.o,$(dirs)))
> +OBJS=$(LIB_OBJ) $(foreach builtin,$(KERNEL_BUILTIN),$(if $($(builtin)),$($(builtin))))
> +export OBJS KERNEL_LIB COV covl_yes covl_no
> +
> +quiet_cmd_cc = CC $@
> + cmd_cc = mkdir -p $(dir $@); \
> + $(CC) $(CFLAGS) -c $< -o $@
> +quiet_cmd_linkko = KO $@
> + cmd_linkko = $(CC) -shared -o $@ -nostdlib $^
> +quiet_cmd_builtin = BUILTIN $@
> + cmd_builtin = mkdir -p $(dir $(srctree)/$@); rm -f $(srctree)/$@; \
> + if test -n "$($(srctree)/$@)"; then for f in $($(srctree)/$@); \
> + do $(AR) Tcru $@ $$f; done; else $(AR) Tcru $@; fi
> +
> +%/builtin.o:
> + $(call if_changed,builtin)
> +%.ko:%.o
> + $(call if_changed,linkko)
> +%.o:%.c
> + $(call if_changed_dep,cc)
> +
> +library: $(KERNEL_LIB) $(LIBOS_TOOLS)
> +modules: $(modules)
> +
> +$(LIBOS_TOOLS): $(KERNEL_LIB) Makefile FORCE
> + $(Q) if [ ! -d "$@" ]; then \
> + git clone $(LIBOS_GIT_REPO) $@ ;\
> + fi
> + $(Q) $(MAKE) -C $(LIBOS_TOOLS)
> +
> +install: modules library
> +
> +install-dir:
> +
> +$(KERNEL_LIB): $(ARCH_DIR)/objs.mk $(AUTOGENS) $(OBJS)
> + $(call if_changed,linklib)
> +
> +quiet_cmd_linklib = LIB $@
> + cmd_linklib = $(CC) -Wl,--whole-archive $(OBJS) $(LDFLAGS) -o $@; \
> + ln -s -f $(KERNEL_LIB) liblinux.so
> +
> +quiet_cmd_clean = CLEAN $@
> + cmd_clean = for f in $(foreach m,$(modules),$($(m))) ; do rm -f $$f 2>/dev/null; done ; \
> + for f in $(ALL_OBJS); do rm -f $$f; done 2>/dev/null ;\
> + rm -rf $(AUTOGENS) $(ARCH_DIR)/objs.mk 2>/dev/null ;\
> + if [ -d $(LIBOS_TOOLS) ]; then $(MAKE) -C $(LIBOS_TOOLS) clean ; fi
> +
> +archclean:
> + $(call if_changed,clean)
> +
> +.%.d:%.c $(srctree)/.config
> + $(Q) set -e; $(CC) -MM -MT $(<:.c=.o) $(CFLAGS) $< > $@
> +
> +deplib: $(DEPENDS)
> + -include $(DEPENDS)
> +
> +test:
> + $(Q) $(MAKE) -C $(DCE_TESTDIR)/
> +
> +.PHONY : clean deplib
> +
> diff --git a/arch/lib/Makefile.print b/arch/lib/Makefile.print
> new file mode 100644
> index 0000000..40e6db0
> --- /dev/null
> +++ b/arch/lib/Makefile.print
> @@ -0,0 +1,45 @@
> +# inherit $(objdir) $(config) $(srcdir) $(to_keep) from command-line
> +
> +include $(config)
> +include $(srcdir)Makefile
> +
> +# fix minor nits for make version dependencies
> +ifeq (3.82,$(firstword $(sort $(MAKE_VERSION) 3.82)))
> + SEPARATOR=
> +else
> + SEPARATOR=/
> +endif
> +
> +to_keep_list=$(subst :, ,$(to_keep))
> +obj-y += $(lib-y)
> +obj-m += $(lib-m)
> +subdirs := $(filter %/, $(obj-y) $(obj-m))
> +subdirs-y := $(filter %/, $(obj-y))
> +subdirs-m := $(filter %/, $(obj-m))
> +tmp1-obj-y=$(patsubst %/,%/builtin.o,$(obj-y))
> +tmp1-obj-m=$(filter-out $(subdirs-m),$(obj-m))
> +tmp2-obj-y=$(foreach m,$(tmp1-obj-y), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
> +tmp2-obj-m=$(foreach m,$(tmp1-obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
> +tmp3-obj-y=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-y)),$(tmp2-obj-y))
> +tmp3-obj-m=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-m)),$(tmp2-obj-m))
> +final-obj-y=$(tmp3-obj-y)
> +final-obj-m=$(tmp3-obj-m)
> +
> +print: $(final-obj-m) $(subdirs)
> + @if test $(if $(final-obj-y),1); then \
> + echo -n $(objdir)builtin.o; echo -n "="; echo $(addprefix $(objdir),$(final-obj-y)); \
> + echo -n $(objdir)builtin.o; echo -n ": "; echo $(addprefix $(objdir),$(final-obj-y)); \
> + echo -n "-include "; echo $(addprefix $(objdir).,$(addsuffix ".cmd", $(final-obj-y))); \
> + echo -n "all-obj-for-clean+="; echo $(addprefix $(objdir),$(final-obj-y)) $(objdir)builtin.o; \
> + fi
> +$(final-obj-m):
> + @echo -n "modules+="; echo $(addprefix $(objdir),$(@:.o=.ko))
> + @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n ": "
> + @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
> + @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n "="
> + @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
> +$(subdirs):
> + @$(MAKE) -s -f $(firstword $(MAKEFILE_LIST)) objdir=$(objdir)$@$(SEPARATOR) config=$(config) srcdir=$(srcdir)$@$(SEPARATOR) to_keep=$(to_keep) print 2>/dev/null
When I did
make ARCH=lib menuconfig
I saw (among other things):
arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `lzo/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `lz4/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `lz4/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
arch/lib/Makefile.print:41: target `slip/' given more than once in the same rule.
I have no idea why. Unclean tree?
> +.PHONY : core
> +.NOTPARALLEL : print $(subdirs) $(final-obj-m)
> --- /dev/null
> +++ b/arch/lib/processor.mk
> @@ -0,0 +1,7 @@
> +PROCESSOR=$(shell uname -m)
> +PROCESSOR_x86_64=64
> +PROCESSOR_i686=32
> +PROCESSOR_i586=32
> +PROCESSOR_i386=32
> +PROCESSOR_i486=32
> +PROCESSOR_SIZE=$(PROCESSOR_$(PROCESSOR))
The rest of the tree appears to use BITS instead of PROCESSOR_SIZE. And
I do hope there's a cleaner way for lib to set PROCESSOR_SIZE than this.
Thanks,
Paul Bolle
Hi Paul,
many thanks for your review.
all the fixes will be on next patchset.
my comments are below.
At Mon, 20 Apr 2015 22:43:07 +0200,
Paul Bolle wrote:
>
> Some random observations while I'm still trying to wrap my head around
> all this (which might take quite some time).
>
> On Sun, 2015-04-19 at 22:28 +0900, Hajime Tazaki wrote:
> > --- /dev/null
> > +++ b/arch/lib/Kconfig
> > @@ -0,0 +1,124 @@
> > +menuconfig LIB
> > + bool "LibOS-specific options"
> > + def_bool n
>
> This is the start of the Kconfig parse for lib. (That would basically
> still be true even if you didn't set KBUILD_KCONFIG, see below.) So why
> not do something like all arches do:
>
> config LIB
> def_bool y
> select [...]
>
> Ie, why would someone want to build for ARCH=lib and still not set LIB?
agreed. fixed.
> > +config EXPERIMENTAL
> > + def_bool y
>
> Unneeded: removed treewide in, I think, 2014.
thanks. fixed.
> > +config MMU
> > + def_bool n
>
> Add empty line.
>
> > +config FPU
> > + def_bool n
>
> Ditto.
both are fixed.
> > +config KTIME_SCALAR
> > + def_bool y
>
> This one is unused.
deleted.
> > +config GENERIC_BUG
> > + def_bool y
> > + depends on BUG
>
> Add empty line here.
fixed.
> > +config GENERIC_FIND_NEXT_BIT
> > + def_bool y
>
> This one is unused too.
deleted.
> > +config SLIB
> > + def_bool y
>
> You've also added SLIB to init/Kconfig in 02/10. But "make ARCH=lib
> *config" will never visit init/Kconfig, will it? And, apparently, none
> of SL[AOU]B are wanted for lib. So I think the entry for config SLIB in
> that file can be dropped (as other arches will never see it because it
> depends on LIB).
>
> (Note that I haven't actually looked into all the Kconfig entries added
> above. Perhaps I might do that. But I'm pretty sure most of the time all
> I can say is: "I have no idea why this entry defaults to $VALUE".)
I intended to SLIB be a generic one, not only for the
arch/lib, as we discussed during v2 patch.
but, you're right: for the moment, no one uses SLIB, we
don't visit init/Kconfig, I dropped config SLIB entry from
init/Kconfig.
> > +source "net/Kconfig"
> > +
> > +source "drivers/base/Kconfig"
> > +
> > +source "crypto/Kconfig"
> > +
> > +source "lib/Kconfig"
> > +
> > +
>
> Trailing empty lines.
deleted. thanks.
> > diff --git a/arch/lib/Makefile b/arch/lib/Makefile
> > new file mode 100644
> > index 0000000..d8a0bf9
> > --- /dev/null
> > +++ b/arch/lib/Makefile
> > @@ -0,0 +1,251 @@
> > +ARCH_DIR := arch/lib
> > +SRCDIR=$(dir $(firstword $(MAKEFILE_LIST)))
>
> Do you use SRCDIR?
no. deleted the line.
> > +DCE_TESTDIR=$(srctree)/tools/testing/libos/
> > +KBUILD_KCONFIG := arch/$(ARCH)/Kconfig
>
> I think you copied this from arch/um/Makefile. But arch/um/ is, well,
> special. Why should lib not start the kconfig parse in the file named
> Kconfig? And if you want to start in arch/lib/Kconfig, it would be nice
> to add a mainmenu (just like arch/x86/um/Kconfig does).
right now, 'lib' only wants to eat arch/lib/Kconfig so that
build and link its wanted files instead of configurable one.
so I beilive arch/lib is also special as arch/um is.
I added a mainmenu btw. thanks.
> (I don't read Makefilese well enough to understand the rest of this
> file. I think it's scary.)
indeed. thank you again to review the cryptic files..
> When I did
> make ARCH=lib menuconfig
>
> I saw (among other things):
> arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
> arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
> arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
> arch/lib/Makefile.print:41: target `trace/' given more than once in the same rule.
> arch/lib/Makefile.print:41: target `lzo/' given more than once in the same rule.
(snip)
> arch/lib/Makefile.print:41: target `ppp/' given more than once in the same rule.
> arch/lib/Makefile.print:41: target `slip/' given more than once in the same rule.
>
> I have no idea why. Unclean tree?
this was due to inappropriate handling of the internal
directory listing procedure. fixed.
> > +.PHONY : core
> > +.NOTPARALLEL : print $(subdirs) $(final-obj-m)
>
> > --- /dev/null
> > +++ b/arch/lib/processor.mk
> > @@ -0,0 +1,7 @@
> > +PROCESSOR=$(shell uname -m)
> > +PROCESSOR_x86_64=64
> > +PROCESSOR_i686=32
> > +PROCESSOR_i586=32
> > +PROCESSOR_i386=32
> > +PROCESSOR_i486=32
> > +PROCESSOR_SIZE=$(PROCESSOR_$(PROCESSOR))
>
> The rest of the tree appears to use BITS instead of PROCESSOR_SIZE. And
> I do hope there's a cleaner way for lib to set PROCESSOR_SIZE than this.
the variable PROCESSOR_SIZE is only used by
arch/lib/Makefile, with the following lines.
> +ifeq ($(PROCESSOR_SIZE),64)
> +CFLAGS+= -DCONFIG_64BIT
> +endif
Thus it eventually uses CONFIG_64BIT.
I think a cleaner way is to follow the way of arch/um, like
below: I deleted processor.mk and PROCESSOR_SIZE variable.
ifeq ($(SUBARCH),x86)
ifeq ($(shell uname -m),x86_64)
CFLAGS+= -DCONFIG_64BIT
endif
though it's not able to cross-compile yet.
again, thank you so much.
I'll be back very soon (v4 patch).
-- Hajime
Hi!
Am 19.04.2015 um 15:28 schrieb Hajime Tazaki:
> changes from v2:
> - Patch 02/11 ("slab: add private memory allocator header for arch/lib")
> * add new allocator named SLIB (Library Allocator): Patch 04/11 is integrated
> to 02 (commented by Christoph Lameter)
> - Overall
> * rewrite commit log messages
>
> changes from v1:
> - Patch 01/11 ("sysctl: make some functions unstatic to access by arch/lib"):
> * add prefix ctl_table_ to newly publiced functions (commented by Joe Perches)
> - Patch 08/11 ("lib: other kernel glue layer code"):
> * significantly reduce glue codes (stubs) (commented by Richard Weinberger)
> - Others
> * adapt to linux-4.0.0
> * detect make dependency by Kbuild .cmd files
I still fail to build it. :-(
for-asm-upstream-v3 on top of Linus' tree gives:
rw@sandpuppy:~/linux (libos $)> make library ARCH=lib
OBJS-MK arch/lib/objs.mk
arch/lib/Makefile.print:41: target 'lzo/' given more than once in the same rule.
make[2]: Nothing to be done for '.config'.
scripts/kconfig/conf --silentoldconfig arch/lib/Kconfig
CHK include/config/kernel.release
CHK include/generated/utsrelease.h
CHK include/generated/uapi/linux/version.h
CHK include/generated/compile.h
GEN arch/lib/timeconst.h
GEN arch/lib/linker.lds
CC arch/lib/lib.o
CC arch/lib/lib-device.o
CC arch/lib/lib-socket.o
CC arch/lib/random.o
CC arch/lib/softirq.o
CC arch/lib/time.o
CC arch/lib/timer.o
CC arch/lib/hrtimer.o
CC arch/lib/sched.o
CC arch/lib/workqueue.o
CC arch/lib/print.o
CC arch/lib/tasklet.o
CC arch/lib/tasklet-hrtimer.o
CC arch/lib/glue.o
CC arch/lib/fs.o
CC arch/lib/sysctl.o
CC arch/lib/proc.o
CC arch/lib/sysfs.o
CC arch/lib/capability.o
arch/lib/capability.c:16:6: error: redefinition of ‘capable’
bool capable(int cap)
^
In file included from arch/lib/capability.c:9:0:
./include/linux/capability.h:236:20: note: previous definition of ‘capable’ was here
static inline bool capable(int cap)
^
arch/lib/capability.c:39:6: error: redefinition of ‘ns_capable’
bool ns_capable(struct user_namespace *ns, int cap)
^
In file included from arch/lib/capability.c:9:0:
./include/linux/capability.h:240:20: note: previous definition of ‘ns_capable’ was here
static inline bool ns_capable(struct user_namespace *ns, int cap)
^
arch/lib/Makefile:210: recipe for target 'arch/lib/capability.o' failed
make: *** [arch/lib/capability.o] Error 1
And on top of v4.0 it fails too:
rw@sandpuppy:~/linux (libos-v4.0 $)> make library ARCH=lib
OBJS-MK arch/lib/objs.mk
arch/lib/Makefile.print:41: target 'lzo/' given more than once in the same rule.
make[2]: Nothing to be done for '.config'.
scripts/kconfig/conf --silentoldconfig arch/lib/Kconfig
CHK include/config/kernel.release
CHK include/generated/utsrelease.h
CHK include/generated/uapi/linux/version.h
CHK include/generated/compile.h
GEN arch/lib/timeconst.h
GEN arch/lib/linker.lds
CC arch/lib/lib.o
CC arch/lib/lib-device.o
CC arch/lib/lib-socket.o
arch/lib/lib-socket.c: In function ‘lib_sock_sendmsg’:
arch/lib/lib-socket.c:114:2: error: too few arguments to function ‘sock_sendmsg’
retval = sock_sendmsg(kernel_socket, &msg_sys);
^
In file included from arch/lib/lib-socket.c:12:0:
./include/linux/net.h:216:5: note: declared here
int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len);
^
arch/lib/Makefile:210: recipe for target 'arch/lib/lib-socket.o' failed
make: *** [arch/lib/lib-socket.o] Error 1
You *really* need to shape up wrt the build process.
Thanks,
//richard
Hi Richard,
At Fri, 24 Apr 2015 09:40:32 +0200,
Richard Weinberger wrote:
>
> Hi!
>
> Am 19.04.2015 um 15:28 schrieb Hajime Tazaki:
> > changes from v2:
> > - Patch 02/11 ("slab: add private memory allocator header for arch/lib")
> > * add new allocator named SLIB (Library Allocator): Patch 04/11 is integrated
> > to 02 (commented by Christoph Lameter)
> > - Overall
> > * rewrite commit log messages
> >
> > changes from v1:
> > - Patch 01/11 ("sysctl: make some functions unstatic to access by arch/lib"):
> > * add prefix ctl_table_ to newly publiced functions (commented by Joe Perches)
> > - Patch 08/11 ("lib: other kernel glue layer code"):
> > * significantly reduce glue codes (stubs) (commented by Richard Weinberger)
> > - Others
> > * adapt to linux-4.0.0
> > * detect make dependency by Kbuild .cmd files
>
> I still fail to build it. :-(
>
> for-asm-upstream-v3 on top of Linus' tree gives:
(snip)
> arch/lib/Makefile:210: recipe for target 'arch/lib/capability.o' failed
> make: *** [arch/lib/capability.o] Error 1
I'm also aware of and already fixed this issue for pre-v4
patch of libos.
> And on top of v4.0 it fails too:
(snip)
> In file included from arch/lib/lib-socket.c:12:0:
> ./include/linux/net.h:216:5: note: declared here
> int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len);
> ^
> arch/lib/Makefile:210: recipe for target 'arch/lib/lib-socket.o' failed
> make: *** [arch/lib/lib-socket.o] Error 1
since tag v4.0 to libos v3 patch, there is an update on the
sock_sendmsg(): v3 patch already followed the change. that's
why the patch can't build on top of v4.0.
> You *really* need to shape up wrt the build process.
at the moment, the implementation of libos can't automate to
follow such changes in the build process. but good news is
it's a trivial task to follow up the latest function.
my observation on this manual follow up since around 3.7
kernel (2.5 yrs ago) is that these changes mostly happened
during merge-window of each new version, and the fix only
takes a couple of hours at maximum.
I think I can survive with these changes but I'd like to ask
broader opinions.
one more question:
I'd really like to have a suggestion on which tree I should
base for libos tree.
I'm proposing a patchset to arnd/asm-generic tree (which I
believe the base tree for new arch/), while the patchset is
tested with davem/net-next tree because right now libos is
only for net/.
shall I propose a patchset based on Linus' tree instead ?
thank you for your feedback.
-- Hajime
Hi!
Am 24.04.2015 um 10:22 schrieb Hajime Tazaki:
>> You *really* need to shape up wrt the build process.
>
> at the moment, the implementation of libos can't automate to
> follow such changes in the build process. but good news is
> it's a trivial task to follow up the latest function.
>
> my observation on this manual follow up since around 3.7
> kernel (2.5 yrs ago) is that these changes mostly happened
> during merge-window of each new version, and the fix only
> takes a couple of hours at maximum.
>
> I think I can survive with these changes but I'd like to ask
> broader opinions.
>
>
> one more question:
>
> I'd really like to have a suggestion on which tree I should
> base for libos tree.
>
> I'm proposing a patchset to arnd/asm-generic tree (which I
> believe the base tree for new arch/), while the patchset is
> tested with davem/net-next tree because right now libos is
> only for net/.
>
> shall I propose a patchset based on Linus' tree instead ?
I'd suggest the following:
Maintain LibOS in your git tree and follow Linus' tree.
Make sure that all kernel releases build and work.
This way you can experiment with automation and other
stuff. If it works well you can ask for mainline inclusion
after a few kernel releases.
Your git history will show how much maintenance burden
LibOS has and how much with every merge window breaks and
needs manual fixup.
Thanks,
//richard
At Fri, 24 Apr 2015 10:59:21 +0200,
Richard Weinberger wrote:
> Am 24.04.2015 um 10:22 schrieb Hajime Tazaki:
> >> You *really* need to shape up wrt the build process.
> >
> > at the moment, the implementation of libos can't automate to
> > follow such changes in the build process. but good news is
> > it's a trivial task to follow up the latest function.
> >
> > my observation on this manual follow up since around 3.7
> > kernel (2.5 yrs ago) is that these changes mostly happened
> > during merge-window of each new version, and the fix only
> > takes a couple of hours at maximum.
> >
> > I think I can survive with these changes but I'd like to ask
> > broader opinions.
> >
> >
> > one more question:
> >
> > I'd really like to have a suggestion on which tree I should
> > base for libos tree.
> >
> > I'm proposing a patchset to arnd/asm-generic tree (which I
> > believe the base tree for new arch/), while the patchset is
> > tested with davem/net-next tree because right now libos is
> > only for net/.
> >
> > shall I propose a patchset based on Linus' tree instead ?
>
> I'd suggest the following:
> Maintain LibOS in your git tree and follow Linus' tree.
I see. will do it from next patch version.
> Make sure that all kernel releases build and work.
>
> This way you can experiment with automation and other
> stuff. If it works well you can ask for mainline inclusion
> after a few kernel releases.
>
> Your git history will show how much maintenance burden
> LibOS has and how much with every merge window breaks and
> needs manual fixup.
I believe this experiment is what we have been doing in the
past a couple of years (it's been tested with net-next tree,
not Linus tree though).
and the experiment is working well (as I stated in the
previous email) and that's why I'm here to propose this
patchset.
you can also see the git history: it also includes libos
specific commits of course.
https://github.com/libos-nuse/net-next-nuse/commits/nuse?author=thehajime
-- Hajime
This is the 4th version of Linux LibOS patchset which reflects a
couple of comments received from people.
changes from v3:
- Patch 09/10 ("lib: libos build scripts and documentation")
1) Remove RFC (now it's a proposal)
2) build environment cleanup (commented by Paul Bolle)
- Overall
3) change based tree from arnd/asm-generic to torvalds/linux.git
(commented by Richard Weinberger)
4) rebased to Linux 4.1-rc1 (b787f68c36d49bb1d9236f403813641efa74a031)
5) change the title of cover letter a bit
changes from v2:
- Patch 02/11 ("slab: add private memory allocator header for arch/lib")
1) add new allocator named SLIB (Library Allocator): Patch 04/11 is integrated
to 02 (commented by Christoph Lameter)
- Overall
2) rewrite commit log messages
changes from v1:
- Patch 01/11 ("sysctl: make some functions unstatic to access by arch/lib"):
1) add prefix ctl_table_ to newly publiced functions (commented by Joe Perches)
- Patch 08/11 ("lib: other kernel glue layer code"):
2) significantly reduce glue codes (stubs) (commented by Richard Weinberger)
- Others
3) adapt to linux-4.0.0
4) detect make dependency by Kbuild .cmd files
patchset history
-----------------
[v3] : https://lkml.org/lkml/2015/4/19/63
[v2] : https://lkml.org/lkml/2015/4/17/140
[v1] : https://lkml.org/lkml/2015/3/24/254
This is an introduction of Linux library operating system (LibOS).
Our objective is to build the kernel network stack as a shared library
that can be linked to by userspace programs to provide network stack
personalization and testing facilities, and allow researchers to more
easily simulate complex network topologies of linux routers/hosts.
Although the architecture itself can virtualize various things, the
current design only focuses on the network stack. You can benefit
network stack feature such as TCP, UDP, SCTP, DCCP (IPv4 and IPv6),
Mobie IPv6, Multipath TCP (IPv4/IPv6, out-of-tree at the present
moment), and netlink with various userspace applications (quagga,
iproute2, iperf, wget, and thttpd).
== What is LibOS ? ==
The library exposes an entry point as API, which is lib_init(), in
order to connect userspace applications to the (userspace-version)
kernel network stack. The clock source, virtual struct net_device, and
scheduler are provided by caller while kernel resource like system
calls is provided by callee.
Once the LibOS is initialized via the API, userspace applications with
POSIX socket can use the system calls defined in LibOS by replacing
from the original socket-related symbols to the LibOS-specific
one. Then application can benefit the network stack of LibOS without
involving the host network stack.
Currently, there are two users of LibOS: Network Stack in Userspace
(NUSE) and ns-3 network simulatior with Direct Code Execution
(DCE). These codes are managed at an external repository(*1).
== How to use it ? ==
to build the library,
% make {defconfig,menuconfig} ARCH=lib
then, build it.
% make library ARCH=lib
You will see liblinux-$(KERNELVERSION).so in the top directory.
== More information ==
The crucial difference between UML (user-mode linux) and this approach
is that we allow multiple network stack instances to co-exist within a
single process with dlmopen(3) like linking for easy debugging.
These patches are also available on this branch:
git://github.com/libos-nuse/net-next-nuse.git for-linus-upstream-libos-v4
(based on the commit b787f68c36d49bb1d9236f403813641efa74a031 of torvalds/linux.git)
For further information, here is a slideset presented at the last
netdev0.1 conference.
http://www.slideshare.net/hajimetazaki/library-operating-system-for-linux-netdev01
I would appreciate any kind of your feedback regarding to upstream
this feature.
*1 https://github.com/libos-nuse/linux-libos-tools
Hajime Tazaki (10):
sysctl: make some functions unstatic to access by arch/lib
slab: add SLIB (Library memory allocator) for arch/lib
lib: public headers and API implementations for userspace programs
lib: time handling (kernel glue code)
lib: context and scheduling functions (kernel glue code) for libos
lib: sysctl handling (kernel glue code)
lib: other kernel glue layer code
lib: auxially files for auto-generated asm-generic files of libos
lib: libos build scripts and documentation
lib: tools used for test scripts
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 3 +
arch/lib/Kconfig | 124 +++++++
arch/lib/Makefile | 224 ++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/capability.c | 25 ++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/filemap.c | 32 ++
arch/lib/fs.c | 70 ++++
arch/lib/generate-linker-script.py | 50 +++
arch/lib/glue.c | 289 +++++++++++++++
arch/lib/hrtimer.c | 122 +++++++
arch/lib/include/asm/Kbuild | 57 +++
arch/lib/include/asm/atomic.h | 50 +++
arch/lib/include/asm/barrier.h | 8 +
arch/lib/include/asm/bitsperlong.h | 16 +
arch/lib/include/asm/current.h | 7 +
arch/lib/include/asm/elf.h | 10 +
arch/lib/include/asm/hardirq.h | 8 +
arch/lib/include/asm/page.h | 14 +
arch/lib/include/asm/pgtable.h | 30 ++
arch/lib/include/asm/processor.h | 19 +
arch/lib/include/asm/ptrace.h | 4 +
arch/lib/include/asm/segment.h | 6 +
arch/lib/include/asm/sembuf.h | 4 +
arch/lib/include/asm/shmbuf.h | 4 +
arch/lib/include/asm/shmparam.h | 4 +
arch/lib/include/asm/sigcontext.h | 6 +
arch/lib/include/asm/stat.h | 4 +
arch/lib/include/asm/statfs.h | 4 +
arch/lib/include/asm/swab.h | 7 +
arch/lib/include/asm/thread_info.h | 36 ++
arch/lib/include/asm/uaccess.h | 14 +
arch/lib/include/asm/unistd.h | 4 +
arch/lib/include/sim-assert.h | 23 ++
arch/lib/include/sim-init.h | 134 +++++++
arch/lib/include/sim-printf.h | 13 +
arch/lib/include/sim-types.h | 53 +++
arch/lib/include/sim.h | 51 +++
arch/lib/include/uapi/asm/byteorder.h | 6 +
arch/lib/lib-device.c | 187 ++++++++++
arch/lib/lib-socket.c | 410 +++++++++++++++++++++
arch/lib/lib.c | 294 +++++++++++++++
arch/lib/lib.h | 21 ++
arch/lib/modules.c | 36 ++
arch/lib/pid.c | 29 ++
arch/lib/print.c | 56 +++
arch/lib/proc.c | 34 ++
arch/lib/random.c | 53 +++
arch/lib/sched.c | 406 +++++++++++++++++++++
arch/lib/softirq.c | 108 ++++++
arch/lib/sysctl.c | 270 ++++++++++++++
arch/lib/sysfs.c | 83 +++++
arch/lib/tasklet-hrtimer.c | 57 +++
arch/lib/tasklet.c | 76 ++++
arch/lib/time.c | 144 ++++++++
arch/lib/timer.c | 238 +++++++++++++
arch/lib/vmscan.c | 26 ++
arch/lib/workqueue.c | 242 +++++++++++++
fs/proc/proc_sysctl.c | 36 +-
include/linux/slab.h | 6 +-
include/linux/slib_def.h | 21 ++
mm/Makefile | 1 +
mm/slab.h | 4 +
mm/slib.c | 205 +++++++++++
tools/testing/libos/.gitignore | 6 +
tools/testing/libos/Makefile | 38 ++
tools/testing/libos/README | 15 +
tools/testing/libos/bisect.sh | 10 +
tools/testing/libos/dce-test.sh | 23 ++
tools/testing/libos/nuse-test.sh | 57 +++
72 files changed, 5560 insertions(+), 18 deletions(-)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/defconfig
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100755 arch/lib/generate-linker-script.py
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/sysctl.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
create mode 100644 arch/lib/vmscan.c
create mode 100644 arch/lib/workqueue.c
create mode 100644 include/linux/slib_def.h
create mode 100644 mm/slib.c
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
--
2.1.0
libos (arch/lib) emulates a sysctl-like interface by a function call of
userspace by enumerating sysctl tree from sysctl_table_root. It requires
to be publicly accessible to this symbol and related functions.
Signed-off-by: Hajime Tazaki <[email protected]>
---
fs/proc/proc_sysctl.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index fea2561..7c5924c 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -35,7 +35,7 @@ static struct ctl_table root_table[] = {
},
{ }
};
-static struct ctl_table_root sysctl_table_root = {
+struct ctl_table_root sysctl_table_root = {
.default_set.dir.header = {
{{.count = 1,
.nreg = 1,
@@ -77,8 +77,9 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2)
}
/* Called under sysctl_lock */
-static struct ctl_table *find_entry(struct ctl_table_header **phead,
- struct ctl_dir *dir, const char *name, int namelen)
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen)
{
struct ctl_table_header *head;
struct ctl_table *entry;
@@ -300,7 +301,7 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
struct ctl_table *entry;
spin_lock(&sysctl_lock);
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (entry && use_table(head))
*phead = head;
else
@@ -321,7 +322,7 @@ static struct ctl_node *first_usable_entry(struct rb_node *node)
return NULL;
}
-static void first_entry(struct ctl_dir *dir,
+void ctl_table_first_entry(struct ctl_dir *dir,
struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = NULL;
@@ -339,7 +340,7 @@ static void first_entry(struct ctl_dir *dir,
*pentry = entry;
}
-static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = *phead;
struct ctl_table *entry = *pentry;
@@ -670,7 +671,8 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
pos = 2;
- for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
if (!scan(h, entry, &pos, file, ctx)) {
sysctl_head_finish(h);
break;
@@ -828,7 +830,7 @@ static struct ctl_dir *find_subdir(struct ctl_dir *dir,
struct ctl_table_header *head;
struct ctl_table *entry;
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (!entry)
return ERR_PTR(-ENOENT);
if (!S_ISDIR(entry->mode))
@@ -924,13 +926,13 @@ failed:
return subdir;
}
-static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
{
struct ctl_dir *parent;
const char *procname;
if (!dir->header.parent)
return &set->dir;
- parent = xlate_dir(set, dir->header.parent);
+ parent = ctl_table_xlate_dir(set, dir->header.parent);
if (IS_ERR(parent))
return parent;
procname = dir->header.ctl_table[0].procname;
@@ -951,13 +953,13 @@ static int sysctl_follow_link(struct ctl_table_header **phead,
spin_lock(&sysctl_lock);
root = (*pentry)->data;
set = lookup_header_set(root, namespaces);
- dir = xlate_dir(set, (*phead)->parent);
+ dir = ctl_table_xlate_dir(set, (*phead)->parent);
if (IS_ERR(dir))
ret = PTR_ERR(dir);
else {
const char *procname = (*pentry)->procname;
head = NULL;
- entry = find_entry(&head, dir, procname, strlen(procname));
+ entry = ctl_table_find_entry(&head, dir, procname, strlen(procname));
ret = -ENOENT;
if (entry && use_table(head)) {
unuse_table(*phead);
@@ -1069,7 +1071,7 @@ static bool get_links(struct ctl_dir *dir,
/* Are there links available for every entry in table? */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
if (!link)
return false;
if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
@@ -1082,7 +1084,7 @@ static bool get_links(struct ctl_dir *dir,
/* The checks passed. Increase the registration count on the links */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
head->nreg++;
}
return true;
@@ -1098,7 +1100,7 @@ static int insert_links(struct ctl_table_header *head)
if (head->set == root_set)
return 0;
- core_parent = xlate_dir(root_set, head->parent);
+ core_parent = ctl_table_xlate_dir(root_set, head->parent);
if (IS_ERR(core_parent))
return 0;
@@ -1479,7 +1481,7 @@ static void put_links(struct ctl_table_header *header)
if (header->set == root_set)
return;
- core_parent = xlate_dir(root_set, parent);
+ core_parent = ctl_table_xlate_dir(root_set, parent);
if (IS_ERR(core_parent))
return;
@@ -1488,7 +1490,7 @@ static void put_links(struct ctl_table_header *header)
struct ctl_table *link;
const char *name = entry->procname;
- link = find_entry(&link_head, core_parent, name, strlen(name));
+ link = ctl_table_find_entry(&link_head, core_parent, name, strlen(name));
if (link &&
((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
(S_ISLNK(link->mode) && (link->data == root)))) {
--
2.1.0
add SLIB allocator for arch/lib (CONFIG_LIB) to wrap kmalloc and co.
This will bring user's own allocator of libos: malloc(3) etc.
Signed-off-by: Hajime Tazaki <[email protected]>
---
include/linux/slab.h | 6 +-
include/linux/slib_def.h | 21 +++++
mm/Makefile | 1 +
mm/slab.h | 4 +
mm/slib.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 236 insertions(+), 1 deletion(-)
create mode 100644 include/linux/slib_def.h
create mode 100644 mm/slib.c
diff --git a/include/linux/slab.h b/include/linux/slab.h
index ffd24c8..0288cf8 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -191,7 +191,7 @@ size_t ksize(const void *);
#endif
#endif
-#ifdef CONFIG_SLOB
+#if defined(CONFIG_SLOB) || defined(CONFIG_SLIB)
/*
* SLOB passes all requests larger than one page to the page allocator.
* No kmalloc array is necessary since objects of different sizes can
@@ -356,6 +356,9 @@ kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
}
#endif
+#ifdef CONFIG_SLIB
+#include <linux/slib_def.h>
+#else
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{
unsigned int order = get_order(size);
@@ -434,6 +437,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
}
return __kmalloc(size, flags);
}
+#endif /* CONFIG_SLIB */
/*
* Determine size used for the nth kmalloc cache.
diff --git a/include/linux/slib_def.h b/include/linux/slib_def.h
new file mode 100644
index 0000000..d9fe7d5
--- /dev/null
+++ b/include/linux/slib_def.h
@@ -0,0 +1,21 @@
+#ifndef _LINUX_SLLB_DEF_H
+#define _LINUX_SLLB_DEF_H
+
+
+struct kmem_cache {
+ unsigned int object_size;
+ const char *name;
+ size_t size;
+ size_t align;
+ unsigned long flags;
+ void (*ctor)(void *);
+};
+
+void *__kmalloc(size_t size, gfp_t flags);
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+static __always_inline void *kmalloc(size_t size, gfp_t flags)
+{
+ return __kmalloc(size, flags);
+}
+
+#endif /* _LINUX_SLLB_DEF_H */
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eae..7d8314f 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
obj-$(CONFIG_SLOB) += slob.o
+obj-$(CONFIG_SLIB) += slib.o
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_KSM) += ksm.o
obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
diff --git a/mm/slab.h b/mm/slab.h
index 4c3ac12..2ea37c9 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -37,6 +37,10 @@ struct kmem_cache {
#include <linux/slub_def.h>
#endif
+#ifdef CONFIG_SLIB
+#include <linux/slib_def.h>
+#endif
+
#include <linux/memcontrol.h>
/*
diff --git a/mm/slib.c b/mm/slib.c
new file mode 100644
index 0000000..37596862
--- /dev/null
+++ b/mm/slib.c
@@ -0,0 +1,205 @@
+/*
+ * Library Slab Allocator (SLIB)
+ *
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/page-flags.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/slib_def.h>
+
+/* glues */
+struct kmem_cache *files_cachep;
+
+void kfree(const void *p)
+{
+ unsigned long start;
+
+ if (p == 0)
+ return;
+ start = (unsigned long)p;
+ start -= sizeof(size_t);
+ lib_free((void *)start);
+}
+size_t ksize(const void *p)
+{
+ size_t *psize = (size_t *)p;
+
+ psize--;
+ return *psize;
+}
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ void *p = lib_malloc(size + sizeof(size));
+ unsigned long start;
+
+ if (!p)
+ return NULL;
+
+ if (p != 0 && (flags & __GFP_ZERO))
+ lib_memset(p, 0, size + sizeof(size));
+ lib_memcpy(p, &size, sizeof(size));
+ start = (unsigned long)p;
+ return (void *)(start + sizeof(size));
+}
+
+void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller)
+{
+ return kmalloc(size, flags);
+}
+
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+
+ if (!new_size) {
+ kfree(p);
+ return ZERO_SIZE_PTR;
+ }
+
+ ret = __kmalloc(new_size, flags);
+ if (ret && p != ret)
+ kfree(p);
+
+ return ret;
+}
+
+struct kmem_cache *
+kmem_cache_create(const char *name, size_t size, size_t align,
+ unsigned long flags, void (*ctor)(void *))
+{
+ struct kmem_cache *cache = kmalloc(sizeof(struct kmem_cache), flags);
+
+ if (!cache)
+ return NULL;
+ cache->name = name;
+ cache->size = size;
+ cache->align = align;
+ cache->flags = flags;
+ cache->ctor = ctor;
+ return cache;
+}
+void kmem_cache_destroy(struct kmem_cache *cache)
+{
+ kfree(cache);
+}
+int kmem_cache_shrink(struct kmem_cache *cache)
+{
+ return 1;
+}
+const char *kmem_cache_name(struct kmem_cache *cache)
+{
+ return cache->name;
+}
+void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags)
+{
+ void *p = kmalloc(cache->size, flags);
+
+ if (p == 0)
+ return NULL;
+ if (cache->ctor)
+ (cache->ctor)(p);
+ return p;
+
+}
+void kmem_cache_free(struct kmem_cache *cache, void *p)
+{
+ kfree(p);
+}
+
+struct page *
+__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist, nodemask_t *nodemask)
+{
+ void *p;
+ struct page *page;
+ unsigned long pointer;
+
+ /* typically, called from networking code by alloc_page or */
+ /* directly with an order = 0. */
+ if (order)
+ return NULL;
+ p = lib_malloc(sizeof(struct page) + (1 << PAGE_SHIFT));
+ page = (struct page *)p;
+
+ atomic_set(&page->_count, 1);
+ page->flags = 0;
+ pointer = (unsigned long)page;
+ pointer += sizeof(struct page);
+ page->virtual = (void *)pointer;
+ return page;
+}
+void __free_pages(struct page *page, unsigned int order)
+{
+ /* typically, called from networking code by __free_page */
+ lib_assert(order == 0);
+ lib_free(page);
+}
+
+void put_page(struct page *page)
+{
+ if (atomic_dec_and_test(&page->_count))
+ lib_free(page);
+}
+unsigned long get_zeroed_page(gfp_t gfp_mask)
+{
+ return __get_free_pages(gfp_mask | __GFP_ZERO, 0);
+}
+
+void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
+{
+ return alloc_pages(gfp_mask, get_order(size));
+}
+
+unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
+{
+ int size = (1 << order) * PAGE_SIZE;
+ void *p = kmalloc(size, gfp_mask);
+
+ return (unsigned long)p;
+}
+void free_pages(unsigned long addr, unsigned int order)
+{
+ if (addr != 0)
+ kfree((void *)addr);
+}
+
+void *vmalloc(unsigned long size)
+{
+ return lib_malloc(size);
+}
+void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
+{
+ return kmalloc(size, gfp_mask);
+}
+void vfree(const void *addr)
+{
+ lib_free((void *)addr);
+}
+void *vmalloc_node(unsigned long size, int node)
+{
+ return lib_malloc(size);
+}
+void vmalloc_sync_all(void)
+{
+}
+void *__alloc_percpu(size_t size, size_t align)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+void free_percpu(void __percpu *ptr)
+{
+ kfree(ptr);
+}
+void *__alloc_bootmem_nopanic(unsigned long size,
+ unsigned long align,
+ unsigned long goal)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
--
2.1.0
userspace programs which uses libos access via a public API, lib_init(),
with passed arguments struct SimImported and struct SimExported.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
arch/lib/include/sim-assert.h | 23 +++
arch/lib/include/sim-init.h | 134 ++++++++++++++
arch/lib/include/sim-printf.h | 13 ++
arch/lib/include/sim-types.h | 53 ++++++
arch/lib/include/sim.h | 51 ++++++
arch/lib/lib-device.c | 187 +++++++++++++++++++
arch/lib/lib-socket.c | 410 ++++++++++++++++++++++++++++++++++++++++++
arch/lib/lib.c | 294 ++++++++++++++++++++++++++++++
arch/lib/lib.h | 21 +++
9 files changed, 1186 insertions(+)
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
diff --git a/arch/lib/include/sim-assert.h b/arch/lib/include/sim-assert.h
new file mode 100644
index 0000000..974122c
--- /dev/null
+++ b/arch/lib/include/sim-assert.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_ASSERT_H
+#define SIM_ASSERT_H
+
+#include "sim-printf.h"
+
+#define lib_assert(v) { \
+ while (!(v)) { \
+ lib_printf("Assert failed %s:%u \"" #v "\"\n", \
+ __FILE__, __LINE__); \
+ char *p = 0; \
+ *p = 1; \
+ } \
+ }
+
+
+#endif /* SIM_ASSERT_H */
diff --git a/arch/lib/include/sim-init.h b/arch/lib/include/sim-init.h
new file mode 100644
index 0000000..e871a59
--- /dev/null
+++ b/arch/lib/include/sim-init.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_INIT_H
+#define SIM_INIT_H
+
+#include <linux/socket.h>
+#include "sim-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _IO_FILE;
+typedef struct _IO_FILE FILE;
+
+struct SimExported {
+ struct SimTask *(*task_create)(void *priv, unsigned long pid);
+ void (*task_destroy)(struct SimTask *task);
+ void *(*task_get_private)(struct SimTask *task);
+
+ int (*sock_socket)(int domain, int type, int protocol,
+ struct SimSocket **socket);
+ int (*sock_close)(struct SimSocket *socket);
+ ssize_t (*sock_recvmsg)(struct SimSocket *socket, struct msghdr *msg,
+ int flags);
+ ssize_t (*sock_sendmsg)(struct SimSocket *socket,
+ const struct msghdr *msg, int flags);
+ int (*sock_getsockname)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_getpeername)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_bind)(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen);
+ int (*sock_connect)(struct SimSocket *socket,
+ const struct sockaddr *name, int namelen,
+ int flags);
+ int (*sock_listen)(struct SimSocket *socket, int backlog);
+ int (*sock_shutdown)(struct SimSocket *socket, int how);
+ int (*sock_accept)(struct SimSocket *socket,
+ struct SimSocket **newSocket, int flags);
+ int (*sock_ioctl)(struct SimSocket *socket, int request, char *argp);
+ int (*sock_setsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ const void *optval, int optlen);
+ int (*sock_getsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ void *optval, int *optlen);
+
+ void (*sock_poll)(struct SimSocket *socket, void *ret);
+ void (*sock_pollfreewait)(void *polltable);
+
+ struct SimDevice *(*dev_create)(const char *ifname, void *priv,
+ enum SimDevFlags flags);
+ void (*dev_destroy)(struct SimDevice *dev);
+ void *(*dev_get_private)(struct SimDevice *task);
+ void (*dev_set_address)(struct SimDevice *dev,
+ unsigned char buffer[6]);
+ void (*dev_set_mtu)(struct SimDevice *dev, int mtu);
+ struct SimDevicePacket (*dev_create_packet)(struct SimDevice *dev,
+ int size);
+ void (*dev_rx)(struct SimDevice *dev, struct SimDevicePacket packet);
+
+ void (*sys_iterate_files)(const struct SimSysIterator *iter);
+ int (*sys_file_read)(const struct SimSysFile *file, char *buffer,
+ int size, int offset);
+ int (*sys_file_write)(const struct SimSysFile *file,
+ const char *buffer, int size, int offset);
+};
+
+struct SimImported {
+ int (*vprintf)(struct SimKernel *kernel, const char *str,
+ va_list args);
+ void *(*malloc)(struct SimKernel *kernel, unsigned long size);
+ void (*free)(struct SimKernel *kernel, void *buffer);
+ void *(*memcpy)(struct SimKernel *kernel, void *dst, const void *src,
+ unsigned long size);
+ void *(*memset)(struct SimKernel *kernel, void *dst, char value,
+ unsigned long size);
+ int (*atexit)(struct SimKernel *kernel, void (*function)(void));
+ int (*access)(struct SimKernel *kernel, const char *pathname,
+ int mode);
+ char *(*getenv)(struct SimKernel *kernel, const char *name);
+ int (*mkdir)(struct SimKernel *kernel, const char *pathname,
+ mode_t mode);
+ int (*open)(struct SimKernel *kernel, const char *pathname, int flags);
+ int (*__fxstat)(struct SimKernel *kernel, int ver, int fd, void *buf);
+ int (*fseek)(struct SimKernel *kernel, FILE *stream, long offset,
+ int whence);
+ void (*setbuf)(struct SimKernel *kernel, FILE *stream, char *buf);
+ FILE *(*fdopen)(struct SimKernel *kernel, int fd, const char *mode);
+ long (*ftell)(struct SimKernel *kernel, FILE *stream);
+ int (*fclose)(struct SimKernel *kernel, FILE *fp);
+ size_t (*fread)(struct SimKernel *kernel, void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+ size_t (*fwrite)(struct SimKernel *kernel, const void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+
+ unsigned long (*random)(struct SimKernel *kernel);
+ void *(*event_schedule_ns)(struct SimKernel *kernel, __u64 ns,
+ void (*fn)(void *context), void *context,
+ void (*pre_fn)(void));
+ void (*event_cancel)(struct SimKernel *kernel, void *event);
+ __u64 (*current_ns)(struct SimKernel *kernel);
+
+ struct SimTask *(*task_start)(struct SimKernel *kernel,
+ void (*callback)(void *),
+ void *context);
+ void (*task_wait)(struct SimKernel *kernel);
+ struct SimTask *(*task_current)(struct SimKernel *kernel);
+ int (*task_wakeup)(struct SimKernel *kernel, struct SimTask *task);
+ void (*task_yield)(struct SimKernel *kernel);
+
+ void (*dev_xmit)(struct SimKernel *kernel, struct SimDevice *dev,
+ unsigned char *data, int len);
+ void (*signal_raised)(struct SimKernel *kernel, struct SimTask *task,
+ int sig);
+ void (*poll_event)(int flag, void *context);
+};
+
+typedef void (*SimInit)(struct SimExported *, const struct SimImported *,
+ struct SimKernel *kernel);
+void sim_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_INIT_H */
diff --git a/arch/lib/include/sim-printf.h b/arch/lib/include/sim-printf.h
new file mode 100644
index 0000000..2bf8245
--- /dev/null
+++ b/arch/lib/include/sim-printf.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_PRINTF_H
+#define SIM_PRINTF_H
+
+void lib_printf(const char *str, ...);
+
+#endif /* SIM_PRINTF_H */
diff --git a/arch/lib/include/sim-types.h b/arch/lib/include/sim-types.h
new file mode 100644
index 0000000..d50b99b
--- /dev/null
+++ b/arch/lib/include/sim-types.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_TYPES_H
+#define SIM_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBOS_API_VERSION 2
+
+struct SimTask;
+struct SimDevice;
+struct SimSocket;
+struct SimKernel;
+struct SimSysFile;
+
+enum SimDevFlags {
+ SIM_DEV_NOARP = (1 << 0),
+ SIM_DEV_POINTTOPOINT = (1 << 1),
+ SIM_DEV_MULTICAST = (1 << 2),
+ SIM_DEV_BROADCAST = (1 << 3),
+};
+
+struct SimDevicePacket {
+ void *buffer;
+ void *token;
+};
+
+enum SimSysFileFlags {
+ SIM_SYS_FILE_READ = 1 << 0,
+ SIM_SYS_FILE_WRITE = 1 << 1,
+};
+
+struct SimSysIterator {
+ void (*report_start_dir)(const struct SimSysIterator *iter,
+ const char *dirname);
+ void (*report_end_dir)(const struct SimSysIterator *iter);
+ void (*report_file)(const struct SimSysIterator *iter,
+ const char *filename,
+ int flags, struct SimSysFile *file);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_TYPES_H */
diff --git a/arch/lib/include/sim.h b/arch/lib/include/sim.h
new file mode 100644
index 0000000..b30d7e8
--- /dev/null
+++ b/arch/lib/include/sim.h
@@ -0,0 +1,51 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_H
+#define SIM_H
+
+#include <stdarg.h>
+#include <linux/types.h>
+
+#include "sim-types.h"
+
+/* API called from within linux kernel. Forwards to SimImported. */
+int lib_vprintf(const char *str, va_list args);
+void *lib_malloc(unsigned long size);
+void lib_free(void *buffer);
+void *lib_memcpy(void *dst, const void *src, unsigned long size);
+void *lib_memset(void *dst, char value, unsigned long size);
+unsigned long lib_random(void);
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context),
+ void *context);
+void lib_event_cancel(void *event);
+__u64 lib_current_ns(void);
+
+struct SimTask *lib_task_start(void (*callback) (void *), void *context);
+void lib_task_wait(void);
+void lib_task_yield(void);
+struct SimTask *lib_task_current(void);
+/* returns 1 if task was woken up, 0 if it was already running. */
+int lib_task_wakeup(struct SimTask *task);
+struct SimTask *lib_task_create(void *priv, unsigned long pid);
+void lib_task_destroy(struct SimTask *task);
+void *lib_task_get_private(struct SimTask *task);
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len);
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size);
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet);
+
+void lib_signal_raised(struct SimTask *task, int sig);
+
+void lib_poll_event(int flag, void *context);
+void lib_softirq_wakeup(void);
+void lib_update_jiffies(void);
+void *lib_dev_get_private(struct SimDevice *);
+void lib_proc_net_initialize(void);
+
+#endif /* SIM_H */
diff --git a/arch/lib/lib-device.c b/arch/lib/lib-device.c
new file mode 100644
index 0000000..1efa6460
--- /dev/null
+++ b/arch/lib/lib-device.c
@@ -0,0 +1,187 @@
+/*
+ * virtual net_device feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ethtool.h>
+
+struct SimDevice {
+ struct net_device dev;
+ void *priv;
+};
+
+static netdev_tx_t
+kernel_dev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ int err;
+
+ netif_stop_queue(dev);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ err = skb_checksum_help(skb);
+ if (unlikely(err)) {
+ pr_err("checksum error (%d)\n", err);
+ return 0;
+ }
+ }
+
+ lib_dev_xmit((struct SimDevice *)dev, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static u32 always_on(struct net_device *dev)
+{
+ return 1;
+}
+
+
+static const struct ethtool_ops lib_ethtool_ops = {
+ .get_link = always_on,
+};
+
+static const struct net_device_ops lib_dev_ops = {
+ .ndo_start_xmit = kernel_dev_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static void lib_dev_setup(struct net_device *dev)
+{
+ dev->mtu = (16 * 1024) + 20 + 20 + 12;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_ETHER;
+ dev->flags = 0;
+ /* dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; */
+ dev->features = 0
+ | NETIF_F_HIGHDMA
+ | NETIF_F_NETNS_LOCAL;
+ /* disabled NETIF_F_TSO NETIF_F_SG NETIF_F_FRAGLIST NETIF_F_LLTX */
+ dev->ethtool_ops = &lib_ethtool_ops;
+ dev->header_ops = ð_header_ops;
+ dev->netdev_ops = &lib_dev_ops;
+ dev->destructor = &free_netdev;
+}
+
+
+struct SimDevice *lib_dev_create(const char *ifname, void *priv,
+ enum SimDevFlags flags)
+{
+ int err;
+ struct SimDevice *dev =
+ (struct SimDevice *)alloc_netdev(sizeof(struct SimDevice),
+ ifname, NET_NAME_UNKNOWN,
+ &lib_dev_setup);
+ ether_setup((struct net_device *)dev);
+
+ if (flags & SIM_DEV_NOARP)
+ dev->dev.flags |= IFF_NOARP;
+ if (flags & SIM_DEV_POINTTOPOINT)
+ dev->dev.flags |= IFF_POINTOPOINT;
+ if (flags & SIM_DEV_MULTICAST)
+ dev->dev.flags |= IFF_MULTICAST;
+ if (flags & SIM_DEV_BROADCAST) {
+ dev->dev.flags |= IFF_BROADCAST;
+ memset(dev->dev.broadcast, 0xff, 6);
+ }
+ dev->priv = priv;
+ err = register_netdev(&dev->dev);
+ return dev;
+}
+void lib_dev_destroy(struct SimDevice *dev)
+{
+ unregister_netdev(&dev->dev);
+ /* XXX */
+ free_netdev(&dev->dev);
+}
+void *lib_dev_get_private(struct SimDevice *dev)
+{
+ return dev->priv;
+}
+
+void lib_dev_set_mtu(struct SimDevice *dev, int mtu)
+{
+ /* called by ns-3 to synchronize the kernel mtu with */
+ /* the simulation mtu */
+ dev->dev.mtu = mtu;
+}
+
+static int lib_ndo_change_mtu(struct net_device *dev,
+ int new_mtu)
+{
+ /* called by kernel to change the mtu when the user */
+ /* asks for it. */
+ /* XXX should forward the set call to ns-3 and wait for */
+ /* ns-3 to notify of the change in the function above */
+ /* but I am way too tired to do this now. */
+ return 0;
+}
+
+void lib_dev_set_address(struct SimDevice *dev, unsigned char buffer[6])
+{
+ /* called by ns-3 to synchronize the kernel address with */
+ /* the simulation address. */
+ struct sockaddr sa;
+
+ sa.sa_family = dev->dev.type;
+ lib_memcpy(&sa.sa_data, buffer, 6);
+ dev->dev.netdev_ops->ndo_set_mac_address(&dev->dev, &sa);
+ /* Note that we don't call dev_set_mac_address (&dev->dev, &sa); */
+ /* because this function expects to be called from within */
+ /* the netlink layer so, it expects to hold */
+ /* the netlink lock during the execution of the associated notifiers */
+}
+static int get_hack_size(int size)
+{
+ /* Note: this hack is coming from nsc */
+ /* Bit of a hack... */
+ /* Note that the size allocated here effects the offered window
+ somewhat. I've got this heuristic here to try and match up with
+ what we observe on the emulation network and by looking at the
+ driver code of the eepro100. In both cases we allocate enough
+ space for our packet, which is the important thing. The amount
+ of slack at the end can make linux decide the grow the window
+ differently. This is quite subtle, but the code in question is
+ in the tcp_grow_window function. It checks skb->truesize, which
+ is the size of the skbuff allocated for the incoming data
+ packet -- what we are allocating right now! */
+ if (size < 1200)
+ return size + 36;
+ else if (size <= 1500)
+ return 1536;
+ else
+ return size + 36;
+}
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size)
+{
+ struct SimDevicePacket packet;
+ int len = get_hack_size(size);
+ struct sk_buff *skb = __dev_alloc_skb(len, __GFP_WAIT);
+
+ packet.token = skb;
+ packet.buffer = skb_put(skb, len);
+ return packet;
+}
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet)
+{
+ struct sk_buff *skb = packet.token;
+ struct net_device *dev = &device->dev;
+
+ skb->protocol = eth_type_trans(skb, dev);
+ /* Do the TCP checksum (FIXME: should be configurable) */
+ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ netif_rx(skb);
+}
diff --git a/arch/lib/lib-socket.c b/arch/lib/lib-socket.c
new file mode 100644
index 0000000..d9be5fc
--- /dev/null
+++ b/arch/lib/lib-socket.c
@@ -0,0 +1,410 @@
+/*
+ * socket feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/net.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/inet_connection_sock.h>
+
+struct SimSocket {};
+
+static struct iovec *copy_iovec(const struct iovec *input, int len)
+{
+ int size = sizeof(struct iovec) * len;
+ struct iovec *output = lib_malloc(size);
+
+ if (!output)
+ return NULL;
+ lib_memcpy(output, input, size);
+ return output;
+}
+
+int lib_sock_socket(int domain, int type, int protocol,
+ struct SimSocket **socket)
+{
+ struct socket **kernel_socket = (struct socket **)socket;
+ int flags;
+
+ /* from net/socket.c */
+ flags = type & ~SOCK_TYPE_MASK;
+ if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ return -EINVAL;
+ type &= SOCK_TYPE_MASK;
+
+ int retval = sock_create(domain, type, protocol, kernel_socket);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ struct file *fp = lib_malloc(sizeof(struct file));
+ (*kernel_socket)->file = fp;
+ fp->f_cred = lib_malloc(sizeof(struct cred));
+ return retval;
+}
+int lib_sock_close(struct SimSocket *socket)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+
+ sock_release(kernel_socket);
+ return 0;
+}
+static size_t iov_size(const struct user_msghdr *msg)
+{
+ size_t i;
+ size_t size = 0;
+
+ for (i = 0; i < msg->msg_iovlen; i++)
+ size += msg->msg_iov[i].iov_len;
+ return size;
+}
+ssize_t lib_sock_recvmsg(struct SimSocket *socket,
+ struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct msghdr msg_sys;
+ struct cmsghdr *user_cmsgh = msg->msg_control;
+ size_t user_cmsghlen = msg->msg_controllen;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, READ,
+ msg->msg_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_recvmsg(kernel_socket, &msg_sys, iov_size(msg), flags);
+
+ msg->msg_name = msg_sys.msg_name;
+ msg->msg_namelen = msg_sys.msg_namelen;
+ msg->msg_control = user_cmsgh;
+ msg->msg_controllen = user_cmsghlen - msg_sys.msg_controllen;
+ return retval;
+}
+ssize_t lib_sock_sendmsg(struct SimSocket *socket,
+ const struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct iovec *kernel_iov = copy_iovec(msg->msg_iov, msg->msg_iovlen);
+ struct msghdr msg_sys;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, WRITE,
+ kernel_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_sendmsg(kernel_socket, &msg_sys);
+ lib_free(kernel_iov);
+ return retval;
+}
+int lib_sock_getsockname(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 0);
+
+ return retval;
+}
+int lib_sock_getpeername(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 1);
+
+ return retval;
+}
+int lib_sock_bind(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ int retval =
+ sock->ops->bind(sock, (struct sockaddr *)&address, namelen);
+ return retval;
+}
+int lib_sock_connect(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen, int flags)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ sock->file->f_flags = flags;
+ int retval = sock->ops->connect(sock, (struct sockaddr *)&address,
+ namelen, flags);
+ return retval;
+}
+int lib_sock_listen(struct SimSocket *socket, int backlog)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->listen(sock, backlog);
+
+ return retval;
+}
+int lib_sock_shutdown(struct SimSocket *socket, int how)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->shutdown(sock, how);
+
+ return retval;
+}
+int lib_sock_accept(struct SimSocket *socket, struct SimSocket **new_socket,
+ int flags)
+{
+ struct socket *sock, *newsock;
+ int err;
+
+ sock = (struct socket *)socket;
+
+ /* the fields do not matter here. If we could, */
+ /* we would call sock_alloc but it's not exported. */
+ err = sock_create_lite(0, 0, 0, &newsock);
+ if (err < 0)
+ return err;
+ newsock->type = sock->type;
+ newsock->ops = sock->ops;
+
+ err = sock->ops->accept(sock, newsock, flags);
+ if (err < 0) {
+ sock_release(newsock);
+ return err;
+ }
+ *new_socket = (struct SimSocket *)newsock;
+ return 0;
+}
+int lib_sock_ioctl(struct SimSocket *socket, int request, char *argp)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sock *sk;
+ struct net *net;
+ int err;
+
+ sk = sock->sk;
+ net = sock_net(sk);
+
+ err = sock->ops->ioctl(sock, request, (long)argp);
+
+ /*
+ * If this ioctl is unknown try to hand it down
+ * to the NIC driver.
+ */
+ if (err == -ENOIOCTLCMD)
+ err = dev_ioctl(net, request, argp);
+ return err;
+}
+int lib_sock_setsockopt(struct SimSocket *socket, int level, int optname,
+ const void *optval, int optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ char *coptval = (char *)optval;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_setsockopt(sock, level, optname, coptval, optlen);
+ else
+ err = sock->ops->setsockopt(sock, level, optname, coptval,
+ optlen);
+ return err;
+}
+int lib_sock_getsockopt(struct SimSocket *socket, int level, int optname,
+ void *optval, int *optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_getsockopt(sock, level, optname, optval, optlen);
+ else
+ err =
+ sock->ops->getsockopt(sock, level, optname, optval,
+ optlen);
+ return err;
+}
+
+int lib_sock_canrecv(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct inet_connection_sock *icsk;
+
+ switch (sock->sk->sk_state) {
+ case TCP_CLOSE:
+ if (SOCK_STREAM == sock->sk->sk_type)
+ return 1;
+ case TCP_ESTABLISHED:
+ return sock->sk->sk_receive_queue.qlen > 0;
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV:
+ case TCP_LAST_ACK:
+ case TCP_CLOSING:
+ return 0;
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_TIME_WAIT:
+ case TCP_CLOSE_WAIT:
+ return 1;
+ case TCP_LISTEN:
+ {
+ icsk = inet_csk(sock->sk);
+ return !reqsk_queue_empty(&icsk->icsk_accept_queue);
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+int lib_sock_cansend(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+
+ return sock_writeable(sock->sk);
+}
+
+/**
+ * Struct used to pass pool table context between DCE and Kernel and back from
+ * Kernel to DCE
+ *
+ * When calling sock_poll we provide in ret field the wanted eventmask, and in
+ * the opaque field the DCE poll table
+ *
+ * if a corresponding event occurs later, the PollEvent will be called by kernel
+ * with the DCE poll table in context variable, then we will able to wake up the
+ * thread blocked in poll call.
+ *
+ * Back from sock_poll method the kernel change ret field with the response from
+ * poll return of the corresponding kernel socket, and in opaque field there is
+ * a reference to the kernel poll table we will use this reference to remove us
+ * from the file wait queue when ending the DCE poll call or when ending the DCE
+ * process which is currently polling.
+ *
+ */
+struct poll_table_ref {
+ int ret;
+ void *opaque;
+};
+
+/* Because the poll main loop code is in NS3/DCE we have only on entry
+ in our kernel poll table */
+struct lib_ptable_entry {
+ wait_queue_t wait;
+ wait_queue_head_t *wait_address;
+ int eventMask; /* Poll wanted event mask. */
+ void *opaque; /* Pointeur to DCE poll table */
+};
+
+static int lib_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)wait->private;
+
+ /* Filter only wanted events */
+ if (key && !((unsigned long)key & entry->eventMask))
+ return 0;
+
+ lib_poll_event((unsigned long)key, entry->opaque);
+ return 1;
+}
+
+static void lib_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table *p)
+{
+ struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)
+ lib_malloc(sizeof(struct lib_ptable_entry));
+ struct poll_table_ref *fromDCE = (struct poll_table_ref *)pwq->table;
+
+ if (!entry)
+ return;
+
+ entry->opaque = fromDCE->opaque; /* Copy DCE poll table reference */
+ entry->eventMask = fromDCE->ret; /* Copy poll mask of wanted events. */
+
+ pwq->table = (struct poll_table_page *)entry;
+
+ init_waitqueue_func_entry(&entry->wait, lib_pollwake);
+ entry->wait.private = entry;
+ entry->wait_address = wait_address;
+ add_wait_queue(wait_address, &entry->wait);
+}
+
+void dce_poll_initwait(struct poll_wqueues *pwq)
+{
+ init_poll_funcptr(&pwq->pt, lib_pollwait);
+ pwq->polling_task = current;
+ pwq->triggered = 0;
+ pwq->error = 0;
+ pwq->table = NULL;
+ pwq->inline_index = 0;
+}
+
+/* call poll on socket ... */
+void lib_sock_poll(struct SimSocket *socket, struct poll_table_ref *ret)
+{
+ struct socket *sock = (struct socket *)socket;
+ /* Provide a fake file structure */
+ struct file zero;
+ poll_table *pwait = 0;
+ struct poll_wqueues *ptable = 0;
+
+ lib_memset(&zero, 0, sizeof(struct file));
+
+ if (ret->opaque) {
+ ptable =
+ (struct poll_wqueues *)lib_malloc(sizeof(struct
+ poll_wqueues));
+ if (!ptable)
+ return;
+
+ dce_poll_initwait(ptable);
+
+ pwait = &(ptable->pt);
+ /* Pass the DCE pool table to lib_pollwait function */
+ ptable->table = (struct poll_table_page *)ret;
+ }
+
+ ret->ret = sock->ops->poll(&zero, sock, pwait);
+ /* Pass back the kernel poll table to DCE in order to DCE to */
+ /* remove from wait queue */
+ /* using lib_sock_pollfreewait method below */
+ ret->opaque = ptable;
+}
+
+void lib_sock_pollfreewait(void *polltable)
+{
+ struct poll_wqueues *ptable = (struct poll_wqueues *)polltable;
+
+ if (ptable && ptable->table) {
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)ptable->table;
+ remove_wait_queue(entry->wait_address, &entry->wait);
+ lib_free(entry);
+ }
+ lib_free(ptable);
+}
+
+
+
+
diff --git a/arch/lib/lib.c b/arch/lib/lib.c
new file mode 100644
index 0000000..52d638e
--- /dev/null
+++ b/arch/lib/lib.c
@@ -0,0 +1,294 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/init.h> /* initcall_t */
+#include <linux/kernel.h> /* SYSTEM_BOOTING */
+#include <linux/sched.h> /* struct task_struct */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <drivers/base/base.h>
+#include <linux/idr.h>
+#include <linux/rcupdate.h>
+#include "sim-init.h"
+#include "sim.h"
+
+enum system_states system_state = SYSTEM_BOOTING;
+/* glues */
+struct task_struct init_task;
+
+struct SimImported g_imported;
+
+
+#define RETURN_void(rettype, v) \
+ ({ \
+ (v); \
+ lib_softirq_wakeup(); \
+ })
+
+#define RETURN_nvoid(rettype, v) \
+ ({ \
+ rettype x = (v); \
+ lib_softirq_wakeup(); \
+ x; \
+ })
+
+#define FORWARDER1(name, type, rettype, t0) \
+ extern rettype name(t0); \
+ static rettype name ## _forwarder(t0 v0) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0))); \
+ }
+
+#define FORWARDER2(name, type, rettype, t0, t1) \
+ extern rettype name(t0, t1); \
+ static rettype name ## _forwarder(t0 v0, t1 v1) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1))); \
+ }
+#define FORWARDER3(name, type, rettype, t0, t1, t2) \
+ extern rettype name(t0, t1, t2); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER5(name, type, rettype, t0, t1, t2, t3, t4) \
+ extern rettype name(t0, t1, t2, t3, t4); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3, t4 v4) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3, v4))); \
+ }
+
+FORWARDER3(lib_dev_create, nvoid, struct SimDevice *, const char *, void *,
+ enum SimDevFlags);
+FORWARDER1(lib_dev_destroy, void, void, struct SimDevice *);
+FORWARDER2(lib_dev_set_address, void, void, struct SimDevice *,
+ unsigned char *);
+FORWARDER2(lib_dev_set_mtu, void, void, struct SimDevice *, int);
+FORWARDER2(lib_dev_create_packet, nvoid, struct SimDevicePacket,
+ struct SimDevice *, int);
+FORWARDER2(lib_dev_rx, void, void, struct SimDevice *, struct SimDevicePacket);
+
+FORWARDER4(lib_sock_socket, nvoid, int, int, int, int, struct SimSocket **);
+FORWARDER1(lib_sock_close, nvoid, int, struct SimSocket *);
+FORWARDER3(lib_sock_recvmsg, nvoid, ssize_t, struct SimSocket *,
+ struct msghdr *, int);
+FORWARDER3(lib_sock_sendmsg, nvoid, ssize_t, struct SimSocket *,
+ const struct msghdr *, int);
+FORWARDER3(lib_sock_getsockname, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_getpeername, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_bind, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int);
+FORWARDER4(lib_sock_connect, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int, int);
+FORWARDER2(lib_sock_listen, nvoid, int, struct SimSocket *, int);
+FORWARDER2(lib_sock_shutdown, nvoid, int, struct SimSocket *, int);
+FORWARDER3(lib_sock_accept, nvoid, int, struct SimSocket *,
+ struct SimSocket **, int);
+FORWARDER3(lib_sock_ioctl, nvoid, int, struct SimSocket *, int, char *);
+FORWARDER5(lib_sock_setsockopt, nvoid, int, struct SimSocket *, int, int,
+ const void *, int);
+FORWARDER5(lib_sock_getsockopt, nvoid, int, struct SimSocket *, int, int,
+ void *, int *);
+
+FORWARDER2(lib_sock_poll, void, void, struct SimSocket *, void *);
+FORWARDER1(lib_sock_pollfreewait, void, void, void *);
+
+FORWARDER1(lib_sys_iterate_files, void, void, const struct SimSysIterator *);
+FORWARDER4(lib_sys_file_read, nvoid, int, const struct SimSysFile *, char *,
+ int, int);
+FORWARDER4(lib_sys_file_write, nvoid, int, const struct SimSysFile *,
+ const char *, int, int);
+
+struct SimKernel *g_kernel;
+
+void lib_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel)
+{
+ /* make sure we can call the callbacks */
+ g_imported = *imported;
+ g_kernel = kernel;
+ exported->task_create = lib_task_create;
+ exported->task_destroy = lib_task_destroy;
+ exported->task_get_private = lib_task_get_private;
+ exported->sock_socket = lib_sock_socket_forwarder;
+ exported->sock_close = lib_sock_close_forwarder;
+ exported->sock_recvmsg = lib_sock_recvmsg_forwarder;
+ exported->sock_sendmsg = lib_sock_sendmsg_forwarder;
+ exported->sock_getsockname = lib_sock_getsockname_forwarder;
+ exported->sock_getpeername = lib_sock_getpeername_forwarder;
+ exported->sock_bind = lib_sock_bind_forwarder;
+ exported->sock_connect = lib_sock_connect_forwarder;
+ exported->sock_listen = lib_sock_listen_forwarder;
+ exported->sock_shutdown = lib_sock_shutdown_forwarder;
+ exported->sock_accept = lib_sock_accept_forwarder;
+ exported->sock_ioctl = lib_sock_ioctl_forwarder;
+ exported->sock_setsockopt = lib_sock_setsockopt_forwarder;
+ exported->sock_getsockopt = lib_sock_getsockopt_forwarder;
+
+ exported->sock_poll = lib_sock_poll_forwarder;
+ exported->sock_pollfreewait = lib_sock_pollfreewait_forwarder;
+
+ exported->dev_create = lib_dev_create_forwarder;
+ exported->dev_destroy = lib_dev_destroy_forwarder;
+ exported->dev_get_private = lib_dev_get_private;
+ exported->dev_set_address = lib_dev_set_address_forwarder;
+ exported->dev_set_mtu = lib_dev_set_mtu_forwarder;
+ exported->dev_create_packet = lib_dev_create_packet_forwarder;
+ exported->dev_rx = lib_dev_rx_forwarder;
+
+ exported->sys_iterate_files = lib_sys_iterate_files_forwarder;
+ exported->sys_file_write = lib_sys_file_write_forwarder;
+ exported->sys_file_read = lib_sys_file_read_forwarder;
+
+ pr_notice("%s", linux_banner);
+
+ rcu_init();
+
+ /* in drivers/base/core.c (called normally by drivers/base/init.c) */
+ devices_init();
+ /* in lib/idr.c (called normally by init/main.c) */
+ idr_init_cache();
+ vfs_caches_init(totalram_pages);
+
+ lib_proc_net_initialize();
+
+ /* and, then, call the normal initcalls */
+ initcall_t *call;
+ extern initcall_t __initcall_start[], __initcall_end[];
+
+ call = __initcall_start;
+ do {
+ (*call)();
+ call++;
+ } while (call < __initcall_end);
+
+ /* finally, put the system in RUNNING state. */
+ system_state = SYSTEM_RUNNING;
+}
+
+int lib_vprintf(const char *str, va_list args)
+{
+ return g_imported.vprintf(g_kernel, str, args);
+}
+void *lib_malloc(unsigned long size)
+{
+ return g_imported.malloc(g_kernel, size);
+}
+void lib_free(void *buffer)
+{
+ return g_imported.free(g_kernel, buffer);
+}
+void *lib_memcpy(void *dst, const void *src, unsigned long size)
+{
+ return g_imported.memcpy(g_kernel, dst, src, size);
+}
+void *lib_memset(void *dst, char value, unsigned long size)
+{
+ return g_imported.memset(g_kernel, dst, value, size);
+}
+unsigned long lib_random(void)
+{
+ return g_imported.random(g_kernel);
+}
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context), void *context)
+{
+ return g_imported.event_schedule_ns(g_kernel, ns, fn, context,
+ lib_update_jiffies);
+}
+void lib_event_cancel(void *event)
+{
+ return g_imported.event_cancel(g_kernel, event);
+}
+__u64 lib_current_ns(void)
+{
+ return g_imported.current_ns(g_kernel);
+}
+struct SimTaskTrampolineContext {
+ void (*callback)(void *);
+ void *context;
+};
+static void lib_task_start_trampoline(void *context)
+{
+ /* we use this trampoline solely for the purpose of executing
+ lib_update_jiffies prior to calling the callback. */
+ struct SimTaskTrampolineContext *ctx = context;
+ void (*callback)(void *) = ctx->callback;
+ void *callback_context = ctx->context;
+
+ lib_free(ctx);
+ lib_update_jiffies();
+ callback(callback_context);
+}
+struct SimTask *lib_task_start(void (*callback) (void *), void *context)
+{
+ struct SimTaskTrampolineContext *ctx =
+ lib_malloc(sizeof(struct SimTaskTrampolineContext));
+
+ if (!ctx)
+ return NULL;
+ ctx->callback = callback;
+ ctx->context = context;
+ return g_imported.task_start(g_kernel, &lib_task_start_trampoline, ctx);
+}
+void lib_task_wait(void)
+{
+ rcu_sched_qs();
+ g_imported.task_wait(g_kernel);
+ lib_update_jiffies();
+}
+struct SimTask *lib_task_current(void)
+{
+ return g_imported.task_current(g_kernel);
+}
+int lib_task_wakeup(struct SimTask *task)
+{
+ return g_imported.task_wakeup(g_kernel, task);
+}
+void lib_task_yield(void)
+{
+ rcu_idle_enter();
+ g_imported.task_yield(g_kernel);
+ rcu_idle_exit();
+ lib_update_jiffies();
+}
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len)
+{
+ return g_imported.dev_xmit(g_kernel, dev, data, len);
+}
+
+void lib_signal_raised(struct SimTask *task, int sig)
+{
+ g_imported.signal_raised(g_kernel, task, sig);
+}
+
+void lib_poll_event(int flag, void *context)
+{
+ g_imported.poll_event(flag, context);
+}
diff --git a/arch/lib/lib.h b/arch/lib/lib.h
new file mode 100644
index 0000000..abf2a26
--- /dev/null
+++ b/arch/lib/lib.h
@@ -0,0 +1,21 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#ifndef LIB_H
+#define LIB_H
+
+#include <linux/sched.h>
+
+struct SimTask {
+ struct list_head head;
+ struct task_struct kernel_task;
+ void *private;
+};
+
+#endif /* LIB_H */
--
2.1.0
timer related (internal) functions such as add_timer(),
do_gettimeofday() of kernel are trivially reimplemented
for libos. these eventually call the functions registered by lib_init()
API.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/hrtimer.c | 122 +++++++++++++++++++++++
arch/lib/tasklet-hrtimer.c | 57 +++++++++++
arch/lib/time.c | 144 +++++++++++++++++++++++++++
arch/lib/timer.c | 238 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 561 insertions(+)
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
diff --git a/arch/lib/hrtimer.c b/arch/lib/hrtimer.c
new file mode 100644
index 0000000..4565b59
--- /dev/null
+++ b/arch/lib/hrtimer.c
@@ -0,0 +1,122 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/hrtimer.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * hrtimer_init - initialize a timer to the given clock
+ * @timer: the timer to be initialized
+ * @clock_id: the clock to be used
+ * @mode: timer mode abs/rel
+ */
+void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
+{
+ memset(timer, 0, sizeof(*timer));
+}
+static void trampoline(void *context)
+{
+ struct hrtimer *timer = context;
+ enum hrtimer_restart restart = timer->function(timer);
+
+ if (restart == HRTIMER_RESTART) {
+ void *event =
+ lib_event_schedule_ns(ktime_to_ns(timer->_softexpires),
+ &trampoline, timer);
+ timer->base = event;
+ } else {
+ /* mark as completed. */
+ timer->base = 0;
+ }
+}
+/**
+ * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
+ * @timer: the timer to be added
+ * @tim: expiry time
+ * @delta_ns: "slack" range for the timer
+ * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
+ *
+ * Returns:
+ * 0 on success
+ * 1 when the timer was active
+ */
+int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns,
+ const enum hrtimer_mode mode,
+ int wakeup)
+{
+ int ret = hrtimer_cancel(timer);
+ s64 ns = ktime_to_ns(tim);
+ void *event;
+
+ if (mode == HRTIMER_MODE_ABS)
+ ns -= lib_current_ns();
+ timer->_softexpires = ns_to_ktime(ns);
+ event = lib_event_schedule_ns(ns, &trampoline, timer);
+ timer->base = event;
+ return ret;
+}
+/**
+ * hrtimer_try_to_cancel - try to deactivate a timer
+ * @timer: hrtimer to stop
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ * -1 when the timer is currently excuting the callback function and
+ * cannot be stopped
+ */
+int hrtimer_try_to_cancel(struct hrtimer *timer)
+{
+ /* Note: we cannot return -1 from this function.
+ see comment in hrtimer_cancel. */
+ if (timer->base == 0)
+ /* timer was not active yet */
+ return 1;
+ lib_event_cancel(timer->base);
+ timer->base = 0;
+ return 0;
+}
+/**
+ * hrtimer_cancel - cancel a timer and wait for the handler to finish.
+ * @timer: the timer to be cancelled
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ */
+int hrtimer_cancel(struct hrtimer *timer)
+{
+ /* Note: because we assume a uniprocessor non-interruptible */
+ /* system when running in the kernel, we know that the timer */
+ /* is not running when we execute this code, so, know that */
+ /* try_to_cancel cannot return -1 and we don't need to retry */
+ /* the cancel later to wait for the handler to finish. */
+ int ret = hrtimer_try_to_cancel(timer);
+
+ lib_assert(ret >= 0);
+ return ret;
+}
+int
+hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
+}
+int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, delta_ns, mode, 1);
+}
+
+int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
+{
+ *tp = ns_to_timespec(1);
+ return 0;
+}
diff --git a/arch/lib/tasklet-hrtimer.c b/arch/lib/tasklet-hrtimer.c
new file mode 100644
index 0000000..fef4902
--- /dev/null
+++ b/arch/lib/tasklet-hrtimer.c
@@ -0,0 +1,57 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
+{
+ struct tasklet_hrtimer *ttimer =
+ container_of(timer, struct tasklet_hrtimer, timer);
+
+ tasklet_schedule(&ttimer->tasklet);
+ return HRTIMER_NORESTART;
+}
+static void __tasklet_hrtimer_trampoline(unsigned long data)
+{
+ struct tasklet_hrtimer *ttimer = (void *)data;
+ enum hrtimer_restart restart;
+
+ restart = ttimer->function(&ttimer->timer);
+ if (restart != HRTIMER_NORESTART)
+ hrtimer_restart(&ttimer->timer);
+}
+/**
+ * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
+ * @ttimer: tasklet_hrtimer which is initialized
+ * @function: hrtimer callback function which gets called from softirq context
+ * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
+ * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
+ */
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+ enum hrtimer_restart (*function)(struct hrtimer *),
+ clockid_t which_clock, enum hrtimer_mode mode)
+{
+ hrtimer_init(&ttimer->timer, which_clock, mode);
+ ttimer->timer.function = __hrtimer_tasklet_trampoline;
+ tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
+ (unsigned long)ttimer);
+ ttimer->function = function;
+}
+
+void __tasklet_hi_schedule(struct tasklet_struct *t)
+{
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ void *event =
+ lib_event_schedule_ns(0, (void *)&t->func, (void *)t->data);
+ t->next = event;
+}
diff --git a/arch/lib/time.c b/arch/lib/time.c
new file mode 100644
index 0000000..b54be75
--- /dev/null
+++ b/arch/lib/time.c
@@ -0,0 +1,144 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/time.h>
+#include <linux/errno.h>
+#include <linux/timex.h>
+#include <linux/ktime.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+unsigned long volatile jiffies = INITIAL_JIFFIES;
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+struct timespec xtime;
+seqlock_t xtime_lock;
+/* accessed from wrap_clock from do_sys_settimeofday.
+ We don't call the latter so we should never access this variable. */
+struct timespec wall_to_monotonic;
+
+uint64_t ns_to_jiffies(uint64_t ns)
+{
+ do_div(ns, (1000000000 / HZ));
+ return ns;
+}
+
+void lib_update_jiffies(void)
+{
+ jiffies = ns_to_jiffies(lib_current_ns());
+ jiffies_64 = ns_to_jiffies(lib_current_ns());
+}
+
+struct timespec current_kernel_time(void)
+{
+ u64 ns = lib_current_ns();
+ struct timespec spec = ns_to_timespec(ns);
+
+ return spec;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ u64 ns = lib_current_ns();
+
+ *tv = ns_to_timeval(ns);
+}
+
+int do_adjtimex(struct timex *timex)
+{
+ lib_assert(false);
+ return -EPERM;
+}
+ktime_t ktime_get(void)
+{
+ u64 ns = lib_current_ns();
+
+ return ns_to_ktime(ns);
+}
+ktime_t ktime_get_with_offset(enum tk_offsets offs)
+{
+ /* FIXME */
+ return ktime_get();
+}
+
+/* copied from kernel/time/hrtimeer.c */
+#if BITS_PER_LONG < 64
+/*
+ * Divide a ktime value by a nanosecond value
+ */
+u64 __ktime_divns(const ktime_t kt, s64 div)
+{
+ u64 dclc;
+ int sft = 0;
+
+ dclc = ktime_to_ns(kt);
+ /* Make sure the divisor is less than 2^32: */
+ while (div >> 32) {
+ sft++;
+ div >>= 1;
+ }
+ dclc >>= sft;
+ do_div(dclc, (unsigned long)div);
+
+ return dclc;
+}
+#endif /* BITS_PER_LONG >= 64 */
+
+void update_xtime_cache(u64 nsec)
+{
+}
+unsigned long get_seconds(void)
+{
+ u64 ns = lib_current_ns();
+
+ do_div(ns, 1000000000);
+ return ns;
+}
+static unsigned long
+round_jiffies_common(unsigned long j,
+ bool force_up)
+{
+ int rem;
+ unsigned long original = j;
+
+ rem = j % HZ;
+ if (rem < HZ / 4 && !force_up) /* round down */
+ j = j - rem;
+ else /* round up */
+ j = j - rem + HZ;
+ if (j <= jiffies) /* rounding ate our timeout entirely; */
+ return original;
+ return j;
+}
+unsigned long round_jiffies(unsigned long j)
+{
+ return round_jiffies_common(j, false);
+}
+unsigned long round_jiffies_relative(unsigned long j)
+{
+ unsigned long j0 = jiffies;
+
+ /* Use j0 because jiffies might change while we run */
+ return round_jiffies_common(j + j0, false) - j0;
+}
+unsigned long round_jiffies_up(unsigned long j)
+{
+ return round_jiffies_common(j, true);
+}
+static void msleep_trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+void msleep(unsigned int msecs)
+{
+ lib_event_schedule_ns(((__u64)msecs) * 1000000, &msleep_trampoline,
+ lib_task_current());
+ lib_task_wait();
+}
diff --git a/arch/lib/timer.c b/arch/lib/timer.c
new file mode 100644
index 0000000..87d2283
--- /dev/null
+++ b/arch/lib/timer.c
@@ -0,0 +1,238 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * init_timer_key - initialize a timer
+ * @timer: the timer to be initialized
+ * @name: name of the timer
+ * @key: lockdep class key of the fake lock used for tracking timer
+ * sync lock dependencies
+ *
+ * init_timer_key() must be done to a timer prior calling *any* of the
+ * other timer functions.
+ */
+void init_timer_key(struct timer_list *timer,
+ unsigned int flags,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * Note: name and key are used for debugging. We ignore them
+ * unconditionally.
+ * Note: we do not initialize the lockdep map either because we
+ * don't care.
+ * and, finally, we never care about the base field either.
+ *
+ * So, for now, we have a timer which is marked as "not started"
+ * thanks to its entry.next field set to NULL (timer_pending
+ * will return 0)
+ */
+ timer->entry.next = NULL;
+ timer->base = 0;
+}
+
+struct list_head g_expired_events = LIST_HEAD_INIT(g_expired_events);
+struct list_head g_pending_events = LIST_HEAD_INIT(g_pending_events);
+
+static void run_timer_softirq(struct softirq_action *h)
+{
+ while (!list_empty(&g_expired_events)) {
+ struct timer_list *timer = list_first_entry(&g_expired_events,
+ struct timer_list,
+ entry);
+ void (*fn)(unsigned long);
+ unsigned long data;
+
+ fn = timer->function;
+ data = timer->data;
+ lib_assert(timer->base == 0);
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ fn(data);
+ }
+ }
+}
+
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
+}
+static void timer_trampoline(void *context)
+{
+ struct timer_list *timer;
+
+ ensure_softirq_opened();
+ timer = context;
+ timer->base = 0;
+ if (timer->entry.prev != LIST_POISON2)
+ list_del(&timer->entry);
+ list_add_tail(&timer->entry, &g_expired_events);
+ raise_softirq(TIMER_SOFTIRQ);
+}
+/**
+ * add_timer - start a timer
+ * @timer: the timer to be added
+ *
+ * The kernel will do a ->function(->data) callback from the
+ * timer interrupt at the ->expires point in the future. The
+ * current time is 'jiffies'.
+ *
+ * The timer's ->expires, ->function (and if the handler uses it, ->data)
+ * fields must be set prior calling this function.
+ *
+ * Timers with an ->expires field in the past will be executed in the next
+ * timer tick.
+ */
+void add_timer(struct timer_list *timer)
+{
+ __u64 delay_ns = 0;
+
+ lib_assert(!timer_pending(timer));
+ if (timer->expires <= jiffies)
+ delay_ns = (1000000000 / HZ); /* next tick. */
+ else
+ delay_ns =
+ ((__u64)timer->expires *
+ (1000000000 / HZ)) - lib_current_ns();
+ void *event = lib_event_schedule_ns(delay_ns, &timer_trampoline, timer);
+ /* store the external event in the base field */
+ /* to be able to retrieve it from del_timer */
+ timer->base = event;
+ /* finally, store timer in list of pending events. */
+ list_add_tail(&timer->entry, &g_pending_events);
+}
+/**
+ * del_timer - deactive a timer.
+ * @timer: the timer to be deactivated
+ *
+ * del_timer() deactivates a timer - this works on both active and inactive
+ * timers.
+ *
+ * The function returns whether it has deactivated a pending timer or not.
+ * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
+ * active timer returns 1.)
+ */
+int del_timer(struct timer_list *timer)
+{
+ int retval;
+
+ if (timer->entry.next == 0)
+ return 0;
+ if (timer->base != 0) {
+ lib_event_cancel(timer->base);
+ retval = 1;
+ } else
+ retval = 0;
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ }
+ return retval;
+}
+
+/* ////////////////////// */
+
+void init_timer_deferrable_key(struct timer_list *timer,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * From lwn.net:
+ * Timers which are initialized in this fashion will be
+ * recognized as deferrable by the kernel. They will not
+ * be considered when the kernel makes its "when should
+ * the next timer interrupt be?" decision. When the system
+ * is busy these timers will fire at the scheduled time. When
+ * things are idle, instead, they will simply wait until
+ * something more important wakes up the processor.
+ *
+ * Note: Our implementation of deferrable timers uses
+ * non-deferrable timers for simplicity.
+ */
+ init_timer_key(timer, 0, name, key);
+}
+/**
+ * add_timer_on - start a timer on a particular CPU
+ * @timer: the timer to be added
+ * @cpu: the CPU to start it on
+ *
+ * This is not very scalable on SMP. Double adds are not possible.
+ */
+void add_timer_on(struct timer_list *timer, int cpu)
+{
+ /* we ignore the cpu: we have only one. */
+ add_timer(timer);
+}
+/**
+ * mod_timer - modify a timer's timeout
+ * @timer: the timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer() is a more efficient way to update the expire field of an
+ * active timer (if the timer is inactive it will be activated)
+ *
+ * mod_timer(timer, expires) is equivalent to:
+ *
+ * del_timer(timer); timer->expires = expires; add_timer(timer);
+ *
+ * Note that if there are multiple unserialized concurrent users of the
+ * same timer, then mod_timer() is the only safe way to modify the timeout,
+ * since add_timer() cannot modify an already running timer.
+ *
+ * The function returns whether it has modified a pending timer or not.
+ * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
+ * active timer returns 1.)
+ */
+int mod_timer(struct timer_list *timer, unsigned long expires)
+{
+ int ret;
+
+ /* common optimization stolen from kernel */
+ if (timer_pending(timer) && timer->expires == expires)
+ return 1;
+
+ ret = del_timer(timer);
+ timer->expires = expires;
+ add_timer(timer);
+ return ret;
+}
+/**
+ * mod_timer_pending - modify a pending timer's timeout
+ * @timer: the pending timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer_pending() is the same for pending timers as mod_timer(),
+ * but will not re-activate and modify already deleted timers.
+ *
+ * It is useful for unserialized use of timers.
+ */
+int mod_timer_pending(struct timer_list *timer, unsigned long expires)
+{
+ if (timer_pending(timer))
+ return 0;
+ return mod_timer(timer, expires);
+}
+
+int mod_timer_pinned(struct timer_list *timer, unsigned long expires)
+{
+ if (timer->expires == expires && timer_pending(timer))
+ return 1;
+
+ return mod_timer(timer, expires);
+}
--
2.1.0
contexnt primitives of kernel such as soft interupts, scheduling,
tasklet are implemented for libos. these functions eventually call the
functions registered by lib_init() API as well.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sched.c | 406 +++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/softirq.c | 108 ++++++++++++++
arch/lib/tasklet.c | 76 ++++++++++
arch/lib/workqueue.c | 242 ++++++++++++++++++++++++++++++
4 files changed, 832 insertions(+)
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/workqueue.c
diff --git a/arch/lib/sched.c b/arch/lib/sched.c
new file mode 100644
index 0000000..98a568a
--- /dev/null
+++ b/arch/lib/sched.c
@@ -0,0 +1,406 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/nsproxy.h>
+#include <linux/hash.h>
+#include <net/net_namespace.h>
+#include "lib.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+/**
+ called by wait_event macro:
+ - prepare_to_wait
+ - schedule
+ - finish_wait
+ */
+
+struct SimTask *lib_task_create(void *private, unsigned long pid)
+{
+ struct SimTask *task = lib_malloc(sizeof(struct SimTask));
+ struct cred *cred;
+ struct nsproxy *ns;
+ struct user_struct *user;
+ struct thread_info *info;
+ struct pid *kpid;
+
+ if (!task)
+ return NULL;
+ memset(task, 0, sizeof(struct SimTask));
+ cred = lib_malloc(sizeof(struct cred));
+ if (!cred)
+ return NULL;
+ /* XXX: we could optimize away this allocation by sharing it
+ for all tasks */
+ ns = lib_malloc(sizeof(struct nsproxy));
+ if (!ns)
+ return NULL;
+ user = lib_malloc(sizeof(struct user_struct));
+ if (!user)
+ return NULL;
+ info = alloc_thread_info(&task->kernel_task);
+ if (!info)
+ return NULL;
+ kpid = lib_malloc(sizeof(struct pid));
+ if (!kpid)
+ return NULL;
+ kpid->numbers[0].nr = pid;
+ cred->fsuid = make_kuid(current_user_ns(), 0);
+ cred->fsgid = make_kgid(current_user_ns(), 0);
+ cred->user = user;
+ atomic_set(&cred->usage, 1);
+ info->task = &task->kernel_task;
+ info->preempt_count = 0;
+ info->flags = 0;
+ atomic_set(&ns->count, 1);
+ ns->uts_ns = 0;
+ ns->ipc_ns = 0;
+ ns->mnt_ns = 0;
+ ns->pid_ns_for_children = 0;
+ ns->net_ns = &init_net;
+ task->kernel_task.cred = cred;
+ task->kernel_task.pid = pid;
+ task->kernel_task.pids[PIDTYPE_PID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_PGID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_SID].pid = kpid;
+ task->kernel_task.nsproxy = ns;
+ task->kernel_task.stack = info;
+ /* this is a hack. */
+ task->kernel_task.group_leader = &task->kernel_task;
+ task->private = private;
+ return task;
+}
+void lib_task_destroy(struct SimTask *task)
+{
+ lib_free((void *)task->kernel_task.nsproxy);
+ lib_free((void *)task->kernel_task.cred);
+ lib_free((void *)task->kernel_task.cred->user);
+ free_thread_info(task->kernel_task.stack);
+ lib_free(task);
+}
+void *lib_task_get_private(struct SimTask *task)
+{
+ return task->private;
+}
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+ struct SimTask *task = lib_task_start((void (*)(void *))fn, arg);
+
+ return task->kernel_task.pid;
+}
+
+struct task_struct *get_current(void)
+{
+ struct SimTask *lib_task = lib_task_current();
+
+ return &lib_task->kernel_task;
+}
+
+struct thread_info *current_thread_info(void)
+{
+ return task_thread_info(get_current());
+}
+struct thread_info *alloc_thread_info(struct task_struct *task)
+{
+ return lib_malloc(sizeof(struct thread_info));
+}
+void free_thread_info(struct thread_info *ti)
+{
+ lib_free(ti);
+}
+
+
+void __put_task_struct(struct task_struct *t)
+{
+ lib_free(t);
+}
+
+void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ list_add(&wait->task_list, &q->task_list);
+}
+void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait->task_list, &q->task_list);
+}
+void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ if (wait->task_list.prev != LIST_POISON2)
+ list_del(&wait->task_list);
+}
+void
+prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ if (list_empty(&wait->task_list))
+ list_add_tail(&wait->task_list, &q->task_list);
+ set_current_state(state);
+}
+void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue(q, wait);
+ set_current_state(state);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ set_current_state(TASK_RUNNING);
+ if (!list_empty(&wait->task_list))
+ list_del_init(&wait->task_list);
+}
+int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync,
+ void *key)
+{
+ int ret = default_wake_function(wait, mode, sync, key);
+
+ if (ret && (wait->task_list.prev != LIST_POISON2))
+ list_del_init(&wait->task_list);
+
+ return ret;
+}
+
+int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ wait->flags |= WQ_FLAG_WOKEN;
+ return default_wake_function(wait, mode, sync, key);
+}
+
+void __init_waitqueue_head(wait_queue_head_t *q, const char *name,
+ struct lock_class_key *k)
+{
+ INIT_LIST_HEAD(&q->task_list);
+}
+/**
+ * wait_for_completion: - waits for completion of a task
+ * @x: holds the state of this particular completion
+ *
+ * This waits to be signaled for completion of a specific task. It is NOT
+ * interruptible and there is no timeout.
+ *
+ * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
+ * and interrupt capability. Also see complete().
+ */
+void wait_for_completion(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+}
+unsigned long wait_for_completion_timeout(struct completion *x,
+ unsigned long timeout)
+{
+ if (!x->done) {
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ wait.flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait.task_list, &x->wait.task_list);
+ do
+ timeout = schedule_timeout(timeout);
+ while (!x->done && timeout);
+ if (wait.task_list.prev != LIST_POISON2)
+ list_del(&wait.task_list);
+
+ if (!x->done)
+ return timeout;
+ }
+ x->done--;
+ return timeout ? : 1;
+}
+
+/**
+ * __wake_up - wake up threads blocked on a waitqueue.
+ * @q: the waitqueue
+ * @mode: which threads
+ * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ * @key: is directly passed to the wakeup function
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
+ */
+void __wake_up(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ wait_queue_t *curr, *next;
+
+ list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
+ unsigned flags = curr->flags;
+
+ if (curr->func(curr, mode, 0, key) &&
+ (flags & WQ_FLAG_EXCLUSIVE) &&
+ !--nr_exclusive)
+ break;
+ }
+}
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ __wake_up(q, mode, nr_exclusive, key);
+}
+int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
+ void *key)
+{
+ struct task_struct *task = (struct task_struct *)curr->private;
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+__sched int bit_wait(struct wait_bit_key *word)
+{
+ if (signal_pending_state(current->state, current))
+ return 1;
+ schedule();
+ return 0;
+}
+int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
+{
+ struct wait_bit_key *key = arg;
+ struct wait_bit_queue *wait_bit
+ = container_of(wait, struct wait_bit_queue, wait);
+
+ if (wait_bit->key.flags != key->flags ||
+ wait_bit->key.bit_nr != key->bit_nr ||
+ test_bit(key->bit_nr, key->flags))
+ return 0;
+ else
+ return autoremove_wake_function(wait, mode, sync, key);
+}
+void __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
+{
+ struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
+ if (waitqueue_active(wq))
+ __wake_up(wq, TASK_NORMAL, 1, &key);
+}
+void wake_up_bit(void *word, int bit)
+{
+ /* FIXME */
+ return;
+ __wake_up_bit(bit_waitqueue(word, bit), word, bit);
+}
+wait_queue_head_t *bit_waitqueue(void *word, int bit)
+{
+ const int shift = BITS_PER_LONG == 32 ? 5 : 6;
+ const struct zone *zone = page_zone(virt_to_page(word));
+ unsigned long val = (unsigned long)word << shift | bit;
+
+ return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
+}
+
+
+void schedule(void)
+{
+ lib_task_wait();
+}
+
+static void trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+
+signed long schedule_timeout(signed long timeout)
+{
+ u64 ns;
+ struct SimTask *self;
+
+ if (timeout == MAX_SCHEDULE_TIMEOUT) {
+ lib_task_wait();
+ return MAX_SCHEDULE_TIMEOUT;
+ }
+ lib_assert(timeout >= 0);
+ ns = ((__u64)timeout) * (1000000000 / HZ);
+ self = lib_task_current();
+ lib_event_schedule_ns(ns, &trampoline, self);
+ lib_task_wait();
+ /* we know that we are always perfectly on time. */
+ return 0;
+}
+
+signed long schedule_timeout_uninterruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+signed long schedule_timeout_interruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+
+void yield(void)
+{
+ lib_task_yield();
+}
+
+void complete_all(struct completion *x)
+{
+ x->done += UINT_MAX / 2;
+ __wake_up(&x->wait, TASK_NORMAL, 0, 0);
+}
+void complete(struct completion *x)
+{
+ x->done++;
+ __wake_up(&x->wait, TASK_NORMAL, 1, 0);
+}
+
+long wait_for_completion_interruptible_timeout(
+ struct completion *x, unsigned long timeout)
+{
+ return wait_for_completion_timeout(x, timeout);
+}
+int wait_for_completion_interruptible(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+ return 0;
+}
+int wake_up_process(struct task_struct *tsk)
+{
+ struct SimTask *lib_task =
+ container_of(tsk, struct SimTask, kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+int _cond_resched(void)
+{
+ /* we never schedule to decrease latency. */
+ return 0;
+}
+int idle_cpu(int cpu)
+{
+ /* we are never idle: we call this from rcutiny.c and the answer */
+ /* does not matter, really. */
+ return 0;
+}
+
+unsigned long long __attribute__((weak)) sched_clock(void)
+{
+ return (unsigned long long)(jiffies - INITIAL_JIFFIES)
+ * (NSEC_PER_SEC / HZ);
+}
+
+u64 local_clock(void)
+{
+ return sched_clock();
+}
+
+void __sched schedule_preempt_disabled(void)
+{
+}
+
+void resched_cpu(int cpu)
+{
+ rcu_sched_qs();
+}
diff --git a/arch/lib/softirq.c b/arch/lib/softirq.c
new file mode 100644
index 0000000..3f6363a
--- /dev/null
+++ b/arch/lib/softirq.c
@@ -0,0 +1,108 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim-init.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+
+static struct softirq_action softirq_vec[NR_SOFTIRQS];
+static struct SimTask *g_softirq_task = 0;
+static int g_n_raises = 0;
+
+void lib_softirq_wakeup(void)
+{
+ g_n_raises++;
+ lib_task_wakeup(g_softirq_task);
+}
+
+static void softirq_task_function(void *context)
+{
+ while (true) {
+ do_softirq();
+ g_n_raises--;
+ if (g_n_raises == 0 || local_softirq_pending() == 0) {
+ g_n_raises = 0;
+ lib_task_wait();
+ }
+ }
+}
+
+static void ensure_task_created(void)
+{
+ if (g_softirq_task != 0)
+ return;
+ g_softirq_task = lib_task_start(&softirq_task_function, 0);
+}
+
+void open_softirq(int nr, void (*action)(struct softirq_action *))
+{
+ ensure_task_created();
+ softirq_vec[nr].action = action;
+}
+#define MAX_SOFTIRQ_RESTART 10
+
+void do_softirq(void)
+{
+ __u32 pending;
+ int max_restart = MAX_SOFTIRQ_RESTART;
+ struct softirq_action *h;
+
+ pending = local_softirq_pending();
+
+restart:
+ /* Reset the pending bitmask before enabling irqs */
+ set_softirq_pending(0);
+
+ local_irq_enable();
+
+ h = softirq_vec;
+
+ do {
+ if (pending & 1)
+ h->action(h);
+ h++;
+ pending >>= 1;
+ } while (pending);
+
+ local_irq_disable();
+
+ pending = local_softirq_pending();
+ if (pending && --max_restart)
+ goto restart;
+}
+void raise_softirq_irqoff(unsigned int nr)
+{
+ __raise_softirq_irqoff(nr);
+
+ lib_softirq_wakeup();
+}
+void __raise_softirq_irqoff(unsigned int nr)
+{
+ /* trace_softirq_raise(nr); */
+ or_softirq_pending(1UL << nr);
+}
+int __cond_resched_softirq(void)
+{
+ /* tell the caller that we did not need to re-schedule. */
+ return 0;
+}
+void raise_softirq(unsigned int nr)
+{
+ /* copy/paste from kernel/softirq.c */
+ unsigned long flags;
+
+ local_irq_save(flags);
+ raise_softirq_irqoff(nr);
+ local_irq_restore(flags);
+}
+
+void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
+{
+}
diff --git a/arch/lib/tasklet.c b/arch/lib/tasklet.c
new file mode 100644
index 0000000..6cc68f4
--- /dev/null
+++ b/arch/lib/tasklet.c
@@ -0,0 +1,76 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void tasklet_init(struct tasklet_struct *t,
+ void (*func)(unsigned long), unsigned long data)
+{
+ t->next = NULL;
+ t->state = 0;
+ atomic_set(&t->count, 0);
+ t->func = func;
+ t->data = data;
+}
+
+void tasklet_kill(struct tasklet_struct *t)
+{
+ /* theoretically, called from user context */
+ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
+ do
+ lib_task_yield();
+ while (test_bit(TASKLET_STATE_SCHED, &t->state));
+ }
+ clear_bit(TASKLET_STATE_SCHED, &t->state);
+}
+struct tasklet_struct *g_sched_events = NULL;
+static void run_tasklet_softirq(struct softirq_action *h)
+{
+ /* while (!list_empty (&g_sched_events)) */
+ /* { */
+ struct tasklet_struct *tasklet = g_sched_events;
+
+ if (atomic_read(&tasklet->count) == 0) {
+ /* this tasklet is enabled so, we run it. */
+ test_and_clear_bit(TASKLET_STATE_SCHED, &tasklet->state);
+ tasklet->func(tasklet->data);
+ }
+ /* } */
+}
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TASKLET_SOFTIRQ, run_tasklet_softirq);
+}
+static void trampoline(void *context)
+{
+ ensure_softirq_opened();
+ struct tasklet_struct *tasklet = context;
+ /* allow the tasklet to re-schedule itself */
+ lib_assert(tasklet->next != 0);
+ tasklet->next = 0;
+ g_sched_events = tasklet;
+ raise_softirq(TASKLET_SOFTIRQ);
+}
+void __tasklet_schedule(struct tasklet_struct *t)
+{
+ void *event;
+
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ event = lib_event_schedule_ns(0, &trampoline, t);
+ t->next = event;
+}
diff --git a/arch/lib/workqueue.c b/arch/lib/workqueue.c
new file mode 100644
index 0000000..bd0e9c5
--- /dev/null
+++ b/arch/lib/workqueue.c
@@ -0,0 +1,242 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+/* copy from kernel/workqueue.c */
+typedef unsigned long mayday_mask_t;
+struct workqueue_struct {
+ unsigned int flags; /* W: WQ_* flags */
+ union {
+ struct cpu_workqueue_struct __percpu *pcpu;
+ struct cpu_workqueue_struct *single;
+ unsigned long v;
+ } cpu_wq; /* I: cwq's */
+ struct list_head list; /* W: list of all workqueues */
+
+ struct mutex flush_mutex; /* protects wq flushing */
+ int work_color; /* F: current work color */
+ int flush_color; /* F: current flush color */
+ atomic_t nr_cwqs_to_flush; /* flush in progress */
+ struct wq_flusher *first_flusher; /* F: first flusher */
+ struct list_head flusher_queue; /* F: flush waiters */
+ struct list_head flusher_overflow; /* F: flush overflow list */
+
+ mayday_mask_t mayday_mask; /* cpus requesting rescue */
+ struct worker *rescuer; /* I: rescue worker */
+
+ int nr_drainers; /* W: drain in progress */
+ int saved_max_active; /* W: saved cwq max_active */
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map lockdep_map;
+#endif
+ char name[]; /* I: workqueue name */
+};
+
+struct wq_barrier {
+ struct SimTask *waiter;
+ struct workqueue_struct wq;
+};
+
+static void
+workqueue_function(void *context)
+{
+ struct workqueue_struct *wq = context;
+
+ while (true) {
+ lib_task_wait();
+ while (!list_empty(&wq->list)) {
+ struct work_struct *work =
+ list_first_entry(&wq->list, struct work_struct,
+ entry);
+ work_func_t f = work->func;
+
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ f(work);
+ }
+ }
+ }
+}
+
+static struct SimTask *workqueue_task(struct workqueue_struct *wq)
+{
+ struct wq_barrier *barr = container_of(wq, struct wq_barrier, wq);
+
+ if (barr->waiter == 0)
+ barr->waiter = lib_task_start(&workqueue_function, wq);
+ return barr->waiter;
+}
+
+static int flush_entry(struct workqueue_struct *wq, struct list_head *prev)
+{
+ int active = 0;
+
+ if (!list_empty(&wq->list)) {
+ active = 1;
+ lib_task_wakeup(workqueue_task(wq));
+ /* XXX: should wait for completion? but this will block
+ and init won't return.. */
+ /* lib_task_wait (); */
+ }
+
+ return active;
+}
+
+void delayed_work_timer_fn(unsigned long data)
+{
+ struct delayed_work *dwork = (struct delayed_work *)data;
+ struct work_struct *work = &dwork->work;
+
+ list_add_tail(&work->entry, &dwork->wq->list);
+ lib_task_wakeup(workqueue_task(dwork->wq));
+}
+
+bool queue_work_on(int cpu, struct workqueue_struct *wq,
+ struct work_struct *work)
+{
+ int ret = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ list_add_tail(&work->entry, &wq->list);
+ lib_task_wakeup(workqueue_task(wq));
+ ret = 1;
+ }
+ return ret;
+}
+
+void flush_scheduled_work(void)
+{
+ flush_entry(system_wq, system_wq->list.prev);
+}
+bool flush_work(struct work_struct *work)
+{
+ return flush_entry(system_wq, &work->entry);
+}
+void flush_workqueue(struct workqueue_struct *wq)
+{
+ flush_entry(wq, wq->list.prev);
+}
+bool cancel_work_sync(struct work_struct *work)
+{
+ int retval = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)))
+ /* work was not yet queued */
+ return 0;
+ if (!list_empty(&work->entry)) {
+ /* work was queued. now unqueued. */
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ retval = 1;
+ }
+ }
+ return retval;
+}
+bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ int ret = 0;
+ struct timer_list *timer = &dwork->timer;
+ struct work_struct *work = &dwork->work;
+
+ if (delay == 0)
+ return queue_work(wq, work);
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ lib_assert(!timer_pending(timer));
+ dwork->wq = wq;
+ /* This stores cwq for the moment, for the timer_fn */
+ timer->expires = jiffies + delay;
+ timer->data = (unsigned long)dwork;
+ timer->function = delayed_work_timer_fn;
+ add_timer(timer);
+ ret = 1;
+ }
+ return ret;
+}
+bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ del_timer(&dwork->timer);
+ __clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&dwork->work));
+ return queue_delayed_work(wq, dwork, delay);
+}
+bool cancel_delayed_work(struct delayed_work *dwork)
+{
+ del_timer(&dwork->timer);
+ return cancel_work_sync(&dwork->work);
+}
+
+struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
+ unsigned int flags,
+ int max_active,
+ struct lock_class_key *key,
+ const char *lock_name, ...)
+{
+ va_list args, args1;
+ struct wq_barrier *barr;
+ struct workqueue_struct *wq;
+ size_t namelen;
+
+ /* determine namelen, allocate wq and format name */
+ va_start(args, lock_name);
+ va_copy(args1, args);
+ namelen = vsnprintf(NULL, 0, fmt, args) + 1;
+
+ barr = kzalloc(sizeof(*barr) + namelen, GFP_KERNEL);
+ if (!barr)
+ goto err;
+ barr->waiter = 0;
+ wq = &barr->wq;
+
+ vsnprintf(wq->name, namelen, fmt, args1);
+ va_end(args);
+ va_end(args1);
+
+ max_active = max_active ? : WQ_DFL_ACTIVE;
+ /* init wq */
+ wq->flags = flags;
+ wq->saved_max_active = max_active;
+ mutex_init(&wq->flush_mutex);
+ atomic_set(&wq->nr_cwqs_to_flush, 0);
+ INIT_LIST_HEAD(&wq->flusher_queue);
+ INIT_LIST_HEAD(&wq->flusher_overflow);
+
+ lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
+ INIT_LIST_HEAD(&wq->list);
+
+ /* start waiter task */
+ workqueue_task(wq);
+ return wq;
+err:
+ if (barr)
+ kfree(barr);
+ return NULL;
+}
+
+struct workqueue_struct *system_wq __read_mostly;
+struct workqueue_struct *system_power_efficient_wq __read_mostly;
+/* from linux/workqueue.h */
+#define system_nrt_wq __system_nrt_wq()
+
+static int __init init_workqueues(void)
+{
+ system_wq = alloc_workqueue("events", 0, 0);
+ system_power_efficient_wq = alloc_workqueue("events_power_efficient",
+ WQ_POWER_EFFICIENT, 0);
+ return 0;
+}
+early_initcall(init_workqueues);
--
2.1.0
This interacts with fs/proc_fs.c for sysctl-like interface registed via
lib_init() API.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sysctl.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 270 insertions(+)
create mode 100644 arch/lib/sysctl.c
diff --git a/arch/lib/sysctl.c b/arch/lib/sysctl.c
new file mode 100644
index 0000000..5f08f9f
--- /dev/null
+++ b/arch/lib/sysctl.c
@@ -0,0 +1,270 @@
+/*
+ * sysctl wrapper for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/mman.h>
+#include <linux/ratelimit.h>
+#include <linux/proc_fs.h>
+#include "sim-assert.h"
+#include "sim-types.h"
+
+int drop_caches_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_writeback_centisecs_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int scan_unevictable_handler(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int sched_rt_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int sysctl_overcommit_memory = OVERCOMMIT_GUESS;
+int sysctl_overcommit_ratio = 50;
+int sysctl_panic_on_oom = 0;
+int sysctl_oom_dump_tasks = 0;
+int sysctl_oom_kill_allocating_task = 0;
+int sysctl_nr_trim_pages = 0;
+int sysctl_drop_caches = 0;
+int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES - 1] = { 32 };
+unsigned int sysctl_sched_child_runs_first = 0;
+unsigned int sysctl_sched_compat_yield = 0;
+unsigned int sysctl_sched_rt_period = 1000000;
+int sysctl_sched_rt_runtime = 950000;
+
+int vm_highmem_is_dirtyable;
+unsigned long vm_dirty_bytes = 0;
+int vm_dirty_ratio = 20;
+int dirty_background_ratio = 10;
+unsigned int dirty_expire_interval = 30 * 100;
+unsigned int dirty_writeback_interval = 5 * 100;
+unsigned long dirty_background_bytes = 0;
+int percpu_pagelist_fraction = 0;
+int panic_timeout = 0;
+int panic_on_oops = 0;
+int printk_delay_msec = 0;
+int panic_on_warn = 0;
+DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
+
+#define RESERVED_PIDS 300
+int pid_max = PID_MAX_DEFAULT;
+int pid_max_min = RESERVED_PIDS + 1;
+int pid_max_max = PID_MAX_LIMIT;
+int min_free_kbytes = 1024;
+int max_threads = 100;
+int laptop_mode = 0;
+
+#define DEFAULT_MESSAGE_LOGLEVEL 4
+#define MINIMUM_CONSOLE_LOGLEVEL 1
+#define DEFAULT_CONSOLE_LOGLEVEL 7
+int console_printk[4] = {
+ DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
+ DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
+ MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
+ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
+};
+
+int print_fatal_signals = 0;
+unsigned int core_pipe_limit = 0;
+int core_uses_pid = 0;
+int vm_swappiness = 60;
+int nr_pdflush_threads = 0;
+unsigned long scan_unevictable_pages = 0;
+int suid_dumpable = 0;
+int page_cluster = 0;
+int block_dump = 0;
+int C_A_D = 0;
+#include <linux/nsproxy.h>
+struct nsproxy init_nsproxy;
+#include <linux/reboot.h>
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
+unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
+
+int pdflush_proc_obsolete(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return nr_pdflush_threads;
+}
+#include <linux/fs.h>
+
+/**
+ * Honestly, I don't understand half of that code.
+ * It was modeled after fs/proc/proc_sysctl.c proc_sys_readdir
+ *
+ * Me either ;) (Hajime, Jan 2013)
+ */
+
+/* from proc_sysctl.c (XXX) */
+extern struct ctl_table_root sysctl_table_root;
+void ctl_table_first_entry(struct ctl_dir *dir,
+ struct ctl_table_header **phead, struct ctl_table **pentry);
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry);
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen);
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir);
+/* for init_net (XXX, should be fixed) */
+#include <net/net_namespace.h>
+
+static void iterate_table_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table *entry;
+
+ for (entry = head->ctl_table; entry->procname; entry++) {
+ bool may_read = (head->ctl_table->mode & MAY_READ);
+ bool may_write = (head->ctl_table->mode & MAY_WRITE);
+ int flags = 0;
+
+ flags |= may_read ? SIM_SYS_FILE_READ : 0;
+ flags |= may_write ? SIM_SYS_FILE_WRITE : 0;
+ iter->report_file(iter, entry->procname, flags,
+ (struct SimSysFile *)entry);
+ }
+}
+
+
+static void iterate_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table_header *h = NULL;
+ struct ctl_table *entry;
+ struct ctl_dir *ctl_dir;
+
+ ctl_dir = container_of(head, struct ctl_dir, header);
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
+ struct ctl_dir *dir;
+ int ret;
+ const char *procname;
+
+ /* copy from sysctl_follow_link () */
+ if (S_ISLNK(entry->mode)) {
+ dir = ctl_table_xlate_dir(&init_net.sysctls, h->parent);
+ if (IS_ERR(dir)) {
+ ret = PTR_ERR(dir);
+ lib_assert(false);
+ } else {
+ procname = entry->procname;
+ h = NULL;
+ entry =
+ ctl_table_find_entry(&h, dir, procname,
+ strlen(procname));
+ ret = -ENOENT;
+ }
+ }
+
+ if (S_ISDIR(entry->mode)) {
+ iter->report_start_dir(iter, entry->procname);
+ iterate_recursive(iter, h);
+ iter->report_end_dir(iter);
+ } else
+ iterate_table_recursive(iter, h);
+ }
+
+}
+
+
+void lib_sys_iterate_files(const struct SimSysIterator *iter)
+{
+ struct ctl_table_header *root =
+ &sysctl_table_root.default_set.dir.header;
+
+ iterate_recursive(iter, root);
+}
+
+int lib_sys_file_read(const struct SimSysFile *file, char *buffer, int size,
+ int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 0, buffer, &result, &ppos);
+ return result;
+}
+int lib_sys_file_write(const struct SimSysFile *file, const char *buffer,
+ int size, int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 1, (char *)buffer, &result, &ppos);
+ return result;
+}
--
2.1.0
These files are used to provide the same function calls so that other
network stack code keeps untouched.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Christoph Paasch <[email protected]>
---
arch/lib/capability.c | 25 +++++
arch/lib/filemap.c | 32 ++++++
arch/lib/fs.c | 70 ++++++++++++
arch/lib/glue.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/modules.c | 36 +++++++
arch/lib/pid.c | 29 +++++
arch/lib/print.c | 56 ++++++++++
arch/lib/proc.c | 34 ++++++
arch/lib/random.c | 53 +++++++++
arch/lib/sysfs.c | 83 +++++++++++++++
arch/lib/vmscan.c | 26 +++++
11 files changed, 733 insertions(+)
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/vmscan.c
diff --git a/arch/lib/capability.c b/arch/lib/capability.c
new file mode 100644
index 0000000..3a1f301
--- /dev/null
+++ b/arch/lib/capability.c
@@ -0,0 +1,25 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "linux/capability.h"
+
+struct sock;
+struct sk_buff;
+
+int file_caps_enabled = 0;
+
+int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+ return 0;
+}
+
+bool file_ns_capable(const struct file *file, struct user_namespace *ns,
+ int cap)
+{
+ return true;
+}
diff --git a/arch/lib/filemap.c b/arch/lib/filemap.c
new file mode 100644
index 0000000..ce424ff
--- /dev/null
+++ b/arch/lib/filemap.c
@@ -0,0 +1,32 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/fs.h>
+
+
+ssize_t generic_file_aio_read(struct kiocb *a, const struct iovec *b,
+ unsigned long c, loff_t d)
+{
+ lib_assert(false);
+
+ return 0;
+}
+
+int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return -ENOSYS;
+}
+
+ssize_t
+generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+ return 0;
+}
diff --git a/arch/lib/fs.c b/arch/lib/fs.c
new file mode 100644
index 0000000..324e10b
--- /dev/null
+++ b/arch/lib/fs.c
@@ -0,0 +1,70 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <fs/mount.h>
+
+#include "sim-assert.h"
+
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock);
+unsigned int dirtytime_expire_interval;
+
+void __init mnt_init(void)
+{
+}
+
+/* Implementation taken from vfs_kern_mount from linux/namespace.c */
+struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
+{
+ static struct mount local_mnt;
+ static int count = 0;
+ struct mount *mnt = &local_mnt;
+ struct dentry *root = 0;
+
+ /* XXX */
+ if (count != 0) return &local_mnt.mnt;
+ count++;
+
+ memset(mnt, 0, sizeof(struct mount));
+ if (!type)
+ return ERR_PTR(-ENODEV);
+ int flags = MS_KERNMOUNT;
+ char *name = (char *)type->name;
+
+ if (flags & MS_KERNMOUNT)
+ mnt->mnt.mnt_flags = MNT_INTERNAL;
+
+ root = type->mount(type, flags, name, data);
+ if (IS_ERR(root))
+ return ERR_CAST(root);
+
+ mnt->mnt.mnt_root = root;
+ mnt->mnt.mnt_sb = root->d_sb;
+ mnt->mnt_mountpoint = mnt->mnt.mnt_root;
+ mnt->mnt_parent = mnt;
+ /* DCE is monothreaded , so we do not care of lock here */
+ list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
+
+ return &mnt->mnt;
+}
+void inode_wait_for_writeback(struct inode *inode)
+{
+}
+void truncate_inode_pages_final(struct address_space *mapping)
+{
+}
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
+
+unsigned int nr_free_buffer_pages(void)
+{
+ return 1024;
+}
diff --git a/arch/lib/glue.c b/arch/lib/glue.c
new file mode 100644
index 0000000..93f72d1
--- /dev/null
+++ b/arch/lib/glue.c
@@ -0,0 +1,289 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <linux/types.h> /* loff_t */
+#include <linux/errno.h> /* ESPIPE */
+#include <linux/pagemap.h> /* PAGE_CACHE_SIZE */
+#include <linux/limits.h> /* NAME_MAX */
+#include <linux/statfs.h> /* struct kstatfs */
+#include <linux/bootmem.h> /* HASHDIST_DEFAULT */
+#include <linux/utsname.h>
+#include <linux/binfmts.h>
+#include <linux/init_task.h>
+#include <linux/sched/rt.h>
+#include <linux/backing-dev.h>
+#include <stdarg.h>
+#include "sim-assert.h"
+#include "sim.h"
+#include "lib.h"
+
+
+struct pipe_buffer;
+struct file;
+struct pipe_inode_info;
+struct wait_queue_t;
+struct kernel_param;
+struct super_block;
+struct tvec_base {};
+
+/* defined in sched.c, used in net/sched/em_meta.c */
+unsigned long avenrun[3];
+/* defined in mm/page_alloc.c, used in net/xfrm/xfrm_hash.c */
+int hashdist = HASHDIST_DEFAULT;
+/* defined in mm/page_alloc.c */
+struct pglist_data __refdata contig_page_data;
+/* defined in linux/mmzone.h mm/memory.c */
+struct page *mem_map = 0;
+/* used during boot. */
+struct tvec_base boot_tvec_bases;
+/* used by sysinfo in kernel/timer.c */
+int nr_threads = 0;
+/* not very useful in mm/vmstat.c */
+atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
+
+/* XXX: used in network stack ! */
+unsigned long num_physpages = 0;
+unsigned long totalram_pages = 0;
+
+/* XXX figure out initial value */
+unsigned int interrupt_pending = 0;
+static unsigned long g_irqflags = 0;
+static unsigned long local_irqflags = 0;
+int overflowgid = 0;
+int overflowuid = 0;
+int fs_overflowgid = 0;
+int fs_overflowuid = 0;
+unsigned long sysctl_overcommit_kbytes __read_mostly;
+DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
+static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
+
+struct backing_dev_info noop_backing_dev_info = {
+ .name = "noop",
+ .capabilities = 0,
+};
+
+/* from rt.c */
+int sched_rr_timeslice = RR_TIMESLICE;
+/* from main.c */
+bool initcall_debug;
+bool static_key_initialized __read_mostly = false;
+unsigned long __start_rodata, __end_rodata;
+
+unsigned long arch_local_save_flags(void)
+{
+ return local_irqflags;
+}
+void arch_local_irq_restore(unsigned long flags)
+{
+ local_irqflags = flags;
+}
+
+
+unsigned long long nr_context_switches(void)
+{
+ /* we just need to return >0 to avoid the warning
+ in kernel/rcupdate.c */
+ return 1;
+}
+
+
+long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long start, unsigned long nr_pages,
+ int write, int force, struct page **pages,
+ struct vm_area_struct **vmas)
+{
+ /* in practice, this function is never called. It's linked in because */
+ /* we link in get_user_pages_fast which is included only because it */
+ /* is located in mm/util.c */
+ lib_assert(false);
+ return 0;
+}
+
+
+void dump_stack(void)
+{
+ /* we assert to make sure that we catch whoever calls dump_stack */
+ lib_assert(false);
+}
+
+
+void lib_printf(const char *str, ...)
+{
+ va_list args;
+
+ va_start(args, str);
+ lib_vprintf(str, args);
+ va_end(args);
+}
+
+#include <linux/vmalloc.h>
+#include <linux/kmemleak.h>
+
+static unsigned long __meminitdata nr_kernel_pages = 8192;
+static unsigned long __meminitdata nr_all_pages = 81920;
+/*
+ * allocate a large system hash table from bootmem
+ * - it is assumed that the hash table must contain an exact power-of-2
+ * quantity of entries
+ * - limit is the number of hash buckets, not the total allocation size
+ */
+void *__init alloc_large_system_hash(const char *tablename,
+ unsigned long bucketsize,
+ unsigned long numentries,
+ int scale,
+ int flags,
+ unsigned int *_hash_shift,
+ unsigned int *_hash_mask,
+ unsigned long low_limit,
+ unsigned long high_limit)
+{
+ unsigned long long max = high_limit;
+ unsigned long log2qty, size;
+ void *table = NULL;
+
+ /* allow the kernel cmdline to have a say */
+ if (!numentries) {
+ /* round applicable memory size up to nearest megabyte */
+ numentries = nr_kernel_pages;
+ numentries += (1UL << (20 - PAGE_SHIFT)) - 1;
+ numentries >>= 20 - PAGE_SHIFT;
+ numentries <<= 20 - PAGE_SHIFT;
+
+ /* limit to 1 bucket per 2^scale bytes of low memory */
+ if (scale > PAGE_SHIFT)
+ numentries >>= (scale - PAGE_SHIFT);
+ else
+ numentries <<= (PAGE_SHIFT - scale);
+
+ /* Make sure we've got at least a 0-order allocation.. */
+ if (unlikely(flags & HASH_SMALL)) {
+ /* Makes no sense without HASH_EARLY */
+ WARN_ON(!(flags & HASH_EARLY));
+ if (!(numentries >> *_hash_shift)) {
+ numentries = 1UL << *_hash_shift;
+ BUG_ON(!numentries);
+ }
+ } else if (unlikely((numentries * bucketsize) < PAGE_SIZE))
+ numentries = PAGE_SIZE / bucketsize;
+ }
+ numentries = roundup_pow_of_two(numentries);
+
+ /* limit allocation size to 1/16 total memory by default */
+ if (max == 0) {
+ max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
+ do_div(max, bucketsize);
+ }
+
+ if (numentries > max)
+ numentries = max;
+
+ log2qty = ilog2(numentries);
+
+ do {
+ size = bucketsize << log2qty;
+ if (flags & HASH_EARLY)
+ table = alloc_bootmem_nopanic(size);
+ else if (hashdist)
+ table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
+ else {
+ /*
+ * If bucketsize is not a power-of-two, we may free
+ * some pages at the end of hash table which
+ * alloc_pages_exact() automatically does
+ */
+ if (get_order(size) < MAX_ORDER) {
+ table = alloc_pages_exact(size, GFP_ATOMIC);
+ kmemleak_alloc(table, size, 1, GFP_ATOMIC);
+ }
+ }
+ } while (!table && size > PAGE_SIZE && --log2qty);
+
+ if (!table)
+ panic("Failed to allocate %s hash table\n", tablename);
+
+ pr_info("%s hash table entries: %d (order: %d, %lu bytes)\n",
+ tablename,
+ (1U << log2qty),
+ ilog2(size) - PAGE_SHIFT,
+ size);
+
+ if (_hash_shift)
+ *_hash_shift = log2qty;
+ if (_hash_mask)
+ *_hash_mask = (1 << log2qty) - 1;
+
+ return table;
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ /* This function is called from the ip layer to get information about
+ the amount of memory in the system and make some educated guesses
+ about some default buffer sizes. We pick a value which ensures
+ small buffers. */
+ val->totalram = 0;
+}
+int slab_is_available(void)
+{
+ /* called from kernel/param.c. */
+ return 1;
+}
+
+/* used from kern_ptr_validate from mm/util.c which is never called */
+void *high_memory = 0;
+
+
+
+void async_synchronize_full(void)
+{
+ /* called from drivers/base/ *.c */
+ /* there is nothing to do, really. */
+}
+
+int send_sig(int signal, struct task_struct *task, int x)
+{
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ lib_signal_raised((struct SimTask *)lib_task, signal);
+ /* lib_assert (false); */
+ return 0;
+}
+unsigned long get_taint(void)
+{
+ /* never tainted. */
+ return 0;
+}
+void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
+{
+}
+struct pid *cad_pid = 0;
+
+void add_device_randomness(const void *buf, unsigned int size)
+{
+}
+
+int sched_rr_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ return 0;
+}
+
+int sysctl_max_threads(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return 1;
+}
+
+void on_each_cpu_mask(const struct cpumask *mask,
+ smp_call_func_t func, void *info, bool wait)
+{
+}
diff --git a/arch/lib/modules.c b/arch/lib/modules.c
new file mode 100644
index 0000000..ca43fdc
--- /dev/null
+++ b/arch/lib/modules.c
@@ -0,0 +1,36 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-assert.h"
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+
+int modules_disabled = 0;
+char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
+
+static struct module_version_attribute g_empty_attr_buffer;
+/* we make the array empty by default because, really, we don't need */
+/* to look at the builtin params */
+const struct kernel_param __start___param[] = {{0}} ;
+const struct kernel_param __stop___param[] = {{0}} ;
+const struct module_version_attribute *__start___modver[] = {
+ &g_empty_attr_buffer};
+const struct module_version_attribute *__stop___modver[] = {
+ &g_empty_attr_buffer};
+
+struct module_attribute module_uevent;
+struct ctl_table usermodehelper_table[] = {};
+
+int __request_module(bool wait, const char *fmt, ...)
+{
+ /* we really should never be trying to load modules that way. */
+ /* lib_assert (false); */
+ return 0;
+}
diff --git a/arch/lib/pid.c b/arch/lib/pid.c
new file mode 100644
index 0000000..00cf7b6
--- /dev/null
+++ b/arch/lib/pid.c
@@ -0,0 +1,29 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/pid.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void put_pid(struct pid *pid)
+{
+}
+pid_t pid_vnr(struct pid *pid)
+{
+ return pid_nr(pid);
+}
+struct task_struct *find_task_by_vpid(pid_t nr)
+{
+ lib_assert(false);
+ return 0;
+}
+struct pid *find_get_pid(int nr)
+{
+ lib_assert(false);
+ return 0;
+}
diff --git a/arch/lib/print.c b/arch/lib/print.c
new file mode 100644
index 0000000..09b1bb5
--- /dev/null
+++ b/arch/lib/print.c
@@ -0,0 +1,56 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <stdarg.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int dmesg_restrict = 1;
+
+/* from lib/vsprintf.c */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+int printk(const char *fmt, ...)
+{
+ va_list args;
+ static char buf[256];
+ int value;
+
+ va_start(args, fmt);
+ value = vsnprintf(buf, 256, printk_skip_level(fmt), args);
+ lib_printf("<%c>%s", printk_get_level(fmt), buf);
+ va_end(args);
+ return value;
+}
+void panic(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+ lib_assert(false);
+}
+
+void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+
+ printk("%s:%d -- ", file, line);
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+}
+
+void warn_slowpath_null(const char *file, int line)
+{
+ printk("%s:%d -- ", file, line);
+}
+
diff --git a/arch/lib/proc.c b/arch/lib/proc.c
new file mode 100644
index 0000000..5507730
--- /dev/null
+++ b/arch/lib/proc.c
@@ -0,0 +1,34 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2014 Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/fs.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <net/net_namespace.h>
+#include "sim-types.h"
+#include "sim-assert.h"
+#include "fs/proc/internal.h" /* XXX */
+
+struct proc_dir_entry;
+static char proc_root_data[sizeof(struct proc_dir_entry) + 4];
+
+static struct proc_dir_entry *proc_root_sim =
+ (struct proc_dir_entry *)proc_root_data;
+
+void lib_proc_net_initialize(void)
+{
+ proc_root_sim->parent = proc_root_sim;
+ strcpy(proc_root_sim->name, "net");
+ proc_root_sim->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ proc_root_sim->subdir = RB_ROOT;
+ init_net.proc_net = proc_root_sim;
+ init_net.proc_net_stat = proc_mkdir("stat", proc_root_sim);
+}
+
diff --git a/arch/lib/random.c b/arch/lib/random.c
new file mode 100644
index 0000000..9fbb8bf
--- /dev/null
+++ b/arch/lib/random.c
@@ -0,0 +1,53 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include <linux/random.h>
+
+u32 random32(void)
+{
+ return lib_random();
+}
+
+void get_random_bytes(void *buf, int nbytes)
+{
+ char *p = (char *)buf;
+ int i;
+
+ for (i = 0; i < nbytes; i++)
+ p[i] = lib_random();
+}
+void srandom32(u32 entropy)
+{
+}
+
+u32 prandom_u32(void)
+{
+ return lib_random();
+}
+void prandom_seed(u32 entropy)
+{
+}
+
+void prandom_bytes(void *buf, size_t bytes)
+{
+ return get_random_bytes(buf, bytes);
+}
+
+#include <linux/sysctl.h>
+
+static int nothing;
+struct ctl_table random_table[] = {
+ {
+ .procname = "nothing",
+ .data = ¬hing,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ }
+};
diff --git a/arch/lib/sysfs.c b/arch/lib/sysfs.c
new file mode 100644
index 0000000..2def2ca
--- /dev/null
+++ b/arch/lib/sysfs.c
@@ -0,0 +1,83 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int sysfs_create_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+ return 0;
+}
+void sysfs_remove_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+}
+int sysfs_create_dir(struct kobject *kobj)
+{
+ return 0;
+}
+int sysfs_create_link(struct kobject *kobj, struct kobject *target,
+ const char *name)
+{
+ return 0;
+}
+int sysfs_move_dir(struct kobject *kobj,
+ struct kobject *new_parent_kobj)
+{
+ return 0;
+}
+void sysfs_remove_dir(struct kobject *kobj)
+{
+}
+void sysfs_remove_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+}
+int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
+{
+ return 0;
+}
+int __must_check sysfs_create_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return 0;
+}
+int sysfs_create_groups(struct kobject *kobj,
+ const struct attribute_group **groups)
+{
+ return 0;
+}
+int sysfs_schedule_callback(struct kobject *kobj,
+ void (*func)(
+ void *), void *data, struct module *owner)
+{
+ return 0;
+}
+void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
+ const char *name)
+{
+}
+void sysfs_exit_ns(enum kobj_ns_type type, const void *tag)
+{
+}
+void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
+{
+}
+int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
+{
+ kobj->sd = lib_malloc(sizeof(struct kernfs_node));
+ return 0;
+}
+int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
+ const void *ns)
+{
+ return 0;
+}
diff --git a/arch/lib/vmscan.c b/arch/lib/vmscan.c
new file mode 100644
index 0000000..3132f66
--- /dev/null
+++ b/arch/lib/vmscan.c
@@ -0,0 +1,26 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/shrinker.h>
+
+/*
+ * Add a shrinker callback to be called from the vm
+ */
+int register_shrinker(struct shrinker *shrinker)
+{
+ return 0;
+}
+
+/*
+ * Remove one
+ */
+void unregister_shrinker(struct shrinker *shrinker)
+{
+}
+
--
2.1.0
these files works as stubs in order to transparently run the other
kernel part (e.g., net/) on libos environment.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/include/asm/Kbuild | 57 +++++++++++++++++++++++++++++++++++
arch/lib/include/asm/atomic.h | 50 ++++++++++++++++++++++++++++++
arch/lib/include/asm/barrier.h | 8 +++++
arch/lib/include/asm/bitsperlong.h | 16 ++++++++++
arch/lib/include/asm/current.h | 7 +++++
arch/lib/include/asm/elf.h | 10 ++++++
arch/lib/include/asm/hardirq.h | 8 +++++
arch/lib/include/asm/page.h | 14 +++++++++
arch/lib/include/asm/pgtable.h | 30 ++++++++++++++++++
arch/lib/include/asm/processor.h | 19 ++++++++++++
arch/lib/include/asm/ptrace.h | 4 +++
arch/lib/include/asm/segment.h | 6 ++++
arch/lib/include/asm/sembuf.h | 4 +++
arch/lib/include/asm/shmbuf.h | 4 +++
arch/lib/include/asm/shmparam.h | 4 +++
arch/lib/include/asm/sigcontext.h | 6 ++++
arch/lib/include/asm/stat.h | 4 +++
arch/lib/include/asm/statfs.h | 4 +++
arch/lib/include/asm/swab.h | 7 +++++
arch/lib/include/asm/thread_info.h | 36 ++++++++++++++++++++++
arch/lib/include/asm/uaccess.h | 14 +++++++++
arch/lib/include/asm/unistd.h | 4 +++
arch/lib/include/uapi/asm/byteorder.h | 6 ++++
23 files changed, 322 insertions(+)
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
diff --git a/arch/lib/include/asm/Kbuild b/arch/lib/include/asm/Kbuild
new file mode 100644
index 0000000..c647b1c
--- /dev/null
+++ b/arch/lib/include/asm/Kbuild
@@ -0,0 +1,57 @@
+generic-y += auxvec.h
+generic-y += bitops.h
+generic-y += bug.h
+generic-y += cache.h
+generic-y += cacheflush.h
+generic-y += checksum.h
+generic-y += cputime.h
+generic-y += cmpxchg.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += exec.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += io.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq.h
+generic-y += irqflags.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += linkage.h
+generic-y += local.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += mmu.h
+generic-y += mmu_context.h
+generic-y += module.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += preempt.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += setup.h
+generic-y += signal.h
+generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += string.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += timex.h
+generic-y += tlbflush.h
+generic-y += types.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += unaligned.h
diff --git a/arch/lib/include/asm/atomic.h b/arch/lib/include/asm/atomic.h
new file mode 100644
index 0000000..41a49285
--- /dev/null
+++ b/arch/lib/include/asm/atomic.h
@@ -0,0 +1,50 @@
+#ifndef _ASM_SIM_ATOMIC_H
+#define _ASM_SIM_ATOMIC_H
+
+#include <linux/types.h>
+
+#if !defined(CONFIG_64BIT)
+typedef struct {
+ volatile long long counter;
+} atomic64_t;
+#endif
+
+#define ATOMIC64_INIT(i) { (i) }
+
+#define atomic64_read(v) (*(volatile long *)&(v)->counter)
+void atomic64_add(long i, atomic64_t *v);
+static inline void atomic64_sub(long i, atomic64_t *v)
+{
+ v->counter -= i;
+}
+static inline void atomic64_inc(atomic64_t *v)
+{
+ v->counter++;
+}
+int atomic64_sub_and_test(long i, atomic64_t *v);
+#define atomic64_dec(v) atomic64_sub(1LL, (v))
+int atomic64_dec_and_test(atomic64_t *v);
+int atomic64_inc_and_test(atomic64_t *v);
+int atomic64_add_negative(long i, atomic64_t *v);
+/* long atomic64_add_return(long i, atomic64_t *v); */
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+ v->counter += i;
+ return v->counter;
+}
+static inline void atomic64_set(atomic64_t *v, long i)
+{
+ v->counter = i;
+}
+long atomic64_sub_return(long i, atomic64_t *v);
+long atomic64_inc_return(atomic64_t *v);
+long atomic64_dec_return(atomic64_t *v);
+long atomic64_cmpxchg(atomic64_t *v, long old, long new);
+long atomic64_xchg(atomic64_t *v, long new);
+int atomic64_add_unless(atomic64_t *v, long a, long u);
+int atomic64_inc_is_not_zero(atomic64_t *v);
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+
+#include <asm-generic/atomic.h>
+
+#endif /* _ASM_SIM_ATOMIC_H */
diff --git a/arch/lib/include/asm/barrier.h b/arch/lib/include/asm/barrier.h
new file mode 100644
index 0000000..47adcc6
--- /dev/null
+++ b/arch/lib/include/asm/barrier.h
@@ -0,0 +1,8 @@
+#include <asm-generic/barrier.h>
+
+#undef smp_store_release
+#define smp_store_release(p, v) \
+ do { \
+ smp_mb(); \
+ ACCESS_ONCE(*p) = (v); \
+ } while (0)
diff --git a/arch/lib/include/asm/bitsperlong.h b/arch/lib/include/asm/bitsperlong.h
new file mode 100644
index 0000000..9890ba9
--- /dev/null
+++ b/arch/lib/include/asm/bitsperlong.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_SIM_BITSPERLONG_H
+#define _ASM_SIM_BITSPERLONG_H
+
+#ifdef CONFIG_64BIT
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif /* CONFIG_64BIT */
+
+#define __BITS_PER_LONG BITS_PER_LONG
+
+#ifndef BITS_PER_LONG_LONG
+#define BITS_PER_LONG_LONG 64
+#endif
+
+#endif /* _ASM_SIM_BITSPERLONG_H */
diff --git a/arch/lib/include/asm/current.h b/arch/lib/include/asm/current.h
new file mode 100644
index 0000000..62489cd
--- /dev/null
+++ b/arch/lib/include/asm/current.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_CURRENT_H
+#define _ASM_SIM_CURRENT_H
+
+struct task_struct *get_current(void);
+#define current get_current()
+
+#endif /* _ASM_SIM_CURRENT_H */
diff --git a/arch/lib/include/asm/elf.h b/arch/lib/include/asm/elf.h
new file mode 100644
index 0000000..a7396c9
--- /dev/null
+++ b/arch/lib/include/asm/elf.h
@@ -0,0 +1,10 @@
+#ifndef _ASM_SIM_ELF_H
+#define _ASM_SIM_ELF_H
+
+#if defined(CONFIG_64BIT)
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+
+#endif /* _ASM_SIM_ELF_H */
diff --git a/arch/lib/include/asm/hardirq.h b/arch/lib/include/asm/hardirq.h
new file mode 100644
index 0000000..47d47f9
--- /dev/null
+++ b/arch/lib/include/asm/hardirq.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_SIM_HARDIRQ_H
+#define _ASM_SIM_HARDIRQ_H
+
+extern unsigned int interrupt_pending;
+
+#define local_softirq_pending() (interrupt_pending)
+
+#endif /* _ASM_SIM_HARDIRQ_H */
diff --git a/arch/lib/include/asm/page.h b/arch/lib/include/asm/page.h
new file mode 100644
index 0000000..8c0aa74
--- /dev/null
+++ b/arch/lib/include/asm/page.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_PAGE_H
+#define _ASM_SIM_PAGE_H
+
+typedef struct {} pud_t;
+
+#define THREAD_ORDER 1
+#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+
+#define WANT_PAGE_VIRTUAL 1
+
+#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
+
+#endif /* _ASM_SIM_PAGE_H */
diff --git a/arch/lib/include/asm/pgtable.h b/arch/lib/include/asm/pgtable.h
new file mode 100644
index 0000000..ce599c8
--- /dev/null
+++ b/arch/lib/include/asm/pgtable.h
@@ -0,0 +1,30 @@
+#ifndef _ASM_SIM_PGTABLE_H
+#define _ASM_SIM_PGTABLE_H
+
+#define PAGE_KERNEL ((pgprot_t) {0 })
+
+#define arch_start_context_switch(prev) do {} while (0)
+
+#define kern_addr_valid(addr)(1)
+#define pte_file(pte)(1)
+/* Encode and de-code a swap entry */
+#define __swp_type(x) (((x).val >> 5) & 0x1f)
+#define __swp_offset(x) ((x).val >> 11)
+#define __swp_entry(type, offset) \
+ ((swp_entry_t) {((type) << 5) | ((offset) << 11) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) {pte_val((pte)) })
+#define __swp_entry_to_pte(x) ((pte_t) {(x).val })
+#define pmd_page(pmd) (struct page *)(pmd_val(pmd) & PAGE_MASK)
+#define pgtable_cache_init() do { } while (0)
+
+static inline int pte_swp_soft_dirty(pte_t pte)
+{
+ return 0;
+}
+
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+ return pte;
+}
+
+#endif /* _ASM_SIM_PGTABLE_H */
diff --git a/arch/lib/include/asm/processor.h b/arch/lib/include/asm/processor.h
new file mode 100644
index 0000000..b673ee0
--- /dev/null
+++ b/arch/lib/include/asm/processor.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_SIM_PROCESSOR_H
+#define _ASM_SIM_PROCESSOR_H
+
+struct thread_struct {};
+
+#define cpu_relax()
+#define cpu_relax_lowlatency() cpu_relax()
+#define KSTK_ESP(tsk) (0)
+
+void *current_text_addr(void);
+
+#define TASK_SIZE ((~(long)0))
+
+#define thread_saved_pc(x) (unsigned long)0
+#define task_pt_regs(t) NULL
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+#endif /* _ASM_SIM_PROCESSOR_H */
diff --git a/arch/lib/include/asm/ptrace.h b/arch/lib/include/asm/ptrace.h
new file mode 100644
index 0000000..ddd9708
--- /dev/null
+++ b/arch/lib/include/asm/ptrace.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_PTRACE_H
+#define _ASM_SIM_PTRACE_H
+
+#endif /* _ASM_SIM_PTRACE_H */
diff --git a/arch/lib/include/asm/segment.h b/arch/lib/include/asm/segment.h
new file mode 100644
index 0000000..e056922
--- /dev/null
+++ b/arch/lib/include/asm/segment.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SEGMENT_H
+#define _ASM_SIM_SEGMENT_H
+
+typedef struct { int seg; } mm_segment_t;
+
+#endif /* _ASM_SIM_SEGMENT_H */
diff --git a/arch/lib/include/asm/sembuf.h b/arch/lib/include/asm/sembuf.h
new file mode 100644
index 0000000..d64927b
--- /dev/null
+++ b/arch/lib/include/asm/sembuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SEMBUF_H
+#define _ASM_SIM_SEMBUF_H
+
+#endif /* _ASM_SIM_SEMBUF_H */
diff --git a/arch/lib/include/asm/shmbuf.h b/arch/lib/include/asm/shmbuf.h
new file mode 100644
index 0000000..42d0a71
--- /dev/null
+++ b/arch/lib/include/asm/shmbuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMBUF_H
+#define _ASM_SIM_SHMBUF_H
+
+#endif /* _ASM_SIM_SHMBUF_H */
diff --git a/arch/lib/include/asm/shmparam.h b/arch/lib/include/asm/shmparam.h
new file mode 100644
index 0000000..3410f1b
--- /dev/null
+++ b/arch/lib/include/asm/shmparam.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMPARAM_H
+#define _ASM_SIM_SHMPARAM_H
+
+#endif /* _ASM_SIM_SHMPARAM_H */
diff --git a/arch/lib/include/asm/sigcontext.h b/arch/lib/include/asm/sigcontext.h
new file mode 100644
index 0000000..230b4b5
--- /dev/null
+++ b/arch/lib/include/asm/sigcontext.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SIGCONTEXT_H
+#define _ASM_SIM_SIGCONTEXT_H
+
+struct sigcontext {};
+
+#endif /* _ASM_SIM_SIGCONTEXT_H */
diff --git a/arch/lib/include/asm/stat.h b/arch/lib/include/asm/stat.h
new file mode 100644
index 0000000..80fa2cb
--- /dev/null
+++ b/arch/lib/include/asm/stat.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STAT_H
+#define _ASM_SIM_STAT_H
+
+#endif /* _ASM_SIM_STAT_H */
diff --git a/arch/lib/include/asm/statfs.h b/arch/lib/include/asm/statfs.h
new file mode 100644
index 0000000..881ce51
--- /dev/null
+++ b/arch/lib/include/asm/statfs.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STATFS_H
+#define _ASM_SIM_STATFS_H
+
+#endif /* _ASM_SIM_STATFS_H */
diff --git a/arch/lib/include/asm/swab.h b/arch/lib/include/asm/swab.h
new file mode 100644
index 0000000..d81376a
--- /dev/null
+++ b/arch/lib/include/asm/swab.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_SWAB_H
+#define _ASM_SIM_SWAB_H
+
+#include <linux/types.h>
+
+
+#endif /* _ASM_SIM_SWAB_H */
diff --git a/arch/lib/include/asm/thread_info.h b/arch/lib/include/asm/thread_info.h
new file mode 100644
index 0000000..ec316c6
--- /dev/null
+++ b/arch/lib/include/asm/thread_info.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_SIM_THREAD_INFO_H
+#define _ASM_SIM_THREAD_INFO_H
+
+#define TIF_NEED_RESCHED 1
+#define TIF_SIGPENDING 2
+#define TIF_MEMDIE 5
+
+struct thread_info {
+ __u32 flags;
+ int preempt_count;
+ struct task_struct *task;
+ struct restart_block restart_block;
+};
+
+struct thread_info *current_thread_info(void);
+struct thread_info *alloc_thread_info(struct task_struct *task);
+void free_thread_info(struct thread_info *ti);
+
+#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+}
+static inline void clear_restore_sigmask(void)
+{
+}
+static inline bool test_restore_sigmask(void)
+{
+ return true;
+}
+static inline bool test_and_clear_restore_sigmask(void)
+{
+ return true;
+}
+
+#endif /* _ASM_SIM_THREAD_INFO_H */
diff --git a/arch/lib/include/asm/uaccess.h b/arch/lib/include/asm/uaccess.h
new file mode 100644
index 0000000..74f973b
--- /dev/null
+++ b/arch/lib/include/asm/uaccess.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_UACCESS_H
+#define _ASM_SIM_UACCESS_H
+
+#define KERNEL_DS ((mm_segment_t) {0 })
+#define USER_DS ((mm_segment_t) {0 })
+#define get_fs() KERNEL_DS
+#define get_ds() USER_DS
+#define set_fs(x) do {} while ((x.seg) != (x.seg))
+
+#define __access_ok(addr, size) (1)
+
+#include <asm-generic/uaccess.h>
+
+#endif /* _ASM_SIM_UACCESS_H */
diff --git a/arch/lib/include/asm/unistd.h b/arch/lib/include/asm/unistd.h
new file mode 100644
index 0000000..6b482b4
--- /dev/null
+++ b/arch/lib/include/asm/unistd.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_UNISTD_H
+#define _ASM_SIM_UNISTD_H
+
+#endif /* _ASM_SIM_UNISTD_H */
diff --git a/arch/lib/include/uapi/asm/byteorder.h b/arch/lib/include/uapi/asm/byteorder.h
new file mode 100644
index 0000000..b13a7a8
--- /dev/null
+++ b/arch/lib/include/uapi/asm/byteorder.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_BYTEORDER_H
+#define _ASM_X86_BYTEORDER_H
+
+#include <linux/byteorder/little_endian.h>
+
+#endif /* _ASM_X86_BYTEORDER_H */
--
2.1.0
document and build scripts for libos architecture.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 3 +
arch/lib/Kconfig | 124 +++++++
arch/lib/Makefile | 224 ++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/generate-linker-script.py | 50 +++
8 files changed, 1252 insertions(+)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/defconfig
create mode 100755 arch/lib/generate-linker-script.py
diff --git a/Documentation/virtual/libos-howto.txt b/Documentation/virtual/libos-howto.txt
new file mode 100644
index 0000000..fbf7946
--- /dev/null
+++ b/Documentation/virtual/libos-howto.txt
@@ -0,0 +1,144 @@
+Library operating system (libos) version of Linux
+=================================================
+
+* Overview
+
+New hardware independent architecture 'arch/lib', configured by
+CONFIG_LIB gives you two features.
+
+- network stack in userspace (NUSE)
+ NUSE will give you a personalized network stack for each application
+ without replacing host operating system.
+
+- network simulator integration, which is called Direct Code Execution (DCE)
+ DCE will give us a network simulation environment with Linux network stack
+ to investigate the detail behavior protocol implementation with a flexible
+ network configuration. This is also useful for the testing environment.
+
+(- more abstracted implementation of underlying platform will be a future
+ direction (e.g., rump hypercall))
+
+In both features, Linux kernel network stack is running on top of
+userspace application with a linked or dynamically loaded library.
+
+They have their own, isolated network stack from host operating system
+so they are configured different IP addresses as other virtualization
+methods do.
+
+
+* How different with others ?
+
+- User-mode Linux (UML)
+
+UML is a way to execute Linux kernel code as a userspace
+application. It is completely isolated from host kernel but can host
+arbitrary userspace applications on top of UML.
+
+- namespace / container
+
+Container technologies with namespace brings a process-level isolation
+to host multiple network entities but shares the kernel among
+processes, which prevents to introduce new features implemented in
+kernel space.
+
+
+* How to build it ?
+
+configuration of arch/lib follows a standard configuration of kernel.
+
+ make defconfig ARCH=lib
+
+or
+
+ make menuconfig ARCH=lib
+
+then you can build a set of libraries for libos.
+
+ make library ARCH=lib
+
+This will give you a shared library file liblinux-$(KERNELVERSION).so
+in the top directory.
+
+* Hello world
+
+you may first need to configure a configuration file, named
+'nuse.conf' so that the library version of network stack can know what
+kind of IP configuration should be used. There is an example file
+at arch/lib/nuse.conf.sample: you may copy and modify it for your purpose.
+
+ sudo NUSECONF=nuse.conf ./nuse ping http://www.google.com
+
+
+
+* Example use cases
+- regression test with Direct Code Execution (DCE)
+
+'make test' by DCE gives a test platform for networking code, with the
+help of network simulator facilities like link delay/bandwidth/drop
+configurations, large network topology with userspace routing protocol
+daemons, etc.
+
+An interesting feature is the determinism of any test executions. A
+test script always gives same results in every execution if there is
+no modification on test target code.
+
+For the first step, you need to obtain network simulator
+environment. 'make testbin' does all the stuff for the preparation.
+
+% make testbin -C tools/testing/libos
+
+Then, you can 'make test' for your code.
+
+% make test ARCH=lib
+
+ PASS: TestSuite netlink-socket
+ PASS: TestSuite process-manager
+ PASS: TestSuite dce-cradle
+ PASS: TestSuite dce-mptcp
+ PASS: TestSuite dce-umip
+ PASS: TestSuite dce-quagga
+ PASS: Example dce-tcp-simple
+ PASS: Example dce-udp-simple
+
+
+- userspace network stack (NUSE)
+
+an application can use its own network stack, distinct from host network stack
+in order to personalize any network feature to the application specific one.
+The 'nuse' wrapper script, based on LD_PRELOAD technique, carefully replaces
+socket API and redirects system calls to the network stack library, provided by
+this framework.
+
+the network stack can be used with any kind of raw-socket like
+technologies such as Intel DPDK, netmap, etc.
+
+
+
+* Files / External Repository
+
+The kernel source tree (i.e., arch/lib) only contains a shared part of
+applications (NUSE/DCE). Pure userspace part is managed at a different
+repository, called Linux-libos-tools: it is automatically downloaded
+during make library.
+
+ https://github.com/libos-nuse/linux-libos-tools
+
+
+* More information
+- [email protected] (LibOS in general and NUSE related questions)
+- [email protected] (ns-3 related questions)
+- articles, slides
+ Experimentation Tools for Networking Research (Lacage, 2010)
+ http://cutebugs.net/files/thesis.pdf
+ Direct code execution: revisiting library OS architecture for reproducible
+ network experiments (Tazaki et al., 2013)
+ http://dx.doi.org/10.1145/2535372.2535374
+ Library Operating System with Mainline Linux Network Stack (Tazaki et al., 2015)
+ https://www.netdev01.org/docs/netdev01-tazaki-libos.pdf (slides)
+
+
+* Authors
+ Mathieu Lacage <[email protected]>
+ Hajime Tazaki <[email protected]>
+ Frederic Urbani <[email protected]>
+ Ryo Nakamura <[email protected]>
diff --git a/MAINTAINERS b/MAINTAINERS
index 2e5bbc0..289ca6f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5896,6 +5896,15 @@ M: Sasha Levin <[email protected]>
S: Maintained
F: tools/lib/lockdep/
+LIBRARY OS (LIBOS)
+M: Hajime Tazaki <[email protected]>
+L: [email protected]
+W: http://libos-nuse.github.io/
+S: Maintained
+F: Documentation/virtual/libos-howto.txt
+F: arch/lib/
+F: tools/testing/libos/
+
LINUX FOR IBM pSERIES (RS/6000)
M: Paul Mackerras <[email protected]>
W: http://www.ibm.com/linux/ltc/projects/ppc
diff --git a/arch/lib/.gitignore b/arch/lib/.gitignore
new file mode 100644
index 0000000..4370d48
--- /dev/null
+++ b/arch/lib/.gitignore
@@ -0,0 +1,3 @@
+linker.lds
+objs.mk
+tools
diff --git a/arch/lib/Kconfig b/arch/lib/Kconfig
new file mode 100644
index 0000000..eef92af
--- /dev/null
+++ b/arch/lib/Kconfig
@@ -0,0 +1,124 @@
+mainmenu "Linux Library OS (libos) $KERNELVERSION Configuration"
+
+config LIB
+ def_bool y
+ select PROC_FS
+ select PROC_SYSCTL
+ select SYSCTL
+ select SYSFS
+ help
+ The 'lib' architecture is a library (user-mode) version of
+ the linux kernel that includes only its network stack and is
+ used within the userspace application, and ns-3 simulator.
+ For more information, about ns-3, see http://www.nsnam.org.
+
+config ARCH
+ string
+ option env="ARCH"
+
+config KERNELVERSION
+ string
+ option env="KERNELVERSION"
+
+config MODULES
+ def_bool y
+ option modules
+
+config MMU
+ def_bool n
+
+config FPU
+ def_bool n
+
+config SMP
+ def_bool n
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+
+config PRINTK
+ def_bool y
+
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+config NO_HZ
+ def_bool y
+
+config BASE_FULL
+ def_bool n
+
+config SELECT_MEMORY_MODEL
+ def_bool n
+
+config FLAT_NODE_MEM_MAP
+ def_bool n
+
+config PAGEFLAGS_EXTENDED
+ def_bool n
+
+config VIRT_TO_BUS
+ def_bool n
+
+config HAS_DMA
+ def_bool n
+
+config HZ
+ int
+ default 250
+
+config TINY_RCU
+ def_bool y
+
+config HZ_250
+ def_bool y
+
+config BASE_SMALL
+ int
+ default 1
+
+config SPLIT_PTLOCK_CPUS
+ int
+ default 1
+
+config FLATMEM
+ def_bool y
+
+config SYSCTL
+ def_bool y
+
+config PROC_FS
+ def_bool y
+
+config SYSFS
+ def_bool y
+
+config PROC_SYSCTL
+ def_bool y
+
+config MULTIUSER
+ def_bool n
+
+config NETDEVICES
+ def_bool y
+
+source "net/Kconfig"
+
+source "drivers/base/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+config SLIB
+ def_bool y
\ No newline at end of file
diff --git a/arch/lib/Makefile b/arch/lib/Makefile
new file mode 100644
index 0000000..7b5d1c3
--- /dev/null
+++ b/arch/lib/Makefile
@@ -0,0 +1,224 @@
+ARCH_DIR := arch/lib
+DCE_TESTDIR=$(srctree)/tools/testing/libos/
+KBUILD_KCONFIG := arch/$(ARCH)/Kconfig
+
+CC = gcc
+GCCVERSIONGTEQ48 := $(shell expr `gcc -dumpversion` \>= 4.8)
+ifeq "$(GCCVERSIONGTEQ48)" "1"
+ NO_TREE_LOOP_OPT += -fno-tree-loop-distribute-patterns
+endif
+
+
+-include $(ARCH_DIR)/objs.mk
+-include $(srctree)/.config
+include $(srctree)/scripts/Kbuild.include
+
+# targets
+LIBOS_TOOLS=$(ARCH_DIR)/tools
+LIBOS_GIT_REPO=git://github.com/libos-nuse/linux-libos-tools
+KERNEL_LIB=liblinux-$(KERNELVERSION).so
+
+ALL_OBJS=$(OBJS) $(KERNEL_LIB) $(modules) $(all-obj-for-clean)
+
+# auto generated files
+AUTOGENS=include/generated/compile.h include/generated/bounds.h \
+ kernel/time/timeconst.h lib/crc32table.h $(ARCH_DIR)/linker.lds
+
+# sources and objects
+LIB_SRC=\
+lib.c lib-device.c lib-socket.c random.c softirq.c time.c \
+timer.c hrtimer.c sched.c workqueue.c \
+print.c tasklet.c tasklet-hrtimer.c \
+glue.c fs.c sysctl.c proc.c sysfs.c \
+capability.c pid.c modules.c filemap.c vmscan.c
+
+LIB_OBJ=$(addprefix $(ARCH_DIR)/,$(addsuffix .o,$(basename $(LIB_SRC))))
+LIB_DEPS=$(addprefix $(ARCH_DIR)/.,$(addsuffix .o.cmd,$(basename $(LIB_SRC))))
+-include $(LIB_DEPS)
+
+# options
+COV?=no
+cov_yes=-fprofile-arcs -ftest-coverage
+cov_no=
+covl_yes=-fprofile-arcs
+covl_no=
+OPT?=yes
+opt_yes=-O3 -fomit-frame-pointer $(NO_TREE_LOOP_OPT)
+opt_no=-O0
+PIC?=yes
+pic_yes=-fpic -DPIC
+pic_no=-mcmodel=large
+PIC_CFLAGS=$(pic_$(PIC))
+
+# flags
+CFLAGS_USPACE= \
+ -Wp,-MD,$(depfile) $(opt_$(OPT)) -g3 -Wall -Wstrict-prototypes -Wno-trigraphs \
+ -fno-inline -fno-strict-aliasing -fno-common \
+ -fno-delete-null-pointer-checks -fno-builtin \
+ -fno-stack-protector -Wno-unused -Wno-pointer-sign \
+ $(PIC_CFLAGS) -D_DEBUG $(cov_$(COV)) -I$(ARCH_DIR)/include
+
+CFLAGS+= \
+ $(CFLAGS_USPACE) -nostdinc -D__KERNEL__ -iwithprefix $(srctree)/include \
+ -DKBUILD_BASENAME=\"clnt\" -DKBUILD_MODNAME=\"nsc\" -DMODVERSIONS \
+ -DEXPORT_SYMTAB \
+ -U__FreeBSD__ -D__linux__=1 -Dlinux=1 -D__linux=1 \
+ -DCONFIG_DEFAULT_HOSTNAME=\"lib\" \
+ -I$(ARCH_DIR)/include/generated/uapi \
+ -I$(ARCH_DIR)/include/generated \
+ -I$(srctree)/include -I$(ARCH_DIR)/include/uapi \
+ -I$(srctree)/include/uapi -I$(srctree)/include/generated/uapi \
+ -include $(srctree)/include/linux/kconfig.h \
+ -I$(ARCH_DIR) -I.
+
+ifeq ($(SUBARCH),x86)
+ ifeq ($(shell uname -m),x86_64)
+ CFLAGS+= -DCONFIG_64BIT
+ endif
+endif
+
+KBUILD_CFLAGS := CFLAGS
+LDFLAGS += -shared -nodefaultlibs -g3 -Wl,-O1 -Wl,-T$(ARCH_DIR)/linker.lds $(covl_$(COV))
+
+# targets
+
+modules:=
+all-obj-for-clean:=
+
+all: library modules
+
+# note: the directory order below matters to ensure that we match the kernel order
+dirs=kernel/ kernel/time/ kernel/rcu/ kernel/locking/ kernel/bpf/ mm/ fs/ fs/proc/ crypto/ lib/ drivers/base/ drivers/net/ net/ init/
+empty:=
+space:= $(empty) $(empty)
+colon:= :
+comma= ,
+kernel/_to_keep=notifier.o params.o sysctl.o \
+rwsem.o semaphore.o kfifo.o cred.o user.o groups.o ksysfs.o
+kernel/time/_to_keep=time.o
+kernel/rcu_to_keep=rcu/srcu.o rcu/pdate.o rcu/tiny.o
+kernel/locking_to_keep=locking/mutex.o
+kernel/bpf_to_keep=bpf/core.o
+mm/_to_keep=util.o list_lru.o slib.o
+crypto/_to_keep=aead.o ahash.o shash.o api.o algapi.o cipher.o compress.o proc.o \
+crc32c_generic.o
+drivers/base/_to_keep=class.o core.o bus.o dd.o driver.o devres.o module.o map.o
+drivers/net/_to_keep=loopback.o
+lib/_to_keep=klist.o kobject.o kref.o hweight.o int_sqrt.o checksum.o \
+find_last_bit.o find_bit.o bitmap.o nlattr.o idr.o libcrc32c.o \
+ctype.o string.o kasprintf.o rbtree.o sha1.o textsearch.o vsprintf.o \
+rwsem-spinlock.o scatterlist.o ratelimit.o hexdump.o dec_and_lock.o \
+div64.o dynamic_queue_limits.o md5.o kstrtox.o iovec.o lockref.o crc32.o \
+rhashtable.o iov_iter.o cmdline.o kobject_uevent.o
+fs/_to_keep=read_write.o libfs.o namei.o filesystems.o file.o file_table.o \
+dcache.o inode.o pipe.o char_dev.o splice.o no-block.o seq_file.o super.o \
+fcntl.o coredump.o
+fs/proc/_to_keep=proc_sysctl.o proc_net.o root.o generic.o inode.o
+init/_to_keep=version.o
+
+quiet_cmd_objsmk = OBJS-MK $@
+ cmd_objsmk = \
+ for i in 1; do \
+ $(foreach d,$(dirs), \
+ $(MAKE) -i -s -f $< srcdir=$(srctree)/$(d) \
+ objdir=$(srctree)/$(d) \
+ config=$(srctree)/.config \
+ to_keep=$(subst $(space),$(colon),$($(d)_to_keep)) print;) \
+ done > $@
+
+$(ARCH_DIR)/objs.mk: $(ARCH_DIR)/Makefile.print $(srctree)/.config $(ARCH_DIR)/Makefile
+ +$(call if_changed,objsmk)
+
+quiet_cmd_linker = GEN $@
+ cmd_linker = ld -shared --verbose | ./$^ > $@
+$(ARCH_DIR)/linker.lds: $(ARCH_DIR)/generate-linker-script.py
+ $(call if_changed,linker)
+
+# calll kernel/time/Makefile
+kernel/time/timeconst.h:
+ $(Q) $(MAKE) $(build)=kernel/time $@
+
+# call lib/Makefile
+lib/crc32table.h:
+ $(Q) $(MAKE) $(build)=lib $@
+
+# call init/Makefile
+include/generated/compile.h: asm-generic include/generated/utsrelease.h\
+ $(version_h)
+ $(Q) $(MAKE) $(build)=init $@
+
+# crafted from $(srctree)/Kbuild
+quiet_cmd_lib_bounds = GEN $@
+define cmd_lib_bounds
+ (set -e; \
+ echo "#ifndef GENERATED_BOUNDS_H"; \
+ echo "#define GENERATED_BOUNDS_H"; \
+ echo ""; \
+ echo "#define NR_PAGEFLAGS (__NR_PAGEFLAGS)"; \
+ echo "#define MAX_NR_ZONES (__MAX_NR_ZONES)"; \
+ echo ""; \
+ echo "#endif /* GENERATED_BOUNDS_H */") > $@
+endef
+
+include/generated/bounds.h:
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,lib_bounds)
+
+
+KERNEL_BUILTIN=$(addprefix $(srctree)/,$(addsuffix builtin.o,$(dirs)))
+OBJS=$(LIB_OBJ) $(foreach builtin,$(KERNEL_BUILTIN),$(if $($(builtin)),$($(builtin))))
+export OBJS KERNEL_LIB COV covl_yes covl_no
+
+quiet_cmd_cc = CC $@
+ cmd_cc = mkdir -p $(dir $@); \
+ $(CC) $(CFLAGS) -c $< -o $@
+quiet_cmd_linkko = KO $@
+ cmd_linkko = $(CC) -shared -o $@ -nostdlib $^
+quiet_cmd_builtin = BUILTIN $@
+ cmd_builtin = mkdir -p $(dir $(srctree)/$@); rm -f $(srctree)/$@; \
+ if test -n "$($(srctree)/$@)"; then for f in $($(srctree)/$@); \
+ do $(AR) Tcru $@ $$f; done; else $(AR) Tcru $@; fi
+
+%/builtin.o:
+ $(call if_changed,builtin)
+%.ko:%.o
+ $(call if_changed,linkko)
+%.o:%.c $(AUTOGENS)
+ $(call if_changed_dep,cc)
+
+library: $(KERNEL_LIB) $(LIBOS_TOOLS)
+modules: $(modules)
+
+$(LIBOS_TOOLS): $(KERNEL_LIB) Makefile FORCE
+ $(Q) if [ ! -d "$@" ]; then \
+ git clone $(LIBOS_GIT_REPO) $@ ;\
+ fi
+ $(Q) $(MAKE) -C $(LIBOS_TOOLS)
+
+install: modules library
+
+install-dir:
+
+$(KERNEL_LIB): $(ARCH_DIR)/objs.mk $(AUTOGENS) $(OBJS)
+ $(call if_changed,linklib)
+
+quiet_cmd_linklib = LIB $@
+ cmd_linklib = $(CC) -Wl,--whole-archive $(OBJS) $(LDFLAGS) -o $@; \
+ ln -s -f $(KERNEL_LIB) liblinux.so
+
+quiet_cmd_clean = CLEAN $@
+ cmd_clean = for f in $(foreach m,$(modules),$($(m))) ; do rm -f $$f 2>/dev/null; done ; \
+ for f in $(ALL_OBJS); do rm -f $$f; done 2>/dev/null ;\
+ rm -rf $(AUTOGENS) $(ARCH_DIR)/objs.mk 2>/dev/null ;\
+ if [ -d $(LIBOS_TOOLS) ]; then $(MAKE) -C $(LIBOS_TOOLS) clean ; fi
+
+archclean:
+ $(call if_changed,clean)
+
+archprepare: include/generated/bounds.h include/generated/utsrelease.h \
+ asm-generic $(version_h)
+
+test:
+ $(Q) $(MAKE) -C $(DCE_TESTDIR)/
+
+.PHONY : clean
diff --git a/arch/lib/Makefile.print b/arch/lib/Makefile.print
new file mode 100644
index 0000000..8585fc8
--- /dev/null
+++ b/arch/lib/Makefile.print
@@ -0,0 +1,45 @@
+# inherit $(objdir) $(config) $(srcdir) $(to_keep) from command-line
+
+include $(config)
+include $(srcdir)Makefile
+
+# fix minor nits for make version dependencies
+ifeq (3.82,$(firstword $(sort $(MAKE_VERSION) 3.82)))
+ SEPARATOR=
+else
+ SEPARATOR=/
+endif
+
+to_keep_list=$(subst :, ,$(to_keep))
+obj-y += $(lib-y)
+obj-m += $(lib-m)
+subdirs:=$(shell echo $(filter %/, $(obj-y) $(obj-m)) | tr ' ' '\n' | sort -u | tr '\n' ' ')
+subdirs-y := $(filter %/, $(obj-y))
+subdirs-m := $(filter %/, $(obj-m))
+tmp1-obj-y=$(patsubst %/,%/builtin.o,$(obj-y))
+tmp1-obj-m=$(filter-out $(subdirs-m),$(obj-m))
+tmp2-obj-y=$(foreach m,$(tmp1-obj-y), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp2-obj-m=$(foreach m,$(tmp1-obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp3-obj-y=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-y)),$(tmp2-obj-y))
+tmp3-obj-m=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-m)),$(tmp2-obj-m))
+final-obj-y=$(tmp3-obj-y)
+final-obj-m=$(tmp3-obj-m)
+
+print: $(final-obj-m) $(subdirs)
+ @if test $(if $(final-obj-y),1); then \
+ echo -n $(objdir)builtin.o; echo -n "="; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n $(objdir)builtin.o; echo -n ": "; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n "-include "; echo $(addprefix $(objdir).,$(addsuffix ".cmd", $(final-obj-y))); \
+ echo -n "all-obj-for-clean+="; echo $(addprefix $(objdir),$(final-obj-y)) $(objdir)builtin.o; \
+ fi
+$(final-obj-m):
+ @echo -n "modules+="; echo $(addprefix $(objdir),$(@:.o=.ko))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n ": "
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n "="
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+$(subdirs):
+ @$(MAKE) -s -f $(firstword $(MAKEFILE_LIST)) objdir=$(objdir)$@$(SEPARATOR) config=$(config) srcdir=$(srcdir)$@$(SEPARATOR) to_keep=$(to_keep) print 2>/dev/null
+
+.PHONY : core
+.NOTPARALLEL : print $(subdirs) $(final-obj-m)
diff --git a/arch/lib/defconfig b/arch/lib/defconfig
new file mode 100644
index 0000000..9307e6f
--- /dev/null
+++ b/arch/lib/defconfig
@@ -0,0 +1,653 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux Kernel Configuration
+#
+CONFIG_LIB=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+# CONFIG_SMP is not set
+CONFIG_KTIME_SCALAR=y
+CONFIG_MODULES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_PRINTK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_NO_HZ=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_SELECT_MEMORY_MODEL is not set
+# CONFIG_FLAT_NODE_MEM_MAP is not set
+# CONFIG_PAGEFLAGS_EXTENDED is not set
+# CONFIG_VIRT_TO_BUS is not set
+# CONFIG_HAS_DMA is not set
+CONFIG_HZ=250
+CONFIG_TINY_RCU=y
+CONFIG_HZ_250=y
+CONFIG_BASE_SMALL=1
+CONFIG_SPLIT_PTLOCK_CPUS=1
+CONFIG_FLATMEM=y
+CONFIG_SYSCTL=y
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IP_TUNNEL=y
+CONFIG_NET_IPGRE=y
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_NET_IPVTI is not set
+CONFIG_NET_UDP_TUNNEL=m
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+# CONFIG_GENEVE is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_INET_UDP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+CONFIG_TCP_CONG_HSTCP=y
+CONFIG_TCP_CONG_HYBLA=y
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=y
+CONFIG_TCP_CONG_LP=y
+CONFIG_TCP_CONG_VENO=y
+CONFIG_TCP_CONG_YEAH=y
+CONFIG_TCP_CONG_ILLINOIS=y
+CONFIG_TCP_CONG_DCTCP=y
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_HYBLA is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_VENO is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_DCTCP is not set
+CONFIG_DEFAULT_RENO=y
+CONFIG_DEFAULT_TCP_CONG="reno"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+# CONFIG_IPV6_VTI is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=y
+# CONFIG_IPV6_GRE is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=m
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_ACCT=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_LOG_COMMON=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+CONFIG_NETFILTER_NETLINK_QUEUE_CT=y
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_NF_NAT_PROTO_DCCP=y
+CONFIG_NF_NAT_PROTO_UDPLITE=y
+CONFIG_NF_NAT_PROTO_SCTP=y
+CONFIG_NF_NAT_AMANDA=y
+CONFIG_NF_NAT_FTP=y
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_TFTP is not set
+CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_TABLES=y
+CONFIG_NF_TABLES_INET=y
+CONFIG_NFT_EXTHDR=y
+CONFIG_NFT_META=y
+CONFIG_NFT_CT=y
+CONFIG_NFT_RBTREE=y
+CONFIG_NFT_HASH=y
+CONFIG_NFT_COUNTER=y
+CONFIG_NFT_LOG=y
+CONFIG_NFT_LIMIT=y
+CONFIG_NFT_MASQ=y
+# CONFIG_NFT_REDIR is not set
+CONFIG_NFT_NAT=y
+# CONFIG_NFT_QUEUE is not set
+# CONFIG_NFT_REJECT is not set
+# CONFIG_NFT_REJECT_INET is not set
+# CONFIG_NFT_COMPAT is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+# CONFIG_NETFILTER_XT_SET is not set
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_NAT=y
+CONFIG_NETFILTER_XT_TARGET_NETMAP=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_RATEEST=y
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=y
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+CONFIG_NETFILTER_XT_MATCH_L2TP=m
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+CONFIG_IP_SET=y
+CONFIG_IP_SET_MAX=256
+# CONFIG_IP_SET_BITMAP_IP is not set
+# CONFIG_IP_SET_BITMAP_IPMAC is not set
+# CONFIG_IP_SET_BITMAP_PORT is not set
+# CONFIG_IP_SET_HASH_IP is not set
+# CONFIG_IP_SET_HASH_IPMARK is not set
+# CONFIG_IP_SET_HASH_IPPORT is not set
+# CONFIG_IP_SET_HASH_IPPORTIP is not set
+# CONFIG_IP_SET_HASH_IPPORTNET is not set
+# CONFIG_IP_SET_HASH_MAC is not set
+# CONFIG_IP_SET_HASH_NETPORTNET is not set
+# CONFIG_IP_SET_HASH_NET is not set
+# CONFIG_IP_SET_HASH_NETNET is not set
+# CONFIG_IP_SET_HASH_NETPORT is not set
+# CONFIG_IP_SET_HASH_NETIFACE is not set
+# CONFIG_IP_SET_LIST_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_NF_LOG_ARP is not set
+CONFIG_NF_LOG_IPV4=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_CHAIN_ROUTE_IPV4=y
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NFT_REJECT_IPV4 is not set
+# CONFIG_NF_TABLES_ARP is not set
+# CONFIG_NF_NAT_IPV4 is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_NF_TABLES_IPV6=y
+# CONFIG_NFT_CHAIN_ROUTE_IPV6 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NFT_REJECT_IPV6 is not set
+CONFIG_NF_LOG_IPV6=y
+# CONFIG_NF_NAT_IPV6 is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+
+#
+# DECnet: Netfilter Configuration
+#
+# CONFIG_DECNET_NF_GRABULATOR is not set
+# CONFIG_NF_TABLES_BRIDGE is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_IP_DCCP=y
+CONFIG_INET_DCCP_DIAG=y
+
+#
+# DCCP CCIDs Configuration
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+CONFIG_IP_SCTP=y
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE=y
+# CONFIG_SCTP_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_COOKIE_HMAC_SHA1 is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_L2TP=m
+# CONFIG_L2TP_V3 is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_VLAN_8021Q_MVRP is not set
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_PHONET=m
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_HSR is not set
+# CONFIG_NET_SWITCHDEV is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_GW=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_DEV=m
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_SJA1000=m
+# CONFIG_CAN_SJA1000_ISA is not set
+CONFIG_CAN_SJA1000_PLATFORM=m
+# CONFIG_CAN_C_CAN is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_CC770 is not set
+# CONFIG_CAN_SOFTING is not set
+CONFIG_CAN_DEBUG_DEVICES=y
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+
+#
+# Dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_BT=m
+CONFIG_BT_BREDR=y
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_LE=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+CONFIG_WIMAX=m
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_RFKILL=m
+# CONFIG_NET_9P is not set
+CONFIG_CAIF=m
+CONFIG_CAIF_DEBUG=y
+CONFIG_CAIF_NETDEV=m
+# CONFIG_CAIF_USB is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_MCRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+CONFIG_CRYPTO_CRCT10DIF=m
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_IO=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
diff --git a/arch/lib/generate-linker-script.py b/arch/lib/generate-linker-script.py
new file mode 100755
index 0000000..db3d7f8
--- /dev/null
+++ b/arch/lib/generate-linker-script.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+import re
+
+def linker_script(reading, writing):
+ delim = re.compile('^==')
+ end_of_ro = re.compile('^ *.gcc_except_table[^:]*:[ ]*ONLY_IF_RW')
+ skipping = True
+ for line in reading.readlines():
+ if delim.search (line) is not None:
+ if skipping:
+ skipping = False
+ continue
+ else:
+ skipping = True
+ if skipping:
+ continue
+ m = end_of_ro.search(line)
+ if m is not None:
+ skipping = False
+ initcall = """
+ /* taken from kernel script*/
+ . = ALIGN (CONSTANT (MAXPAGESIZE));
+ .initcall.init : AT(ADDR(.initcall.init)) {
+ __initcall_start = .;
+ *(.initcallearly.init)
+ *(.initcall0.init)
+ *(.initcall0s.init)
+ *(.initcall1.init)
+ *(.initcall1s.init)
+ *(.initcall2.init)
+ *(.initcall2s.init)
+ *(.initcall3.init)
+ *(.initcall3s.init)
+ *(.initcall4.init)
+ *(.initcall4s.init)
+ *(.initcall5.init)
+ *(.initcall5s.init)
+ *(.initcall6.init)
+ *(.initcall6s.init)
+ *(.initcall7.init)
+ *(.initcall7s.init)
+ __initcall_end = .;
+ }
+"""
+ writing.write (initcall)
+ writing.write(line)
+
+import sys
+linker_script (sys.stdin, sys.stdout)
--
2.1.0
These auxiliary files are used for testing and debugging of net/ code
with libos. a simple test is implemented with make test ARCH=lib.
Signed-off-by: Hajime Tazaki <[email protected]>
---
tools/testing/libos/.gitignore | 6 +++++
tools/testing/libos/Makefile | 38 +++++++++++++++++++++++++++
tools/testing/libos/README | 15 +++++++++++
tools/testing/libos/bisect.sh | 10 +++++++
tools/testing/libos/dce-test.sh | 23 ++++++++++++++++
tools/testing/libos/nuse-test.sh | 57 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 149 insertions(+)
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
diff --git a/tools/testing/libos/.gitignore b/tools/testing/libos/.gitignore
new file mode 100644
index 0000000..57a74a0
--- /dev/null
+++ b/tools/testing/libos/.gitignore
@@ -0,0 +1,6 @@
+*.pcap
+files-*
+bake
+buildtop
+core
+exitprocs
diff --git a/tools/testing/libos/Makefile b/tools/testing/libos/Makefile
new file mode 100644
index 0000000..3da25429
--- /dev/null
+++ b/tools/testing/libos/Makefile
@@ -0,0 +1,38 @@
+ADD_PARAM?=
+
+all: test
+
+bake:
+ hg clone http://code.nsnam.org/bake
+
+check_pkgs:
+ @./bake/bake.py check | grep Bazaar | grep OK || (echo "bzr is missing" && ./bake/bake.py check)
+ @./bake/bake.py check | grep autoreconf | grep OK || (echo "autotools is missing" && ./bake/bake.py check && exit 1)
+
+testbin: bake check_pkgs
+ @cp ../../../arch/lib/tools/bakeconf-linux.xml bake/bakeconf.xml
+ @mkdir -p buildtop/build/bin_dce
+ cd buildtop ; \
+ ../bake/bake.py configure -e dce-linux-inkernel $(BAKECONF_PARAMS)
+ cd buildtop ; \
+ ../bake/bake.py show --enabledTree | grep -v -E "pygoocanvas|graphviz|python-dev" | grep Missing && (echo "required packages are missing") || echo ""
+ cd buildtop ; \
+ ../bake/bake.py download ; \
+ ../bake/bake.py update ; \
+ ../bake/bake.py build
+
+test:
+ @./dce-test.sh ADD_PARAM=$(ADD_PARAM)
+
+test-valgrind:
+ @./dce-test.sh -g ADD_PARAM=$(ADD_PARAM)
+
+test-fault-injection:
+ @./dce-test.sh -f ADD_PARAM=$(ADD_PARAM)
+
+clean:
+# @rm -rf buildtop
+ @rm -f *.pcap
+ @rm -rf files-*
+ @rm -f exitprocs
+ @rm -f core
diff --git a/tools/testing/libos/README b/tools/testing/libos/README
new file mode 100644
index 0000000..51ac5a5
--- /dev/null
+++ b/tools/testing/libos/README
@@ -0,0 +1,15 @@
+
+- bisect.sh
+a sample script to bisect an issue of network stack code with the help
+of LibOS (and ns-3 network simulator). This was used to detect the issue
+for the following patch.
+
+http://patchwork.ozlabs.org/patch/436351/
+
+- dce-test.sh
+a test script invoked by 'make test ARCH=lib'. The contents of test
+scenario are implemented as test suites of ns-3 network simulator.
+
+- nuse-test.sh
+a simple test script for Network Stack in Userspace (NUSE).
+
diff --git a/tools/testing/libos/bisect.sh b/tools/testing/libos/bisect.sh
new file mode 100755
index 0000000..9377ac3
--- /dev/null
+++ b/tools/testing/libos/bisect.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+git merge origin/nuse --no-commit
+make clean ARCH=lib
+make library ARCH=lib OPT=no
+make test ARCH=lib ADD_PARAM=" -s dce-umip"
+RET=$?
+git reset --hard
+
+exit $RET
diff --git a/tools/testing/libos/dce-test.sh b/tools/testing/libos/dce-test.sh
new file mode 100755
index 0000000..e81e2d8
--- /dev/null
+++ b/tools/testing/libos/dce-test.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+#set -x
+export LD_LOG=symbol-fail
+#VERBOSE="-v"
+VALGRIND=""
+FAULT_INJECTION=""
+
+if [ "$1" = "-g" ] ; then
+ VALGRIND="-g"
+# Not implemneted yet.
+#elif [ "$1" = "-f" ] ; then
+# FAULT_INJECTION="-f"
+fi
+
+# FIXME
+#export NS_ATTRIBUTE_DEFAULT='ns3::DceManagerHelper::LoaderFactory=ns3::\
+#DlmLoaderFactory[];ns3::TaskManager::FiberManagerType=UcontextFiberManager'
+
+cd buildtop/source/ns-3-dce
+LD_LIBRARY_PATH=${srctree} ./test.py -n ${VALGRIND} ${FAULT_INJECTION}\
+ ${VERBOSE} ${ADD_PARAM}
diff --git a/tools/testing/libos/nuse-test.sh b/tools/testing/libos/nuse-test.sh
new file mode 100755
index 0000000..198e7e4
--- /dev/null
+++ b/tools/testing/libos/nuse-test.sh
@@ -0,0 +1,57 @@
+#!/bin/bash -e
+
+LIBOS_TOOLS=arch/lib/tools
+
+IFNAME=`ip route |grep default | awk '{print $5}'`
+GW=`ip route |grep default | awk '{print $3}'`
+#XXX
+IPADDR=`echo $GW | sed -r "s/([0-9]+\.[0-9]+\.[0-9]+\.)([0-9]+)$/\1\`expr \2 + 10\`/"`
+
+# ip route
+# ip address
+# ip link
+
+NUSE_CONF=/tmp/nuse.conf
+
+cat > ${NUSE_CONF} << ENDCONF
+
+interface ${IFNAME}
+ address ${IPADDR}
+ netmask 255.255.255.0
+ macaddr 00:01:01:01:01:02
+ viftype RAW
+
+route
+ network 0.0.0.0
+ netmask 0.0.0.0
+ gateway ${GW}
+
+ENDCONF
+
+cd ${LIBOS_TOOLS}
+sudo NUSECONF=${NUSE_CONF} ./nuse ping 127.0.0.1 -c 2
+
+# rump test
+sudo NUSECONF=${NUSE_CONF} ./nuse sleep 5 &
+
+sleep 2
+PID_SLEEP=`/bin/ls -ltr /tmp/rump-server-nuse.* | tail -1 | awk '{print $9}' | sed -e "s/.*rump-server-nuse\.//g" | sed "s/=//"`
+RUMP_URL=unix:///tmp/rump-server-nuse.$PID_SLEEP
+# ls -ltr /tmp/*
+
+sudo chmod 777 /tmp/rump-server-nuse.$PID_SLEEP
+LD_PRELOAD=./libnuse-hijack.so RUMPHIJACK=socket=all \
+ RUMP_SERVER=$RUMP_URL ip addr show
+
+wait %1
+
+if [ "$1" == "--extended" ] ; then
+sudo NUSECONF=${NUSE_CONF} ./nuse ping ${GW} -c 2
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 2000 -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 8 -u -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse dig http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse host http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse nslookup http://www.google.com
+#sudo NUSECONF=${NUSE_CONF} ./nuse nc http://www.google.com 80
+sudo NUSECONF=${NUSE_CONF} ./nuse wget http://www.google.com -O -
+fi
--
2.1.0
Hi!
Am 27.04.2015 um 05:00 schrieb Hajime Tazaki:
> This is the 4th version of Linux LibOS patchset which reflects a
> couple of comments received from people.
>
> changes from v3:
> - Patch 09/10 ("lib: libos build scripts and documentation")
> 1) Remove RFC (now it's a proposal)
> 2) build environment cleanup (commented by Paul Bolle)
> - Overall
> 3) change based tree from arnd/asm-generic to torvalds/linux.git
> (commented by Richard Weinberger)
> 4) rebased to Linux 4.1-rc1 (b787f68c36d49bb1d9236f403813641efa74a031)
Hmm, it still does not build. This time I got:
CC kernel/time/time.o
In file included from kernel/time/time.c:44:0:
kernel/time/timeconst.h:11:2: error: #error "kernel/timeconst.h has the wrong HZ value!"
#error "kernel/timeconst.h has the wrong HZ value!"
^
arch/lib/Makefile:187: recipe for target 'kernel/time/time.o' failed
make: *** [kernel/time/time.o] Error 1
Thanks,
//richard
Am 27.04.2015 um 09:29 schrieb Richard Weinberger:
> Hi!
>
> Am 27.04.2015 um 05:00 schrieb Hajime Tazaki:
>> This is the 4th version of Linux LibOS patchset which reflects a
>> couple of comments received from people.
>>
>> changes from v3:
>> - Patch 09/10 ("lib: libos build scripts and documentation")
>> 1) Remove RFC (now it's a proposal)
>> 2) build environment cleanup (commented by Paul Bolle)
>> - Overall
>> 3) change based tree from arnd/asm-generic to torvalds/linux.git
>> (commented by Richard Weinberger)
>> 4) rebased to Linux 4.1-rc1 (b787f68c36d49bb1d9236f403813641efa74a031)
>
> Hmm, it still does not build. This time I got:
>
> CC kernel/time/time.o
> In file included from kernel/time/time.c:44:0:
> kernel/time/timeconst.h:11:2: error: #error "kernel/timeconst.h has the wrong HZ value!"
> #error "kernel/timeconst.h has the wrong HZ value!"
> ^
> arch/lib/Makefile:187: recipe for target 'kernel/time/time.o' failed
> make: *** [kernel/time/time.o] Error 1
A make mrproper made the issue go away.
Please use kbuild. :)
Thanks,
//richard
At Mon, 27 Apr 2015 09:39:20 +0200,
Richard Weinberger wrote:
> > Hmm, it still does not build. This time I got:
> >
> > CC kernel/time/time.o
> > In file included from kernel/time/time.c:44:0:
> > kernel/time/timeconst.h:11:2: error: #error "kernel/timeconst.h has the wrong HZ value!"
> > #error "kernel/timeconst.h has the wrong HZ value!"
> > ^
> > arch/lib/Makefile:187: recipe for target 'kernel/time/time.o' failed
> > make: *** [kernel/time/time.o] Error 1
>
> A make mrproper made the issue go away.
> Please use kbuild. :)
thanks for the report.
it's been fixed and I added a test (locally) to avoid
further regressions.
-- Hajime
This is the 5th version of Linux LibOS patchset which reflects a
couple of comments received from people.
changes from v4:
- Patch 09/10 ("lib: libos build scripts and documentation")
1) lib: fix dependency detection of kernel/time/timeconst.h
(commented by Richard Weinberger)
- Overall
2) rebased to Linux 4.1-rc3 (4cfceaf0c087f47033f5e61a801f4136d6fb68c6)
changes from v3:
- Patch 09/10 ("lib: libos build scripts and documentation")
1) Remove RFC (now it's a proposal)
2) build environment cleanup (commented by Paul Bolle)
- Overall
3) change based tree from arnd/asm-generic to torvalds/linux.git
(commented by Richard Weinberger)
4) rebased to Linux 4.1-rc1 (b787f68c36d49bb1d9236f403813641efa74a031)
5) change the title of cover letter a bit
changes from v2:
- Patch 02/11 ("slab: add private memory allocator header for arch/lib")
1) add new allocator named SLIB (Library Allocator): Patch 04/11 is integrated
to 02 (commented by Christoph Lameter)
- Overall
2) rewrite commit log messages
changes from v1:
- Patch 01/11 ("sysctl: make some functions unstatic to access by arch/lib"):
1) add prefix ctl_table_ to newly publiced functions (commented by Joe Perches)
- Patch 08/11 ("lib: other kernel glue layer code"):
2) significantly reduce glue codes (stubs) (commented by Richard Weinberger)
- Others
3) adapt to linux-4.0.0
4) detect make dependency by Kbuild .cmd files
patchset history
-----------------
[v4] : https://lkml.org/lkml/2015/4/26/279
[v3] : https://lkml.org/lkml/2015/4/19/63
[v2] : https://lkml.org/lkml/2015/4/17/140
[v1] : https://lkml.org/lkml/2015/3/24/254
This is an introduction of Linux library operating system (LibOS).
Our objective is to build the kernel network stack as a shared library
that can be linked to by userspace programs to provide network stack
personalization and testing facilities, and allow researchers to more
easily simulate complex network topologies of linux routers/hosts.
Although the architecture itself can virtualize various things, the
current design only focuses on the network stack. You can benefit
network stack feature such as TCP, UDP, SCTP, DCCP (IPv4 and IPv6),
Mobie IPv6, Multipath TCP (IPv4/IPv6, out-of-tree at the present
moment), and netlink with various userspace applications (quagga,
iproute2, iperf, wget, and thttpd).
== What is LibOS ? ==
The library exposes an entry point as API, which is lib_init(), in
order to connect userspace applications to the (userspace-version)
kernel network stack. The clock source, virtual struct net_device, and
scheduler are provided by caller while kernel resource like system
calls is provided by callee.
Once the LibOS is initialized via the API, userspace applications with
POSIX socket can use the system calls defined in LibOS by replacing
from the original socket-related symbols to the LibOS-specific
one. Then application can benefit the network stack of LibOS without
involving the host network stack.
Currently, there are two users of LibOS: Network Stack in Userspace
(NUSE) and ns-3 network simulatior with Direct Code Execution
(DCE). These codes are managed at an external repository(*1).
== How to use it ? ==
to build the library,
% make {defconfig,menuconfig} ARCH=lib
then, build it.
% make library ARCH=lib
You will see liblinux-$(KERNELVERSION).so in the top directory.
== More information ==
The crucial difference between UML (user-mode linux) and this approach
is that we allow multiple network stack instances to co-exist within a
single process with dlmopen(3) like linking for easy debugging.
These patches are also available on this branch:
git://github.com/libos-nuse/net-next-nuse.git for-linus-upstream-libos-v5
For further information, here is a slideset presented at the last
netdev0.1 conference.
http://www.slideshare.net/hajimetazaki/library-operating-system-for-linux-netdev01
I would appreciate any kind of your feedback regarding to upstream
this feature.
*1 https://github.com/libos-nuse/linux-libos-tools
Hajime Tazaki (10):
sysctl: make some functions unstatic to access by arch/lib
slab: add SLIB (Library memory allocator) for arch/lib
lib: public headers and API implementations for userspace programs
lib: time handling (kernel glue code)
lib: context and scheduling functions (kernel glue code) for libos
lib: sysctl handling (kernel glue code)
lib: other kernel glue layer code
lib: auxiliary files for auto-generated asm-generic files of libos
lib: libos build scripts and documentation
lib: tools used for test scripts
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 3 +
arch/lib/Kconfig | 124 +++++++
arch/lib/Makefile | 224 ++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/capability.c | 25 ++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/filemap.c | 32 ++
arch/lib/fs.c | 70 ++++
arch/lib/generate-linker-script.py | 50 +++
arch/lib/glue.c | 289 +++++++++++++++
arch/lib/hrtimer.c | 122 +++++++
arch/lib/include/asm/Kbuild | 57 +++
arch/lib/include/asm/atomic.h | 59 +++
arch/lib/include/asm/barrier.h | 8 +
arch/lib/include/asm/bitsperlong.h | 16 +
arch/lib/include/asm/current.h | 7 +
arch/lib/include/asm/elf.h | 10 +
arch/lib/include/asm/hardirq.h | 8 +
arch/lib/include/asm/page.h | 14 +
arch/lib/include/asm/pgtable.h | 30 ++
arch/lib/include/asm/processor.h | 19 +
arch/lib/include/asm/ptrace.h | 4 +
arch/lib/include/asm/segment.h | 6 +
arch/lib/include/asm/sembuf.h | 4 +
arch/lib/include/asm/shmbuf.h | 4 +
arch/lib/include/asm/shmparam.h | 4 +
arch/lib/include/asm/sigcontext.h | 6 +
arch/lib/include/asm/stat.h | 4 +
arch/lib/include/asm/statfs.h | 4 +
arch/lib/include/asm/swab.h | 7 +
arch/lib/include/asm/thread_info.h | 36 ++
arch/lib/include/asm/uaccess.h | 14 +
arch/lib/include/asm/unistd.h | 4 +
arch/lib/include/sim-assert.h | 23 ++
arch/lib/include/sim-init.h | 134 +++++++
arch/lib/include/sim-printf.h | 13 +
arch/lib/include/sim-types.h | 53 +++
arch/lib/include/sim.h | 51 +++
arch/lib/include/uapi/asm/byteorder.h | 6 +
arch/lib/lib-device.c | 187 ++++++++++
arch/lib/lib-socket.c | 410 +++++++++++++++++++++
arch/lib/lib.c | 294 +++++++++++++++
arch/lib/lib.h | 21 ++
arch/lib/modules.c | 36 ++
arch/lib/pid.c | 29 ++
arch/lib/print.c | 56 +++
arch/lib/proc.c | 34 ++
arch/lib/random.c | 53 +++
arch/lib/sched.c | 406 +++++++++++++++++++++
arch/lib/softirq.c | 108 ++++++
arch/lib/sysctl.c | 270 ++++++++++++++
arch/lib/sysfs.c | 83 +++++
arch/lib/tasklet-hrtimer.c | 57 +++
arch/lib/tasklet.c | 76 ++++
arch/lib/time.c | 144 ++++++++
arch/lib/timer.c | 238 +++++++++++++
arch/lib/vmscan.c | 26 ++
arch/lib/workqueue.c | 242 +++++++++++++
fs/proc/proc_sysctl.c | 36 +-
include/linux/slab.h | 6 +-
include/linux/slib_def.h | 21 ++
mm/Makefile | 1 +
mm/slab.h | 4 +
mm/slib.c | 205 +++++++++++
tools/testing/libos/.gitignore | 6 +
tools/testing/libos/Makefile | 38 ++
tools/testing/libos/README | 15 +
tools/testing/libos/bisect.sh | 10 +
tools/testing/libos/dce-test.sh | 23 ++
tools/testing/libos/nuse-test.sh | 57 +++
72 files changed, 5569 insertions(+), 18 deletions(-)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/defconfig
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100755 arch/lib/generate-linker-script.py
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/sysctl.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
create mode 100644 arch/lib/vmscan.c
create mode 100644 arch/lib/workqueue.c
create mode 100644 include/linux/slib_def.h
create mode 100644 mm/slib.c
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
--
2.1.0
libos (arch/lib) emulates a sysctl-like interface by a function call of
userspace by enumerating sysctl tree from sysctl_table_root. It requires
to be publicly accessible to this symbol and related functions.
Signed-off-by: Hajime Tazaki <[email protected]>
---
fs/proc/proc_sysctl.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index fea2561..7c5924c 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -35,7 +35,7 @@ static struct ctl_table root_table[] = {
},
{ }
};
-static struct ctl_table_root sysctl_table_root = {
+struct ctl_table_root sysctl_table_root = {
.default_set.dir.header = {
{{.count = 1,
.nreg = 1,
@@ -77,8 +77,9 @@ static int namecmp(const char *name1, int len1, const char *name2, int len2)
}
/* Called under sysctl_lock */
-static struct ctl_table *find_entry(struct ctl_table_header **phead,
- struct ctl_dir *dir, const char *name, int namelen)
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen)
{
struct ctl_table_header *head;
struct ctl_table *entry;
@@ -300,7 +301,7 @@ static struct ctl_table *lookup_entry(struct ctl_table_header **phead,
struct ctl_table *entry;
spin_lock(&sysctl_lock);
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (entry && use_table(head))
*phead = head;
else
@@ -321,7 +322,7 @@ static struct ctl_node *first_usable_entry(struct rb_node *node)
return NULL;
}
-static void first_entry(struct ctl_dir *dir,
+void ctl_table_first_entry(struct ctl_dir *dir,
struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = NULL;
@@ -339,7 +340,7 @@ static void first_entry(struct ctl_dir *dir,
*pentry = entry;
}
-static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry)
{
struct ctl_table_header *head = *phead;
struct ctl_table *entry = *pentry;
@@ -670,7 +671,8 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx)
pos = 2;
- for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) {
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
if (!scan(h, entry, &pos, file, ctx)) {
sysctl_head_finish(h);
break;
@@ -828,7 +830,7 @@ static struct ctl_dir *find_subdir(struct ctl_dir *dir,
struct ctl_table_header *head;
struct ctl_table *entry;
- entry = find_entry(&head, dir, name, namelen);
+ entry = ctl_table_find_entry(&head, dir, name, namelen);
if (!entry)
return ERR_PTR(-ENOENT);
if (!S_ISDIR(entry->mode))
@@ -924,13 +926,13 @@ failed:
return subdir;
}
-static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir)
{
struct ctl_dir *parent;
const char *procname;
if (!dir->header.parent)
return &set->dir;
- parent = xlate_dir(set, dir->header.parent);
+ parent = ctl_table_xlate_dir(set, dir->header.parent);
if (IS_ERR(parent))
return parent;
procname = dir->header.ctl_table[0].procname;
@@ -951,13 +953,13 @@ static int sysctl_follow_link(struct ctl_table_header **phead,
spin_lock(&sysctl_lock);
root = (*pentry)->data;
set = lookup_header_set(root, namespaces);
- dir = xlate_dir(set, (*phead)->parent);
+ dir = ctl_table_xlate_dir(set, (*phead)->parent);
if (IS_ERR(dir))
ret = PTR_ERR(dir);
else {
const char *procname = (*pentry)->procname;
head = NULL;
- entry = find_entry(&head, dir, procname, strlen(procname));
+ entry = ctl_table_find_entry(&head, dir, procname, strlen(procname));
ret = -ENOENT;
if (entry && use_table(head)) {
unuse_table(*phead);
@@ -1069,7 +1071,7 @@ static bool get_links(struct ctl_dir *dir,
/* Are there links available for every entry in table? */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
if (!link)
return false;
if (S_ISDIR(link->mode) && S_ISDIR(entry->mode))
@@ -1082,7 +1084,7 @@ static bool get_links(struct ctl_dir *dir,
/* The checks passed. Increase the registration count on the links */
for (entry = table; entry->procname; entry++) {
const char *procname = entry->procname;
- link = find_entry(&head, dir, procname, strlen(procname));
+ link = ctl_table_find_entry(&head, dir, procname, strlen(procname));
head->nreg++;
}
return true;
@@ -1098,7 +1100,7 @@ static int insert_links(struct ctl_table_header *head)
if (head->set == root_set)
return 0;
- core_parent = xlate_dir(root_set, head->parent);
+ core_parent = ctl_table_xlate_dir(root_set, head->parent);
if (IS_ERR(core_parent))
return 0;
@@ -1479,7 +1481,7 @@ static void put_links(struct ctl_table_header *header)
if (header->set == root_set)
return;
- core_parent = xlate_dir(root_set, parent);
+ core_parent = ctl_table_xlate_dir(root_set, parent);
if (IS_ERR(core_parent))
return;
@@ -1488,7 +1490,7 @@ static void put_links(struct ctl_table_header *header)
struct ctl_table *link;
const char *name = entry->procname;
- link = find_entry(&link_head, core_parent, name, strlen(name));
+ link = ctl_table_find_entry(&link_head, core_parent, name, strlen(name));
if (link &&
((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) ||
(S_ISLNK(link->mode) && (link->data == root)))) {
--
2.1.0
add SLIB allocator for arch/lib (CONFIG_LIB) to wrap kmalloc and co.
This will bring user's own allocator of libos: malloc(3) etc.
Signed-off-by: Hajime Tazaki <[email protected]>
---
include/linux/slab.h | 6 +-
include/linux/slib_def.h | 21 +++++
mm/Makefile | 1 +
mm/slab.h | 4 +
mm/slib.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 236 insertions(+), 1 deletion(-)
create mode 100644 include/linux/slib_def.h
create mode 100644 mm/slib.c
diff --git a/include/linux/slab.h b/include/linux/slab.h
index ffd24c8..0288cf8 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -191,7 +191,7 @@ size_t ksize(const void *);
#endif
#endif
-#ifdef CONFIG_SLOB
+#if defined(CONFIG_SLOB) || defined(CONFIG_SLIB)
/*
* SLOB passes all requests larger than one page to the page allocator.
* No kmalloc array is necessary since objects of different sizes can
@@ -356,6 +356,9 @@ kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
}
#endif
+#ifdef CONFIG_SLIB
+#include <linux/slib_def.h>
+#else
static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
{
unsigned int order = get_order(size);
@@ -434,6 +437,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags)
}
return __kmalloc(size, flags);
}
+#endif /* CONFIG_SLIB */
/*
* Determine size used for the nth kmalloc cache.
diff --git a/include/linux/slib_def.h b/include/linux/slib_def.h
new file mode 100644
index 0000000..d9fe7d5
--- /dev/null
+++ b/include/linux/slib_def.h
@@ -0,0 +1,21 @@
+#ifndef _LINUX_SLLB_DEF_H
+#define _LINUX_SLLB_DEF_H
+
+
+struct kmem_cache {
+ unsigned int object_size;
+ const char *name;
+ size_t size;
+ size_t align;
+ unsigned long flags;
+ void (*ctor)(void *);
+};
+
+void *__kmalloc(size_t size, gfp_t flags);
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+static __always_inline void *kmalloc(size_t size, gfp_t flags)
+{
+ return __kmalloc(size, flags);
+}
+
+#endif /* _LINUX_SLLB_DEF_H */
diff --git a/mm/Makefile b/mm/Makefile
index 98c4eae..7d8314f 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -46,6 +46,7 @@ obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o
obj-$(CONFIG_SLOB) += slob.o
+obj-$(CONFIG_SLIB) += slib.o
obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
obj-$(CONFIG_KSM) += ksm.o
obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
diff --git a/mm/slab.h b/mm/slab.h
index 4c3ac12..2ea37c9 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -37,6 +37,10 @@ struct kmem_cache {
#include <linux/slub_def.h>
#endif
+#ifdef CONFIG_SLIB
+#include <linux/slib_def.h>
+#endif
+
#include <linux/memcontrol.h>
/*
diff --git a/mm/slib.c b/mm/slib.c
new file mode 100644
index 0000000..37596862
--- /dev/null
+++ b/mm/slib.c
@@ -0,0 +1,205 @@
+/*
+ * Library Slab Allocator (SLIB)
+ *
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/page-flags.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/slib_def.h>
+
+/* glues */
+struct kmem_cache *files_cachep;
+
+void kfree(const void *p)
+{
+ unsigned long start;
+
+ if (p == 0)
+ return;
+ start = (unsigned long)p;
+ start -= sizeof(size_t);
+ lib_free((void *)start);
+}
+size_t ksize(const void *p)
+{
+ size_t *psize = (size_t *)p;
+
+ psize--;
+ return *psize;
+}
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ void *p = lib_malloc(size + sizeof(size));
+ unsigned long start;
+
+ if (!p)
+ return NULL;
+
+ if (p != 0 && (flags & __GFP_ZERO))
+ lib_memset(p, 0, size + sizeof(size));
+ lib_memcpy(p, &size, sizeof(size));
+ start = (unsigned long)p;
+ return (void *)(start + sizeof(size));
+}
+
+void *__kmalloc_track_caller(size_t size, gfp_t flags, unsigned long caller)
+{
+ return kmalloc(size, flags);
+}
+
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+
+ if (!new_size) {
+ kfree(p);
+ return ZERO_SIZE_PTR;
+ }
+
+ ret = __kmalloc(new_size, flags);
+ if (ret && p != ret)
+ kfree(p);
+
+ return ret;
+}
+
+struct kmem_cache *
+kmem_cache_create(const char *name, size_t size, size_t align,
+ unsigned long flags, void (*ctor)(void *))
+{
+ struct kmem_cache *cache = kmalloc(sizeof(struct kmem_cache), flags);
+
+ if (!cache)
+ return NULL;
+ cache->name = name;
+ cache->size = size;
+ cache->align = align;
+ cache->flags = flags;
+ cache->ctor = ctor;
+ return cache;
+}
+void kmem_cache_destroy(struct kmem_cache *cache)
+{
+ kfree(cache);
+}
+int kmem_cache_shrink(struct kmem_cache *cache)
+{
+ return 1;
+}
+const char *kmem_cache_name(struct kmem_cache *cache)
+{
+ return cache->name;
+}
+void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags)
+{
+ void *p = kmalloc(cache->size, flags);
+
+ if (p == 0)
+ return NULL;
+ if (cache->ctor)
+ (cache->ctor)(p);
+ return p;
+
+}
+void kmem_cache_free(struct kmem_cache *cache, void *p)
+{
+ kfree(p);
+}
+
+struct page *
+__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
+ struct zonelist *zonelist, nodemask_t *nodemask)
+{
+ void *p;
+ struct page *page;
+ unsigned long pointer;
+
+ /* typically, called from networking code by alloc_page or */
+ /* directly with an order = 0. */
+ if (order)
+ return NULL;
+ p = lib_malloc(sizeof(struct page) + (1 << PAGE_SHIFT));
+ page = (struct page *)p;
+
+ atomic_set(&page->_count, 1);
+ page->flags = 0;
+ pointer = (unsigned long)page;
+ pointer += sizeof(struct page);
+ page->virtual = (void *)pointer;
+ return page;
+}
+void __free_pages(struct page *page, unsigned int order)
+{
+ /* typically, called from networking code by __free_page */
+ lib_assert(order == 0);
+ lib_free(page);
+}
+
+void put_page(struct page *page)
+{
+ if (atomic_dec_and_test(&page->_count))
+ lib_free(page);
+}
+unsigned long get_zeroed_page(gfp_t gfp_mask)
+{
+ return __get_free_pages(gfp_mask | __GFP_ZERO, 0);
+}
+
+void *alloc_pages_exact(size_t size, gfp_t gfp_mask)
+{
+ return alloc_pages(gfp_mask, get_order(size));
+}
+
+unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
+{
+ int size = (1 << order) * PAGE_SIZE;
+ void *p = kmalloc(size, gfp_mask);
+
+ return (unsigned long)p;
+}
+void free_pages(unsigned long addr, unsigned int order)
+{
+ if (addr != 0)
+ kfree((void *)addr);
+}
+
+void *vmalloc(unsigned long size)
+{
+ return lib_malloc(size);
+}
+void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
+{
+ return kmalloc(size, gfp_mask);
+}
+void vfree(const void *addr)
+{
+ lib_free((void *)addr);
+}
+void *vmalloc_node(unsigned long size, int node)
+{
+ return lib_malloc(size);
+}
+void vmalloc_sync_all(void)
+{
+}
+void *__alloc_percpu(size_t size, size_t align)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+void free_percpu(void __percpu *ptr)
+{
+ kfree(ptr);
+}
+void *__alloc_bootmem_nopanic(unsigned long size,
+ unsigned long align,
+ unsigned long goal)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
--
2.1.0
userspace programs which uses libos access via a public API, lib_init(),
with passed arguments struct SimImported and struct SimExported.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
arch/lib/include/sim-assert.h | 23 +++
arch/lib/include/sim-init.h | 134 ++++++++++++++
arch/lib/include/sim-printf.h | 13 ++
arch/lib/include/sim-types.h | 53 ++++++
arch/lib/include/sim.h | 51 ++++++
arch/lib/lib-device.c | 187 +++++++++++++++++++
arch/lib/lib-socket.c | 410 ++++++++++++++++++++++++++++++++++++++++++
arch/lib/lib.c | 294 ++++++++++++++++++++++++++++++
arch/lib/lib.h | 21 +++
9 files changed, 1186 insertions(+)
create mode 100644 arch/lib/include/sim-assert.h
create mode 100644 arch/lib/include/sim-init.h
create mode 100644 arch/lib/include/sim-printf.h
create mode 100644 arch/lib/include/sim-types.h
create mode 100644 arch/lib/include/sim.h
create mode 100644 arch/lib/lib-device.c
create mode 100644 arch/lib/lib-socket.c
create mode 100644 arch/lib/lib.c
create mode 100644 arch/lib/lib.h
diff --git a/arch/lib/include/sim-assert.h b/arch/lib/include/sim-assert.h
new file mode 100644
index 0000000..974122c
--- /dev/null
+++ b/arch/lib/include/sim-assert.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_ASSERT_H
+#define SIM_ASSERT_H
+
+#include "sim-printf.h"
+
+#define lib_assert(v) { \
+ while (!(v)) { \
+ lib_printf("Assert failed %s:%u \"" #v "\"\n", \
+ __FILE__, __LINE__); \
+ char *p = 0; \
+ *p = 1; \
+ } \
+ }
+
+
+#endif /* SIM_ASSERT_H */
diff --git a/arch/lib/include/sim-init.h b/arch/lib/include/sim-init.h
new file mode 100644
index 0000000..e871a59
--- /dev/null
+++ b/arch/lib/include/sim-init.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_INIT_H
+#define SIM_INIT_H
+
+#include <linux/socket.h>
+#include "sim-types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _IO_FILE;
+typedef struct _IO_FILE FILE;
+
+struct SimExported {
+ struct SimTask *(*task_create)(void *priv, unsigned long pid);
+ void (*task_destroy)(struct SimTask *task);
+ void *(*task_get_private)(struct SimTask *task);
+
+ int (*sock_socket)(int domain, int type, int protocol,
+ struct SimSocket **socket);
+ int (*sock_close)(struct SimSocket *socket);
+ ssize_t (*sock_recvmsg)(struct SimSocket *socket, struct msghdr *msg,
+ int flags);
+ ssize_t (*sock_sendmsg)(struct SimSocket *socket,
+ const struct msghdr *msg, int flags);
+ int (*sock_getsockname)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_getpeername)(struct SimSocket *socket,
+ struct sockaddr *name, int *namelen);
+ int (*sock_bind)(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen);
+ int (*sock_connect)(struct SimSocket *socket,
+ const struct sockaddr *name, int namelen,
+ int flags);
+ int (*sock_listen)(struct SimSocket *socket, int backlog);
+ int (*sock_shutdown)(struct SimSocket *socket, int how);
+ int (*sock_accept)(struct SimSocket *socket,
+ struct SimSocket **newSocket, int flags);
+ int (*sock_ioctl)(struct SimSocket *socket, int request, char *argp);
+ int (*sock_setsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ const void *optval, int optlen);
+ int (*sock_getsockopt)(struct SimSocket *socket, int level,
+ int optname,
+ void *optval, int *optlen);
+
+ void (*sock_poll)(struct SimSocket *socket, void *ret);
+ void (*sock_pollfreewait)(void *polltable);
+
+ struct SimDevice *(*dev_create)(const char *ifname, void *priv,
+ enum SimDevFlags flags);
+ void (*dev_destroy)(struct SimDevice *dev);
+ void *(*dev_get_private)(struct SimDevice *task);
+ void (*dev_set_address)(struct SimDevice *dev,
+ unsigned char buffer[6]);
+ void (*dev_set_mtu)(struct SimDevice *dev, int mtu);
+ struct SimDevicePacket (*dev_create_packet)(struct SimDevice *dev,
+ int size);
+ void (*dev_rx)(struct SimDevice *dev, struct SimDevicePacket packet);
+
+ void (*sys_iterate_files)(const struct SimSysIterator *iter);
+ int (*sys_file_read)(const struct SimSysFile *file, char *buffer,
+ int size, int offset);
+ int (*sys_file_write)(const struct SimSysFile *file,
+ const char *buffer, int size, int offset);
+};
+
+struct SimImported {
+ int (*vprintf)(struct SimKernel *kernel, const char *str,
+ va_list args);
+ void *(*malloc)(struct SimKernel *kernel, unsigned long size);
+ void (*free)(struct SimKernel *kernel, void *buffer);
+ void *(*memcpy)(struct SimKernel *kernel, void *dst, const void *src,
+ unsigned long size);
+ void *(*memset)(struct SimKernel *kernel, void *dst, char value,
+ unsigned long size);
+ int (*atexit)(struct SimKernel *kernel, void (*function)(void));
+ int (*access)(struct SimKernel *kernel, const char *pathname,
+ int mode);
+ char *(*getenv)(struct SimKernel *kernel, const char *name);
+ int (*mkdir)(struct SimKernel *kernel, const char *pathname,
+ mode_t mode);
+ int (*open)(struct SimKernel *kernel, const char *pathname, int flags);
+ int (*__fxstat)(struct SimKernel *kernel, int ver, int fd, void *buf);
+ int (*fseek)(struct SimKernel *kernel, FILE *stream, long offset,
+ int whence);
+ void (*setbuf)(struct SimKernel *kernel, FILE *stream, char *buf);
+ FILE *(*fdopen)(struct SimKernel *kernel, int fd, const char *mode);
+ long (*ftell)(struct SimKernel *kernel, FILE *stream);
+ int (*fclose)(struct SimKernel *kernel, FILE *fp);
+ size_t (*fread)(struct SimKernel *kernel, void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+ size_t (*fwrite)(struct SimKernel *kernel, const void *ptr, size_t size,
+ size_t nmemb, FILE *stream);
+
+ unsigned long (*random)(struct SimKernel *kernel);
+ void *(*event_schedule_ns)(struct SimKernel *kernel, __u64 ns,
+ void (*fn)(void *context), void *context,
+ void (*pre_fn)(void));
+ void (*event_cancel)(struct SimKernel *kernel, void *event);
+ __u64 (*current_ns)(struct SimKernel *kernel);
+
+ struct SimTask *(*task_start)(struct SimKernel *kernel,
+ void (*callback)(void *),
+ void *context);
+ void (*task_wait)(struct SimKernel *kernel);
+ struct SimTask *(*task_current)(struct SimKernel *kernel);
+ int (*task_wakeup)(struct SimKernel *kernel, struct SimTask *task);
+ void (*task_yield)(struct SimKernel *kernel);
+
+ void (*dev_xmit)(struct SimKernel *kernel, struct SimDevice *dev,
+ unsigned char *data, int len);
+ void (*signal_raised)(struct SimKernel *kernel, struct SimTask *task,
+ int sig);
+ void (*poll_event)(int flag, void *context);
+};
+
+typedef void (*SimInit)(struct SimExported *, const struct SimImported *,
+ struct SimKernel *kernel);
+void sim_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_INIT_H */
diff --git a/arch/lib/include/sim-printf.h b/arch/lib/include/sim-printf.h
new file mode 100644
index 0000000..2bf8245
--- /dev/null
+++ b/arch/lib/include/sim-printf.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_PRINTF_H
+#define SIM_PRINTF_H
+
+void lib_printf(const char *str, ...);
+
+#endif /* SIM_PRINTF_H */
diff --git a/arch/lib/include/sim-types.h b/arch/lib/include/sim-types.h
new file mode 100644
index 0000000..d50b99b
--- /dev/null
+++ b/arch/lib/include/sim-types.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_TYPES_H
+#define SIM_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LIBOS_API_VERSION 2
+
+struct SimTask;
+struct SimDevice;
+struct SimSocket;
+struct SimKernel;
+struct SimSysFile;
+
+enum SimDevFlags {
+ SIM_DEV_NOARP = (1 << 0),
+ SIM_DEV_POINTTOPOINT = (1 << 1),
+ SIM_DEV_MULTICAST = (1 << 2),
+ SIM_DEV_BROADCAST = (1 << 3),
+};
+
+struct SimDevicePacket {
+ void *buffer;
+ void *token;
+};
+
+enum SimSysFileFlags {
+ SIM_SYS_FILE_READ = 1 << 0,
+ SIM_SYS_FILE_WRITE = 1 << 1,
+};
+
+struct SimSysIterator {
+ void (*report_start_dir)(const struct SimSysIterator *iter,
+ const char *dirname);
+ void (*report_end_dir)(const struct SimSysIterator *iter);
+ void (*report_file)(const struct SimSysIterator *iter,
+ const char *filename,
+ int flags, struct SimSysFile *file);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SIM_TYPES_H */
diff --git a/arch/lib/include/sim.h b/arch/lib/include/sim.h
new file mode 100644
index 0000000..b30d7e8
--- /dev/null
+++ b/arch/lib/include/sim.h
@@ -0,0 +1,51 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#ifndef SIM_H
+#define SIM_H
+
+#include <stdarg.h>
+#include <linux/types.h>
+
+#include "sim-types.h"
+
+/* API called from within linux kernel. Forwards to SimImported. */
+int lib_vprintf(const char *str, va_list args);
+void *lib_malloc(unsigned long size);
+void lib_free(void *buffer);
+void *lib_memcpy(void *dst, const void *src, unsigned long size);
+void *lib_memset(void *dst, char value, unsigned long size);
+unsigned long lib_random(void);
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context),
+ void *context);
+void lib_event_cancel(void *event);
+__u64 lib_current_ns(void);
+
+struct SimTask *lib_task_start(void (*callback) (void *), void *context);
+void lib_task_wait(void);
+void lib_task_yield(void);
+struct SimTask *lib_task_current(void);
+/* returns 1 if task was woken up, 0 if it was already running. */
+int lib_task_wakeup(struct SimTask *task);
+struct SimTask *lib_task_create(void *priv, unsigned long pid);
+void lib_task_destroy(struct SimTask *task);
+void *lib_task_get_private(struct SimTask *task);
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len);
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size);
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet);
+
+void lib_signal_raised(struct SimTask *task, int sig);
+
+void lib_poll_event(int flag, void *context);
+void lib_softirq_wakeup(void);
+void lib_update_jiffies(void);
+void *lib_dev_get_private(struct SimDevice *);
+void lib_proc_net_initialize(void);
+
+#endif /* SIM_H */
diff --git a/arch/lib/lib-device.c b/arch/lib/lib-device.c
new file mode 100644
index 0000000..1efa6460
--- /dev/null
+++ b/arch/lib/lib-device.c
@@ -0,0 +1,187 @@
+/*
+ * virtual net_device feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ethtool.h>
+
+struct SimDevice {
+ struct net_device dev;
+ void *priv;
+};
+
+static netdev_tx_t
+kernel_dev_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ int err;
+
+ netif_stop_queue(dev);
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ err = skb_checksum_help(skb);
+ if (unlikely(err)) {
+ pr_err("checksum error (%d)\n", err);
+ return 0;
+ }
+ }
+
+ lib_dev_xmit((struct SimDevice *)dev, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ netif_wake_queue(dev);
+ return 0;
+}
+
+static u32 always_on(struct net_device *dev)
+{
+ return 1;
+}
+
+
+static const struct ethtool_ops lib_ethtool_ops = {
+ .get_link = always_on,
+};
+
+static const struct net_device_ops lib_dev_ops = {
+ .ndo_start_xmit = kernel_dev_xmit,
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+static void lib_dev_setup(struct net_device *dev)
+{
+ dev->mtu = (16 * 1024) + 20 + 20 + 12;
+ dev->hard_header_len = ETH_HLEN; /* 14 */
+ dev->addr_len = ETH_ALEN; /* 6 */
+ dev->tx_queue_len = 0;
+ dev->type = ARPHRD_ETHER;
+ dev->flags = 0;
+ /* dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; */
+ dev->features = 0
+ | NETIF_F_HIGHDMA
+ | NETIF_F_NETNS_LOCAL;
+ /* disabled NETIF_F_TSO NETIF_F_SG NETIF_F_FRAGLIST NETIF_F_LLTX */
+ dev->ethtool_ops = &lib_ethtool_ops;
+ dev->header_ops = ð_header_ops;
+ dev->netdev_ops = &lib_dev_ops;
+ dev->destructor = &free_netdev;
+}
+
+
+struct SimDevice *lib_dev_create(const char *ifname, void *priv,
+ enum SimDevFlags flags)
+{
+ int err;
+ struct SimDevice *dev =
+ (struct SimDevice *)alloc_netdev(sizeof(struct SimDevice),
+ ifname, NET_NAME_UNKNOWN,
+ &lib_dev_setup);
+ ether_setup((struct net_device *)dev);
+
+ if (flags & SIM_DEV_NOARP)
+ dev->dev.flags |= IFF_NOARP;
+ if (flags & SIM_DEV_POINTTOPOINT)
+ dev->dev.flags |= IFF_POINTOPOINT;
+ if (flags & SIM_DEV_MULTICAST)
+ dev->dev.flags |= IFF_MULTICAST;
+ if (flags & SIM_DEV_BROADCAST) {
+ dev->dev.flags |= IFF_BROADCAST;
+ memset(dev->dev.broadcast, 0xff, 6);
+ }
+ dev->priv = priv;
+ err = register_netdev(&dev->dev);
+ return dev;
+}
+void lib_dev_destroy(struct SimDevice *dev)
+{
+ unregister_netdev(&dev->dev);
+ /* XXX */
+ free_netdev(&dev->dev);
+}
+void *lib_dev_get_private(struct SimDevice *dev)
+{
+ return dev->priv;
+}
+
+void lib_dev_set_mtu(struct SimDevice *dev, int mtu)
+{
+ /* called by ns-3 to synchronize the kernel mtu with */
+ /* the simulation mtu */
+ dev->dev.mtu = mtu;
+}
+
+static int lib_ndo_change_mtu(struct net_device *dev,
+ int new_mtu)
+{
+ /* called by kernel to change the mtu when the user */
+ /* asks for it. */
+ /* XXX should forward the set call to ns-3 and wait for */
+ /* ns-3 to notify of the change in the function above */
+ /* but I am way too tired to do this now. */
+ return 0;
+}
+
+void lib_dev_set_address(struct SimDevice *dev, unsigned char buffer[6])
+{
+ /* called by ns-3 to synchronize the kernel address with */
+ /* the simulation address. */
+ struct sockaddr sa;
+
+ sa.sa_family = dev->dev.type;
+ lib_memcpy(&sa.sa_data, buffer, 6);
+ dev->dev.netdev_ops->ndo_set_mac_address(&dev->dev, &sa);
+ /* Note that we don't call dev_set_mac_address (&dev->dev, &sa); */
+ /* because this function expects to be called from within */
+ /* the netlink layer so, it expects to hold */
+ /* the netlink lock during the execution of the associated notifiers */
+}
+static int get_hack_size(int size)
+{
+ /* Note: this hack is coming from nsc */
+ /* Bit of a hack... */
+ /* Note that the size allocated here effects the offered window
+ somewhat. I've got this heuristic here to try and match up with
+ what we observe on the emulation network and by looking at the
+ driver code of the eepro100. In both cases we allocate enough
+ space for our packet, which is the important thing. The amount
+ of slack at the end can make linux decide the grow the window
+ differently. This is quite subtle, but the code in question is
+ in the tcp_grow_window function. It checks skb->truesize, which
+ is the size of the skbuff allocated for the incoming data
+ packet -- what we are allocating right now! */
+ if (size < 1200)
+ return size + 36;
+ else if (size <= 1500)
+ return 1536;
+ else
+ return size + 36;
+}
+struct SimDevicePacket lib_dev_create_packet(struct SimDevice *dev, int size)
+{
+ struct SimDevicePacket packet;
+ int len = get_hack_size(size);
+ struct sk_buff *skb = __dev_alloc_skb(len, __GFP_WAIT);
+
+ packet.token = skb;
+ packet.buffer = skb_put(skb, len);
+ return packet;
+}
+void lib_dev_rx(struct SimDevice *device, struct SimDevicePacket packet)
+{
+ struct sk_buff *skb = packet.token;
+ struct net_device *dev = &device->dev;
+
+ skb->protocol = eth_type_trans(skb, dev);
+ /* Do the TCP checksum (FIXME: should be configurable) */
+ skb->ip_summed = CHECKSUM_PARTIAL;
+
+ netif_rx(skb);
+}
diff --git a/arch/lib/lib-socket.c b/arch/lib/lib-socket.c
new file mode 100644
index 0000000..d9be5fc
--- /dev/null
+++ b/arch/lib/lib-socket.c
@@ -0,0 +1,410 @@
+/*
+ * socket feature for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-init.h"
+#include "sim.h"
+#include <linux/net.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+#include <net/inet_connection_sock.h>
+
+struct SimSocket {};
+
+static struct iovec *copy_iovec(const struct iovec *input, int len)
+{
+ int size = sizeof(struct iovec) * len;
+ struct iovec *output = lib_malloc(size);
+
+ if (!output)
+ return NULL;
+ lib_memcpy(output, input, size);
+ return output;
+}
+
+int lib_sock_socket(int domain, int type, int protocol,
+ struct SimSocket **socket)
+{
+ struct socket **kernel_socket = (struct socket **)socket;
+ int flags;
+
+ /* from net/socket.c */
+ flags = type & ~SOCK_TYPE_MASK;
+ if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
+ return -EINVAL;
+ type &= SOCK_TYPE_MASK;
+
+ int retval = sock_create(domain, type, protocol, kernel_socket);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ struct file *fp = lib_malloc(sizeof(struct file));
+ (*kernel_socket)->file = fp;
+ fp->f_cred = lib_malloc(sizeof(struct cred));
+ return retval;
+}
+int lib_sock_close(struct SimSocket *socket)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+
+ sock_release(kernel_socket);
+ return 0;
+}
+static size_t iov_size(const struct user_msghdr *msg)
+{
+ size_t i;
+ size_t size = 0;
+
+ for (i = 0; i < msg->msg_iovlen; i++)
+ size += msg->msg_iov[i].iov_len;
+ return size;
+}
+ssize_t lib_sock_recvmsg(struct SimSocket *socket,
+ struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct msghdr msg_sys;
+ struct cmsghdr *user_cmsgh = msg->msg_control;
+ size_t user_cmsghlen = msg->msg_controllen;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, READ,
+ msg->msg_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_recvmsg(kernel_socket, &msg_sys, iov_size(msg), flags);
+
+ msg->msg_name = msg_sys.msg_name;
+ msg->msg_namelen = msg_sys.msg_namelen;
+ msg->msg_control = user_cmsgh;
+ msg->msg_controllen = user_cmsghlen - msg_sys.msg_controllen;
+ return retval;
+}
+ssize_t lib_sock_sendmsg(struct SimSocket *socket,
+ const struct user_msghdr *msg,
+ int flags)
+{
+ struct socket *kernel_socket = (struct socket *)socket;
+ struct iovec *kernel_iov = copy_iovec(msg->msg_iov, msg->msg_iovlen);
+ struct msghdr msg_sys;
+ int retval;
+
+ msg_sys.msg_name = msg->msg_name;
+ msg_sys.msg_namelen = msg->msg_namelen;
+ msg_sys.msg_control = msg->msg_control;
+ msg_sys.msg_controllen = msg->msg_controllen;
+ msg_sys.msg_flags = flags;
+
+ iov_iter_init(&msg_sys.msg_iter, WRITE,
+ kernel_iov, msg->msg_iovlen, iov_size(msg));
+
+ retval = sock_sendmsg(kernel_socket, &msg_sys);
+ lib_free(kernel_iov);
+ return retval;
+}
+int lib_sock_getsockname(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 0);
+
+ return retval;
+}
+int lib_sock_getpeername(struct SimSocket *socket, struct sockaddr *name,
+ int *namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->getname(sock, name, namelen, 1);
+
+ return retval;
+}
+int lib_sock_bind(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ int retval =
+ sock->ops->bind(sock, (struct sockaddr *)&address, namelen);
+ return retval;
+}
+int lib_sock_connect(struct SimSocket *socket, const struct sockaddr *name,
+ int namelen, int flags)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sockaddr_storage address;
+
+ memcpy(&address, name, namelen);
+ /* XXX: SCTP code never look at flags args, but file flags instead. */
+ sock->file->f_flags = flags;
+ int retval = sock->ops->connect(sock, (struct sockaddr *)&address,
+ namelen, flags);
+ return retval;
+}
+int lib_sock_listen(struct SimSocket *socket, int backlog)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->listen(sock, backlog);
+
+ return retval;
+}
+int lib_sock_shutdown(struct SimSocket *socket, int how)
+{
+ struct socket *sock = (struct socket *)socket;
+ int retval = sock->ops->shutdown(sock, how);
+
+ return retval;
+}
+int lib_sock_accept(struct SimSocket *socket, struct SimSocket **new_socket,
+ int flags)
+{
+ struct socket *sock, *newsock;
+ int err;
+
+ sock = (struct socket *)socket;
+
+ /* the fields do not matter here. If we could, */
+ /* we would call sock_alloc but it's not exported. */
+ err = sock_create_lite(0, 0, 0, &newsock);
+ if (err < 0)
+ return err;
+ newsock->type = sock->type;
+ newsock->ops = sock->ops;
+
+ err = sock->ops->accept(sock, newsock, flags);
+ if (err < 0) {
+ sock_release(newsock);
+ return err;
+ }
+ *new_socket = (struct SimSocket *)newsock;
+ return 0;
+}
+int lib_sock_ioctl(struct SimSocket *socket, int request, char *argp)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct sock *sk;
+ struct net *net;
+ int err;
+
+ sk = sock->sk;
+ net = sock_net(sk);
+
+ err = sock->ops->ioctl(sock, request, (long)argp);
+
+ /*
+ * If this ioctl is unknown try to hand it down
+ * to the NIC driver.
+ */
+ if (err == -ENOIOCTLCMD)
+ err = dev_ioctl(net, request, argp);
+ return err;
+}
+int lib_sock_setsockopt(struct SimSocket *socket, int level, int optname,
+ const void *optval, int optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ char *coptval = (char *)optval;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_setsockopt(sock, level, optname, coptval, optlen);
+ else
+ err = sock->ops->setsockopt(sock, level, optname, coptval,
+ optlen);
+ return err;
+}
+int lib_sock_getsockopt(struct SimSocket *socket, int level, int optname,
+ void *optval, int *optlen)
+{
+ struct socket *sock = (struct socket *)socket;
+ int err;
+
+ if (level == SOL_SOCKET)
+ err = sock_getsockopt(sock, level, optname, optval, optlen);
+ else
+ err =
+ sock->ops->getsockopt(sock, level, optname, optval,
+ optlen);
+ return err;
+}
+
+int lib_sock_canrecv(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+ struct inet_connection_sock *icsk;
+
+ switch (sock->sk->sk_state) {
+ case TCP_CLOSE:
+ if (SOCK_STREAM == sock->sk->sk_type)
+ return 1;
+ case TCP_ESTABLISHED:
+ return sock->sk->sk_receive_queue.qlen > 0;
+ case TCP_SYN_SENT:
+ case TCP_SYN_RECV:
+ case TCP_LAST_ACK:
+ case TCP_CLOSING:
+ return 0;
+ case TCP_FIN_WAIT1:
+ case TCP_FIN_WAIT2:
+ case TCP_TIME_WAIT:
+ case TCP_CLOSE_WAIT:
+ return 1;
+ case TCP_LISTEN:
+ {
+ icsk = inet_csk(sock->sk);
+ return !reqsk_queue_empty(&icsk->icsk_accept_queue);
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+int lib_sock_cansend(struct SimSocket *socket)
+{
+ struct socket *sock = (struct socket *)socket;
+
+ return sock_writeable(sock->sk);
+}
+
+/**
+ * Struct used to pass pool table context between DCE and Kernel and back from
+ * Kernel to DCE
+ *
+ * When calling sock_poll we provide in ret field the wanted eventmask, and in
+ * the opaque field the DCE poll table
+ *
+ * if a corresponding event occurs later, the PollEvent will be called by kernel
+ * with the DCE poll table in context variable, then we will able to wake up the
+ * thread blocked in poll call.
+ *
+ * Back from sock_poll method the kernel change ret field with the response from
+ * poll return of the corresponding kernel socket, and in opaque field there is
+ * a reference to the kernel poll table we will use this reference to remove us
+ * from the file wait queue when ending the DCE poll call or when ending the DCE
+ * process which is currently polling.
+ *
+ */
+struct poll_table_ref {
+ int ret;
+ void *opaque;
+};
+
+/* Because the poll main loop code is in NS3/DCE we have only on entry
+ in our kernel poll table */
+struct lib_ptable_entry {
+ wait_queue_t wait;
+ wait_queue_head_t *wait_address;
+ int eventMask; /* Poll wanted event mask. */
+ void *opaque; /* Pointeur to DCE poll table */
+};
+
+static int lib_pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)wait->private;
+
+ /* Filter only wanted events */
+ if (key && !((unsigned long)key & entry->eventMask))
+ return 0;
+
+ lib_poll_event((unsigned long)key, entry->opaque);
+ return 1;
+}
+
+static void lib_pollwait(struct file *filp, wait_queue_head_t *wait_address,
+ poll_table *p)
+{
+ struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)
+ lib_malloc(sizeof(struct lib_ptable_entry));
+ struct poll_table_ref *fromDCE = (struct poll_table_ref *)pwq->table;
+
+ if (!entry)
+ return;
+
+ entry->opaque = fromDCE->opaque; /* Copy DCE poll table reference */
+ entry->eventMask = fromDCE->ret; /* Copy poll mask of wanted events. */
+
+ pwq->table = (struct poll_table_page *)entry;
+
+ init_waitqueue_func_entry(&entry->wait, lib_pollwake);
+ entry->wait.private = entry;
+ entry->wait_address = wait_address;
+ add_wait_queue(wait_address, &entry->wait);
+}
+
+void dce_poll_initwait(struct poll_wqueues *pwq)
+{
+ init_poll_funcptr(&pwq->pt, lib_pollwait);
+ pwq->polling_task = current;
+ pwq->triggered = 0;
+ pwq->error = 0;
+ pwq->table = NULL;
+ pwq->inline_index = 0;
+}
+
+/* call poll on socket ... */
+void lib_sock_poll(struct SimSocket *socket, struct poll_table_ref *ret)
+{
+ struct socket *sock = (struct socket *)socket;
+ /* Provide a fake file structure */
+ struct file zero;
+ poll_table *pwait = 0;
+ struct poll_wqueues *ptable = 0;
+
+ lib_memset(&zero, 0, sizeof(struct file));
+
+ if (ret->opaque) {
+ ptable =
+ (struct poll_wqueues *)lib_malloc(sizeof(struct
+ poll_wqueues));
+ if (!ptable)
+ return;
+
+ dce_poll_initwait(ptable);
+
+ pwait = &(ptable->pt);
+ /* Pass the DCE pool table to lib_pollwait function */
+ ptable->table = (struct poll_table_page *)ret;
+ }
+
+ ret->ret = sock->ops->poll(&zero, sock, pwait);
+ /* Pass back the kernel poll table to DCE in order to DCE to */
+ /* remove from wait queue */
+ /* using lib_sock_pollfreewait method below */
+ ret->opaque = ptable;
+}
+
+void lib_sock_pollfreewait(void *polltable)
+{
+ struct poll_wqueues *ptable = (struct poll_wqueues *)polltable;
+
+ if (ptable && ptable->table) {
+ struct lib_ptable_entry *entry =
+ (struct lib_ptable_entry *)ptable->table;
+ remove_wait_queue(entry->wait_address, &entry->wait);
+ lib_free(entry);
+ }
+ lib_free(ptable);
+}
+
+
+
+
diff --git a/arch/lib/lib.c b/arch/lib/lib.c
new file mode 100644
index 0000000..52d638e
--- /dev/null
+++ b/arch/lib/lib.c
@@ -0,0 +1,294 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/init.h> /* initcall_t */
+#include <linux/kernel.h> /* SYSTEM_BOOTING */
+#include <linux/sched.h> /* struct task_struct */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <drivers/base/base.h>
+#include <linux/idr.h>
+#include <linux/rcupdate.h>
+#include "sim-init.h"
+#include "sim.h"
+
+enum system_states system_state = SYSTEM_BOOTING;
+/* glues */
+struct task_struct init_task;
+
+struct SimImported g_imported;
+
+
+#define RETURN_void(rettype, v) \
+ ({ \
+ (v); \
+ lib_softirq_wakeup(); \
+ })
+
+#define RETURN_nvoid(rettype, v) \
+ ({ \
+ rettype x = (v); \
+ lib_softirq_wakeup(); \
+ x; \
+ })
+
+#define FORWARDER1(name, type, rettype, t0) \
+ extern rettype name(t0); \
+ static rettype name ## _forwarder(t0 v0) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0))); \
+ }
+
+#define FORWARDER2(name, type, rettype, t0, t1) \
+ extern rettype name(t0, t1); \
+ static rettype name ## _forwarder(t0 v0, t1 v1) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1))); \
+ }
+#define FORWARDER3(name, type, rettype, t0, t1, t2) \
+ extern rettype name(t0, t1, t2); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER4(name, type, rettype, t0, t1, t2, t3) \
+ extern rettype name(t0, t1, t2, t3); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3))); \
+ }
+#define FORWARDER5(name, type, rettype, t0, t1, t2, t3, t4) \
+ extern rettype name(t0, t1, t2, t3, t4); \
+ static rettype name ## _forwarder(t0 v0, t1 v1, t2 v2, t3 v3, t4 v4) \
+ { \
+ lib_update_jiffies(); \
+ return RETURN_ ## type(rettype, (name(v0, v1, v2, v3, v4))); \
+ }
+
+FORWARDER3(lib_dev_create, nvoid, struct SimDevice *, const char *, void *,
+ enum SimDevFlags);
+FORWARDER1(lib_dev_destroy, void, void, struct SimDevice *);
+FORWARDER2(lib_dev_set_address, void, void, struct SimDevice *,
+ unsigned char *);
+FORWARDER2(lib_dev_set_mtu, void, void, struct SimDevice *, int);
+FORWARDER2(lib_dev_create_packet, nvoid, struct SimDevicePacket,
+ struct SimDevice *, int);
+FORWARDER2(lib_dev_rx, void, void, struct SimDevice *, struct SimDevicePacket);
+
+FORWARDER4(lib_sock_socket, nvoid, int, int, int, int, struct SimSocket **);
+FORWARDER1(lib_sock_close, nvoid, int, struct SimSocket *);
+FORWARDER3(lib_sock_recvmsg, nvoid, ssize_t, struct SimSocket *,
+ struct msghdr *, int);
+FORWARDER3(lib_sock_sendmsg, nvoid, ssize_t, struct SimSocket *,
+ const struct msghdr *, int);
+FORWARDER3(lib_sock_getsockname, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_getpeername, nvoid, int, struct SimSocket *,
+ struct sockaddr *, int *);
+FORWARDER3(lib_sock_bind, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int);
+FORWARDER4(lib_sock_connect, nvoid, int, struct SimSocket *,
+ const struct sockaddr *, int, int);
+FORWARDER2(lib_sock_listen, nvoid, int, struct SimSocket *, int);
+FORWARDER2(lib_sock_shutdown, nvoid, int, struct SimSocket *, int);
+FORWARDER3(lib_sock_accept, nvoid, int, struct SimSocket *,
+ struct SimSocket **, int);
+FORWARDER3(lib_sock_ioctl, nvoid, int, struct SimSocket *, int, char *);
+FORWARDER5(lib_sock_setsockopt, nvoid, int, struct SimSocket *, int, int,
+ const void *, int);
+FORWARDER5(lib_sock_getsockopt, nvoid, int, struct SimSocket *, int, int,
+ void *, int *);
+
+FORWARDER2(lib_sock_poll, void, void, struct SimSocket *, void *);
+FORWARDER1(lib_sock_pollfreewait, void, void, void *);
+
+FORWARDER1(lib_sys_iterate_files, void, void, const struct SimSysIterator *);
+FORWARDER4(lib_sys_file_read, nvoid, int, const struct SimSysFile *, char *,
+ int, int);
+FORWARDER4(lib_sys_file_write, nvoid, int, const struct SimSysFile *,
+ const char *, int, int);
+
+struct SimKernel *g_kernel;
+
+void lib_init(struct SimExported *exported, const struct SimImported *imported,
+ struct SimKernel *kernel)
+{
+ /* make sure we can call the callbacks */
+ g_imported = *imported;
+ g_kernel = kernel;
+ exported->task_create = lib_task_create;
+ exported->task_destroy = lib_task_destroy;
+ exported->task_get_private = lib_task_get_private;
+ exported->sock_socket = lib_sock_socket_forwarder;
+ exported->sock_close = lib_sock_close_forwarder;
+ exported->sock_recvmsg = lib_sock_recvmsg_forwarder;
+ exported->sock_sendmsg = lib_sock_sendmsg_forwarder;
+ exported->sock_getsockname = lib_sock_getsockname_forwarder;
+ exported->sock_getpeername = lib_sock_getpeername_forwarder;
+ exported->sock_bind = lib_sock_bind_forwarder;
+ exported->sock_connect = lib_sock_connect_forwarder;
+ exported->sock_listen = lib_sock_listen_forwarder;
+ exported->sock_shutdown = lib_sock_shutdown_forwarder;
+ exported->sock_accept = lib_sock_accept_forwarder;
+ exported->sock_ioctl = lib_sock_ioctl_forwarder;
+ exported->sock_setsockopt = lib_sock_setsockopt_forwarder;
+ exported->sock_getsockopt = lib_sock_getsockopt_forwarder;
+
+ exported->sock_poll = lib_sock_poll_forwarder;
+ exported->sock_pollfreewait = lib_sock_pollfreewait_forwarder;
+
+ exported->dev_create = lib_dev_create_forwarder;
+ exported->dev_destroy = lib_dev_destroy_forwarder;
+ exported->dev_get_private = lib_dev_get_private;
+ exported->dev_set_address = lib_dev_set_address_forwarder;
+ exported->dev_set_mtu = lib_dev_set_mtu_forwarder;
+ exported->dev_create_packet = lib_dev_create_packet_forwarder;
+ exported->dev_rx = lib_dev_rx_forwarder;
+
+ exported->sys_iterate_files = lib_sys_iterate_files_forwarder;
+ exported->sys_file_write = lib_sys_file_write_forwarder;
+ exported->sys_file_read = lib_sys_file_read_forwarder;
+
+ pr_notice("%s", linux_banner);
+
+ rcu_init();
+
+ /* in drivers/base/core.c (called normally by drivers/base/init.c) */
+ devices_init();
+ /* in lib/idr.c (called normally by init/main.c) */
+ idr_init_cache();
+ vfs_caches_init(totalram_pages);
+
+ lib_proc_net_initialize();
+
+ /* and, then, call the normal initcalls */
+ initcall_t *call;
+ extern initcall_t __initcall_start[], __initcall_end[];
+
+ call = __initcall_start;
+ do {
+ (*call)();
+ call++;
+ } while (call < __initcall_end);
+
+ /* finally, put the system in RUNNING state. */
+ system_state = SYSTEM_RUNNING;
+}
+
+int lib_vprintf(const char *str, va_list args)
+{
+ return g_imported.vprintf(g_kernel, str, args);
+}
+void *lib_malloc(unsigned long size)
+{
+ return g_imported.malloc(g_kernel, size);
+}
+void lib_free(void *buffer)
+{
+ return g_imported.free(g_kernel, buffer);
+}
+void *lib_memcpy(void *dst, const void *src, unsigned long size)
+{
+ return g_imported.memcpy(g_kernel, dst, src, size);
+}
+void *lib_memset(void *dst, char value, unsigned long size)
+{
+ return g_imported.memset(g_kernel, dst, value, size);
+}
+unsigned long lib_random(void)
+{
+ return g_imported.random(g_kernel);
+}
+void *lib_event_schedule_ns(__u64 ns, void (*fn) (void *context), void *context)
+{
+ return g_imported.event_schedule_ns(g_kernel, ns, fn, context,
+ lib_update_jiffies);
+}
+void lib_event_cancel(void *event)
+{
+ return g_imported.event_cancel(g_kernel, event);
+}
+__u64 lib_current_ns(void)
+{
+ return g_imported.current_ns(g_kernel);
+}
+struct SimTaskTrampolineContext {
+ void (*callback)(void *);
+ void *context;
+};
+static void lib_task_start_trampoline(void *context)
+{
+ /* we use this trampoline solely for the purpose of executing
+ lib_update_jiffies prior to calling the callback. */
+ struct SimTaskTrampolineContext *ctx = context;
+ void (*callback)(void *) = ctx->callback;
+ void *callback_context = ctx->context;
+
+ lib_free(ctx);
+ lib_update_jiffies();
+ callback(callback_context);
+}
+struct SimTask *lib_task_start(void (*callback) (void *), void *context)
+{
+ struct SimTaskTrampolineContext *ctx =
+ lib_malloc(sizeof(struct SimTaskTrampolineContext));
+
+ if (!ctx)
+ return NULL;
+ ctx->callback = callback;
+ ctx->context = context;
+ return g_imported.task_start(g_kernel, &lib_task_start_trampoline, ctx);
+}
+void lib_task_wait(void)
+{
+ rcu_sched_qs();
+ g_imported.task_wait(g_kernel);
+ lib_update_jiffies();
+}
+struct SimTask *lib_task_current(void)
+{
+ return g_imported.task_current(g_kernel);
+}
+int lib_task_wakeup(struct SimTask *task)
+{
+ return g_imported.task_wakeup(g_kernel, task);
+}
+void lib_task_yield(void)
+{
+ rcu_idle_enter();
+ g_imported.task_yield(g_kernel);
+ rcu_idle_exit();
+ lib_update_jiffies();
+}
+
+void lib_dev_xmit(struct SimDevice *dev, unsigned char *data, int len)
+{
+ return g_imported.dev_xmit(g_kernel, dev, data, len);
+}
+
+void lib_signal_raised(struct SimTask *task, int sig)
+{
+ g_imported.signal_raised(g_kernel, task, sig);
+}
+
+void lib_poll_event(int flag, void *context)
+{
+ g_imported.poll_event(flag, context);
+}
diff --git a/arch/lib/lib.h b/arch/lib/lib.h
new file mode 100644
index 0000000..abf2a26
--- /dev/null
+++ b/arch/lib/lib.h
@@ -0,0 +1,21 @@
+/*
+ * library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#ifndef LIB_H
+#define LIB_H
+
+#include <linux/sched.h>
+
+struct SimTask {
+ struct list_head head;
+ struct task_struct kernel_task;
+ void *private;
+};
+
+#endif /* LIB_H */
--
2.1.0
timer related (internal) functions such as add_timer(),
do_gettimeofday() of kernel are trivially reimplemented
for libos. these eventually call the functions registered by lib_init()
API.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/hrtimer.c | 122 +++++++++++++++++++++++
arch/lib/tasklet-hrtimer.c | 57 +++++++++++
arch/lib/time.c | 144 +++++++++++++++++++++++++++
arch/lib/timer.c | 238 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 561 insertions(+)
create mode 100644 arch/lib/hrtimer.c
create mode 100644 arch/lib/tasklet-hrtimer.c
create mode 100644 arch/lib/time.c
create mode 100644 arch/lib/timer.c
diff --git a/arch/lib/hrtimer.c b/arch/lib/hrtimer.c
new file mode 100644
index 0000000..4565b59
--- /dev/null
+++ b/arch/lib/hrtimer.c
@@ -0,0 +1,122 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/hrtimer.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * hrtimer_init - initialize a timer to the given clock
+ * @timer: the timer to be initialized
+ * @clock_id: the clock to be used
+ * @mode: timer mode abs/rel
+ */
+void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
+{
+ memset(timer, 0, sizeof(*timer));
+}
+static void trampoline(void *context)
+{
+ struct hrtimer *timer = context;
+ enum hrtimer_restart restart = timer->function(timer);
+
+ if (restart == HRTIMER_RESTART) {
+ void *event =
+ lib_event_schedule_ns(ktime_to_ns(timer->_softexpires),
+ &trampoline, timer);
+ timer->base = event;
+ } else {
+ /* mark as completed. */
+ timer->base = 0;
+ }
+}
+/**
+ * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU
+ * @timer: the timer to be added
+ * @tim: expiry time
+ * @delta_ns: "slack" range for the timer
+ * @mode: expiry mode: absolute (HRTIMER_ABS) or relative (HRTIMER_REL)
+ *
+ * Returns:
+ * 0 on success
+ * 1 when the timer was active
+ */
+int __hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns,
+ const enum hrtimer_mode mode,
+ int wakeup)
+{
+ int ret = hrtimer_cancel(timer);
+ s64 ns = ktime_to_ns(tim);
+ void *event;
+
+ if (mode == HRTIMER_MODE_ABS)
+ ns -= lib_current_ns();
+ timer->_softexpires = ns_to_ktime(ns);
+ event = lib_event_schedule_ns(ns, &trampoline, timer);
+ timer->base = event;
+ return ret;
+}
+/**
+ * hrtimer_try_to_cancel - try to deactivate a timer
+ * @timer: hrtimer to stop
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ * -1 when the timer is currently excuting the callback function and
+ * cannot be stopped
+ */
+int hrtimer_try_to_cancel(struct hrtimer *timer)
+{
+ /* Note: we cannot return -1 from this function.
+ see comment in hrtimer_cancel. */
+ if (timer->base == 0)
+ /* timer was not active yet */
+ return 1;
+ lib_event_cancel(timer->base);
+ timer->base = 0;
+ return 0;
+}
+/**
+ * hrtimer_cancel - cancel a timer and wait for the handler to finish.
+ * @timer: the timer to be cancelled
+ *
+ * Returns:
+ * 0 when the timer was not active
+ * 1 when the timer was active
+ */
+int hrtimer_cancel(struct hrtimer *timer)
+{
+ /* Note: because we assume a uniprocessor non-interruptible */
+ /* system when running in the kernel, we know that the timer */
+ /* is not running when we execute this code, so, know that */
+ /* try_to_cancel cannot return -1 and we don't need to retry */
+ /* the cancel later to wait for the handler to finish. */
+ int ret = hrtimer_try_to_cancel(timer);
+
+ lib_assert(ret >= 0);
+ return ret;
+}
+int
+hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, 0, mode, 1);
+}
+int hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim,
+ unsigned long delta_ns, const enum hrtimer_mode mode)
+{
+ return __hrtimer_start_range_ns(timer, tim, delta_ns, mode, 1);
+}
+
+int hrtimer_get_res(const clockid_t which_clock, struct timespec *tp)
+{
+ *tp = ns_to_timespec(1);
+ return 0;
+}
diff --git a/arch/lib/tasklet-hrtimer.c b/arch/lib/tasklet-hrtimer.c
new file mode 100644
index 0000000..fef4902
--- /dev/null
+++ b/arch/lib/tasklet-hrtimer.c
@@ -0,0 +1,57 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer)
+{
+ struct tasklet_hrtimer *ttimer =
+ container_of(timer, struct tasklet_hrtimer, timer);
+
+ tasklet_schedule(&ttimer->tasklet);
+ return HRTIMER_NORESTART;
+}
+static void __tasklet_hrtimer_trampoline(unsigned long data)
+{
+ struct tasklet_hrtimer *ttimer = (void *)data;
+ enum hrtimer_restart restart;
+
+ restart = ttimer->function(&ttimer->timer);
+ if (restart != HRTIMER_NORESTART)
+ hrtimer_restart(&ttimer->timer);
+}
+/**
+ * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
+ * @ttimer: tasklet_hrtimer which is initialized
+ * @function: hrtimer callback function which gets called from softirq context
+ * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
+ * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
+ */
+void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer,
+ enum hrtimer_restart (*function)(struct hrtimer *),
+ clockid_t which_clock, enum hrtimer_mode mode)
+{
+ hrtimer_init(&ttimer->timer, which_clock, mode);
+ ttimer->timer.function = __hrtimer_tasklet_trampoline;
+ tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline,
+ (unsigned long)ttimer);
+ ttimer->function = function;
+}
+
+void __tasklet_hi_schedule(struct tasklet_struct *t)
+{
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ void *event =
+ lib_event_schedule_ns(0, (void *)&t->func, (void *)t->data);
+ t->next = event;
+}
diff --git a/arch/lib/time.c b/arch/lib/time.c
new file mode 100644
index 0000000..b54be75
--- /dev/null
+++ b/arch/lib/time.c
@@ -0,0 +1,144 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/time.h>
+#include <linux/errno.h>
+#include <linux/timex.h>
+#include <linux/ktime.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+unsigned long volatile jiffies = INITIAL_JIFFIES;
+u64 jiffies_64 = INITIAL_JIFFIES;
+
+struct timespec xtime;
+seqlock_t xtime_lock;
+/* accessed from wrap_clock from do_sys_settimeofday.
+ We don't call the latter so we should never access this variable. */
+struct timespec wall_to_monotonic;
+
+uint64_t ns_to_jiffies(uint64_t ns)
+{
+ do_div(ns, (1000000000 / HZ));
+ return ns;
+}
+
+void lib_update_jiffies(void)
+{
+ jiffies = ns_to_jiffies(lib_current_ns());
+ jiffies_64 = ns_to_jiffies(lib_current_ns());
+}
+
+struct timespec current_kernel_time(void)
+{
+ u64 ns = lib_current_ns();
+ struct timespec spec = ns_to_timespec(ns);
+
+ return spec;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ u64 ns = lib_current_ns();
+
+ *tv = ns_to_timeval(ns);
+}
+
+int do_adjtimex(struct timex *timex)
+{
+ lib_assert(false);
+ return -EPERM;
+}
+ktime_t ktime_get(void)
+{
+ u64 ns = lib_current_ns();
+
+ return ns_to_ktime(ns);
+}
+ktime_t ktime_get_with_offset(enum tk_offsets offs)
+{
+ /* FIXME */
+ return ktime_get();
+}
+
+/* copied from kernel/time/hrtimeer.c */
+#if BITS_PER_LONG < 64
+/*
+ * Divide a ktime value by a nanosecond value
+ */
+u64 __ktime_divns(const ktime_t kt, s64 div)
+{
+ u64 dclc;
+ int sft = 0;
+
+ dclc = ktime_to_ns(kt);
+ /* Make sure the divisor is less than 2^32: */
+ while (div >> 32) {
+ sft++;
+ div >>= 1;
+ }
+ dclc >>= sft;
+ do_div(dclc, (unsigned long)div);
+
+ return dclc;
+}
+#endif /* BITS_PER_LONG >= 64 */
+
+void update_xtime_cache(u64 nsec)
+{
+}
+unsigned long get_seconds(void)
+{
+ u64 ns = lib_current_ns();
+
+ do_div(ns, 1000000000);
+ return ns;
+}
+static unsigned long
+round_jiffies_common(unsigned long j,
+ bool force_up)
+{
+ int rem;
+ unsigned long original = j;
+
+ rem = j % HZ;
+ if (rem < HZ / 4 && !force_up) /* round down */
+ j = j - rem;
+ else /* round up */
+ j = j - rem + HZ;
+ if (j <= jiffies) /* rounding ate our timeout entirely; */
+ return original;
+ return j;
+}
+unsigned long round_jiffies(unsigned long j)
+{
+ return round_jiffies_common(j, false);
+}
+unsigned long round_jiffies_relative(unsigned long j)
+{
+ unsigned long j0 = jiffies;
+
+ /* Use j0 because jiffies might change while we run */
+ return round_jiffies_common(j + j0, false) - j0;
+}
+unsigned long round_jiffies_up(unsigned long j)
+{
+ return round_jiffies_common(j, true);
+}
+static void msleep_trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+void msleep(unsigned int msecs)
+{
+ lib_event_schedule_ns(((__u64)msecs) * 1000000, &msleep_trampoline,
+ lib_task_current());
+ lib_task_wait();
+}
diff --git a/arch/lib/timer.c b/arch/lib/timer.c
new file mode 100644
index 0000000..87d2283
--- /dev/null
+++ b/arch/lib/timer.c
@@ -0,0 +1,238 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include "sim-assert.h"
+#include "sim.h"
+
+/**
+ * init_timer_key - initialize a timer
+ * @timer: the timer to be initialized
+ * @name: name of the timer
+ * @key: lockdep class key of the fake lock used for tracking timer
+ * sync lock dependencies
+ *
+ * init_timer_key() must be done to a timer prior calling *any* of the
+ * other timer functions.
+ */
+void init_timer_key(struct timer_list *timer,
+ unsigned int flags,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * Note: name and key are used for debugging. We ignore them
+ * unconditionally.
+ * Note: we do not initialize the lockdep map either because we
+ * don't care.
+ * and, finally, we never care about the base field either.
+ *
+ * So, for now, we have a timer which is marked as "not started"
+ * thanks to its entry.next field set to NULL (timer_pending
+ * will return 0)
+ */
+ timer->entry.next = NULL;
+ timer->base = 0;
+}
+
+struct list_head g_expired_events = LIST_HEAD_INIT(g_expired_events);
+struct list_head g_pending_events = LIST_HEAD_INIT(g_pending_events);
+
+static void run_timer_softirq(struct softirq_action *h)
+{
+ while (!list_empty(&g_expired_events)) {
+ struct timer_list *timer = list_first_entry(&g_expired_events,
+ struct timer_list,
+ entry);
+ void (*fn)(unsigned long);
+ unsigned long data;
+
+ fn = timer->function;
+ data = timer->data;
+ lib_assert(timer->base == 0);
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ fn(data);
+ }
+ }
+}
+
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
+}
+static void timer_trampoline(void *context)
+{
+ struct timer_list *timer;
+
+ ensure_softirq_opened();
+ timer = context;
+ timer->base = 0;
+ if (timer->entry.prev != LIST_POISON2)
+ list_del(&timer->entry);
+ list_add_tail(&timer->entry, &g_expired_events);
+ raise_softirq(TIMER_SOFTIRQ);
+}
+/**
+ * add_timer - start a timer
+ * @timer: the timer to be added
+ *
+ * The kernel will do a ->function(->data) callback from the
+ * timer interrupt at the ->expires point in the future. The
+ * current time is 'jiffies'.
+ *
+ * The timer's ->expires, ->function (and if the handler uses it, ->data)
+ * fields must be set prior calling this function.
+ *
+ * Timers with an ->expires field in the past will be executed in the next
+ * timer tick.
+ */
+void add_timer(struct timer_list *timer)
+{
+ __u64 delay_ns = 0;
+
+ lib_assert(!timer_pending(timer));
+ if (timer->expires <= jiffies)
+ delay_ns = (1000000000 / HZ); /* next tick. */
+ else
+ delay_ns =
+ ((__u64)timer->expires *
+ (1000000000 / HZ)) - lib_current_ns();
+ void *event = lib_event_schedule_ns(delay_ns, &timer_trampoline, timer);
+ /* store the external event in the base field */
+ /* to be able to retrieve it from del_timer */
+ timer->base = event;
+ /* finally, store timer in list of pending events. */
+ list_add_tail(&timer->entry, &g_pending_events);
+}
+/**
+ * del_timer - deactive a timer.
+ * @timer: the timer to be deactivated
+ *
+ * del_timer() deactivates a timer - this works on both active and inactive
+ * timers.
+ *
+ * The function returns whether it has deactivated a pending timer or not.
+ * (ie. del_timer() of an inactive timer returns 0, del_timer() of an
+ * active timer returns 1.)
+ */
+int del_timer(struct timer_list *timer)
+{
+ int retval;
+
+ if (timer->entry.next == 0)
+ return 0;
+ if (timer->base != 0) {
+ lib_event_cancel(timer->base);
+ retval = 1;
+ } else
+ retval = 0;
+ if (timer->entry.prev != LIST_POISON2) {
+ list_del(&timer->entry);
+ timer->entry.next = NULL;
+ }
+ return retval;
+}
+
+/* ////////////////////// */
+
+void init_timer_deferrable_key(struct timer_list *timer,
+ const char *name,
+ struct lock_class_key *key)
+{
+ /**
+ * From lwn.net:
+ * Timers which are initialized in this fashion will be
+ * recognized as deferrable by the kernel. They will not
+ * be considered when the kernel makes its "when should
+ * the next timer interrupt be?" decision. When the system
+ * is busy these timers will fire at the scheduled time. When
+ * things are idle, instead, they will simply wait until
+ * something more important wakes up the processor.
+ *
+ * Note: Our implementation of deferrable timers uses
+ * non-deferrable timers for simplicity.
+ */
+ init_timer_key(timer, 0, name, key);
+}
+/**
+ * add_timer_on - start a timer on a particular CPU
+ * @timer: the timer to be added
+ * @cpu: the CPU to start it on
+ *
+ * This is not very scalable on SMP. Double adds are not possible.
+ */
+void add_timer_on(struct timer_list *timer, int cpu)
+{
+ /* we ignore the cpu: we have only one. */
+ add_timer(timer);
+}
+/**
+ * mod_timer - modify a timer's timeout
+ * @timer: the timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer() is a more efficient way to update the expire field of an
+ * active timer (if the timer is inactive it will be activated)
+ *
+ * mod_timer(timer, expires) is equivalent to:
+ *
+ * del_timer(timer); timer->expires = expires; add_timer(timer);
+ *
+ * Note that if there are multiple unserialized concurrent users of the
+ * same timer, then mod_timer() is the only safe way to modify the timeout,
+ * since add_timer() cannot modify an already running timer.
+ *
+ * The function returns whether it has modified a pending timer or not.
+ * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an
+ * active timer returns 1.)
+ */
+int mod_timer(struct timer_list *timer, unsigned long expires)
+{
+ int ret;
+
+ /* common optimization stolen from kernel */
+ if (timer_pending(timer) && timer->expires == expires)
+ return 1;
+
+ ret = del_timer(timer);
+ timer->expires = expires;
+ add_timer(timer);
+ return ret;
+}
+/**
+ * mod_timer_pending - modify a pending timer's timeout
+ * @timer: the pending timer to be modified
+ * @expires: new timeout in jiffies
+ *
+ * mod_timer_pending() is the same for pending timers as mod_timer(),
+ * but will not re-activate and modify already deleted timers.
+ *
+ * It is useful for unserialized use of timers.
+ */
+int mod_timer_pending(struct timer_list *timer, unsigned long expires)
+{
+ if (timer_pending(timer))
+ return 0;
+ return mod_timer(timer, expires);
+}
+
+int mod_timer_pinned(struct timer_list *timer, unsigned long expires)
+{
+ if (timer->expires == expires && timer_pending(timer))
+ return 1;
+
+ return mod_timer(timer, expires);
+}
--
2.1.0
context primitives of kernel such as soft interrupts, scheduling,
tasklet are implemented for libos. these functions eventually call the
functions registered by lib_init() API as well.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sched.c | 406 +++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/softirq.c | 108 ++++++++++++++
arch/lib/tasklet.c | 76 ++++++++++
arch/lib/workqueue.c | 242 ++++++++++++++++++++++++++++++
4 files changed, 832 insertions(+)
create mode 100644 arch/lib/sched.c
create mode 100644 arch/lib/softirq.c
create mode 100644 arch/lib/tasklet.c
create mode 100644 arch/lib/workqueue.c
diff --git a/arch/lib/sched.c b/arch/lib/sched.c
new file mode 100644
index 0000000..98a568a
--- /dev/null
+++ b/arch/lib/sched.c
@@ -0,0 +1,406 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/nsproxy.h>
+#include <linux/hash.h>
+#include <net/net_namespace.h>
+#include "lib.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+/**
+ called by wait_event macro:
+ - prepare_to_wait
+ - schedule
+ - finish_wait
+ */
+
+struct SimTask *lib_task_create(void *private, unsigned long pid)
+{
+ struct SimTask *task = lib_malloc(sizeof(struct SimTask));
+ struct cred *cred;
+ struct nsproxy *ns;
+ struct user_struct *user;
+ struct thread_info *info;
+ struct pid *kpid;
+
+ if (!task)
+ return NULL;
+ memset(task, 0, sizeof(struct SimTask));
+ cred = lib_malloc(sizeof(struct cred));
+ if (!cred)
+ return NULL;
+ /* XXX: we could optimize away this allocation by sharing it
+ for all tasks */
+ ns = lib_malloc(sizeof(struct nsproxy));
+ if (!ns)
+ return NULL;
+ user = lib_malloc(sizeof(struct user_struct));
+ if (!user)
+ return NULL;
+ info = alloc_thread_info(&task->kernel_task);
+ if (!info)
+ return NULL;
+ kpid = lib_malloc(sizeof(struct pid));
+ if (!kpid)
+ return NULL;
+ kpid->numbers[0].nr = pid;
+ cred->fsuid = make_kuid(current_user_ns(), 0);
+ cred->fsgid = make_kgid(current_user_ns(), 0);
+ cred->user = user;
+ atomic_set(&cred->usage, 1);
+ info->task = &task->kernel_task;
+ info->preempt_count = 0;
+ info->flags = 0;
+ atomic_set(&ns->count, 1);
+ ns->uts_ns = 0;
+ ns->ipc_ns = 0;
+ ns->mnt_ns = 0;
+ ns->pid_ns_for_children = 0;
+ ns->net_ns = &init_net;
+ task->kernel_task.cred = cred;
+ task->kernel_task.pid = pid;
+ task->kernel_task.pids[PIDTYPE_PID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_PGID].pid = kpid;
+ task->kernel_task.pids[PIDTYPE_SID].pid = kpid;
+ task->kernel_task.nsproxy = ns;
+ task->kernel_task.stack = info;
+ /* this is a hack. */
+ task->kernel_task.group_leader = &task->kernel_task;
+ task->private = private;
+ return task;
+}
+void lib_task_destroy(struct SimTask *task)
+{
+ lib_free((void *)task->kernel_task.nsproxy);
+ lib_free((void *)task->kernel_task.cred);
+ lib_free((void *)task->kernel_task.cred->user);
+ free_thread_info(task->kernel_task.stack);
+ lib_free(task);
+}
+void *lib_task_get_private(struct SimTask *task)
+{
+ return task->private;
+}
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
+{
+ struct SimTask *task = lib_task_start((void (*)(void *))fn, arg);
+
+ return task->kernel_task.pid;
+}
+
+struct task_struct *get_current(void)
+{
+ struct SimTask *lib_task = lib_task_current();
+
+ return &lib_task->kernel_task;
+}
+
+struct thread_info *current_thread_info(void)
+{
+ return task_thread_info(get_current());
+}
+struct thread_info *alloc_thread_info(struct task_struct *task)
+{
+ return lib_malloc(sizeof(struct thread_info));
+}
+void free_thread_info(struct thread_info *ti)
+{
+ lib_free(ti);
+}
+
+
+void __put_task_struct(struct task_struct *t)
+{
+ lib_free(t);
+}
+
+void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ list_add(&wait->task_list, &q->task_list);
+}
+void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait->task_list, &q->task_list);
+}
+void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ if (wait->task_list.prev != LIST_POISON2)
+ list_del(&wait->task_list);
+}
+void
+prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ wait->flags |= WQ_FLAG_EXCLUSIVE;
+ if (list_empty(&wait->task_list))
+ list_add_tail(&wait->task_list, &q->task_list);
+ set_current_state(state);
+}
+void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
+{
+ unsigned long flags;
+
+ wait->flags &= ~WQ_FLAG_EXCLUSIVE;
+ spin_lock_irqsave(&q->lock, flags);
+ if (list_empty(&wait->task_list))
+ __add_wait_queue(q, wait);
+ set_current_state(state);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+void finish_wait(wait_queue_head_t *q, wait_queue_t *wait)
+{
+ set_current_state(TASK_RUNNING);
+ if (!list_empty(&wait->task_list))
+ list_del_init(&wait->task_list);
+}
+int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync,
+ void *key)
+{
+ int ret = default_wake_function(wait, mode, sync, key);
+
+ if (ret && (wait->task_list.prev != LIST_POISON2))
+ list_del_init(&wait->task_list);
+
+ return ret;
+}
+
+int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ wait->flags |= WQ_FLAG_WOKEN;
+ return default_wake_function(wait, mode, sync, key);
+}
+
+void __init_waitqueue_head(wait_queue_head_t *q, const char *name,
+ struct lock_class_key *k)
+{
+ INIT_LIST_HEAD(&q->task_list);
+}
+/**
+ * wait_for_completion: - waits for completion of a task
+ * @x: holds the state of this particular completion
+ *
+ * This waits to be signaled for completion of a specific task. It is NOT
+ * interruptible and there is no timeout.
+ *
+ * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
+ * and interrupt capability. Also see complete().
+ */
+void wait_for_completion(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+}
+unsigned long wait_for_completion_timeout(struct completion *x,
+ unsigned long timeout)
+{
+ if (!x->done) {
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ wait.flags |= WQ_FLAG_EXCLUSIVE;
+ list_add_tail(&wait.task_list, &x->wait.task_list);
+ do
+ timeout = schedule_timeout(timeout);
+ while (!x->done && timeout);
+ if (wait.task_list.prev != LIST_POISON2)
+ list_del(&wait.task_list);
+
+ if (!x->done)
+ return timeout;
+ }
+ x->done--;
+ return timeout ? : 1;
+}
+
+/**
+ * __wake_up - wake up threads blocked on a waitqueue.
+ * @q: the waitqueue
+ * @mode: which threads
+ * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ * @key: is directly passed to the wakeup function
+ *
+ * It may be assumed that this function implies a write memory barrier before
+ * changing the task state if and only if any tasks are woken up.
+ */
+void __wake_up(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ wait_queue_t *curr, *next;
+
+ list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
+ unsigned flags = curr->flags;
+
+ if (curr->func(curr, mode, 0, key) &&
+ (flags & WQ_FLAG_EXCLUSIVE) &&
+ !--nr_exclusive)
+ break;
+ }
+}
+void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode,
+ int nr_exclusive, void *key)
+{
+ __wake_up(q, mode, nr_exclusive, key);
+}
+int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
+ void *key)
+{
+ struct task_struct *task = (struct task_struct *)curr->private;
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+__sched int bit_wait(struct wait_bit_key *word)
+{
+ if (signal_pending_state(current->state, current))
+ return 1;
+ schedule();
+ return 0;
+}
+int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
+{
+ struct wait_bit_key *key = arg;
+ struct wait_bit_queue *wait_bit
+ = container_of(wait, struct wait_bit_queue, wait);
+
+ if (wait_bit->key.flags != key->flags ||
+ wait_bit->key.bit_nr != key->bit_nr ||
+ test_bit(key->bit_nr, key->flags))
+ return 0;
+ else
+ return autoremove_wake_function(wait, mode, sync, key);
+}
+void __wake_up_bit(wait_queue_head_t *wq, void *word, int bit)
+{
+ struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit);
+ if (waitqueue_active(wq))
+ __wake_up(wq, TASK_NORMAL, 1, &key);
+}
+void wake_up_bit(void *word, int bit)
+{
+ /* FIXME */
+ return;
+ __wake_up_bit(bit_waitqueue(word, bit), word, bit);
+}
+wait_queue_head_t *bit_waitqueue(void *word, int bit)
+{
+ const int shift = BITS_PER_LONG == 32 ? 5 : 6;
+ const struct zone *zone = page_zone(virt_to_page(word));
+ unsigned long val = (unsigned long)word << shift | bit;
+
+ return &zone->wait_table[hash_long(val, zone->wait_table_bits)];
+}
+
+
+void schedule(void)
+{
+ lib_task_wait();
+}
+
+static void trampoline(void *context)
+{
+ struct SimTask *task = context;
+
+ lib_task_wakeup(task);
+}
+
+signed long schedule_timeout(signed long timeout)
+{
+ u64 ns;
+ struct SimTask *self;
+
+ if (timeout == MAX_SCHEDULE_TIMEOUT) {
+ lib_task_wait();
+ return MAX_SCHEDULE_TIMEOUT;
+ }
+ lib_assert(timeout >= 0);
+ ns = ((__u64)timeout) * (1000000000 / HZ);
+ self = lib_task_current();
+ lib_event_schedule_ns(ns, &trampoline, self);
+ lib_task_wait();
+ /* we know that we are always perfectly on time. */
+ return 0;
+}
+
+signed long schedule_timeout_uninterruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+signed long schedule_timeout_interruptible(signed long timeout)
+{
+ return schedule_timeout(timeout);
+}
+
+void yield(void)
+{
+ lib_task_yield();
+}
+
+void complete_all(struct completion *x)
+{
+ x->done += UINT_MAX / 2;
+ __wake_up(&x->wait, TASK_NORMAL, 0, 0);
+}
+void complete(struct completion *x)
+{
+ x->done++;
+ __wake_up(&x->wait, TASK_NORMAL, 1, 0);
+}
+
+long wait_for_completion_interruptible_timeout(
+ struct completion *x, unsigned long timeout)
+{
+ return wait_for_completion_timeout(x, timeout);
+}
+int wait_for_completion_interruptible(struct completion *x)
+{
+ wait_for_completion_timeout(x, MAX_SCHEDULE_TIMEOUT);
+ return 0;
+}
+int wake_up_process(struct task_struct *tsk)
+{
+ struct SimTask *lib_task =
+ container_of(tsk, struct SimTask, kernel_task);
+
+ return lib_task_wakeup(lib_task);
+}
+int _cond_resched(void)
+{
+ /* we never schedule to decrease latency. */
+ return 0;
+}
+int idle_cpu(int cpu)
+{
+ /* we are never idle: we call this from rcutiny.c and the answer */
+ /* does not matter, really. */
+ return 0;
+}
+
+unsigned long long __attribute__((weak)) sched_clock(void)
+{
+ return (unsigned long long)(jiffies - INITIAL_JIFFIES)
+ * (NSEC_PER_SEC / HZ);
+}
+
+u64 local_clock(void)
+{
+ return sched_clock();
+}
+
+void __sched schedule_preempt_disabled(void)
+{
+}
+
+void resched_cpu(int cpu)
+{
+ rcu_sched_qs();
+}
diff --git a/arch/lib/softirq.c b/arch/lib/softirq.c
new file mode 100644
index 0000000..3f6363a
--- /dev/null
+++ b/arch/lib/softirq.c
@@ -0,0 +1,108 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim-init.h"
+#include "sim.h"
+#include "sim-assert.h"
+
+
+static struct softirq_action softirq_vec[NR_SOFTIRQS];
+static struct SimTask *g_softirq_task = 0;
+static int g_n_raises = 0;
+
+void lib_softirq_wakeup(void)
+{
+ g_n_raises++;
+ lib_task_wakeup(g_softirq_task);
+}
+
+static void softirq_task_function(void *context)
+{
+ while (true) {
+ do_softirq();
+ g_n_raises--;
+ if (g_n_raises == 0 || local_softirq_pending() == 0) {
+ g_n_raises = 0;
+ lib_task_wait();
+ }
+ }
+}
+
+static void ensure_task_created(void)
+{
+ if (g_softirq_task != 0)
+ return;
+ g_softirq_task = lib_task_start(&softirq_task_function, 0);
+}
+
+void open_softirq(int nr, void (*action)(struct softirq_action *))
+{
+ ensure_task_created();
+ softirq_vec[nr].action = action;
+}
+#define MAX_SOFTIRQ_RESTART 10
+
+void do_softirq(void)
+{
+ __u32 pending;
+ int max_restart = MAX_SOFTIRQ_RESTART;
+ struct softirq_action *h;
+
+ pending = local_softirq_pending();
+
+restart:
+ /* Reset the pending bitmask before enabling irqs */
+ set_softirq_pending(0);
+
+ local_irq_enable();
+
+ h = softirq_vec;
+
+ do {
+ if (pending & 1)
+ h->action(h);
+ h++;
+ pending >>= 1;
+ } while (pending);
+
+ local_irq_disable();
+
+ pending = local_softirq_pending();
+ if (pending && --max_restart)
+ goto restart;
+}
+void raise_softirq_irqoff(unsigned int nr)
+{
+ __raise_softirq_irqoff(nr);
+
+ lib_softirq_wakeup();
+}
+void __raise_softirq_irqoff(unsigned int nr)
+{
+ /* trace_softirq_raise(nr); */
+ or_softirq_pending(1UL << nr);
+}
+int __cond_resched_softirq(void)
+{
+ /* tell the caller that we did not need to re-schedule. */
+ return 0;
+}
+void raise_softirq(unsigned int nr)
+{
+ /* copy/paste from kernel/softirq.c */
+ unsigned long flags;
+
+ local_irq_save(flags);
+ raise_softirq_irqoff(nr);
+ local_irq_restore(flags);
+}
+
+void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
+{
+}
diff --git a/arch/lib/tasklet.c b/arch/lib/tasklet.c
new file mode 100644
index 0000000..6cc68f4
--- /dev/null
+++ b/arch/lib/tasklet.c
@@ -0,0 +1,76 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/interrupt.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void tasklet_init(struct tasklet_struct *t,
+ void (*func)(unsigned long), unsigned long data)
+{
+ t->next = NULL;
+ t->state = 0;
+ atomic_set(&t->count, 0);
+ t->func = func;
+ t->data = data;
+}
+
+void tasklet_kill(struct tasklet_struct *t)
+{
+ /* theoretically, called from user context */
+ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
+ do
+ lib_task_yield();
+ while (test_bit(TASKLET_STATE_SCHED, &t->state));
+ }
+ clear_bit(TASKLET_STATE_SCHED, &t->state);
+}
+struct tasklet_struct *g_sched_events = NULL;
+static void run_tasklet_softirq(struct softirq_action *h)
+{
+ /* while (!list_empty (&g_sched_events)) */
+ /* { */
+ struct tasklet_struct *tasklet = g_sched_events;
+
+ if (atomic_read(&tasklet->count) == 0) {
+ /* this tasklet is enabled so, we run it. */
+ test_and_clear_bit(TASKLET_STATE_SCHED, &tasklet->state);
+ tasklet->func(tasklet->data);
+ }
+ /* } */
+}
+static void ensure_softirq_opened(void)
+{
+ static bool opened = false;
+
+ if (opened)
+ return;
+ opened = true;
+ open_softirq(TASKLET_SOFTIRQ, run_tasklet_softirq);
+}
+static void trampoline(void *context)
+{
+ ensure_softirq_opened();
+ struct tasklet_struct *tasklet = context;
+ /* allow the tasklet to re-schedule itself */
+ lib_assert(tasklet->next != 0);
+ tasklet->next = 0;
+ g_sched_events = tasklet;
+ raise_softirq(TASKLET_SOFTIRQ);
+}
+void __tasklet_schedule(struct tasklet_struct *t)
+{
+ void *event;
+
+ /* Note: no need to set TASKLET_STATE_SCHED because
+ it is set by caller. */
+ lib_assert(t->next == 0);
+ /* run the tasklet at the next immediately available opportunity. */
+ event = lib_event_schedule_ns(0, &trampoline, t);
+ t->next = event;
+}
diff --git a/arch/lib/workqueue.c b/arch/lib/workqueue.c
new file mode 100644
index 0000000..bd0e9c5
--- /dev/null
+++ b/arch/lib/workqueue.c
@@ -0,0 +1,242 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+/* copy from kernel/workqueue.c */
+typedef unsigned long mayday_mask_t;
+struct workqueue_struct {
+ unsigned int flags; /* W: WQ_* flags */
+ union {
+ struct cpu_workqueue_struct __percpu *pcpu;
+ struct cpu_workqueue_struct *single;
+ unsigned long v;
+ } cpu_wq; /* I: cwq's */
+ struct list_head list; /* W: list of all workqueues */
+
+ struct mutex flush_mutex; /* protects wq flushing */
+ int work_color; /* F: current work color */
+ int flush_color; /* F: current flush color */
+ atomic_t nr_cwqs_to_flush; /* flush in progress */
+ struct wq_flusher *first_flusher; /* F: first flusher */
+ struct list_head flusher_queue; /* F: flush waiters */
+ struct list_head flusher_overflow; /* F: flush overflow list */
+
+ mayday_mask_t mayday_mask; /* cpus requesting rescue */
+ struct worker *rescuer; /* I: rescue worker */
+
+ int nr_drainers; /* W: drain in progress */
+ int saved_max_active; /* W: saved cwq max_active */
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map lockdep_map;
+#endif
+ char name[]; /* I: workqueue name */
+};
+
+struct wq_barrier {
+ struct SimTask *waiter;
+ struct workqueue_struct wq;
+};
+
+static void
+workqueue_function(void *context)
+{
+ struct workqueue_struct *wq = context;
+
+ while (true) {
+ lib_task_wait();
+ while (!list_empty(&wq->list)) {
+ struct work_struct *work =
+ list_first_entry(&wq->list, struct work_struct,
+ entry);
+ work_func_t f = work->func;
+
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ f(work);
+ }
+ }
+ }
+}
+
+static struct SimTask *workqueue_task(struct workqueue_struct *wq)
+{
+ struct wq_barrier *barr = container_of(wq, struct wq_barrier, wq);
+
+ if (barr->waiter == 0)
+ barr->waiter = lib_task_start(&workqueue_function, wq);
+ return barr->waiter;
+}
+
+static int flush_entry(struct workqueue_struct *wq, struct list_head *prev)
+{
+ int active = 0;
+
+ if (!list_empty(&wq->list)) {
+ active = 1;
+ lib_task_wakeup(workqueue_task(wq));
+ /* XXX: should wait for completion? but this will block
+ and init won't return.. */
+ /* lib_task_wait (); */
+ }
+
+ return active;
+}
+
+void delayed_work_timer_fn(unsigned long data)
+{
+ struct delayed_work *dwork = (struct delayed_work *)data;
+ struct work_struct *work = &dwork->work;
+
+ list_add_tail(&work->entry, &dwork->wq->list);
+ lib_task_wakeup(workqueue_task(dwork->wq));
+}
+
+bool queue_work_on(int cpu, struct workqueue_struct *wq,
+ struct work_struct *work)
+{
+ int ret = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ list_add_tail(&work->entry, &wq->list);
+ lib_task_wakeup(workqueue_task(wq));
+ ret = 1;
+ }
+ return ret;
+}
+
+void flush_scheduled_work(void)
+{
+ flush_entry(system_wq, system_wq->list.prev);
+}
+bool flush_work(struct work_struct *work)
+{
+ return flush_entry(system_wq, &work->entry);
+}
+void flush_workqueue(struct workqueue_struct *wq)
+{
+ flush_entry(wq, wq->list.prev);
+}
+bool cancel_work_sync(struct work_struct *work)
+{
+ int retval = 0;
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)))
+ /* work was not yet queued */
+ return 0;
+ if (!list_empty(&work->entry)) {
+ /* work was queued. now unqueued. */
+ if (work->entry.prev != LIST_POISON2) {
+ list_del_init(&work->entry);
+ clear_bit(WORK_STRUCT_PENDING_BIT,
+ work_data_bits(work));
+ retval = 1;
+ }
+ }
+ return retval;
+}
+bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ int ret = 0;
+ struct timer_list *timer = &dwork->timer;
+ struct work_struct *work = &dwork->work;
+
+ if (delay == 0)
+ return queue_work(wq, work);
+
+ if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+ lib_assert(!timer_pending(timer));
+ dwork->wq = wq;
+ /* This stores cwq for the moment, for the timer_fn */
+ timer->expires = jiffies + delay;
+ timer->data = (unsigned long)dwork;
+ timer->function = delayed_work_timer_fn;
+ add_timer(timer);
+ ret = 1;
+ }
+ return ret;
+}
+bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
+ struct delayed_work *dwork, unsigned long delay)
+{
+ del_timer(&dwork->timer);
+ __clear_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&dwork->work));
+ return queue_delayed_work(wq, dwork, delay);
+}
+bool cancel_delayed_work(struct delayed_work *dwork)
+{
+ del_timer(&dwork->timer);
+ return cancel_work_sync(&dwork->work);
+}
+
+struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
+ unsigned int flags,
+ int max_active,
+ struct lock_class_key *key,
+ const char *lock_name, ...)
+{
+ va_list args, args1;
+ struct wq_barrier *barr;
+ struct workqueue_struct *wq;
+ size_t namelen;
+
+ /* determine namelen, allocate wq and format name */
+ va_start(args, lock_name);
+ va_copy(args1, args);
+ namelen = vsnprintf(NULL, 0, fmt, args) + 1;
+
+ barr = kzalloc(sizeof(*barr) + namelen, GFP_KERNEL);
+ if (!barr)
+ goto err;
+ barr->waiter = 0;
+ wq = &barr->wq;
+
+ vsnprintf(wq->name, namelen, fmt, args1);
+ va_end(args);
+ va_end(args1);
+
+ max_active = max_active ? : WQ_DFL_ACTIVE;
+ /* init wq */
+ wq->flags = flags;
+ wq->saved_max_active = max_active;
+ mutex_init(&wq->flush_mutex);
+ atomic_set(&wq->nr_cwqs_to_flush, 0);
+ INIT_LIST_HEAD(&wq->flusher_queue);
+ INIT_LIST_HEAD(&wq->flusher_overflow);
+
+ lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
+ INIT_LIST_HEAD(&wq->list);
+
+ /* start waiter task */
+ workqueue_task(wq);
+ return wq;
+err:
+ if (barr)
+ kfree(barr);
+ return NULL;
+}
+
+struct workqueue_struct *system_wq __read_mostly;
+struct workqueue_struct *system_power_efficient_wq __read_mostly;
+/* from linux/workqueue.h */
+#define system_nrt_wq __system_nrt_wq()
+
+static int __init init_workqueues(void)
+{
+ system_wq = alloc_workqueue("events", 0, 0);
+ system_power_efficient_wq = alloc_workqueue("events_power_efficient",
+ WQ_POWER_EFFICIENT, 0);
+ return 0;
+}
+early_initcall(init_workqueues);
--
2.1.0
This interacts with fs/proc_fs.c for sysctl-like interface registered via
lib_init() API.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/sysctl.c | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 270 insertions(+)
create mode 100644 arch/lib/sysctl.c
diff --git a/arch/lib/sysctl.c b/arch/lib/sysctl.c
new file mode 100644
index 0000000..5f08f9f
--- /dev/null
+++ b/arch/lib/sysctl.c
@@ -0,0 +1,270 @@
+/*
+ * sysctl wrapper for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/mman.h>
+#include <linux/ratelimit.h>
+#include <linux/proc_fs.h>
+#include "sim-assert.h"
+#include "sim-types.h"
+
+int drop_caches_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_background_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_ratio_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_bytes_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int dirty_writeback_centisecs_handler(struct ctl_table *table, int write,
+ void *buffer, size_t *length,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int scan_unevictable_handler(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *length, loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+int sched_rt_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ lib_assert(false);
+ return 0;
+}
+
+int sysctl_overcommit_memory = OVERCOMMIT_GUESS;
+int sysctl_overcommit_ratio = 50;
+int sysctl_panic_on_oom = 0;
+int sysctl_oom_dump_tasks = 0;
+int sysctl_oom_kill_allocating_task = 0;
+int sysctl_nr_trim_pages = 0;
+int sysctl_drop_caches = 0;
+int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES - 1] = { 32 };
+unsigned int sysctl_sched_child_runs_first = 0;
+unsigned int sysctl_sched_compat_yield = 0;
+unsigned int sysctl_sched_rt_period = 1000000;
+int sysctl_sched_rt_runtime = 950000;
+
+int vm_highmem_is_dirtyable;
+unsigned long vm_dirty_bytes = 0;
+int vm_dirty_ratio = 20;
+int dirty_background_ratio = 10;
+unsigned int dirty_expire_interval = 30 * 100;
+unsigned int dirty_writeback_interval = 5 * 100;
+unsigned long dirty_background_bytes = 0;
+int percpu_pagelist_fraction = 0;
+int panic_timeout = 0;
+int panic_on_oops = 0;
+int printk_delay_msec = 0;
+int panic_on_warn = 0;
+DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10);
+
+#define RESERVED_PIDS 300
+int pid_max = PID_MAX_DEFAULT;
+int pid_max_min = RESERVED_PIDS + 1;
+int pid_max_max = PID_MAX_LIMIT;
+int min_free_kbytes = 1024;
+int max_threads = 100;
+int laptop_mode = 0;
+
+#define DEFAULT_MESSAGE_LOGLEVEL 4
+#define MINIMUM_CONSOLE_LOGLEVEL 1
+#define DEFAULT_CONSOLE_LOGLEVEL 7
+int console_printk[4] = {
+ DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */
+ DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */
+ MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */
+ DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */
+};
+
+int print_fatal_signals = 0;
+unsigned int core_pipe_limit = 0;
+int core_uses_pid = 0;
+int vm_swappiness = 60;
+int nr_pdflush_threads = 0;
+unsigned long scan_unevictable_pages = 0;
+int suid_dumpable = 0;
+int page_cluster = 0;
+int block_dump = 0;
+int C_A_D = 0;
+#include <linux/nsproxy.h>
+struct nsproxy init_nsproxy;
+#include <linux/reboot.h>
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */
+unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */
+
+int pdflush_proc_obsolete(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return nr_pdflush_threads;
+}
+#include <linux/fs.h>
+
+/**
+ * Honestly, I don't understand half of that code.
+ * It was modeled after fs/proc/proc_sysctl.c proc_sys_readdir
+ *
+ * Me either ;) (Hajime, Jan 2013)
+ */
+
+/* from proc_sysctl.c (XXX) */
+extern struct ctl_table_root sysctl_table_root;
+void ctl_table_first_entry(struct ctl_dir *dir,
+ struct ctl_table_header **phead, struct ctl_table **pentry);
+void ctl_table_next_entry(struct ctl_table_header **phead, struct ctl_table **pentry);
+struct ctl_table *ctl_table_find_entry(struct ctl_table_header **phead,
+ struct ctl_dir *dir, const char *name,
+ int namelen);
+struct ctl_dir *ctl_table_xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir);
+/* for init_net (XXX, should be fixed) */
+#include <net/net_namespace.h>
+
+static void iterate_table_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table *entry;
+
+ for (entry = head->ctl_table; entry->procname; entry++) {
+ bool may_read = (head->ctl_table->mode & MAY_READ);
+ bool may_write = (head->ctl_table->mode & MAY_WRITE);
+ int flags = 0;
+
+ flags |= may_read ? SIM_SYS_FILE_READ : 0;
+ flags |= may_write ? SIM_SYS_FILE_WRITE : 0;
+ iter->report_file(iter, entry->procname, flags,
+ (struct SimSysFile *)entry);
+ }
+}
+
+
+static void iterate_recursive(const struct SimSysIterator *iter,
+ struct ctl_table_header *head)
+{
+ struct ctl_table_header *h = NULL;
+ struct ctl_table *entry;
+ struct ctl_dir *ctl_dir;
+
+ ctl_dir = container_of(head, struct ctl_dir, header);
+ for (ctl_table_first_entry(ctl_dir, &h, &entry); h;
+ ctl_table_next_entry(&h, &entry)) {
+ struct ctl_dir *dir;
+ int ret;
+ const char *procname;
+
+ /* copy from sysctl_follow_link () */
+ if (S_ISLNK(entry->mode)) {
+ dir = ctl_table_xlate_dir(&init_net.sysctls, h->parent);
+ if (IS_ERR(dir)) {
+ ret = PTR_ERR(dir);
+ lib_assert(false);
+ } else {
+ procname = entry->procname;
+ h = NULL;
+ entry =
+ ctl_table_find_entry(&h, dir, procname,
+ strlen(procname));
+ ret = -ENOENT;
+ }
+ }
+
+ if (S_ISDIR(entry->mode)) {
+ iter->report_start_dir(iter, entry->procname);
+ iterate_recursive(iter, h);
+ iter->report_end_dir(iter);
+ } else
+ iterate_table_recursive(iter, h);
+ }
+
+}
+
+
+void lib_sys_iterate_files(const struct SimSysIterator *iter)
+{
+ struct ctl_table_header *root =
+ &sysctl_table_root.default_set.dir.header;
+
+ iterate_recursive(iter, root);
+}
+
+int lib_sys_file_read(const struct SimSysFile *file, char *buffer, int size,
+ int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 0, buffer, &result, &ppos);
+ return result;
+}
+int lib_sys_file_write(const struct SimSysFile *file, const char *buffer,
+ int size, int offset)
+{
+ struct ctl_table *table = (struct ctl_table *)file;
+ loff_t ppos = offset;
+ size_t result = size;
+ int error;
+
+ error = table->proc_handler(table, 1, (char *)buffer, &result, &ppos);
+ return result;
+}
--
2.1.0
These files are used to provide the same function calls so that other
network stack code keeps untouched.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Christoph Paasch <[email protected]>
---
arch/lib/capability.c | 25 +++++
arch/lib/filemap.c | 32 ++++++
arch/lib/fs.c | 70 ++++++++++++
arch/lib/glue.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++
arch/lib/modules.c | 36 +++++++
arch/lib/pid.c | 29 +++++
arch/lib/print.c | 56 ++++++++++
arch/lib/proc.c | 34 ++++++
arch/lib/random.c | 53 +++++++++
arch/lib/sysfs.c | 83 +++++++++++++++
arch/lib/vmscan.c | 26 +++++
11 files changed, 733 insertions(+)
create mode 100644 arch/lib/capability.c
create mode 100644 arch/lib/filemap.c
create mode 100644 arch/lib/fs.c
create mode 100644 arch/lib/glue.c
create mode 100644 arch/lib/modules.c
create mode 100644 arch/lib/pid.c
create mode 100644 arch/lib/print.c
create mode 100644 arch/lib/proc.c
create mode 100644 arch/lib/random.c
create mode 100644 arch/lib/sysfs.c
create mode 100644 arch/lib/vmscan.c
diff --git a/arch/lib/capability.c b/arch/lib/capability.c
new file mode 100644
index 0000000..3a1f301
--- /dev/null
+++ b/arch/lib/capability.c
@@ -0,0 +1,25 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "linux/capability.h"
+
+struct sock;
+struct sk_buff;
+
+int file_caps_enabled = 0;
+
+int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+ return 0;
+}
+
+bool file_ns_capable(const struct file *file, struct user_namespace *ns,
+ int cap)
+{
+ return true;
+}
diff --git a/arch/lib/filemap.c b/arch/lib/filemap.c
new file mode 100644
index 0000000..ce424ff
--- /dev/null
+++ b/arch/lib/filemap.c
@@ -0,0 +1,32 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim.h"
+#include "sim-assert.h"
+#include <linux/fs.h>
+
+
+ssize_t generic_file_aio_read(struct kiocb *a, const struct iovec *b,
+ unsigned long c, loff_t d)
+{
+ lib_assert(false);
+
+ return 0;
+}
+
+int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return -ENOSYS;
+}
+
+ssize_t
+generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
+{
+ return 0;
+}
diff --git a/arch/lib/fs.c b/arch/lib/fs.c
new file mode 100644
index 0000000..33efe5f
--- /dev/null
+++ b/arch/lib/fs.c
@@ -0,0 +1,70 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <fs/mount.h>
+
+#include "sim-assert.h"
+
+__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock);
+unsigned int dirtytime_expire_interval;
+
+void __init mnt_init(void)
+{
+}
+
+/* Implementation taken from vfs_kern_mount from linux/namespace.c */
+struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
+{
+ static struct mount local_mnt;
+ static int count = 0;
+ struct mount *mnt = &local_mnt;
+ struct dentry *root = 0;
+
+ /* XXX */
+ if (count != 0) return &local_mnt.mnt;
+ count++;
+
+ memset(mnt, 0, sizeof(struct mount));
+ if (!type)
+ return ERR_PTR(-ENODEV);
+ int flags = MS_KERNMOUNT;
+ char *name = (char *)type->name;
+
+ if (flags & MS_KERNMOUNT)
+ mnt->mnt.mnt_flags = MNT_INTERNAL;
+
+ root = type->mount(type, flags, name, data);
+ if (IS_ERR(root))
+ return ERR_CAST(root);
+
+ mnt->mnt.mnt_root = root;
+ mnt->mnt.mnt_sb = root->d_sb;
+ mnt->mnt_mountpoint = mnt->mnt.mnt_root;
+ mnt->mnt_parent = mnt;
+ /* DCE is monothreaded , so we do not care of lock here */
+ list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
+
+ return &mnt->mnt;
+}
+void inode_wait_for_writeback(struct inode *inode)
+{
+}
+void truncate_inode_pages_final(struct address_space *mapping)
+{
+}
+int dirtytime_interval_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
+
+unsigned int nr_free_buffer_pages(void)
+{
+ return 65535;
+}
diff --git a/arch/lib/glue.c b/arch/lib/glue.c
new file mode 100644
index 0000000..93f72d1
--- /dev/null
+++ b/arch/lib/glue.c
@@ -0,0 +1,289 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include <linux/types.h> /* loff_t */
+#include <linux/errno.h> /* ESPIPE */
+#include <linux/pagemap.h> /* PAGE_CACHE_SIZE */
+#include <linux/limits.h> /* NAME_MAX */
+#include <linux/statfs.h> /* struct kstatfs */
+#include <linux/bootmem.h> /* HASHDIST_DEFAULT */
+#include <linux/utsname.h>
+#include <linux/binfmts.h>
+#include <linux/init_task.h>
+#include <linux/sched/rt.h>
+#include <linux/backing-dev.h>
+#include <stdarg.h>
+#include "sim-assert.h"
+#include "sim.h"
+#include "lib.h"
+
+
+struct pipe_buffer;
+struct file;
+struct pipe_inode_info;
+struct wait_queue_t;
+struct kernel_param;
+struct super_block;
+struct tvec_base {};
+
+/* defined in sched.c, used in net/sched/em_meta.c */
+unsigned long avenrun[3];
+/* defined in mm/page_alloc.c, used in net/xfrm/xfrm_hash.c */
+int hashdist = HASHDIST_DEFAULT;
+/* defined in mm/page_alloc.c */
+struct pglist_data __refdata contig_page_data;
+/* defined in linux/mmzone.h mm/memory.c */
+struct page *mem_map = 0;
+/* used during boot. */
+struct tvec_base boot_tvec_bases;
+/* used by sysinfo in kernel/timer.c */
+int nr_threads = 0;
+/* not very useful in mm/vmstat.c */
+atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];
+
+/* XXX: used in network stack ! */
+unsigned long num_physpages = 0;
+unsigned long totalram_pages = 0;
+
+/* XXX figure out initial value */
+unsigned int interrupt_pending = 0;
+static unsigned long g_irqflags = 0;
+static unsigned long local_irqflags = 0;
+int overflowgid = 0;
+int overflowuid = 0;
+int fs_overflowgid = 0;
+int fs_overflowuid = 0;
+unsigned long sysctl_overcommit_kbytes __read_mostly;
+DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
+static DECLARE_BITMAP(cpu_possible_bits, CONFIG_NR_CPUS) __read_mostly;
+const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
+
+struct backing_dev_info noop_backing_dev_info = {
+ .name = "noop",
+ .capabilities = 0,
+};
+
+/* from rt.c */
+int sched_rr_timeslice = RR_TIMESLICE;
+/* from main.c */
+bool initcall_debug;
+bool static_key_initialized __read_mostly = false;
+unsigned long __start_rodata, __end_rodata;
+
+unsigned long arch_local_save_flags(void)
+{
+ return local_irqflags;
+}
+void arch_local_irq_restore(unsigned long flags)
+{
+ local_irqflags = flags;
+}
+
+
+unsigned long long nr_context_switches(void)
+{
+ /* we just need to return >0 to avoid the warning
+ in kernel/rcupdate.c */
+ return 1;
+}
+
+
+long get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+ unsigned long start, unsigned long nr_pages,
+ int write, int force, struct page **pages,
+ struct vm_area_struct **vmas)
+{
+ /* in practice, this function is never called. It's linked in because */
+ /* we link in get_user_pages_fast which is included only because it */
+ /* is located in mm/util.c */
+ lib_assert(false);
+ return 0;
+}
+
+
+void dump_stack(void)
+{
+ /* we assert to make sure that we catch whoever calls dump_stack */
+ lib_assert(false);
+}
+
+
+void lib_printf(const char *str, ...)
+{
+ va_list args;
+
+ va_start(args, str);
+ lib_vprintf(str, args);
+ va_end(args);
+}
+
+#include <linux/vmalloc.h>
+#include <linux/kmemleak.h>
+
+static unsigned long __meminitdata nr_kernel_pages = 8192;
+static unsigned long __meminitdata nr_all_pages = 81920;
+/*
+ * allocate a large system hash table from bootmem
+ * - it is assumed that the hash table must contain an exact power-of-2
+ * quantity of entries
+ * - limit is the number of hash buckets, not the total allocation size
+ */
+void *__init alloc_large_system_hash(const char *tablename,
+ unsigned long bucketsize,
+ unsigned long numentries,
+ int scale,
+ int flags,
+ unsigned int *_hash_shift,
+ unsigned int *_hash_mask,
+ unsigned long low_limit,
+ unsigned long high_limit)
+{
+ unsigned long long max = high_limit;
+ unsigned long log2qty, size;
+ void *table = NULL;
+
+ /* allow the kernel cmdline to have a say */
+ if (!numentries) {
+ /* round applicable memory size up to nearest megabyte */
+ numentries = nr_kernel_pages;
+ numentries += (1UL << (20 - PAGE_SHIFT)) - 1;
+ numentries >>= 20 - PAGE_SHIFT;
+ numentries <<= 20 - PAGE_SHIFT;
+
+ /* limit to 1 bucket per 2^scale bytes of low memory */
+ if (scale > PAGE_SHIFT)
+ numentries >>= (scale - PAGE_SHIFT);
+ else
+ numentries <<= (PAGE_SHIFT - scale);
+
+ /* Make sure we've got at least a 0-order allocation.. */
+ if (unlikely(flags & HASH_SMALL)) {
+ /* Makes no sense without HASH_EARLY */
+ WARN_ON(!(flags & HASH_EARLY));
+ if (!(numentries >> *_hash_shift)) {
+ numentries = 1UL << *_hash_shift;
+ BUG_ON(!numentries);
+ }
+ } else if (unlikely((numentries * bucketsize) < PAGE_SIZE))
+ numentries = PAGE_SIZE / bucketsize;
+ }
+ numentries = roundup_pow_of_two(numentries);
+
+ /* limit allocation size to 1/16 total memory by default */
+ if (max == 0) {
+ max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4;
+ do_div(max, bucketsize);
+ }
+
+ if (numentries > max)
+ numentries = max;
+
+ log2qty = ilog2(numentries);
+
+ do {
+ size = bucketsize << log2qty;
+ if (flags & HASH_EARLY)
+ table = alloc_bootmem_nopanic(size);
+ else if (hashdist)
+ table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
+ else {
+ /*
+ * If bucketsize is not a power-of-two, we may free
+ * some pages at the end of hash table which
+ * alloc_pages_exact() automatically does
+ */
+ if (get_order(size) < MAX_ORDER) {
+ table = alloc_pages_exact(size, GFP_ATOMIC);
+ kmemleak_alloc(table, size, 1, GFP_ATOMIC);
+ }
+ }
+ } while (!table && size > PAGE_SIZE && --log2qty);
+
+ if (!table)
+ panic("Failed to allocate %s hash table\n", tablename);
+
+ pr_info("%s hash table entries: %d (order: %d, %lu bytes)\n",
+ tablename,
+ (1U << log2qty),
+ ilog2(size) - PAGE_SHIFT,
+ size);
+
+ if (_hash_shift)
+ *_hash_shift = log2qty;
+ if (_hash_mask)
+ *_hash_mask = (1 << log2qty) - 1;
+
+ return table;
+}
+
+void si_meminfo(struct sysinfo *val)
+{
+ /* This function is called from the ip layer to get information about
+ the amount of memory in the system and make some educated guesses
+ about some default buffer sizes. We pick a value which ensures
+ small buffers. */
+ val->totalram = 0;
+}
+int slab_is_available(void)
+{
+ /* called from kernel/param.c. */
+ return 1;
+}
+
+/* used from kern_ptr_validate from mm/util.c which is never called */
+void *high_memory = 0;
+
+
+
+void async_synchronize_full(void)
+{
+ /* called from drivers/base/ *.c */
+ /* there is nothing to do, really. */
+}
+
+int send_sig(int signal, struct task_struct *task, int x)
+{
+ struct SimTask *lib_task = container_of(task, struct SimTask,
+ kernel_task);
+
+ lib_signal_raised((struct SimTask *)lib_task, signal);
+ /* lib_assert (false); */
+ return 0;
+}
+unsigned long get_taint(void)
+{
+ /* never tainted. */
+ return 0;
+}
+void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
+{
+}
+struct pid *cad_pid = 0;
+
+void add_device_randomness(const void *buf, unsigned int size)
+{
+}
+
+int sched_rr_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ return 0;
+}
+
+int sysctl_max_threads(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return 1;
+}
+
+void on_each_cpu_mask(const struct cpumask *mask,
+ smp_call_func_t func, void *info, bool wait)
+{
+}
diff --git a/arch/lib/modules.c b/arch/lib/modules.c
new file mode 100644
index 0000000..ca43fdc
--- /dev/null
+++ b/arch/lib/modules.c
@@ -0,0 +1,36 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ * Frederic Urbani
+ */
+
+#include "sim-assert.h"
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+
+int modules_disabled = 0;
+char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
+
+static struct module_version_attribute g_empty_attr_buffer;
+/* we make the array empty by default because, really, we don't need */
+/* to look at the builtin params */
+const struct kernel_param __start___param[] = {{0}} ;
+const struct kernel_param __stop___param[] = {{0}} ;
+const struct module_version_attribute *__start___modver[] = {
+ &g_empty_attr_buffer};
+const struct module_version_attribute *__stop___modver[] = {
+ &g_empty_attr_buffer};
+
+struct module_attribute module_uevent;
+struct ctl_table usermodehelper_table[] = {};
+
+int __request_module(bool wait, const char *fmt, ...)
+{
+ /* we really should never be trying to load modules that way. */
+ /* lib_assert (false); */
+ return 0;
+}
diff --git a/arch/lib/pid.c b/arch/lib/pid.c
new file mode 100644
index 0000000..00cf7b6
--- /dev/null
+++ b/arch/lib/pid.c
@@ -0,0 +1,29 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/pid.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+void put_pid(struct pid *pid)
+{
+}
+pid_t pid_vnr(struct pid *pid)
+{
+ return pid_nr(pid);
+}
+struct task_struct *find_task_by_vpid(pid_t nr)
+{
+ lib_assert(false);
+ return 0;
+}
+struct pid *find_get_pid(int nr)
+{
+ lib_assert(false);
+ return 0;
+}
diff --git a/arch/lib/print.c b/arch/lib/print.c
new file mode 100644
index 0000000..09b1bb5
--- /dev/null
+++ b/arch/lib/print.c
@@ -0,0 +1,56 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <stdarg.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int dmesg_restrict = 1;
+
+/* from lib/vsprintf.c */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+int printk(const char *fmt, ...)
+{
+ va_list args;
+ static char buf[256];
+ int value;
+
+ va_start(args, fmt);
+ value = vsnprintf(buf, 256, printk_skip_level(fmt), args);
+ lib_printf("<%c>%s", printk_get_level(fmt), buf);
+ va_end(args);
+ return value;
+}
+void panic(const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+ lib_assert(false);
+}
+
+void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+
+ printk("%s:%d -- ", file, line);
+ va_start(args, fmt);
+ lib_vprintf(fmt, args);
+ va_end(args);
+}
+
+void warn_slowpath_null(const char *file, int line)
+{
+ printk("%s:%d -- ", file, line);
+}
+
diff --git a/arch/lib/proc.c b/arch/lib/proc.c
new file mode 100644
index 0000000..5507730
--- /dev/null
+++ b/arch/lib/proc.c
@@ -0,0 +1,34 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2014 Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/fs.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <net/net_namespace.h>
+#include "sim-types.h"
+#include "sim-assert.h"
+#include "fs/proc/internal.h" /* XXX */
+
+struct proc_dir_entry;
+static char proc_root_data[sizeof(struct proc_dir_entry) + 4];
+
+static struct proc_dir_entry *proc_root_sim =
+ (struct proc_dir_entry *)proc_root_data;
+
+void lib_proc_net_initialize(void)
+{
+ proc_root_sim->parent = proc_root_sim;
+ strcpy(proc_root_sim->name, "net");
+ proc_root_sim->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ proc_root_sim->subdir = RB_ROOT;
+ init_net.proc_net = proc_root_sim;
+ init_net.proc_net_stat = proc_mkdir("stat", proc_root_sim);
+}
+
diff --git a/arch/lib/random.c b/arch/lib/random.c
new file mode 100644
index 0000000..9fbb8bf
--- /dev/null
+++ b/arch/lib/random.c
@@ -0,0 +1,53 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include "sim.h"
+#include <linux/random.h>
+
+u32 random32(void)
+{
+ return lib_random();
+}
+
+void get_random_bytes(void *buf, int nbytes)
+{
+ char *p = (char *)buf;
+ int i;
+
+ for (i = 0; i < nbytes; i++)
+ p[i] = lib_random();
+}
+void srandom32(u32 entropy)
+{
+}
+
+u32 prandom_u32(void)
+{
+ return lib_random();
+}
+void prandom_seed(u32 entropy)
+{
+}
+
+void prandom_bytes(void *buf, size_t bytes)
+{
+ return get_random_bytes(buf, bytes);
+}
+
+#include <linux/sysctl.h>
+
+static int nothing;
+struct ctl_table random_table[] = {
+ {
+ .procname = "nothing",
+ .data = ¬hing,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ }
+};
diff --git a/arch/lib/sysfs.c b/arch/lib/sysfs.c
new file mode 100644
index 0000000..2def2ca
--- /dev/null
+++ b/arch/lib/sysfs.c
@@ -0,0 +1,83 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include "sim.h"
+#include "sim-assert.h"
+
+int sysfs_create_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+ return 0;
+}
+void sysfs_remove_bin_file(struct kobject *kobj,
+ const struct bin_attribute *attr)
+{
+}
+int sysfs_create_dir(struct kobject *kobj)
+{
+ return 0;
+}
+int sysfs_create_link(struct kobject *kobj, struct kobject *target,
+ const char *name)
+{
+ return 0;
+}
+int sysfs_move_dir(struct kobject *kobj,
+ struct kobject *new_parent_kobj)
+{
+ return 0;
+}
+void sysfs_remove_dir(struct kobject *kobj)
+{
+}
+void sysfs_remove_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+}
+int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
+{
+ return 0;
+}
+int __must_check sysfs_create_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return 0;
+}
+int sysfs_create_groups(struct kobject *kobj,
+ const struct attribute_group **groups)
+{
+ return 0;
+}
+int sysfs_schedule_callback(struct kobject *kobj,
+ void (*func)(
+ void *), void *data, struct module *owner)
+{
+ return 0;
+}
+void sysfs_delete_link(struct kobject *dir, struct kobject *targ,
+ const char *name)
+{
+}
+void sysfs_exit_ns(enum kobj_ns_type type, const void *tag)
+{
+}
+void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr)
+{
+}
+int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
+{
+ kobj->sd = lib_malloc(sizeof(struct kernfs_node));
+ return 0;
+}
+int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr,
+ const void *ns)
+{
+ return 0;
+}
diff --git a/arch/lib/vmscan.c b/arch/lib/vmscan.c
new file mode 100644
index 0000000..3132f66
--- /dev/null
+++ b/arch/lib/vmscan.c
@@ -0,0 +1,26 @@
+/*
+ * glue code for library version of Linux kernel
+ * Copyright (c) 2015 INRIA, Hajime Tazaki
+ *
+ * Author: Mathieu Lacage <[email protected]>
+ * Hajime Tazaki <[email protected]>
+ */
+
+#include <linux/mm.h>
+#include <linux/shrinker.h>
+
+/*
+ * Add a shrinker callback to be called from the vm
+ */
+int register_shrinker(struct shrinker *shrinker)
+{
+ return 0;
+}
+
+/*
+ * Remove one
+ */
+void unregister_shrinker(struct shrinker *shrinker)
+{
+}
+
--
2.1.0
these files works as stubs in order to transparently run the other
kernel part (e.g., net/) on libos environment.
Signed-off-by: Hajime Tazaki <[email protected]>
---
arch/lib/include/asm/Kbuild | 57 +++++++++++++++++++++++++++++++++
arch/lib/include/asm/atomic.h | 59 +++++++++++++++++++++++++++++++++++
arch/lib/include/asm/barrier.h | 8 +++++
arch/lib/include/asm/bitsperlong.h | 16 ++++++++++
arch/lib/include/asm/current.h | 7 +++++
arch/lib/include/asm/elf.h | 10 ++++++
arch/lib/include/asm/hardirq.h | 8 +++++
arch/lib/include/asm/page.h | 14 +++++++++
arch/lib/include/asm/pgtable.h | 30 ++++++++++++++++++
arch/lib/include/asm/processor.h | 19 +++++++++++
arch/lib/include/asm/ptrace.h | 4 +++
arch/lib/include/asm/segment.h | 6 ++++
arch/lib/include/asm/sembuf.h | 4 +++
arch/lib/include/asm/shmbuf.h | 4 +++
arch/lib/include/asm/shmparam.h | 4 +++
arch/lib/include/asm/sigcontext.h | 6 ++++
arch/lib/include/asm/stat.h | 4 +++
arch/lib/include/asm/statfs.h | 4 +++
arch/lib/include/asm/swab.h | 7 +++++
arch/lib/include/asm/thread_info.h | 36 +++++++++++++++++++++
arch/lib/include/asm/uaccess.h | 14 +++++++++
arch/lib/include/asm/unistd.h | 4 +++
arch/lib/include/uapi/asm/byteorder.h | 6 ++++
23 files changed, 331 insertions(+)
create mode 100644 arch/lib/include/asm/Kbuild
create mode 100644 arch/lib/include/asm/atomic.h
create mode 100644 arch/lib/include/asm/barrier.h
create mode 100644 arch/lib/include/asm/bitsperlong.h
create mode 100644 arch/lib/include/asm/current.h
create mode 100644 arch/lib/include/asm/elf.h
create mode 100644 arch/lib/include/asm/hardirq.h
create mode 100644 arch/lib/include/asm/page.h
create mode 100644 arch/lib/include/asm/pgtable.h
create mode 100644 arch/lib/include/asm/processor.h
create mode 100644 arch/lib/include/asm/ptrace.h
create mode 100644 arch/lib/include/asm/segment.h
create mode 100644 arch/lib/include/asm/sembuf.h
create mode 100644 arch/lib/include/asm/shmbuf.h
create mode 100644 arch/lib/include/asm/shmparam.h
create mode 100644 arch/lib/include/asm/sigcontext.h
create mode 100644 arch/lib/include/asm/stat.h
create mode 100644 arch/lib/include/asm/statfs.h
create mode 100644 arch/lib/include/asm/swab.h
create mode 100644 arch/lib/include/asm/thread_info.h
create mode 100644 arch/lib/include/asm/uaccess.h
create mode 100644 arch/lib/include/asm/unistd.h
create mode 100644 arch/lib/include/uapi/asm/byteorder.h
diff --git a/arch/lib/include/asm/Kbuild b/arch/lib/include/asm/Kbuild
new file mode 100644
index 0000000..c647b1c
--- /dev/null
+++ b/arch/lib/include/asm/Kbuild
@@ -0,0 +1,57 @@
+generic-y += auxvec.h
+generic-y += bitops.h
+generic-y += bug.h
+generic-y += cache.h
+generic-y += cacheflush.h
+generic-y += checksum.h
+generic-y += cputime.h
+generic-y += cmpxchg.h
+generic-y += delay.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += exec.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += io.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq.h
+generic-y += irqflags.h
+generic-y += irq_regs.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += linkage.h
+generic-y += local.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += mmu.h
+generic-y += mmu_context.h
+generic-y += module.h
+generic-y += mutex.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += preempt.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += setup.h
+generic-y += signal.h
+generic-y += siginfo.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += string.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += timex.h
+generic-y += tlbflush.h
+generic-y += types.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += unaligned.h
diff --git a/arch/lib/include/asm/atomic.h b/arch/lib/include/asm/atomic.h
new file mode 100644
index 0000000..444a953
--- /dev/null
+++ b/arch/lib/include/asm/atomic.h
@@ -0,0 +1,59 @@
+#ifndef _ASM_SIM_ATOMIC_H
+#define _ASM_SIM_ATOMIC_H
+
+#include <linux/types.h>
+#include <asm-generic/cmpxchg.h>
+
+#if !defined(CONFIG_64BIT)
+typedef struct {
+ volatile long long counter;
+} atomic64_t;
+#endif
+
+#define ATOMIC64_INIT(i) { (i) }
+
+#define atomic64_read(v) (*(volatile long *)&(v)->counter)
+void atomic64_add(long i, atomic64_t *v);
+static inline void atomic64_sub(long i, atomic64_t *v)
+{
+ v->counter -= i;
+}
+static inline void atomic64_inc(atomic64_t *v)
+{
+ v->counter++;
+}
+int atomic64_sub_and_test(long i, atomic64_t *v);
+#define atomic64_dec(v) atomic64_sub(1LL, (v))
+int atomic64_dec_and_test(atomic64_t *v);
+int atomic64_inc_and_test(atomic64_t *v);
+int atomic64_add_negative(long i, atomic64_t *v);
+/* long atomic64_add_return(long i, atomic64_t *v); */
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+ v->counter += i;
+ return v->counter;
+}
+static inline void atomic64_set(atomic64_t *v, long i)
+{
+ v->counter = i;
+}
+long atomic64_sub_return(long i, atomic64_t *v);
+#define atomic64_inc_return(v) (atomic64_add_return(1, (v)))
+#define atomic64_dec_return(v) (atomic64_sub_return(1, (v)))
+static inline long atomic64_cmpxchg(atomic64_t *v, long old, long new)
+{
+ long long val;
+
+ val = v->counter;
+ if (val == old)
+ v->counter = new;
+ return val;
+}
+long atomic64_xchg(atomic64_t *v, long new);
+int atomic64_add_unless(atomic64_t *v, long a, long u);
+int atomic64_inc_is_not_zero(atomic64_t *v);
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+
+#include <asm-generic/atomic.h>
+
+#endif /* _ASM_SIM_ATOMIC_H */
diff --git a/arch/lib/include/asm/barrier.h b/arch/lib/include/asm/barrier.h
new file mode 100644
index 0000000..47adcc6
--- /dev/null
+++ b/arch/lib/include/asm/barrier.h
@@ -0,0 +1,8 @@
+#include <asm-generic/barrier.h>
+
+#undef smp_store_release
+#define smp_store_release(p, v) \
+ do { \
+ smp_mb(); \
+ ACCESS_ONCE(*p) = (v); \
+ } while (0)
diff --git a/arch/lib/include/asm/bitsperlong.h b/arch/lib/include/asm/bitsperlong.h
new file mode 100644
index 0000000..9890ba9
--- /dev/null
+++ b/arch/lib/include/asm/bitsperlong.h
@@ -0,0 +1,16 @@
+#ifndef _ASM_SIM_BITSPERLONG_H
+#define _ASM_SIM_BITSPERLONG_H
+
+#ifdef CONFIG_64BIT
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif /* CONFIG_64BIT */
+
+#define __BITS_PER_LONG BITS_PER_LONG
+
+#ifndef BITS_PER_LONG_LONG
+#define BITS_PER_LONG_LONG 64
+#endif
+
+#endif /* _ASM_SIM_BITSPERLONG_H */
diff --git a/arch/lib/include/asm/current.h b/arch/lib/include/asm/current.h
new file mode 100644
index 0000000..62489cd
--- /dev/null
+++ b/arch/lib/include/asm/current.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_CURRENT_H
+#define _ASM_SIM_CURRENT_H
+
+struct task_struct *get_current(void);
+#define current get_current()
+
+#endif /* _ASM_SIM_CURRENT_H */
diff --git a/arch/lib/include/asm/elf.h b/arch/lib/include/asm/elf.h
new file mode 100644
index 0000000..a7396c9
--- /dev/null
+++ b/arch/lib/include/asm/elf.h
@@ -0,0 +1,10 @@
+#ifndef _ASM_SIM_ELF_H
+#define _ASM_SIM_ELF_H
+
+#if defined(CONFIG_64BIT)
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+
+#endif /* _ASM_SIM_ELF_H */
diff --git a/arch/lib/include/asm/hardirq.h b/arch/lib/include/asm/hardirq.h
new file mode 100644
index 0000000..47d47f9
--- /dev/null
+++ b/arch/lib/include/asm/hardirq.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_SIM_HARDIRQ_H
+#define _ASM_SIM_HARDIRQ_H
+
+extern unsigned int interrupt_pending;
+
+#define local_softirq_pending() (interrupt_pending)
+
+#endif /* _ASM_SIM_HARDIRQ_H */
diff --git a/arch/lib/include/asm/page.h b/arch/lib/include/asm/page.h
new file mode 100644
index 0000000..8c0aa74
--- /dev/null
+++ b/arch/lib/include/asm/page.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_PAGE_H
+#define _ASM_SIM_PAGE_H
+
+typedef struct {} pud_t;
+
+#define THREAD_ORDER 1
+#define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER)
+
+#define WANT_PAGE_VIRTUAL 1
+
+#include <asm-generic/page.h>
+#include <asm-generic/getorder.h>
+
+#endif /* _ASM_SIM_PAGE_H */
diff --git a/arch/lib/include/asm/pgtable.h b/arch/lib/include/asm/pgtable.h
new file mode 100644
index 0000000..ce599c8
--- /dev/null
+++ b/arch/lib/include/asm/pgtable.h
@@ -0,0 +1,30 @@
+#ifndef _ASM_SIM_PGTABLE_H
+#define _ASM_SIM_PGTABLE_H
+
+#define PAGE_KERNEL ((pgprot_t) {0 })
+
+#define arch_start_context_switch(prev) do {} while (0)
+
+#define kern_addr_valid(addr)(1)
+#define pte_file(pte)(1)
+/* Encode and de-code a swap entry */
+#define __swp_type(x) (((x).val >> 5) & 0x1f)
+#define __swp_offset(x) ((x).val >> 11)
+#define __swp_entry(type, offset) \
+ ((swp_entry_t) {((type) << 5) | ((offset) << 11) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) {pte_val((pte)) })
+#define __swp_entry_to_pte(x) ((pte_t) {(x).val })
+#define pmd_page(pmd) (struct page *)(pmd_val(pmd) & PAGE_MASK)
+#define pgtable_cache_init() do { } while (0)
+
+static inline int pte_swp_soft_dirty(pte_t pte)
+{
+ return 0;
+}
+
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+ return pte;
+}
+
+#endif /* _ASM_SIM_PGTABLE_H */
diff --git a/arch/lib/include/asm/processor.h b/arch/lib/include/asm/processor.h
new file mode 100644
index 0000000..b673ee0
--- /dev/null
+++ b/arch/lib/include/asm/processor.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_SIM_PROCESSOR_H
+#define _ASM_SIM_PROCESSOR_H
+
+struct thread_struct {};
+
+#define cpu_relax()
+#define cpu_relax_lowlatency() cpu_relax()
+#define KSTK_ESP(tsk) (0)
+
+void *current_text_addr(void);
+
+#define TASK_SIZE ((~(long)0))
+
+#define thread_saved_pc(x) (unsigned long)0
+#define task_pt_regs(t) NULL
+
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+#endif /* _ASM_SIM_PROCESSOR_H */
diff --git a/arch/lib/include/asm/ptrace.h b/arch/lib/include/asm/ptrace.h
new file mode 100644
index 0000000..ddd9708
--- /dev/null
+++ b/arch/lib/include/asm/ptrace.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_PTRACE_H
+#define _ASM_SIM_PTRACE_H
+
+#endif /* _ASM_SIM_PTRACE_H */
diff --git a/arch/lib/include/asm/segment.h b/arch/lib/include/asm/segment.h
new file mode 100644
index 0000000..e056922
--- /dev/null
+++ b/arch/lib/include/asm/segment.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SEGMENT_H
+#define _ASM_SIM_SEGMENT_H
+
+typedef struct { int seg; } mm_segment_t;
+
+#endif /* _ASM_SIM_SEGMENT_H */
diff --git a/arch/lib/include/asm/sembuf.h b/arch/lib/include/asm/sembuf.h
new file mode 100644
index 0000000..d64927b
--- /dev/null
+++ b/arch/lib/include/asm/sembuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SEMBUF_H
+#define _ASM_SIM_SEMBUF_H
+
+#endif /* _ASM_SIM_SEMBUF_H */
diff --git a/arch/lib/include/asm/shmbuf.h b/arch/lib/include/asm/shmbuf.h
new file mode 100644
index 0000000..42d0a71
--- /dev/null
+++ b/arch/lib/include/asm/shmbuf.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMBUF_H
+#define _ASM_SIM_SHMBUF_H
+
+#endif /* _ASM_SIM_SHMBUF_H */
diff --git a/arch/lib/include/asm/shmparam.h b/arch/lib/include/asm/shmparam.h
new file mode 100644
index 0000000..3410f1b
--- /dev/null
+++ b/arch/lib/include/asm/shmparam.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_SHMPARAM_H
+#define _ASM_SIM_SHMPARAM_H
+
+#endif /* _ASM_SIM_SHMPARAM_H */
diff --git a/arch/lib/include/asm/sigcontext.h b/arch/lib/include/asm/sigcontext.h
new file mode 100644
index 0000000..230b4b5
--- /dev/null
+++ b/arch/lib/include/asm/sigcontext.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SIM_SIGCONTEXT_H
+#define _ASM_SIM_SIGCONTEXT_H
+
+struct sigcontext {};
+
+#endif /* _ASM_SIM_SIGCONTEXT_H */
diff --git a/arch/lib/include/asm/stat.h b/arch/lib/include/asm/stat.h
new file mode 100644
index 0000000..80fa2cb
--- /dev/null
+++ b/arch/lib/include/asm/stat.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STAT_H
+#define _ASM_SIM_STAT_H
+
+#endif /* _ASM_SIM_STAT_H */
diff --git a/arch/lib/include/asm/statfs.h b/arch/lib/include/asm/statfs.h
new file mode 100644
index 0000000..881ce51
--- /dev/null
+++ b/arch/lib/include/asm/statfs.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_STATFS_H
+#define _ASM_SIM_STATFS_H
+
+#endif /* _ASM_SIM_STATFS_H */
diff --git a/arch/lib/include/asm/swab.h b/arch/lib/include/asm/swab.h
new file mode 100644
index 0000000..d81376a
--- /dev/null
+++ b/arch/lib/include/asm/swab.h
@@ -0,0 +1,7 @@
+#ifndef _ASM_SIM_SWAB_H
+#define _ASM_SIM_SWAB_H
+
+#include <linux/types.h>
+
+
+#endif /* _ASM_SIM_SWAB_H */
diff --git a/arch/lib/include/asm/thread_info.h b/arch/lib/include/asm/thread_info.h
new file mode 100644
index 0000000..ec316c6
--- /dev/null
+++ b/arch/lib/include/asm/thread_info.h
@@ -0,0 +1,36 @@
+#ifndef _ASM_SIM_THREAD_INFO_H
+#define _ASM_SIM_THREAD_INFO_H
+
+#define TIF_NEED_RESCHED 1
+#define TIF_SIGPENDING 2
+#define TIF_MEMDIE 5
+
+struct thread_info {
+ __u32 flags;
+ int preempt_count;
+ struct task_struct *task;
+ struct restart_block restart_block;
+};
+
+struct thread_info *current_thread_info(void);
+struct thread_info *alloc_thread_info(struct task_struct *task);
+void free_thread_info(struct thread_info *ti);
+
+#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+}
+static inline void clear_restore_sigmask(void)
+{
+}
+static inline bool test_restore_sigmask(void)
+{
+ return true;
+}
+static inline bool test_and_clear_restore_sigmask(void)
+{
+ return true;
+}
+
+#endif /* _ASM_SIM_THREAD_INFO_H */
diff --git a/arch/lib/include/asm/uaccess.h b/arch/lib/include/asm/uaccess.h
new file mode 100644
index 0000000..74f973b
--- /dev/null
+++ b/arch/lib/include/asm/uaccess.h
@@ -0,0 +1,14 @@
+#ifndef _ASM_SIM_UACCESS_H
+#define _ASM_SIM_UACCESS_H
+
+#define KERNEL_DS ((mm_segment_t) {0 })
+#define USER_DS ((mm_segment_t) {0 })
+#define get_fs() KERNEL_DS
+#define get_ds() USER_DS
+#define set_fs(x) do {} while ((x.seg) != (x.seg))
+
+#define __access_ok(addr, size) (1)
+
+#include <asm-generic/uaccess.h>
+
+#endif /* _ASM_SIM_UACCESS_H */
diff --git a/arch/lib/include/asm/unistd.h b/arch/lib/include/asm/unistd.h
new file mode 100644
index 0000000..6b482b4
--- /dev/null
+++ b/arch/lib/include/asm/unistd.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_SIM_UNISTD_H
+#define _ASM_SIM_UNISTD_H
+
+#endif /* _ASM_SIM_UNISTD_H */
diff --git a/arch/lib/include/uapi/asm/byteorder.h b/arch/lib/include/uapi/asm/byteorder.h
new file mode 100644
index 0000000..b13a7a8
--- /dev/null
+++ b/arch/lib/include/uapi/asm/byteorder.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_X86_BYTEORDER_H
+#define _ASM_X86_BYTEORDER_H
+
+#include <linux/byteorder/little_endian.h>
+
+#endif /* _ASM_X86_BYTEORDER_H */
--
2.1.0
document and build scripts for libos architecture.
Signed-off-by: Hajime Tazaki <[email protected]>
Signed-off-by: Ryo Nakamura <[email protected]>
---
Documentation/virtual/libos-howto.txt | 144 ++++++++
MAINTAINERS | 9 +
arch/lib/.gitignore | 3 +
arch/lib/Kconfig | 124 +++++++
arch/lib/Makefile | 224 ++++++++++++
arch/lib/Makefile.print | 45 +++
arch/lib/defconfig | 653 ++++++++++++++++++++++++++++++++++
arch/lib/generate-linker-script.py | 50 +++
8 files changed, 1252 insertions(+)
create mode 100644 Documentation/virtual/libos-howto.txt
create mode 100644 arch/lib/.gitignore
create mode 100644 arch/lib/Kconfig
create mode 100644 arch/lib/Makefile
create mode 100644 arch/lib/Makefile.print
create mode 100644 arch/lib/defconfig
create mode 100755 arch/lib/generate-linker-script.py
diff --git a/Documentation/virtual/libos-howto.txt b/Documentation/virtual/libos-howto.txt
new file mode 100644
index 0000000..fbf7946
--- /dev/null
+++ b/Documentation/virtual/libos-howto.txt
@@ -0,0 +1,144 @@
+Library operating system (libos) version of Linux
+=================================================
+
+* Overview
+
+New hardware independent architecture 'arch/lib', configured by
+CONFIG_LIB gives you two features.
+
+- network stack in userspace (NUSE)
+ NUSE will give you a personalized network stack for each application
+ without replacing host operating system.
+
+- network simulator integration, which is called Direct Code Execution (DCE)
+ DCE will give us a network simulation environment with Linux network stack
+ to investigate the detail behavior protocol implementation with a flexible
+ network configuration. This is also useful for the testing environment.
+
+(- more abstracted implementation of underlying platform will be a future
+ direction (e.g., rump hypercall))
+
+In both features, Linux kernel network stack is running on top of
+userspace application with a linked or dynamically loaded library.
+
+They have their own, isolated network stack from host operating system
+so they are configured different IP addresses as other virtualization
+methods do.
+
+
+* How different with others ?
+
+- User-mode Linux (UML)
+
+UML is a way to execute Linux kernel code as a userspace
+application. It is completely isolated from host kernel but can host
+arbitrary userspace applications on top of UML.
+
+- namespace / container
+
+Container technologies with namespace brings a process-level isolation
+to host multiple network entities but shares the kernel among
+processes, which prevents to introduce new features implemented in
+kernel space.
+
+
+* How to build it ?
+
+configuration of arch/lib follows a standard configuration of kernel.
+
+ make defconfig ARCH=lib
+
+or
+
+ make menuconfig ARCH=lib
+
+then you can build a set of libraries for libos.
+
+ make library ARCH=lib
+
+This will give you a shared library file liblinux-$(KERNELVERSION).so
+in the top directory.
+
+* Hello world
+
+you may first need to configure a configuration file, named
+'nuse.conf' so that the library version of network stack can know what
+kind of IP configuration should be used. There is an example file
+at arch/lib/nuse.conf.sample: you may copy and modify it for your purpose.
+
+ sudo NUSECONF=nuse.conf ./nuse ping http://www.google.com
+
+
+
+* Example use cases
+- regression test with Direct Code Execution (DCE)
+
+'make test' by DCE gives a test platform for networking code, with the
+help of network simulator facilities like link delay/bandwidth/drop
+configurations, large network topology with userspace routing protocol
+daemons, etc.
+
+An interesting feature is the determinism of any test executions. A
+test script always gives same results in every execution if there is
+no modification on test target code.
+
+For the first step, you need to obtain network simulator
+environment. 'make testbin' does all the stuff for the preparation.
+
+% make testbin -C tools/testing/libos
+
+Then, you can 'make test' for your code.
+
+% make test ARCH=lib
+
+ PASS: TestSuite netlink-socket
+ PASS: TestSuite process-manager
+ PASS: TestSuite dce-cradle
+ PASS: TestSuite dce-mptcp
+ PASS: TestSuite dce-umip
+ PASS: TestSuite dce-quagga
+ PASS: Example dce-tcp-simple
+ PASS: Example dce-udp-simple
+
+
+- userspace network stack (NUSE)
+
+an application can use its own network stack, distinct from host network stack
+in order to personalize any network feature to the application specific one.
+The 'nuse' wrapper script, based on LD_PRELOAD technique, carefully replaces
+socket API and redirects system calls to the network stack library, provided by
+this framework.
+
+the network stack can be used with any kind of raw-socket like
+technologies such as Intel DPDK, netmap, etc.
+
+
+
+* Files / External Repository
+
+The kernel source tree (i.e., arch/lib) only contains a shared part of
+applications (NUSE/DCE). Pure userspace part is managed at a different
+repository, called Linux-libos-tools: it is automatically downloaded
+during make library.
+
+ https://github.com/libos-nuse/linux-libos-tools
+
+
+* More information
+- [email protected] (LibOS in general and NUSE related questions)
+- [email protected] (ns-3 related questions)
+- articles, slides
+ Experimentation Tools for Networking Research (Lacage, 2010)
+ http://cutebugs.net/files/thesis.pdf
+ Direct code execution: revisiting library OS architecture for reproducible
+ network experiments (Tazaki et al., 2013)
+ http://dx.doi.org/10.1145/2535372.2535374
+ Library Operating System with Mainline Linux Network Stack (Tazaki et al., 2015)
+ https://www.netdev01.org/docs/netdev01-tazaki-libos.pdf (slides)
+
+
+* Authors
+ Mathieu Lacage <[email protected]>
+ Hajime Tazaki <[email protected]>
+ Frederic Urbani <[email protected]>
+ Ryo Nakamura <[email protected]>
diff --git a/MAINTAINERS b/MAINTAINERS
index 590304b..895c55f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5912,6 +5912,15 @@ M: Sasha Levin <[email protected]>
S: Maintained
F: tools/lib/lockdep/
+LIBRARY OS (LIBOS)
+M: Hajime Tazaki <[email protected]>
+L: [email protected]
+W: http://libos-nuse.github.io/
+S: Maintained
+F: Documentation/virtual/libos-howto.txt
+F: arch/lib/
+F: tools/testing/libos/
+
LINUX FOR IBM pSERIES (RS/6000)
M: Paul Mackerras <[email protected]>
W: http://www.ibm.com/linux/ltc/projects/ppc
diff --git a/arch/lib/.gitignore b/arch/lib/.gitignore
new file mode 100644
index 0000000..4370d48
--- /dev/null
+++ b/arch/lib/.gitignore
@@ -0,0 +1,3 @@
+linker.lds
+objs.mk
+tools
diff --git a/arch/lib/Kconfig b/arch/lib/Kconfig
new file mode 100644
index 0000000..eef92af
--- /dev/null
+++ b/arch/lib/Kconfig
@@ -0,0 +1,124 @@
+mainmenu "Linux Library OS (libos) $KERNELVERSION Configuration"
+
+config LIB
+ def_bool y
+ select PROC_FS
+ select PROC_SYSCTL
+ select SYSCTL
+ select SYSFS
+ help
+ The 'lib' architecture is a library (user-mode) version of
+ the linux kernel that includes only its network stack and is
+ used within the userspace application, and ns-3 simulator.
+ For more information, about ns-3, see http://www.nsnam.org.
+
+config ARCH
+ string
+ option env="ARCH"
+
+config KERNELVERSION
+ string
+ option env="KERNELVERSION"
+
+config MODULES
+ def_bool y
+ option modules
+
+config MMU
+ def_bool n
+
+config FPU
+ def_bool n
+
+config SMP
+ def_bool n
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+
+config PRINTK
+ def_bool y
+
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+config NO_HZ
+ def_bool y
+
+config BASE_FULL
+ def_bool n
+
+config SELECT_MEMORY_MODEL
+ def_bool n
+
+config FLAT_NODE_MEM_MAP
+ def_bool n
+
+config PAGEFLAGS_EXTENDED
+ def_bool n
+
+config VIRT_TO_BUS
+ def_bool n
+
+config HAS_DMA
+ def_bool n
+
+config HZ
+ int
+ default 250
+
+config TINY_RCU
+ def_bool y
+
+config HZ_250
+ def_bool y
+
+config BASE_SMALL
+ int
+ default 1
+
+config SPLIT_PTLOCK_CPUS
+ int
+ default 1
+
+config FLATMEM
+ def_bool y
+
+config SYSCTL
+ def_bool y
+
+config PROC_FS
+ def_bool y
+
+config SYSFS
+ def_bool y
+
+config PROC_SYSCTL
+ def_bool y
+
+config MULTIUSER
+ def_bool n
+
+config NETDEVICES
+ def_bool y
+
+source "net/Kconfig"
+
+source "drivers/base/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+config SLIB
+ def_bool y
\ No newline at end of file
diff --git a/arch/lib/Makefile b/arch/lib/Makefile
new file mode 100644
index 0000000..47bd08c
--- /dev/null
+++ b/arch/lib/Makefile
@@ -0,0 +1,224 @@
+ARCH_DIR := arch/lib
+DCE_TESTDIR=$(srctree)/tools/testing/libos/
+KBUILD_KCONFIG := arch/$(ARCH)/Kconfig
+
+CC = gcc
+GCCVERSIONGTEQ48 := $(shell expr `gcc -dumpversion` \>= 4.8)
+ifeq "$(GCCVERSIONGTEQ48)" "1"
+ NO_TREE_LOOP_OPT += -fno-tree-loop-distribute-patterns
+endif
+
+
+-include $(ARCH_DIR)/objs.mk
+-include $(srctree)/.config
+include $(srctree)/scripts/Kbuild.include
+
+# targets
+LIBOS_TOOLS=$(ARCH_DIR)/tools
+LIBOS_GIT_REPO=git://github.com/libos-nuse/linux-libos-tools
+KERNEL_LIB=liblinux-$(KERNELVERSION).so
+
+ALL_OBJS=$(OBJS) $(KERNEL_LIB) $(modules) $(all-obj-for-clean)
+
+# auto generated files
+AUTOGENS=include/generated/compile.h include/generated/bounds.h \
+ kernel/time/timeconst.h lib/crc32table.h $(ARCH_DIR)/linker.lds
+
+# sources and objects
+LIB_SRC=\
+lib.c lib-device.c lib-socket.c random.c softirq.c time.c \
+timer.c hrtimer.c sched.c workqueue.c \
+print.c tasklet.c tasklet-hrtimer.c \
+glue.c fs.c sysctl.c proc.c sysfs.c \
+capability.c pid.c modules.c filemap.c vmscan.c
+
+LIB_OBJ=$(addprefix $(ARCH_DIR)/,$(addsuffix .o,$(basename $(LIB_SRC))))
+LIB_DEPS=$(addprefix $(ARCH_DIR)/.,$(addsuffix .o.cmd,$(basename $(LIB_SRC))))
+-include $(LIB_DEPS)
+
+# options
+COV?=no
+cov_yes=-fprofile-arcs -ftest-coverage
+cov_no=
+covl_yes=-fprofile-arcs
+covl_no=
+OPT?=yes
+opt_yes=-O3 -fomit-frame-pointer $(NO_TREE_LOOP_OPT)
+opt_no=-O0
+PIC?=yes
+pic_yes=-fpic -DPIC
+pic_no=-mcmodel=large
+PIC_CFLAGS=$(pic_$(PIC))
+
+# flags
+CFLAGS_USPACE= \
+ -Wp,-MD,$(depfile) $(opt_$(OPT)) -g3 -Wall -Wstrict-prototypes -Wno-trigraphs \
+ -fno-inline -fno-strict-aliasing -fno-common \
+ -fno-delete-null-pointer-checks -fno-builtin \
+ -fno-stack-protector -Wno-unused -Wno-pointer-sign \
+ $(PIC_CFLAGS) -D_DEBUG $(cov_$(COV)) -I$(ARCH_DIR)/include
+
+CFLAGS+= \
+ $(CFLAGS_USPACE) -nostdinc -D__KERNEL__ -iwithprefix $(srctree)/include \
+ -DKBUILD_BASENAME=\"clnt\" -DKBUILD_MODNAME=\"nsc\" -DMODVERSIONS \
+ -DEXPORT_SYMTAB \
+ -U__FreeBSD__ -D__linux__=1 -Dlinux=1 -D__linux=1 \
+ -DCONFIG_DEFAULT_HOSTNAME=\"lib\" \
+ -I$(ARCH_DIR)/include/generated/uapi \
+ -I$(ARCH_DIR)/include/generated \
+ -I$(srctree)/include -I$(ARCH_DIR)/include/uapi \
+ -I$(srctree)/include/uapi -I$(srctree)/include/generated/uapi \
+ -include $(srctree)/include/linux/kconfig.h \
+ -I$(ARCH_DIR) -I.
+
+ifeq ($(SUBARCH),x86)
+ ifeq ($(shell uname -m),x86_64)
+ CFLAGS+= -DCONFIG_64BIT
+ endif
+endif
+
+KBUILD_CFLAGS := CFLAGS
+LDFLAGS += -shared -nodefaultlibs -g3 -Wl,-O1 -Wl,-T$(ARCH_DIR)/linker.lds $(covl_$(COV))
+
+# targets
+
+modules:=
+all-obj-for-clean:=
+
+all: library modules
+
+# note: the directory order below matters to ensure that we match the kernel order
+dirs=kernel/ kernel/time/ kernel/rcu/ kernel/locking/ kernel/bpf/ mm/ fs/ fs/proc/ crypto/ lib/ drivers/base/ drivers/net/ net/ init/
+empty:=
+space:= $(empty) $(empty)
+colon:= :
+comma= ,
+kernel/_to_keep=notifier.o params.o sysctl.o \
+rwsem.o semaphore.o kfifo.o cred.o user.o groups.o ksysfs.o
+kernel/time/_to_keep=time.o
+kernel/rcu_to_keep=rcu/srcu.o rcu/pdate.o rcu/tiny.o
+kernel/locking_to_keep=locking/mutex.o
+kernel/bpf_to_keep=bpf/core.o
+mm/_to_keep=util.o list_lru.o slib.o
+crypto/_to_keep=aead.o ahash.o shash.o api.o algapi.o cipher.o compress.o proc.o \
+crc32c_generic.o
+drivers/base/_to_keep=class.o core.o bus.o dd.o driver.o devres.o module.o map.o
+drivers/net/_to_keep=loopback.o
+lib/_to_keep=klist.o kobject.o kref.o hweight.o int_sqrt.o checksum.o \
+find_last_bit.o find_bit.o bitmap.o nlattr.o idr.o libcrc32c.o \
+ctype.o string.o kasprintf.o rbtree.o sha1.o textsearch.o vsprintf.o \
+rwsem-spinlock.o scatterlist.o ratelimit.o hexdump.o dec_and_lock.o \
+div64.o dynamic_queue_limits.o md5.o kstrtox.o iovec.o lockref.o crc32.o \
+rhashtable.o iov_iter.o cmdline.o kobject_uevent.o
+fs/_to_keep=read_write.o libfs.o namei.o filesystems.o file.o file_table.o \
+dcache.o inode.o pipe.o char_dev.o splice.o no-block.o seq_file.o super.o \
+fcntl.o coredump.o
+fs/proc/_to_keep=proc_sysctl.o proc_net.o root.o generic.o inode.o
+init/_to_keep=version.o
+
+quiet_cmd_objsmk = OBJS-MK $@
+ cmd_objsmk = \
+ for i in 1; do \
+ $(foreach d,$(dirs), \
+ $(MAKE) -i -s -f $< srcdir=$(srctree)/$(d) \
+ objdir=$(srctree)/$(d) \
+ config=$(srctree)/.config \
+ to_keep=$(subst $(space),$(colon),$($(d)_to_keep)) print;) \
+ done > $@
+
+$(ARCH_DIR)/objs.mk: $(ARCH_DIR)/Makefile.print $(srctree)/.config $(ARCH_DIR)/Makefile
+ +$(call if_changed,objsmk)
+
+quiet_cmd_linker = GEN $@
+ cmd_linker = ld -shared --verbose | ./$^ > $@
+$(ARCH_DIR)/linker.lds: $(ARCH_DIR)/generate-linker-script.py
+ $(call if_changed,linker)
+
+# calll kernel/time/Makefile
+kernel/time/timeconst.h: $(srctree)/.config
+ $(Q) $(MAKE) $(build)=kernel/time $@
+
+# call lib/Makefile
+lib/crc32table.h:
+ $(Q) $(MAKE) $(build)=lib $@
+
+# call init/Makefile
+include/generated/compile.h: asm-generic include/generated/utsrelease.h\
+ $(version_h)
+ $(Q) $(MAKE) $(build)=init $@
+
+# crafted from $(srctree)/Kbuild
+quiet_cmd_lib_bounds = GEN $@
+define cmd_lib_bounds
+ (set -e; \
+ echo "#ifndef GENERATED_BOUNDS_H"; \
+ echo "#define GENERATED_BOUNDS_H"; \
+ echo ""; \
+ echo "#define NR_PAGEFLAGS (__NR_PAGEFLAGS)"; \
+ echo "#define MAX_NR_ZONES (__MAX_NR_ZONES)"; \
+ echo ""; \
+ echo "#endif /* GENERATED_BOUNDS_H */") > $@
+endef
+
+include/generated/bounds.h:
+ $(Q)mkdir -p $(dir $@)
+ $(call cmd,lib_bounds)
+
+
+KERNEL_BUILTIN=$(addprefix $(srctree)/,$(addsuffix builtin.o,$(dirs)))
+OBJS=$(LIB_OBJ) $(foreach builtin,$(KERNEL_BUILTIN),$(if $($(builtin)),$($(builtin))))
+export OBJS KERNEL_LIB COV covl_yes covl_no
+
+quiet_cmd_cc = CC $@
+ cmd_cc = mkdir -p $(dir $@); \
+ $(CC) $(CFLAGS) -c $< -o $@
+quiet_cmd_linkko = KO $@
+ cmd_linkko = $(CC) -shared -o $@ -nostdlib $^
+quiet_cmd_builtin = BUILTIN $@
+ cmd_builtin = mkdir -p $(dir $(srctree)/$@); rm -f $(srctree)/$@; \
+ if test -n "$($(srctree)/$@)"; then for f in $($(srctree)/$@); \
+ do $(AR) Tcru $@ $$f; done; else $(AR) Tcru $@; fi
+
+%/builtin.o:
+ $(call if_changed,builtin)
+%.ko:%.o
+ $(call if_changed,linkko)
+%.o:%.c $(AUTOGENS)
+ $(call if_changed_dep,cc)
+
+library: $(KERNEL_LIB) $(LIBOS_TOOLS)
+modules: $(modules)
+
+$(LIBOS_TOOLS): $(KERNEL_LIB) Makefile FORCE
+ $(Q) if [ ! -d "$@" ]; then \
+ git clone $(LIBOS_GIT_REPO) $@ ;\
+ fi
+ $(Q) $(MAKE) -C $(LIBOS_TOOLS)
+
+install: modules library
+
+install-dir:
+
+$(KERNEL_LIB): $(ARCH_DIR)/objs.mk $(AUTOGENS) $(OBJS)
+ $(call if_changed,linklib)
+
+quiet_cmd_linklib = LIB $@
+ cmd_linklib = $(CC) -Wl,--whole-archive $(OBJS) $(LDFLAGS) -o $@; \
+ ln -s -f $(KERNEL_LIB) liblinux.so
+
+quiet_cmd_clean = CLEAN $@
+ cmd_clean = for f in $(foreach m,$(modules),$($(m))) ; do rm -f $$f 2>/dev/null; done ; \
+ for f in $(ALL_OBJS); do rm -f $$f; done 2>/dev/null ;\
+ rm -rf $(AUTOGENS) $(ARCH_DIR)/objs.mk 2>/dev/null ;\
+ if [ -d $(LIBOS_TOOLS) ]; then $(MAKE) -C $(LIBOS_TOOLS) clean ; fi
+
+archclean:
+ $(call if_changed,clean)
+
+archprepare: include/generated/bounds.h include/generated/utsrelease.h \
+ asm-generic $(version_h)
+
+test:
+ $(Q) $(MAKE) -C $(DCE_TESTDIR)/
+
+.PHONY : clean
diff --git a/arch/lib/Makefile.print b/arch/lib/Makefile.print
new file mode 100644
index 0000000..8585fc8
--- /dev/null
+++ b/arch/lib/Makefile.print
@@ -0,0 +1,45 @@
+# inherit $(objdir) $(config) $(srcdir) $(to_keep) from command-line
+
+include $(config)
+include $(srcdir)Makefile
+
+# fix minor nits for make version dependencies
+ifeq (3.82,$(firstword $(sort $(MAKE_VERSION) 3.82)))
+ SEPARATOR=
+else
+ SEPARATOR=/
+endif
+
+to_keep_list=$(subst :, ,$(to_keep))
+obj-y += $(lib-y)
+obj-m += $(lib-m)
+subdirs:=$(shell echo $(filter %/, $(obj-y) $(obj-m)) | tr ' ' '\n' | sort -u | tr '\n' ' ')
+subdirs-y := $(filter %/, $(obj-y))
+subdirs-m := $(filter %/, $(obj-m))
+tmp1-obj-y=$(patsubst %/,%/builtin.o,$(obj-y))
+tmp1-obj-m=$(filter-out $(subdirs-m),$(obj-m))
+tmp2-obj-y=$(foreach m,$(tmp1-obj-y), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp2-obj-m=$(foreach m,$(tmp1-obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(if $($(m:.o=-y)),$($(m:.o=-y)),$(m))))
+tmp3-obj-y=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-y)),$(tmp2-obj-y))
+tmp3-obj-m=$(if $(to_keep_list),$(filter $(to_keep_list),$(tmp2-obj-m)),$(tmp2-obj-m))
+final-obj-y=$(tmp3-obj-y)
+final-obj-m=$(tmp3-obj-m)
+
+print: $(final-obj-m) $(subdirs)
+ @if test $(if $(final-obj-y),1); then \
+ echo -n $(objdir)builtin.o; echo -n "="; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n $(objdir)builtin.o; echo -n ": "; echo $(addprefix $(objdir),$(final-obj-y)); \
+ echo -n "-include "; echo $(addprefix $(objdir).,$(addsuffix ".cmd", $(final-obj-y))); \
+ echo -n "all-obj-for-clean+="; echo $(addprefix $(objdir),$(final-obj-y)) $(objdir)builtin.o; \
+ fi
+$(final-obj-m):
+ @echo -n "modules+="; echo $(addprefix $(objdir),$(@:.o=.ko))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n ": "
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+ @echo -n $(addprefix $(objdir),$(@:.o=.ko)); echo -n "="
+ @echo $(addprefix $(objdir),$(if $($(@:.o=-objs)),$($(@:.o=-objs)),$@))
+$(subdirs):
+ @$(MAKE) -s -f $(firstword $(MAKEFILE_LIST)) objdir=$(objdir)$@$(SEPARATOR) config=$(config) srcdir=$(srcdir)$@$(SEPARATOR) to_keep=$(to_keep) print 2>/dev/null
+
+.PHONY : core
+.NOTPARALLEL : print $(subdirs) $(final-obj-m)
diff --git a/arch/lib/defconfig b/arch/lib/defconfig
new file mode 100644
index 0000000..9307e6f
--- /dev/null
+++ b/arch/lib/defconfig
@@ -0,0 +1,653 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux Kernel Configuration
+#
+CONFIG_LIB=y
+CONFIG_EXPERIMENTAL=y
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+# CONFIG_SMP is not set
+CONFIG_KTIME_SCALAR=y
+CONFIG_MODULES=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_PRINTK=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_NO_HZ=y
+# CONFIG_BASE_FULL is not set
+# CONFIG_SELECT_MEMORY_MODEL is not set
+# CONFIG_FLAT_NODE_MEM_MAP is not set
+# CONFIG_PAGEFLAGS_EXTENDED is not set
+# CONFIG_VIRT_TO_BUS is not set
+# CONFIG_HAS_DMA is not set
+CONFIG_HZ=250
+CONFIG_TINY_RCU=y
+CONFIG_HZ_250=y
+CONFIG_BASE_SMALL=1
+CONFIG_SPLIT_PTLOCK_CPUS=1
+CONFIG_FLATMEM=y
+CONFIG_SYSCTL=y
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=y
+CONFIG_NET_KEY=y
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE_DEMUX=y
+CONFIG_NET_IP_TUNNEL=y
+CONFIG_NET_IPGRE=y
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_NET_IPVTI is not set
+CONFIG_NET_UDP_TUNNEL=m
+# CONFIG_NET_FOU is not set
+# CONFIG_NET_FOU_IP_TUNNELS is not set
+# CONFIG_GENEVE is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+CONFIG_INET_UDP_DIAG=y
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+CONFIG_TCP_CONG_HSTCP=y
+CONFIG_TCP_CONG_HYBLA=y
+CONFIG_TCP_CONG_VEGAS=y
+CONFIG_TCP_CONG_SCALABLE=y
+CONFIG_TCP_CONG_LP=y
+CONFIG_TCP_CONG_VENO=y
+CONFIG_TCP_CONG_YEAH=y
+CONFIG_TCP_CONG_ILLINOIS=y
+CONFIG_TCP_CONG_DCTCP=y
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_HYBLA is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_VENO is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_DCTCP is not set
+CONFIG_DEFAULT_RENO=y
+CONFIG_DEFAULT_TCP_CONG="reno"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_ROUTER_PREF=y
+# CONFIG_IPV6_ROUTE_INFO is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=y
+# CONFIG_IPV6_VTI is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=y
+# CONFIG_IPV6_GRE is not set
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NET_PTP_CLASSIFY is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=m
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_ACCT=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_LOG_COMMON=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_PROCFS=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_SNMP is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NF_CT_NETLINK_TIMEOUT is not set
+CONFIG_NETFILTER_NETLINK_QUEUE_CT=y
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_NF_NAT_PROTO_DCCP=y
+CONFIG_NF_NAT_PROTO_UDPLITE=y
+CONFIG_NF_NAT_PROTO_SCTP=y
+CONFIG_NF_NAT_AMANDA=y
+CONFIG_NF_NAT_FTP=y
+# CONFIG_NF_NAT_IRC is not set
+# CONFIG_NF_NAT_SIP is not set
+# CONFIG_NF_NAT_TFTP is not set
+CONFIG_NF_NAT_REDIRECT=y
+CONFIG_NF_TABLES=y
+CONFIG_NF_TABLES_INET=y
+CONFIG_NFT_EXTHDR=y
+CONFIG_NFT_META=y
+CONFIG_NFT_CT=y
+CONFIG_NFT_RBTREE=y
+CONFIG_NFT_HASH=y
+CONFIG_NFT_COUNTER=y
+CONFIG_NFT_LOG=y
+CONFIG_NFT_LIMIT=y
+CONFIG_NFT_MASQ=y
+# CONFIG_NFT_REDIR is not set
+CONFIG_NFT_NAT=y
+# CONFIG_NFT_QUEUE is not set
+# CONFIG_NFT_REJECT is not set
+# CONFIG_NFT_REJECT_INET is not set
+# CONFIG_NFT_COMPAT is not set
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=y
+CONFIG_NETFILTER_XT_CONNMARK=y
+# CONFIG_NETFILTER_XT_SET is not set
+
+#
+# Xtables targets
+#
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+# CONFIG_NETFILTER_XT_TARGET_HMARK is not set
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_NAT=y
+CONFIG_NETFILTER_XT_TARGET_NETMAP=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_RATEEST=y
+CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
+# CONFIG_NETFILTER_XT_TARGET_TEE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_BPF is not set
+# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=y
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ECN is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_HL is not set
+# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+CONFIG_NETFILTER_XT_MATCH_L2TP=m
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set
+# CONFIG_NETFILTER_XT_MATCH_OSF is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+CONFIG_NETFILTER_XT_MATCH_SCTP=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+CONFIG_IP_SET=y
+CONFIG_IP_SET_MAX=256
+# CONFIG_IP_SET_BITMAP_IP is not set
+# CONFIG_IP_SET_BITMAP_IPMAC is not set
+# CONFIG_IP_SET_BITMAP_PORT is not set
+# CONFIG_IP_SET_HASH_IP is not set
+# CONFIG_IP_SET_HASH_IPMARK is not set
+# CONFIG_IP_SET_HASH_IPPORT is not set
+# CONFIG_IP_SET_HASH_IPPORTIP is not set
+# CONFIG_IP_SET_HASH_IPPORTNET is not set
+# CONFIG_IP_SET_HASH_MAC is not set
+# CONFIG_IP_SET_HASH_NETPORTNET is not set
+# CONFIG_IP_SET_HASH_NET is not set
+# CONFIG_IP_SET_HASH_NETNET is not set
+# CONFIG_IP_SET_HASH_NETPORT is not set
+# CONFIG_IP_SET_HASH_NETIFACE is not set
+# CONFIG_IP_SET_LIST_SET is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_NF_LOG_ARP is not set
+CONFIG_NF_LOG_IPV4=y
+CONFIG_NF_TABLES_IPV4=y
+CONFIG_NFT_CHAIN_ROUTE_IPV4=y
+# CONFIG_NF_REJECT_IPV4 is not set
+# CONFIG_NFT_REJECT_IPV4 is not set
+# CONFIG_NF_TABLES_ARP is not set
+# CONFIG_NF_NAT_IPV4 is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_TARGET_SYNPROXY is not set
+# CONFIG_IP_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_NF_TABLES_IPV6=y
+# CONFIG_NFT_CHAIN_ROUTE_IPV6 is not set
+# CONFIG_NF_REJECT_IPV6 is not set
+# CONFIG_NFT_REJECT_IPV6 is not set
+CONFIG_NF_LOG_IPV6=y
+# CONFIG_NF_NAT_IPV6 is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+
+#
+# DECnet: Netfilter Configuration
+#
+# CONFIG_DECNET_NF_GRABULATOR is not set
+# CONFIG_NF_TABLES_BRIDGE is not set
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_IP_DCCP=y
+CONFIG_INET_DCCP_DIAG=y
+
+#
+# DCCP CCIDs Configuration
+#
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=y
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_TFRC_LIB=y
+CONFIG_IP_SCTP=y
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1 is not set
+CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE=y
+# CONFIG_SCTP_COOKIE_HMAC_MD5 is not set
+# CONFIG_SCTP_COOKIE_HMAC_SHA1 is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
+CONFIG_L2TP=m
+# CONFIG_L2TP_V3 is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+# CONFIG_BRIDGE_VLAN_FILTERING is not set
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_VLAN_8021Q_MVRP is not set
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+CONFIG_IPX_INTERN=y
+CONFIG_ATALK=m
+CONFIG_DEV_APPLETALK=m
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+CONFIG_PHONET=m
+# CONFIG_6LOWPAN is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_VSOCKETS is not set
+# CONFIG_NETLINK_MMAP is not set
+# CONFIG_NETLINK_DIAG is not set
+# CONFIG_NET_MPLS_GSO is not set
+# CONFIG_HSR is not set
+# CONFIG_NET_SWITCHDEV is not set
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_GW=m
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=m
+CONFIG_CAN_DEV=m
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_SJA1000=m
+# CONFIG_CAN_SJA1000_ISA is not set
+CONFIG_CAN_SJA1000_PLATFORM=m
+# CONFIG_CAN_C_CAN is not set
+# CONFIG_CAN_M_CAN is not set
+# CONFIG_CAN_CC770 is not set
+# CONFIG_CAN_SOFTING is not set
+CONFIG_CAN_DEBUG_DEVICES=y
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+
+#
+# Dongle support
+#
+
+#
+# FIR device drivers
+#
+CONFIG_BT=m
+CONFIG_BT_BREDR=y
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_LE=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIVHCI=m
+CONFIG_BT_MRVL=m
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+CONFIG_WIMAX=m
+CONFIG_WIMAX_DEBUG_LEVEL=8
+CONFIG_RFKILL=m
+# CONFIG_NET_9P is not set
+CONFIG_CAIF=m
+CONFIG_CAIF_DEBUG=y
+CONFIG_CAIF_NETDEV=m
+# CONFIG_CAIF_USB is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER=y
+CONFIG_UEVENT_HELPER_PATH=""
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_FW_LOADER_USER_HELPER_FALLBACK is not set
+CONFIG_ALLOW_DEV_COREDUMP=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+# CONFIG_DMA_SHARED_BUFFER is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+# CONFIG_CRYPTO_MCRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_CMAC=m
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+# CONFIG_CRYPTO_CRC32 is not set
+CONFIG_CRYPTO_CRCT10DIF=m
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_BLOWFISH_COMMON=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST_COMMON=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+# CONFIG_CRYPTO_LZ4 is not set
+# CONFIG_CRYPTO_LZ4HC is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_DRBG_MENU is not set
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_IO=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC_T10DIF=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+CONFIG_CRC7=m
+CONFIG_LIBCRC32C=y
+# CONFIG_CRC8 is not set
+# CONFIG_AUDIT_ARCH_COMPAT_GENERIC is not set
+# CONFIG_RANDOM32_SELFTEST is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
diff --git a/arch/lib/generate-linker-script.py b/arch/lib/generate-linker-script.py
new file mode 100755
index 0000000..db3d7f8
--- /dev/null
+++ b/arch/lib/generate-linker-script.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+import re
+
+def linker_script(reading, writing):
+ delim = re.compile('^==')
+ end_of_ro = re.compile('^ *.gcc_except_table[^:]*:[ ]*ONLY_IF_RW')
+ skipping = True
+ for line in reading.readlines():
+ if delim.search (line) is not None:
+ if skipping:
+ skipping = False
+ continue
+ else:
+ skipping = True
+ if skipping:
+ continue
+ m = end_of_ro.search(line)
+ if m is not None:
+ skipping = False
+ initcall = """
+ /* taken from kernel script*/
+ . = ALIGN (CONSTANT (MAXPAGESIZE));
+ .initcall.init : AT(ADDR(.initcall.init)) {
+ __initcall_start = .;
+ *(.initcallearly.init)
+ *(.initcall0.init)
+ *(.initcall0s.init)
+ *(.initcall1.init)
+ *(.initcall1s.init)
+ *(.initcall2.init)
+ *(.initcall2s.init)
+ *(.initcall3.init)
+ *(.initcall3s.init)
+ *(.initcall4.init)
+ *(.initcall4s.init)
+ *(.initcall5.init)
+ *(.initcall5s.init)
+ *(.initcall6.init)
+ *(.initcall6s.init)
+ *(.initcall7.init)
+ *(.initcall7s.init)
+ __initcall_end = .;
+ }
+"""
+ writing.write (initcall)
+ writing.write(line)
+
+import sys
+linker_script (sys.stdin, sys.stdout)
--
2.1.0
These auxiliary files are used for testing and debugging of net/ code
with libos. a simple test is implemented with make test ARCH=lib.
Signed-off-by: Hajime Tazaki <[email protected]>
---
tools/testing/libos/.gitignore | 6 +++++
tools/testing/libos/Makefile | 38 +++++++++++++++++++++++++++
tools/testing/libos/README | 15 +++++++++++
tools/testing/libos/bisect.sh | 10 +++++++
tools/testing/libos/dce-test.sh | 23 ++++++++++++++++
tools/testing/libos/nuse-test.sh | 57 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 149 insertions(+)
create mode 100644 tools/testing/libos/.gitignore
create mode 100644 tools/testing/libos/Makefile
create mode 100644 tools/testing/libos/README
create mode 100755 tools/testing/libos/bisect.sh
create mode 100755 tools/testing/libos/dce-test.sh
create mode 100755 tools/testing/libos/nuse-test.sh
diff --git a/tools/testing/libos/.gitignore b/tools/testing/libos/.gitignore
new file mode 100644
index 0000000..57a74a0
--- /dev/null
+++ b/tools/testing/libos/.gitignore
@@ -0,0 +1,6 @@
+*.pcap
+files-*
+bake
+buildtop
+core
+exitprocs
diff --git a/tools/testing/libos/Makefile b/tools/testing/libos/Makefile
new file mode 100644
index 0000000..3da25429
--- /dev/null
+++ b/tools/testing/libos/Makefile
@@ -0,0 +1,38 @@
+ADD_PARAM?=
+
+all: test
+
+bake:
+ hg clone http://code.nsnam.org/bake
+
+check_pkgs:
+ @./bake/bake.py check | grep Bazaar | grep OK || (echo "bzr is missing" && ./bake/bake.py check)
+ @./bake/bake.py check | grep autoreconf | grep OK || (echo "autotools is missing" && ./bake/bake.py check && exit 1)
+
+testbin: bake check_pkgs
+ @cp ../../../arch/lib/tools/bakeconf-linux.xml bake/bakeconf.xml
+ @mkdir -p buildtop/build/bin_dce
+ cd buildtop ; \
+ ../bake/bake.py configure -e dce-linux-inkernel $(BAKECONF_PARAMS)
+ cd buildtop ; \
+ ../bake/bake.py show --enabledTree | grep -v -E "pygoocanvas|graphviz|python-dev" | grep Missing && (echo "required packages are missing") || echo ""
+ cd buildtop ; \
+ ../bake/bake.py download ; \
+ ../bake/bake.py update ; \
+ ../bake/bake.py build
+
+test:
+ @./dce-test.sh ADD_PARAM=$(ADD_PARAM)
+
+test-valgrind:
+ @./dce-test.sh -g ADD_PARAM=$(ADD_PARAM)
+
+test-fault-injection:
+ @./dce-test.sh -f ADD_PARAM=$(ADD_PARAM)
+
+clean:
+# @rm -rf buildtop
+ @rm -f *.pcap
+ @rm -rf files-*
+ @rm -f exitprocs
+ @rm -f core
diff --git a/tools/testing/libos/README b/tools/testing/libos/README
new file mode 100644
index 0000000..51ac5a5
--- /dev/null
+++ b/tools/testing/libos/README
@@ -0,0 +1,15 @@
+
+- bisect.sh
+a sample script to bisect an issue of network stack code with the help
+of LibOS (and ns-3 network simulator). This was used to detect the issue
+for the following patch.
+
+http://patchwork.ozlabs.org/patch/436351/
+
+- dce-test.sh
+a test script invoked by 'make test ARCH=lib'. The contents of test
+scenario are implemented as test suites of ns-3 network simulator.
+
+- nuse-test.sh
+a simple test script for Network Stack in Userspace (NUSE).
+
diff --git a/tools/testing/libos/bisect.sh b/tools/testing/libos/bisect.sh
new file mode 100755
index 0000000..9377ac3
--- /dev/null
+++ b/tools/testing/libos/bisect.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+git merge origin/nuse --no-commit
+make clean ARCH=lib
+make library ARCH=lib OPT=no
+make test ARCH=lib ADD_PARAM=" -s dce-umip"
+RET=$?
+git reset --hard
+
+exit $RET
diff --git a/tools/testing/libos/dce-test.sh b/tools/testing/libos/dce-test.sh
new file mode 100755
index 0000000..e81e2d8
--- /dev/null
+++ b/tools/testing/libos/dce-test.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+#set -x
+export LD_LOG=symbol-fail
+#VERBOSE="-v"
+VALGRIND=""
+FAULT_INJECTION=""
+
+if [ "$1" = "-g" ] ; then
+ VALGRIND="-g"
+# Not implemneted yet.
+#elif [ "$1" = "-f" ] ; then
+# FAULT_INJECTION="-f"
+fi
+
+# FIXME
+#export NS_ATTRIBUTE_DEFAULT='ns3::DceManagerHelper::LoaderFactory=ns3::\
+#DlmLoaderFactory[];ns3::TaskManager::FiberManagerType=UcontextFiberManager'
+
+cd buildtop/source/ns-3-dce
+LD_LIBRARY_PATH=${srctree} ./test.py -n ${VALGRIND} ${FAULT_INJECTION}\
+ ${VERBOSE} ${ADD_PARAM}
diff --git a/tools/testing/libos/nuse-test.sh b/tools/testing/libos/nuse-test.sh
new file mode 100755
index 0000000..198e7e4
--- /dev/null
+++ b/tools/testing/libos/nuse-test.sh
@@ -0,0 +1,57 @@
+#!/bin/bash -e
+
+LIBOS_TOOLS=arch/lib/tools
+
+IFNAME=`ip route |grep default | awk '{print $5}'`
+GW=`ip route |grep default | awk '{print $3}'`
+#XXX
+IPADDR=`echo $GW | sed -r "s/([0-9]+\.[0-9]+\.[0-9]+\.)([0-9]+)$/\1\`expr \2 + 10\`/"`
+
+# ip route
+# ip address
+# ip link
+
+NUSE_CONF=/tmp/nuse.conf
+
+cat > ${NUSE_CONF} << ENDCONF
+
+interface ${IFNAME}
+ address ${IPADDR}
+ netmask 255.255.255.0
+ macaddr 00:01:01:01:01:02
+ viftype RAW
+
+route
+ network 0.0.0.0
+ netmask 0.0.0.0
+ gateway ${GW}
+
+ENDCONF
+
+cd ${LIBOS_TOOLS}
+sudo NUSECONF=${NUSE_CONF} ./nuse ping 127.0.0.1 -c 2
+
+# rump test
+sudo NUSECONF=${NUSE_CONF} ./nuse sleep 5 &
+
+sleep 2
+PID_SLEEP=`/bin/ls -ltr /tmp/rump-server-nuse.* | tail -1 | awk '{print $9}' | sed -e "s/.*rump-server-nuse\.//g" | sed "s/=//"`
+RUMP_URL=unix:///tmp/rump-server-nuse.$PID_SLEEP
+# ls -ltr /tmp/*
+
+sudo chmod 777 /tmp/rump-server-nuse.$PID_SLEEP
+LD_PRELOAD=./libnuse-hijack.so RUMPHIJACK=socket=all \
+ RUMP_SERVER=$RUMP_URL ip addr show
+
+wait %1
+
+if [ "$1" == "--extended" ] ; then
+sudo NUSECONF=${NUSE_CONF} ./nuse ping ${GW} -c 2
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 2000 -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse iperf -c ${GW} -p 8 -u -t 3
+sudo NUSECONF=${NUSE_CONF} ./nuse dig http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse host http://www.google.com
+sudo NUSECONF=${NUSE_CONF} ./nuse nslookup http://www.google.com
+#sudo NUSECONF=${NUSE_CONF} ./nuse nc http://www.google.com 80
+sudo NUSECONF=${NUSE_CONF} ./nuse wget http://www.google.com -O -
+fi
--
2.1.0