aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Bucur <stefanb@zytor.com>2008-06-09 17:55:57 +0300
committerStefan Bucur <stefanb@zytor.com>2008-06-09 17:55:57 +0300
commite4642a4d0fac67f22e2e63cbcaea915c507e241e (patch)
tree7457b6fd2d29401b73d4780497fb0a45a5ac3954
parent80a1747d4b8c5149af0c6101fa5110dcda85d2fe (diff)
downloadsyslinux-elf-e4642a4d0fac67f22e2e63cbcaea915c507e241e.tar.gz
syslinux-elf-e4642a4d0fac67f22e2e63cbcaea915c507e241e.tar.xz
syslinux-elf-e4642a4d0fac67f22e2e63cbcaea915c507e241e.zip
Created the basic module infrastructure.
-rw-r--r--elf/Makefile29
-rw-r--r--elf/elf_module.c211
-rw-r--r--elf/elf_module.h58
-rw-r--r--elf/elftest.c88
-rw-r--r--elf/hello.c13
-rw-r--r--elf/linux_list.h450
6 files changed, 785 insertions, 64 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 3c793d65..0cab8eab 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1,37 +1,52 @@
## License would go here
+########
# Tools
CC = gcc
RM = rm -f
-
+################
# Build options
-CFLAGS = -Wall
+CFLAGS = -Wall -DELF_USERSPACE_TEST
LDFLAGS =
-
+##################
# Generated files
# Test executable name
TESTPROG = elftest
+# Test module name
+TESTMODULE = hello.so
+###############
# Make targets
-.PHONY: all test clean
+.PHONY: all test-prog test-module clean
+
+all: test-prog test-module
-all: test
-test: $(TESTPROG)
+# The testing user-space application
+test-prog: $(TESTPROG)
-$(TESTPROG): elftest.o
+$(TESTPROG): elftest.o elf_module.o
$(CC) -o $@ $^
+
+# The shared module to test on
+test-module: $(TESTMODULE)
+
+$(TESTMODULE): hello.o
+ $(CC) -shared -o $@ $^
+
+# Cleanup target
clean:
-$(RM) *.o
-$(RM) $(TESTPROG)
+ -$(RM) $(TESTMODULE)
diff --git a/elf/elf_module.c b/elf/elf_module.c
new file mode 100644
index 00000000..de5a311a
--- /dev/null
+++ b/elf/elf_module.c
@@ -0,0 +1,211 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+
+#ifdef ELF_USERSPACE_TEST
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#endif //ELF_USERSPACE_TEST
+
+#include "linux_list.h"
+#include "elf_module.h"
+
+
+// The list of loaded modules
+static LIST_HEAD(modules);
+
+
+// User-space debugging routines
+#ifdef ELF_USERSPACE_TEST
+static void print_elf_ehdr(Elf32_Ehdr *ehdr) {
+ int i;
+
+ printf("Identification:\t");
+ for (i=0; i < EI_NIDENT; i++) {
+ printf("%d ", ehdr->e_ident[i]);
+ }
+ printf("\n");
+ printf("Type:\t\t%u\n", ehdr->e_type);
+ printf("Machine:\t%u\n", ehdr->e_machine);
+ printf("Version:\t%u\n", ehdr->e_version);
+ printf("Entry:\t\t0x%08x\n", ehdr->e_entry);
+ printf("PHT Offset:\t0x%08x\n", ehdr->e_phoff);
+ printf("SHT Offset:\t0x%08x\n", ehdr->e_shoff);
+ printf("Flags:\t\t%u\n", ehdr->e_flags);
+ printf("Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,
+ sizeof(Elf32_Ehdr));
+}
+#endif //ELF_USERSPACE_TEST
+
+#ifdef ELF_USERSPACE_TEST
+static int load_image(struct elf_module *module) {
+ char file_name[MODULE_NAME_SIZE+3]; // Include the extension
+ struct stat elf_stat;
+
+ strcpy(file_name, module->name);
+ strcat(file_name, ".so");
+
+ module->file_fd = open(file_name, O_RDONLY);
+
+ if (module->file_fd < 0) {
+ perror("Could not open object file");
+ goto error;
+ }
+
+ if (fstat(module->file_fd, &elf_stat) < 0) {
+ perror("Could not get file information");
+ goto error;
+ }
+
+ module->file_size = elf_stat.st_size;
+
+ module->file_image = mmap(NULL, module->file_size, PROT_READ, MAP_PRIVATE,
+ module->file_fd, 0);
+
+ if (module->file_image == NULL) {
+ perror("Could not map the file into memory");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ if (module->file_image != NULL) {
+ munmap(module->file_image, module->file_size);
+ module->file_image = NULL;
+ }
+
+ if (module->file_fd > 0) {
+ close(module->file_fd);
+ module->file_fd = 0;
+ }
+ return -1;
+}
+
+
+static int unload_image(struct elf_module *module) {
+ munmap(module->file_image, module->file_size);
+ module->file_image = NULL;
+
+ close(module->file_fd);
+ module->file_fd = 0;
+
+ return 0;
+}
+
+
+#else
+static int load_image(struct elf_module *module) {
+ // TODO: Implement SYSLINUX specific code here
+ return 0;
+}
+
+static int unload_image(struct elf_module *module) {
+ // TODO: Implement SYSLINUX specific code here
+ return 0;
+}
+#endif //ELF_USERSPACE_TEST
+
+
+// Initialization of the module subsystem
+int modules_init() {
+ return 0;
+}
+
+// Termination of the module subsystem
+void modules_term() {
+
+}
+
+// Allocates the structure for a new module
+struct elf_module *module_alloc(const char *name) {
+ struct elf_module *result = malloc(sizeof(struct elf_module));
+
+ memset(result, 0, sizeof(struct elf_module));
+
+ strncpy(result->name, name, MODULE_NAME_SIZE);
+
+ return result;
+}
+
+static int check_header(Elf32_Ehdr *elf_hdr) {
+
+ // Check the header magic
+ if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
+
+ fprintf(stderr, "Invalid ELF magic\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
+ fprintf(stderr, "Invalid ELF class code\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
+ fprintf(stderr, "Invalid ELF data encoding\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION) {
+ fprintf(stderr, "Invalid ELF file version\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+// Loads the module into the system
+int module_load(struct elf_module *module) {
+ int res;
+ Elf32_Ehdr *elf_hdr;
+
+ INIT_LIST_HEAD(&module->list);
+ INIT_LIST_HEAD(&module->deps);
+
+ res = load_image(module);
+
+ if (res < 0) {
+ return res;
+ }
+
+ elf_hdr = (Elf32_Ehdr*)module->file_image;
+
+ res = check_header(elf_hdr);
+
+ if (res < 0) {
+ goto error;
+ }
+
+ print_elf_ehdr(elf_hdr);
+
+ res = unload_image(module);
+
+ if (res < 0) {
+ return res;
+ }
+
+ return 0;
+
+error:
+ unload_image(module);
+
+ return res;
+}
+
+// Unloads the module from the system and releases all the associated memory
+int module_unload(struct elf_module *module) {
+
+ free(module);
+
+ return 0;
+}
diff --git a/elf/elf_module.h b/elf/elf_module.h
new file mode 100644
index 00000000..fd0e15c5
--- /dev/null
+++ b/elf/elf_module.h
@@ -0,0 +1,58 @@
+#ifndef ELF_MODULE_H_
+#define ELF_MODULE_H_
+
+#include <elf.h>
+#include <stdint.h>
+#include "linux_list.h"
+
+#define MODULE_NAME_SIZE 64
+
+#define MODULE_ELF_CLASS ELFCLASS32
+#define MODULE_ELF_DATA ELFDATA2LSB
+#define MODULE_ELF_VERSION EV_CURRENT
+
+
+typedef int (*module_init_func)();
+typedef void (*module_exit_func)();
+
+// Structure encapsulating a module loaded in memory
+struct elf_module {
+ char name[MODULE_NAME_SIZE]; // The module name
+
+ struct list_head deps; // Head of module dependency list
+ struct list_head list; // The list entry in the module list
+
+ module_init_func init_func; // The initialization entry point
+ module_exit_func exit_func; // The module finalization code
+
+ void *file_image; // The image of the module file in memory
+ uint32_t file_size; // The size of the module file
+
+ // Information for modules loaded in user space
+#ifdef ELF_USERSPACE_TEST
+ int file_fd; // The file descriptor of the open file
+#endif
+};
+
+// Structure encapsulating a module dependency need
+struct module_dep {
+ struct list_head list; // The list entry in the dependency list
+
+ char name[MODULE_NAME_SIZE]; // The name of the module
+};
+
+// Initialization of the module subsystem
+extern int modules_init();
+// Termination of the module subsystem
+extern void modules_term();
+
+// Allocates the structure for a new module
+extern struct elf_module *module_alloc(const char *name);
+
+// Loads the module into the system
+extern int module_load(struct elf_module *module);
+
+// Unloads the module from the system and releases all the associated memory
+extern int module_unload(struct elf_module *module);
+
+#endif /*ELF_MODULE_H_*/
diff --git a/elf/elftest.c b/elf/elftest.c
index 5436b40e..6462ad6a 100644
--- a/elf/elftest.c
+++ b/elf/elftest.c
@@ -7,84 +7,58 @@
#include <fcntl.h>
#include <unistd.h>
-#include <elf.h>
+#include "elf_module.h"
void print_usage() {
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\telftest objfile\n");
}
-void print_elf_info(const char *file_name) {
- int elf_fd = open(file_name, O_RDONLY);
- void *elf_addr = NULL;
- Elf32_Ehdr *elf_header;
- struct stat elf_stat;
- int i;
+int main(int argc, char **argv) {
+ int res;
+ struct elf_module *module;
+ const char *module_name = NULL;
- if (elf_fd < 0) {
- perror("Could not open object file");
- goto error;
+ // Skip program name
+ argc--;
+ argv++;
+
+ if (argc != 1) {
+ print_usage();
+ return 1;
}
- if (fstat(elf_fd, &elf_stat) < 0) {
- perror("Could not get file information");
- goto error;
+ module_name = argv[0];
+
+ res = modules_init();
+
+ if (res < 0) {
+ fprintf(stderr, "Could not initialize module subsystem\n");
+ exit(1);
}
- elf_addr = mmap(NULL, elf_stat.st_size, PROT_READ, MAP_PRIVATE, elf_fd, 0);
+ module = module_alloc(module_name);
- if (elf_addr == NULL) {
- perror("Could not map the file into memory");
+ if (module == NULL) {
+ fprintf(stderr, "Could not allocate the module\n");
goto error;
}
- elf_header = (Elf32_Ehdr*)elf_addr;
+ res = module_load(module);
- printf("Identification:\t");
- for (i=0; i < EI_NIDENT; i++) {
- printf("%d ", elf_header->e_ident[i]);
+ if (res < 0) {
+ fprintf(stderr, "Could not load the module\n");
+ goto error;
}
- printf("\n");
- printf("Type:\t\t%u\n", elf_header->e_type);
- printf("Machine:\t%u\n", elf_header->e_machine);
- printf("Version:\t%u\n", elf_header->e_version);
- printf("Entry:\t\t0x%08x\n", elf_header->e_entry);
- printf("PHT Offset:\t0x%08x\n", elf_header->e_phoff);
- printf("SHT Offset:\t0x%08x\n", elf_header->e_shoff);
- printf("Flags:\t\t%u\n", elf_header->e_flags);
- printf("Header size:\t%u (Structure size: %u)\n", elf_header->e_ehsize,
- sizeof(Elf32_Ehdr));
+ module_unload(module);
- munmap(elf_addr, elf_stat.st_size);
- close(elf_fd);
+ modules_term();
- return;
+ return 0;
error:
- if (elf_addr != NULL)
- munmap(elf_addr, elf_stat.st_size);
-
- if (elf_fd >= 0)
- close(elf_fd);
- exit(2);
-}
-
-int main(int argc, char **argv) {
- const char *file_name = NULL;
-
- // Skip program name
- argc--;
- argv++;
+ modules_term();
- if (argc != 1) {
- print_usage();
- return 1;
- }
-
- file_name = argv[0];
-
- print_elf_info(file_name);
-
- return 0;
+ return 1;
}
diff --git a/elf/hello.c b/elf/hello.c
new file mode 100644
index 00000000..d7b46c04
--- /dev/null
+++ b/elf/hello.c
@@ -0,0 +1,13 @@
+// A simple Hello World ELF module
+
+// TODO: Define some macros that would put the initialization and termination
+// functions in a separate section (suggestion: .init and .fini)
+
+int hello_init() {
+ // Do nothing
+ return 0;
+}
+
+void hello_exit() {
+ // Do nothing
+}
diff --git a/elf/linux_list.h b/elf/linux_list.h
new file mode 100644
index 00000000..73c56869
--- /dev/null
+++ b/elf/linux_list.h
@@ -0,0 +1,450 @@
+// This list structure implementation is adapted from the list implementation
+// on the Linux kernel.
+
+// Original source:
+// http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.25.y.git;a=blob_plain;f=include/linux/list.h;hb=HEAD
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#include <stdlib.h>
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = NULL;
+ entry->prev = NULL;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+ for (pos = (head)->prev, n = pos->prev; \
+ prefetch(pos->prev), pos != (head); \
+ pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
+ prefetch(pos->member.prev), &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; prefetch(pos->member.next), &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+
+#endif