aboutsummaryrefslogtreecommitdiff
path: root/kernel/include/util
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/include/util')
-rw-r--r--kernel/include/util/atomic.h31
-rw-r--r--kernel/include/util/bits.h27
-rw-r--r--kernel/include/util/debug.h305
-rw-r--r--kernel/include/util/delay.h73
-rw-r--r--kernel/include/util/gdb.h5
-rw-r--r--kernel/include/util/init.h21
-rw-r--r--kernel/include/util/list.h224
-rw-r--r--kernel/include/util/printf.h87
-rw-r--r--kernel/include/util/string.h93
-rw-r--r--kernel/include/util/time.h25
-rw-r--r--kernel/include/util/timer.h28
11 files changed, 919 insertions, 0 deletions
diff --git a/kernel/include/util/atomic.h b/kernel/include/util/atomic.h
new file mode 100644
index 0000000..2c67e38
--- /dev/null
+++ b/kernel/include/util/atomic.h
@@ -0,0 +1,31 @@
+#ifndef ATOMIC_H
+#define ATOMIC_H
+
+typedef int atomic_t;
+
+#define ATOMIC_INIT(i) (i)
+
+static inline int __atomic_add_unless(atomic_t *a, int v, int u)
+{
+ int c, old;
+ c = __sync_fetch_and_add(a, 0);
+ while (c != u && (old = __sync_val_compare_and_swap(a, c, c + v)) != c)
+ c = old;
+ return c;
+}
+
+static inline void atomic_set(atomic_t *a, int i) { *a = i; }
+
+static inline void atomic_inc(atomic_t *a) { __sync_add_and_fetch(a, 1); }
+
+static inline int atomic_dec_and_test(atomic_t *a)
+{
+ return __sync_sub_and_fetch(a, 1) == 0;
+}
+
+static inline int atomic_inc_not_zero(atomic_t *a)
+{
+ return __atomic_add_unless(a, 1, 0);
+}
+
+#endif \ No newline at end of file
diff --git a/kernel/include/util/bits.h b/kernel/include/util/bits.h
new file mode 100644
index 0000000..d328574
--- /dev/null
+++ b/kernel/include/util/bits.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "kernel.h"
+#include "types.h"
+
+#define BIT(n) (1 << (n))
+
+static inline void bit_flip(void *addr, uintptr_t bit)
+{
+ uint32_t *map = (uint32_t *)addr;
+ map += (bit >> 5);
+ *map ^= (uint32_t)(1 << (bit & 0x1f));
+}
+
+static inline int bit_check(const void *addr, uintptr_t bit)
+{
+ const uint32_t *map = (const uint32_t *)addr;
+ map += (bit >> 5);
+ return (*map & (1 << (bit & 0x1f)));
+}
+
+#define MOD_POW_2(x, y) ((x) & ((y)-1))
+
+#define IS_POW_2(x) (!MOD_POW_2(x, x))
+
+#define SELECT(condition, trueval, falseval) \
+ (!!(condition) * (trueval) + !condition * (falseval))
diff --git a/kernel/include/util/debug.h b/kernel/include/util/debug.h
new file mode 100644
index 0000000..7e6eb91
--- /dev/null
+++ b/kernel/include/util/debug.h
@@ -0,0 +1,305 @@
+#pragma once
+
+#include "globals.h"
+#include "main/interrupt.h"
+#include "mm/page.h"
+#include "proc/spinlock.h"
+#include "types.h"
+#include <main/apic.h>
+
+/* How to create new dbg modes:
+ *
+ * 1) Add a new '#define DBG_NAME DBG_MODE(number)' down below. Make sure the
+ * number you choose is not already being used and is less than 64.
+ * 2) Add a new entry into the DBG_TAB below. Make sure it is above the entry
+ * for "all". The first entry should be the name you want to use to
+ * disable/enable it in the makefile, the second should be the #define'd
+ * name you gave it in step 1 and the third should be a color from the list
+ * directly below this comment. Make sure you include the '\' at the end of
+ * the line with the new entry.
+ *
+ */
+
+/*
+ * These color definitions are from the ANSI specs.
+ * Do a web search for ANSI color codes to find out
+ * more funky shit like this
+ */
+
+#define _NORMAL_ "\x1b[0m"
+#define _BLACK_ "\x1b[30;47m"
+#define _RED_ "\x1b[31;40m"
+#define _GREEN_ "\x1b[32;40m"
+#define _YELLOW_ "\x1b[33;40m"
+#define _BLUE_ "\x1b[34;40m"
+#define _MAGENTA_ "\x1b[35;40m"
+#define _CYAN_ "\x1b[36;40m"
+#define _WHITE_ "\x1b[37;40m"
+
+#define _BRED_ "\x1b[1;31;40m"
+#define _BGREEN_ "\x1b[1;32;40m"
+#define _BYELLOW_ "\x1b[1;33;40m"
+#define _BBLUE_ "\x1b[1;34;40m"
+#define _BMAGENTA_ "\x1b[1;35;40m"
+#define _BCYAN_ "\x1b[1;36;40m"
+#define _BWHITE_ "\x1b[1;37;40m"
+
+#define DBG_MODE(x) (1ULL << (x))
+
+/* These defines list all of the possible debugging
+ * types. They are flags, so make sure to use the
+ * DBG_MODE macro to declare new values. */
+#define DBG_ALL (~0ULL) /* umm, "verbose" */
+#define DBG_CORE DBG_MODE(0) /* core boot code */
+#define DBG_MM DBG_MODE(1) /* memory management */
+#define DBG_INIT DBG_MODE(2) /* boot/init code */
+#define DBG_SCHED DBG_MODE(3) /* swtch, scheduling */
+#define DBG_DISK DBG_MODE(4) /* disk driver */
+#define DBG_TEMP DBG_MODE(5) /* for resolving temporary problems */
+#define DBG_KMALLOC DBG_MODE(6) /* kmalloc, kmem_cache_alloc */
+#define DBG_PAGEALLOC DBG_MODE(7) /* page_alloc, etc. */
+#define DBG_INTR DBG_MODE(8) /* misc. trap/interrupt */
+#define DBG_TERM DBG_MODE(9) /* the terminal device */
+#define DBG_FORK DBG_MODE(10) /* fork(2) */
+#define DBG_PROC DBG_MODE(11) /* process stuff */
+#define DBG_VNREF DBG_MODE(12) /* vnode reference counts */
+#define DBG_PFRAME DBG_MODE(13) /* pframe subsys */
+#define DBG_ERROR DBG_MODE(14) /* error conditions */
+#define DBG_SYSCALL DBG_MODE(15) /* system calls */
+#define DBG_FREF DBG_MODE(16) /* file reference counts */
+#define DBG_PGTBL DBG_MODE(17) /* page table manipulation */
+#define DBG_BRK DBG_MODE(18) /* process break; user memory alloc */
+#define DBG_EXEC DBG_MODE(19) /* new process exec */
+#define DBG_VFS DBG_MODE(20) /* vfs */
+#define DBG_S5FS DBG_MODE(21) /* system V file system */
+#define DBG_KB DBG_MODE(22) /* keyboard */
+#define DBG_THR DBG_MODE(23) /* thread stuff */
+#define DBG_PRINT DBG_MODE(24) /* printdbg.c */
+#define DBG_OSYSCALL DBG_MODE(25) /* other system calls */
+#define DBG_VM DBG_MODE(28) /* VM */
+#define DBG_TEST DBG_MODE(30) /* for testing code */
+#define DBG_TESTPASS DBG_MODE(31) /* for testing code */
+#define DBG_TESTFAIL DBG_MODE(32) /* for testing code */
+
+#define DBG_MEMDEV DBG_MODE(33) /* For memory devices ("null" and "zero") */
+#define DBG_ANON DBG_MODE(34) /* anonymous vm objects */
+#define DBG_VMMAP DBG_MODE(35) /* vm area mappings */
+#define DBG_ELF DBG_MODE(37) /* elf loader */
+#define DBG_USER DBG_MODE(38) /* user land */
+#define DBG_DEFAULT DBG_ERROR /* default modes, 0 for none */
+
+/* This defines the name that is used in the
+ * environment variable to turn on the given
+ * debugging type, along with the color of the debug type */
+/* NOTE that there is an order to these objects - the color chosen for a
+ * debug statement with multiple DBG specifiers will be the first matching
+ * result in the table */
+/* Note that rearranging the table will affect results, and may be beneficial
+ * later */
+#define DBG_TAB \
+ /* General */ \
+ {"error", DBG_ERROR, _BWHITE_}, {"temp", DBG_TEMP, _NORMAL_}, \
+ {"print", DBG_PRINT, _NORMAL_}, {"test", DBG_TEST, _RED_}, \
+ {"testpass", DBG_TESTPASS, _GREEN_}, \
+ {"testfail", DBG_TESTFAIL, _RED_}, /* Kern 1 */ \
+ {"proc", DBG_PROC, _BLUE_}, {"thr", DBG_THR, _CYAN_}, \
+ {"sched", DBG_SCHED, _GREEN_}, \
+ {"init", DBG_INIT, _NORMAL_}, /* Kern 2 */ \
+ {"term", DBG_TERM, _BMAGENTA_}, {"disk", DBG_DISK, _YELLOW_}, \
+ {"memdev", DBG_MEMDEV, _BBLUE_}, /* VFS */ \
+ {"vfs", DBG_VFS, _WHITE_}, {"fref", DBG_FREF, _MAGENTA_}, \
+ {"vnref", DBG_VNREF, _CYAN_}, /* S5FS */ \
+ {"s5fs", DBG_S5FS, _BRED_}, \
+ {"pframe", DBG_PFRAME, _BMAGENTA_}, /* VM */ \
+ {"anon", DBG_ANON, _WHITE_}, {"vmmap", DBG_VMMAP, _BGREEN_}, \
+ {"fork", DBG_FORK, _BYELLOW_}, {"brk", DBG_BRK, _YELLOW_}, \
+ {"exec", DBG_EXEC, _BRED_}, {"elf", DBG_ELF, _BGREEN_}, \
+ {"pgtbl", DBG_PGTBL, _BBLUE_}, {"osyscall", DBG_OSYSCALL, _BMAGENTA_}, \
+ {"vm", DBG_VM, _RED_}, /* Syscalls (VFS - VM) */ \
+ {"syscall", DBG_SYSCALL, _RED_}, /* support code */ \
+ {"intr", DBG_INTR, _BRED_}, {"kmalloc", DBG_KMALLOC, _MAGENTA_}, \
+ {"pagealloc", DBG_PAGEALLOC, _WHITE_}, {"kb", DBG_KB, _BLUE_}, \
+ {"core", DBG_CORE, _GREEN_}, {"mm", DBG_MM, _RED_}, \
+ {"user", DBG_USER, _BYELLOW_}, \
+ /* Note this MUST be last or the color code will break */ /* Also note \
+ that the \
+ color \
+ specified \
+ here is \
+ effectively \
+ the \
+ "default" \
+ */ \
+ {"all", DBG_ALL, _NORMAL_}, \
+ { \
+ NULL, 0, NULL \
+ }
+
+extern uint64_t dbg_modes;
+
+/* A common interface for functions which provide human-readable information
+ * about some data structure. Functions implementing this interface should fill
+ * buf with up to size characters to describe the data passed in as data, then
+ * return the number of characters writen. If there is not enough space in buf
+ * to write all information then only size characters will be writen and size
+ * will be returned. The returned string will be null terminated regardless of
+ * its length. */
+typedef size_t (*dbg_infofunc_t)(const void *data, char *buf, size_t size);
+
+#define DBG_BUFFER_SIZE (PAGE_SIZE)
+
+void dbg_init(void);
+
+void dbg_print(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+
+void dbg_printinfo(dbg_infofunc_t func, const void *data);
+
+const char *dbg_color(uint64_t d_mode);
+
+#if defined(__SMP__) || defined(__KPREEMPT__)
+#define DEBUG_ENTER \
+ uint8_t __ipl = apic_initialized() ? intr_setipl(IPL_HIGH) : IPL_LOW; \
+#define DEBUG_EXIT \
+ if (apic_initialized()) \
+ intr_setipl(__ipl);
+#else
+#define DEBUG_ENTER \
+ do \
+ { \
+ } while (0);
+#define DEBUG_EXIT \
+ do \
+ { \
+ } while (0);
+#endif
+
+#ifndef NDEBUG
+#define dbg(mode, ...) \
+ do \
+ { \
+ if (dbg_active(mode)) \
+ { \
+ DEBUG_ENTER \
+ dbg_print("%s", dbg_color(mode)); \
+ dbg_print("C%ld P%ld ", curcore.kc_id, \
+ curproc ? curproc->p_pid : -1L); \
+ dbg_print("%s:%d %s(): ", __FILE__, __LINE__, __func__); \
+ dbg_print(__VA_ARGS__); \
+ dbg_print("%s", _NORMAL_); \
+ DEBUG_EXIT \
+ } \
+ } while (0)
+
+#define dbg_force(mode, ...) \
+ do \
+ { \
+ DEBUG_ENTER \
+ dbg_print("%s", dbg_color(mode)); \
+ dbg_print("C%ld P%ld ", curcore.kc_id, \
+ curproc ? curproc->p_pid : -1L); \
+ dbg_print("%s:%d %s(): ", __FILE__, __LINE__, __func__); \
+ dbg_print(__VA_ARGS__); \
+ dbg_print("%s", _NORMAL_); \
+ DEBUG_EXIT \
+ } while (0)
+
+#define dbgq(mode, ...) \
+ do \
+ { \
+ if (dbg_active(mode)) \
+ { \
+ DEBUG_ENTER \
+ dbg_print("%s", dbg_color(mode)); \
+ dbg_print("C%ld P%ld ", curcore.kc_id, \
+ curproc ? curproc->p_pid : -1L); \
+ dbg_print(__VA_ARGS__); \
+ dbg_print("%s", _NORMAL_); \
+ DEBUG_EXIT \
+ } \
+ } while (0)
+
+#define dbginfo(mode, func, data) \
+ do \
+ { \
+ if (dbg_active(mode)) \
+ { \
+ DEBUG_ENTER \
+ dbg_print("%s", dbg_color(mode)); \
+ dbg_print("C%ld P%ld ", curcore.kc_id, \
+ curproc ? curproc->p_pid : -1L); \
+ dbg_printinfo(func, data); \
+ dbg_print("%s", _NORMAL_); \
+ DEBUG_EXIT \
+ } \
+ } while (0)
+
+#define dbg_active(mode) (dbg_modes & (mode))
+
+void dbg_add_mode(const char *mode);
+
+void dbg_add_modes(const char *modes);
+
+#else
+#define dbg(mode, ...)
+#define dbgq(mode, ...)
+#define dbginfo(mode, func, data)
+#define dbg_active(mode) 0
+#define dbg_add_mode(mode)
+#define dbg_add_modes(modes)
+#endif
+
+noreturn void dbg_panic(const char *file, int line, const char *func,
+ const char *fmt, ...)
+ __attribute__((format(printf, 4, 5)));
+
+#define panic(...) dbg_panic(__FILE__, __LINE__, __func__, __VA_ARGS__)
+
+#ifndef NDEBUG
+#define KASSERT(x) \
+ do \
+ { \
+ if (!(x)) \
+ panic("assertion failed: %s", #x); \
+ } while (0)
+
+#define KASSERT_GENERIC(left, right, comparator, comp_str) \
+ do \
+ { \
+ int __left = (int)(left); \
+ int __right = (int)(right); \
+ if (!comparator(__left, __right)) \
+ { \
+ panic("assertion failed: %s %s %s. Left: %d, Right: %d\n", #left, \
+ comp_str, #right, __left, __right); \
+ } \
+ } while (0)
+
+static long equals(long l, long r)
+{
+ return l == r;
+}
+
+static long notequals(long l, long r) { return l != r; }
+
+static long lessthan(long l, long r) { return l < r; }
+
+static long greaterthan(long l, long r) { return l > r; }
+
+static long lessthaneq(long l, long r) { return l <= r; }
+
+static long greaterthaneq(long l, long r) { return l >= r; }
+
+#define KASSERTEQ(l, r) KASSERT_GENERIC(l, r, equals, "==")
+#define KASSERTNEQ(l, r) KASSERT_GENERIC(l, r, notequals, "!=")
+#define KASSERT_GREATER(l, r) KASSERT_GENERIC(l, r, greaterthan, ">")
+#define KASSERT_LESS(l, r) KASSERT_GENERIC(l, r, lessthan, "<")
+#define KASSERT_GREQ(l, r) KASSERT_GENERIC(l, r, greaterthaneq, ">=")
+#define KASSERT_LESSEQ(l, r) KASSERT_GENERIC(l, r, lessthaneq, "<=")
+#else
+#define KASSERT(x)
+#define KASSERTEQ(l, r)
+#define KASSERT_GREATER(l, r)
+#define KASSERT_LESS(l, r)
+#define KASSERT_GREQ(l, r)
+#define KASSERT_LESSEQ(l, r)
+#endif
diff --git a/kernel/include/util/delay.h b/kernel/include/util/delay.h
new file mode 100644
index 0000000..29cf3b2
--- /dev/null
+++ b/kernel/include/util/delay.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include "types.h"
+#include "util/debug.h"
+
+/* Approximate numbers taken from various points in Linux kernel */
+#define LOOPS_PER_JIFFY (1 << 12)
+#define HZ 100 /* Found this in a random place in the kernel */
+
+/* From arch/x86/lib/delay.c in Linux kernel */
+/*
+ * Precise Delay Loops for i386
+ *
+ * Copyright (C) 1993 Linus Torvalds
+ * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * Copyright (C) 2008 Jiri Hladky <hladky _dot_ jiri _at_ gmail _dot_ com>
+ *
+ * The __delay function must _NOT_ be inlined as its execution time
+ * depends wildly on alignment on many x86 processors. The additional
+ * jump magic is needed to get the timing stable on all the CPU's
+ * we have to worry about.
+ */
+
+static void __delay(unsigned long loops)
+{
+ __asm__ volatile(
+ " test %0,%0 \n"
+ " jz 3f \n"
+ " jmp 1f \n"
+
+ ".align 16 \n"
+ "1: jmp 2f \n"
+
+ ".align 16 \n"
+ "2: dec %0 \n"
+ " jnz 2b \n"
+ "3: dec %0 \n"
+
+ : /* we don't need output */
+ : "a"(loops));
+}
+
+static inline void __const_udelay(unsigned long xloops)
+{
+ int d0;
+
+ xloops *= 4;
+ __asm__ volatile("mull %%edx"
+ : "=d"(xloops), "=&a"(d0)
+ : "1"(xloops), "0"(LOOPS_PER_JIFFY * (HZ / 4)));
+
+ __delay(++xloops);
+}
+
+static inline void __udelay(unsigned long usecs)
+{
+ __const_udelay(usecs * 4295); /* 2**32 / 1000000 */
+}
+
+static inline void __ndelay(unsigned long nsecs)
+{
+ __const_udelay(nsecs * 5); /* 2**32 / 1000000000 */
+}
+
+#define udelay(n) \
+ (__builtin_constant_p(n) ? ((n) > 20000 ? panic("Delay too large!") \
+ : __const_udelay((n)*4295)) \
+ : __udelay(n))
+
+#define ndelay(n) \
+ (__builtin_constant_p(n) \
+ ? ((n) > 20000 ? panic("Delay too large!") : __const_udelay((n)*5)) \
+ : __ndelay(n))
diff --git a/kernel/include/util/gdb.h b/kernel/include/util/gdb.h
new file mode 100644
index 0000000..cc28dbc
--- /dev/null
+++ b/kernel/include/util/gdb.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#define GDB_DEFINE_HOOK(name, ...) \
+ void __py_hook_##name(__VA_ARGS__) {}
+#define GDB_CALL_HOOK(name, ...) __py_hook_##name(__VA_ARGS__)
diff --git a/kernel/include/util/init.h b/kernel/include/util/init.h
new file mode 100644
index 0000000..9be7e3c
--- /dev/null
+++ b/kernel/include/util/init.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#define init_func(func) \
+ __asm__( \
+ ".pushsection .init\n\t" \
+ ".long " #func \
+ "\n\t" \
+ ".string \"" #func \
+ "\"\n\t" \
+ ".popsection\n\t");
+#define init_depends(name) \
+ __asm__( \
+ ".pushsection .init\n\t" \
+ ".long 0\n\t" \
+ ".string \"" #name \
+ "\"\n\t" \
+ ".popsection\n\t");
+
+typedef void (*init_func_t)();
+
+void init_call_all(void);
diff --git a/kernel/include/util/list.h b/kernel/include/util/list.h
new file mode 100644
index 0000000..5fd44c1
--- /dev/null
+++ b/kernel/include/util/list.h
@@ -0,0 +1,224 @@
+#pragma once
+
+#include "kernel.h"
+
+/*
+ * Generic circular doubly linked list implementation.
+ *
+ * list_t is the head of the list.
+ * list_link_t should be included in structures which want to be
+ * linked on a list_t.
+ *
+ * All of the list functions take pointers to list_t and list_link_t
+ * types, unless otherwise specified.
+ *
+ * list_init(list) initializes a list_t to an empty list.
+ *
+ * list_empty(list) returns 1 iff the list is empty.
+ *
+ * Insertion functions.
+ * list_insert_head(list, link) inserts link at the front of the list.
+ * list_insert_tail(list, link) inserts link at the end of the list.
+ * list_insert_before(olink, nlink) inserts nlink before olink in list.
+ *
+ * Removal functions.
+ * Head is list->l_next. Tail is list->l_prev.
+ * The following functions should only be called on non-empty lists.
+ * list_remove(link) removes a specific element from the list.
+ * list_remove_head(list) removes the first element of list.
+ * list_remove_tail(list) removes the last element of list.
+ *
+ * Item accessors.
+ * list_item(link, type, member)
+ *
+ * Given a list_link_t* and the name of the type of structure which contains
+ * the list_link_t and the name of the member corresponding to the list_link_t,
+ * returns a pointer (of type "type*") to the item.
+ *
+ * Example:
+ * struct my_struct { list_link_t my_link };
+ * struct my_struct a;
+ * list_link_init(&a.my_link);
+ *
+ * struct my_struct *b = list_item(&a.my_link, struct my_struct, my_link);
+ * // b should equal &a here
+ *
+ * To iterate over a list,
+ * list_link_t *link;
+ * for (link = list->l_next;
+ * link != list; link = link->l_next)
+ * ...
+ *
+ * Or, use the macros, which will work even if you list_remove() the
+ * current link:
+ * list_iterate(list, iterator, type, member) {
+ * ... use iterator ...
+ * }
+ * (see also list_iterate_reverse for iterating in reverse)
+ *
+ * Where:
+ * - list is a pointer to the list_t to iterate over,
+ * - iterator is a name for the loop variable which will take on the value
+ * of each item in the list,
+ * - type is the type of items in the list,
+ * - member is the name of the field in the item type that is the list_link_t
+ *
+ * Example (from kernel/drivers/chardev.c)
+ * // chardevs is a list_t
+ * // chardev_t has a cd_link member which is a list_link_t
+ * list_iterate(&chardevs, cd, chardev_t, cd_link)
+ * {
+ * if (dev->cd_id == cd->cd_id)
+ * {
+ * return -1;
+ * }
+ * }
+ */
+
+/**
+ * Initialize a list_t.
+ */
+#define LIST_INITIALIZER(list) \
+ { \
+ .l_next = &(list), .l_prev = &(list) \
+ }
+
+/**
+ * Initialize a list link.
+ */
+#define LIST_LINK_INITIALIZER(list_link) \
+ { \
+ .l_next = NULL, .l_prev = NULL \
+ }
+
+typedef struct list
+{
+ struct list *l_next;
+ struct list *l_prev;
+} list_t, list_link_t;
+
+/**
+ * Initialize a list link.
+ */
+void list_link_init(list_link_t *link);
+
+/**
+ * Initialize a list_t.
+ */
+void list_init(list_t *list);
+
+/**
+ * Check if a link is linked to some list.
+ *
+ * @param link The link to check.
+ * @return long 1 if linked, 0 otherwise.
+ */
+long list_link_is_linked(const list_link_t *link);
+
+/**
+ * Check if a list is empty.
+ *
+ * @param list The list to check.
+ * @return long 1 if empty, 0 otherwise.
+ */
+long list_empty(const list_t *list);
+
+/**
+ * Assert that the internal state of a list is sane, and
+ * panic if it is not.
+ *
+ * @param list The list to check for sanity.
+ */
+void list_assert_sanity(const list_t *list);
+
+/**
+ * Insert a new link onto a list before another link.
+ *
+ * @param link The link before which the new link should be inserted.
+ * @param to_insert The new link to be inserted.
+ */
+void list_insert_before(list_link_t *link, list_link_t *to_insert);
+
+/**
+ * Insert a new link at the head (beginning) of a given list.
+ *
+ * @param list The list to insert on.
+ * @param link The new link to insert.
+ */
+void list_insert_head(list_t *list, list_link_t *link);
+
+/**
+ * Insert a new link at the tail (end) of a given list.
+ *
+ * @param list The list to insert on.
+ * @param link The new link to insert.
+ */
+void list_insert_tail(list_t *list, list_link_t *link);
+
+/**
+ * Remove a particular link from the list it's on.
+ *
+ * @param link The link to be removed from its list.
+ */
+void list_remove(list_link_t *link);
+
+/**
+ * Get a pointer to the item that contains the given link.
+ *
+ * For instance, given a list_link_t contained within a proc_t, get a reference
+ * to the proc_t itself.
+ *
+ * @param link The link contained within the item to access.
+ * @param type The type of the outer item struct (e.g., proc_t)
+ * @param member The name of the struct member which is the list_link_t (e.g. p_list_link)
+ *
+ */
+#define list_item(link, type, member) \
+ (type *)((char *)(link)-offsetof(type, member))
+
+/**
+ * Get the item at the head of the list. See list_item for explanation
+ * of type and member.
+ */
+#define list_head(list, type, member) list_item((list)->l_next, type, member)
+
+/**
+ * Get the item at the tail of the list. See list_item for explanation
+ * of type and member.
+ */
+#define list_tail(list, type, member) list_item((list)->l_prev, type, member)
+
+/**
+ * Get the next item in a list that occurs after the given item.
+ *
+ * @param current An item from the list (e.g. a proc_t)
+ * See list_item for explanation of type and member.
+ */
+#define list_next(current, type, member) \
+ list_head(&(current)->member, type, member)
+
+/**
+ * Get the previous item in a list given an item. See list_next for explanation.
+ */
+#define list_prev(current, type, member) \
+ list_tail(&(current)->member, type, member)
+
+/**
+ * Iterate over elements in in a list. See comment at top of list.h for
+ * detailed description.
+ */
+#define list_iterate(list, var, type, member) \
+ for (type *var = list_head(list, type, member), \
+ *__next_##var = list_next(var, type, member); \
+ &var->member != (list); \
+ var = __next_##var, __next_##var = list_next(var, type, member))
+
+/**
+ * Iterate over the elements of a list in reverse. See comment at top of list.h for
+ * detailed description.
+ */
+#define list_iterate_reverse(list, var, type, member) \
+ for (type *var = list_tail(list, type, member), \
+ *__next_##var = list_prev(var, type, member); \
+ &var->member != (list); \
+ var = __next_##var, __next_##var = list_prev(var, type, member))
diff --git a/kernel/include/util/printf.h b/kernel/include/util/printf.h
new file mode 100644
index 0000000..430b156
--- /dev/null
+++ b/kernel/include/util/printf.h
@@ -0,0 +1,87 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: lib.h
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes:
+ *
+ * Date: Aug 2003
+ *
+ * Environment: Xen Minimal OS
+ * Description: Random useful library functions, contains some freebsd stuff
+ *
+ ****************************************************************************
+ * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stdarg.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/i386/include/stdarg.h,v 1.10 1999/08/28 00:44:26 peter Exp
+ *$
+ */
+
+#pragma once
+
+#include "stdarg.h"
+#include <types.h>
+
+/* printing */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+int snprintf(char *buf, size_t size, const char *fmt, ...);
+
+int scnprintf(char *buf, size_t size, const char *fmt, ...);
+
+// a pretty simple way to avoid kernel buffer overflow attacks, no?
+// int vsprintf(char *buf, const char *fmt, va_list args);
+// int sprintf(char *buf, const char *fmt, ...);
+
+/* A variation on printf designed to be used in debug info functions.
+ * The function takes in a pointer to the address of a string buffer
+ * and a pointer to the size of the buffer. The buffer address pointed
+ * by str is incremented to point to the null character writen at the
+ * end of the new string. The size is decremented by the number of
+ * characters writen, not including the null character. The function
+ * returns the number of characters left in the buffer (after taking
+ * in to account the null character). */
+int iprintf(char **str, size_t *size, char *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
+
+int vsscanf(const char *buf, const char *fmt, va_list args);
+
+int sscanf(const char *buf, const char *fmt, ...);
diff --git a/kernel/include/util/string.h b/kernel/include/util/string.h
new file mode 100644
index 0000000..04dc0f7
--- /dev/null
+++ b/kernel/include/util/string.h
@@ -0,0 +1,93 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+ ****************************************************************************
+ * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
+ ****************************************************************************
+ *
+ * File: lib.h
+ * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
+ * Changes:
+ *
+ * Date: Aug 2003
+ *
+ * Environment: Xen Minimal OS
+ * Description: Random useful library functions, contains some freebsd stuff
+ *
+ ****************************************************************************
+ * $Id: h-insert.h,v 1.4 2002/11/08 16:03:55 rn Exp $
+ ****************************************************************************
+ *
+ *-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stdarg.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD: src/sys/i386/include/stdarg.h,v 1.10 1999/08/28 00:44:26 peter Exp
+ *$
+ */
+
+#pragma once
+
+#include "stdarg.h"
+#include "types.h"
+
+/* string and memory manipulation */
+int memcmp(const void *cs, const void *ct, size_t count);
+
+void *memcpy(void *dest, const void *src, size_t count);
+
+int strncmp(const char *cs, const char *ct, size_t count);
+
+int strcmp(const char *cs, const char *ct);
+
+char *strcpy(char *dest, const char *src);
+
+char *strncpy(char *dest, const char *src, size_t count);
+
+void *memset(void *s, int c, size_t count);
+
+size_t strnlen(const char *s, size_t count);
+
+size_t strlen(const char *s);
+
+char *strchr(const char *s, int c);
+
+char *strrchr(const char *s, int c);
+
+char *strstr(const char *s1, const char *s2);
+
+char *strcat(char *dest, const char *src);
+
+char *strdup(const char *s);
+
+char *strtok(char *s, const char *d);
+
+/* return string-representation of an errno */
+char *strerror(int errnum);
diff --git a/kernel/include/util/time.h b/kernel/include/util/time.h
new file mode 100644
index 0000000..fe3df18
--- /dev/null
+++ b/kernel/include/util/time.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "types.h"
+#include "util/debug.h"
+
+extern uint64_t timer_tickcount;
+extern uint64_t kernel_preempted_count;
+extern uint64_t user_preempted_count;
+extern uint64_t not_preempted_count;
+extern uint64_t idle_count;
+extern volatile uint64_t jiffies;
+
+void time_init();
+
+void time_spin(time_t ms);
+
+void time_sleep(time_t ms);
+
+long do_usleep(useconds_t usec);
+
+time_t core_uptime();
+
+time_t do_time();
+
+size_t time_stats(char *buf, size_t len);
diff --git a/kernel/include/util/timer.h b/kernel/include/util/timer.h
new file mode 100644
index 0000000..57889f9
--- /dev/null
+++ b/kernel/include/util/timer.h
@@ -0,0 +1,28 @@
+#ifndef TIMER_H
+#define TIMER_H
+
+#include "util/list.h"
+
+typedef struct timer
+{
+ void (*function)(uint64_t data);
+ uint64_t data;
+ uint64_t expires;
+ list_link_t link;
+} timer_t;
+
+void timer_init(timer_t *timer);
+
+void timer_add(timer_t *timer);
+
+int timer_del(timer_t *timer);
+
+int timer_mod(timer_t *timer, int expires);
+
+int timer_pending(timer_t *timer);
+
+int timer_del_sync(timer_t *timer);
+
+void __timers_fire();
+
+#endif \ No newline at end of file