From 9290f1fe99c91ba6c57dec956ff73d1741d81b45 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 10:29:23 +0100 Subject: Add DDEKit headers. --- libddekit/include/.svn/all-wcprops | 17 + libddekit/include/.svn/entries | 99 ++++ libddekit/include/.svn/format | 1 + libddekit/include/.svn/text-base/Makefile.svn-base | 9 + libddekit/include/.svn/text-base/dde.h.svn-base | 14 + libddekit/include/Makefile | 9 + libddekit/include/dde.h | 14 + libddekit/include/ddekit/.svn/all-wcprops | 107 ++++ libddekit/include/ddekit/.svn/entries | 606 +++++++++++++++++++++ libddekit/include/ddekit/.svn/format | 1 + .../ddekit/.svn/text-base/assert.h.svn-base | 23 + .../ddekit/.svn/text-base/condvar.h.svn-base | 54 ++ .../include/ddekit/.svn/text-base/debug.h.svn-base | 8 + .../ddekit/.svn/text-base/initcall.h.svn-base | 42 ++ .../ddekit/.svn/text-base/inline.h.svn-base | 2 + .../ddekit/.svn/text-base/interrupt.h.svn-base | 57 ++ .../include/ddekit/.svn/text-base/lock.h.svn-base | 83 +++ .../ddekit/.svn/text-base/memory.h.svn-base | 144 +++++ .../include/ddekit/.svn/text-base/panic.h.svn-base | 16 + .../include/ddekit/.svn/text-base/pci.h.svn-base | 199 +++++++ .../include/ddekit/.svn/text-base/pgtab.h.svn-base | 86 +++ .../ddekit/.svn/text-base/printf.h.svn-base | 33 ++ .../ddekit/.svn/text-base/resources.h.svn-base | 13 + .../ddekit/.svn/text-base/semaphore.h.svn-base | 50 ++ .../ddekit/.svn/text-base/thread.h.svn-base | 162 ++++++ .../include/ddekit/.svn/text-base/timer.h.svn-base | 55 ++ .../include/ddekit/.svn/text-base/types.h.svn-base | 22 + libddekit/include/ddekit/assert.h | 23 + libddekit/include/ddekit/condvar.h | 54 ++ libddekit/include/ddekit/debug.h | 8 + libddekit/include/ddekit/initcall.h | 42 ++ libddekit/include/ddekit/inline.h | 2 + libddekit/include/ddekit/interrupt.h | 57 ++ libddekit/include/ddekit/lock.h | 83 +++ libddekit/include/ddekit/memory.h | 144 +++++ libddekit/include/ddekit/panic.h | 16 + libddekit/include/ddekit/pci.h | 199 +++++++ libddekit/include/ddekit/pgtab.h | 86 +++ libddekit/include/ddekit/printf.h | 33 ++ libddekit/include/ddekit/resources.h | 13 + libddekit/include/ddekit/semaphore.h | 50 ++ libddekit/include/ddekit/thread.h | 162 ++++++ libddekit/include/ddekit/timer.h | 55 ++ libddekit/include/ddekit/types.h | 22 + 44 files changed, 2975 insertions(+) create mode 100644 libddekit/include/.svn/all-wcprops create mode 100644 libddekit/include/.svn/entries create mode 100644 libddekit/include/.svn/format create mode 100644 libddekit/include/.svn/text-base/Makefile.svn-base create mode 100644 libddekit/include/.svn/text-base/dde.h.svn-base create mode 100644 libddekit/include/Makefile create mode 100644 libddekit/include/dde.h create mode 100644 libddekit/include/ddekit/.svn/all-wcprops create mode 100644 libddekit/include/ddekit/.svn/entries create mode 100644 libddekit/include/ddekit/.svn/format create mode 100644 libddekit/include/ddekit/.svn/text-base/assert.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/condvar.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/debug.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/initcall.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/inline.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/lock.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/memory.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/panic.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/pci.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/pgtab.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/printf.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/resources.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/thread.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/timer.h.svn-base create mode 100644 libddekit/include/ddekit/.svn/text-base/types.h.svn-base create mode 100644 libddekit/include/ddekit/assert.h create mode 100644 libddekit/include/ddekit/condvar.h create mode 100644 libddekit/include/ddekit/debug.h create mode 100644 libddekit/include/ddekit/initcall.h create mode 100644 libddekit/include/ddekit/inline.h create mode 100644 libddekit/include/ddekit/interrupt.h create mode 100644 libddekit/include/ddekit/lock.h create mode 100644 libddekit/include/ddekit/memory.h create mode 100644 libddekit/include/ddekit/panic.h create mode 100644 libddekit/include/ddekit/pci.h create mode 100644 libddekit/include/ddekit/pgtab.h create mode 100644 libddekit/include/ddekit/printf.h create mode 100644 libddekit/include/ddekit/resources.h create mode 100644 libddekit/include/ddekit/semaphore.h create mode 100644 libddekit/include/ddekit/thread.h create mode 100644 libddekit/include/ddekit/timer.h create mode 100644 libddekit/include/ddekit/types.h (limited to 'libddekit/include') diff --git a/libddekit/include/.svn/all-wcprops b/libddekit/include/.svn/all-wcprops new file mode 100644 index 00000000..7ba2dd51 --- /dev/null +++ b/libddekit/include/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 50 +/repos/tudos/!svn/ver/457/trunk/l4/pkg/dde/include +END +dde.h +K 25 +svn:wc:ra_dav:version-url +V 56 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/dde.h +END +Makefile +K 25 +svn:wc:ra_dav:version-url +V 59 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/Makefile +END diff --git a/libddekit/include/.svn/entries b/libddekit/include/.svn/entries new file mode 100644 index 00000000..4bc0ab10 --- /dev/null +++ b/libddekit/include/.svn/entries @@ -0,0 +1,99 @@ +9 + +dir +465 +http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/include +http://svn.tudos.org/repos/tudos + + + +2009-05-23T02:50:17.774710Z +457 +l4check + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +a704ac0b-3a55-4d43-a2a9-7be6f07c34fb + +dde.h +file + + + + +2009-11-15T17:14:44.000000Z +55a0119faab08988da07a2e0aa7f95a9 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +308 + +ddekit +dir + +Makefile +file + + + + +2009-11-15T17:14:44.000000Z +48ec0344857f2fa21c99f765cc91f0e6 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +276 + diff --git a/libddekit/include/.svn/format b/libddekit/include/.svn/format new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/libddekit/include/.svn/format @@ -0,0 +1 @@ +9 diff --git a/libddekit/include/.svn/text-base/Makefile.svn-base b/libddekit/include/.svn/text-base/Makefile.svn-base new file mode 100644 index 00000000..8d31023f --- /dev/null +++ b/libddekit/include/.svn/text-base/Makefile.svn-base @@ -0,0 +1,9 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +# All haeder files found in this directory tree will be automatically +# installed in a way that they can be included with +# #include later. +# No need to list them in this Makefile. + +include $(L4DIR)/mk/include.mk diff --git a/libddekit/include/.svn/text-base/dde.h.svn-base b/libddekit/include/.svn/text-base/dde.h.svn-base new file mode 100644 index 00000000..12f8a81a --- /dev/null +++ b/libddekit/include/.svn/text-base/dde.h.svn-base @@ -0,0 +1,14 @@ +#ifndef l4_ddekit_h +#define l4_ddekit_h + +/* FIXME if this is ddekit.h, it should be moved into dde/ddekit/include/ddekit.h (also + * all headers under include/ddekit) */ + +/** + * Initialize the DDE. Must be called before any other DDE function. + * + * FIXME revisit this one + */ +void ddekit_init(void); + +#endif diff --git a/libddekit/include/Makefile b/libddekit/include/Makefile new file mode 100644 index 00000000..8d31023f --- /dev/null +++ b/libddekit/include/Makefile @@ -0,0 +1,9 @@ +PKGDIR ?= .. +L4DIR ?= $(PKGDIR)/../.. + +# All haeder files found in this directory tree will be automatically +# installed in a way that they can be included with +# #include later. +# No need to list them in this Makefile. + +include $(L4DIR)/mk/include.mk diff --git a/libddekit/include/dde.h b/libddekit/include/dde.h new file mode 100644 index 00000000..12f8a81a --- /dev/null +++ b/libddekit/include/dde.h @@ -0,0 +1,14 @@ +#ifndef l4_ddekit_h +#define l4_ddekit_h + +/* FIXME if this is ddekit.h, it should be moved into dde/ddekit/include/ddekit.h (also + * all headers under include/ddekit) */ + +/** + * Initialize the DDE. Must be called before any other DDE function. + * + * FIXME revisit this one + */ +void ddekit_init(void); + +#endif diff --git a/libddekit/include/ddekit/.svn/all-wcprops b/libddekit/include/ddekit/.svn/all-wcprops new file mode 100644 index 00000000..e216cf47 --- /dev/null +++ b/libddekit/include/ddekit/.svn/all-wcprops @@ -0,0 +1,107 @@ +K 25 +svn:wc:ra_dav:version-url +V 57 +/repos/tudos/!svn/ver/457/trunk/l4/pkg/dde/include/ddekit +END +panic.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/panic.h +END +interrupt.h +K 25 +svn:wc:ra_dav:version-url +V 69 +/repos/tudos/!svn/ver/301/trunk/l4/pkg/dde/include/ddekit/interrupt.h +END +condvar.h +K 25 +svn:wc:ra_dav:version-url +V 67 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/condvar.h +END +pgtab.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/395/trunk/l4/pkg/dde/include/ddekit/pgtab.h +END +initcall.h +K 25 +svn:wc:ra_dav:version-url +V 68 +/repos/tudos/!svn/ver/238/trunk/l4/pkg/dde/include/ddekit/initcall.h +END +assert.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/assert.h +END +printf.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/printf.h +END +types.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/types.h +END +thread.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/238/trunk/l4/pkg/dde/include/ddekit/thread.h +END +memory.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/memory.h +END +resources.h +K 25 +svn:wc:ra_dav:version-url +V 69 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/resources.h +END +pci.h +K 25 +svn:wc:ra_dav:version-url +V 63 +/repos/tudos/!svn/ver/455/trunk/l4/pkg/dde/include/ddekit/pci.h +END +inline.h +K 25 +svn:wc:ra_dav:version-url +V 66 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/inline.h +END +timer.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/457/trunk/l4/pkg/dde/include/ddekit/timer.h +END +semaphore.h +K 25 +svn:wc:ra_dav:version-url +V 69 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/semaphore.h +END +debug.h +K 25 +svn:wc:ra_dav:version-url +V 65 +/repos/tudos/!svn/ver/174/trunk/l4/pkg/dde/include/ddekit/debug.h +END +lock.h +K 25 +svn:wc:ra_dav:version-url +V 64 +/repos/tudos/!svn/ver/253/trunk/l4/pkg/dde/include/ddekit/lock.h +END diff --git a/libddekit/include/ddekit/.svn/entries b/libddekit/include/ddekit/.svn/entries new file mode 100644 index 00000000..21752264 --- /dev/null +++ b/libddekit/include/ddekit/.svn/entries @@ -0,0 +1,606 @@ +9 + +dir +465 +http://svn.tudos.org/repos/tudos/trunk/l4/pkg/dde/include/ddekit +http://svn.tudos.org/repos/tudos + + + +2009-05-23T02:50:17.774710Z +457 +l4check + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +a704ac0b-3a55-4d43-a2a9-7be6f07c34fb + +panic.h +file + + + + +2009-11-15T17:14:44.000000Z +2570239ee2dbc1154cf146aa16bcf547 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +330 + +interrupt.h +file + + + + +2009-11-15T17:14:44.000000Z +ee8b18c79ba7d7cf50a35d8105f68750 +2008-02-16T03:51:13.191963Z +301 +l4check + + + + + + + + + + + + + + + + + + + + + +1586 + +condvar.h +file + + + + +2009-11-15T17:14:44.000000Z +6ad1a17ba32ef17c1345685eda2bb129 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +1239 + +pgtab.h +file + + + + +2009-11-15T17:14:44.000000Z +5991c64662b8e2d95e1202eb4ff6045c +2008-08-14T02:50:25.232552Z +395 +l4check + + + + + + + + + + + + + + + + + + + + + +2086 + +initcall.h +file + + + + +2009-11-15T17:14:44.000000Z +c04d502176e023a054602b5d18ac29e1 +2007-11-08T03:52:28.731143Z +238 +l4check + + + + + + + + + + + + + + + + + + + + + +1135 + +assert.h +file + + + + +2009-11-15T17:14:44.000000Z +ab222d72d5dc9ad29a5c435561818d0c +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +592 + +printf.h +file + + + + +2009-11-15T17:14:44.000000Z +a0e9adfc93ede606218916e4f5d9f437 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +731 + +types.h +file + + + + +2009-11-15T17:14:44.000000Z +a0fd3a957254115d16d6bafe5f23c630 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +616 + +thread.h +file + + + + +2009-11-15T17:14:44.000000Z +1e42c7c3396e9dbb7d238e19e4368e6d +2007-11-08T03:52:28.731143Z +238 +l4check + + + + + + + + + + + + + + + + + + + + + +3877 + +memory.h +file + + + + +2009-11-15T17:14:44.000000Z +980f4cc26bf2735a3518da3d16060500 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +3486 + +resources.h +file + + + + +2009-11-15T17:14:44.000000Z +cdd94bcecf43cb4001bf3f5919704968 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +449 + +pci.h +file + + + + +2009-11-15T17:14:44.000000Z +3d708d2ff3ac2937415cd19bb0ac9e0d +2009-05-20T14:32:55.606606Z +455 +l4check + + + + + + + + + + + + + + + + + + + + + +5045 + +inline.h +file + + + + +2009-11-15T17:14:44.000000Z +0c47197d7519e09e4b8bbd76b56c4b60 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +58 + +timer.h +file + + + + +2009-11-15T17:14:44.000000Z +850acfa4cd49770e7a2f8b511b1cfde4 +2009-05-23T02:50:17.774710Z +457 +l4check + + + + + + + + + + + + + + + + + + + + + +1186 + +semaphore.h +file + + + + +2009-11-15T17:14:44.000000Z +b8f721cb8c9d58ba4d163510c9687843 +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +991 + +debug.h +file + + + + +2009-11-15T17:14:44.000000Z +8a52d2548bcf2855c1d843a074e81ceb +2007-09-08T19:44:13.897747Z +174 +l4check + + + + + + + + + + + + + + + + + + + + + +146 + +lock.h +file + + + + +2009-11-15T17:14:44.000000Z +a8a89bd7ee88b2f8279f2f6716c6ee15 +2007-12-13T03:50:57.801357Z +253 +l4check + + + + + + + + + + + + + + + + + + + + + +2114 + diff --git a/libddekit/include/ddekit/.svn/format b/libddekit/include/ddekit/.svn/format new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/libddekit/include/ddekit/.svn/format @@ -0,0 +1 @@ +9 diff --git a/libddekit/include/ddekit/.svn/text-base/assert.h.svn-base b/libddekit/include/ddekit/.svn/text-base/assert.h.svn-base new file mode 100644 index 00000000..5d572b49 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/assert.h.svn-base @@ -0,0 +1,23 @@ +#ifndef _ddekit_assert_h +#define _ddekit_assert_h + +#include +#include + +/** \file ddekit/assert.h */ + +/** Assert that an expression is true and panic if not. + * \ingroup DDEKit_util + */ +#define Assert(expr) do \ + { \ + if (!(expr)) { \ + ddekit_print("\033[31;1mDDE: Assertion failed: "#expr"\033[0m\n"); \ + ddekit_printf(" File: %s:%d\n",__FILE__,__LINE__); \ + ddekit_printf(" Function: %s()\n", __FUNCTION__); \ + ddekit_panic("Assertion failed."); \ + }} while (0); + +#endif + +#define assert Assert diff --git a/libddekit/include/ddekit/.svn/text-base/condvar.h.svn-base b/libddekit/include/ddekit/.svn/text-base/condvar.h.svn-base new file mode 100644 index 00000000..b6dc4bd3 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/condvar.h.svn-base @@ -0,0 +1,54 @@ +#ifndef _ddekit_condvar_h +#define _ddekit_condvar_h + +/** \file ddekit/condvar.h */ + +#include + +struct ddekit_condvar; +typedef struct ddekit_condvar ddekit_condvar_t; + +/** Initialize conditional variable. + * + * \ingroup DDEKit_synchronization + */ +ddekit_condvar_t * ddekit_condvar_init(void); + +/** Uninitialize conditional variable. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_deinit(ddekit_condvar_t *cvp); + +/** Wait on a conditional variable. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp); + +/** Wait on a conditional variable at most until a timeout expires. + * + * \ingroup DDEKit_synchronization + * + * \param cvp pointer to condvar + * \param mp lock + * \param timo timeout in ms + * + * \return 0 success + * \return !=0 timeout + */ +int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp, ddekit_lock_t *mp, int timo); + +/** Send signal to the next one waiting for condvar. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_signal(ddekit_condvar_t *cvp); + +/** Send signal to all threads waiting for condvar. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_broadcast(ddekit_condvar_t *cvp); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/debug.h.svn-base b/libddekit/include/ddekit/.svn/text-base/debug.h.svn-base new file mode 100644 index 00000000..79a8e7b5 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/debug.h.svn-base @@ -0,0 +1,8 @@ +#define DDEBUG_QUIET 0 +#define DDEBUG_ERR 1 +#define DDEBUG_WARN 2 +#define DDEBUG_INFO 3 +#define DDEBUG_VERBOSE 4 + +#define DDEBUG_MEM DDEBUG_INFO + diff --git a/libddekit/include/ddekit/.svn/text-base/initcall.h.svn-base b/libddekit/include/ddekit/.svn/text-base/initcall.h.svn-base new file mode 100644 index 00000000..b503cc6a --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/initcall.h.svn-base @@ -0,0 +1,42 @@ +#ifndef _ddekit_initcall_h +#define _ddekit_initcall_h + +// from l4/sys/compiler.h +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4 +#define L4_STICKY(x) __attribute__((used)) x +#else +#define L4_STICKY(x) __attribute__((unused)) x +#endif + +#define l4str(s) #s + +// from dde_linux/ARCH-x86/ctor.h +typedef void (*l4ddekit_initcall_t)(void); + +#define __l4ddekit_initcall(p) \ + __attribute__ ((__section__ (".l4dde_ctors." #p))) + +/** Define a function to be a DDEKit initcall. + * + * Define a function to be a DDEKit initcall. This function will then be placed + * in a separate linker section of the binary (called .l4dde_ctors). The L4Env + * construction mechanism will execute all constructors in this section during + * application startup. + * + * This is the right place to place Linux' module_init functions & Co. + * + * \param fn function + */ +#define DDEKIT_INITCALL(fn) DDEKIT_CTOR(fn, 1) + +#define DDEKIT_CTOR(fn, prio) \ + static l4ddekit_initcall_t \ + L4_STICKY(__l4ddekit_initcall_##fn) \ + __l4ddekit_initcall(prio) = (void *)fn + +/** + * Runs all registered initcalls. + */ +void ddekit_do_initcalls(void); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/inline.h.svn-base b/libddekit/include/ddekit/.svn/text-base/inline.h.svn-base new file mode 100644 index 00000000..e59a5c68 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/inline.h.svn-base @@ -0,0 +1,2 @@ +#define INLINE __inline__ __attribute__((always_inline)) + diff --git a/libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base b/libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base new file mode 100644 index 00000000..bbabedb2 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/interrupt.h.svn-base @@ -0,0 +1,57 @@ +/* + * \brief Hardware-interrupt subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2007-01-26 + * + * DDEKit supports registration of one handler function per interrupt. If any + * specific DDE implementation needs to register more than one handler, + * multiplexing has to be implemented there! + */ + +#ifndef _ddekit_interrupt_h +#define _ddekit_interrupt_h + +#include + +#define DDEKIT_IRQ_PRIO 0x11 + +/** + * Attach to hardware interrupt + * + * \param irq IRQ number to attach to + * \param shared set to 1 if interrupt sharing is supported; set to 0 + * otherwise + * \param thread_init called just after DDEKit internal init and before any + * other function + * \param handler IRQ handler for interrupt irq + * \param priv private token (argument for thread_init and handler) + * + * \return pointer to interrupt thread created + */ +ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, + void(*thread_init)(void *), + void(*handler)(void *), void *priv); + +/** + * Detach from a previously attached interrupt. + * + * \param irq IRQ number + */ +void ddekit_interrupt_detach(int irq); + +/** + * Block interrupt. + * + * \param irq IRQ number to block + */ +void ddekit_interrupt_disable(int irq); + +/** + * Enable interrupt. + * + * \param irq IRQ number to block + */ +void ddekit_interrupt_enable(int irq); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/lock.h.svn-base b/libddekit/include/ddekit/.svn/text-base/lock.h.svn-base new file mode 100644 index 00000000..872acad0 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/lock.h.svn-base @@ -0,0 +1,83 @@ +#ifndef _ddekit_lock_h +#define _ddekit_lock_h + +struct ddekit_lock; + +/** Initialize a DDEKit lock. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_init (struct ddekit_lock **mtx); + +/** Uninitialize a DDEKit lock. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_deinit (struct ddekit_lock **mtx); + +/** Acquire a lock. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_lock (struct ddekit_lock **mtx); + +/** Acquire a lock, non-blocking. + * + * \ingroup DDEKit_synchronization + */ +int _ddekit_lock_try_lock(struct ddekit_lock **mtx); + +/** Unlock function. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_unlock (struct ddekit_lock **mtx); + +/** Get lock owner. + * + * \ingroup DDEKit_synchronization + */ +int _ddekit_lock_owner(struct ddekit_lock **mtx); + +// definition of ddekit_lock_t +typedef struct ddekit_lock *ddekit_lock_t; + +// common prototypes +static void ddekit_lock_init_locked(ddekit_lock_t *mtx); +static void ddekit_lock_init_unlocked(ddekit_lock_t *mtx); +#define ddekit_lock_init ddekit_lock_init_unlocked +static void ddekit_lock_deinit (ddekit_lock_t *mtx); +static void ddekit_lock_lock (ddekit_lock_t *mtx); +static int ddekit_lock_try_lock(ddekit_lock_t *mtx); // returns 0 on success, != 0 if it would block +static void ddekit_lock_unlock (ddekit_lock_t *mtx); + +// inline implementation or inline call to non-inline implementation +#include + +static INLINE void ddekit_lock_init_unlocked(ddekit_lock_t *mtx) { + _ddekit_lock_init(mtx); +} + +static INLINE void ddekit_lock_init_locked(ddekit_lock_t *mtx) { + _ddekit_lock_init(mtx); + _ddekit_lock_lock(mtx); +} + +static INLINE void ddekit_lock_deinit(ddekit_lock_t *mtx) { + _ddekit_lock_deinit(mtx); +} +static INLINE void ddekit_lock_lock(ddekit_lock_t *mtx) { + _ddekit_lock_lock(mtx); +} +static INLINE int ddekit_lock_try_lock(ddekit_lock_t *mtx) { + return _ddekit_lock_try_lock(mtx); +} +static INLINE void ddekit_lock_unlock(ddekit_lock_t *mtx) { + _ddekit_lock_unlock(mtx); +} + +static INLINE int ddekit_lock_owner(ddekit_lock_t *mtx) { + return _ddekit_lock_owner(mtx); +} + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/memory.h.svn-base b/libddekit/include/ddekit/.svn/text-base/memory.h.svn-base new file mode 100644 index 00000000..051a4d9e --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/memory.h.svn-base @@ -0,0 +1,144 @@ +/* + * \brief Memory subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-03 + */ + +#ifndef _ddekit_memory_h +#define _ddekit_memory_h + + +/******************* + ** Slab facility ** + *******************/ + +struct ddekit_slab; + +/** + * Store user pointer in slab cache + * + * \param slab pointer to slab cache + * \param data user pointer + */ +void ddekit_slab_set_data(struct ddekit_slab * slab, void *data); + +/** + * Read user pointer from slab cache + * + * \param slab pointer to slab cache + * + * \return stored user pointer or 0 + */ +void *ddekit_slab_get_data(struct ddekit_slab * slab); + +/** + * Allocate slab in slab cache + * + * \param slab pointer to slab cache + * + * \return pointer to allocated slab + */ +void *ddekit_slab_alloc(struct ddekit_slab * slab); + +/** + * Deallocate slab in slab cache + * + * \param slab pointer to slab cache + * \param objp pointer to allocated slab + */ +void ddekit_slab_free(struct ddekit_slab * slab, void *objp); + +/** + * Setup page cache for all slabs + * + * \param pages maximal number of memory pages + * + * If 'pages' is too low, memory pages may be given back to the memory server + * (dm_phys) and just to be allocated again later. This hits performance (but + * saves memory). Increase 'pages' to avoid this thrashing-like effect. + * + * If the maximal number of unused pages is exceeded, subsequent deallocation + * will be freed at the memory server. This page cache caches pages from all + * slabs. + */ +void ddekit_slab_setup_page_cache(unsigned pages); + +/** + * Destroy slab cache + * + * \param slab pointer to slab cache structure + */ +void ddekit_slab_destroy(struct ddekit_slab * slab); + +/** + * Initialize slab cache + * + * \param size size of cache objects + * \param contiguous make this slab use physically contiguous memory + * + * \return pointer to new slab cache or 0 on error + */ +struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous); + + +/********************** + ** Memory allocator ** + **********************/ + +/** + * Allocate large memory block + * + * \param size block size + * \return pointer to new memory block + * + * Allocations via this allocator may be slow (because memory servers are + * involved) and should be used only for large (i.e., > page size) blocks. If + * allocations/deallocations are relatively dynamic this may not be what you + * want. + * + * Allocated blocks have valid virt->phys mappings and are physically + * contiguous. + */ +void *ddekit_large_malloc(int size); + +/** + * Free large memory block + * + * \param p pointer to memory block + */ +void ddekit_large_free(void *p); + +/** FIXME + * contig_malloc() is the lowest-level allocator interface one could implement. + * we should consider to provide vmalloc() too. */ +void *ddekit_contig_malloc( + unsigned long size, + unsigned long low, unsigned long high, + unsigned long alignment, unsigned long boundary +); + + +/***************************** + ** Simple memory allocator ** + *****************************/ + +/** + * Allocate memory block via simple allocator + * + * \param size block size + * \return pointer to new memory block + * + * The blocks allocated via this allocator CANNOT be used for DMA or other + * device operations, i.e., there exists no virt->phys mapping. + */ +void *ddekit_simple_malloc(unsigned size); + +/** + * Free memory block via simple allocator + * + * \param p pointer to memory block + */ +void ddekit_simple_free(void *p); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/panic.h.svn-base b/libddekit/include/ddekit/.svn/text-base/panic.h.svn-base new file mode 100644 index 00000000..1468675f --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/panic.h.svn-base @@ -0,0 +1,16 @@ +#ifndef _ddekit_panic_h +#define _ddekit_panic_h + +/** \defgroup DDEKit_util */ + +/** Panic - print error message and enter the kernel debugger. + * \ingroup DDEKit_util + */ +void ddekit_panic(char *fmt, ...) __attribute__((noreturn)); + +/** Print a debug message. + * \ingroup DDEKit_util + */ +void ddekit_debug(char *fmt, ...); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/pci.h.svn-base b/libddekit/include/ddekit/.svn/text-base/pci.h.svn-base new file mode 100644 index 00000000..9ec7cd4f --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/pci.h.svn-base @@ -0,0 +1,199 @@ +#ifndef _ddekit_pci_h +#define _ddekit_pci_h + +#include + +/** \defgroup DDEKit_pci */ + +/** Our version of PCI_ANY_ID */ +#define DDEKIT_PCI_ANY_ID (~0) + +/** Copy of L4IO_PCIDEV_RES */ +#define DDEKIT_PCIDEV_RES 12 + +struct ddekit_pci_dev; + +/** PCI resource descriptor. Copied from generic_io. + * + * XXX! + */ +typedef struct ddekit_pci_resource { + unsigned long start; + unsigned long end; + unsigned long flags; +} ddekit_pci_res_t; + +void ddekit_pci_init(void); + +int ddekit_pci_get_device(int nr, int *bus, int *slot, int *func); + +int ddekit_pci_read(int bus, int slot, int func, int pos, int len, ddekit_uint32_t *val); +int ddekit_pci_write(int bus, int slot, int func, int pos, int len, ddekit_uint32_t val); + +/** Read byte from PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val read value + * + * \return 0 success + */ +int ddekit_pci_readb (int bus, int slot, int func, int pos, ddekit_uint8_t *val); + +/** Read word from PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val read value + * + * \return 0 success + */ +int ddekit_pci_readw (int bus, int slot, int func, int pos, ddekit_uint16_t *val); + +/** Read dword from PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val read value + * + * \return 0 success + */ +int ddekit_pci_readl (int bus, int slot, int func, int pos, ddekit_uint32_t *val); + +/** Write byte to PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val value to write + * + * \return 0 success + */ +int ddekit_pci_writeb(int bus, int slot, int func, int pos, ddekit_uint8_t val); + +/** Write word to PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val value to write + * + * \return 0 success + */ +int ddekit_pci_writew(int bus, int slot, int func, int pos, ddekit_uint16_t val); + +/** Write word to PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val value to write + * + * \return 0 success + */ +int ddekit_pci_writel(int bus, int slot, int func, int pos, ddekit_uint32_t val); + +/** Find a PCI device. + * + * \ingroup DDEKit_pci + * + * \param bus pointer to bus number or \ref DDEKIT_PCI_ANY_ID + * \param slot pointer to slot number (devfn >> DEVFN_SLOTSHIFT) or \ref DDEKIT_PCI_ANY_ID + * \param func pointer to func number (devfc & DEVFN_FUNCMASK) or \ref DDEKIT_PCI_ANY_ID + * \param start search device list only behind this device (excluding it!), NULL + * searches whole device list + * + * \retval bus bus number + * \retval slot slot number + * \retval func function number + * + * \return device a valid PCI device + * \return NULL if no device found + */ +struct ddekit_pci_dev * +ddekit_pci_find_device(int *bus, int *slot, int *func, struct ddekit_pci_dev *start); + +/** Enable PCI device + * \ingroup DDEKit_pci + */ +int ddekit_pci_enable_device(struct ddekit_pci_dev *dev); + +/** Disable PCI device + * \ingroup DDEKit_pci + */ +int ddekit_pci_disable_device(struct ddekit_pci_dev *dev); + +/** Enable bus-mastering for device. + * \ingroup DDEKit_pci + */ +void ddekit_pci_set_master(struct ddekit_pci_dev *dev); + +/** Get device vendor ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev); + +/** Get device ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev); + +/** Get device subvendor ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev); + +/** Get subdevice ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev); + +/** Get device class ID. + * \ingroup DDEKit_pci + */ +unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev); + +/** Get device's IRQ number. + * \ingroup DDEKit_pci + */ +unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev); + +/** Get device name. + * \ingroup DDEKit_pci + */ +char *ddekit_pci_get_name(struct ddekit_pci_dev *dev); + +/** Get device's slot name. + * \ingroup DDEKit_pci + */ +char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev); + +/** Get one of the device's resources. + * \ingroup DDEKit_pci + */ +ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned int idx); + +int ddekit_pci_irq_enable(int bus, int slot, int func, int pin, int *irq); + +#endif // _ddekit_pci_h diff --git a/libddekit/include/ddekit/.svn/text-base/pgtab.h.svn-base b/libddekit/include/ddekit/.svn/text-base/pgtab.h.svn-base new file mode 100644 index 00000000..3b68192c --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/pgtab.h.svn-base @@ -0,0 +1,86 @@ +/* + * \brief Virtual page-table facility + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-03 + */ + +#ifndef _ddekit_pgtab_h +#define _ddekit_pgtab_h + +#include + +/* FIXME Region types may be defined by pgtab users. Do we really need them + * here? */ +enum ddekit_pgtab_type +{ + PTE_TYPE_OTHER, PTE_TYPE_LARGE, PTE_TYPE_UMA, PTE_TYPE_CONTIG +}; + + +/** + * Set virtual->physical mapping for VM region + * + * \param virt virtual start address for region + * \param phys physical start address for region + * \param pages number of pages in region + * \param type pgtab type for region + */ +void ddekit_pgtab_set_region(void *virt, ddekit_addr_t phys, int pages, int type); + + +/** + * Set virtual->physical mapping for VM region given a specific size in bytes. + * + * Internally, DDEKit manages regions with pages. However, DDEs do not need to tangle + * with the underlying mechanism and therefore can use this function that takes care + * of translating a size to an amount of pages. + */ +void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type); + + +/** + * Clear virtual->physical mapping for VM region + * + * \param virt virtual start address for region + * \param type pgtab type for region + */ +void ddekit_pgtab_clear_region(void *virt, int type); + +/** + * Get physical address for virtual address + * + * \param virt virtual address + * + * \return physical address + */ +ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virt); + +/** + * Get virtual address for physical address + * + * \param physical physical address + * + * \return virtual address + */ +ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical); + +/** + * Get type of VM region. + * + * \param virt virtual address + + * \return VM region type + */ +int ddekit_pgtab_get_type(const void *virt); + +/** + * Get size of VM region. + * + * \param virt virtual address + * + * \return VM region size (in bytes) + */ +int ddekit_pgtab_get_size(const void *virt); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/printf.h.svn-base b/libddekit/include/ddekit/.svn/text-base/printf.h.svn-base new file mode 100644 index 00000000..35b0dfa1 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/printf.h.svn-base @@ -0,0 +1,33 @@ +#ifndef _ddekit_print_h +#define _ddekit_print_h + +#include + +/** Print message. + * \ingroup DDEKit_util + */ +int ddekit_print(const char *); + +/** Print message with format. + * \ingroup DDEKit_util + */ +int ddekit_printf(const char *fmt, ...); + +/** Print message with format list. + * \ingroup DDEKit_util + */ +int ddekit_vprintf(const char *fmt, va_list va); + +/** Log function and message. + * \ingroup DDEKit_util + */ +#define ddekit_log(doit, msg...) \ + do { \ + if (doit) { \ + ddekit_printf("%s(): ", __func__); \ + ddekit_printf(msg); \ + ddekit_printf("\n"); \ + } \ + } while(0); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/resources.h.svn-base b/libddekit/include/ddekit/.svn/text-base/resources.h.svn-base new file mode 100644 index 00000000..e0fa68f0 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/resources.h.svn-base @@ -0,0 +1,13 @@ +#ifndef _ddekit_resources_h +#define _ddekit_resources_h + +#include + +int ddekit_request_dma(int nr); +int ddekit_release_dma(int nr); +int ddekit_request_io (ddekit_addr_t start, ddekit_addr_t count); +int ddekit_release_io (ddekit_addr_t start, ddekit_addr_t count); +int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr); +int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base b/libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base new file mode 100644 index 00000000..c959919d --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/semaphore.h.svn-base @@ -0,0 +1,50 @@ +#ifndef _ddekit_semaphore_h +#define _ddekit_semaphore_h + +/** \defgroup DDEKit_synchronization */ + +struct ddekit_sem; +typedef struct ddekit_sem ddekit_sem_t; + +/** Initialize DDEKit semaphore. + * + * \ingroup DDEKit_synchronization + * + * \param value initial semaphore counter + */ +ddekit_sem_t *ddekit_sem_init(int value); + +/** Uninitialize semaphore. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_sem_deinit(ddekit_sem_t *sem); + +/** Semaphore down method. */ +void ddekit_sem_down(ddekit_sem_t *sem); + +/** Semaphore down method, non-blocking. + * + * \ingroup DDEKit_synchronization + * + * \return 0 success + * \return !=0 would block + */ +int ddekit_sem_down_try(ddekit_sem_t *sem); + +/** Semaphore down with timeout. + * + * \ingroup DDEKit_synchronization + * + * \return 0 success + * \return !=0 would block + */ +int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo); + +/** Semaphore up method. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_sem_up(ddekit_sem_t *sem); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/thread.h.svn-base b/libddekit/include/ddekit/.svn/text-base/thread.h.svn-base new file mode 100644 index 00000000..ecd399d9 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/thread.h.svn-base @@ -0,0 +1,162 @@ +#ifndef _ddekit_thread_h +#define _ddekit_thread_h + +/** \defgroup DDEKit_threads */ + +#include + +struct ddekit_thread; +typedef struct ddekit_thread ddekit_thread_t; + +/** Create thread + * + * \ingroup DDEKit_threads + * + * Create a new thread running the specified thread function with the specified + * arguments. The thread is assigned the given internal name. + * + * Additionally, DDEKit threads possess a thread-local storage area where they + * may store arbitrary data. + * + * \param fun thread function + * \param arg optional argument to thread function, set to NULL if not needed + * \param name internal thread name + */ +ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name); + +/** Reference to own DDEKit thread id. + * + * \ingroup DDEKit_threads + */ +ddekit_thread_t *ddekit_thread_myself(void); + +/** Initialize thread with given name. + * + * \ingroup DDEKit_threads + * + * This function may be used by threads that were not created using + * \ref ddekit_thread_create. This enables such threads to be handled as if they + * were DDEKit threads. + */ +ddekit_thread_t *ddekit_thread_setup_myself(const char *name); + +/** Get TLS data for a specific thread. + * + * \ingroup DDEKit_threads + * + * \return Pointer to TLS data of this thread. + */ +void *ddekit_thread_get_data(ddekit_thread_t *thread); + +/** Get TLS data for current thread. + * + * \ingroup DDEKit_threads + * + * Same as calling \ref ddekit_thread_get_data with \ref ddekit_thread_myself + * as parameter. + * + * \return Pointer to TLS data of current thread. + */ +void *ddekit_thread_get_my_data(void); + +/** Set TLS data for specific thread. + * + * \ingroup DDEKit_threads + * + * \param thread DDEKit thread + * \param data pointer to thread data + */ +void ddekit_thread_set_data(ddekit_thread_t *thread, void *data); + +/** Set TLS data for current thread. + * + * \ingroup DDEKit_threads + * + * \param data pointer to thread data + */ +void ddekit_thread_set_my_data(void *data); + +/** Sleep for some miliseconds. + * + * \ingroup DDEKit_threads + * + * \param msecs time to sleep in ms. + */ +void ddekit_thread_msleep(unsigned long msecs); + +/** Sleep for some microseconds. + * + * \ingroup DDEKit_threads + * + * \param usecs time to sleep in µs. + */ +void ddekit_thread_usleep(unsigned long usecs); + +/** Sleep for some nanoseconds. + * + * \ingroup DDEKit_threads + * + * \param usecs time to sleep in ns. + */ +void ddekit_thread_nsleep(unsigned long nsecs); + +/** Sleep until a lock becomes unlocked. + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_sleep(ddekit_lock_t *lock); + +/** Wakeup a waiting thread. + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_wakeup(ddekit_thread_t *thread); + +/** Terminate a thread + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_exit(void) __attribute__((noreturn)); + +/** Terminate a thread + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_terminate(ddekit_thread_t *thread); + +/** Get the name, a thread registered with DDEKit. + * + * \ingroup DDEKit_threads + */ +const char *ddekit_thread_get_name(ddekit_thread_t *thread); + +/** Get unique ID of a DDEKit thread. + * + * \ingroup DDEKit_threads + * + * DDEKit does not allow direct access to the thread data + * structure, since this struct contains L4-specific data types. + * However, applications might want to get some kind of ID related + * to a ddekit_thread, for instance to use it as a Linux-like PID. + */ +int ddekit_thread_get_id(ddekit_thread_t *thread); + +/** Hint that this thread is done and may be scheduled somehow. + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_schedule(void); + +/** Hint that this thread is done and may be scheduled somehow. + * + * \ingroup DDEKit_threads + */ +void ddekit_yield(void); + +/** Initialize DDEKit thread subsystem. + * + * \ingroup DDEKit_threads + */ +void ddekit_init_threads(void); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/timer.h.svn-base b/libddekit/include/ddekit/.svn/text-base/timer.h.svn-base new file mode 100644 index 00000000..c352475c --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/timer.h.svn-base @@ -0,0 +1,55 @@ +#ifndef _ddekit_timer_h +#define _ddekit_timer_h + +#include + +enum +{ + DDEKIT_INVALID_TIMER_ID = -1, +}; + +/** \defgroup DDEKit_timer + * + * Timer subsystem + * + * DDEKit provides a generic timer implementation that enables users + * to execute a function with some arguments after a certain period + * of time. DDEKit therefore starts a timer thread that executes these + * functions and keeps track of the currently running timers. + */ + +/** Add a timer event. After the absolute timeout has expired, function fn + * is called with args as arguments. + * + * \ingroup DDEKit_timer + * + * \return >=0 valid timer ID + * \return < 0 error + */ +int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout); + +/** Delete timer with the corresponding timer id. + * + * \ingroup DDEKit_timer + */ +int ddekit_del_timer(int timer); + +/** Check whether a timer is pending + * + * \ingroup DDEKit_timer + * + * Linux needs this. + */ +int ddekit_timer_pending(int timer); + +/** Initialization function, startup timer thread + * + * \ingroup DDEKit_timer + */ +void ddekit_init_timers(void); + +/** Get the timer thread. + */ +ddekit_thread_t *ddekit_get_timer_thread(void); + +#endif diff --git a/libddekit/include/ddekit/.svn/text-base/types.h.svn-base b/libddekit/include/ddekit/.svn/text-base/types.h.svn-base new file mode 100644 index 00000000..83d92c65 --- /dev/null +++ b/libddekit/include/ddekit/.svn/text-base/types.h.svn-base @@ -0,0 +1,22 @@ +/* + * \brief Types for ddekit (x86 version) + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-09 + * + * FIXME This is definitely arch-dependent! Move to ARCH-something + */ + +#ifndef _DDEKIT_TYPES_H +#define _DDEKIT_TYPES_H + +typedef signed char ddekit_int8_t; +typedef unsigned char ddekit_uint8_t; +typedef signed short int ddekit_int16_t; +typedef unsigned short int ddekit_uint16_t; +typedef signed int ddekit_int32_t; +typedef unsigned int ddekit_uint32_t; + +typedef unsigned long ddekit_addr_t; + +#endif diff --git a/libddekit/include/ddekit/assert.h b/libddekit/include/ddekit/assert.h new file mode 100644 index 00000000..5d572b49 --- /dev/null +++ b/libddekit/include/ddekit/assert.h @@ -0,0 +1,23 @@ +#ifndef _ddekit_assert_h +#define _ddekit_assert_h + +#include +#include + +/** \file ddekit/assert.h */ + +/** Assert that an expression is true and panic if not. + * \ingroup DDEKit_util + */ +#define Assert(expr) do \ + { \ + if (!(expr)) { \ + ddekit_print("\033[31;1mDDE: Assertion failed: "#expr"\033[0m\n"); \ + ddekit_printf(" File: %s:%d\n",__FILE__,__LINE__); \ + ddekit_printf(" Function: %s()\n", __FUNCTION__); \ + ddekit_panic("Assertion failed."); \ + }} while (0); + +#endif + +#define assert Assert diff --git a/libddekit/include/ddekit/condvar.h b/libddekit/include/ddekit/condvar.h new file mode 100644 index 00000000..b6dc4bd3 --- /dev/null +++ b/libddekit/include/ddekit/condvar.h @@ -0,0 +1,54 @@ +#ifndef _ddekit_condvar_h +#define _ddekit_condvar_h + +/** \file ddekit/condvar.h */ + +#include + +struct ddekit_condvar; +typedef struct ddekit_condvar ddekit_condvar_t; + +/** Initialize conditional variable. + * + * \ingroup DDEKit_synchronization + */ +ddekit_condvar_t * ddekit_condvar_init(void); + +/** Uninitialize conditional variable. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_deinit(ddekit_condvar_t *cvp); + +/** Wait on a conditional variable. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp); + +/** Wait on a conditional variable at most until a timeout expires. + * + * \ingroup DDEKit_synchronization + * + * \param cvp pointer to condvar + * \param mp lock + * \param timo timeout in ms + * + * \return 0 success + * \return !=0 timeout + */ +int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp, ddekit_lock_t *mp, int timo); + +/** Send signal to the next one waiting for condvar. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_signal(ddekit_condvar_t *cvp); + +/** Send signal to all threads waiting for condvar. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_condvar_broadcast(ddekit_condvar_t *cvp); + +#endif diff --git a/libddekit/include/ddekit/debug.h b/libddekit/include/ddekit/debug.h new file mode 100644 index 00000000..79a8e7b5 --- /dev/null +++ b/libddekit/include/ddekit/debug.h @@ -0,0 +1,8 @@ +#define DDEBUG_QUIET 0 +#define DDEBUG_ERR 1 +#define DDEBUG_WARN 2 +#define DDEBUG_INFO 3 +#define DDEBUG_VERBOSE 4 + +#define DDEBUG_MEM DDEBUG_INFO + diff --git a/libddekit/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h new file mode 100644 index 00000000..b503cc6a --- /dev/null +++ b/libddekit/include/ddekit/initcall.h @@ -0,0 +1,42 @@ +#ifndef _ddekit_initcall_h +#define _ddekit_initcall_h + +// from l4/sys/compiler.h +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4 +#define L4_STICKY(x) __attribute__((used)) x +#else +#define L4_STICKY(x) __attribute__((unused)) x +#endif + +#define l4str(s) #s + +// from dde_linux/ARCH-x86/ctor.h +typedef void (*l4ddekit_initcall_t)(void); + +#define __l4ddekit_initcall(p) \ + __attribute__ ((__section__ (".l4dde_ctors." #p))) + +/** Define a function to be a DDEKit initcall. + * + * Define a function to be a DDEKit initcall. This function will then be placed + * in a separate linker section of the binary (called .l4dde_ctors). The L4Env + * construction mechanism will execute all constructors in this section during + * application startup. + * + * This is the right place to place Linux' module_init functions & Co. + * + * \param fn function + */ +#define DDEKIT_INITCALL(fn) DDEKIT_CTOR(fn, 1) + +#define DDEKIT_CTOR(fn, prio) \ + static l4ddekit_initcall_t \ + L4_STICKY(__l4ddekit_initcall_##fn) \ + __l4ddekit_initcall(prio) = (void *)fn + +/** + * Runs all registered initcalls. + */ +void ddekit_do_initcalls(void); + +#endif diff --git a/libddekit/include/ddekit/inline.h b/libddekit/include/ddekit/inline.h new file mode 100644 index 00000000..e59a5c68 --- /dev/null +++ b/libddekit/include/ddekit/inline.h @@ -0,0 +1,2 @@ +#define INLINE __inline__ __attribute__((always_inline)) + diff --git a/libddekit/include/ddekit/interrupt.h b/libddekit/include/ddekit/interrupt.h new file mode 100644 index 00000000..bbabedb2 --- /dev/null +++ b/libddekit/include/ddekit/interrupt.h @@ -0,0 +1,57 @@ +/* + * \brief Hardware-interrupt subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2007-01-26 + * + * DDEKit supports registration of one handler function per interrupt. If any + * specific DDE implementation needs to register more than one handler, + * multiplexing has to be implemented there! + */ + +#ifndef _ddekit_interrupt_h +#define _ddekit_interrupt_h + +#include + +#define DDEKIT_IRQ_PRIO 0x11 + +/** + * Attach to hardware interrupt + * + * \param irq IRQ number to attach to + * \param shared set to 1 if interrupt sharing is supported; set to 0 + * otherwise + * \param thread_init called just after DDEKit internal init and before any + * other function + * \param handler IRQ handler for interrupt irq + * \param priv private token (argument for thread_init and handler) + * + * \return pointer to interrupt thread created + */ +ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, + void(*thread_init)(void *), + void(*handler)(void *), void *priv); + +/** + * Detach from a previously attached interrupt. + * + * \param irq IRQ number + */ +void ddekit_interrupt_detach(int irq); + +/** + * Block interrupt. + * + * \param irq IRQ number to block + */ +void ddekit_interrupt_disable(int irq); + +/** + * Enable interrupt. + * + * \param irq IRQ number to block + */ +void ddekit_interrupt_enable(int irq); + +#endif diff --git a/libddekit/include/ddekit/lock.h b/libddekit/include/ddekit/lock.h new file mode 100644 index 00000000..872acad0 --- /dev/null +++ b/libddekit/include/ddekit/lock.h @@ -0,0 +1,83 @@ +#ifndef _ddekit_lock_h +#define _ddekit_lock_h + +struct ddekit_lock; + +/** Initialize a DDEKit lock. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_init (struct ddekit_lock **mtx); + +/** Uninitialize a DDEKit lock. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_deinit (struct ddekit_lock **mtx); + +/** Acquire a lock. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_lock (struct ddekit_lock **mtx); + +/** Acquire a lock, non-blocking. + * + * \ingroup DDEKit_synchronization + */ +int _ddekit_lock_try_lock(struct ddekit_lock **mtx); + +/** Unlock function. + * + * \ingroup DDEKit_synchronization + */ +void _ddekit_lock_unlock (struct ddekit_lock **mtx); + +/** Get lock owner. + * + * \ingroup DDEKit_synchronization + */ +int _ddekit_lock_owner(struct ddekit_lock **mtx); + +// definition of ddekit_lock_t +typedef struct ddekit_lock *ddekit_lock_t; + +// common prototypes +static void ddekit_lock_init_locked(ddekit_lock_t *mtx); +static void ddekit_lock_init_unlocked(ddekit_lock_t *mtx); +#define ddekit_lock_init ddekit_lock_init_unlocked +static void ddekit_lock_deinit (ddekit_lock_t *mtx); +static void ddekit_lock_lock (ddekit_lock_t *mtx); +static int ddekit_lock_try_lock(ddekit_lock_t *mtx); // returns 0 on success, != 0 if it would block +static void ddekit_lock_unlock (ddekit_lock_t *mtx); + +// inline implementation or inline call to non-inline implementation +#include + +static INLINE void ddekit_lock_init_unlocked(ddekit_lock_t *mtx) { + _ddekit_lock_init(mtx); +} + +static INLINE void ddekit_lock_init_locked(ddekit_lock_t *mtx) { + _ddekit_lock_init(mtx); + _ddekit_lock_lock(mtx); +} + +static INLINE void ddekit_lock_deinit(ddekit_lock_t *mtx) { + _ddekit_lock_deinit(mtx); +} +static INLINE void ddekit_lock_lock(ddekit_lock_t *mtx) { + _ddekit_lock_lock(mtx); +} +static INLINE int ddekit_lock_try_lock(ddekit_lock_t *mtx) { + return _ddekit_lock_try_lock(mtx); +} +static INLINE void ddekit_lock_unlock(ddekit_lock_t *mtx) { + _ddekit_lock_unlock(mtx); +} + +static INLINE int ddekit_lock_owner(ddekit_lock_t *mtx) { + return _ddekit_lock_owner(mtx); +} + +#endif diff --git a/libddekit/include/ddekit/memory.h b/libddekit/include/ddekit/memory.h new file mode 100644 index 00000000..051a4d9e --- /dev/null +++ b/libddekit/include/ddekit/memory.h @@ -0,0 +1,144 @@ +/* + * \brief Memory subsystem + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-03 + */ + +#ifndef _ddekit_memory_h +#define _ddekit_memory_h + + +/******************* + ** Slab facility ** + *******************/ + +struct ddekit_slab; + +/** + * Store user pointer in slab cache + * + * \param slab pointer to slab cache + * \param data user pointer + */ +void ddekit_slab_set_data(struct ddekit_slab * slab, void *data); + +/** + * Read user pointer from slab cache + * + * \param slab pointer to slab cache + * + * \return stored user pointer or 0 + */ +void *ddekit_slab_get_data(struct ddekit_slab * slab); + +/** + * Allocate slab in slab cache + * + * \param slab pointer to slab cache + * + * \return pointer to allocated slab + */ +void *ddekit_slab_alloc(struct ddekit_slab * slab); + +/** + * Deallocate slab in slab cache + * + * \param slab pointer to slab cache + * \param objp pointer to allocated slab + */ +void ddekit_slab_free(struct ddekit_slab * slab, void *objp); + +/** + * Setup page cache for all slabs + * + * \param pages maximal number of memory pages + * + * If 'pages' is too low, memory pages may be given back to the memory server + * (dm_phys) and just to be allocated again later. This hits performance (but + * saves memory). Increase 'pages' to avoid this thrashing-like effect. + * + * If the maximal number of unused pages is exceeded, subsequent deallocation + * will be freed at the memory server. This page cache caches pages from all + * slabs. + */ +void ddekit_slab_setup_page_cache(unsigned pages); + +/** + * Destroy slab cache + * + * \param slab pointer to slab cache structure + */ +void ddekit_slab_destroy(struct ddekit_slab * slab); + +/** + * Initialize slab cache + * + * \param size size of cache objects + * \param contiguous make this slab use physically contiguous memory + * + * \return pointer to new slab cache or 0 on error + */ +struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous); + + +/********************** + ** Memory allocator ** + **********************/ + +/** + * Allocate large memory block + * + * \param size block size + * \return pointer to new memory block + * + * Allocations via this allocator may be slow (because memory servers are + * involved) and should be used only for large (i.e., > page size) blocks. If + * allocations/deallocations are relatively dynamic this may not be what you + * want. + * + * Allocated blocks have valid virt->phys mappings and are physically + * contiguous. + */ +void *ddekit_large_malloc(int size); + +/** + * Free large memory block + * + * \param p pointer to memory block + */ +void ddekit_large_free(void *p); + +/** FIXME + * contig_malloc() is the lowest-level allocator interface one could implement. + * we should consider to provide vmalloc() too. */ +void *ddekit_contig_malloc( + unsigned long size, + unsigned long low, unsigned long high, + unsigned long alignment, unsigned long boundary +); + + +/***************************** + ** Simple memory allocator ** + *****************************/ + +/** + * Allocate memory block via simple allocator + * + * \param size block size + * \return pointer to new memory block + * + * The blocks allocated via this allocator CANNOT be used for DMA or other + * device operations, i.e., there exists no virt->phys mapping. + */ +void *ddekit_simple_malloc(unsigned size); + +/** + * Free memory block via simple allocator + * + * \param p pointer to memory block + */ +void ddekit_simple_free(void *p); + +#endif diff --git a/libddekit/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h new file mode 100644 index 00000000..1468675f --- /dev/null +++ b/libddekit/include/ddekit/panic.h @@ -0,0 +1,16 @@ +#ifndef _ddekit_panic_h +#define _ddekit_panic_h + +/** \defgroup DDEKit_util */ + +/** Panic - print error message and enter the kernel debugger. + * \ingroup DDEKit_util + */ +void ddekit_panic(char *fmt, ...) __attribute__((noreturn)); + +/** Print a debug message. + * \ingroup DDEKit_util + */ +void ddekit_debug(char *fmt, ...); + +#endif diff --git a/libddekit/include/ddekit/pci.h b/libddekit/include/ddekit/pci.h new file mode 100644 index 00000000..9ec7cd4f --- /dev/null +++ b/libddekit/include/ddekit/pci.h @@ -0,0 +1,199 @@ +#ifndef _ddekit_pci_h +#define _ddekit_pci_h + +#include + +/** \defgroup DDEKit_pci */ + +/** Our version of PCI_ANY_ID */ +#define DDEKIT_PCI_ANY_ID (~0) + +/** Copy of L4IO_PCIDEV_RES */ +#define DDEKIT_PCIDEV_RES 12 + +struct ddekit_pci_dev; + +/** PCI resource descriptor. Copied from generic_io. + * + * XXX! + */ +typedef struct ddekit_pci_resource { + unsigned long start; + unsigned long end; + unsigned long flags; +} ddekit_pci_res_t; + +void ddekit_pci_init(void); + +int ddekit_pci_get_device(int nr, int *bus, int *slot, int *func); + +int ddekit_pci_read(int bus, int slot, int func, int pos, int len, ddekit_uint32_t *val); +int ddekit_pci_write(int bus, int slot, int func, int pos, int len, ddekit_uint32_t val); + +/** Read byte from PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val read value + * + * \return 0 success + */ +int ddekit_pci_readb (int bus, int slot, int func, int pos, ddekit_uint8_t *val); + +/** Read word from PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val read value + * + * \return 0 success + */ +int ddekit_pci_readw (int bus, int slot, int func, int pos, ddekit_uint16_t *val); + +/** Read dword from PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val read value + * + * \return 0 success + */ +int ddekit_pci_readl (int bus, int slot, int func, int pos, ddekit_uint32_t *val); + +/** Write byte to PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val value to write + * + * \return 0 success + */ +int ddekit_pci_writeb(int bus, int slot, int func, int pos, ddekit_uint8_t val); + +/** Write word to PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val value to write + * + * \return 0 success + */ +int ddekit_pci_writew(int bus, int slot, int func, int pos, ddekit_uint16_t val); + +/** Write word to PCI config space. + * + * \ingroup DDEKit_pci + * + * \param bus bus ID + * \param slot slot # + * \param func function # + * \param pos offset in config space + * \retval val value to write + * + * \return 0 success + */ +int ddekit_pci_writel(int bus, int slot, int func, int pos, ddekit_uint32_t val); + +/** Find a PCI device. + * + * \ingroup DDEKit_pci + * + * \param bus pointer to bus number or \ref DDEKIT_PCI_ANY_ID + * \param slot pointer to slot number (devfn >> DEVFN_SLOTSHIFT) or \ref DDEKIT_PCI_ANY_ID + * \param func pointer to func number (devfc & DEVFN_FUNCMASK) or \ref DDEKIT_PCI_ANY_ID + * \param start search device list only behind this device (excluding it!), NULL + * searches whole device list + * + * \retval bus bus number + * \retval slot slot number + * \retval func function number + * + * \return device a valid PCI device + * \return NULL if no device found + */ +struct ddekit_pci_dev * +ddekit_pci_find_device(int *bus, int *slot, int *func, struct ddekit_pci_dev *start); + +/** Enable PCI device + * \ingroup DDEKit_pci + */ +int ddekit_pci_enable_device(struct ddekit_pci_dev *dev); + +/** Disable PCI device + * \ingroup DDEKit_pci + */ +int ddekit_pci_disable_device(struct ddekit_pci_dev *dev); + +/** Enable bus-mastering for device. + * \ingroup DDEKit_pci + */ +void ddekit_pci_set_master(struct ddekit_pci_dev *dev); + +/** Get device vendor ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev); + +/** Get device ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev); + +/** Get device subvendor ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev); + +/** Get subdevice ID. + * \ingroup DDEKit_pci + */ +unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev); + +/** Get device class ID. + * \ingroup DDEKit_pci + */ +unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev); + +/** Get device's IRQ number. + * \ingroup DDEKit_pci + */ +unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev); + +/** Get device name. + * \ingroup DDEKit_pci + */ +char *ddekit_pci_get_name(struct ddekit_pci_dev *dev); + +/** Get device's slot name. + * \ingroup DDEKit_pci + */ +char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev); + +/** Get one of the device's resources. + * \ingroup DDEKit_pci + */ +ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned int idx); + +int ddekit_pci_irq_enable(int bus, int slot, int func, int pin, int *irq); + +#endif // _ddekit_pci_h diff --git a/libddekit/include/ddekit/pgtab.h b/libddekit/include/ddekit/pgtab.h new file mode 100644 index 00000000..3b68192c --- /dev/null +++ b/libddekit/include/ddekit/pgtab.h @@ -0,0 +1,86 @@ +/* + * \brief Virtual page-table facility + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-03 + */ + +#ifndef _ddekit_pgtab_h +#define _ddekit_pgtab_h + +#include + +/* FIXME Region types may be defined by pgtab users. Do we really need them + * here? */ +enum ddekit_pgtab_type +{ + PTE_TYPE_OTHER, PTE_TYPE_LARGE, PTE_TYPE_UMA, PTE_TYPE_CONTIG +}; + + +/** + * Set virtual->physical mapping for VM region + * + * \param virt virtual start address for region + * \param phys physical start address for region + * \param pages number of pages in region + * \param type pgtab type for region + */ +void ddekit_pgtab_set_region(void *virt, ddekit_addr_t phys, int pages, int type); + + +/** + * Set virtual->physical mapping for VM region given a specific size in bytes. + * + * Internally, DDEKit manages regions with pages. However, DDEs do not need to tangle + * with the underlying mechanism and therefore can use this function that takes care + * of translating a size to an amount of pages. + */ +void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type); + + +/** + * Clear virtual->physical mapping for VM region + * + * \param virt virtual start address for region + * \param type pgtab type for region + */ +void ddekit_pgtab_clear_region(void *virt, int type); + +/** + * Get physical address for virtual address + * + * \param virt virtual address + * + * \return physical address + */ +ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virt); + +/** + * Get virtual address for physical address + * + * \param physical physical address + * + * \return virtual address + */ +ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical); + +/** + * Get type of VM region. + * + * \param virt virtual address + + * \return VM region type + */ +int ddekit_pgtab_get_type(const void *virt); + +/** + * Get size of VM region. + * + * \param virt virtual address + * + * \return VM region size (in bytes) + */ +int ddekit_pgtab_get_size(const void *virt); + +#endif diff --git a/libddekit/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h new file mode 100644 index 00000000..35b0dfa1 --- /dev/null +++ b/libddekit/include/ddekit/printf.h @@ -0,0 +1,33 @@ +#ifndef _ddekit_print_h +#define _ddekit_print_h + +#include + +/** Print message. + * \ingroup DDEKit_util + */ +int ddekit_print(const char *); + +/** Print message with format. + * \ingroup DDEKit_util + */ +int ddekit_printf(const char *fmt, ...); + +/** Print message with format list. + * \ingroup DDEKit_util + */ +int ddekit_vprintf(const char *fmt, va_list va); + +/** Log function and message. + * \ingroup DDEKit_util + */ +#define ddekit_log(doit, msg...) \ + do { \ + if (doit) { \ + ddekit_printf("%s(): ", __func__); \ + ddekit_printf(msg); \ + ddekit_printf("\n"); \ + } \ + } while(0); + +#endif diff --git a/libddekit/include/ddekit/resources.h b/libddekit/include/ddekit/resources.h new file mode 100644 index 00000000..e0fa68f0 --- /dev/null +++ b/libddekit/include/ddekit/resources.h @@ -0,0 +1,13 @@ +#ifndef _ddekit_resources_h +#define _ddekit_resources_h + +#include + +int ddekit_request_dma(int nr); +int ddekit_release_dma(int nr); +int ddekit_request_io (ddekit_addr_t start, ddekit_addr_t count); +int ddekit_release_io (ddekit_addr_t start, ddekit_addr_t count); +int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr); +int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count); + +#endif diff --git a/libddekit/include/ddekit/semaphore.h b/libddekit/include/ddekit/semaphore.h new file mode 100644 index 00000000..c959919d --- /dev/null +++ b/libddekit/include/ddekit/semaphore.h @@ -0,0 +1,50 @@ +#ifndef _ddekit_semaphore_h +#define _ddekit_semaphore_h + +/** \defgroup DDEKit_synchronization */ + +struct ddekit_sem; +typedef struct ddekit_sem ddekit_sem_t; + +/** Initialize DDEKit semaphore. + * + * \ingroup DDEKit_synchronization + * + * \param value initial semaphore counter + */ +ddekit_sem_t *ddekit_sem_init(int value); + +/** Uninitialize semaphore. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_sem_deinit(ddekit_sem_t *sem); + +/** Semaphore down method. */ +void ddekit_sem_down(ddekit_sem_t *sem); + +/** Semaphore down method, non-blocking. + * + * \ingroup DDEKit_synchronization + * + * \return 0 success + * \return !=0 would block + */ +int ddekit_sem_down_try(ddekit_sem_t *sem); + +/** Semaphore down with timeout. + * + * \ingroup DDEKit_synchronization + * + * \return 0 success + * \return !=0 would block + */ +int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo); + +/** Semaphore up method. + * + * \ingroup DDEKit_synchronization + */ +void ddekit_sem_up(ddekit_sem_t *sem); + +#endif diff --git a/libddekit/include/ddekit/thread.h b/libddekit/include/ddekit/thread.h new file mode 100644 index 00000000..ecd399d9 --- /dev/null +++ b/libddekit/include/ddekit/thread.h @@ -0,0 +1,162 @@ +#ifndef _ddekit_thread_h +#define _ddekit_thread_h + +/** \defgroup DDEKit_threads */ + +#include + +struct ddekit_thread; +typedef struct ddekit_thread ddekit_thread_t; + +/** Create thread + * + * \ingroup DDEKit_threads + * + * Create a new thread running the specified thread function with the specified + * arguments. The thread is assigned the given internal name. + * + * Additionally, DDEKit threads possess a thread-local storage area where they + * may store arbitrary data. + * + * \param fun thread function + * \param arg optional argument to thread function, set to NULL if not needed + * \param name internal thread name + */ +ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name); + +/** Reference to own DDEKit thread id. + * + * \ingroup DDEKit_threads + */ +ddekit_thread_t *ddekit_thread_myself(void); + +/** Initialize thread with given name. + * + * \ingroup DDEKit_threads + * + * This function may be used by threads that were not created using + * \ref ddekit_thread_create. This enables such threads to be handled as if they + * were DDEKit threads. + */ +ddekit_thread_t *ddekit_thread_setup_myself(const char *name); + +/** Get TLS data for a specific thread. + * + * \ingroup DDEKit_threads + * + * \return Pointer to TLS data of this thread. + */ +void *ddekit_thread_get_data(ddekit_thread_t *thread); + +/** Get TLS data for current thread. + * + * \ingroup DDEKit_threads + * + * Same as calling \ref ddekit_thread_get_data with \ref ddekit_thread_myself + * as parameter. + * + * \return Pointer to TLS data of current thread. + */ +void *ddekit_thread_get_my_data(void); + +/** Set TLS data for specific thread. + * + * \ingroup DDEKit_threads + * + * \param thread DDEKit thread + * \param data pointer to thread data + */ +void ddekit_thread_set_data(ddekit_thread_t *thread, void *data); + +/** Set TLS data for current thread. + * + * \ingroup DDEKit_threads + * + * \param data pointer to thread data + */ +void ddekit_thread_set_my_data(void *data); + +/** Sleep for some miliseconds. + * + * \ingroup DDEKit_threads + * + * \param msecs time to sleep in ms. + */ +void ddekit_thread_msleep(unsigned long msecs); + +/** Sleep for some microseconds. + * + * \ingroup DDEKit_threads + * + * \param usecs time to sleep in µs. + */ +void ddekit_thread_usleep(unsigned long usecs); + +/** Sleep for some nanoseconds. + * + * \ingroup DDEKit_threads + * + * \param usecs time to sleep in ns. + */ +void ddekit_thread_nsleep(unsigned long nsecs); + +/** Sleep until a lock becomes unlocked. + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_sleep(ddekit_lock_t *lock); + +/** Wakeup a waiting thread. + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_wakeup(ddekit_thread_t *thread); + +/** Terminate a thread + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_exit(void) __attribute__((noreturn)); + +/** Terminate a thread + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_terminate(ddekit_thread_t *thread); + +/** Get the name, a thread registered with DDEKit. + * + * \ingroup DDEKit_threads + */ +const char *ddekit_thread_get_name(ddekit_thread_t *thread); + +/** Get unique ID of a DDEKit thread. + * + * \ingroup DDEKit_threads + * + * DDEKit does not allow direct access to the thread data + * structure, since this struct contains L4-specific data types. + * However, applications might want to get some kind of ID related + * to a ddekit_thread, for instance to use it as a Linux-like PID. + */ +int ddekit_thread_get_id(ddekit_thread_t *thread); + +/** Hint that this thread is done and may be scheduled somehow. + * + * \ingroup DDEKit_threads + */ +void ddekit_thread_schedule(void); + +/** Hint that this thread is done and may be scheduled somehow. + * + * \ingroup DDEKit_threads + */ +void ddekit_yield(void); + +/** Initialize DDEKit thread subsystem. + * + * \ingroup DDEKit_threads + */ +void ddekit_init_threads(void); + +#endif diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h new file mode 100644 index 00000000..c352475c --- /dev/null +++ b/libddekit/include/ddekit/timer.h @@ -0,0 +1,55 @@ +#ifndef _ddekit_timer_h +#define _ddekit_timer_h + +#include + +enum +{ + DDEKIT_INVALID_TIMER_ID = -1, +}; + +/** \defgroup DDEKit_timer + * + * Timer subsystem + * + * DDEKit provides a generic timer implementation that enables users + * to execute a function with some arguments after a certain period + * of time. DDEKit therefore starts a timer thread that executes these + * functions and keeps track of the currently running timers. + */ + +/** Add a timer event. After the absolute timeout has expired, function fn + * is called with args as arguments. + * + * \ingroup DDEKit_timer + * + * \return >=0 valid timer ID + * \return < 0 error + */ +int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout); + +/** Delete timer with the corresponding timer id. + * + * \ingroup DDEKit_timer + */ +int ddekit_del_timer(int timer); + +/** Check whether a timer is pending + * + * \ingroup DDEKit_timer + * + * Linux needs this. + */ +int ddekit_timer_pending(int timer); + +/** Initialization function, startup timer thread + * + * \ingroup DDEKit_timer + */ +void ddekit_init_timers(void); + +/** Get the timer thread. + */ +ddekit_thread_t *ddekit_get_timer_thread(void); + +#endif diff --git a/libddekit/include/ddekit/types.h b/libddekit/include/ddekit/types.h new file mode 100644 index 00000000..83d92c65 --- /dev/null +++ b/libddekit/include/ddekit/types.h @@ -0,0 +1,22 @@ +/* + * \brief Types for ddekit (x86 version) + * \author Thomas Friebel + * \author Christian Helmuth + * \date 2006-11-09 + * + * FIXME This is definitely arch-dependent! Move to ARCH-something + */ + +#ifndef _DDEKIT_TYPES_H +#define _DDEKIT_TYPES_H + +typedef signed char ddekit_int8_t; +typedef unsigned char ddekit_uint8_t; +typedef signed short int ddekit_int16_t; +typedef unsigned short int ddekit_uint16_t; +typedef signed int ddekit_int32_t; +typedef unsigned int ddekit_uint32_t; + +typedef unsigned long ddekit_addr_t; + +#endif -- cgit v1.2.3 From 6c2afa3c02447135e2bedd11f0b86833d4533692 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 17 Nov 2009 11:19:05 +0100 Subject: Use libpciaccess to implement it. --- libddekit/include/ddekit/pci.h | 2 +- libddekit/pci.c | 90 ++++++++++++++++-------------------------- 2 files changed, 34 insertions(+), 58 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/pci.h b/libddekit/include/ddekit/pci.h index 9ec7cd4f..5a5fd29b 100644 --- a/libddekit/include/ddekit/pci.h +++ b/libddekit/include/ddekit/pci.h @@ -1,7 +1,7 @@ #ifndef _ddekit_pci_h #define _ddekit_pci_h -#include +#include "ddekit/types.h" /** \defgroup DDEKit_pci */ diff --git a/libddekit/pci.c b/libddekit/pci.c index 35fb7aea..32e02b84 100644 --- a/libddekit/pci.c +++ b/libddekit/pci.c @@ -1,14 +1,5 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - +#include +#include "ddekit/pci.h" #include "config.h" #define dbg_this 0 @@ -20,7 +11,7 @@ typedef struct ddekit_pci_dev { int bus; /**< bus ID */ int slot; /**< slot ID */ int func; /**< function */ - l4io_pci_dev_t l4dev; /**< L4IO handle */ + struct pci_device *dev; struct ddekit_pci_dev *next; /**< chaining info */ } ddekit_pci_dev_t; @@ -40,49 +31,31 @@ static inline int invalid_device(ddekit_pci_dev_t *d) */ void ddekit_pci_init(void) { - l4io_pdev_t start = 0; - int slots_found = 0; int i; + struct pci_device *pci_dev; + struct pci_device_iterator *dev_iter; /* Init device list */ for (i = 0; i < MAX_PCI_DEVS; i++) ddekit_pci_bus[i].slot = -1; - while (1) { - l4io_pci_dev_t l4dev; - int err; - - /* search next device */ - err = l4io_pci_find_device(~0, ~0, start, &l4dev); - if (err) { - if (err == -L4_ENOTFOUND) { - LOGd(dbg_this, "no more pci devices"); - } else { - LOGd(dbg_this, "error: scanning pci devices: %s (%d)", l4env_errstr(err), err); - } + dev_iter = pci_slot_match_iterator_create (NULL); + while ((pci_dev = pci_device_next (dev_iter)) != NULL) { + if (slots_found == MAX_PCI_DEVS) { + LOGd(dbg_this, "find more than %d pci devices", + slots_found); break; } - - /* next search start from here */ - start = l4dev.handle; - - /* print info */ - /* Pretend all our devices are chained to exactly one bus. */ ddekit_pci_bus[slots_found].bus = 0; /*l4dev.bus;*/ ddekit_pci_bus[slots_found].slot = slots_found; ddekit_pci_bus[slots_found].func = 0; - ddekit_pci_bus[slots_found].l4dev = l4dev; - - LOGd(dbg_this, "pcib_identify: found device (%x, %x, %x), mapped to (%x, %x, %x)", - l4dev.bus, l4dev.devfn >> 3, l4dev.devfn & 0x07, - ddekit_pci_bus[slots_found].bus, - ddekit_pci_bus[slots_found].slot, - ddekit_pci_bus[slots_found].func); + ddekit_pci_bus[slots_found].dev = pci_dev; ++slots_found; } + pci_iterator_destroy (dev_iter); } @@ -184,7 +157,7 @@ int ddekit_pci_readb (int bus, int slot, int func, int pos, ddekit_uint8_t *val { ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func); if (dev) - return l4io_pci_readb_cfg(dev->l4dev.handle, pos, val); + return pci_device_cfg_read_u8 (dev->dev, val, pos); else return -1; } @@ -194,7 +167,7 @@ int ddekit_pci_readw (int bus, int slot, int func, int pos, ddekit_uint16_t *val { ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func); if (dev) - return l4io_pci_readw_cfg(dev->l4dev.handle, pos, val); + return pci_device_cfg_read_u16 (dev->dev, val, pos); else return -1; } @@ -204,7 +177,7 @@ int ddekit_pci_readl (int bus, int slot, int func, int pos, ddekit_uint32_t *val { ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func); if (dev) - return l4io_pci_readl_cfg(dev->l4dev.handle, pos, val); + return pci_device_cfg_read_u32 (dev->dev, val, pos); else return -1; } @@ -214,7 +187,7 @@ int ddekit_pci_writeb(int bus, int slot, int func, int pos, ddekit_uint8_t val { ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func); if (dev) - return l4io_pci_writeb_cfg(dev->l4dev.handle, pos, val); + return pci_device_cfg_write_u8 (dev->dev, val, pos); else return -1; } @@ -224,7 +197,7 @@ int ddekit_pci_writew(int bus, int slot, int func, int pos, ddekit_uint16_t val { ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func); if (dev) - return l4io_pci_writew_cfg(dev->l4dev.handle, pos, val); + return pci_device_cfg_write_u16 (dev->dev, val, pos); else return -1; } @@ -234,19 +207,20 @@ int ddekit_pci_writel(int bus, int slot, int func, int pos, ddekit_uint32_t val { ddekit_pci_dev_t *dev = ddekit_pci_find_device_fixed(bus, slot, func); if (dev) - return l4io_pci_writel_cfg(dev->l4dev.handle, pos, val); + return pci_device_cfg_write_u32 (dev->dev, val, pos); else return -1; } int ddekit_pci_enable_device(struct ddekit_pci_dev *dev) { - return l4io_pci_enable(dev->l4dev.handle); + return pci_device_enable (dev->dev); } int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) { - return l4io_pci_disable(dev->l4dev.handle); + // TODO + return -1; } /******************************************************************************** @@ -264,7 +238,7 @@ int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) { - return dev->l4dev.vendor; + return dev->dev.vendor_id; } @@ -277,7 +251,7 @@ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) { - return dev->l4dev.device; + return dev->dev.device_id; } @@ -290,7 +264,7 @@ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) { - return dev->l4dev.sub_vendor; + return dev->dev.subvendor_id; } @@ -303,7 +277,7 @@ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) { - return dev->l4dev.sub_device; + return dev->dev.subdevice_id; } @@ -316,7 +290,7 @@ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) */ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) { - return dev->l4dev.dev_class; + return dev->dev.device_class; } @@ -329,7 +303,7 @@ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) */ unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev) { - return dev->l4dev.irq; + return dev->dev.irq; } @@ -342,7 +316,8 @@ unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev) */ char *ddekit_pci_get_name(struct ddekit_pci_dev *dev) { - return dev->l4dev.name; + // TODO + return NULL; } @@ -355,7 +330,8 @@ char *ddekit_pci_get_name(struct ddekit_pci_dev *dev) */ char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev) { - return dev->l4dev.slot_name; + // TODO + return NULL; } @@ -372,7 +348,7 @@ ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned i if (idx > L4IO_PCIDEV_RES) return NULL; - return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); + //TODO return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); } @@ -383,7 +359,7 @@ ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned i */ void ddekit_pci_set_master(struct ddekit_pci_dev *dev) { - l4io_pci_set_master(dev->l4dev.handle); + //TODO l4io_pci_set_master(dev->l4dev.handle); } int ddekit_pci_irq_enable(int bus, int slot, int func, int pin, int *irq) -- cgit v1.2.3 From 35881fb690c341f53ea3fb969e8d87b69401e49c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 18 Nov 2009 01:45:36 +0100 Subject: Adapt the implementation of DDEKit threads. --- libddekit/include/ddekit/thread.h | 19 ---- libddekit/thread.c | 213 +++++++++++++++++--------------------- 2 files changed, 97 insertions(+), 135 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/thread.h b/libddekit/include/ddekit/thread.h index ecd399d9..6e505818 100644 --- a/libddekit/include/ddekit/thread.h +++ b/libddekit/include/ddekit/thread.h @@ -3,8 +3,6 @@ /** \defgroup DDEKit_threads */ -#include - struct ddekit_thread; typedef struct ddekit_thread ddekit_thread_t; @@ -118,29 +116,12 @@ void ddekit_thread_wakeup(ddekit_thread_t *thread); */ void ddekit_thread_exit(void) __attribute__((noreturn)); -/** Terminate a thread - * - * \ingroup DDEKit_threads - */ -void ddekit_thread_terminate(ddekit_thread_t *thread); - /** Get the name, a thread registered with DDEKit. * * \ingroup DDEKit_threads */ const char *ddekit_thread_get_name(ddekit_thread_t *thread); -/** Get unique ID of a DDEKit thread. - * - * \ingroup DDEKit_threads - * - * DDEKit does not allow direct access to the thread data - * structure, since this struct contains L4-specific data types. - * However, applications might want to get some kind of ID related - * to a ddekit_thread, for instance to use it as a Linux-like PID. - */ -int ddekit_thread_get_id(ddekit_thread_t *thread); - /** Hint that this thread is done and may be scheduled somehow. * * \ingroup DDEKit_threads diff --git a/libddekit/thread.c b/libddekit/thread.c index db767dc9..a4566d77 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -1,114 +1,68 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - #include #include +#include +#include +#include + +#include "ddekit/thread.h" #define DDEKIT_THREAD_STACK_SIZE 0x2000 /* 8 KB */ static struct ddekit_slab *ddekit_stack_slab = NULL; struct ddekit_thread { - l4thread_t l4thread; - void *data; - void *stack; - ddekit_condvar_t *sleep_cv; - const char *name; + struct cthread thread; }; -/** - * The thread-local-storage key for the BSD struct thread. - */ -static int tlskey_thread; - -struct startup_args { - void (*fun)(void *); - void *arg; - const char *name; -}; - -ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { - ddekit_thread_t *td; - int namelen = strlen(name); - char *pname; - - td = ddekit_simple_malloc(sizeof(*td) + (namelen+1)); - pname = (char *) td + sizeof(*td); +static void setup_thread (cthread_t *t, const char *name) { + if (name) { + const char *cpy = NULL; - td->data=NULL; - td->sleep_cv = ddekit_condvar_init(); - td->l4thread = l4thread_myself(); - td->name = pname; + cpy = malloc (strlen (name) + 1); + if (cpy == NULL) + error (0, 0, "fail to allocate memory"); + else + strcpy (cpy, name); - strcpy(pname, name); + cthread_set_name (t, name); + } - l4thread_data_set_current(tlskey_thread, td); - - return td; + /* + * ldata isn't used by cthread. Since cthread isn't exposed to + * the user of this library. It's very safe to store + * the condition variable in ldata. + */ + sleep_cond = condition_alloc (); + condition_init (sleep_cond); + cthread_set_ldata (t, sleep_cond); } -static void ddekit_thread_startup(void *arg) { - struct startup_args su; - ddekit_thread_t *td; - - /* copy arg to su so that it can bee freed by caller */ - su = *((struct startup_args*)arg); - - /* init dde thread structure */ - td = ddekit_thread_setup_myself(su.name); - /* inform caller of initialization */ - l4thread_started(td); +ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { + ddekit_thread_t *td = ddekit_thread_myself(); - /* call thread routine */ - su.fun(su.arg); + setup_thread (&td->thread, name); + return td; } ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char *name) { - struct startup_args su; ddekit_thread_t *td; - l4thread_t l4td; - char l4name[20]; - void *stack; - - su.fun = fun; - su.arg = arg; - su.name = name; - - snprintf(l4name, 20, ".%s", name); - - stack = ddekit_slab_alloc(ddekit_stack_slab); - - - l4td = l4thread_create_long(L4THREAD_INVALID_ID, ddekit_thread_startup, l4name, - (l4_addr_t) stack + (DDEKIT_THREAD_STACK_SIZE-1 )* sizeof (void *), - DDEKIT_THREAD_STACK_SIZE, - L4THREAD_DEFAULT_PRIO, &su, L4THREAD_CREATE_SYNC); - - if (l4td < 0) - ddekit_panic("error creating thread"); - - td = (ddekit_thread_t*) l4thread_startup_return(l4td); - - td->stack = stack; - + condition_t sleep_cond; + + // TODO not very sure whether I should let the thread suspend + // before initialization is completed. + td = (ddekit_thread_t *) cthread_fork (fun, arg); + setup_thread (&td->thread, name); return td; } ddekit_thread_t *ddekit_thread_myself(void) { - return (ddekit_thread_t *) l4thread_data_get_current(tlskey_thread); + return (ddekit_thread_t *) cthread_self (); } void ddekit_thread_set_data(ddekit_thread_t *thread, void *data) { - thread->data = data; + // TODO not very sure whether I should call cthread_set_ldata + // or cthread_set_data. + cthread_set_data ((cthread_t) thread, data); } void ddekit_thread_set_my_data(void *data) { @@ -116,7 +70,7 @@ void ddekit_thread_set_my_data(void *data) { } void *ddekit_thread_get_data(ddekit_thread_t *thread) { - return thread->data; + return cthread_data ((cthread_t) thread); } void *ddekit_thread_get_my_data() { @@ -124,72 +78,99 @@ void *ddekit_thread_get_my_data() { } void ddekit_thread_msleep(unsigned long msecs) { - l4thread_sleep(msecs); + int ret; + struct timespec rgt; + + rgt.tv_sec = (time_t) (msecs / 1000); + rgt.tv_nsec = (msecs % 1000) * 1000 * 1000; + ret = nanosleep (&rgt , NULL); + if (ret < 0) + error (0, errno, "nanosleep"); } void ddekit_thread_usleep(unsigned long usecs) { - l4_busy_wait_us(usecs); + int ret; + struct timespec rgt; + + rgt.tv_sec = (time_t) (usecs / 1000 / 1000); + rgt.tv_nsec = (usecs % (1000 * 1000)) * 1000; + ret = nanosleep (&rgt , NULL); + if (ret < 0) + error (0, errno, "nanosleep"); } void ddekit_thread_nsleep(unsigned long nsecs) { - l4_busy_wait_ns(nsecs); + int ret; + struct timespec rgt; + + rgt.tv_sec = (time_t) (nsecs / 1000 / 1000 / 1000); + rgt.tv_nsec = nsecs % (1000 * 1000 * 1000); + ret = nanosleep (&rgt , NULL); + if (ret < 0) + error (0, errno, "nanosleep"); } void ddekit_thread_sleep(ddekit_lock_t *lock) { ddekit_thread_t *td; + condition_t sleep_cond; td = ddekit_thread_myself(); + sleep_cond = ddekit_thread_get_data (&td->thread); - ddekit_condvar_wait(td->sleep_cv, lock); + mutex_lock (lock); + // TODO condition_wait cannot guarantee that the thread is + // woke up by another thread, maybe by signals. + // Does it matter here? + condition_wait (sleep_cond, lock); + mutex_unlock (lock); } void ddekit_thread_wakeup(ddekit_thread_t *td) { - ddekit_condvar_signal(td->sleep_cv); -} - -void ddekit_thread_exit() { ddekit_thread_t *td; + condition_t sleep_cond; td = ddekit_thread_myself(); - - l4thread_exit(); + sleep_cond = ddekit_thread_get_data (&td->thread); - ddekit_slab_free(ddekit_stack_slab ,td->stack); - + condition_signal (sleep_cond); } -void ddekit_thread_terminate(ddekit_thread_t *t) -{ - l4thread_shutdown(t->l4thread); -} +void ddekit_thread_exit() { + const char *name; + condition_t sleep_cond; + cthread_t t = cthread_self (); -const char *ddekit_thread_get_name(ddekit_thread_t *thread) { - return thread->name; + // TODO I hope I don't need a lock to protect ldata and name. + + /* I have to free the sleep condition variable + * before the thread exits. */ + sleep_cond = cthread_ldata (t); + cthread_set_ldata (t, NULL); + condition_free (sleep_cond); + + name = cthread_name (t); + cthread_set_name (t, NULL); + free (name); + + cthread_exit (0); } -int ddekit_thread_get_id(ddekit_thread_t *t) -{ - return t->l4thread; +const char *ddekit_thread_get_name(ddekit_thread_t *thread) { + return cthread_name ((cthread_t) thread); } void ddekit_thread_schedule(void) { - l4_yield(); + cthread_yield(); } void ddekit_yield(void) { - l4_yield(); + cthread_yield(); } void ddekit_init_threads() { - /* register TLS key for pointer to dde thread structure */ - tlskey_thread = l4thread_data_allocate_key(); - - /* setup dde part of thread data */ - ddekit_thread_setup_myself("main"); - - /* create slab for stacks */ - ddekit_stack_slab = ddekit_slab_init(DDEKIT_THREAD_STACK_SIZE, 1); + // TODO maybe the name has already been set. + cthread_set_name (cthread_self (), "main"); } -- cgit v1.2.3 From bcbb19bbe30d89a24591d632bbed62123dbef8be Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 18 Nov 2009 02:19:17 +0100 Subject: Adapt the implementation of lock. TODO: the implementation of the owner of lock hasn't been adapted. --- libddekit/include/ddekit/lock.h | 2 +- libddekit/lock.c | 42 +++++++++-------------------------------- 2 files changed, 10 insertions(+), 34 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/lock.h b/libddekit/include/ddekit/lock.h index 872acad0..dd398b38 100644 --- a/libddekit/include/ddekit/lock.h +++ b/libddekit/include/ddekit/lock.h @@ -52,7 +52,7 @@ static int ddekit_lock_try_lock(ddekit_lock_t *mtx); // returns 0 on success, ! static void ddekit_lock_unlock (ddekit_lock_t *mtx); // inline implementation or inline call to non-inline implementation -#include +#include "ddekit/inline.h" static INLINE void ddekit_lock_init_unlocked(ddekit_lock_t *mtx) { _ddekit_lock_init(mtx); diff --git a/libddekit/lock.c b/libddekit/lock.c index 0f451dfd..1e61b8b6 100644 --- a/libddekit/lock.c +++ b/libddekit/lock.c @@ -1,58 +1,34 @@ -#include -#include +#include -#include -#include +#include "ddekit/lock.h" #define DDEKIT_DEBUG_LOCKS 0 struct ddekit_lock { - l4lock_t lock; + struct mutex lock; }; void _ddekit_lock_init(struct ddekit_lock **mtx) { - *mtx = (struct ddekit_lock *) ddekit_simple_malloc(sizeof(struct ddekit_lock)); - (*mtx)->lock = L4LOCK_UNLOCKED; + *mtx = (struct ddekit_lock *) mutex_alloc (); + mutex_init (*mtx); } void _ddekit_lock_deinit(struct ddekit_lock **mtx) { - ddekit_simple_free(*mtx); + mutex_free (*mtx); *mtx = NULL; } void _ddekit_lock_lock(struct ddekit_lock **mtx) { -#if DDEKIT_DEBUG_LOCKS - if (&(*mtx)->lock == 0x35ac) - LOG("DOWN %p: "l4util_idfmt" <-> "l4util_idfmt, - &(*mtx)->lock, - l4util_idstr(l4_myself()), - l4util_idstr(l4thread_l4_id(l4lock_owner(&((*mtx)->lock))))); -#endif - l4lock_lock(&(*mtx)->lock); -#if DDEKIT_DEBUG_LOCKS - if (&(*mtx)->lock == 0x35ac) - LOG("DOWN %p! "l4util_idfmt, &(*mtx)->lock, l4util_idstr(l4_myself())); -#endif + mutex_lock (&(*mtx)->lock); } /* returns 0 on success, != 0 if it would block */ int _ddekit_lock_try_lock(struct ddekit_lock **mtx) { - return l4lock_try_lock(&(*mtx)->lock) ? 0 : 1; + return !mutex_try_lock (&(*mtx)->lock); } void _ddekit_lock_unlock(struct ddekit_lock **mtx) { -#if DDEKIT_DEBUG_LOCKS - if (&(*mtx)->lock == 0x35ac) - LOG("UP %p: "l4util_idfmt" <-> "l4util_idfmt, - &(*mtx)->lock, - l4util_idstr(l4_myself()), - l4util_idstr(l4thread_l4_id(l4lock_owner(&((*mtx)->lock))))); -#endif - l4lock_unlock(&(*mtx)->lock); -#if DDEKIT_DEBUG_LOCKS - if (&(*mtx)->lock == 0x35ac) - LOG("UP %p! "l4util_idfmt, &(*mtx)->lock, l4util_idstr(l4_myself())); -#endif + mutex_unlock (&(*mtx)->lock); } -- cgit v1.2.3 From b537f6cede63b0e55e82a2ee1467d094200d953e Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 21 Nov 2009 00:47:01 +0100 Subject: Emulate the timer in the Hurd. --- libddekit/include/ddekit/timer.h | 4 +- libddekit/timer.c | 107 ++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 52 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index c352475c..a57c8fce 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -1,7 +1,9 @@ #ifndef _ddekit_timer_h #define _ddekit_timer_h -#include +#include "ddekit/thread.h" + +#define jiffies fetch_jiffies() enum { diff --git a/libddekit/timer.c b/libddekit/timer.c index b1af99bf..d0a6ccc0 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -1,20 +1,14 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include +#include +#include +#include + +#include "ddekit/timer.h" #define __DEBUG 0 +volatile struct mapped_time_value *mapped_time; +long long root_jiffies; + /* Just to remind BjoernD of what this is: * HZ = clock ticks per second * jiffies = clock ticks counter. @@ -22,7 +16,6 @@ * So, if someone schedules a timeout to expire in 2 seconds, * this expires date will be in jiffies + 2 * HZ. */ -extern volatile unsigned long jiffies; extern unsigned long HZ; typedef struct _timer @@ -36,8 +29,8 @@ typedef struct _timer static ddekit_timer_t *timer_list = NULL; ///< list of pending timers -static l4lock_t timer_lock = L4LOCK_UNLOCKED; ///< lock to access timer_list -static l4_threadid_t timer_thread = L4_NIL_ID; ///< the timer thread +static struct mutex timer_lock = MUTEX_INITIALIZER; ///< lock to access timer_list +static cthread_t timer_thread; ///< the timer thread static ddekit_thread_t *timer_thread_ddekit = NULL; ///< ddekit ID of timer thread static ddekit_sem_t *notify_semaphore = NULL; ///< timer thread's wait semaphore @@ -58,20 +51,27 @@ static void dump_list(char *msg) #endif } +int fetch_jiffies () +{ + struct timeval tv; + long long j; + + maptime_read (mapped_time, &tv); + + j = (long long) tv.tv_sec * HZ + ((long long) tv.tv_usec * HZ) / 1000000; + return j - root_jiffies; +} /** Notify the timer thread there is a new timer at the beginning of the * timer list. */ static inline void __notify_timer_thread(void) { - int err; - l4_msgdope_t result; - /* Do not notify if there is no timer thread. * XXX: Perhaps we should better assert that there is a timer * thread before allowing users to add a timer. */ - if (l4_is_nil_id(timer_thread)) + if (timer_thread == NULL) return; ddekit_sem_up(notify_semaphore); @@ -91,7 +91,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) t->expires = timeout; t->next = NULL; - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); t->id = timer_id_ctr++; @@ -122,7 +122,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) __notify_timer_thread(); } - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); dump_list("after add"); @@ -135,7 +135,7 @@ int ddekit_del_timer(int timer) ddekit_timer_t *it, *it_next; int ret = -1; - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); /* no timer? */ if (!timer_list) { @@ -176,7 +176,7 @@ int ddekit_del_timer(int timer) } out: - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); dump_list("after del"); @@ -195,7 +195,7 @@ int ddekit_timer_pending(int timer) ddekit_timer_t *t = NULL; int r = 0; - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); t = timer_list; while (t) { @@ -206,7 +206,7 @@ int ddekit_timer_pending(int timer) t = t->next; } - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); return r; } @@ -222,8 +222,7 @@ static ddekit_timer_t *get_next_timer(void) ddekit_timer_t *t = NULL; /* This function must be called with the timer_lock held. */ - Assert(l4_thread_equal(l4thread_l4_id(l4lock_owner(&timer_lock)), - timer_thread)); + Assert(timer_lock.holder == timer_thread); if (timer_list && (timer_list->expires <= jiffies)) { @@ -248,27 +247,24 @@ enum */ static inline int __timer_sleep(unsigned to) { - l4_umword_t dummy; - l4_msgdope_t res; - int err = 0; - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); - if (to == DDEKIT_TIMEOUT_NEVER) { - ddekit_sem_down(notify_semaphore); - } - else { + if (to == DDEKIT_TIMEOUT_NEVER) { + ddekit_sem_down(notify_semaphore); + } + else { #if 0 - ddekit_printf("Going to sleep for %lu µs (%lu ms)\n", to * 1000, to); + ddekit_printf("Going to sleep for %lu µs (%lu ms)\n", to * 1000, to); #endif - err = ddekit_sem_down_timed(notify_semaphore, to); + err = ddekit_sem_down_timed(notify_semaphore, to); #if 0 - ddekit_printf("err: %x\n", err); + ddekit_printf("err: %x\n", err); #endif - } + } - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); return (err ? 1 : 0); } @@ -283,9 +279,9 @@ static void ddekit_timer_thread(void *arg) l4thread_set_prio(l4thread_myself(), 0x11); #endif - l4thread_started(0); +// l4thread_started(0); - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); while (1) { ddekit_timer_t *timer = NULL; unsigned long to = DDEKIT_TIMEOUT_NEVER; @@ -303,13 +299,14 @@ static void ddekit_timer_thread(void *arg) __timer_sleep(to); while ((timer = get_next_timer()) != NULL) { - l4lock_unlock(&timer_lock); + mutex_unlock (&timer_lock); //ddekit_printf("doing timer fn @ %p\n", timer->fn); timer->fn(timer->args); ddekit_simple_free(timer); - l4lock_lock(&timer_lock); + mutex_lock (&timer_lock); } } + // TODO how is the thread terminated? } ddekit_thread_t *ddekit_get_timer_thread() @@ -320,10 +317,18 @@ ddekit_thread_t *ddekit_get_timer_thread() void ddekit_init_timers(void) { - l4_tsc_init(L4_TSC_INIT_AUTO); + error_t err; + struct timeval tp; + + err = maptime_map (0, 0, &mapped_time); + if (err) + error (2, err, "cannot map time device"); + + maptime_read (mapped_time, &tp); + + root_jiffies = (long long) tp.tv_sec * HZ + + ((long long) tp.tv_usec * HZ) / 1000000; - /* XXX this module needs HZ and jiffies to work - so l4io info page must be mapped */ - timer_thread = l4thread_l4_id( l4thread_create_named(ddekit_timer_thread, - "ddekit_timer", 0, - L4THREAD_CREATE_SYNC)); + timer_thread = cthread_fork ((cthread_fn_t) timer_function, 0); + cthread_detach (timer_thread); } -- cgit v1.2.3 From d33a9a7e6a46543156a8f07b8e684b171c2ba456 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 13:59:14 +0100 Subject: The implementation of condition variables. ddekit_condvar_wait_timed hasn't been implemented as it is only used by freebsd drivers. --- libddekit/condvar.c | 94 ++++++-------------------------------- libddekit/include/ddekit/condvar.h | 2 - 2 files changed, 15 insertions(+), 81 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/condvar.c b/libddekit/condvar.c index a495cf92..96e28c07 100644 --- a/libddekit/condvar.c +++ b/libddekit/condvar.c @@ -4,105 +4,41 @@ * * \author Thomas Friebel */ -#include -#include -#include +#include -#include -#include -#include +#include "ddekit/condvar.h" struct ddekit_condvar { - unsigned waiters; - unsigned signals; - l4lock_t lock; - l4semaphore_t sem; - l4semaphore_t handshake; + struct condition cond; }; ddekit_condvar_t *ddekit_condvar_init() { ddekit_condvar_t *cvp; - cvp = ddekit_simple_malloc(sizeof(*cvp)); - - cvp->waiters = 0; - cvp->signals = 0; - cvp->lock = L4LOCK_UNLOCKED; - cvp->sem = L4SEMAPHORE_INIT(0); - cvp->handshake = L4SEMAPHORE_INIT(0); + cvp = condition_alloc (); + condition_init (cvp); return cvp; } void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp) { - ddekit_condvar_wait_timed(cvp, mp, -1); + /* This isn't nice. The encapsulation is broken. + * TODO I can merge the two files condvar.c and lock.c. */ + condition_wait (&cvp->cond, (struct mutex *) mp); } -int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp, ddekit_lock_t *mp, int timo) { - int rval; - - l4lock_lock(&cvp->lock); - cvp->waiters++; - l4lock_unlock(&cvp->lock); - - ddekit_lock_unlock(mp); - - if (timo == -1) { - l4semaphore_down(&cvp->sem); - rval = 0; - } else { - rval = l4semaphore_down_timed(&cvp->sem, timo); - } - - l4lock_lock(&cvp->lock); - if (cvp->signals > 0) { - /* if we timed out, but there is a signal now, consume it */ - if (rval) l4semaphore_down(&cvp->sem); - - l4semaphore_up(&cvp->handshake); - cvp->signals--; - } - cvp->waiters--; - l4lock_unlock(&cvp->lock); - - ddekit_lock_lock(mp); - - return rval; +int ddekit_condvar_wait_timed(ddekit_condvar_t *cvp, + ddekit_lock_t *mp, int timo) { + // TODO currently just let it like this. + ddekit_condvar_wait (cvp, mp); + return 0; } void ddekit_condvar_signal(ddekit_condvar_t *cvp) { - l4lock_lock(&cvp->lock); - - if (cvp->waiters > cvp->signals) { - cvp->signals++; - l4semaphore_up(&cvp->sem); - l4lock_unlock(&cvp->lock); - l4semaphore_down(&cvp->handshake); - } else { - /* nobody left to wakeup */ - l4lock_unlock(&cvp->lock); - } + condition_signal (&cvp->cond); } void ddekit_condvar_broadcast(ddekit_condvar_t *cvp) { - int waiters; - - l4lock_lock(&cvp->lock); - - waiters = cvp->waiters - cvp->signals; - if (waiters > 0) { - int i; - - cvp->signals = cvp->waiters; - for (i=0; isem); - } - l4lock_unlock(&cvp->lock); - for (i=0; ihandshake); - } - } else { - l4lock_unlock(&cvp->lock); - } + condition_broadcast (&cvp->cond); } diff --git a/libddekit/include/ddekit/condvar.h b/libddekit/include/ddekit/condvar.h index b6dc4bd3..ba87358d 100644 --- a/libddekit/include/ddekit/condvar.h +++ b/libddekit/include/ddekit/condvar.h @@ -3,8 +3,6 @@ /** \file ddekit/condvar.h */ -#include - struct ddekit_condvar; typedef struct ddekit_condvar ddekit_condvar_t; -- cgit v1.2.3 From 0441d40c8f86487734d89d08f9f2023a64410489 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 14:20:42 +0100 Subject: Modify resource.c. --- libddekit/include/ddekit/resources.h | 2 +- libddekit/resources.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/resources.h b/libddekit/include/ddekit/resources.h index e0fa68f0..dfbb1322 100644 --- a/libddekit/include/ddekit/resources.h +++ b/libddekit/include/ddekit/resources.h @@ -1,7 +1,7 @@ #ifndef _ddekit_resources_h #define _ddekit_resources_h -#include +#include "ddekit/types.h" int ddekit_request_dma(int nr); int ddekit_release_dma(int nr); diff --git a/libddekit/resources.c b/libddekit/resources.c index d4d421c4..4bbd2db9 100644 --- a/libddekit/resources.c +++ b/libddekit/resources.c @@ -1,15 +1,21 @@ -#include +#include -#include +#include "ddekit/resources.h" #include "config.h" int ddekit_request_dma(int nr) { +#if 0 return l4io_request_dma(nr); +#endif + return -1; } int ddekit_release_dma(int nr) { +#if 0 return l4io_release_dma(nr); +#endif + return -1; } /** Request an IO region @@ -18,7 +24,7 @@ int ddekit_release_dma(int nr) { * \return -1 error */ int ddekit_request_io(ddekit_addr_t start, ddekit_addr_t count) { - return l4io_request_region(start, count); + return ioperm (start, count, 1); } /** Release an IO region. @@ -27,7 +33,7 @@ int ddekit_request_io(ddekit_addr_t start, ddekit_addr_t count) { * \return <0 error */ int ddekit_release_io(ddekit_addr_t start, ddekit_addr_t count) { - return l4io_release_region(start, count); + return ioperm (start, count, 0); } /** Request a memory region. @@ -37,6 +43,7 @@ int ddekit_release_io(ddekit_addr_t start, ddekit_addr_t count) { * \return -1 error */ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr) { +#if 0 ddekit_addr_t v; v = l4io_request_mem_region(start, count, 0); @@ -45,6 +52,8 @@ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t * return 0; } else return -1; +#endif + return -1; } /** Release memory region. @@ -53,5 +62,8 @@ int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t * * \return <0 error */ int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count) { +#if 0 return l4io_release_mem_region(start, count); +#endif + return -1; } -- cgit v1.2.3 From 09b6164c0b107cae65a48c2e070c83a4da676bec Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 16:39:07 +0100 Subject: Implement physical <--> virtual address mapping. --- libddekit/include/ddekit/pgtab.h | 2 +- libddekit/kmem.c | 496 +++++++++++++++++++++++++++++++++++++++ libddekit/pgtab.c | 138 ++--------- 3 files changed, 511 insertions(+), 125 deletions(-) create mode 100644 libddekit/kmem.c (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/pgtab.h b/libddekit/include/ddekit/pgtab.h index 3b68192c..8964b713 100644 --- a/libddekit/include/ddekit/pgtab.h +++ b/libddekit/include/ddekit/pgtab.h @@ -8,7 +8,7 @@ #ifndef _ddekit_pgtab_h #define _ddekit_pgtab_h -#include +#include "ddekit/types.h" /* FIXME Region types may be defined by pgtab users. Do we really need them * here? */ diff --git a/libddekit/kmem.c b/libddekit/kmem.c new file mode 100644 index 00000000..4769190e --- /dev/null +++ b/libddekit/kmem.c @@ -0,0 +1,496 @@ +/* + * Linux memory allocation. + * + * Copyright (C) 1996 The University of Utah and the Computer Systems + * Laboratory at the University of Utah (CSL) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Shantanu Goel, University of Utah CSL + * + */ + +#include +#include +#include "mach_U.h" +#include +#include + +#include "util.h" +#include "vm_param.h" + +extern int printf (const char *, ...); + +/* Amount of memory to reserve for Linux memory allocator. + We reserve 64K chunks to stay within DMA limits. + Increase MEM_CHUNKS if the kernel is running out of memory. */ +#define MEM_CHUNK_SIZE (64 * 1024) +#define MEM_CHUNKS 7 + +/* Mininum amount that linux_kmalloc will allocate. */ +#define MIN_ALLOC 12 + +#ifndef NBPW +#define NBPW 32 +#endif + +/* Memory block header. */ +struct blkhdr +{ + unsigned short free; /* 1 if block is free */ + unsigned short size; /* size of block */ +}; + +/* This structure heads a page allocated by linux_kmalloc. */ +struct pagehdr +{ + unsigned size; /* size (multiple of PAGE_SIZE) */ + struct pagehdr *next; /* next header in list */ +}; + +/* This structure describes a memory chunk. */ +struct chunkhdr +{ + vm_address_t start; /* start address */ + vm_address_t pstart; /* start physical address */ + vm_address_t end; /* end address */ + unsigned long bitmap; /* busy/free bitmap of pages */ +}; + +unsigned long __get_free_pages (unsigned long order, int dma); +void free_pages (unsigned long addr, unsigned long order); + +static struct mutex mem_lock = MUTEX_INITIALIZER; + +/* Chunks from which pages are allocated. */ +static struct chunkhdr pages_free[MEM_CHUNKS]; + +/* Memory list maintained by linux_kmalloc. */ +static struct pagehdr *memlist; + +/* Some statistics. */ +int num_block_coalesce = 0; +int num_page_collect = 0; +int linux_mem_avail; + +int virt_to_phys (vm_address_t addr) +{ + int i; + + for (i = 0; i < MEM_CHUNKS; i++) + { + if (pages_free[i].start <= addr && pages_free[i].end > addr) + return addr - pages_free[i].start + pages_free[i].pstart; + } + debug ("an address not in any chunks."); + abort (); +} + +int phys_to_virt (vm_address_t addr) +{ +#define CHUNK_SIZE(chunk) ((chunk)->end - (chunk)->start) + int i; + + for (i = 0; i < MEM_CHUNKS; i++) + { + if (pages_free[i].pstart <= addr + && pages_free[i].pstart + CHUNK_SIZE (pages_free + i) > addr) + return addr - pages_free[i].pstart + pages_free[i].start; + } + debug ("an address not in any chunks."); + abort (); +} + +/* Initialize the Linux memory allocator. */ +void +linux_kmem_init () +{ + extern mach_port_t priv_host; + int i, j; + + for (i = 0; i < MEM_CHUNKS; i++) + { + error_t err; + + /* Allocate memory. */ + err = vm_dma_buff_alloc (priv_host, mach_task_self (), + MEM_CHUNK_SIZE, &pages_free[i].start, + &pages_free[i].pstart); + if (err) + abort (); + + assert (pages_free[i].start); +// assert ((pages_free[i].start & 0xffff) == 0); + +// /* Sanity check: ensure pages are contiguous and within DMA limits. */ +// for (p = pages, j = 0; j < MEM_CHUNK_SIZE - PAGE_SIZE; j += PAGE_SIZE) +// { +// assert (p->phys_addr < 16 * 1024 * 1024); +// assert (p->phys_addr + PAGE_SIZE +// == ((vm_page_t) p->pageq.next)->phys_addr); +// +// p = (vm_page_t) p->pageq.next; +// } + + pages_free[i].end = pages_free[i].start + MEM_CHUNK_SIZE; + assert (pages_free[i].end <= 16 * 1024 * 1024); + + /* Initialize free page bitmap. */ + pages_free[i].bitmap = 0; + j = MEM_CHUNK_SIZE >> PAGE_SHIFT; + while (--j >= 0) + pages_free[i].bitmap |= 1 << j; + } + + linux_mem_avail = (MEM_CHUNKS * MEM_CHUNK_SIZE) >> PAGE_SHIFT; +} + +/* Return the number by which the page size should be + shifted such that the resulting value is >= SIZE. */ +static unsigned long +get_page_order (int size) +{ + unsigned long order; + + for (order = 0; (PAGE_SIZE << order) < size; order++) + ; + return order; +} + +#ifdef LINUX_DEV_DEBUG +static void +check_page_list (int line) +{ + unsigned size; + struct pagehdr *ph; + struct blkhdr *bh; + + for (ph = memlist; ph; ph = ph->next) + { + if ((int) ph & PAGE_MASK) + panic ("%s:%d: page header not aligned", __FILE__, line); + + size = 0; + bh = (struct blkhdr *) (ph + 1); + while (bh < (struct blkhdr *) ((void *) ph + ph->size)) + { + size += bh->size + sizeof (struct blkhdr); + bh = (void *) (bh + 1) + bh->size; + } + + if (size + sizeof (struct pagehdr) != ph->size) + panic ("%s:%d: memory list destroyed", __FILE__, line); + } +} +#else +#define check_page_list(line) +#endif + +/* Merge adjacent free blocks in the memory list. */ +static void +coalesce_blocks () +{ + struct pagehdr *ph; + struct blkhdr *bh, *bhp, *ebh; + + num_block_coalesce++; + + for (ph = memlist; ph; ph = ph->next) + { + bh = (struct blkhdr *) (ph + 1); + ebh = (struct blkhdr *) ((void *) ph + ph->size); + while (1) + { + /* Skip busy blocks. */ + while (bh < ebh && !bh->free) + bh = (struct blkhdr *) ((void *) (bh + 1) + bh->size); + if (bh == ebh) + break; + + /* Merge adjacent free blocks. */ + while (1) + { + bhp = (struct blkhdr *) ((void *) (bh + 1) + bh->size); + if (bhp == ebh) + { + bh = bhp; + break; + } + if (!bhp->free) + { + bh = (struct blkhdr *) ((void *) (bhp + 1) + bhp->size); + break; + } + bh->size += bhp->size + sizeof (struct blkhdr); + } + } + } +} + +/* Allocate SIZE bytes of memory. + The PRIORITY parameter specifies various flags + such as DMA, atomicity, etc. It is not used by Mach. */ +void * +linux_kmalloc (unsigned int size, int priority) +{ + int order, coalesced = 0; + struct pagehdr *ph; + struct blkhdr *bh, *new_bh; + + if (size < MIN_ALLOC) + size = MIN_ALLOC; + else + size = (size + sizeof (int) - 1) & ~(sizeof (int) - 1); + + assert (size <= (MEM_CHUNK_SIZE + - sizeof (struct pagehdr) + - sizeof (struct blkhdr))); + + mutex_lock (&mem_lock); + +again: + check_page_list (__LINE__); + + /* Walk the page list and find the first free block with size + greater than or equal to the one required. */ + for (ph = memlist; ph; ph = ph->next) + { + bh = (struct blkhdr *) (ph + 1); + while (bh < (struct blkhdr *) ((void *) ph + ph->size)) + { + if (bh->free && bh->size >= size) + { + bh->free = 0; + if (bh->size - size >= MIN_ALLOC + sizeof (struct blkhdr)) + { + /* Split the current block and create a new free block. */ + new_bh = (void *) (bh + 1) + size; + new_bh->free = 1; + new_bh->size = bh->size - size - sizeof (struct blkhdr); + bh->size = size; + } + + check_page_list (__LINE__); + + mutex_unlock (&mem_lock); + return bh + 1; + } + bh = (void *) (bh + 1) + bh->size; + } + } + + check_page_list (__LINE__); + + /* Allocation failed; coalesce free blocks and try again. */ + if (!coalesced) + { + coalesce_blocks (); + coalesced = 1; + goto again; + } + + /* Allocate more pages. */ + order = get_page_order (size + + sizeof (struct pagehdr) + + sizeof (struct blkhdr)); + ph = (struct pagehdr *) __get_free_pages (order, ~0UL); + if (!ph) + { + mutex_unlock (&mem_lock); + return NULL; + } + + ph->size = PAGE_SIZE << order; + ph->next = memlist; + memlist = ph; + bh = (struct blkhdr *) (ph + 1); + bh->free = 0; + bh->size = ph->size - sizeof (struct pagehdr) - sizeof (struct blkhdr); + if (bh->size - size >= MIN_ALLOC + sizeof (struct blkhdr)) + { + new_bh = (void *) (bh + 1) + size; + new_bh->free = 1; + new_bh->size = bh->size - size - sizeof (struct blkhdr); + bh->size = size; + } + + check_page_list (__LINE__); + + mutex_unlock (&mem_lock); + return bh + 1; +} + +/* Free memory P previously allocated by linux_kmalloc. */ +void +linux_kfree (void *p) +{ + struct blkhdr *bh; + struct pagehdr *ph; + + assert (((int) p & (sizeof (int) - 1)) == 0); + + mutex_lock (&mem_lock); + + check_page_list (__LINE__); + + for (ph = memlist; ph; ph = ph->next) + if (p >= (void *) ph && p < (void *) ph + ph->size) + break; + + assert (ph); + + bh = (struct blkhdr *) p - 1; + + assert (!bh->free); + assert (bh->size >= MIN_ALLOC); + assert ((bh->size & (sizeof (int) - 1)) == 0); + + bh->free = 1; + + check_page_list (__LINE__); + + mutex_unlock (&mem_lock); +} + +/* Free any pages that are not in use. + Called by __get_free_pages when pages are running low. */ +static void +collect_kmalloc_pages () +{ + struct blkhdr *bh; + struct pagehdr *ph, **prev_ph; + + check_page_list (__LINE__); + + coalesce_blocks (); + + check_page_list (__LINE__); + + ph = memlist; + prev_ph = &memlist; + while (ph) + { + bh = (struct blkhdr *) (ph + 1); + if (bh->free && (void *) (bh + 1) + bh->size == (void *) ph + ph->size) + { + *prev_ph = ph->next; + free_pages ((unsigned long) ph, get_page_order (ph->size)); + ph = *prev_ph; + } + else + { + prev_ph = &ph->next; + ph = ph->next; + } + } + + check_page_list (__LINE__); +} + +/* Allocate ORDER + 1 number of physically contiguous pages. + PRIORITY and DMA are not used in Mach. + NOTE: mem_lock has been held. + + XXX: This needs to be dynamic. To do that we need to make + the Mach page manipulation routines interrupt safe and they + must provide machine dependant hooks. */ +unsigned long +__get_free_pages (unsigned long order, int dma) +{ + int i, pages_collected = 0; + unsigned bits, off, j, len; + + assert ((PAGE_SIZE << order) <= MEM_CHUNK_SIZE); + + /* Construct bitmap of contiguous pages. */ + bits = 0; + j = 0; + len = 0; + while (len < (PAGE_SIZE << order)) + { + bits |= 1 << j++; + len += PAGE_SIZE; + } + +again: + + /* Search each chunk for the required number of contiguous pages. */ + for (i = 0; i < MEM_CHUNKS; i++) + { + off = 0; + j = bits; + while (MEM_CHUNK_SIZE - off >= (PAGE_SIZE << order)) + { + if ((pages_free[i].bitmap & j) == j) + { + pages_free[i].bitmap &= ~j; + linux_mem_avail -= order + 1; + return pages_free[i].start + off; + } + j <<= 1; + off += PAGE_SIZE; + } + } + + /* Allocation failed; collect kmalloc and buffer pages + and try again. */ + if (!pages_collected) + { + num_page_collect++; + collect_kmalloc_pages (); + pages_collected = 1; + goto again; + } + + printf ("%s:%d: __get_free_pages: ran out of pages\n", __FILE__, __LINE__); + + return 0; +} + +/* Free ORDER + 1 number of physically + contiguous pages starting at address ADDR. */ +void +free_pages (unsigned long addr, unsigned long order) +{ + int i; + unsigned bits, len, j; + + assert ((addr & PAGE_MASK) == 0); + + for (i = 0; i < MEM_CHUNKS; i++) + if (addr >= pages_free[i].start && addr < pages_free[i].end) + break; + + assert (i < MEM_CHUNKS); + + /* Contruct bitmap of contiguous pages. */ + len = 0; + j = 0; + bits = 0; + while (len < (PAGE_SIZE << order)) + { + bits |= 1 << j++; + len += PAGE_SIZE; + } + bits <<= (addr - pages_free[i].start) >> PAGE_SHIFT; + + mutex_lock (&mem_lock); + + assert ((pages_free[i].bitmap & bits) == 0); + + pages_free[i].bitmap |= bits; + linux_mem_avail += order + 1; + mutex_unlock (&mem_lock); +} diff --git a/libddekit/pgtab.c b/libddekit/pgtab.c index 3c39f54f..88273b7c 100644 --- a/libddekit/pgtab.c +++ b/libddekit/pgtab.c @@ -11,47 +11,12 @@ * For this to work, dataspaces must be attached to l4rm regions! */ -#include -#include -#include +#include -#include -#include -#include +#include "ddekit/pgtab.h" #include "config.h" - -/** - * "Page-table" object - */ -struct pgtab_object -{ - l4_addr_t va; /* virtual start address */ - l4_addr_t pa; /* physical start address */ - - /* FIXME reconsider the following members */ - l4_size_t size; - unsigned type; /* pgtab region type */ - - struct pgtab_object * next; - struct pgtab_object * prev; -}; - -/** - * pa_list_head of page-table object list (for get_virtaddr()) - */ -static struct pgtab_object pa_list_head = - { - .va = 0, - .pa = 0, - .size = 0, - .next = &pa_list_head, - .prev = &pa_list_head - }; - -static l4lock_t pa_list_lock = L4LOCK_UNLOCKED; - /***************************** ** Page-table facility API ** *****************************/ @@ -64,18 +29,8 @@ static l4lock_t pa_list_lock = L4LOCK_UNLOCKED; */ ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual) { - /* find pgtab object */ - struct pgtab_object *p = l4rm_get_userptr(virtual); - if (!p) { - /* XXX this is verbose */ - LOG_Error("no virt->phys mapping for virtual address %p", virtual); - return 0; - } - - /* return virt->phys mapping */ - l4_size_t offset = (l4_addr_t) virtual - p->va; - - return p->pa + offset; + extern int virt_to_phys (vm_address_t addr); + return virt_to_phys ((vm_address_t) virtual); } /** @@ -86,32 +41,14 @@ ddekit_addr_t ddekit_pgtab_get_physaddr(const void *virtual) */ ddekit_addr_t ddekit_pgtab_get_virtaddr(const ddekit_addr_t physical) { - /* find pgtab object */ - struct pgtab_object *p; - ddekit_addr_t retval = 0; - - /* find phys->virt mapping */ - l4lock_lock(&pa_list_lock); - for (p = pa_list_head.next ; p != &pa_list_head ; p = p->next) { - if (p->pa <= (l4_addr_t)physical && - (l4_addr_t)physical < p->pa + p->size) { - l4_size_t offset = (l4_addr_t) physical - p->pa; - retval = p->va + offset; - break; - } - } - l4lock_unlock(&pa_list_lock); - - if (!retval) - LOG_Error("no phys->virt mapping for physical address %p", (void*)physical); - - return retval; + extern int phys_to_virt (vm_address_t addr); + return phys_to_virt (physical); } - - +// TODO int ddekit_pgtab_get_type(const void *virtual) { +#if 0 /* find pgtab object */ struct pgtab_object *p = l4rm_get_userptr(virtual); if (!p) { @@ -121,11 +58,14 @@ int ddekit_pgtab_get_type(const void *virtual) } return p->type; +#endif + return 0; } - +//TODO int ddekit_pgtab_get_size(const void *virtual) { +#if 0 /* find pgtab object */ struct pgtab_object *p = l4rm_get_userptr(virtual); if (!p) { @@ -135,6 +75,8 @@ int ddekit_pgtab_get_size(const void *virtual) } return p->size; +#endif + return 0; } @@ -146,28 +88,6 @@ int ddekit_pgtab_get_size(const void *virtual) */ void ddekit_pgtab_clear_region(void *virtual, int type) { - struct pgtab_object *p; - - /* find pgtab object */ - p = (struct pgtab_object *)l4rm_get_userptr(virtual); - if (!p) { - /* XXX this is verbose */ - LOG_Error("no virt->phys mapping for %p", virtual); - return; - } - - /* reset userptr in region map */ - /* XXX no error handling here */ - l4rm_set_userptr(virtual, 0); - - /* remove pgtab object from list */ - l4lock_lock(&pa_list_lock); - p->next->prev= p->prev; - p->prev->next= p->next; - l4lock_unlock(&pa_list_lock); - - /* free pgtab object */ - ddekit_simple_free(p); } @@ -181,39 +101,9 @@ void ddekit_pgtab_clear_region(void *virtual, int type) */ void ddekit_pgtab_set_region(void *virtual, ddekit_addr_t physical, int pages, int type) { - /* allocate pgtab object */ - struct pgtab_object *p = ddekit_simple_malloc(sizeof(*p)); - if (!p) { - LOG_Error("ddekit heap exhausted"); - return; - } - - /* initialize pgtab object */ - p->va = l4_trunc_page(virtual); - p->pa = l4_trunc_page(physical); - p->size = pages * L4_PAGESIZE; - p->type = type; - - l4lock_lock(&pa_list_lock); - p->next=pa_list_head.next; - p->prev=&pa_list_head; - pa_list_head.next->prev=p; - pa_list_head.next=p; - l4lock_unlock(&pa_list_lock); - - /* set userptr in region map to pgtab object */ - int err = l4rm_set_userptr((void *)p->va, p); - if (err) { - LOG_Error("l4rm_set_userptr returned %d", err); - ddekit_panic("l4rm_set_userptr"); - ddekit_simple_free(p); - } } void ddekit_pgtab_set_region_with_size(void *virt, ddekit_addr_t phys, int size, int type) { - int p = l4_round_page(size); - p >>= L4_PAGESHIFT; - ddekit_pgtab_set_region(virt, phys, p, type); } -- cgit v1.2.3 From b6bc230f90c7ca641f4555647649bdf681a268c1 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 3 Dec 2009 16:46:34 +0100 Subject: Implement panic. --- libddekit/Makefile | 2 +- libddekit/include/ddekit/panic.h | 19 +++++++++++++++++-- libddekit/panic.c | 29 ----------------------------- 3 files changed, 18 insertions(+), 32 deletions(-) delete mode 100644 libddekit/panic.c (limited to 'libddekit/include') diff --git a/libddekit/Makefile b/libddekit/Makefile index 59e5c5a9..1203ca38 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -20,7 +20,7 @@ makemode := library libname = libddekit SRCS= condvar.c init.c initcall.c interrupt.c lock.c malloc.c memory.c \ - panic.c pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ + pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/initcall.h include/ddekit/debug.h \ diff --git a/libddekit/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h index 1468675f..11c46ebb 100644 --- a/libddekit/include/ddekit/panic.h +++ b/libddekit/include/ddekit/panic.h @@ -3,14 +3,29 @@ /** \defgroup DDEKit_util */ +#include + /** Panic - print error message and enter the kernel debugger. * \ingroup DDEKit_util */ -void ddekit_panic(char *fmt, ...) __attribute__((noreturn)); +#define ddekit_panic(format, ...) do \ +{ \ + char buf[1024]; \ + snprintf (buf, 1024, "%s", format); \ + fprintf (stderr , buf, ## __VA_ARGS__); \ + fflush (stderr); \ + abort (); \ +} while (0) /** Print a debug message. * \ingroup DDEKit_util */ -void ddekit_debug(char *fmt, ...); +#define ddekit_debug(format, ...) do \ +{ \ + char buf[1024]; \ + snprintf (buf, 1024, "%s: %s\n", __func__, format); \ + fprintf (stderr , buf, ## __VA_ARGS__); \ + fflush (stderr); \ +} while (0) #endif diff --git a/libddekit/panic.c b/libddekit/panic.c deleted file mode 100644 index 24ace989..00000000 --- a/libddekit/panic.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -#include -#include - -void ddekit_panic(char *fmt, ...) { - va_list va; - - va_start(va, fmt); - ddekit_vprintf(fmt, va); - va_end(va); - ddekit_printf("\n"); - - while (1) - enter_kdebug("ddekit_panic()"); -} - -void ddekit_debug(char *fmt, ...) { - va_list va; - - va_start(va, fmt); - ddekit_vprintf(fmt, va); - va_end(va); - ddekit_printf("\n"); - - enter_kdebug("ddekit_debug()"); -} - -- cgit v1.2.3 From 85f31e4301efbb0721dc1de148738f94cb73fe8f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 5 Dec 2009 02:53:15 +0100 Subject: Implementation of interrupt. --- libddekit/include/ddekit/interrupt.h | 4 +- libddekit/interrupt.c | 127 ++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 64 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/interrupt.h b/libddekit/include/ddekit/interrupt.h index bbabedb2..3f789210 100644 --- a/libddekit/include/ddekit/interrupt.h +++ b/libddekit/include/ddekit/interrupt.h @@ -12,9 +12,9 @@ #ifndef _ddekit_interrupt_h #define _ddekit_interrupt_h -#include +#include "ddekit/thread.h" -#define DDEKIT_IRQ_PRIO 0x11 +#define DDEKIT_IRQ_PRIO 2 /** * Attach to hardware interrupt diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 557611a6..142659ff 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -8,15 +8,7 @@ * FIXME use consume flag to indicate IRQ was handled */ -#include -#include -#include -#include -#include - -#include -#include -#include +#include "ddekit/interrupt.h" #include @@ -44,58 +36,57 @@ struct intloop_params static struct { int handle_irq; /* nested irq disable count */ - ddekit_sem_t *irqsem; /* synch semaphore */ + ddekit_lock_t *irqlock; ddekit_thread_t *irq_thread; /* thread ID for detaching from IRQ later on */ - omega0_irqdesc_t irq_desc; /* Omega0-style IRQ descriptor */ + boolean_t thread_exit; + thread_t mach_thread; } ddekit_irq_ctrl[MAX_INTERRUPTS]; static void ddekit_irq_exit_fn(l4thread_t thread, void *data) { - int idx = (int)data; - - // * detach from IRQ - omega0_detach(ddekit_irq_ctrl[idx].irq_desc); + // TODO we can remove the port for delivery of interrupt explicitly, + // though it cannot cause any harm even if we don't remove it. } -L4THREAD_EXIT_FN_STATIC(exit_fn, ddekit_irq_exit_fn); - - /** * Interrupt service loop * */ static void intloop(void *arg) { + kern_return_t ret; struct intloop_params *params = arg; - - l4thread_set_prio(l4thread_myself(), DDEKIT_IRQ_PRIO); - - omega0_request_t req = { .i = 0 }; - int o0handle; - int my_index = params->irq; - omega0_irqdesc_t *desc = &ddekit_irq_ctrl[my_index].irq_desc; - - /* setup interrupt descriptor */ - desc->s.num = params->irq + 1; - desc->s.shared = params->shared; - - /* allocate irq */ - o0handle = omega0_attach(*desc); - if (o0handle < 0) { + mach_port_t delivery_port; + int my_index; + + my_index = params->irq; + ddekit_irq_ctrl[my_index]->mach_thread = mach_thread_self (); + ret = thread_priority (mach_thread_self (), DDEKIT_IRQ_PRIO, 0); + if (ret) + error (0, ret, "thread_priority"); + + // TODO I should give another parameter to show whether + // the interrupt can be shared. + ret = device_intr_notify (master_device, dev->irq, + dev->dev_id, delivery_port, + MACH_MSG_TYPE_MAKE_SEND); + if (!ret) { /* inform thread creator of error */ /* XXX does omega0 error code have any meaning to DDEKit users? */ - params->start_err = o0handle; + params->start_err = ret; ddekit_sem_up(params->started); - return; + return NULL; } +#if 0 /* * Setup an exit fn. This will make sure that we clean up everything, * before shutting down an IRQ thread. */ if (l4thread_on_exit(&exit_fn, (void *)my_index) < 0) ddekit_panic("Could not set exit handler for IRQ fn."); +#endif /* after successful initialization call thread_init() before doing anything * else here */ @@ -105,27 +96,21 @@ static void intloop(void *arg) params->start_err = 0; ddekit_sem_up(params->started); - /* prepare request structure */ - req.s.param = params->irq + 1; - req.s.wait = 1; - req.s.consume = 0; - req.s.unmask = 1; - - while (1) { - int err; - - /* wait for int */ - err = omega0_request(o0handle, req); - if (err != params->irq + 1) - LOG("omega0_request returned %d, %d (irq+1) expected", err, params->irq + 1); + int irq_server (mach_msg_header_t *inp, mach_msg_header_t *outp) { + mach_irq_notification_t *irq_header = (mach_irq_notification_t *) inp; - LOGd(DEBUG_INTERRUPTS, "received irq 0x%X", err - 1); + if (inp->msgh_id != MACH_NOTIFY_IRQ) + return 0; - /* unmask only the first time */ - req.s.unmask = 0; + /* It's an interrupt not for us. It shouldn't happen. */ + if (irq_header->irq != params->irq) { + LOG("We get interrupt %d, %d is expected", + irq_header->irq, params->irq); + return 1; + } /* only call registered handler function, if IRQ is not disabled */ - ddekit_sem_down(ddekit_irq_ctrl[my_index].irqsem); + ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock); if (ddekit_irq_ctrl[my_index].handle_irq > 0) { LOGd(DEBUG_INTERRUPTS, "IRQ %x, handler %p", my_index,params->handler); params->handler(params->priv); @@ -133,9 +118,18 @@ static void intloop(void *arg) else LOGd(DEBUG_INTERRUPTS, "not handling IRQ %x, because it is disabled.", my_index); - ddekit_sem_up(ddekit_irq_ctrl[my_index].irqsem); - LOGd(DEBUG_INTERRUPTS, "after irq handler"); + // ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; + + if (ddekit_irq_ctrl[irq].thread_exit) { + ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock); + ddekit_thread_exit(); + return 1; + } + ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock); + return 1; } + + mach_msg_server (int_server, 0, delivery_port); } @@ -164,6 +158,7 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, params = ddekit_simple_malloc(sizeof(*params)); if (!params) return NULL; + // TODO make sure irq is 0-15 instead of 1-16. params->irq = irq; params->thread_init = thread_init; params->handler = handler; @@ -175,6 +170,7 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, /* construct name */ snprintf(thread_name, 10, "irq%02X", irq); + /* allocate irq */ /* create interrupt loop thread */ thread = ddekit_thread_create(intloop, params, thread_name); if (!thread) { @@ -182,9 +178,11 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, return NULL; } + // TODO can ddekit really work for shared irq? ddekit_irq_ctrl[irq].handle_irq = 1; /* IRQ nesting level is initially 1 */ ddekit_irq_ctrl[irq].irq_thread = thread; - ddekit_irq_ctrl[irq].irqsem = ddekit_sem_init(1); + ddekit_lock_init_unlocked (&ddekit_irq_ctrl[irq].irqlock); + ddekit_irq_ctrl[irq].thread_exit = FALSE; /* wait for intloop initialization result */ @@ -205,25 +203,30 @@ ddekit_thread_t *ddekit_interrupt_attach(int irq, int shared, void ddekit_interrupt_detach(int irq) { ddekit_interrupt_disable(irq); - ddekit_thread_terminate(ddekit_irq_ctrl[irq].irq_thread); + ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock); + ddekit_irq_ctrl[irq].thread_exit = TRUE; + ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); + + /* I hope this ugly trick can work. */ + thread_abort (ddekit_irq_ctrl[irq].mach_thread); } void ddekit_interrupt_disable(int irq) { - if (ddekit_irq_ctrl[irq].irqsem) { - ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem); + if (ddekit_irq_ctrl[irq].irqlock) { + ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock); --ddekit_irq_ctrl[irq].handle_irq; - ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem); + ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); } } void ddekit_interrupt_enable(int irq) { - if (ddekit_irq_ctrl[irq].irqsem) { - ddekit_sem_down(ddekit_irq_ctrl[irq].irqsem); + if (ddekit_irq_ctrl[irq].irqlock) { + ddekit_lock_lock (&ddekit_irq_ctrl[irq].irqlock); ++ddekit_irq_ctrl[irq].handle_irq; - ddekit_sem_up(ddekit_irq_ctrl[irq].irqsem); + ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); } } -- cgit v1.2.3 From b4bffcfcdf3ab7a55d664e9aa5907f88da503f38 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 05:14:54 +0100 Subject: The code can be compiled now. --- libddekit/Makefile | 11 +- libddekit/condvar.c | 4 +- libddekit/device.defs | 204 ++++++++++ libddekit/include/Makefile | 9 - libddekit/include/ddekit/assert.h | 4 +- libddekit/include/ddekit/condvar.h | 1 + libddekit/include/ddekit/initcall.h | 42 -- libddekit/include/ddekit/thread.h | 2 + libddekit/init.c | 3 + libddekit/initcall.c | 8 - libddekit/interrupt.c | 63 ++- libddekit/kmem.c | 5 +- libddekit/list.c | 4 +- libddekit/lock.c | 3 +- libddekit/mach.defs | 779 ++++++++++++++++++++++++++++++++++++ libddekit/malloc.c | 3 + libddekit/memory.c | 5 +- libddekit/pci.c | 33 +- libddekit/printf.c | 3 + libddekit/thread.c | 68 ++-- libddekit/timer.c | 7 +- libddekit/vm_param.h | 7 + 22 files changed, 1132 insertions(+), 136 deletions(-) create mode 100644 libddekit/device.defs delete mode 100644 libddekit/include/Makefile delete mode 100644 libddekit/include/ddekit/initcall.h delete mode 100644 libddekit/initcall.c create mode 100644 libddekit/mach.defs create mode 100644 libddekit/vm_param.h (limited to 'libddekit/include') diff --git a/libddekit/Makefile b/libddekit/Makefile index 1203ca38..67a3b193 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -19,22 +19,22 @@ dir := libddekit makemode := library libname = libddekit -SRCS= condvar.c init.c initcall.c interrupt.c lock.c malloc.c memory.c \ - pci.c pgtab-old.c pgtab.c printf.c resources.c list.c \ +SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ + pci.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ - include/ddekit/initcall.h include/ddekit/debug.h \ + include/ddekit/semaphore.h include/ddekit/debug.h \ include/ddekit/inline.h include/ddekit/panic.h \ include/ddekit/thread.h include/ddekit/types.h \ include/ddekit/pgtab.h include/ddekit/printf.h \ include/ddekit/pci.h include/ddekit/assert.h \ include/ddekit/interrupt.h include/ddekit/resources.h \ include/ddekit/memory.h include/ddekit/timer.h \ - include/ddekit/semaphore.h include/dde.h \ + include/dde.h \ config.h list.h installhdrs = -MIGSTUBS = +MIGSTUBS = deviceUser.o machUser.o OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS)) HURDLIBS = threads ports @@ -44,3 +44,4 @@ MIGCOMSFLAGS = -prefix dde_ include ../Makeconf LDFLAGS += -lpciaccess +CFLAGS += -Iinclude -Iinclude/ddekit diff --git a/libddekit/condvar.c b/libddekit/condvar.c index 96e28c07..bbd49417 100644 --- a/libddekit/condvar.c +++ b/libddekit/condvar.c @@ -13,12 +13,12 @@ struct ddekit_condvar { }; ddekit_condvar_t *ddekit_condvar_init() { - ddekit_condvar_t *cvp; + struct condition *cvp; cvp = condition_alloc (); condition_init (cvp); - return cvp; + return (ddekit_condvar_t *) cvp; } void ddekit_condvar_wait(ddekit_condvar_t *cvp, ddekit_lock_t *mp) { diff --git a/libddekit/device.defs b/libddekit/device.defs new file mode 100644 index 00000000..6a73853a --- /dev/null +++ b/libddekit/device.defs @@ -0,0 +1,204 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: device/device.defs + * Author: Douglas Orr + * Feb 10, 1988 + * Abstract: + * Mach device support. Mach devices are accessed through + * block and character device interfaces to the kernel. + */ + +#ifdef MACH_KERNEL +simport ; /* for obsolete routines */ +#endif + +subsystem +#if KERNEL_SERVER + KernelServer +#endif + device 2800; + +#include +#include +#include + +serverprefix ds_; + +type pci_config_data_t = array[*:4] of char; +type reply_port_t = MACH_MSG_TYPE_MAKE_SEND_ONCE | polymorphic + ctype: mach_port_t; + +routine device_open( + master_port : mach_port_t; + sreplyport reply_port : reply_port_t; + mode : dev_mode_t; + name : dev_name_t; + out device : device_t + ); + +routine device_close( + device : device_t + ); + +routine device_write( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in data : io_buf_ptr_t; + out bytes_written : int + ); + +routine device_write_inband( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in data : io_buf_ptr_inband_t; + out bytes_written : int + ); + +routine device_read( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in bytes_wanted : int; + out data : io_buf_ptr_t + ); + +routine device_read_inband( + device : device_t; + sreplyport reply_port : reply_port_t; + in mode : dev_mode_t; + in recnum : recnum_t; + in bytes_wanted : int; + out data : io_buf_ptr_inband_t + ); + +/* obsolete */ +routine xxx_device_set_status( + device : device_t; + in flavor : dev_flavor_t; + in status : dev_status_t, IsLong + ); + +/* obsolete */ +routine xxx_device_get_status( + device : device_t; + in flavor : dev_flavor_t; + out status : dev_status_t, IsLong + ); + +/* obsolete */ +routine xxx_device_set_filter( + device : device_t; + in receive_port : mach_port_send_t; + in priority : int; + in filter : filter_array_t, IsLong + ); + +routine device_map( + device : device_t; + in prot : vm_prot_t; + in offset : vm_offset_t; + in size : vm_size_t; + out pager : memory_object_t; + in unmap : int + ); + +routine device_set_status( + device : device_t; + in flavor : dev_flavor_t; + in status : dev_status_t + ); + +routine device_get_status( + device : device_t; + in flavor : dev_flavor_t; + out status : dev_status_t, CountInOut + ); + +routine device_set_filter( + device : device_t; + in receive_port : mach_port_send_t; + in priority : int; + in filter : filter_array_t + ); + +routine device_intr_notify( + master_port : mach_port_t; + in irq : int; + in id : int; + in receive_port : mach_port_send_t + ); + +/* + * Test whether IPC devices exist. + */ +routine pci_present( + master_port : mach_port_t); + +/* + * Find the specified PCI device. + */ +routine pci_find_device( + master_port : mach_port_t; + vendor : short; + device_id : short; + index : short; + out bus : char; + out device_fn : char); + +/* + * Read the configuration space of a IPC device. + */ +routine pci_read_config( + master_port : mach_port_t; + bus : char; + device_fn : char; + where : char; + bytes_wanted : int; + out result : pci_config_data_t); + +/* + * Write the configuration space of a IPC device. + */ +routine pci_write_config( + master_port : mach_port_t; + bus : char; + device_fn : char; + where : char; + data : pci_config_data_t); + +/* + * enable/disable the specified irq. + */ +routine device_irq_enable( + master_port : mach_port_t; + irq : int; + status : char); diff --git a/libddekit/include/Makefile b/libddekit/include/Makefile deleted file mode 100644 index 8d31023f..00000000 --- a/libddekit/include/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -PKGDIR ?= .. -L4DIR ?= $(PKGDIR)/../.. - -# All haeder files found in this directory tree will be automatically -# installed in a way that they can be included with -# #include later. -# No need to list them in this Makefile. - -include $(L4DIR)/mk/include.mk diff --git a/libddekit/include/ddekit/assert.h b/libddekit/include/ddekit/assert.h index 5d572b49..5d593662 100644 --- a/libddekit/include/ddekit/assert.h +++ b/libddekit/include/ddekit/assert.h @@ -1,8 +1,8 @@ #ifndef _ddekit_assert_h #define _ddekit_assert_h -#include -#include +#include "ddekit/printf.h" +#include "ddekit/panic.h" /** \file ddekit/assert.h */ diff --git a/libddekit/include/ddekit/condvar.h b/libddekit/include/ddekit/condvar.h index ba87358d..129a718d 100644 --- a/libddekit/include/ddekit/condvar.h +++ b/libddekit/include/ddekit/condvar.h @@ -2,6 +2,7 @@ #define _ddekit_condvar_h /** \file ddekit/condvar.h */ +#include "ddekit/lock.h" struct ddekit_condvar; typedef struct ddekit_condvar ddekit_condvar_t; diff --git a/libddekit/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h deleted file mode 100644 index b503cc6a..00000000 --- a/libddekit/include/ddekit/initcall.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _ddekit_initcall_h -#define _ddekit_initcall_h - -// from l4/sys/compiler.h -#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4 -#define L4_STICKY(x) __attribute__((used)) x -#else -#define L4_STICKY(x) __attribute__((unused)) x -#endif - -#define l4str(s) #s - -// from dde_linux/ARCH-x86/ctor.h -typedef void (*l4ddekit_initcall_t)(void); - -#define __l4ddekit_initcall(p) \ - __attribute__ ((__section__ (".l4dde_ctors." #p))) - -/** Define a function to be a DDEKit initcall. - * - * Define a function to be a DDEKit initcall. This function will then be placed - * in a separate linker section of the binary (called .l4dde_ctors). The L4Env - * construction mechanism will execute all constructors in this section during - * application startup. - * - * This is the right place to place Linux' module_init functions & Co. - * - * \param fn function - */ -#define DDEKIT_INITCALL(fn) DDEKIT_CTOR(fn, 1) - -#define DDEKIT_CTOR(fn, prio) \ - static l4ddekit_initcall_t \ - L4_STICKY(__l4ddekit_initcall_##fn) \ - __l4ddekit_initcall(prio) = (void *)fn - -/** - * Runs all registered initcalls. - */ -void ddekit_do_initcalls(void); - -#endif diff --git a/libddekit/include/ddekit/thread.h b/libddekit/include/ddekit/thread.h index 6e505818..8ed52013 100644 --- a/libddekit/include/ddekit/thread.h +++ b/libddekit/include/ddekit/thread.h @@ -3,6 +3,8 @@ /** \defgroup DDEKit_threads */ +#include "ddekit/lock.h" + struct ddekit_thread; typedef struct ddekit_thread ddekit_thread_t; diff --git a/libddekit/init.c b/libddekit/init.c index 6bc9d8ff..9114ff46 100644 --- a/libddekit/init.c +++ b/libddekit/init.c @@ -9,8 +9,11 @@ void ddekit_init(void) { extern void linux_kmem_init (); extern int log_init (); + extern void interrupt_init (); + ddekit_init_threads(); linux_kmem_init (); log_init (); + interrupt_init (); } diff --git a/libddekit/initcall.c b/libddekit/initcall.c deleted file mode 100644 index 49e1fec1..00000000 --- a/libddekit/initcall.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -#include - -void ddekit_do_initcalls() { - crt0_dde_construction(); -} - diff --git a/libddekit/interrupt.c b/libddekit/interrupt.c index 6a8b3fd8..5a778f9b 100644 --- a/libddekit/interrupt.c +++ b/libddekit/interrupt.c @@ -8,9 +8,17 @@ * FIXME use consume flag to indicate IRQ was handled */ +#include +#include +#include +#include + #include "ddekit/interrupt.h" +#include "ddekit/semaphore.h" +#include "ddekit/printf.h" +#include "ddekit/memory.h" -#include +#include "device_U.h" #define DEBUG_INTERRUPTS 0 @@ -18,6 +26,15 @@ #define BLOCK_IRQ 0 +#define MACH_NOTIFY_IRQ 100 + +typedef struct +{ + mach_msg_header_t irq_header; + mach_msg_type_t irq_type; + int irq; +} mach_irq_notification_t; + /* * Internal type for interrupt loop parameters */ @@ -35,19 +52,14 @@ struct intloop_params static struct { - int handle_irq; /* nested irq disable count */ - ddekit_lock_t *irqlock; + int handle_irq; /* nested irq disable count */ + ddekit_lock_t irqlock; ddekit_thread_t *irq_thread; /* thread ID for detaching from IRQ later on */ boolean_t thread_exit; thread_t mach_thread; } ddekit_irq_ctrl[MAX_INTERRUPTS]; - -static void ddekit_irq_exit_fn(l4thread_t thread, void *data) -{ - // TODO we can remove the port for delivery of interrupt explicitly, - // though it cannot cause any harm even if we don't remove it. -} +static mach_port_t master_device; /** * Interrupt service loop @@ -57,26 +69,25 @@ static void intloop(void *arg) { kern_return_t ret; struct intloop_params *params = arg; - mach_port_t delivery_port; + mach_port_t delivery_port = mach_reply_port (); int my_index; my_index = params->irq; - ddekit_irq_ctrl[my_index]->mach_thread = mach_thread_self (); + ddekit_irq_ctrl[my_index].mach_thread = mach_thread_self (); ret = thread_priority (mach_thread_self (), DDEKIT_IRQ_PRIO, 0); if (ret) error (0, ret, "thread_priority"); // TODO I should give another parameter to show whether // the interrupt can be shared. - ret = device_intr_notify (master_device, dev->irq, - dev->dev_id, delivery_port, + ret = device_intr_notify (master_device, params->irq, + 0, delivery_port, MACH_MSG_TYPE_MAKE_SEND); if (!ret) { /* inform thread creator of error */ /* XXX does omega0 error code have any meaning to DDEKit users? */ params->start_err = ret; ddekit_sem_up(params->started); - return NULL; } #if 0 @@ -104,23 +115,25 @@ static void intloop(void *arg) /* It's an interrupt not for us. It shouldn't happen. */ if (irq_header->irq != params->irq) { - LOG("We get interrupt %d, %d is expected", - irq_header->irq, params->irq); + ddekit_printf ("We get interrupt %d, %d is expected", + irq_header->irq, params->irq); return 1; } /* only call registered handler function, if IRQ is not disabled */ ddekit_lock_lock (&ddekit_irq_ctrl[my_index].irqlock); if (ddekit_irq_ctrl[my_index].handle_irq > 0) { - LOGd(DEBUG_INTERRUPTS, "IRQ %x, handler %p", my_index,params->handler); + ddekit_printf ("IRQ %x, handler %p", + my_index,params->handler); params->handler(params->priv); } else - LOGd(DEBUG_INTERRUPTS, "not handling IRQ %x, because it is disabled.", my_index); + ddekit_printf ("not handling IRQ %x, because it is disabled.", + my_index); // ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY; - if (ddekit_irq_ctrl[irq].thread_exit) { + if (ddekit_irq_ctrl[my_index].thread_exit) { ddekit_lock_unlock (&ddekit_irq_ctrl[my_index].irqlock); ddekit_thread_exit(); return 1; @@ -129,7 +142,7 @@ static void intloop(void *arg) return 1; } - mach_msg_server (int_server, 0, delivery_port); + mach_msg_server (irq_server, 0, delivery_port); } @@ -238,3 +251,13 @@ void ddekit_interrupt_enable(int irq) ddekit_lock_unlock (&ddekit_irq_ctrl[irq].irqlock); } } + +void interrupt_init () +{ + + error_t err; + + err = get_privileged_ports (0, &master_device); + if (err) + error (1, err, "get_privileged_ports"); +} diff --git a/libddekit/kmem.c b/libddekit/kmem.c index 4769190e..2e6f7340 100644 --- a/libddekit/kmem.c +++ b/libddekit/kmem.c @@ -28,9 +28,12 @@ #include #include -#include "util.h" #include "vm_param.h" +#include "ddekit/panic.h" + +#define debug ddekit_debug + extern int printf (const char *, ...); /* Amount of memory to reserve for Linux memory allocator. diff --git a/libddekit/list.c b/libddekit/list.c index 992ea9ad..4f163584 100644 --- a/libddekit/list.c +++ b/libddekit/list.c @@ -48,7 +48,7 @@ struct list *remove_entry_head (struct list *head) { struct list *entry = head->next; - if (EMPTY_ENTRY (entry)) + if (EMPTY_LIST (entry)) return NULL; remove_entry (entry); @@ -59,7 +59,7 @@ struct list *remove_entry_end (struct list *head) { struct list *entry = head->prev; - if (EMPTY_ENTRY (entry)) + if (EMPTY_LIST (entry)) return NULL; remove_entry (entry); diff --git a/libddekit/lock.c b/libddekit/lock.c index bf643e65..4c4cff01 100644 --- a/libddekit/lock.c +++ b/libddekit/lock.c @@ -1,6 +1,7 @@ #include #include "ddekit/lock.h" +#include "ddekit/memory.h" #define DDEKIT_DEBUG_LOCKS 0 @@ -48,6 +49,6 @@ int _ddekit_lock_owner(struct ddekit_lock **mtx) { /* The return value is the address of the holder. * I hope it will be OK. At least, it is OK * for the current implementation of DDE Linux/BSD */ - return (int) (*mtx)->holder; + return (int) (*mtx)->helder; } diff --git a/libddekit/mach.defs b/libddekit/mach.defs new file mode 100644 index 00000000..764bd451 --- /dev/null +++ b/libddekit/mach.defs @@ -0,0 +1,779 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University. + * Copyright (c) 1993,1994 The University of Utah and + * the Computer Systems Laboratory (CSL). + * All rights reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF + * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY + * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF + * THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Matchmaker definitions file for Mach kernel interface. + */ + +#ifdef MACH_KERNEL +simport ; /* for obsolete routines */ +#endif /* MACH_KERNEL */ + +subsystem +#if KERNEL_USER + KernelUser +#endif /* KERNEL_USER */ +#if KERNEL_SERVER + KernelServer +#endif /* KERNEL_SERVER */ + mach 2000; + +#ifdef KERNEL_USER +userprefix r_; +#endif /* KERNEL_USER */ + +#include +#include + +skip; /* old port_allocate */ +skip; /* old port_deallocate */ +skip; /* old port_enable */ +skip; /* old port_disable */ +skip; /* old port_select */ +skip; /* old port_set_backlog */ +skip; /* old port_status */ + +/* + * Create a new task with an empty set of IPC rights, + * and having an address space constructed from the + * target task (or empty, if inherit_memory is FALSE). + */ +routine task_create( + target_task : task_t; + inherit_memory : boolean_t; + out child_task : task_t); + +/* + * Destroy the target task, causing all of its threads + * to be destroyed, all of its IPC rights to be deallocated, + * and all of its address space to be deallocated. + */ +routine task_terminate( + target_task : task_t); + +/* + * Get user-level handler entry points for all + * emulated system calls. + */ +routine task_get_emulation_vector( + task : task_t; + out vector_start : int; + out emulation_vector: emulation_vector_t); + +/* + * Establish user-level handlers for the specified + * system calls. Non-emulated system calls are specified + * with emulation_vector[i] == EML_ROUTINE_NULL. + */ +routine task_set_emulation_vector( + task : task_t; + vector_start : int; + emulation_vector: emulation_vector_t); + + +/* + * Returns the set of threads belonging to the target task. + */ +routine task_threads( + target_task : task_t; + out thread_list : thread_array_t); + +/* + * Returns information about the target task. + */ +routine task_info( + target_task : task_t; + flavor : int; + out task_info_out : task_info_t, CountInOut); + + +skip; /* old task_status */ +skip; /* old task_set_notify */ +skip; /* old thread_create */ + +/* + * Destroy the target thread. + */ +routine thread_terminate( + target_thread : thread_t); + +/* + * Return the selected state information for the target + * thread. If the thread is currently executing, the results + * may be stale. [Flavor THREAD_STATE_FLAVOR_LIST provides a + * list of valid flavors for the target thread.] + */ +routine thread_get_state( + target_thread : thread_t; + flavor : int; + out old_state : thread_state_t, CountInOut); + +/* + * Set the selected state information for the target thread. + * If the thread is currently executing, the state change + * may be ill-defined. + */ +routine thread_set_state( + target_thread : thread_t; + flavor : int; + new_state : thread_state_t); + +/* + * Returns information about the target thread. + */ +routine thread_info( + target_thread : thread_t; + flavor : int; + out thread_info_out : thread_info_t, CountInOut); + +skip; /* old thread_mutate */ + +/* + * Allocate zero-filled memory in the address space + * of the target task, either at the specified address, + * or wherever space can be found (if anywhere is TRUE), + * of the specified size. The address at which the + * allocation actually took place is returned. + */ +#ifdef EMULATOR +skip; /* the emulator redefines vm_allocate using vm_map */ +#else /* EMULATOR */ +routine vm_allocate( + target_task : vm_task_t; + inout address : vm_address_t; + size : vm_size_t; + anywhere : boolean_t); +#endif /* EMULATOR */ + +skip; /* old vm_allocate_with_pager */ + +/* + * Deallocate the specified range from the virtual + * address space of the target task. + */ +routine vm_deallocate( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t); + +/* + * Set the current or maximum protection attribute + * for the specified range of the virtual address + * space of the target task. The current protection + * limits the memory access rights of threads within + * the task; the maximum protection limits the accesses + * that may be given in the current protection. + * Protections are specified as a set of {read, write, execute} + * *permissions*. + */ +routine vm_protect( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + set_maximum : boolean_t; + new_protection : vm_prot_t); + +/* + * Set the inheritance attribute for the specified range + * of the virtual address space of the target task. + * The inheritance value is one of {none, copy, share}, and + * specifies how the child address space should acquire + * this memory at the time of a task_create call. + */ +routine vm_inherit( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + new_inheritance : vm_inherit_t); + +/* + * Returns the contents of the specified range of the + * virtual address space of the target task. [The + * range must be aligned on a virtual page boundary, + * and must be a multiple of pages in extent. The + * protection on the specified range must permit reading.] + */ +routine vm_read( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + out data : pointer_t); + +/* + * Writes the contents of the specified range of the + * virtual address space of the target task. [The + * range must be aligned on a virtual page boundary, + * and must be a multiple of pages in extent. The + * protection on the specified range must permit writing.] + */ +routine vm_write( + target_task : vm_task_t; + address : vm_address_t; + data : pointer_t); + +/* + * Copy the contents of the source range of the virtual + * address space of the target task to the destination + * range in that same address space. [Both of the + * ranges must be aligned on a virtual page boundary, + * and must be multiples of pages in extent. The + * protection on the source range must permit reading, + * and the protection on the destination range must + * permit writing.] + */ +routine vm_copy( + target_task : vm_task_t; + source_address : vm_address_t; + size : vm_size_t; + dest_address : vm_address_t); + +/* + * Returns information about the contents of the virtual + * address space of the target task at the specified + * address. The returned protection, inheritance, sharing + * and memory object values apply to the entire range described + * by the address range returned; the memory object offset + * corresponds to the beginning of the address range. + * [If the specified address is not allocated, the next + * highest address range is described. If no addresses beyond + * the one specified are allocated, the call returns KERN_NO_SPACE.] + */ +routine vm_region( + target_task : vm_task_t; + inout address : vm_address_t; + out size : vm_size_t; + out protection : vm_prot_t; + out max_protection : vm_prot_t; + out inheritance : vm_inherit_t; + out is_shared : boolean_t; + /* avoid out-translation of the argument */ + out object_name : memory_object_name_t = + MACH_MSG_TYPE_MOVE_SEND + ctype: mach_port_t; + out offset : vm_offset_t); + +/* + * Return virtual memory statistics for the host + * on which the target task resides. [Note that the + * statistics are not specific to the target task.] + */ +routine vm_statistics( + target_task : vm_task_t; + out vm_stats : vm_statistics_data_t); + +skip; /* old task_by_u*x_pid */ +skip; /* old vm_pageable */ + +/* + * Stash a handful of ports for the target task; child + * tasks inherit this stash at task_create time. + */ +routine mach_ports_register( + target_task : task_t; + init_port_set : mach_port_array_t = + ^array[] of mach_port_t); + +/* + * Retrieve the stashed ports for the target task. + */ +routine mach_ports_lookup( + target_task : task_t; + out init_port_set : mach_port_array_t = + ^array[] of mach_port_t); + +skip; /* old u*x_pid */ +skip; /* old netipc_listen */ +skip; /* old netipc_ignore */ + +/* + * Provide the data contents of a range of the given memory + * object, with the access restriction specified. [Only + * whole virtual pages of data can be accepted; partial pages + * will be discarded. Data should be provided on request, but + * may be provided in advance as desired. When data already + * held by this kernel is provided again, the new data is ignored. + * The access restriction is the subset of {read, write, execute} + * which are prohibited. The kernel may not provide any data (or + * protection) consistency among pages with different virtual page + * alignments within the same object.] + */ +simpleroutine memory_object_data_provided( + memory_control : memory_object_control_t; + offset : vm_offset_t; + data : pointer_t; + lock_value : vm_prot_t); + +/* + * Indicate that a range of the given temporary memory object does + * not exist, and that the backing memory object should be used + * instead (or zero-fill memory be used, if no backing object exists). + * [This call is intended for use only by the default memory manager. + * It should not be used to indicate a real error -- + * memory_object_data_error should be used for that purpose.] + */ +simpleroutine memory_object_data_unavailable( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t); + +/* + * Retrieves the attributes currently associated with + * a memory object. + */ +routine memory_object_get_attributes( + memory_control : memory_object_control_t; + out object_ready : boolean_t; + out may_cache : boolean_t; + out copy_strategy : memory_object_copy_strategy_t); + +/* + * Sets the default memory manager, the port to which + * newly-created temporary memory objects are delivered. + * [See (memory_object_default)memory_object_create.] + * The old memory manager port is returned. + */ +routine vm_set_default_memory_manager( + host_priv : host_priv_t; + inout default_manager : mach_port_make_send_t); + +skip; /* old pager_flush_request */ + +/* + * Control use of the data associated with the given + * memory object. For each page in the given range, + * perform the following operations, in order: + * 1) restrict access to the page (disallow + * forms specified by "prot"); + * 2) write back modifications (if "should_return" + * is RETURN_DIRTY and the page is dirty, or + * "should_return" is RETURN_ALL and the page + * is either dirty or precious); and, + * 3) flush the cached copy (if "should_flush" + * is asserted). + * The set of pages is defined by a starting offset + * ("offset") and size ("size"). Only pages with the + * same page alignment as the starting offset are + * considered. + * + * A single acknowledgement is sent (to the "reply_to" + * port) when these actions are complete. + * + * There are two versions of this routine because IPC distinguishes + * between booleans and integers (a 2-valued integer is NOT a + * boolean). The new routine is backwards compatible at the C + * language interface. + */ +simpleroutine xxx_memory_object_lock_request( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t; + should_clean : boolean_t; + should_flush : boolean_t; + lock_value : vm_prot_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + + +simpleroutine memory_object_lock_request( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t; + should_return : memory_object_return_t; + should_flush : boolean_t; + lock_value : vm_prot_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + +/* obsolete */ +routine xxx_task_get_emulation_vector( + task : task_t; + out vector_start : int; + out emulation_vector: xxx_emulation_vector_t, IsLong); + +/* obsolete */ +routine xxx_task_set_emulation_vector( + task : task_t; + vector_start : int; + emulation_vector: xxx_emulation_vector_t, IsLong); + +/* + * Returns information about the host on which the + * target object resides. [This object may be + * a task, thread, or memory_object_control port.] + */ +routine xxx_host_info( + target_task : mach_port_t; + out info : machine_info_data_t); + +/* + * Returns information about a particular processor on + * the host on which the target task resides. + */ +routine xxx_slot_info( + target_task : task_t; + slot : int; + out info : machine_slot_data_t); + +/* + * Performs control operations (currently only + * turning off or on) on a particular processor on + * the host on which the target task resides. + */ +routine xxx_cpu_control( + target_task : task_t; + cpu : int; + running : boolean_t); + +skip; /* old thread_statistics */ +skip; /* old task_statistics */ +skip; /* old netport_init */ +skip; /* old netport_enter */ +skip; /* old netport_remove */ +skip; /* old thread_set_priority */ + +/* + * Increment the suspend count for the target task. + * No threads within a task may run when the suspend + * count for that task is non-zero. + */ +routine task_suspend( + target_task : task_t); + +/* + * Decrement the suspend count for the target task, + * if the count is currently non-zero. If the resulting + * suspend count is zero, then threads within the task + * that also have non-zero suspend counts may execute. + */ +routine task_resume( + target_task : task_t); + +/* + * Returns the current value of the selected special port + * associated with the target task. + */ +routine task_get_special_port( + task : task_t; + which_port : int; + out special_port : mach_port_t); + +/* + * Set one of the special ports associated with the + * target task. + */ +routine task_set_special_port( + task : task_t; + which_port : int; + special_port : mach_port_t); + +/* obsolete */ +routine xxx_task_info( + target_task : task_t; + flavor : int; + out task_info_out : task_info_t, IsLong); + + +/* + * Create a new thread within the target task, returning + * the port representing that new thread. The + * initial execution state of the thread is undefined. + */ +routine thread_create( + parent_task : task_t; + out child_thread : thread_t); + +/* + * Increment the suspend count for the target thread. + * Once this call has completed, the thread will not + * execute any further user or meta- instructions. + * Once suspended, a thread may not execute again until + * its suspend count is zero, and the suspend count + * for its task is also zero. + */ +routine thread_suspend( + target_thread : thread_t); + +/* + * Decrement the suspend count for the target thread, + * if that count is not already zero. + */ +routine thread_resume( + target_thread : thread_t); + +/* + * Cause any user or meta- instructions currently being + * executed by the target thread to be aborted. [Meta- + * instructions consist of the basic traps for IPC + * (e.g., msg_send, msg_receive) and self-identification + * (e.g., task_self, thread_self, thread_reply). Calls + * described by MiG interfaces are not meta-instructions + * themselves.] + */ +routine thread_abort( + target_thread : thread_t); + +/* obsolete */ +routine xxx_thread_get_state( + target_thread : thread_t; + flavor : int; + out old_state : thread_state_t, IsLong); + +/* obsolete */ +routine xxx_thread_set_state( + target_thread : thread_t; + flavor : int; + new_state : thread_state_t, IsLong); + +/* + * Returns the current value of the selected special port + * associated with the target thread. + */ +routine thread_get_special_port( + thread : thread_t; + which_port : int; + out special_port : mach_port_t); + +/* + * Set one of the special ports associated with the + * target thread. + */ +routine thread_set_special_port( + thread : thread_t; + which_port : int; + special_port : mach_port_t); + +/* obsolete */ +routine xxx_thread_info( + target_thread : thread_t; + flavor : int; + out thread_info_out : thread_info_t, IsLong); + +/* + * Establish a user-level handler for the specified + * system call. + */ +routine task_set_emulation( + target_port : task_t; + routine_entry_pt: vm_address_t; + routine_number : int); + +/* + * Establish restart pc for interrupted atomic sequences. + * This reuses the message number for the old task_get_io_port. + * See task_info.h for description of flavors. + * + */ +routine task_ras_control( + target_task : task_t; + basepc : vm_address_t; + boundspc : vm_address_t; + flavor : int); + + + +skip; /* old host_ipc_statistics */ +skip; /* old port_names */ +skip; /* old port_type */ +skip; /* old port_rename */ +skip; /* old port_allocate */ +skip; /* old port_deallocate */ +skip; /* old port_set_backlog */ +skip; /* old port_status */ +skip; /* old port_set_allocate */ +skip; /* old port_set_deallocate */ +skip; /* old port_set_add */ +skip; /* old port_set_remove */ +skip; /* old port_set_status */ +skip; /* old port_insert_send */ +skip; /* old port_extract_send */ +skip; /* old port_insert_receive */ +skip; /* old port_extract_receive */ + +/* + * Map a user-defined memory object into the virtual address + * space of the target task. If desired (anywhere is TRUE), + * the kernel will find a suitable address range of the + * specified size; else, the specific address will be allocated. + * + * The beginning address of the range will be aligned on a virtual + * page boundary, be at or beyond the address specified, and + * meet the mask requirements (bits turned on in the mask must not + * be turned on in the result); the size of the range, in bytes, + * will be rounded up to an integral number of virtual pages. + * + * The memory in the resulting range will be associated with the + * specified memory object, with the beginning of the memory range + * referring to the specified offset into the memory object. + * + * The mapping will take the current and maximum protections and + * the inheritance attributes specified; see the vm_protect and + * vm_inherit calls for a description of these attributes. + * + * If desired (copy is TRUE), the memory range will be filled + * with a copy of the data from the memory object; this copy will + * be private to this mapping in this target task. Otherwise, + * the memory in this mapping will be shared with other mappings + * of the same memory object at the same offset (in this task or + * in other tasks). [The Mach kernel only enforces shared memory + * consistency among mappings on one host with similar page alignments. + * The user-defined memory manager for this object is responsible + * for further consistency.] + */ +#ifdef EMULATOR +routine htg_vm_map( + target_task : vm_task_t; + ureplyport reply_port : mach_port_make_send_once_t; + inout address : vm_address_t; + size : vm_size_t; + mask : vm_address_t; + anywhere : boolean_t; + memory_object : memory_object_t; + offset : vm_offset_t; + copy : boolean_t; + cur_protection : vm_prot_t; + max_protection : vm_prot_t; + inheritance : vm_inherit_t); +#else /* EMULATOR */ +routine vm_map( + target_task : vm_task_t; + inout address : vm_address_t; + size : vm_size_t; + mask : vm_address_t; + anywhere : boolean_t; + memory_object : memory_object_t; + offset : vm_offset_t; + copy : boolean_t; + cur_protection : vm_prot_t; + max_protection : vm_prot_t; + inheritance : vm_inherit_t); +#endif /* EMULATOR */ + +/* + * Indicate that a range of the specified memory object cannot + * be provided at this time. [Threads waiting for memory pages + * specified by this call will experience a memory exception. + * Only threads waiting at the time of the call are affected.] + */ +simpleroutine memory_object_data_error( + memory_control : memory_object_control_t; + offset : vm_offset_t; + size : vm_size_t; + error_value : kern_return_t); + +/* + * Make decisions regarding the use of the specified + * memory object. + */ +simpleroutine memory_object_set_attributes( + memory_control : memory_object_control_t; + object_ready : boolean_t; + may_cache : boolean_t; + copy_strategy : memory_object_copy_strategy_t); + +/* + */ +simpleroutine memory_object_destroy( + memory_control : memory_object_control_t; + reason : kern_return_t); + +/* + * Provide the data contents of a range of the given memory + * object, with the access restriction specified, optional + * precious attribute, and reply message. [Only + * whole virtual pages of data can be accepted; partial pages + * will be discarded. Data should be provided on request, but + * may be provided in advance as desired. When data already + * held by this kernel is provided again, the new data is ignored. + * The access restriction is the subset of {read, write, execute} + * which are prohibited. The kernel may not provide any data (or + * protection) consistency among pages with different virtual page + * alignments within the same object. The precious value controls + * how the kernel treats the data. If it is FALSE, the kernel treats + * its copy as a temporary and may throw it away if it hasn't been + * changed. If the precious value is TRUE, the kernel treats its + * copy as a data repository and promises to return it to the manager; + * the manager may tell the kernel to throw it away instead by flushing + * and not cleaning the data -- see memory_object_lock_request. The + * reply_to port is for a compeletion message; it will be + * memory_object_supply_completed.] + */ + +simpleroutine memory_object_data_supply( + memory_control : memory_object_control_t; + offset : vm_offset_t; + data : pointer_t, Dealloc[]; + lock_value : vm_prot_t; + precious : boolean_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + +simpleroutine memory_object_ready( + memory_control : memory_object_control_t; + may_cache : boolean_t; + copy_strategy : memory_object_copy_strategy_t); + +simpleroutine memory_object_change_attributes( + memory_control : memory_object_control_t; + may_cache : boolean_t; + copy_strategy : memory_object_copy_strategy_t; + reply_to : mach_port_t = + MACH_MSG_TYPE_MAKE_SEND_ONCE|polymorphic); + +skip; /* old host_callout_statistics_reset */ +skip; /* old port_set_select */ +skip; /* old port_set_backup */ + +/* + * Set/Get special properties of memory associated + * to some virtual address range, such as cachability, + * migrability, replicability. Machine-dependent. + */ +routine vm_machine_attribute( + target_task : vm_task_t; + address : vm_address_t; + size : vm_size_t; + attribute : vm_machine_attribute_t; + inout value : vm_machine_attribute_val_t); + +/*skip;*/ /* old host_fpa_counters_reset */ + +/* + * This routine is created for allocating DMA buffers. + * We are going to get a contiguous physical memory + * and its physical address in addition to the virtual address. + */ +routine vm_dma_buff_alloc( + host_priv : host_priv_t; + target_task : vm_task_t; + size : vm_size_t; + out vaddr : vm_address_t; + out paddr : vm_address_t); + +/* + * There is no more room in this interface for additional calls. + */ diff --git a/libddekit/malloc.c b/libddekit/malloc.c index c3735bdb..a30cd7b7 100644 --- a/libddekit/malloc.c +++ b/libddekit/malloc.c @@ -29,6 +29,9 @@ * * Each chunk stores its size in the first word for free() to work. */ + +#include + void *ddekit_simple_malloc(unsigned size) { return malloc (size); diff --git a/libddekit/memory.c b/libddekit/memory.c index 93853e55..27be4eeb 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -11,8 +11,10 @@ */ #include "ddekit/memory.h" +#include "ddekit/panic.h" extern void * linux_kmalloc (unsigned int size, int priority); +extern void linux_kfree (void *p); /**************** @@ -110,6 +112,7 @@ void *ddekit_slab_get_data(struct ddekit_slab * slab) #if 0 return l4slab_get_data(&slab->cache); #endif + return NULL; } @@ -154,7 +157,7 @@ struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) */ void ddekit_large_free(void *objp) { - return linux_kfree (objp); + linux_kfree (objp); } diff --git a/libddekit/pci.c b/libddekit/pci.c index 32e02b84..5c3f4ef6 100644 --- a/libddekit/pci.c +++ b/libddekit/pci.c @@ -1,4 +1,8 @@ +#include #include + +#include "ddekit/assert.h" +#include "ddekit/printf.h" #include "ddekit/pci.h" #include "config.h" @@ -43,8 +47,8 @@ void ddekit_pci_init(void) dev_iter = pci_slot_match_iterator_create (NULL); while ((pci_dev = pci_device_next (dev_iter)) != NULL) { if (slots_found == MAX_PCI_DEVS) { - LOGd(dbg_this, "find more than %d pci devices", - slots_found); + ddekit_printf ("find more than %d pci devices", + slots_found); break; } /* Pretend all our devices are chained to exactly one bus. */ @@ -68,7 +72,7 @@ int ddekit_pci_get_device(int nr, int *bus, int *slot, int *func) { ddekit_pci_dev_t *dev; - LOGd(dbg_this, "searching for dev #%d", nr); + ddekit_printf ("searching for dev #%d", nr); if (nr >= 0 && nr < MAX_PCI_DEVS && !invalid_device(&ddekit_pci_bus[nr])) { dev = &ddekit_pci_bus[nr]; @@ -89,7 +93,8 @@ ddekit_pci_dev_t *ddekit_pci_find_device(int *bus, int *slot, int *func, Assert(slot); Assert(func); - LOGd(dbg_this, "start %p (slot %d)", start, start ? start->slot : -1); + ddekit_printf ("start %p (slot %d)", + start, start ? start->slot : -1); int idx = start ? start->slot + 1 : 0; for ( ; idx < MAX_PCI_DEVS; ++idx) { @@ -214,7 +219,8 @@ int ddekit_pci_writel(int bus, int slot, int func, int pos, ddekit_uint32_t val int ddekit_pci_enable_device(struct ddekit_pci_dev *dev) { - return pci_device_enable (dev->dev); + pci_device_enable (dev->dev); + return 0; } int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) @@ -238,7 +244,7 @@ int ddekit_pci_disable_device(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) { - return dev->dev.vendor_id; + return dev->dev->vendor_id; } @@ -251,7 +257,7 @@ unsigned short ddekit_pci_get_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) { - return dev->dev.device_id; + return dev->dev->device_id; } @@ -264,7 +270,7 @@ unsigned short ddekit_pci_get_device_id(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) { - return dev->dev.subvendor_id; + return dev->dev->subvendor_id; } @@ -277,7 +283,7 @@ unsigned short ddekit_pci_get_sub_vendor(struct ddekit_pci_dev *dev) */ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) { - return dev->dev.subdevice_id; + return dev->dev->subdevice_id; } @@ -290,7 +296,7 @@ unsigned short ddekit_pci_get_sub_device(struct ddekit_pci_dev *dev) */ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) { - return dev->dev.device_class; + return dev->dev->device_class; } @@ -303,7 +309,7 @@ unsigned ddekit_pci_get_dev_class(struct ddekit_pci_dev *dev) */ unsigned long ddekit_pci_get_irq(struct ddekit_pci_dev *dev) { - return dev->dev.irq; + return dev->dev->irq; } @@ -345,10 +351,11 @@ char *ddekit_pci_get_slot_name(struct ddekit_pci_dev *dev) */ ddekit_pci_res_t *ddekit_pci_get_resource(struct ddekit_pci_dev *dev, unsigned int idx) { - if (idx > L4IO_PCIDEV_RES) + // TODO +// if (idx > L4IO_PCIDEV_RES) return NULL; - //TODO return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); +// return (ddekit_pci_res_t *)(&(dev->l4dev.res[idx])); } diff --git a/libddekit/printf.c b/libddekit/printf.c index bbd58863..72ff5003 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -4,7 +4,10 @@ * \date 2006-03-01 */ +#include +#include #include +#include #include #include "ddekit/printf.h" diff --git a/libddekit/thread.c b/libddekit/thread.c index a095db2f..081a4742 100644 --- a/libddekit/thread.c +++ b/libddekit/thread.c @@ -3,14 +3,18 @@ #include #include #include +#include +#include +#include +#include "ddekit/memory.h" #include "ddekit/semaphore.h" #include "list.h" #include "ddekit/thread.h" #define DDEKIT_THREAD_STACK_SIZE 0x2000 /* 8 KB */ -static struct ddekit_slab *ddekit_stack_slab = NULL; +//static struct ddekit_slab *ddekit_stack_slab = NULL; struct _ddekit_private_data { struct list list; @@ -18,8 +22,7 @@ struct _ddekit_private_data { /* point to the thread who has the private data. */ struct ddekit_thread *thread; mach_msg_header_t wakeupmsg; - -} +}; struct ddekit_thread { struct cthread thread; @@ -64,20 +67,20 @@ static error_t _create_wakeupmsg (struct _ddekit_private_data *data) return 0; } -static void setup_thread (cthread_t *t, const char *name) { +static void setup_thread (struct ddekit_thread *t, const char *name) { error_t err; struct _ddekit_private_data *private_data; if (name) { - const char *cpy = NULL; + char *cpy = NULL; - cpy = malloc (strlen (name) + 1); + cpy = ddekit_simple_malloc (strlen (name) + 1); if (cpy == NULL) error (0, 0, "fail to allocate memory"); else strcpy (cpy, name); - cthread_set_name (t, name); + cthread_set_name (&t->thread, name); } /* @@ -92,20 +95,21 @@ static void setup_thread (cthread_t *t, const char *name) { private_data->sleep_cond = condition_alloc (); condition_init (private_data->sleep_cond); - private_data->list = {&private_data->list, &private_data->list}; + private_data->list.prev = &private_data->list; + private_data->list.next = &private_data->list; private_data->thread = t; err = _create_wakeupmsg (private_data); - // TODO I need to change this. - assert_perror (err); + if (err) + error (1, err, "_create_wakeupmsg"); - cthread_set_ldata (t, private_data); + cthread_set_ldata (&t->thread, private_data); } ddekit_thread_t *ddekit_thread_setup_myself(const char *name) { ddekit_thread_t *td = ddekit_thread_myself(); - setup_thread (&td->thread, name); + setup_thread (td, name); return td; } @@ -116,7 +120,7 @@ ddekit_thread_t *ddekit_thread_create(void (*fun)(void *), void *arg, const char // before initialization is completed. td = (ddekit_thread_t *) cthread_fork (fun, arg); cthread_detach (&td->thread); - setup_thread (&td->thread, name); + setup_thread (td, name); return td; } @@ -180,7 +184,7 @@ void ddekit_thread_sleep(ddekit_lock_t *lock) { // TODO condition_wait cannot guarantee that the thread is // woke up by another thread, maybe by signals. // Does it matter here? - condition_wait (data->sleep_cond, lock); + condition_wait (data->sleep_cond, (struct mutex *) *lock); } void dekit_thread_wakeup(ddekit_thread_t *td) { @@ -205,7 +209,7 @@ void ddekit_thread_exit() { name = cthread_name (t); cthread_set_name (t, NULL); - free (name); + ddekit_simple_free ((char *) name); cthread_exit (0); } @@ -225,10 +229,18 @@ void ddekit_yield(void) } void ddekit_init_threads() { + char *str = "main"; + char *name = ddekit_simple_malloc (strlen (str) + 1); + + strcpy (name, str); // TODO maybe the name has already been set. - cthread_set_name (cthread_self (), "main"); + cthread_set_name (cthread_self (), name); } +/********************************************************************** + * semaphore + **********************************************************************/ + /* Block THREAD. */ static error_t _timedblock (struct _ddekit_private_data *data, const struct timespec *abstime) @@ -281,16 +293,16 @@ static void _block (struct _ddekit_private_data *data) assert_perror (err); } -static int _sem_timedwait_internal (sem_t *restrict sem, +static int _sem_timedwait_internal (ddekit_sem_t *restrict sem, const struct timespec *restrict timeout) { - struct ddekit_private_data *self_private_data; + struct _ddekit_private_data *self_private_data; spin_lock (&sem->lock); if (sem->value > 0) { /* Successful down. */ sem->value --; - spin_unlock (&sem->__lock); + spin_unlock (&sem->lock); return 0; } @@ -350,13 +362,14 @@ ddekit_sem_t *ddekit_sem_init(int value) { (ddekit_sem_t *) ddekit_simple_malloc (sizeof (*sem)); sem->lock = SPIN_LOCK_INITIALIZER; - sem->head = {&sem->head, &sem->head}; + sem->head.prev = &sem->head; + sem->head.next = &sem->head; sem->value = value; return sem; } void ddekit_sem_deinit(ddekit_sem_t *sem) { - if (!EMPTY_ENTRY (&sem->head)) { + if (!EMPTY_LIST (&sem->head)) { error (0, EBUSY, "ddekit_sem_deinit"); } else @@ -388,11 +401,11 @@ int ddekit_sem_down_timed(ddekit_sem_t *sem, int timo) { timeout.tv_sec = timo / 1000; timeout.tv_nsec = (timo % 1000) * 1000 * 1000; - return __sem_timedwait_internal (sem, &timeout); + return _sem_timedwait_internal (sem, &timeout); } void ddekit_sem_up(ddekit_sem_t *sem) { - struct _ddekit_thread_data *wakeup; + struct _ddekit_private_data *wakeup; spin_lock (&sem->lock); if (sem->value > 0) { @@ -400,26 +413,25 @@ void ddekit_sem_up(ddekit_sem_t *sem) { assert (EMPTY_LIST (&sem->head)); sem->value ++; spin_unlock (&sem->lock); - return 0; + return; } if (EMPTY_LIST (&sem->head)) { /* No one waiting. */ sem->value = 1; spin_unlock (&sem->lock); - return 0; + return; } /* Wake someone up. */ /* First dequeue someone. */ - wakeup = (struct _ddekit_private_data *) remove_entry_end (&sem->head); + wakeup = LIST_ENTRY (remove_entry_end (&sem->head), + struct _ddekit_private_data, list); /* Then drop the lock and transfer control. */ spin_unlock (&sem->lock); if (wakeup) _thread_wakeup (wakeup); - - return 0; } diff --git a/libddekit/timer.c b/libddekit/timer.c index d0a6ccc0..f8bfc7a1 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -2,6 +2,9 @@ #include #include +#include "ddekit/memory.h" +#include "ddekit/assert.h" +#include "ddekit/semaphore.h" #include "ddekit/timer.h" #define __DEBUG 0 @@ -118,7 +121,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) * necessary to notify the timer thread. */ if (t == timer_list) { - Assert(!l4_is_nil_id(timer_thread)); + Assert(timer_thread); __notify_timer_thread(); } @@ -329,6 +332,6 @@ void ddekit_init_timers(void) root_jiffies = (long long) tp.tv_sec * HZ + ((long long) tp.tv_usec * HZ) / 1000000; - timer_thread = cthread_fork ((cthread_fn_t) timer_function, 0); + timer_thread = cthread_fork ((cthread_fn_t) ddekit_timer_thread, 0); cthread_detach (timer_thread); } diff --git a/libddekit/vm_param.h b/libddekit/vm_param.h new file mode 100644 index 00000000..7b615c8a --- /dev/null +++ b/libddekit/vm_param.h @@ -0,0 +1,7 @@ +#ifndef __VM_PARAM_H__ +#define __VM_PARAM_H__ + +#define PAGE_SIZE __vm_page_size +#define PAGE_MASK (PAGE_SIZE-1) + +#endif -- cgit v1.2.3 From 974a402ed6a28e7801f3c6202516ef232d73256a Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 19:13:54 +0100 Subject: Redefine HZ. --- libddekit/include/ddekit/timer.h | 1 + libddekit/timer.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index a57c8fce..bb30e1f9 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -4,6 +4,7 @@ #include "ddekit/thread.h" #define jiffies fetch_jiffies() +#define HZ 100 enum { diff --git a/libddekit/timer.c b/libddekit/timer.c index f8bfc7a1..be23ee14 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -19,7 +19,6 @@ long long root_jiffies; * So, if someone schedules a timeout to expire in 2 seconds, * this expires date will be in jiffies + 2 * HZ. */ -extern unsigned long HZ; typedef struct _timer { -- cgit v1.2.3 From 9341952a7cea0d39b871ecdb6ac153fc820524c8 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 7 Dec 2009 02:25:32 +0100 Subject: Make ddekit_simple_malloc/free inline. --- libddekit/Makefile | 2 +- libddekit/include/ddekit/memory.h | 13 +++++++++-- libddekit/malloc.c | 49 --------------------------------------- libddekit/memory.c | 3 +++ 4 files changed, 15 insertions(+), 52 deletions(-) delete mode 100644 libddekit/malloc.c (limited to 'libddekit/include') diff --git a/libddekit/Makefile b/libddekit/Makefile index 018d67c9..f2e52f25 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -19,7 +19,7 @@ dir := libddekit makemode := library libname = libddekit -SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ +SRCS= condvar.c init.c interrupt.c lock.c memory.c \ pci.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ diff --git a/libddekit/include/ddekit/memory.h b/libddekit/include/ddekit/memory.h index 051a4d9e..2c573d8f 100644 --- a/libddekit/include/ddekit/memory.h +++ b/libddekit/include/ddekit/memory.h @@ -123,6 +123,9 @@ void *ddekit_contig_malloc( ** Simple memory allocator ** *****************************/ +#include +#include "ddekit/inline.h" + /** * Allocate memory block via simple allocator * @@ -132,13 +135,19 @@ void *ddekit_contig_malloc( * The blocks allocated via this allocator CANNOT be used for DMA or other * device operations, i.e., there exists no virt->phys mapping. */ -void *ddekit_simple_malloc(unsigned size); +static INLINE void *ddekit_simple_malloc(unsigned size) +{ + return malloc (size); +} /** * Free memory block via simple allocator * * \param p pointer to memory block */ -void ddekit_simple_free(void *p); +static INLINE void ddekit_simple_free(void *p) +{ + free (p); +} #endif diff --git a/libddekit/malloc.c b/libddekit/malloc.c deleted file mode 100644 index a30cd7b7..00000000 --- a/libddekit/malloc.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright (C) 2009 Free Software Foundation, Inc. - Written by Zheng Da. - - This file is part of the GNU Hurd. - - The GNU Hurd is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - The GNU Hurd is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with the GNU Hurd; see the file COPYING. If not, write to - the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - -/** - * Allocate memory block via simple allocator - * - * \param size block size - * \return pointer to new memory block - * - * The blocks allocated via this allocator CANNOT be used for DMA or other - * device operations, i.e., there exists no virt->phys mapping. - * - * Each chunk stores its size in the first word for free() to work. - */ - -#include - -void *ddekit_simple_malloc(unsigned size) -{ - return malloc (size); -} - - -/** - * Free memory block via simple allocator - * - * \param p pointer to memory block - */ -void ddekit_simple_free(void *p) -{ - free (p); -} diff --git a/libddekit/memory.c b/libddekit/memory.c index 1ffb15b0..781a4bae 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -160,6 +160,9 @@ struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) * Free large block of memory * * This is no useful for allocation < page size. + * + * TODO The freed memory can be cached and will be still accessible ( + * no page fault when accessed). I hope it won't caused any troubles. */ void ddekit_large_free(void *objp) { -- cgit v1.2.3 From 3d4eb7565f63ec437a6c74f42cfa092cfb192f16 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 11 Dec 2009 13:52:23 +0100 Subject: Use ddekit lock instead of mutex. --- libddekit/include/ddekit/timer.h | 2 +- libddekit/timer.c | 38 ++++++++++++++++++++++++-------------- 2 files changed, 25 insertions(+), 15 deletions(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index bb30e1f9..c0bea6bf 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -3,7 +3,7 @@ #include "ddekit/thread.h" -#define jiffies fetch_jiffies() +#define jiffies (fetch_jiffies()) #define HZ 100 enum diff --git a/libddekit/timer.c b/libddekit/timer.c index be23ee14..4944be69 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -2,6 +2,7 @@ #include #include +#include "ddekit/lock.h" #include "ddekit/memory.h" #include "ddekit/assert.h" #include "ddekit/semaphore.h" @@ -31,7 +32,7 @@ typedef struct _timer static ddekit_timer_t *timer_list = NULL; ///< list of pending timers -static struct mutex timer_lock = MUTEX_INITIALIZER; ///< lock to access timer_list +static ddekit_lock_t timer_lock; ///< lock to access timer_list static cthread_t timer_thread; ///< the timer thread static ddekit_thread_t *timer_thread_ddekit = NULL; ///< ddekit ID of timer thread static ddekit_sem_t *notify_semaphore = NULL; ///< timer thread's wait semaphore @@ -53,11 +54,13 @@ static void dump_list(char *msg) #endif } -int fetch_jiffies () +long long fetch_jiffies () { struct timeval tv; long long j; + if (mapped_time == NULL) + ddekit_init_timers (); maptime_read (mapped_time, &tv); j = (long long) tv.tv_sec * HZ + ((long long) tv.tv_usec * HZ) / 1000000; @@ -86,6 +89,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) ddekit_timer_t *t = ddekit_simple_malloc(sizeof(ddekit_timer_t)); Assert(t); + printf ("add a timer at %ld\n", timeout); /* fill in values */ t->fn = fn; @@ -93,7 +97,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) t->expires = timeout; t->next = NULL; - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); t->id = timer_id_ctr++; @@ -124,7 +128,7 @@ int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout) __notify_timer_thread(); } - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); dump_list("after add"); @@ -137,7 +141,7 @@ int ddekit_del_timer(int timer) ddekit_timer_t *it, *it_next; int ret = -1; - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); /* no timer? */ if (!timer_list) { @@ -178,7 +182,7 @@ int ddekit_del_timer(int timer) } out: - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); dump_list("after del"); @@ -197,7 +201,7 @@ int ddekit_timer_pending(int timer) ddekit_timer_t *t = NULL; int r = 0; - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); t = timer_list; while (t) { @@ -208,7 +212,7 @@ int ddekit_timer_pending(int timer) t = t->next; } - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); return r; } @@ -224,7 +228,7 @@ static ddekit_timer_t *get_next_timer(void) ddekit_timer_t *t = NULL; /* This function must be called with the timer_lock held. */ - Assert(timer_lock.holder == timer_thread); + Assert(ddekit_lock_owner (&timer_lock) == (int) timer_thread); if (timer_list && (timer_list->expires <= jiffies)) { @@ -251,7 +255,7 @@ static inline int __timer_sleep(unsigned to) { int err = 0; - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); if (to == DDEKIT_TIMEOUT_NEVER) { ddekit_sem_down(notify_semaphore); @@ -266,7 +270,7 @@ static inline int __timer_sleep(unsigned to) #endif } - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); return (err ? 1 : 0); } @@ -283,7 +287,7 @@ static void ddekit_timer_thread(void *arg) // l4thread_started(0); - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); while (1) { ddekit_timer_t *timer = NULL; unsigned long to = DDEKIT_TIMEOUT_NEVER; @@ -301,11 +305,11 @@ static void ddekit_timer_thread(void *arg) __timer_sleep(to); while ((timer = get_next_timer()) != NULL) { - mutex_unlock (&timer_lock); + ddekit_lock_unlock (&timer_lock); //ddekit_printf("doing timer fn @ %p\n", timer->fn); timer->fn(timer->args); ddekit_simple_free(timer); - mutex_lock (&timer_lock); + ddekit_lock_lock (&timer_lock); } } // TODO how is the thread terminated? @@ -321,7 +325,12 @@ void ddekit_init_timers(void) { error_t err; struct timeval tp; + static boolean_t initialized = FALSE; + if (initialized) + return; + + initialized = TRUE; err = maptime_map (0, 0, &mapped_time); if (err) error (2, err, "cannot map time device"); @@ -331,6 +340,7 @@ void ddekit_init_timers(void) root_jiffies = (long long) tp.tv_sec * HZ + ((long long) tp.tv_usec * HZ) / 1000000; + ddekit_lock_init (&timer_lock); timer_thread = cthread_fork ((cthread_fn_t) ddekit_timer_thread, 0); cthread_detach (timer_thread); } -- cgit v1.2.3 From 0ea79b053d4a853d7bdd3363ccb6c132b2f7ee5c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 29 Dec 2009 20:48:00 +0100 Subject: Don't include C library headers files in our header files. --- libddekit/Makefile | 2 +- libddekit/c_headers.h | 7 ++++++ libddekit/include/ddekit/memory.h | 13 ++--------- libddekit/include/ddekit/panic.h | 2 +- libddekit/include/ddekit/printf.h | 2 +- libddekit/malloc.c | 49 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 61 insertions(+), 14 deletions(-) create mode 100644 libddekit/c_headers.h create mode 100644 libddekit/malloc.c (limited to 'libddekit/include') diff --git a/libddekit/Makefile b/libddekit/Makefile index f2e52f25..018d67c9 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -19,7 +19,7 @@ dir := libddekit makemode := library libname = libddekit -SRCS= condvar.c init.c interrupt.c lock.c memory.c \ +SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ pci.c pgtab.c printf.c resources.c list.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ diff --git a/libddekit/c_headers.h b/libddekit/c_headers.h new file mode 100644 index 00000000..6141e900 --- /dev/null +++ b/libddekit/c_headers.h @@ -0,0 +1,7 @@ +#ifndef __C_HEADERS_H__ +#define __C_HEADERS_H__ + +#include +#include + +#endif diff --git a/libddekit/include/ddekit/memory.h b/libddekit/include/ddekit/memory.h index 2c573d8f..051a4d9e 100644 --- a/libddekit/include/ddekit/memory.h +++ b/libddekit/include/ddekit/memory.h @@ -123,9 +123,6 @@ void *ddekit_contig_malloc( ** Simple memory allocator ** *****************************/ -#include -#include "ddekit/inline.h" - /** * Allocate memory block via simple allocator * @@ -135,19 +132,13 @@ void *ddekit_contig_malloc( * The blocks allocated via this allocator CANNOT be used for DMA or other * device operations, i.e., there exists no virt->phys mapping. */ -static INLINE void *ddekit_simple_malloc(unsigned size) -{ - return malloc (size); -} +void *ddekit_simple_malloc(unsigned size); /** * Free memory block via simple allocator * * \param p pointer to memory block */ -static INLINE void ddekit_simple_free(void *p) -{ - free (p); -} +void ddekit_simple_free(void *p); #endif diff --git a/libddekit/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h index 11c46ebb..f036ab3e 100644 --- a/libddekit/include/ddekit/panic.h +++ b/libddekit/include/ddekit/panic.h @@ -3,7 +3,7 @@ /** \defgroup DDEKit_util */ -#include +#include "c_headers.h" /** Panic - print error message and enter the kernel debugger. * \ingroup DDEKit_util diff --git a/libddekit/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h index 35b0dfa1..aa086c71 100644 --- a/libddekit/include/ddekit/printf.h +++ b/libddekit/include/ddekit/printf.h @@ -1,7 +1,7 @@ #ifndef _ddekit_print_h #define _ddekit_print_h -#include +#include "c_headers.h" /** Print message. * \ingroup DDEKit_util diff --git a/libddekit/malloc.c b/libddekit/malloc.c new file mode 100644 index 00000000..a30cd7b7 --- /dev/null +++ b/libddekit/malloc.c @@ -0,0 +1,49 @@ +/* + Copyright (C) 2009 Free Software Foundation, Inc. + Written by Zheng Da. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + The GNU Hurd is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the GNU Hurd; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/** + * Allocate memory block via simple allocator + * + * \param size block size + * \return pointer to new memory block + * + * The blocks allocated via this allocator CANNOT be used for DMA or other + * device operations, i.e., there exists no virt->phys mapping. + * + * Each chunk stores its size in the first word for free() to work. + */ + +#include + +void *ddekit_simple_malloc(unsigned size) +{ + return malloc (size); +} + + +/** + * Free memory block via simple allocator + * + * \param p pointer to memory block + */ +void ddekit_simple_free(void *p) +{ + free (p); +} -- cgit v1.2.3 From 7460caca37c30536b7b507d141cf5b7c51697cf3 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 1 Jan 2010 14:54:28 +0100 Subject: Remove c_headers.h --- libddekit/Makefile | 2 +- libddekit/c_headers.h | 7 ------- libddekit/include/ddekit/panic.h | 19 ++----------------- libddekit/include/ddekit/printf.h | 2 +- libddekit/memory.c | 2 ++ libddekit/timer.c | 1 + 6 files changed, 7 insertions(+), 26 deletions(-) delete mode 100644 libddekit/c_headers.h (limited to 'libddekit/include') diff --git a/libddekit/Makefile b/libddekit/Makefile index 018d67c9..4d5d58fa 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -20,7 +20,7 @@ makemode := library libname = libddekit SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ - pci.c pgtab.c printf.c resources.c list.c \ + pci.c pgtab.c printf.c resources.c list.c panic.c \ thread.c timer.c kmem.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/semaphore.h include/ddekit/debug.h \ diff --git a/libddekit/c_headers.h b/libddekit/c_headers.h deleted file mode 100644 index 6141e900..00000000 --- a/libddekit/c_headers.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __C_HEADERS_H__ -#define __C_HEADERS_H__ - -#include -#include - -#endif diff --git a/libddekit/include/ddekit/panic.h b/libddekit/include/ddekit/panic.h index f036ab3e..1468675f 100644 --- a/libddekit/include/ddekit/panic.h +++ b/libddekit/include/ddekit/panic.h @@ -3,29 +3,14 @@ /** \defgroup DDEKit_util */ -#include "c_headers.h" - /** Panic - print error message and enter the kernel debugger. * \ingroup DDEKit_util */ -#define ddekit_panic(format, ...) do \ -{ \ - char buf[1024]; \ - snprintf (buf, 1024, "%s", format); \ - fprintf (stderr , buf, ## __VA_ARGS__); \ - fflush (stderr); \ - abort (); \ -} while (0) +void ddekit_panic(char *fmt, ...) __attribute__((noreturn)); /** Print a debug message. * \ingroup DDEKit_util */ -#define ddekit_debug(format, ...) do \ -{ \ - char buf[1024]; \ - snprintf (buf, 1024, "%s: %s\n", __func__, format); \ - fprintf (stderr , buf, ## __VA_ARGS__); \ - fflush (stderr); \ -} while (0) +void ddekit_debug(char *fmt, ...); #endif diff --git a/libddekit/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h index aa086c71..35b0dfa1 100644 --- a/libddekit/include/ddekit/printf.h +++ b/libddekit/include/ddekit/printf.h @@ -1,7 +1,7 @@ #ifndef _ddekit_print_h #define _ddekit_print_h -#include "c_headers.h" +#include /** Print message. * \ingroup DDEKit_util diff --git a/libddekit/memory.c b/libddekit/memory.c index 781a4bae..69088c2a 100644 --- a/libddekit/memory.c +++ b/libddekit/memory.c @@ -10,6 +10,8 @@ * FIXME check thread-safety and add locks where appropriate */ +#include + #include "ddekit/memory.h" #include "ddekit/panic.h" diff --git a/libddekit/timer.c b/libddekit/timer.c index 4944be69..ea66e5f5 100644 --- a/libddekit/timer.c +++ b/libddekit/timer.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "ddekit/lock.h" #include "ddekit/memory.h" -- cgit v1.2.3 From f3b3a2ca7ee85517888940a35e652325fa38293f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 5 Jan 2010 16:07:54 +0100 Subject: Declare fetch_jiffies in the header file. --- libddekit/include/ddekit/timer.h | 1 + 1 file changed, 1 insertion(+) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index c0bea6bf..435ba8aa 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -54,5 +54,6 @@ void ddekit_init_timers(void); /** Get the timer thread. */ ddekit_thread_t *ddekit_get_timer_thread(void); +extern long long fetch_jiffies (void); #endif -- cgit v1.2.3 From 76ab4925b163ee5bf6594c79be063662e2157d00 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 19 Jan 2010 11:21:27 +0100 Subject: Add initcall in ddekit. --- libddekit/Makefile | 2 +- libddekit/include/ddekit/initcall.h | 42 +++++++++++++++++++++++++++++++++++++ libddekit/initcall.c | 27 ++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 libddekit/include/ddekit/initcall.h create mode 100644 libddekit/initcall.c (limited to 'libddekit/include') diff --git a/libddekit/Makefile b/libddekit/Makefile index 4d5d58fa..958e67d3 100644 --- a/libddekit/Makefile +++ b/libddekit/Makefile @@ -21,7 +21,7 @@ makemode := library libname = libddekit SRCS= condvar.c init.c interrupt.c lock.c malloc.c memory.c \ pci.c pgtab.c printf.c resources.c list.c panic.c \ - thread.c timer.c kmem.c + thread.c timer.c kmem.c initcall.c LCLHDRS = include/ddekit/condvar.h include/ddekit/lock.h \ include/ddekit/semaphore.h include/ddekit/debug.h \ include/ddekit/inline.h include/ddekit/panic.h \ diff --git a/libddekit/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h new file mode 100644 index 00000000..b503cc6a --- /dev/null +++ b/libddekit/include/ddekit/initcall.h @@ -0,0 +1,42 @@ +#ifndef _ddekit_initcall_h +#define _ddekit_initcall_h + +// from l4/sys/compiler.h +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4 +#define L4_STICKY(x) __attribute__((used)) x +#else +#define L4_STICKY(x) __attribute__((unused)) x +#endif + +#define l4str(s) #s + +// from dde_linux/ARCH-x86/ctor.h +typedef void (*l4ddekit_initcall_t)(void); + +#define __l4ddekit_initcall(p) \ + __attribute__ ((__section__ (".l4dde_ctors." #p))) + +/** Define a function to be a DDEKit initcall. + * + * Define a function to be a DDEKit initcall. This function will then be placed + * in a separate linker section of the binary (called .l4dde_ctors). The L4Env + * construction mechanism will execute all constructors in this section during + * application startup. + * + * This is the right place to place Linux' module_init functions & Co. + * + * \param fn function + */ +#define DDEKIT_INITCALL(fn) DDEKIT_CTOR(fn, 1) + +#define DDEKIT_CTOR(fn, prio) \ + static l4ddekit_initcall_t \ + L4_STICKY(__l4ddekit_initcall_##fn) \ + __l4ddekit_initcall(prio) = (void *)fn + +/** + * Runs all registered initcalls. + */ +void ddekit_do_initcalls(void); + +#endif diff --git a/libddekit/initcall.c b/libddekit/initcall.c new file mode 100644 index 00000000..78c24146 --- /dev/null +++ b/libddekit/initcall.c @@ -0,0 +1,27 @@ +#include + +#define BEG { (crt0_hook) ~1U } +#define END { (crt0_hook) 0 } + +#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || __GNUC__ >= 4 +#define SECTION(x) __attribute__((used, section( x ))) +#else +#define SECTION(x) __attribute__((section( x ))) +#endif + +typedef void (*const crt0_hook)(void); + +static crt0_hook __L4DDE_CTOR_BEG__[1] SECTION(".mark_beg_l4dde_ctors") = BEG; +static crt0_hook __l4DDE_CTOR_END__[1] SECTION(".mark_end_l4dde_ctors") = END; + +void ddekit_do_initcalls() { + crt0_hook *list = __L4DDE_CTOR_BEG__; + + list++; + while (*list) + { + (**list)(); + list++; + } +} + -- cgit v1.2.3 From d31e486426aed7952b3468a63f2e81735d09943c Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 6 Apr 2010 04:33:16 +0200 Subject: implement dump_stack in libddekit with backtrace. --- libdde_linux26/lib/src/arch/l4/process.c | 4 ---- libddekit/include/ddekit/printf.h | 2 ++ libddekit/printf.c | 12 ++++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'libddekit/include') diff --git a/libdde_linux26/lib/src/arch/l4/process.c b/libdde_linux26/lib/src/arch/l4/process.c index b5189cd4..ac700f82 100644 --- a/libdde_linux26/lib/src/arch/l4/process.c +++ b/libdde_linux26/lib/src/arch/l4/process.c @@ -220,10 +220,6 @@ void do_exit(long code) ** Misc functions ** *****************************************************************************/ -void dump_stack(void) -{ -} - char *get_task_comm(char *buf, struct task_struct *tsk) { diff --git a/libddekit/include/ddekit/printf.h b/libddekit/include/ddekit/printf.h index 35b0dfa1..6dafa18d 100644 --- a/libddekit/include/ddekit/printf.h +++ b/libddekit/include/ddekit/printf.h @@ -18,6 +18,8 @@ int ddekit_printf(const char *fmt, ...); */ int ddekit_vprintf(const char *fmt, va_list va); +void dump_stack(void); + /** Log function and message. * \ingroup DDEKit_util */ diff --git a/libddekit/printf.c b/libddekit/printf.c index dacc65e6..c4a8b718 100644 --- a/libddekit/printf.c +++ b/libddekit/printf.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "ddekit/printf.h" @@ -93,3 +94,14 @@ int log_init () return 0; } + +void dump_stack() +{ +#define NUM_TRACES 16 + void *trace[NUM_TRACES]; + int trace_size = 0; + + fprintf (stderr, "dump the stack\n"); + trace_size = backtrace(trace, NUM_TRACES); + backtrace_symbols_fd(trace, trace_size, 2); +} -- cgit v1.2.3 From b168f41d6eab6319bb5a2fcc065541ba2b18926e Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Thu, 22 Apr 2010 15:07:28 +0200 Subject: jiffies in the type of unsigned long. --- libddekit/include/ddekit/timer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/timer.h b/libddekit/include/ddekit/timer.h index 435ba8aa..387f2078 100644 --- a/libddekit/include/ddekit/timer.h +++ b/libddekit/include/ddekit/timer.h @@ -54,6 +54,6 @@ void ddekit_init_timers(void); /** Get the timer thread. */ ddekit_thread_t *ddekit_get_timer_thread(void); -extern long long fetch_jiffies (void); +extern unsigned long fetch_jiffies (void); #endif -- cgit v1.2.3 From 13e0bf0fc4959a448fe8d1f33eb6eac01b4c4e06 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 9 Jun 2010 13:49:20 +0200 Subject: make __l4ddekit_initcall_* variables global. --- libddekit/include/ddekit/initcall.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libddekit/include') diff --git a/libddekit/include/ddekit/initcall.h b/libddekit/include/ddekit/initcall.h index b503cc6a..6befa31c 100644 --- a/libddekit/include/ddekit/initcall.h +++ b/libddekit/include/ddekit/initcall.h @@ -30,7 +30,7 @@ typedef void (*l4ddekit_initcall_t)(void); #define DDEKIT_INITCALL(fn) DDEKIT_CTOR(fn, 1) #define DDEKIT_CTOR(fn, prio) \ - static l4ddekit_initcall_t \ + l4ddekit_initcall_t \ L4_STICKY(__l4ddekit_initcall_##fn) \ __l4ddekit_initcall(prio) = (void *)fn -- cgit v1.2.3 From 9cd3c840876b1f3ea79ab810a5b00d9931749631 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 15 Jun 2010 16:20:24 +0200 Subject: implement get_random_bytes() with random() in libc --- libdde_linux26/contrib/drivers/char/random.c | 1691 ------------------------- libdde_linux26/lib/src/Makefile | 3 +- libdde_linux26/lib/src/drivers/char/random.c | 1709 ++++++++++++++++++++++++++ libddekit/include/ddekit/resources.h | 1 + libddekit/resources.c | 6 + 5 files changed, 1718 insertions(+), 1692 deletions(-) delete mode 100644 libdde_linux26/contrib/drivers/char/random.c create mode 100644 libdde_linux26/lib/src/drivers/char/random.c (limited to 'libddekit/include') diff --git a/libdde_linux26/contrib/drivers/char/random.c b/libdde_linux26/contrib/drivers/char/random.c deleted file mode 100644 index 7c13581c..00000000 --- a/libdde_linux26/contrib/drivers/char/random.c +++ /dev/null @@ -1,1691 +0,0 @@ -/* - * random.c -- A strong random number generator - * - * Copyright Matt Mackall , 2003, 2004, 2005 - * - * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. 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, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 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. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -/* - * (now, with legal B.S. out of the way.....) - * - * This routine gathers environmental noise from device drivers, etc., - * and returns good random numbers, suitable for cryptographic use. - * Besides the obvious cryptographic uses, these numbers are also good - * for seeding TCP sequence numbers, and other places where it is - * desirable to have numbers which are not only random, but hard to - * predict by an attacker. - * - * Theory of operation - * =================== - * - * Computers are very predictable devices. Hence it is extremely hard - * to produce truly random numbers on a computer --- as opposed to - * pseudo-random numbers, which can easily generated by using a - * algorithm. Unfortunately, it is very easy for attackers to guess - * the sequence of pseudo-random number generators, and for some - * applications this is not acceptable. So instead, we must try to - * gather "environmental noise" from the computer's environment, which - * must be hard for outside attackers to observe, and use that to - * generate random numbers. In a Unix environment, this is best done - * from inside the kernel. - * - * Sources of randomness from the environment include inter-keyboard - * timings, inter-interrupt timings from some interrupts, and other - * events which are both (a) non-deterministic and (b) hard for an - * outside observer to measure. Randomness from these sources are - * added to an "entropy pool", which is mixed using a CRC-like function. - * This is not cryptographically strong, but it is adequate assuming - * the randomness is not chosen maliciously, and it is fast enough that - * the overhead of doing it on every interrupt is very reasonable. - * As random bytes are mixed into the entropy pool, the routines keep - * an *estimate* of how many bits of randomness have been stored into - * the random number generator's internal state. - * - * When random bytes are desired, they are obtained by taking the SHA - * hash of the contents of the "entropy pool". The SHA hash avoids - * exposing the internal state of the entropy pool. It is believed to - * be computationally infeasible to derive any useful information - * about the input of SHA from its output. Even if it is possible to - * analyze SHA in some clever way, as long as the amount of data - * returned from the generator is less than the inherent entropy in - * the pool, the output data is totally unpredictable. For this - * reason, the routine decreases its internal estimate of how many - * bits of "true randomness" are contained in the entropy pool as it - * outputs random numbers. - * - * If this estimate goes to zero, the routine can still generate - * random numbers; however, an attacker may (at least in theory) be - * able to infer the future output of the generator from prior - * outputs. This requires successful cryptanalysis of SHA, which is - * not believed to be feasible, but there is a remote possibility. - * Nonetheless, these numbers should be useful for the vast majority - * of purposes. - * - * Exported interfaces ---- output - * =============================== - * - * There are three exported interfaces; the first is one designed to - * be used from within the kernel: - * - * void get_random_bytes(void *buf, int nbytes); - * - * This interface will return the requested number of random bytes, - * and place it in the requested buffer. - * - * The two other interfaces are two character devices /dev/random and - * /dev/urandom. /dev/random is suitable for use when very high - * quality randomness is desired (for example, for key generation or - * one-time pads), as it will only return a maximum of the number of - * bits of randomness (as estimated by the random number generator) - * contained in the entropy pool. - * - * The /dev/urandom device does not have this limit, and will return - * as many bytes as are requested. As more and more random bytes are - * requested without giving time for the entropy pool to recharge, - * this will result in random numbers that are merely cryptographically - * strong. For many applications, however, this is acceptable. - * - * Exported interfaces ---- input - * ============================== - * - * The current exported interfaces for gathering environmental noise - * from the devices are: - * - * void add_input_randomness(unsigned int type, unsigned int code, - * unsigned int value); - * void add_interrupt_randomness(int irq); - * - * add_input_randomness() uses the input layer interrupt timing, as well as - * the event type information from the hardware. - * - * add_interrupt_randomness() uses the inter-interrupt timing as random - * inputs to the entropy pool. Note that not all interrupts are good - * sources of randomness! For example, the timer interrupts is not a - * good choice, because the periodicity of the interrupts is too - * regular, and hence predictable to an attacker. Disk interrupts are - * a better measure, since the timing of the disk interrupts are more - * unpredictable. - * - * All of these routines try to estimate how many bits of randomness a - * particular randomness source. They do this by keeping track of the - * first and second order deltas of the event timings. - * - * Ensuring unpredictability at system startup - * ============================================ - * - * When any operating system starts up, it will go through a sequence - * of actions that are fairly predictable by an adversary, especially - * if the start-up does not involve interaction with a human operator. - * This reduces the actual number of bits of unpredictability in the - * entropy pool below the value in entropy_count. In order to - * counteract this effect, it helps to carry information in the - * entropy pool across shut-downs and start-ups. To do this, put the - * following lines an appropriate script which is run during the boot - * sequence: - * - * echo "Initializing random number generator..." - * random_seed=/var/run/random-seed - * # Carry a random seed from start-up to start-up - * # Load and then save the whole entropy pool - * if [ -f $random_seed ]; then - * cat $random_seed >/dev/urandom - * else - * touch $random_seed - * fi - * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=512 - * - * and the following lines in an appropriate script which is run as - * the system is shutdown: - * - * # Carry a random seed from shut-down to start-up - * # Save the whole entropy pool - * echo "Saving random seed..." - * random_seed=/var/run/random-seed - * touch $random_seed - * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=512 - * - * For example, on most modern systems using the System V init - * scripts, such code fragments would be found in - * /etc/rc.d/init.d/random. On older Linux systems, the correct script - * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0. - * - * Effectively, these commands cause the contents of the entropy pool - * to be saved at shut-down time and reloaded into the entropy pool at - * start-up. (The 'dd' in the addition to the bootup script is to - * make sure that /etc/random-seed is different for every start-up, - * even if the system crashes without executing rc.0.) Even with - * complete knowledge of the start-up activities, predicting the state - * of the entropy pool requires knowledge of the previous history of - * the system. - * - * Configuring the /dev/random driver under Linux - * ============================================== - * - * The /dev/random driver under Linux uses minor numbers 8 and 9 of - * the /dev/mem major number (#1). So if your system does not have - * /dev/random and /dev/urandom created already, they can be created - * by using the commands: - * - * mknod /dev/random c 1 8 - * mknod /dev/urandom c 1 9 - * - * Acknowledgements: - * ================= - * - * Ideas for constructing this random number generator were derived - * from Pretty Good Privacy's random number generator, and from private - * discussions with Phil Karn. Colin Plumb provided a faster random - * number generator, which speed up the mixing function of the entropy - * pool, taken from PGPfone. Dale Worley has also contributed many - * useful ideas and suggestions to improve this driver. - * - * Any flaws in the design are solely my responsibility, and should - * not be attributed to the Phil, Colin, or any of authors of PGP. - * - * Further background information on this topic may be obtained from - * RFC 1750, "Randomness Recommendations for Security", by Donald - * Eastlake, Steve Crocker, and Jeff Schiller. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * Configuration information - */ -#define INPUT_POOL_WORDS 128 -#define OUTPUT_POOL_WORDS 32 -#define SEC_XFER_SIZE 512 - -/* - * The minimum number of bits of entropy before we wake up a read on - * /dev/random. Should be enough to do a significant reseed. - */ -static int random_read_wakeup_thresh = 64; - -/* - * If the entropy count falls under this number of bits, then we - * should wake up processes which are selecting or polling on write - * access to /dev/random. - */ -static int random_write_wakeup_thresh = 128; - -/* - * When the input pool goes over trickle_thresh, start dropping most - * samples to avoid wasting CPU time and reduce lock contention. - */ - -static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; - -static DEFINE_PER_CPU(int, trickle_count); - -/* - * A pool of size .poolwords is stirred with a primitive polynomial - * of degree .poolwords over GF(2). The taps for various sizes are - * defined below. They are chosen to be evenly spaced (minimum RMS - * distance from evenly spaced; the numbers in the comments are a - * scaled squared error sum) except for the last tap, which is 1 to - * get the twisting happening as fast as possible. - */ -static struct poolinfo { - int poolwords; - int tap1, tap2, tap3, tap4, tap5; -} poolinfo_table[] = { - /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ - { 128, 103, 76, 51, 25, 1 }, - /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ - { 32, 26, 20, 14, 7, 1 }, -#if 0 - /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ - { 2048, 1638, 1231, 819, 411, 1 }, - - /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ - { 1024, 817, 615, 412, 204, 1 }, - - /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ - { 1024, 819, 616, 410, 207, 2 }, - - /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ - { 512, 411, 308, 208, 104, 1 }, - - /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ - { 512, 409, 307, 206, 102, 2 }, - /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ - { 512, 409, 309, 205, 103, 2 }, - - /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ - { 256, 205, 155, 101, 52, 1 }, - - /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ - { 128, 103, 78, 51, 27, 2 }, - - /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ - { 64, 52, 39, 26, 14, 1 }, -#endif -}; - -#define POOLBITS poolwords*32 -#define POOLBYTES poolwords*4 - -/* - * For the purposes of better mixing, we use the CRC-32 polynomial as - * well to make a twisted Generalized Feedback Shift Reigster - * - * (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM - * Transactions on Modeling and Computer Simulation 2(3):179-194. - * Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators - * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) - * - * Thanks to Colin Plumb for suggesting this. - * - * We have not analyzed the resultant polynomial to prove it primitive; - * in fact it almost certainly isn't. Nonetheless, the irreducible factors - * of a random large-degree polynomial over GF(2) are more than large enough - * that periodicity is not a concern. - * - * The input hash is much less sensitive than the output hash. All - * that we want of it is that it be a good non-cryptographic hash; - * i.e. it not produce collisions when fed "random" data of the sort - * we expect to see. As long as the pool state differs for different - * inputs, we have preserved the input entropy and done a good job. - * The fact that an intelligent attacker can construct inputs that - * will produce controlled alterations to the pool's state is not - * important because we don't consider such inputs to contribute any - * randomness. The only property we need with respect to them is that - * the attacker can't increase his/her knowledge of the pool's state. - * Since all additions are reversible (knowing the final state and the - * input, you can reconstruct the initial state), if an attacker has - * any uncertainty about the initial state, he/she can only shuffle - * that uncertainty about, but never cause any collisions (which would - * decrease the uncertainty). - * - * The chosen system lets the state of the pool be (essentially) the input - * modulo the generator polymnomial. Now, for random primitive polynomials, - * this is a universal class of hash functions, meaning that the chance - * of a collision is limited by the attacker's knowledge of the generator - * polynomail, so if it is chosen at random, an attacker can never force - * a collision. Here, we use a fixed polynomial, but we *can* assume that - * ###--> it is unknown to the processes generating the input entropy. <-### - * Because of this important property, this is a good, collision-resistant - * hash; hash collisions will occur no more often than chance. - */ - -/* - * Static global variables - */ -static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); -static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); -static struct fasync_struct *fasync; - -#if 0 -static int debug; -module_param(debug, bool, 0644); -#define DEBUG_ENT(fmt, arg...) do { \ - if (debug) \ - printk(KERN_DEBUG "random %04d %04d %04d: " \ - fmt,\ - input_pool.entropy_count,\ - blocking_pool.entropy_count,\ - nonblocking_pool.entropy_count,\ - ## arg); } while (0) -#else -#define DEBUG_ENT(fmt, arg...) do {} while (0) -#endif - -/********************************************************************** - * - * OS independent entropy store. Here are the functions which handle - * storing entropy in an entropy pool. - * - **********************************************************************/ - -struct entropy_store; -struct entropy_store { - /* read-only data: */ - struct poolinfo *poolinfo; - __u32 *pool; - const char *name; - int limit; - struct entropy_store *pull; - - /* read-write data: */ - spinlock_t lock; - unsigned add_ptr; - int entropy_count; - int input_rotate; -}; - -static __u32 input_pool_data[INPUT_POOL_WORDS]; -static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; -static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; - -static struct entropy_store input_pool = { - .poolinfo = &poolinfo_table[0], - .name = "input", - .limit = 1, - .lock = __SPIN_LOCK_UNLOCKED(&input_pool.lock), - .pool = input_pool_data -}; - -static struct entropy_store blocking_pool = { - .poolinfo = &poolinfo_table[1], - .name = "blocking", - .limit = 1, - .pull = &input_pool, - .lock = __SPIN_LOCK_UNLOCKED(&blocking_pool.lock), - .pool = blocking_pool_data -}; - -static struct entropy_store nonblocking_pool = { - .poolinfo = &poolinfo_table[1], - .name = "nonblocking", - .pull = &input_pool, - .lock = __SPIN_LOCK_UNLOCKED(&nonblocking_pool.lock), - .pool = nonblocking_pool_data -}; - -/* - * This function adds bytes into the entropy "pool". It does not - * update the entropy estimate. The caller should call - * credit_entropy_bits if this is appropriate. - * - * The pool is stirred with a primitive polynomial of the appropriate - * degree, and then twisted. We twist by three bits at a time because - * it's cheap to do so and helps slightly in the expected case where - * the entropy is concentrated in the low-order bits. - */ -static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, - int nbytes, __u8 out[64]) -{ - static __u32 const twist_table[8] = { - 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, - 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - unsigned long i, j, tap1, tap2, tap3, tap4, tap5; - int input_rotate; - int wordmask = r->poolinfo->poolwords - 1; - const char *bytes = in; - __u32 w; - unsigned long flags; - - /* Taps are constant, so we can load them without holding r->lock. */ - tap1 = r->poolinfo->tap1; - tap2 = r->poolinfo->tap2; - tap3 = r->poolinfo->tap3; - tap4 = r->poolinfo->tap4; - tap5 = r->poolinfo->tap5; - - spin_lock_irqsave(&r->lock, flags); - input_rotate = r->input_rotate; - i = r->add_ptr; - - /* mix one byte at a time to simplify size handling and churn faster */ - while (nbytes--) { - w = rol32(*bytes++, input_rotate & 31); - i = (i - 1) & wordmask; - - /* XOR in the various taps */ - w ^= r->pool[i]; - w ^= r->pool[(i + tap1) & wordmask]; - w ^= r->pool[(i + tap2) & wordmask]; - w ^= r->pool[(i + tap3) & wordmask]; - w ^= r->pool[(i + tap4) & wordmask]; - w ^= r->pool[(i + tap5) & wordmask]; - - /* Mix the result back in with a twist */ - r->pool[i] = (w >> 3) ^ twist_table[w & 7]; - - /* - * Normally, we add 7 bits of rotation to the pool. - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - input_rotate += i ? 7 : 14; - } - - r->input_rotate = input_rotate; - r->add_ptr = i; - - if (out) - for (j = 0; j < 16; j++) - ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; - - spin_unlock_irqrestore(&r->lock, flags); -} - -static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) -{ - mix_pool_bytes_extract(r, in, bytes, NULL); -} - -/* - * Credit (or debit) the entropy store with n bits of entropy - */ -static void credit_entropy_bits(struct entropy_store *r, int nbits) -{ - unsigned long flags; - int entropy_count; - - if (!nbits) - return; - - spin_lock_irqsave(&r->lock, flags); - - DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); - entropy_count = r->entropy_count; - entropy_count += nbits; - if (entropy_count < 0) { - DEBUG_ENT("negative entropy/overflow\n"); - entropy_count = 0; - } else if (entropy_count > r->poolinfo->POOLBITS) - entropy_count = r->poolinfo->POOLBITS; - r->entropy_count = entropy_count; - - /* should we wake readers? */ - if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { - wake_up_interruptible(&random_read_wait); - kill_fasync(&fasync, SIGIO, POLL_IN); - } - spin_unlock_irqrestore(&r->lock, flags); -} - -/********************************************************************* - * - * Entropy input management - * - *********************************************************************/ - -/* There is one of these per entropy source */ -struct timer_rand_state { - cycles_t last_time; - long last_delta, last_delta2; - unsigned dont_count_entropy:1; -}; - -#ifndef CONFIG_SPARSE_IRQ - -static struct timer_rand_state *irq_timer_state[NR_IRQS]; - -static struct timer_rand_state *get_timer_rand_state(unsigned int irq) -{ - return irq_timer_state[irq]; -} - -static void set_timer_rand_state(unsigned int irq, - struct timer_rand_state *state) -{ - irq_timer_state[irq] = state; -} - -#else - -static struct timer_rand_state *get_timer_rand_state(unsigned int irq) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - return desc->timer_rand_state; -} - -static void set_timer_rand_state(unsigned int irq, - struct timer_rand_state *state) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - - desc->timer_rand_state = state; -} -#endif - -static struct timer_rand_state input_timer_state; - -/* - * This function adds entropy to the entropy "pool" by using timing - * delays. It uses the timer_rand_state structure to make an estimate - * of how many bits of entropy this call has added to the pool. - * - * The number "num" is also added to the pool - it should somehow describe - * the type of event which just happened. This is currently 0-255 for - * keyboard scan codes, and 256 upwards for interrupts. - * - */ -static void add_timer_randomness(struct timer_rand_state *state, unsigned num) -{ - struct { - cycles_t cycles; - long jiffies; - unsigned num; - } sample; - long delta, delta2, delta3; - - preempt_disable(); - /* if over the trickle threshold, use only 1 in 4096 samples */ - if (input_pool.entropy_count > trickle_thresh && - (__get_cpu_var(trickle_count)++ & 0xfff)) - goto out; - - sample.jiffies = jiffies; - sample.cycles = get_cycles(); - sample.num = num; - mix_pool_bytes(&input_pool, &sample, sizeof(sample)); - - /* - * Calculate number of bits of randomness we probably added. - * We take into account the first, second and third-order deltas - * in order to make our estimate. - */ - - if (!state->dont_count_entropy) { - delta = sample.jiffies - state->last_time; - state->last_time = sample.jiffies; - - delta2 = delta - state->last_delta; - state->last_delta = delta; - - delta3 = delta2 - state->last_delta2; - state->last_delta2 = delta2; - - if (delta < 0) - delta = -delta; - if (delta2 < 0) - delta2 = -delta2; - if (delta3 < 0) - delta3 = -delta3; - if (delta > delta2) - delta = delta2; - if (delta > delta3) - delta = delta3; - - /* - * delta is now minimum absolute delta. - * Round down by 1 bit on general principles, - * and limit entropy entimate to 12 bits. - */ - credit_entropy_bits(&input_pool, - min_t(int, fls(delta>>1), 11)); - } -out: - preempt_enable(); -} - -void add_input_randomness(unsigned int type, unsigned int code, - unsigned int value) -{ - static unsigned char last_value; - - /* ignore autorepeat and the like */ - if (value == last_value) - return; - - DEBUG_ENT("input event\n"); - last_value = value; - add_timer_randomness(&input_timer_state, - (type << 4) ^ code ^ (code >> 4) ^ value); -} -EXPORT_SYMBOL_GPL(add_input_randomness); - -void add_interrupt_randomness(int irq) -{ - struct timer_rand_state *state; - - state = get_timer_rand_state(irq); - - if (state == NULL) - return; - - DEBUG_ENT("irq event %d\n", irq); - add_timer_randomness(state, 0x100 + irq); -} - -#ifdef CONFIG_BLOCK -void add_disk_randomness(struct gendisk *disk) -{ - if (!disk || !disk->random) - return; - /* first major is 1, so we get >= 0x200 here */ - DEBUG_ENT("disk event %d:%d\n", - MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); - - add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); -} -#endif - -#define EXTRACT_SIZE 10 - -/********************************************************************* - * - * Entropy extraction routines - * - *********************************************************************/ - -static ssize_t extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int min, int rsvd); - -/* - * This utility inline function is responsible for transfering entropy - * from the primary pool to the secondary extraction pool. We make - * sure we pull enough for a 'catastrophic reseed'. - */ -static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) -{ - __u32 tmp[OUTPUT_POOL_WORDS]; - - if (r->pull && r->entropy_count < nbytes * 8 && - r->entropy_count < r->poolinfo->POOLBITS) { - /* If we're limited, always leave two wakeup worth's BITS */ - int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; - int bytes = nbytes; - - /* pull at least as many as BYTES as wakeup BITS */ - bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); - /* but never more than the buffer size */ - bytes = min_t(int, bytes, sizeof(tmp)); - - DEBUG_ENT("going to reseed %s with %d bits " - "(%d of %d requested)\n", - r->name, bytes * 8, nbytes * 8, r->entropy_count); - - bytes = extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_thresh / 8, rsvd); - mix_pool_bytes(r, tmp, bytes); - credit_entropy_bits(r, bytes*8); - } -} - -/* - * These functions extracts randomness from the "entropy pool", and - * returns it in a buffer. - * - * The min parameter specifies the minimum amount we can pull before - * failing to avoid races that defeat catastrophic reseeding while the - * reserved parameter indicates how much entropy we must leave in the - * pool after each pull to avoid starving other readers. - * - * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. - */ - -static size_t account(struct entropy_store *r, size_t nbytes, int min, - int reserved) -{ - unsigned long flags; - - /* Hold lock while accounting */ - spin_lock_irqsave(&r->lock, flags); - - BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); - DEBUG_ENT("trying to extract %d bits from %s\n", - nbytes * 8, r->name); - - /* Can we pull enough? */ - if (r->entropy_count / 8 < min + reserved) { - nbytes = 0; - } else { - /* If limited, never pull more than available */ - if (r->limit && nbytes + reserved >= r->entropy_count / 8) - nbytes = r->entropy_count/8 - reserved; - - if (r->entropy_count / 8 >= nbytes + reserved) - r->entropy_count -= nbytes*8; - else - r->entropy_count = reserved; - - if (r->entropy_count < random_write_wakeup_thresh) { - wake_up_interruptible(&random_write_wait); - kill_fasync(&fasync, SIGIO, POLL_OUT); - } - } - - DEBUG_ENT("debiting %d entropy credits from %s%s\n", - nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); - - spin_unlock_irqrestore(&r->lock, flags); - - return nbytes; -} - -static void extract_buf(struct entropy_store *r, __u8 *out) -{ - int i; - __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; - __u8 extract[64]; - - /* Generate a hash across the pool, 16 words (512 bits) at a time */ - sha_init(hash); - for (i = 0; i < r->poolinfo->poolwords; i += 16) - sha_transform(hash, (__u8 *)(r->pool + i), workspace); - - /* - * We mix the hash back into the pool to prevent backtracking - * attacks (where the attacker knows the state of the pool - * plus the current outputs, and attempts to find previous - * ouputs), unless the hash function can be inverted. By - * mixing at least a SHA1 worth of hash data back, we make - * brute-forcing the feedback as hard as brute-forcing the - * hash. - */ - mix_pool_bytes_extract(r, hash, sizeof(hash), extract); - - /* - * To avoid duplicates, we atomically extract a portion of the - * pool while mixing, and hash one final time. - */ - sha_transform(hash, extract, workspace); - memset(extract, 0, sizeof(extract)); - memset(workspace, 0, sizeof(workspace)); - - /* - * In case the hash function has some recognizable output - * pattern, we fold it in half. Thus, we always feed back - * twice as much data as we output. - */ - hash[0] ^= hash[3]; - hash[1] ^= hash[4]; - hash[2] ^= rol32(hash[2], 16); - memcpy(out, hash, EXTRACT_SIZE); - memset(hash, 0, sizeof(hash)); -} - -static ssize_t extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int min, int reserved) -{ - ssize_t ret = 0, i; - __u8 tmp[EXTRACT_SIZE]; - - xfer_secondary_pool(r, nbytes); - nbytes = account(r, nbytes, min, reserved); - - while (nbytes) { - extract_buf(r, tmp); - i = min_t(int, nbytes, EXTRACT_SIZE); - memcpy(buf, tmp, i); - nbytes -= i; - buf += i; - ret += i; - } - - /* Wipe data just returned from memory */ - memset(tmp, 0, sizeof(tmp)); - - return ret; -} - -static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, - size_t nbytes) -{ - ssize_t ret = 0, i; - __u8 tmp[EXTRACT_SIZE]; - - xfer_secondary_pool(r, nbytes); - nbytes = account(r, nbytes, 0, 0); - - while (nbytes) { - if (need_resched()) { - if (signal_pending(current)) { - if (ret == 0) - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - extract_buf(r, tmp); - i = min_t(int, nbytes, EXTRACT_SIZE); - if (copy_to_user(buf, tmp, i)) { - ret = -EFAULT; - break; - } - - nbytes -= i; - buf += i; - ret += i; - } - - /* Wipe data just returned from memory */ - memset(tmp, 0, sizeof(tmp)); - - return ret; -} - -/* - * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for seeding TCP sequence - * numbers, etc. - */ -void get_random_bytes(void *buf, int nbytes) -{ - extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); -} -EXPORT_SYMBOL(get_random_bytes); - -/* - * init_std_data - initialize pool with system data - * - * @r: pool to initialize - * - * This function clears the pool's entropy count and mixes some system - * data into the pool to prepare it for use. The pool is not cleared - * as that can only decrease the entropy in the pool. - */ -static void init_std_data(struct entropy_store *r) -{ - ktime_t now; - unsigned long flags; - - spin_lock_irqsave(&r->lock, flags); - r->entropy_count = 0; - spin_unlock_irqrestore(&r->lock, flags); - - now = ktime_get_real(); - mix_pool_bytes(r, &now, sizeof(now)); - mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); -} - -static int rand_initialize(void) -{ - init_std_data(&input_pool); - init_std_data(&blocking_pool); - init_std_data(&nonblocking_pool); - return 0; -} -module_init(rand_initialize); - -void rand_initialize_irq(int irq) -{ - struct timer_rand_state *state; - - state = get_timer_rand_state(irq); - - if (state) - return; - - /* - * If kzalloc returns null, we just won't use that entropy - * source. - */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) - set_timer_rand_state(irq, state); -} - -#ifdef CONFIG_BLOCK -void rand_initialize_disk(struct gendisk *disk) -{ - struct timer_rand_state *state; - - /* - * If kzalloc returns null, we just won't use that entropy - * source. - */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) - disk->random = state; -} -#endif - -static ssize_t -random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) -{ - ssize_t n, retval = 0, count = 0; - - if (nbytes == 0) - return 0; - - while (nbytes > 0) { - n = nbytes; - if (n > SEC_XFER_SIZE) - n = SEC_XFER_SIZE; - - DEBUG_ENT("reading %d bits\n", n*8); - - n = extract_entropy_user(&blocking_pool, buf, n); - - DEBUG_ENT("read got %d bits (%d still needed)\n", - n*8, (nbytes-n)*8); - - if (n == 0) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - - DEBUG_ENT("sleeping?\n"); - - wait_event_interruptible(random_read_wait, - input_pool.entropy_count >= - random_read_wakeup_thresh); - - DEBUG_ENT("awake\n"); - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - - continue; - } - - if (n < 0) { - retval = n; - break; - } - count += n; - buf += n; - nbytes -= n; - break; /* This break makes the device work */ - /* like a named pipe */ - } - - /* - * If we gave the user some bytes, update the access time. - */ - if (count) - file_accessed(file); - - return (count ? count : retval); -} - -static ssize_t -urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) -{ - return extract_entropy_user(&nonblocking_pool, buf, nbytes); -} - -static unsigned int -random_poll(struct file *file, poll_table * wait) -{ - unsigned int mask; - - poll_wait(file, &random_read_wait, wait); - poll_wait(file, &random_write_wait, wait); - mask = 0; - if (input_pool.entropy_count >= random_read_wakeup_thresh) - mask |= POLLIN | POLLRDNORM; - if (input_pool.entropy_count < random_write_wakeup_thresh) - mask |= POLLOUT | POLLWRNORM; - return mask; -} - -static int -write_pool(struct entropy_store *r, const char __user *buffer, size_t count) -{ - size_t bytes; - __u32 buf[16]; - const char __user *p = buffer; - - while (count > 0) { - bytes = min(count, sizeof(buf)); - if (copy_from_user(&buf, p, bytes)) - return -EFAULT; - - count -= bytes; - p += bytes; - - mix_pool_bytes(r, buf, bytes); - cond_resched(); - } - - return 0; -} - -static ssize_t random_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - size_t ret; - struct inode *inode = file->f_path.dentry->d_inode; - - ret = write_pool(&blocking_pool, buffer, count); - if (ret) - return ret; - ret = write_pool(&nonblocking_pool, buffer, count); - if (ret) - return ret; - - inode->i_mtime = current_fs_time(inode->i_sb); - mark_inode_dirty(inode); - return (ssize_t)count; -} - -static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - int size, ent_count; - int __user *p = (int __user *)arg; - int retval; - - switch (cmd) { - case RNDGETENTCNT: - /* inherently racy, no point locking */ - if (put_user(input_pool.entropy_count, p)) - return -EFAULT; - return 0; - case RNDADDTOENTCNT: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ent_count, p)) - return -EFAULT; - credit_entropy_bits(&input_pool, ent_count); - return 0; - case RNDADDENTROPY: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ent_count, p++)) - return -EFAULT; - if (ent_count < 0) - return -EINVAL; - if (get_user(size, p++)) - return -EFAULT; - retval = write_pool(&input_pool, (const char __user *)p, - size); - if (retval < 0) - return retval; - credit_entropy_bits(&input_pool, ent_count); - return 0; - case RNDZAPENTCNT: - case RNDCLEARPOOL: - /* Clear the entropy pool counters. */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - rand_initialize(); - return 0; - default: - return -EINVAL; - } -} - -static int random_fasync(int fd, struct file *filp, int on) -{ - return fasync_helper(fd, filp, on, &fasync); -} - -const struct file_operations random_fops = { - .read = random_read, - .write = random_write, - .poll = random_poll, - .unlocked_ioctl = random_ioctl, - .fasync = random_fasync, -}; - -const struct file_operations urandom_fops = { - .read = urandom_read, - .write = random_write, - .unlocked_ioctl = random_ioctl, - .fasync = random_fasync, -}; - -/*************************************************************** - * Random UUID interface - * - * Used here for a Boot ID, but can be useful for other kernel - * drivers. - ***************************************************************/ - -/* - * Generate random UUID - */ -void generate_random_uuid(unsigned char uuid_out[16]) -{ - get_random_bytes(uuid_out, 16); - /* Set UUID version to 4 --- truely random generation */ - uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40; - /* Set the UUID variant to DCE */ - uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; -} -EXPORT_SYMBOL(generate_random_uuid); - -/******************************************************************** - * - * Sysctl interface - * - ********************************************************************/ - -#ifdef CONFIG_SYSCTL - -#include - -static int min_read_thresh = 8, min_write_thresh; -static int max_read_thresh = INPUT_POOL_WORDS * 32; -static int max_write_thresh = INPUT_POOL_WORDS * 32; -static char sysctl_bootid[16]; - -/* - * These functions is used to return both the bootid UUID, and random - * UUID. The difference is in whether table->data is NULL; if it is, - * then a new UUID is generated and returned to the user. - * - * If the user accesses this via the proc interface, it will be returned - * as an ASCII string in the standard UUID format. If accesses via the - * sysctl system call, it is returned as 16 bytes of binary data. - */ -static int proc_do_uuid(ctl_table *table, int write, struct file *filp, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - ctl_table fake_table; - unsigned char buf[64], tmp_uuid[16], *uuid; - - uuid = table->data; - if (!uuid) { - uuid = tmp_uuid; - uuid[8] = 0; - } - if (uuid[8] == 0) - generate_random_uuid(uuid); - - sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" - "%02x%02x%02x%02x%02x%02x", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]); - fake_table.data = buf; - fake_table.maxlen = sizeof(buf); - - return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos); -} - -static int uuid_strategy(ctl_table *table, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen) -{ - unsigned char tmp_uuid[16], *uuid; - unsigned int len; - - if (!oldval || !oldlenp) - return 1; - - uuid = table->data; - if (!uuid) { - uuid = tmp_uuid; - uuid[8] = 0; - } - if (uuid[8] == 0) - generate_random_uuid(uuid); - - if (get_user(len, oldlenp)) - return -EFAULT; - if (len) { - if (len > 16) - len = 16; - if (copy_to_user(oldval, uuid, len) || - put_user(len, oldlenp)) - return -EFAULT; - } - return 1; -} - -static int sysctl_poolsize = INPUT_POOL_WORDS * 32; -ctl_table random_table[] = { - { - .ctl_name = RANDOM_POOLSIZE, - .procname = "poolsize", - .data = &sysctl_poolsize, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = &proc_dointvec, - }, - { - .ctl_name = RANDOM_ENTROPY_COUNT, - .procname = "entropy_avail", - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = &proc_dointvec, - .data = &input_pool.entropy_count, - }, - { - .ctl_name = RANDOM_READ_THRESH, - .procname = "read_wakeup_threshold", - .data = &random_read_wakeup_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &min_read_thresh, - .extra2 = &max_read_thresh, - }, - { - .ctl_name = RANDOM_WRITE_THRESH, - .procname = "write_wakeup_threshold", - .data = &random_write_wakeup_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, - .extra1 = &min_write_thresh, - .extra2 = &max_write_thresh, - }, - { - .ctl_name = RANDOM_BOOT_ID, - .procname = "boot_id", - .data = &sysctl_bootid, - .maxlen = 16, - .mode = 0444, - .proc_handler = &proc_do_uuid, - .strategy = &uuid_strategy, - }, - { - .ctl_name = RANDOM_UUID, - .procname = "uuid", - .maxlen = 16, - .mode = 0444, - .proc_handler = &proc_do_uuid, - .strategy = &uuid_strategy, - }, - { .ctl_name = 0 } -}; -#endif /* CONFIG_SYSCTL */ - -/******************************************************************** - * - * Random funtions for networking - * - ********************************************************************/ - -/* - * TCP initial sequence number picking. This uses the random number - * generator to pick an initial secret value. This value is hashed - * along with the TCP endpoint information to provide a unique - * starting point for each pair of TCP endpoints. This defeats - * attacks which rely on guessing the initial TCP sequence number. - * This algorithm was suggested by Steve Bellovin. - * - * Using a very strong hash was taking an appreciable amount of the total - * TCP connection establishment time, so this is a weaker hash, - * compensated for by changing the secret periodically. - */ - -/* F, G and H are basic MD4 functions: selection, majority, parity */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) - -/* - * The generic round function. The application is so specific that - * we don't bother protecting all the arguments with parens, as is generally - * good macro practice, in favor of extra legibility. - * Rotation is separate from addition to prevent recomputation - */ -#define ROUND(f, a, b, c, d, x, s) \ - (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s))) -#define K1 0 -#define K2 013240474631UL -#define K3 015666365641UL - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - -static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) -{ - __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ - ROUND(F, a, b, c, d, in[ 0] + K1, 3); - ROUND(F, d, a, b, c, in[ 1] + K1, 7); - ROUND(F, c, d, a, b, in[ 2] + K1, 11); - ROUND(F, b, c, d, a, in[ 3] + K1, 19); - ROUND(F, a, b, c, d, in[ 4] + K1, 3); - ROUND(F, d, a, b, c, in[ 5] + K1, 7); - ROUND(F, c, d, a, b, in[ 6] + K1, 11); - ROUND(F, b, c, d, a, in[ 7] + K1, 19); - ROUND(F, a, b, c, d, in[ 8] + K1, 3); - ROUND(F, d, a, b, c, in[ 9] + K1, 7); - ROUND(F, c, d, a, b, in[10] + K1, 11); - ROUND(F, b, c, d, a, in[11] + K1, 19); - - /* Round 2 */ - ROUND(G, a, b, c, d, in[ 1] + K2, 3); - ROUND(G, d, a, b, c, in[ 3] + K2, 5); - ROUND(G, c, d, a, b, in[ 5] + K2, 9); - ROUND(G, b, c, d, a, in[ 7] + K2, 13); - ROUND(G, a, b, c, d, in[ 9] + K2, 3); - ROUND(G, d, a, b, c, in[11] + K2, 5); - ROUND(G, c, d, a, b, in[ 0] + K2, 9); - ROUND(G, b, c, d, a, in[ 2] + K2, 13); - ROUND(G, a, b, c, d, in[ 4] + K2, 3); - ROUND(G, d, a, b, c, in[ 6] + K2, 5); - ROUND(G, c, d, a, b, in[ 8] + K2, 9); - ROUND(G, b, c, d, a, in[10] + K2, 13); - - /* Round 3 */ - ROUND(H, a, b, c, d, in[ 3] + K3, 3); - ROUND(H, d, a, b, c, in[ 7] + K3, 9); - ROUND(H, c, d, a, b, in[11] + K3, 11); - ROUND(H, b, c, d, a, in[ 2] + K3, 15); - ROUND(H, a, b, c, d, in[ 6] + K3, 3); - ROUND(H, d, a, b, c, in[10] + K3, 9); - ROUND(H, c, d, a, b, in[ 1] + K3, 11); - ROUND(H, b, c, d, a, in[ 5] + K3, 15); - ROUND(H, a, b, c, d, in[ 9] + K3, 3); - ROUND(H, d, a, b, c, in[ 0] + K3, 9); - ROUND(H, c, d, a, b, in[ 4] + K3, 11); - ROUND(H, b, c, d, a, in[ 8] + K3, 15); - - return buf[1] + b; /* "most hashed" word */ - /* Alternative: return sum of all words? */ -} -#endif - -#undef ROUND -#undef F -#undef G -#undef H -#undef K1 -#undef K2 -#undef K3 - -/* This should not be decreased so low that ISNs wrap too fast. */ -#define REKEY_INTERVAL (300 * HZ) -/* - * Bit layout of the tcp sequence numbers (before adding current time): - * bit 24-31: increased after every key exchange - * bit 0-23: hash(source,dest) - * - * The implementation is similar to the algorithm described - * in the Appendix of RFC 1185, except that - * - it uses a 1 MHz clock instead of a 250 kHz clock - * - it performs a rekey every 5 minutes, which is equivalent - * to a (source,dest) tulple dependent forward jump of the - * clock by 0..2^(HASH_BITS+1) - * - * Thus the average ISN wraparound time is 68 minutes instead of - * 4.55 hours. - * - * SMP cleanup and lock avoidance with poor man's RCU. - * Manfred Spraul - * - */ -#define COUNT_BITS 8 -#define COUNT_MASK ((1 << COUNT_BITS) - 1) -#define HASH_BITS 24 -#define HASH_MASK ((1 << HASH_BITS) - 1) - -static struct keydata { - __u32 count; /* already shifted to the final position */ - __u32 secret[12]; -} ____cacheline_aligned ip_keydata[2]; - -static unsigned int ip_cnt; - -static void rekey_seq_generator(struct work_struct *work); - -static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); - -/* - * Lock avoidance: - * The ISN generation runs lockless - it's just a hash over random data. - * State changes happen every 5 minutes when the random key is replaced. - * Synchronization is performed by having two copies of the hash function - * state and rekey_seq_generator always updates the inactive copy. - * The copy is then activated by updating ip_cnt. - * The implementation breaks down if someone blocks the thread - * that processes SYN requests for more than 5 minutes. Should never - * happen, and even if that happens only a not perfectly compliant - * ISN is generated, nothing fatal. - */ -static void rekey_seq_generator(struct work_struct *work) -{ - struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; - - get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); - keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS; - smp_wmb(); - ip_cnt++; - schedule_delayed_work(&rekey_work, REKEY_INTERVAL); -} - -static inline struct keydata *get_keyptr(void) -{ - struct keydata *keyptr = &ip_keydata[ip_cnt & 1]; - - smp_rmb(); - - return keyptr; -} - -static __init int seqgen_init(void) -{ - rekey_seq_generator(NULL); - return 0; -} -late_initcall(seqgen_init); - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, - __be16 sport, __be16 dport) -{ - __u32 seq; - __u32 hash[12]; - struct keydata *keyptr = get_keyptr(); - - /* The procedure is the same as for IPv4, but addresses are longer. - * Thus we must use twothirdsMD4Transform. - */ - - memcpy(hash, saddr, 16); - hash[4] = ((__force u16)sport << 16) + (__force u16)dport; - memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); - - seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; - seq += keyptr->count; - - seq += ktime_to_ns(ktime_get_real()); - - return seq; -} -EXPORT_SYMBOL(secure_tcpv6_sequence_number); -#endif - -/* The code below is shamelessly stolen from secure_tcp_sequence_number(). - * All blames to Andrey V. Savochkin . - */ -__u32 secure_ip_id(__be32 daddr) -{ - struct keydata *keyptr; - __u32 hash[4]; - - keyptr = get_keyptr(); - - /* - * Pick a unique starting offset for each IP destination. - * The dest ip address is placed in the starting vector, - * which is then hashed with random data. - */ - hash[0] = (__force __u32)daddr; - hash[1] = keyptr->secret[9]; - hash[2] = keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - - return half_md4_transform(hash, keyptr->secret); -} - -#ifdef CONFIG_INET - -__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - __u32 seq; - __u32 hash[4]; - struct keydata *keyptr = get_keyptr(); - - /* - * Pick a unique starting offset for each TCP connection endpoints - * (saddr, daddr, sport, dport). - * Note that the words are placed into the starting vector, which is - * then mixed with a partial MD4 over random data. - */ - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = keyptr->secret[11]; - - seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; - seq += keyptr->count; - /* - * As close as possible to RFC 793, which - * suggests using a 250 kHz clock. - * Further reading shows this assumes 2 Mb/s networks. - * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. - * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but - * we also need to limit the resolution so that the u32 seq - * overlaps less than one time per MSL (2 minutes). - * Choosing a clock of 64 ns period is OK. (period of 274 s) - */ - seq += ktime_to_ns(ktime_get_real()) >> 6; - - return seq; -} - -/* Generate secure starting point for ephemeral IPV4 transport port search */ -u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) -{ - struct keydata *keyptr = get_keyptr(); - u32 hash[4]; - - /* - * Pick a unique starting offset for each ephemeral port search - * (saddr, daddr, dport) and 48bits of random data. - */ - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = (__force u32)dport ^ keyptr->secret[10]; - hash[3] = keyptr->secret[11]; - - return half_md4_transform(hash, keyptr->secret); -} -EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); - -#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, - __be16 dport) -{ - struct keydata *keyptr = get_keyptr(); - u32 hash[12]; - - memcpy(hash, saddr, 16); - hash[4] = (__force u32)dport; - memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); - - return twothirdsMD4Transform((const __u32 *)daddr, hash); -} -#endif - -#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) -/* Similar to secure_tcp_sequence_number but generate a 48 bit value - * bit's 32-47 increase every key exchange - * 0-31 hash(source, dest) - */ -u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - u64 seq; - __u32 hash[4]; - struct keydata *keyptr = get_keyptr(); - - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = keyptr->secret[11]; - - seq = half_md4_transform(hash, keyptr->secret); - seq |= ((u64)keyptr->count) << (32 - HASH_BITS); - - seq += ktime_to_ns(ktime_get_real()); - seq &= (1ull << 48) - 1; - - return seq; -} -EXPORT_SYMBOL(secure_dccp_sequence_number); -#endif - -#endif /* CONFIG_INET */ - - -/* - * Get a random word for internal kernel use only. Similar to urandom but - * with the goal of minimal entropy pool depletion. As a result, the random - * value is not cryptographically secure but for several uses the cost of - * depleting entropy is too high - */ -unsigned int get_random_int(void) -{ - /* - * Use IP's RNG. It suits our purpose perfectly: it re-keys itself - * every second, from the entropy pool (and thus creates a limited - * drain on it), and uses halfMD4Transform within the second. We - * also mix it with jiffies and the PID: - */ - return secure_ip_id((__force __be32)(current->pid + jiffies)); -} - -/* - * randomize_range() returns a start address such that - * - * [...... .....] - * start end - * - * a with size "len" starting at the return value is inside in the - * area defined by [start, end], but is otherwise randomized. - */ -unsigned long -randomize_range(unsigned long start, unsigned long end, unsigned long len) -{ - unsigned long range = end - len - start; - - if (end <= start + len) - return 0; - return PAGE_ALIGN(get_random_int() % range + start); -} diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 36af1365..ed53fdeb 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -144,7 +144,8 @@ SRC_C_libdde_linux26.o.a += \ drivers/pci/probe.c \ drivers/pci/search.c \ drivers/pci/setup-bus.c \ - drivers/pci/setup-res.c + drivers/pci/setup-res.c \ + drivers/char/random.c ################################################################## # Sources for libdde_linux_net.a # diff --git a/libdde_linux26/lib/src/drivers/char/random.c b/libdde_linux26/lib/src/drivers/char/random.c new file mode 100644 index 00000000..0430c9d0 --- /dev/null +++ b/libdde_linux26/lib/src/drivers/char/random.c @@ -0,0 +1,1709 @@ +/* + * random.c -- A strong random number generator + * + * Copyright Matt Mackall , 2003, 2004, 2005 + * + * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. 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, and the entire permission notice in its entirety, + * including the disclaimer of warranties. + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * ALTERNATIVELY, this product may be distributed under the terms of + * the GNU General Public License, in which case the provisions of the GPL are + * required INSTEAD OF the above restrictions. (This clause is + * necessary due to a potential bad interaction between the GPL and + * the restrictions contained in a BSD-style copyright.) + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF + * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 NOT ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/* + * (now, with legal B.S. out of the way.....) + * + * This routine gathers environmental noise from device drivers, etc., + * and returns good random numbers, suitable for cryptographic use. + * Besides the obvious cryptographic uses, these numbers are also good + * for seeding TCP sequence numbers, and other places where it is + * desirable to have numbers which are not only random, but hard to + * predict by an attacker. + * + * Theory of operation + * =================== + * + * Computers are very predictable devices. Hence it is extremely hard + * to produce truly random numbers on a computer --- as opposed to + * pseudo-random numbers, which can easily generated by using a + * algorithm. Unfortunately, it is very easy for attackers to guess + * the sequence of pseudo-random number generators, and for some + * applications this is not acceptable. So instead, we must try to + * gather "environmental noise" from the computer's environment, which + * must be hard for outside attackers to observe, and use that to + * generate random numbers. In a Unix environment, this is best done + * from inside the kernel. + * + * Sources of randomness from the environment include inter-keyboard + * timings, inter-interrupt timings from some interrupts, and other + * events which are both (a) non-deterministic and (b) hard for an + * outside observer to measure. Randomness from these sources are + * added to an "entropy pool", which is mixed using a CRC-like function. + * This is not cryptographically strong, but it is adequate assuming + * the randomness is not chosen maliciously, and it is fast enough that + * the overhead of doing it on every interrupt is very reasonable. + * As random bytes are mixed into the entropy pool, the routines keep + * an *estimate* of how many bits of randomness have been stored into + * the random number generator's internal state. + * + * When random bytes are desired, they are obtained by taking the SHA + * hash of the contents of the "entropy pool". The SHA hash avoids + * exposing the internal state of the entropy pool. It is believed to + * be computationally infeasible to derive any useful information + * about the input of SHA from its output. Even if it is possible to + * analyze SHA in some clever way, as long as the amount of data + * returned from the generator is less than the inherent entropy in + * the pool, the output data is totally unpredictable. For this + * reason, the routine decreases its internal estimate of how many + * bits of "true randomness" are contained in the entropy pool as it + * outputs random numbers. + * + * If this estimate goes to zero, the routine can still generate + * random numbers; however, an attacker may (at least in theory) be + * able to infer the future output of the generator from prior + * outputs. This requires successful cryptanalysis of SHA, which is + * not believed to be feasible, but there is a remote possibility. + * Nonetheless, these numbers should be useful for the vast majority + * of purposes. + * + * Exported interfaces ---- output + * =============================== + * + * There are three exported interfaces; the first is one designed to + * be used from within the kernel: + * + * void get_random_bytes(void *buf, int nbytes); + * + * This interface will return the requested number of random bytes, + * and place it in the requested buffer. + * + * The two other interfaces are two character devices /dev/random and + * /dev/urandom. /dev/random is suitable for use when very high + * quality randomness is desired (for example, for key generation or + * one-time pads), as it will only return a maximum of the number of + * bits of randomness (as estimated by the random number generator) + * contained in the entropy pool. + * + * The /dev/urandom device does not have this limit, and will return + * as many bytes as are requested. As more and more random bytes are + * requested without giving time for the entropy pool to recharge, + * this will result in random numbers that are merely cryptographically + * strong. For many applications, however, this is acceptable. + * + * Exported interfaces ---- input + * ============================== + * + * The current exported interfaces for gathering environmental noise + * from the devices are: + * + * void add_input_randomness(unsigned int type, unsigned int code, + * unsigned int value); + * void add_interrupt_randomness(int irq); + * + * add_input_randomness() uses the input layer interrupt timing, as well as + * the event type information from the hardware. + * + * add_interrupt_randomness() uses the inter-interrupt timing as random + * inputs to the entropy pool. Note that not all interrupts are good + * sources of randomness! For example, the timer interrupts is not a + * good choice, because the periodicity of the interrupts is too + * regular, and hence predictable to an attacker. Disk interrupts are + * a better measure, since the timing of the disk interrupts are more + * unpredictable. + * + * All of these routines try to estimate how many bits of randomness a + * particular randomness source. They do this by keeping track of the + * first and second order deltas of the event timings. + * + * Ensuring unpredictability at system startup + * ============================================ + * + * When any operating system starts up, it will go through a sequence + * of actions that are fairly predictable by an adversary, especially + * if the start-up does not involve interaction with a human operator. + * This reduces the actual number of bits of unpredictability in the + * entropy pool below the value in entropy_count. In order to + * counteract this effect, it helps to carry information in the + * entropy pool across shut-downs and start-ups. To do this, put the + * following lines an appropriate script which is run during the boot + * sequence: + * + * echo "Initializing random number generator..." + * random_seed=/var/run/random-seed + * # Carry a random seed from start-up to start-up + * # Load and then save the whole entropy pool + * if [ -f $random_seed ]; then + * cat $random_seed >/dev/urandom + * else + * touch $random_seed + * fi + * chmod 600 $random_seed + * dd if=/dev/urandom of=$random_seed count=1 bs=512 + * + * and the following lines in an appropriate script which is run as + * the system is shutdown: + * + * # Carry a random seed from shut-down to start-up + * # Save the whole entropy pool + * echo "Saving random seed..." + * random_seed=/var/run/random-seed + * touch $random_seed + * chmod 600 $random_seed + * dd if=/dev/urandom of=$random_seed count=1 bs=512 + * + * For example, on most modern systems using the System V init + * scripts, such code fragments would be found in + * /etc/rc.d/init.d/random. On older Linux systems, the correct script + * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0. + * + * Effectively, these commands cause the contents of the entropy pool + * to be saved at shut-down time and reloaded into the entropy pool at + * start-up. (The 'dd' in the addition to the bootup script is to + * make sure that /etc/random-seed is different for every start-up, + * even if the system crashes without executing rc.0.) Even with + * complete knowledge of the start-up activities, predicting the state + * of the entropy pool requires knowledge of the previous history of + * the system. + * + * Configuring the /dev/random driver under Linux + * ============================================== + * + * The /dev/random driver under Linux uses minor numbers 8 and 9 of + * the /dev/mem major number (#1). So if your system does not have + * /dev/random and /dev/urandom created already, they can be created + * by using the commands: + * + * mknod /dev/random c 1 8 + * mknod /dev/urandom c 1 9 + * + * Acknowledgements: + * ================= + * + * Ideas for constructing this random number generator were derived + * from Pretty Good Privacy's random number generator, and from private + * discussions with Phil Karn. Colin Plumb provided a faster random + * number generator, which speed up the mixing function of the entropy + * pool, taken from PGPfone. Dale Worley has also contributed many + * useful ideas and suggestions to improve this driver. + * + * Any flaws in the design are solely my responsibility, and should + * not be attributed to the Phil, Colin, or any of authors of PGP. + * + * Further background information on this topic may be obtained from + * RFC 1750, "Randomness Recommendations for Security", by Donald + * Eastlake, Steve Crocker, and Jeff Schiller. + */ + +#ifdef DDE_LINUX +#include +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Configuration information + */ +#define INPUT_POOL_WORDS 128 +#define OUTPUT_POOL_WORDS 32 +#define SEC_XFER_SIZE 512 + +/* + * The minimum number of bits of entropy before we wake up a read on + * /dev/random. Should be enough to do a significant reseed. + */ +static int random_read_wakeup_thresh = 64; + +/* + * If the entropy count falls under this number of bits, then we + * should wake up processes which are selecting or polling on write + * access to /dev/random. + */ +static int random_write_wakeup_thresh = 128; + +/* + * When the input pool goes over trickle_thresh, start dropping most + * samples to avoid wasting CPU time and reduce lock contention. + */ + +static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; + +static DEFINE_PER_CPU(int, trickle_count); + +/* + * A pool of size .poolwords is stirred with a primitive polynomial + * of degree .poolwords over GF(2). The taps for various sizes are + * defined below. They are chosen to be evenly spaced (minimum RMS + * distance from evenly spaced; the numbers in the comments are a + * scaled squared error sum) except for the last tap, which is 1 to + * get the twisting happening as fast as possible. + */ +static struct poolinfo { + int poolwords; + int tap1, tap2, tap3, tap4, tap5; +} poolinfo_table[] = { + /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ + { 128, 103, 76, 51, 25, 1 }, + /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ + { 32, 26, 20, 14, 7, 1 }, +#if 0 + /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ + { 2048, 1638, 1231, 819, 411, 1 }, + + /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ + { 1024, 817, 615, 412, 204, 1 }, + + /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ + { 1024, 819, 616, 410, 207, 2 }, + + /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ + { 512, 411, 308, 208, 104, 1 }, + + /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ + { 512, 409, 307, 206, 102, 2 }, + /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ + { 512, 409, 309, 205, 103, 2 }, + + /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ + { 256, 205, 155, 101, 52, 1 }, + + /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ + { 128, 103, 78, 51, 27, 2 }, + + /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ + { 64, 52, 39, 26, 14, 1 }, +#endif +}; + +#define POOLBITS poolwords*32 +#define POOLBYTES poolwords*4 + +/* + * For the purposes of better mixing, we use the CRC-32 polynomial as + * well to make a twisted Generalized Feedback Shift Reigster + * + * (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR generators. ACM + * Transactions on Modeling and Computer Simulation 2(3):179-194. + * Also see M. Matsumoto & Y. Kurita, 1994. Twisted GFSR generators + * II. ACM Transactions on Mdeling and Computer Simulation 4:254-266) + * + * Thanks to Colin Plumb for suggesting this. + * + * We have not analyzed the resultant polynomial to prove it primitive; + * in fact it almost certainly isn't. Nonetheless, the irreducible factors + * of a random large-degree polynomial over GF(2) are more than large enough + * that periodicity is not a concern. + * + * The input hash is much less sensitive than the output hash. All + * that we want of it is that it be a good non-cryptographic hash; + * i.e. it not produce collisions when fed "random" data of the sort + * we expect to see. As long as the pool state differs for different + * inputs, we have preserved the input entropy and done a good job. + * The fact that an intelligent attacker can construct inputs that + * will produce controlled alterations to the pool's state is not + * important because we don't consider such inputs to contribute any + * randomness. The only property we need with respect to them is that + * the attacker can't increase his/her knowledge of the pool's state. + * Since all additions are reversible (knowing the final state and the + * input, you can reconstruct the initial state), if an attacker has + * any uncertainty about the initial state, he/she can only shuffle + * that uncertainty about, but never cause any collisions (which would + * decrease the uncertainty). + * + * The chosen system lets the state of the pool be (essentially) the input + * modulo the generator polymnomial. Now, for random primitive polynomials, + * this is a universal class of hash functions, meaning that the chance + * of a collision is limited by the attacker's knowledge of the generator + * polynomail, so if it is chosen at random, an attacker can never force + * a collision. Here, we use a fixed polynomial, but we *can* assume that + * ###--> it is unknown to the processes generating the input entropy. <-### + * Because of this important property, this is a good, collision-resistant + * hash; hash collisions will occur no more often than chance. + */ + +/* + * Static global variables + */ +static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); +static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static struct fasync_struct *fasync; + +#if 0 +static int debug; +module_param(debug, bool, 0644); +#define DEBUG_ENT(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG "random %04d %04d %04d: " \ + fmt,\ + input_pool.entropy_count,\ + blocking_pool.entropy_count,\ + nonblocking_pool.entropy_count,\ + ## arg); } while (0) +#else +#define DEBUG_ENT(fmt, arg...) do {} while (0) +#endif + +/********************************************************************** + * + * OS independent entropy store. Here are the functions which handle + * storing entropy in an entropy pool. + * + **********************************************************************/ + +struct entropy_store; +struct entropy_store { + /* read-only data: */ + struct poolinfo *poolinfo; + __u32 *pool; + const char *name; + int limit; + struct entropy_store *pull; + + /* read-write data: */ + spinlock_t lock; + unsigned add_ptr; + int entropy_count; + int input_rotate; +}; + +static __u32 input_pool_data[INPUT_POOL_WORDS]; +static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; +static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; + +static struct entropy_store input_pool = { + .poolinfo = &poolinfo_table[0], + .name = "input", + .limit = 1, + .lock = __SPIN_LOCK_UNLOCKED(&input_pool.lock), + .pool = input_pool_data +}; + +static struct entropy_store blocking_pool = { + .poolinfo = &poolinfo_table[1], + .name = "blocking", + .limit = 1, + .pull = &input_pool, + .lock = __SPIN_LOCK_UNLOCKED(&blocking_pool.lock), + .pool = blocking_pool_data +}; + +static struct entropy_store nonblocking_pool = { + .poolinfo = &poolinfo_table[1], + .name = "nonblocking", + .pull = &input_pool, + .lock = __SPIN_LOCK_UNLOCKED(&nonblocking_pool.lock), + .pool = nonblocking_pool_data +}; + +/* + * This function adds bytes into the entropy "pool". It does not + * update the entropy estimate. The caller should call + * credit_entropy_bits if this is appropriate. + * + * The pool is stirred with a primitive polynomial of the appropriate + * degree, and then twisted. We twist by three bits at a time because + * it's cheap to do so and helps slightly in the expected case where + * the entropy is concentrated in the low-order bits. + */ +static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) +{ + static __u32 const twist_table[8] = { + 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, + 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; + unsigned long i, j, tap1, tap2, tap3, tap4, tap5; + int input_rotate; + int wordmask = r->poolinfo->poolwords - 1; + const char *bytes = in; + __u32 w; + unsigned long flags; + + /* Taps are constant, so we can load them without holding r->lock. */ + tap1 = r->poolinfo->tap1; + tap2 = r->poolinfo->tap2; + tap3 = r->poolinfo->tap3; + tap4 = r->poolinfo->tap4; + tap5 = r->poolinfo->tap5; + + spin_lock_irqsave(&r->lock, flags); + input_rotate = r->input_rotate; + i = r->add_ptr; + + /* mix one byte at a time to simplify size handling and churn faster */ + while (nbytes--) { + w = rol32(*bytes++, input_rotate & 31); + i = (i - 1) & wordmask; + + /* XOR in the various taps */ + w ^= r->pool[i]; + w ^= r->pool[(i + tap1) & wordmask]; + w ^= r->pool[(i + tap2) & wordmask]; + w ^= r->pool[(i + tap3) & wordmask]; + w ^= r->pool[(i + tap4) & wordmask]; + w ^= r->pool[(i + tap5) & wordmask]; + + /* Mix the result back in with a twist */ + r->pool[i] = (w >> 3) ^ twist_table[w & 7]; + + /* + * Normally, we add 7 bits of rotation to the pool. + * At the beginning of the pool, add an extra 7 bits + * rotation, so that successive passes spread the + * input bits across the pool evenly. + */ + input_rotate += i ? 7 : 14; + } + + r->input_rotate = input_rotate; + r->add_ptr = i; + + if (out) + for (j = 0; j < 16; j++) + ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; + + spin_unlock_irqrestore(&r->lock, flags); +} + +static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) +{ + mix_pool_bytes_extract(r, in, bytes, NULL); +} + +/* + * Credit (or debit) the entropy store with n bits of entropy + */ +static void credit_entropy_bits(struct entropy_store *r, int nbits) +{ + unsigned long flags; + int entropy_count; + + if (!nbits) + return; + + spin_lock_irqsave(&r->lock, flags); + + DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); + entropy_count = r->entropy_count; + entropy_count += nbits; + if (entropy_count < 0) { + DEBUG_ENT("negative entropy/overflow\n"); + entropy_count = 0; + } else if (entropy_count > r->poolinfo->POOLBITS) + entropy_count = r->poolinfo->POOLBITS; + r->entropy_count = entropy_count; + + /* should we wake readers? */ + if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { + wake_up_interruptible(&random_read_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); + } + spin_unlock_irqrestore(&r->lock, flags); +} + +/********************************************************************* + * + * Entropy input management + * + *********************************************************************/ + +/* There is one of these per entropy source */ +struct timer_rand_state { + cycles_t last_time; + long last_delta, last_delta2; + unsigned dont_count_entropy:1; +}; + +#ifndef CONFIG_SPARSE_IRQ + +static struct timer_rand_state *irq_timer_state[NR_IRQS]; + +static struct timer_rand_state *get_timer_rand_state(unsigned int irq) +{ + return irq_timer_state[irq]; +} + +static void set_timer_rand_state(unsigned int irq, + struct timer_rand_state *state) +{ + irq_timer_state[irq] = state; +} + +#else + +static struct timer_rand_state *get_timer_rand_state(unsigned int irq) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + + return desc->timer_rand_state; +} + +static void set_timer_rand_state(unsigned int irq, + struct timer_rand_state *state) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + + desc->timer_rand_state = state; +} +#endif + +static struct timer_rand_state input_timer_state; + +/* + * This function adds entropy to the entropy "pool" by using timing + * delays. It uses the timer_rand_state structure to make an estimate + * of how many bits of entropy this call has added to the pool. + * + * The number "num" is also added to the pool - it should somehow describe + * the type of event which just happened. This is currently 0-255 for + * keyboard scan codes, and 256 upwards for interrupts. + * + */ +static void add_timer_randomness(struct timer_rand_state *state, unsigned num) +{ + struct { + cycles_t cycles; + long jiffies; + unsigned num; + } sample; + long delta, delta2, delta3; + + preempt_disable(); + /* if over the trickle threshold, use only 1 in 4096 samples */ + if (input_pool.entropy_count > trickle_thresh && + (__get_cpu_var(trickle_count)++ & 0xfff)) + goto out; + + sample.jiffies = jiffies; + sample.cycles = get_cycles(); + sample.num = num; + mix_pool_bytes(&input_pool, &sample, sizeof(sample)); + + /* + * Calculate number of bits of randomness we probably added. + * We take into account the first, second and third-order deltas + * in order to make our estimate. + */ + + if (!state->dont_count_entropy) { + delta = sample.jiffies - state->last_time; + state->last_time = sample.jiffies; + + delta2 = delta - state->last_delta; + state->last_delta = delta; + + delta3 = delta2 - state->last_delta2; + state->last_delta2 = delta2; + + if (delta < 0) + delta = -delta; + if (delta2 < 0) + delta2 = -delta2; + if (delta3 < 0) + delta3 = -delta3; + if (delta > delta2) + delta = delta2; + if (delta > delta3) + delta = delta3; + + /* + * delta is now minimum absolute delta. + * Round down by 1 bit on general principles, + * and limit entropy entimate to 12 bits. + */ + credit_entropy_bits(&input_pool, + min_t(int, fls(delta>>1), 11)); + } +out: + preempt_enable(); +} + +void add_input_randomness(unsigned int type, unsigned int code, + unsigned int value) +{ + static unsigned char last_value; + + /* ignore autorepeat and the like */ + if (value == last_value) + return; + + DEBUG_ENT("input event\n"); + last_value = value; + add_timer_randomness(&input_timer_state, + (type << 4) ^ code ^ (code >> 4) ^ value); +} +EXPORT_SYMBOL_GPL(add_input_randomness); + +void add_interrupt_randomness(int irq) +{ + struct timer_rand_state *state; + + state = get_timer_rand_state(irq); + + if (state == NULL) + return; + + DEBUG_ENT("irq event %d\n", irq); + add_timer_randomness(state, 0x100 + irq); +} + +#ifdef CONFIG_BLOCK +void add_disk_randomness(struct gendisk *disk) +{ + if (!disk || !disk->random) + return; + /* first major is 1, so we get >= 0x200 here */ + DEBUG_ENT("disk event %d:%d\n", + MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); + + add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); +} +#endif + +#define EXTRACT_SIZE 10 + +/********************************************************************* + * + * Entropy extraction routines + * + *********************************************************************/ + +static ssize_t extract_entropy(struct entropy_store *r, void *buf, + size_t nbytes, int min, int rsvd); + +/* + * This utility inline function is responsible for transfering entropy + * from the primary pool to the secondary extraction pool. We make + * sure we pull enough for a 'catastrophic reseed'. + */ +static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) +{ + __u32 tmp[OUTPUT_POOL_WORDS]; + + if (r->pull && r->entropy_count < nbytes * 8 && + r->entropy_count < r->poolinfo->POOLBITS) { + /* If we're limited, always leave two wakeup worth's BITS */ + int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4; + int bytes = nbytes; + + /* pull at least as many as BYTES as wakeup BITS */ + bytes = max_t(int, bytes, random_read_wakeup_thresh / 8); + /* but never more than the buffer size */ + bytes = min_t(int, bytes, sizeof(tmp)); + + DEBUG_ENT("going to reseed %s with %d bits " + "(%d of %d requested)\n", + r->name, bytes * 8, nbytes * 8, r->entropy_count); + + bytes = extract_entropy(r->pull, tmp, bytes, + random_read_wakeup_thresh / 8, rsvd); + mix_pool_bytes(r, tmp, bytes); + credit_entropy_bits(r, bytes*8); + } +} + +/* + * These functions extracts randomness from the "entropy pool", and + * returns it in a buffer. + * + * The min parameter specifies the minimum amount we can pull before + * failing to avoid races that defeat catastrophic reseeding while the + * reserved parameter indicates how much entropy we must leave in the + * pool after each pull to avoid starving other readers. + * + * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. + */ + +static size_t account(struct entropy_store *r, size_t nbytes, int min, + int reserved) +{ + unsigned long flags; + + /* Hold lock while accounting */ + spin_lock_irqsave(&r->lock, flags); + + BUG_ON(r->entropy_count > r->poolinfo->POOLBITS); + DEBUG_ENT("trying to extract %d bits from %s\n", + nbytes * 8, r->name); + + /* Can we pull enough? */ + if (r->entropy_count / 8 < min + reserved) { + nbytes = 0; + } else { + /* If limited, never pull more than available */ + if (r->limit && nbytes + reserved >= r->entropy_count / 8) + nbytes = r->entropy_count/8 - reserved; + + if (r->entropy_count / 8 >= nbytes + reserved) + r->entropy_count -= nbytes*8; + else + r->entropy_count = reserved; + + if (r->entropy_count < random_write_wakeup_thresh) { + wake_up_interruptible(&random_write_wait); + kill_fasync(&fasync, SIGIO, POLL_OUT); + } + } + + DEBUG_ENT("debiting %d entropy credits from %s%s\n", + nbytes * 8, r->name, r->limit ? "" : " (unlimited)"); + + spin_unlock_irqrestore(&r->lock, flags); + + return nbytes; +} + +static void extract_buf(struct entropy_store *r, __u8 *out) +{ + int i; + __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; + __u8 extract[64]; + + /* Generate a hash across the pool, 16 words (512 bits) at a time */ + sha_init(hash); + for (i = 0; i < r->poolinfo->poolwords; i += 16) + sha_transform(hash, (__u8 *)(r->pool + i), workspace); + + /* + * We mix the hash back into the pool to prevent backtracking + * attacks (where the attacker knows the state of the pool + * plus the current outputs, and attempts to find previous + * ouputs), unless the hash function can be inverted. By + * mixing at least a SHA1 worth of hash data back, we make + * brute-forcing the feedback as hard as brute-forcing the + * hash. + */ + mix_pool_bytes_extract(r, hash, sizeof(hash), extract); + + /* + * To avoid duplicates, we atomically extract a portion of the + * pool while mixing, and hash one final time. + */ + sha_transform(hash, extract, workspace); + memset(extract, 0, sizeof(extract)); + memset(workspace, 0, sizeof(workspace)); + + /* + * In case the hash function has some recognizable output + * pattern, we fold it in half. Thus, we always feed back + * twice as much data as we output. + */ + hash[0] ^= hash[3]; + hash[1] ^= hash[4]; + hash[2] ^= rol32(hash[2], 16); + memcpy(out, hash, EXTRACT_SIZE); + memset(hash, 0, sizeof(hash)); +} + +static ssize_t extract_entropy(struct entropy_store *r, void *buf, + size_t nbytes, int min, int reserved) +{ + ssize_t ret = 0, i; + __u8 tmp[EXTRACT_SIZE]; + + xfer_secondary_pool(r, nbytes); + nbytes = account(r, nbytes, min, reserved); + + while (nbytes) { + extract_buf(r, tmp); + i = min_t(int, nbytes, EXTRACT_SIZE); + memcpy(buf, tmp, i); + nbytes -= i; + buf += i; + ret += i; + } + + /* Wipe data just returned from memory */ + memset(tmp, 0, sizeof(tmp)); + + return ret; +} + +static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, + size_t nbytes) +{ + ssize_t ret = 0, i; + __u8 tmp[EXTRACT_SIZE]; + + xfer_secondary_pool(r, nbytes); + nbytes = account(r, nbytes, 0, 0); + + while (nbytes) { + if (need_resched()) { + if (signal_pending(current)) { + if (ret == 0) + ret = -ERESTARTSYS; + break; + } + schedule(); + } + + extract_buf(r, tmp); + i = min_t(int, nbytes, EXTRACT_SIZE); + if (copy_to_user(buf, tmp, i)) { + ret = -EFAULT; + break; + } + + nbytes -= i; + buf += i; + ret += i; + } + + /* Wipe data just returned from memory */ + memset(tmp, 0, sizeof(tmp)); + + return ret; +} + +#endif + +/* + * This function is the exported kernel interface. It returns some + * number of good random numbers, suitable for seeding TCP sequence + * numbers, etc. + */ +void get_random_bytes(void *buf, int nbytes) +{ +#ifndef DDE_LINUX + extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); +#else + int i; + int nlwords = nbytes / sizeof (long); + for (i = 0; i < nlwords; i++) + ((long *) buf)[i] = ddekit_random (); + for (i = nlwords * sizeof (long); i < nbytes; i++) + ((char *) buf)[i] = (char) ddekit_random (); +#endif +} +EXPORT_SYMBOL(get_random_bytes); + +#ifndef DDE_LINUX +/* + * init_std_data - initialize pool with system data + * + * @r: pool to initialize + * + * This function clears the pool's entropy count and mixes some system + * data into the pool to prepare it for use. The pool is not cleared + * as that can only decrease the entropy in the pool. + */ +static void init_std_data(struct entropy_store *r) +{ + ktime_t now; + unsigned long flags; + + spin_lock_irqsave(&r->lock, flags); + r->entropy_count = 0; + spin_unlock_irqrestore(&r->lock, flags); + + now = ktime_get_real(); + mix_pool_bytes(r, &now, sizeof(now)); + mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); +} + +static int rand_initialize(void) +{ + init_std_data(&input_pool); + init_std_data(&blocking_pool); + init_std_data(&nonblocking_pool); + return 0; +} +module_init(rand_initialize); + +void rand_initialize_irq(int irq) +{ + struct timer_rand_state *state; + + state = get_timer_rand_state(irq); + + if (state) + return; + + /* + * If kzalloc returns null, we just won't use that entropy + * source. + */ + state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) + set_timer_rand_state(irq, state); +} + +#ifdef CONFIG_BLOCK +void rand_initialize_disk(struct gendisk *disk) +{ + struct timer_rand_state *state; + + /* + * If kzalloc returns null, we just won't use that entropy + * source. + */ + state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); + if (state) + disk->random = state; +} +#endif + +static ssize_t +random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +{ + ssize_t n, retval = 0, count = 0; + + if (nbytes == 0) + return 0; + + while (nbytes > 0) { + n = nbytes; + if (n > SEC_XFER_SIZE) + n = SEC_XFER_SIZE; + + DEBUG_ENT("reading %d bits\n", n*8); + + n = extract_entropy_user(&blocking_pool, buf, n); + + DEBUG_ENT("read got %d bits (%d still needed)\n", + n*8, (nbytes-n)*8); + + if (n == 0) { + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + + DEBUG_ENT("sleeping?\n"); + + wait_event_interruptible(random_read_wait, + input_pool.entropy_count >= + random_read_wakeup_thresh); + + DEBUG_ENT("awake\n"); + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + continue; + } + + if (n < 0) { + retval = n; + break; + } + count += n; + buf += n; + nbytes -= n; + break; /* This break makes the device work */ + /* like a named pipe */ + } + + /* + * If we gave the user some bytes, update the access time. + */ + if (count) + file_accessed(file); + + return (count ? count : retval); +} + +static ssize_t +urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +{ + return extract_entropy_user(&nonblocking_pool, buf, nbytes); +} + +static unsigned int +random_poll(struct file *file, poll_table * wait) +{ + unsigned int mask; + + poll_wait(file, &random_read_wait, wait); + poll_wait(file, &random_write_wait, wait); + mask = 0; + if (input_pool.entropy_count >= random_read_wakeup_thresh) + mask |= POLLIN | POLLRDNORM; + if (input_pool.entropy_count < random_write_wakeup_thresh) + mask |= POLLOUT | POLLWRNORM; + return mask; +} + +static int +write_pool(struct entropy_store *r, const char __user *buffer, size_t count) +{ + size_t bytes; + __u32 buf[16]; + const char __user *p = buffer; + + while (count > 0) { + bytes = min(count, sizeof(buf)); + if (copy_from_user(&buf, p, bytes)) + return -EFAULT; + + count -= bytes; + p += bytes; + + mix_pool_bytes(r, buf, bytes); + cond_resched(); + } + + return 0; +} + +static ssize_t random_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + size_t ret; + struct inode *inode = file->f_path.dentry->d_inode; + + ret = write_pool(&blocking_pool, buffer, count); + if (ret) + return ret; + ret = write_pool(&nonblocking_pool, buffer, count); + if (ret) + return ret; + + inode->i_mtime = current_fs_time(inode->i_sb); + mark_inode_dirty(inode); + return (ssize_t)count; +} + +static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) +{ + int size, ent_count; + int __user *p = (int __user *)arg; + int retval; + + switch (cmd) { + case RNDGETENTCNT: + /* inherently racy, no point locking */ + if (put_user(input_pool.entropy_count, p)) + return -EFAULT; + return 0; + case RNDADDTOENTCNT: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(ent_count, p)) + return -EFAULT; + credit_entropy_bits(&input_pool, ent_count); + return 0; + case RNDADDENTROPY: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(ent_count, p++)) + return -EFAULT; + if (ent_count < 0) + return -EINVAL; + if (get_user(size, p++)) + return -EFAULT; + retval = write_pool(&input_pool, (const char __user *)p, + size); + if (retval < 0) + return retval; + credit_entropy_bits(&input_pool, ent_count); + return 0; + case RNDZAPENTCNT: + case RNDCLEARPOOL: + /* Clear the entropy pool counters. */ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + rand_initialize(); + return 0; + default: + return -EINVAL; + } +} + +static int random_fasync(int fd, struct file *filp, int on) +{ + return fasync_helper(fd, filp, on, &fasync); +} + +const struct file_operations random_fops = { + .read = random_read, + .write = random_write, + .poll = random_poll, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, +}; + +const struct file_operations urandom_fops = { + .read = urandom_read, + .write = random_write, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, +}; + +/*************************************************************** + * Random UUID interface + * + * Used here for a Boot ID, but can be useful for other kernel + * drivers. + ***************************************************************/ + +/* + * Generate random UUID + */ +void generate_random_uuid(unsigned char uuid_out[16]) +{ + get_random_bytes(uuid_out, 16); + /* Set UUID version to 4 --- truely random generation */ + uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40; + /* Set the UUID variant to DCE */ + uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; +} +EXPORT_SYMBOL(generate_random_uuid); + +/******************************************************************** + * + * Sysctl interface + * + ********************************************************************/ + +#ifdef CONFIG_SYSCTL + +#include + +static int min_read_thresh = 8, min_write_thresh; +static int max_read_thresh = INPUT_POOL_WORDS * 32; +static int max_write_thresh = INPUT_POOL_WORDS * 32; +static char sysctl_bootid[16]; + +/* + * These functions is used to return both the bootid UUID, and random + * UUID. The difference is in whether table->data is NULL; if it is, + * then a new UUID is generated and returned to the user. + * + * If the user accesses this via the proc interface, it will be returned + * as an ASCII string in the standard UUID format. If accesses via the + * sysctl system call, it is returned as 16 bytes of binary data. + */ +static int proc_do_uuid(ctl_table *table, int write, struct file *filp, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + ctl_table fake_table; + unsigned char buf[64], tmp_uuid[16], *uuid; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + uuid[8] = 0; + } + if (uuid[8] == 0) + generate_random_uuid(uuid); + + sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + fake_table.data = buf; + fake_table.maxlen = sizeof(buf); + + return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos); +} + +static int uuid_strategy(ctl_table *table, + void __user *oldval, size_t __user *oldlenp, + void __user *newval, size_t newlen) +{ + unsigned char tmp_uuid[16], *uuid; + unsigned int len; + + if (!oldval || !oldlenp) + return 1; + + uuid = table->data; + if (!uuid) { + uuid = tmp_uuid; + uuid[8] = 0; + } + if (uuid[8] == 0) + generate_random_uuid(uuid); + + if (get_user(len, oldlenp)) + return -EFAULT; + if (len) { + if (len > 16) + len = 16; + if (copy_to_user(oldval, uuid, len) || + put_user(len, oldlenp)) + return -EFAULT; + } + return 1; +} + +static int sysctl_poolsize = INPUT_POOL_WORDS * 32; +ctl_table random_table[] = { + { + .ctl_name = RANDOM_POOLSIZE, + .procname = "poolsize", + .data = &sysctl_poolsize, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = RANDOM_ENTROPY_COUNT, + .procname = "entropy_avail", + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + .data = &input_pool.entropy_count, + }, + { + .ctl_name = RANDOM_READ_THRESH, + .procname = "read_wakeup_threshold", + .data = &random_read_wakeup_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_read_thresh, + .extra2 = &max_read_thresh, + }, + { + .ctl_name = RANDOM_WRITE_THRESH, + .procname = "write_wakeup_threshold", + .data = &random_write_wakeup_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_write_thresh, + .extra2 = &max_write_thresh, + }, + { + .ctl_name = RANDOM_BOOT_ID, + .procname = "boot_id", + .data = &sysctl_bootid, + .maxlen = 16, + .mode = 0444, + .proc_handler = &proc_do_uuid, + .strategy = &uuid_strategy, + }, + { + .ctl_name = RANDOM_UUID, + .procname = "uuid", + .maxlen = 16, + .mode = 0444, + .proc_handler = &proc_do_uuid, + .strategy = &uuid_strategy, + }, + { .ctl_name = 0 } +}; +#endif /* CONFIG_SYSCTL */ + +/******************************************************************** + * + * Random funtions for networking + * + ********************************************************************/ + +/* + * TCP initial sequence number picking. This uses the random number + * generator to pick an initial secret value. This value is hashed + * along with the TCP endpoint information to provide a unique + * starting point for each pair of TCP endpoints. This defeats + * attacks which rely on guessing the initial TCP sequence number. + * This algorithm was suggested by Steve Bellovin. + * + * Using a very strong hash was taking an appreciable amount of the total + * TCP connection establishment time, so this is a weaker hash, + * compensated for by changing the secret periodically. + */ + +/* F, G and H are basic MD4 functions: selection, majority, parity */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The generic round function. The application is so specific that + * we don't bother protecting all the arguments with parens, as is generally + * good macro practice, in favor of extra legibility. + * Rotation is separate from addition to prevent recomputation + */ +#define ROUND(f, a, b, c, d, x, s) \ + (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s))) +#define K1 0 +#define K2 013240474631UL +#define K3 015666365641UL + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) +{ + __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ + ROUND(F, a, b, c, d, in[ 0] + K1, 3); + ROUND(F, d, a, b, c, in[ 1] + K1, 7); + ROUND(F, c, d, a, b, in[ 2] + K1, 11); + ROUND(F, b, c, d, a, in[ 3] + K1, 19); + ROUND(F, a, b, c, d, in[ 4] + K1, 3); + ROUND(F, d, a, b, c, in[ 5] + K1, 7); + ROUND(F, c, d, a, b, in[ 6] + K1, 11); + ROUND(F, b, c, d, a, in[ 7] + K1, 19); + ROUND(F, a, b, c, d, in[ 8] + K1, 3); + ROUND(F, d, a, b, c, in[ 9] + K1, 7); + ROUND(F, c, d, a, b, in[10] + K1, 11); + ROUND(F, b, c, d, a, in[11] + K1, 19); + + /* Round 2 */ + ROUND(G, a, b, c, d, in[ 1] + K2, 3); + ROUND(G, d, a, b, c, in[ 3] + K2, 5); + ROUND(G, c, d, a, b, in[ 5] + K2, 9); + ROUND(G, b, c, d, a, in[ 7] + K2, 13); + ROUND(G, a, b, c, d, in[ 9] + K2, 3); + ROUND(G, d, a, b, c, in[11] + K2, 5); + ROUND(G, c, d, a, b, in[ 0] + K2, 9); + ROUND(G, b, c, d, a, in[ 2] + K2, 13); + ROUND(G, a, b, c, d, in[ 4] + K2, 3); + ROUND(G, d, a, b, c, in[ 6] + K2, 5); + ROUND(G, c, d, a, b, in[ 8] + K2, 9); + ROUND(G, b, c, d, a, in[10] + K2, 13); + + /* Round 3 */ + ROUND(H, a, b, c, d, in[ 3] + K3, 3); + ROUND(H, d, a, b, c, in[ 7] + K3, 9); + ROUND(H, c, d, a, b, in[11] + K3, 11); + ROUND(H, b, c, d, a, in[ 2] + K3, 15); + ROUND(H, a, b, c, d, in[ 6] + K3, 3); + ROUND(H, d, a, b, c, in[10] + K3, 9); + ROUND(H, c, d, a, b, in[ 1] + K3, 11); + ROUND(H, b, c, d, a, in[ 5] + K3, 15); + ROUND(H, a, b, c, d, in[ 9] + K3, 3); + ROUND(H, d, a, b, c, in[ 0] + K3, 9); + ROUND(H, c, d, a, b, in[ 4] + K3, 11); + ROUND(H, b, c, d, a, in[ 8] + K3, 15); + + return buf[1] + b; /* "most hashed" word */ + /* Alternative: return sum of all words? */ +} +#endif + +#undef ROUND +#undef F +#undef G +#undef H +#undef K1 +#undef K2 +#undef K3 + +/* This should not be decreased so low that ISNs wrap too fast. */ +#define REKEY_INTERVAL (300 * HZ) +/* + * Bit layout of the tcp sequence numbers (before adding current time): + * bit 24-31: increased after every key exchange + * bit 0-23: hash(source,dest) + * + * The implementation is similar to the algorithm described + * in the Appendix of RFC 1185, except that + * - it uses a 1 MHz clock instead of a 250 kHz clock + * - it performs a rekey every 5 minutes, which is equivalent + * to a (source,dest) tulple dependent forward jump of the + * clock by 0..2^(HASH_BITS+1) + * + * Thus the average ISN wraparound time is 68 minutes instead of + * 4.55 hours. + * + * SMP cleanup and lock avoidance with poor man's RCU. + * Manfred Spraul + * + */ +#define COUNT_BITS 8 +#define COUNT_MASK ((1 << COUNT_BITS) - 1) +#define HASH_BITS 24 +#define HASH_MASK ((1 << HASH_BITS) - 1) + +static struct keydata { + __u32 count; /* already shifted to the final position */ + __u32 secret[12]; +} ____cacheline_aligned ip_keydata[2]; + +static unsigned int ip_cnt; + +static void rekey_seq_generator(struct work_struct *work); + +static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator); + +/* + * Lock avoidance: + * The ISN generation runs lockless - it's just a hash over random data. + * State changes happen every 5 minutes when the random key is replaced. + * Synchronization is performed by having two copies of the hash function + * state and rekey_seq_generator always updates the inactive copy. + * The copy is then activated by updating ip_cnt. + * The implementation breaks down if someone blocks the thread + * that processes SYN requests for more than 5 minutes. Should never + * happen, and even if that happens only a not perfectly compliant + * ISN is generated, nothing fatal. + */ +static void rekey_seq_generator(struct work_struct *work) +{ + struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)]; + + get_random_bytes(keyptr->secret, sizeof(keyptr->secret)); + keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS; + smp_wmb(); + ip_cnt++; + schedule_delayed_work(&rekey_work, REKEY_INTERVAL); +} + +static inline struct keydata *get_keyptr(void) +{ + struct keydata *keyptr = &ip_keydata[ip_cnt & 1]; + + smp_rmb(); + + return keyptr; +} + +static __init int seqgen_init(void) +{ + rekey_seq_generator(NULL); + return 0; +} +late_initcall(seqgen_init); + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, + __be16 sport, __be16 dport) +{ + __u32 seq; + __u32 hash[12]; + struct keydata *keyptr = get_keyptr(); + + /* The procedure is the same as for IPv4, but addresses are longer. + * Thus we must use twothirdsMD4Transform. + */ + + memcpy(hash, saddr, 16); + hash[4] = ((__force u16)sport << 16) + (__force u16)dport; + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); + + seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; + seq += keyptr->count; + + seq += ktime_to_ns(ktime_get_real()); + + return seq; +} +EXPORT_SYMBOL(secure_tcpv6_sequence_number); +#endif + +/* The code below is shamelessly stolen from secure_tcp_sequence_number(). + * All blames to Andrey V. Savochkin . + */ +__u32 secure_ip_id(__be32 daddr) +{ + struct keydata *keyptr; + __u32 hash[4]; + + keyptr = get_keyptr(); + + /* + * Pick a unique starting offset for each IP destination. + * The dest ip address is placed in the starting vector, + * which is then hashed with random data. + */ + hash[0] = (__force __u32)daddr; + hash[1] = keyptr->secret[9]; + hash[2] = keyptr->secret[10]; + hash[3] = keyptr->secret[11]; + + return half_md4_transform(hash, keyptr->secret); +} + +#ifdef CONFIG_INET + +__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) +{ + __u32 seq; + __u32 hash[4]; + struct keydata *keyptr = get_keyptr(); + + /* + * Pick a unique starting offset for each TCP connection endpoints + * (saddr, daddr, sport, dport). + * Note that the words are placed into the starting vector, which is + * then mixed with a partial MD4 over random data. + */ + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; + hash[3] = keyptr->secret[11]; + + seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; + seq += keyptr->count; + /* + * As close as possible to RFC 793, which + * suggests using a 250 kHz clock. + * Further reading shows this assumes 2 Mb/s networks. + * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. + * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but + * we also need to limit the resolution so that the u32 seq + * overlaps less than one time per MSL (2 minutes). + * Choosing a clock of 64 ns period is OK. (period of 274 s) + */ + seq += ktime_to_ns(ktime_get_real()) >> 6; + + return seq; +} + +/* Generate secure starting point for ephemeral IPV4 transport port search */ +u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) +{ + struct keydata *keyptr = get_keyptr(); + u32 hash[4]; + + /* + * Pick a unique starting offset for each ephemeral port search + * (saddr, daddr, dport) and 48bits of random data. + */ + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = (__force u32)dport ^ keyptr->secret[10]; + hash[3] = keyptr->secret[11]; + + return half_md4_transform(hash, keyptr->secret); +} +EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, + __be16 dport) +{ + struct keydata *keyptr = get_keyptr(); + u32 hash[12]; + + memcpy(hash, saddr, 16); + hash[4] = (__force u32)dport; + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); + + return twothirdsMD4Transform((const __u32 *)daddr, hash); +} +#endif + +#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) +/* Similar to secure_tcp_sequence_number but generate a 48 bit value + * bit's 32-47 increase every key exchange + * 0-31 hash(source, dest) + */ +u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, + __be16 sport, __be16 dport) +{ + u64 seq; + __u32 hash[4]; + struct keydata *keyptr = get_keyptr(); + + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; + hash[3] = keyptr->secret[11]; + + seq = half_md4_transform(hash, keyptr->secret); + seq |= ((u64)keyptr->count) << (32 - HASH_BITS); + + seq += ktime_to_ns(ktime_get_real()); + seq &= (1ull << 48) - 1; + + return seq; +} +EXPORT_SYMBOL(secure_dccp_sequence_number); +#endif + +#endif /* CONFIG_INET */ + + +/* + * Get a random word for internal kernel use only. Similar to urandom but + * with the goal of minimal entropy pool depletion. As a result, the random + * value is not cryptographically secure but for several uses the cost of + * depleting entropy is too high + */ +unsigned int get_random_int(void) +{ + /* + * Use IP's RNG. It suits our purpose perfectly: it re-keys itself + * every second, from the entropy pool (and thus creates a limited + * drain on it), and uses halfMD4Transform within the second. We + * also mix it with jiffies and the PID: + */ + return secure_ip_id((__force __be32)(current->pid + jiffies)); +} + +/* + * randomize_range() returns a start address such that + * + * [...... .....] + * start end + * + * a with size "len" starting at the return value is inside in the + * area defined by [start, end], but is otherwise randomized. + */ +unsigned long +randomize_range(unsigned long start, unsigned long end, unsigned long len) +{ + unsigned long range = end - len - start; + + if (end <= start + len) + return 0; + return PAGE_ALIGN(get_random_int() % range + start); +} + +#endif diff --git a/libddekit/include/ddekit/resources.h b/libddekit/include/ddekit/resources.h index dfbb1322..657295a0 100644 --- a/libddekit/include/ddekit/resources.h +++ b/libddekit/include/ddekit/resources.h @@ -9,5 +9,6 @@ int ddekit_request_io (ddekit_addr_t start, ddekit_addr_t count); int ddekit_release_io (ddekit_addr_t start, ddekit_addr_t count); int ddekit_request_mem(ddekit_addr_t start, ddekit_addr_t count, ddekit_addr_t *vaddr); int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count); +long ddekit_random (void); #endif diff --git a/libddekit/resources.c b/libddekit/resources.c index 212dcae7..45704378 100644 --- a/libddekit/resources.c +++ b/libddekit/resources.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -117,3 +118,8 @@ int ddekit_release_mem(ddekit_addr_t start, ddekit_addr_t count) { } return 0; } + +long ddekit_random () +{ + return random (); +} -- cgit v1.2.3