From 8a6d48c0542876eb3acfc0970c0ab7872db08d5f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 05:26:23 +0100 Subject: check in the original version of dde linux26. --- libdde_linux26/lib/src/Makefile | 230 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 libdde_linux26/lib/src/Makefile (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile new file mode 100644 index 00000000..3707b2cb --- /dev/null +++ b/libdde_linux26/lib/src/Makefile @@ -0,0 +1,230 @@ +PKGDIR ?= ../../.. +L4DIR ?= $(PKGDIR)/../.. +CONTRIB ?= $(PKGDIR)/linux26/contrib + +-include $(PKGDIR_OBJ)/Makeconf + +ifeq ($(CONFIG_DDE26_COMMON),y) +TARGET += libdde_linux26.o.a +endif + +ifeq ($(CONFIG_DDE26_NET),y) +TARGET += libdde_linux26_net.a +endif + +ifeq ($(CONFIG_DDE26_BLOCK),y) +TARGET += libdde_linux26_block.a +endif + +ifeq ($(CONFIG_DDE26_SOUND),y) +TARGET += libdde_linux26_sound.a +endif + +ifeq ($(CONFIG_DDE26_CHAR),y) +TARGET += libdde_linux26_char.a +endif + +SYSTEMS = x86-l4v2 + +ifeq ($(ARCH), x86) +ARCH_DIR = arch/x86 +endif + +ifeq ($(ARCH), arm) +ARCH_DIR = arch/arm +MARCH = realview +DEFINES += -D__LINUX_ARM_ARCH__=6 +endif + +# contrib sources are in $(CONTRIB) +vpath %.c $(CONTRIB) +vpath %.S $(CONTRIB) + +PRIVATE_INCDIR += $(CONTRIB)/drivers/pci $(PKGDIR)/linux26/lib/src/arch/l4 \ + $(CONTRIB)/$(ARCH_DIR)/pci $(CONTRIB)/drivers/base/ \ + $(CONTRIB)/lib $(PKGDIR_OBJ) $(CONTRIB)/net/core $(CONTRIB)/fs + +################################################################## +# Sources for libdde_linux.a # +################################################################## +SRC_DDE = cli_sti.c fs.c hw-helpers.c init_task.c init.c pci.c power.c \ + process.c res.c sched.c signal.c smp.c softirq.c timer.c \ + page_alloc.c kmem_cache.c kmalloc.c irq.c param.c \ + vmalloc.c vmstat.c mm-helper.c + +# our implementation +SRC_C_libdde_linux26.o.a = $(addprefix arch/l4/, $(SRC_DDE)) + +ifeq ($(ARCH), x86) +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/semaphore_32.S +SRC_C_libdde_linux26.o.a += lib/rwsem.c +SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/kernel/pci-dma.c +SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/kernel/pci-nommu.c +SRC_S_libdde_linux26_net.a += $(ARCH_DIR)/lib/checksum_32.S +endif + +ifeq ($(ARCH), arm) +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/changebit.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/clearbit.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/div64.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/findbit.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/memzero.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/setbit.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/testclearbit.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/testchangebit.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/testsetbit.S +SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/kernel/semaphore.c +SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/kernel/traps.c +SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/mach-$(MARCH)/clock.c +SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/mach-$(MARCH)/realview_eb.c +SRC_C_libdde_linux26.o.a += lib/rwsem-spinlock.c +SRC_C_libdde_linux26.o.a += drivers/amba/bus.c +endif + +# + contrib stuff / slightly modified stuff +SRC_C_libdde_linux26.o.a += \ + kernel/exit.c \ + kernel/kthread.c \ + kernel/mutex.c \ + kernel/notifier.c \ + kernel/resource.c \ + kernel/rwsem.c \ + kernel/sched.c \ + kernel/semaphore.c \ + kernel/sys.c \ + kernel/time.c \ + kernel/timer.c \ + kernel/wait.c \ + kernel/workqueue.c \ + lib/bitmap.c \ + lib/bitrev.c \ + lib/crc32.c \ + lib/ctype.c \ + lib/cpumask.c \ + lib/find_next_bit.c \ + lib/hexdump.c \ + lib/idr.c \ + lib/iomap.c \ + lib/hweight.c \ + lib/kasprintf.c \ + lib/kernel_lock.c \ + lib/klist.c \ + lib/kobject.c \ + lib/kref.c \ + lib/parser.c \ + lib/proportions.c \ + lib/radix-tree.c \ + lib/scatterlist.c \ + lib/sha1.c \ + lib/string.c \ + lib/vsprintf.c \ + mm/dmapool.c \ + mm/mempool.c \ + mm/swap.c \ + mm/util.c \ + drivers/base/attribute_container.c \ + drivers/base/bus.c \ + drivers/base/class.c \ + drivers/base/core.c \ + drivers/base/cpu.c \ + drivers/base/dd.c \ + drivers/base/devres.c \ + drivers/base/driver.c \ + drivers/base/init.c \ + drivers/base/map.c \ + drivers/base/platform.c \ + drivers/base/sys.c \ + drivers/pci/access.c \ + drivers/pci/bus.c \ + drivers/pci/hotplug-pci.c \ + drivers/pci/pci.c \ + drivers/pci/pci-driver.c \ + drivers/pci/probe.c \ + drivers/pci/search.c \ + drivers/pci/setup-bus.c \ + drivers/pci/setup-res.c + +################################################################## +# Sources for libdde_linux_net.a # +################################################################## +SRC_C_libdde_linux26_net.a += \ + arch/l4/net.c \ + drivers/net/mii.c \ + net/core/dev.c \ + net/core/dev_mcast.c \ + net/core/ethtool.c \ + net/core/link_watch.c \ + net/core/neighbour.c \ + net/core/netevent.c \ + net/core/net-sysfs.c \ + net/core/net_namespace.c \ + net/core/rtnetlink.c \ + net/core/skbuff.c \ + net/core/skb_dma_map.c \ + net/core/utils.c \ + net/ethernet/eth.c \ + net/sched/sch_generic.c + +################################################################## +# Sources for libdde_linux_sound.a # +################################################################## +SRC_C_libdde_linux26_sound.a += \ + sound/sound_core.c \ + arch/l4/sound.c + +################################################################## +# Sources for libdde_linux_block.a # +################################################################## +# +SRC_C_libdde_linux26_block.a += \ + arch/l4/inodes.c \ + block/blk-barrier.c \ + block/blk-core.c \ + block/blk-exec.c \ + block/blk-ioc.c \ + block/blk-merge.c \ + block/blk-settings.c \ + block/blk-softirq.c \ + block/blk-sysfs.c \ + block/blk-tag.c \ + block/blk-timeout.c \ + block/elevator.c \ + block/genhd.c \ + block/noop-iosched.c \ + block/ioctl.c \ + block/scsi_ioctl.c \ + mm/backing-dev.c \ + mm/bounce.c \ + mm/page-writeback.c \ + fs/bio.c \ + fs/block_dev.c \ + fs/buffer.c \ + fs/filesystems.c +################################################################## +# Sources for libdde_linux_char.a # +################################################################## +SRC_C_libdde_linux26_char.a += \ + arch/l4/inodes.c \ + fs/char_dev.c + +all:: +lib/crc32.o : crc32table.h +lib/crc32.o : PRIVATE_INCDIR += . +kernel/time.o : timeconst.h +kernel/time.o : PRIVATE_INCDIR += . + +timeconst.h : $(SRC_DIR)/kernel/timeconst.pl + @$(GEN_MESSAGE) + $(VERBOSE)$< 250 >$@ + +crc32table.h : gen_crc32table + @$(GEN_MESSAGE) + $(VERBOSE)./$< >$@ + +gen_crc32table : lib/gen_crc32table.c + @$(GEN_MESSAGE) + $(VERBOSE)$(HOST_CC) -O2 -o $@ $< + +include $(PKGDIR)/linux26/Makeconf + +include $(L4DIR)/mk/lib.mk -- cgit v1.2.3 From de60719e36c86cd19e7ace9a1f1c485ce2af4060 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 21 Dec 2009 22:53:52 +0100 Subject: a temporary version of Makefiles for libdde_linux26 --- libdde_linux26/Makeconf | 51 +++++++++++++++++++ libdde_linux26/Makefile | 6 +-- libdde_linux26/contrib/Makefile | 6 ++- libdde_linux26/contrib/arch/x86/include/Makefile | 4 +- libdde_linux26/contrib/include/Makefile | 6 +-- libdde_linux26/include/Makefile | 6 +-- libdde_linux26/lib/Makefile | 10 ++-- libdde_linux26/lib/src/Makefile | 15 ++++-- libdde_linux26/lib/src/Makefile.inc | 50 ++++++++++++++++++ libdde_linux26/mk/Makeconf | 64 ++++++++++++------------ libdde_linux26/mk/include.mk | 2 +- libdde_linux26/mk/lib.mk | 3 +- libdde_linux26/mk/subdir.mk | 10 +--- 13 files changed, 168 insertions(+), 65 deletions(-) create mode 100644 libdde_linux26/Makeconf create mode 100644 libdde_linux26/lib/src/Makefile.inc (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/Makeconf b/libdde_linux26/Makeconf new file mode 100644 index 00000000..de84e39a --- /dev/null +++ b/libdde_linux26/Makeconf @@ -0,0 +1,51 @@ +# Linux 2.6 defines some macros on command line +KBUILD_DEFINES = -D"KBUILD_STR(s)=\#s" \ + -D"KBUILD_BASENAME=KBUILD_STR($(patsubst %.o, %, $(notdir $@)))" \ + -D"KBUILD_MODNAME=KBUILD_STR($(patsubst %.o, %, $@))" + +# for some reasons, Linux 2.6 does not include autoconf.h in the implementation +# files but does so on the command line +ifeq ($(ARCH), x86) +KBUILD_CPPFLAGS = -include linux/autoconf.h +endif + +ifeq ($(ARCH), arm) +KBUILD_CPPFLAGS = -include linux/autoconf-arm.h +endif + +# includes +MY_DDE_INCDIR = $(OBJ_BASE)/include/$(ARCH)/l4/dde/linux26 \ + $(OBJ_BASE)/include/l4/dde/linux26 + +SUFFIX_amd64 = x86_64 +SUFFIX_x86 = x86 +SUFFIX_arm = arm + +MY_LINUX26_INCDIR = $(OBJ_BASE)/include/$(ARCH)/l4/dde/linux26/linux-headers \ + $(OBJ_BASE)/include/$(ARCH)/l4/dde/linux26/asm \ + $(OBJ_BASE)/include/l4/dde/linux26/linux-headers + +# stolen from fiasco/src/Makeconf, checks whether a compiler supports a certain +# parameter +CHECKCC = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ + > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) + +# Linux always uses C... +MODE_USE_C = y +L4_MULTITHREADED = y + +# arch-specific stuff +ifeq ($(ARCH), x86) +MY_DDE_INCDIR += $(OBJ_BASE)/include/l4/dde/linux26/linux-headers/asm/mach-default +endif + +PRIVATE_INCDIR += $(MY_DDE_INCDIR) $(MY_LINUX26_INCDIR) + +DEFINES += -D__KERNEL__ -DDDE_LINUX $(KBUILD_DEFINES) +CPPFLAGS += $(KBUILD_CPPFLAGS) +CFLAGS += -ffunction-sections +ASFLAGS += -D__ASSEMBLY__ + +WARNINGS += -Wall -Wstrict-prototypes -fno-strict-aliasing +WARNINGS += $(call CHECKCC, -Wno-unused,) +WARNINGS += $(call CHECKCC, -Wno-pointer-sign,) diff --git a/libdde_linux26/Makefile b/libdde_linux26/Makefile index 5d180d78..092ea77e 100644 --- a/libdde_linux26/Makefile +++ b/libdde_linux26/Makefile @@ -1,6 +1,6 @@ -PKGDIR ?= .. -L4DIR ?= $(PKGDIR)/../.. +PKGDIR ?= . +L4DIR ?= $(PKGDIR) -TARGET = contrib include lib examples +TARGET = contrib include lib include $(L4DIR)/mk/subdir.mk diff --git a/libdde_linux26/contrib/Makefile b/libdde_linux26/contrib/Makefile index ec3eca26..232423de 100644 --- a/libdde_linux26/contrib/Makefile +++ b/libdde_linux26/contrib/Makefile @@ -1,5 +1,7 @@ -PKGDIR ?= ../.. -L4DIR ?= $(PKGDIR)/../.. +PKGDIR ?= .. +L4DIR ?= $(PKGDIR) + +BUILD_ARCH := x86 TARGET = include arch/$(BUILD_ARCH)/include diff --git a/libdde_linux26/contrib/arch/x86/include/Makefile b/libdde_linux26/contrib/arch/x86/include/Makefile index c374502c..665e84a2 100644 --- a/libdde_linux26/contrib/arch/x86/include/Makefile +++ b/libdde_linux26/contrib/arch/x86/include/Makefile @@ -1,5 +1,5 @@ -PKGDIR ?= ../../../../.. -L4DIR ?= $(PKGDIR)/../.. +PKGDIR ?= ../../../.. +L4DIR ?= $(PKGDIR) # Force these include files to appear in a special subfolder of dde/ INSTALL_INC_PREFIX = l4/dde/linux26/linux-headers/ diff --git a/libdde_linux26/contrib/include/Makefile b/libdde_linux26/contrib/include/Makefile index 009352f5..fa9f5f1b 100644 --- a/libdde_linux26/contrib/include/Makefile +++ b/libdde_linux26/contrib/include/Makefile @@ -1,8 +1,8 @@ -PKGDIR ?= ../../.. -L4DIR ?= $(PKGDIR)/../.. +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR) # Force these include files to appear in a special subfolder of dde/ -INSTALL_INC_PREFIX = l4/dde/linux26/linux-headers +INSTALL_INC_PREFIX = linux-headers include $(L4DIR)/mk/include.mk diff --git a/libdde_linux26/include/Makefile b/libdde_linux26/include/Makefile index a300aaaf..7584d036 100644 --- a/libdde_linux26/include/Makefile +++ b/libdde_linux26/include/Makefile @@ -1,10 +1,10 @@ -PKGDIR ?= ../.. -L4DIR ?= $(PKGDIR)/../.. +PKGDIR ?= .. +L4DIR ?= $(PKGDIR) # Force these include files to appear in a special subfolder of dde/ INSTALL_INC_PREFIX = l4/dde/linux26 -include $(L4DIR)/mk/Makeconf +#include $(L4DIR)/mk/Makeconf -include $(PKGDIR_OBJ)/Makeconf include $(L4DIR)/mk/include.mk diff --git a/libdde_linux26/lib/Makefile b/libdde_linux26/lib/Makefile index 0ea410d0..7e6ceb0c 100644 --- a/libdde_linux26/lib/Makefile +++ b/libdde_linux26/lib/Makefile @@ -1,11 +1,11 @@ -PKGDIR ?= ../.. -L4DIR ?= $(PKGDIR)/../.. +PKGDIR ?= .. +L4DIR ?= $(PKGDIR) -include $(L4DIR)/mk/Makeconf +#include $(L4DIR)/mk/Makeconf -include $(PKGDIR_OBJ)/Makeconf -ifeq ($(CONFIG_DDE26),y) +#ifeq ($(CONFIG_DDE26),y) TARGET = src src_ip -endif +#endif include $(L4DIR)/mk/subdir.mk diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 3707b2cb..7802479b 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -1,9 +1,15 @@ -PKGDIR ?= ../../.. -L4DIR ?= $(PKGDIR)/../.. -CONTRIB ?= $(PKGDIR)/linux26/contrib +PKGDIR ?= ../.. +L4DIR ?= $(PKGDIR) +CONTRIB ?= $(PKGDIR)/contrib -include $(PKGDIR_OBJ)/Makeconf +CONFIG_DDE26_COMMON := y +CONFIG_DDE26_NET := y +CONFIG_DDE26_BLOCK := y +CONFIG_DDE26_SOUND := y +CONFIG_DDE26_CHAR :=y + ifeq ($(CONFIG_DDE26_COMMON),y) TARGET += libdde_linux26.o.a endif @@ -25,6 +31,7 @@ TARGET += libdde_linux26_char.a endif SYSTEMS = x86-l4v2 +ARCH = x86 ifeq ($(ARCH), x86) ARCH_DIR = arch/x86 @@ -225,6 +232,6 @@ gen_crc32table : lib/gen_crc32table.c @$(GEN_MESSAGE) $(VERBOSE)$(HOST_CC) -O2 -o $@ $< -include $(PKGDIR)/linux26/Makeconf +include $(PKGDIR)/Makeconf include $(L4DIR)/mk/lib.mk diff --git a/libdde_linux26/lib/src/Makefile.inc b/libdde_linux26/lib/src/Makefile.inc new file mode 100644 index 00000000..12df220d --- /dev/null +++ b/libdde_linux26/lib/src/Makefile.inc @@ -0,0 +1,50 @@ +# automatically generated, do not edit! + +IDL_SRC_C_libdde_linux26.o.a= +IDL_SRC_C_libdde_linux26_net.a= +IDL_SRC_C_libdde_linux26_block.a= +IDL_SRC_C_libdde_linux26_sound.a= +IDL_SRC_C_libdde_linux26_char.a= +SRC_C_libdde_linux26.o.a += $(IDL_SRC_C_libdde_linux26.o.a) +SRC_C_libdde_linux26_net.a += $(IDL_SRC_C_libdde_linux26_net.a) +SRC_C_libdde_linux26_block.a += $(IDL_SRC_C_libdde_linux26_block.a) +SRC_C_libdde_linux26_sound.a += $(IDL_SRC_C_libdde_linux26_sound.a) +SRC_C_libdde_linux26_char.a += $(IDL_SRC_C_libdde_linux26_char.a) +Makefile.inc: IDL_SRC_C_libdde_linux26.o.a= +Makefile.inc: IDL_SRC_C_libdde_linux26_net.a= +Makefile.inc: IDL_SRC_C_libdde_linux26_block.a= +Makefile.inc: IDL_SRC_C_libdde_linux26_sound.a= +Makefile.inc: IDL_SRC_C_libdde_linux26_char.a= +IDL_SRC_CC_libdde_linux26.o.a= +IDL_SRC_CC_libdde_linux26_net.a= +IDL_SRC_CC_libdde_linux26_block.a= +IDL_SRC_CC_libdde_linux26_sound.a= +IDL_SRC_CC_libdde_linux26_char.a= +SRC_CC_libdde_linux26.o.a += $(IDL_SRC_CC_libdde_linux26.o.a) +SRC_CC_libdde_linux26_net.a += $(IDL_SRC_CC_libdde_linux26_net.a) +SRC_CC_libdde_linux26_block.a += $(IDL_SRC_CC_libdde_linux26_block.a) +SRC_CC_libdde_linux26_sound.a += $(IDL_SRC_CC_libdde_linux26_sound.a) +SRC_CC_libdde_linux26_char.a += $(IDL_SRC_CC_libdde_linux26_char.a) +Makefile.inc: IDL_SRC_CC_libdde_linux26.o.a= +Makefile.inc: IDL_SRC_CC_libdde_linux26_net.a= +Makefile.inc: IDL_SRC_CC_libdde_linux26_block.a= +Makefile.inc: IDL_SRC_CC_libdde_linux26_sound.a= +Makefile.inc: IDL_SRC_CC_libdde_linux26_char.a= +OBJS_libdde_linux26.o.a += arch/l4/cli_sti.o arch/l4/fs.o arch/l4/hw-helpers.o arch/l4/init_task.o arch/l4/init.o arch/l4/pci.o arch/l4/power.o arch/l4/process.o arch/l4/res.o arch/l4/sched.o arch/l4/signal.o arch/l4/smp.o arch/l4/softirq.o arch/l4/timer.o arch/l4/page_alloc.o arch/l4/kmem_cache.o arch/l4/kmalloc.o arch/l4/irq.o arch/l4/param.o arch/l4/vmalloc.o arch/l4/vmstat.o arch/l4/mm-helper.o lib/rwsem.o arch/x86/kernel/pci-dma.o arch/x86/kernel/pci-nommu.o kernel/exit.o kernel/kthread.o kernel/mutex.o kernel/notifier.o kernel/resource.o kernel/rwsem.o kernel/sched.o kernel/semaphore.o kernel/sys.o kernel/time.o kernel/timer.o kernel/wait.o kernel/workqueue.o lib/bitmap.o lib/bitrev.o lib/crc32.o lib/ctype.o lib/cpumask.o lib/find_next_bit.o lib/hexdump.o lib/idr.o lib/iomap.o lib/hweight.o lib/kasprintf.o lib/kernel_lock.o lib/klist.o lib/kobject.o lib/kref.o lib/parser.o lib/proportions.o lib/radix-tree.o lib/scatterlist.o lib/sha1.o lib/string.o lib/vsprintf.o mm/dmapool.o mm/mempool.o mm/swap.o mm/util.o drivers/base/attribute_container.o drivers/base/bus.o drivers/base/class.o drivers/base/core.o drivers/base/cpu.o drivers/base/dd.o drivers/base/devres.o drivers/base/driver.o drivers/base/init.o drivers/base/map.o drivers/base/platform.o drivers/base/sys.o drivers/pci/access.o drivers/pci/bus.o drivers/pci/hotplug-pci.o drivers/pci/pci.o drivers/pci/pci-driver.o drivers/pci/probe.o drivers/pci/search.o drivers/pci/setup-bus.o drivers/pci/setup-res.o arch/x86/lib/semaphore_32.o +OBJS_libdde_linux26_net.a += arch/l4/net.o drivers/net/mii.o net/core/dev.o net/core/dev_mcast.o net/core/ethtool.o net/core/link_watch.o net/core/neighbour.o net/core/netevent.o net/core/net-sysfs.o net/core/net_namespace.o net/core/rtnetlink.o net/core/skbuff.o net/core/skb_dma_map.o net/core/utils.o net/ethernet/eth.o net/sched/sch_generic.o arch/x86/lib/checksum_32.o +OBJS_libdde_linux26_block.a += arch/l4/inodes.o block/blk-barrier.o block/blk-core.o block/blk-exec.o block/blk-ioc.o block/blk-merge.o block/blk-settings.o block/blk-softirq.o block/blk-sysfs.o block/blk-tag.o block/blk-timeout.o block/elevator.o block/genhd.o block/noop-iosched.o block/ioctl.o block/scsi_ioctl.o mm/backing-dev.o mm/bounce.o mm/page-writeback.o fs/bio.o fs/block_dev.o fs/buffer.o fs/filesystems.o +OBJS_libdde_linux26_sound.a += sound/sound_core.o arch/l4/sound.o +OBJS_libdde_linux26_char.a += arch/l4/inodes.o fs/char_dev.o + + +libdde_linux26.o.a: $(OBJS_libdde_linux26.o.a) +libdde_linux26_net.a: $(OBJS_libdde_linux26_net.a) +libdde_linux26_block.a: $(OBJS_libdde_linux26_block.a) +libdde_linux26_sound.a: $(OBJS_libdde_linux26_sound.a) +libdde_linux26_char.a: $(OBJS_libdde_linux26_char.a) + +$(OBJS_libdde_linux26.o.a): .general.d +$(OBJS_libdde_linux26_net.a): .general.d +$(OBJS_libdde_linux26_block.a): .general.d +$(OBJS_libdde_linux26_sound.a): .general.d +$(OBJS_libdde_linux26_char.a): .general.d diff --git a/libdde_linux26/mk/Makeconf b/libdde_linux26/mk/Makeconf index 1c927e45..5a1e495c 100644 --- a/libdde_linux26/mk/Makeconf +++ b/libdde_linux26/mk/Makeconf @@ -139,19 +139,19 @@ findfile = $(firstword $(wildcard $(addsuffix /$(1),$(2))) $(1)_NOT_FOUND) # include this one early to be able to set OBJ_BASE -include $(L4DIR)/Makeconf.local -ifeq ($(filter $(IGNORE_OBJDIR_TARGETS),$(MAKECMDGOALS)),) +#ifeq ($(filter $(IGNORE_OBJDIR_TARGETS),$(MAKECMDGOALS)),) # output directory -ifeq ($(O)$(OBJ_BASE),) -$(error need to give builddir with O=.../builddir) -else -ifneq ($(O),) -ifeq ($(origin OBJ_BASE),undefined) -OBJ_BASE := $(call absfilename, $(O)) -export OBJ_BASE -endif -endif -endif -endif +#ifeq ($(O)$(OBJ_BASE),) +#$(error need to give builddir with O=.../builddir) +#else +#ifneq ($(O),) +#ifeq ($(origin OBJ_BASE),undefined) +#OBJ_BASE := $(call absfilename, $(O)) +#export OBJ_BASE +#endif +#endif +#endif +#endif ifeq ($(origin L4DIR_ABS),undefined) L4DIR_ABS := $(call absfilename,$(L4DIR)) @@ -207,25 +207,25 @@ VPATH_SRC_BASE ?= $(SRC_DIR) # Makeconf.local handling # dont use -include here, as we have special build conditions in $(L4DIR)/ -ifeq ($(origin BID_ROOT_CONF),undefined) -BID_ROOT_CONF := $(call absfilename, $(OBJ_BASE))/Makeconf.bid.local -endif -ifeq ($(filter $(IGNORE_OBJDIR_TARGETS),$(MAKECMDGOALS)),) -ifeq ($(wildcard $(BID_ROOT_CONF)),) -ifeq ($(BID_IGN_ROOT_CONF),) -$(error No configuration file found in build directory "$(OBJ_BASE)". Please run "make O=/path/to/objdir config" in "$(L4DIR_ABS)" or specify a valid build directory) -endif -else -include $(BID_ROOT_CONF) -endif -endif - --include $(L4DIR)/Makeconf.$(CONFIG_LABEL) - --include $(OBJ_BASE)/Makeconf.local -ifneq ($(PKGDIR),) --include $(PKGDIR)/Makeconf.local -endif +#ifeq ($(origin BID_ROOT_CONF),undefined) +#BID_ROOT_CONF := $(call absfilename, $(OBJ_BASE))/Makeconf.bid.local +#endif +#ifeq ($(filter $(IGNORE_OBJDIR_TARGETS),$(MAKECMDGOALS)),) +#ifeq ($(wildcard $(BID_ROOT_CONF)),) +#ifeq ($(BID_IGN_ROOT_CONF),) +#$(error No configuration file found in build directory "$(OBJ_BASE)". Please run "make O=/path/to/objdir config" in "$(L4DIR_ABS)" or specify a valid build directory) +#endif +#else +#include $(BID_ROOT_CONF) +#endif +#endif + +#-include $(L4DIR)/Makeconf.$(CONFIG_LABEL) + +#-include $(OBJ_BASE)/Makeconf.local +#ifneq ($(PKGDIR),) +#-include $(PKGDIR)/Makeconf.local +#endif # if it is not already set, we use this in the local dir MAKECONFLOCAL ?= Makeconf.local -include $(MAKECONFLOCAL) @@ -248,7 +248,7 @@ PL_j := -j $(PL) export PL endif -include $(L4DIR)/mk/config.inc +#include $(L4DIR)/mk/config.inc ifeq ($(HAVE_LDSO),y) # MAKEDEP-call: diff --git a/libdde_linux26/mk/include.mk b/libdde_linux26/mk/include.mk index 4725374b..3e325cd4 100644 --- a/libdde_linux26/mk/include.mk +++ b/libdde_linux26/mk/include.mk @@ -34,7 +34,7 @@ endif INSTALL_INC_PREFIX ?= l4/$(PKGNAME) INCSRC_DIR ?= $(SRC_DIR) -include $(L4DIR)/mk/Makeconf +#include $(L4DIR)/mk/Makeconf $(GENERAL_D_LOC): $(L4DIR)/mk/include.mk -include $(DEPSVAR) diff --git a/libdde_linux26/mk/lib.mk b/libdde_linux26/mk/lib.mk index 3ae24dbe..c96fcaaf 100644 --- a/libdde_linux26/mk/lib.mk +++ b/libdde_linux26/mk/lib.mk @@ -16,6 +16,7 @@ ifeq ($(origin _L4DIR_MK_LIB_MK),undefined) _L4DIR_MK_LIB_MK=y ROLE = lib.mk +SYSTEM = x86-l4v2 # define INSTALLDIRs prior to including install.inc, where the install- # rules are defined. Same for INSTALLDIR. @@ -60,7 +61,7 @@ LDFLAGS += $(LIBS) $(LDFLAGS_$@) $(LDNOSTDLIB) LDSCRIPT = $(call findfile,main_rel.ld,$(L4LIBDIR)) # install.inc eventually defines rules for every target -include $(L4DIR)/mk/install.inc +#include $(L4DIR)/mk/install.inc DEPS += $(foreach file,$(TARGET), $(dir $(file)).$(notdir $(file)).d) diff --git a/libdde_linux26/mk/subdir.mk b/libdde_linux26/mk/subdir.mk index 0f31b2d1..176200fe 100644 --- a/libdde_linux26/mk/subdir.mk +++ b/libdde_linux26/mk/subdir.mk @@ -6,18 +6,10 @@ # # 05/2002 Jork Loeser -include $(L4DIR)/mk/Makeconf +#include $(L4DIR)/mk/Makeconf -ifeq ($(PKGDIR),.) -TARGET ?= $(patsubst %/Makefile,%,$(wildcard $(addsuffix /Makefile, \ - idl include src lib server examples doc))) -$(if $(wildcard include/Makefile), idl lib server examples: include) -$(if $(wildcard idl/Makefile), lib server examples: idl) -$(if $(wildcard lib/Makefile), server examples: lib) -else TARGET ?= $(patsubst %/Makefile,%,$(wildcard $(addsuffix /Makefile, \ idl src lib server examples doc))) -endif SUBDIR_TARGET := $(if $(filter doc,$(MAKECMDGOALS)),$(TARGET), \ $(filter-out doc,$(TARGET))) -- cgit v1.2.3 From 7e9133b89dc05abed543420bca068ee5501beb31 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 5 Jan 2010 16:14:11 +0100 Subject: define SRC_DIR in Makefile in linux26/lib --- libdde_linux26/lib/src/Makefile | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 7802479b..be4104c1 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -3,6 +3,9 @@ L4DIR ?= $(PKGDIR) CONTRIB ?= $(PKGDIR)/contrib -include $(PKGDIR_OBJ)/Makeconf +ifeq ($(origin SRC_DIR),undefined) +SRC_DIR := $(shell pwd) +endif CONFIG_DDE26_COMMON := y CONFIG_DDE26_NET := y -- cgit v1.2.3 From adeade168d189df93ac07f771d852bfdf68e2f89 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Tue, 5 Jan 2010 16:15:11 +0100 Subject: Don't compile the sound component in linux26. --- libdde_linux26/lib/src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index be4104c1..21885805 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -10,7 +10,7 @@ endif CONFIG_DDE26_COMMON := y CONFIG_DDE26_NET := y CONFIG_DDE26_BLOCK := y -CONFIG_DDE26_SOUND := y +#CONFIG_DDE26_SOUND := y CONFIG_DDE26_CHAR :=y ifeq ($(CONFIG_DDE26_COMMON),y) -- cgit v1.2.3 From 2568808344d9e3cbb62edbb6404be2aff956052d Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 13 Jan 2010 11:45:56 +0100 Subject: move variables to Makeconf.local --- libdde_linux26/Makeconf | 2 -- libdde_linux26/Makeconf.local | 11 +++++++++++ libdde_linux26/lib/src/Makefile | 11 +---------- 3 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 libdde_linux26/Makeconf.local (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/Makeconf b/libdde_linux26/Makeconf index f81b29da..c84466f8 100644 --- a/libdde_linux26/Makeconf +++ b/libdde_linux26/Makeconf @@ -13,8 +13,6 @@ ifeq ($(ARCH), arm) KBUILD_CPPFLAGS = -include linux/autoconf-arm.h endif -OBJ_BASE = /root/hurd/libdde_linux26/build - # includes MY_DDE_INCDIR = $(OBJ_BASE)/include/$(ARCH) \ $(OBJ_BASE)/include/ diff --git a/libdde_linux26/Makeconf.local b/libdde_linux26/Makeconf.local new file mode 100644 index 00000000..aa6207c3 --- /dev/null +++ b/libdde_linux26/Makeconf.local @@ -0,0 +1,11 @@ +CONFIG_DDE26_COMMON := y +CONFIG_DDE26_NET := y +CONFIG_DDE26_BLOCK := y +#CONFIG_DDE26_SOUND := y +CONFIG_DDE26_CHAR :=y + +SYSTEMS = x86-l4v2 +ARCH = x86 +SYSTEM = x86-l4v2 + +OBJ_BASE = /root/hurd/libdde_linux26/build diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 21885805..8f31f9b8 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -2,17 +2,11 @@ PKGDIR ?= ../.. L4DIR ?= $(PKGDIR) CONTRIB ?= $(PKGDIR)/contrib --include $(PKGDIR_OBJ)/Makeconf +include $(PKGDIR)/Makeconf.local ifeq ($(origin SRC_DIR),undefined) SRC_DIR := $(shell pwd) endif -CONFIG_DDE26_COMMON := y -CONFIG_DDE26_NET := y -CONFIG_DDE26_BLOCK := y -#CONFIG_DDE26_SOUND := y -CONFIG_DDE26_CHAR :=y - ifeq ($(CONFIG_DDE26_COMMON),y) TARGET += libdde_linux26.o.a endif @@ -33,9 +27,6 @@ ifeq ($(CONFIG_DDE26_CHAR),y) TARGET += libdde_linux26_char.a endif -SYSTEMS = x86-l4v2 -ARCH = x86 - ifeq ($(ARCH), x86) ARCH_DIR = arch/x86 endif -- cgit v1.2.3 From 1b030ec21564529f29c2e557c2254b9f17e762ba Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 13 Jan 2010 11:47:18 +0100 Subject: fix a include path in dde linux26. --- libdde_linux26/Makeconf | 1 - libdde_linux26/lib/src/Makefile | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/Makeconf b/libdde_linux26/Makeconf index c84466f8..d5dc9c2a 100644 --- a/libdde_linux26/Makeconf +++ b/libdde_linux26/Makeconf @@ -23,7 +23,6 @@ SUFFIX_arm = arm MY_LINUX26_INCDIR = $(OBJ_BASE)/include/$(ARCH)/linux-headers \ $(OBJ_BASE)/include/$(ARCH)/asm \ - $(OBJ_BASE)/include/linux-headers/asm \ $(OBJ_BASE)/include/linux-headers # stolen from fiasco/src/Makeconf, checks whether a compiler supports a certain diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 8f31f9b8..b6670ed5 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -41,7 +41,7 @@ endif vpath %.c $(CONTRIB) vpath %.S $(CONTRIB) -PRIVATE_INCDIR += $(CONTRIB)/drivers/pci $(PKGDIR)/linux26/lib/src/arch/l4 \ +PRIVATE_INCDIR += $(CONTRIB)/drivers/pci $(PKGDIR)/lib/src/arch/l4 \ $(CONTRIB)/$(ARCH_DIR)/pci $(CONTRIB)/drivers/base/ \ $(CONTRIB)/lib $(PKGDIR_OBJ) $(CONTRIB)/net/core $(CONTRIB)/fs -- cgit v1.2.3 From 2bbc0548875321fa8660566254699cbab9aa00e9 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 29 Jan 2010 20:31:20 +0100 Subject: libdde_linux26 is adapted to be used by libmachdev. --- libdde_linux26/contrib/include/linux/skbuff.h | 5 ++ libdde_linux26/include/dde26_net.h | 9 ++- libdde_linux26/lib/src/Makefile | 1 + libdde_linux26/lib/src/arch/l4/mach_glue.c | 85 +++++++++++++++++++++++++++ libdde_linux26/lib/src/net/core/skbuff.c | 11 ++++ 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 libdde_linux26/lib/src/arch/l4/mach_glue.c (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/contrib/include/linux/skbuff.h b/libdde_linux26/contrib/include/linux/skbuff.h index 9dcf956a..a9e9534d 100644 --- a/libdde_linux26/contrib/include/linux/skbuff.h +++ b/libdde_linux26/contrib/include/linux/skbuff.h @@ -354,6 +354,11 @@ struct sk_buff { *data; unsigned int truesize; atomic_t users; + +#ifdef DDE_LINUX + void *del_data; + int (*pre_del_func) (struct sk_buff *, void *); +#endif }; #ifdef __KERNEL__ diff --git a/libdde_linux26/include/dde26_net.h b/libdde_linux26/include/dde26_net.h index 2c3847b8..4545e7cc 100644 --- a/libdde_linux26/include/dde26_net.h +++ b/libdde_linux26/include/dde26_net.h @@ -2,9 +2,10 @@ #define __DDE_26_NET_H #include +#include /** rx callback function */ -typedef int (*linux_rx_callback)(struct sk_buff *); +typedef int (*linux_rx_callback)(char *, int, struct net_device *); extern linux_rx_callback l4dde26_rx_callback; @@ -25,8 +26,10 @@ linux_rx_callback l4dde26_register_rx_callback(linux_rx_callback cb); */ static inline int l4dde26_do_rx_callback(struct sk_buff *s) { - if (l4dde26_rx_callback != NULL) - return l4dde26_rx_callback(s); + if (l4dde26_rx_callback != NULL) { + skb_push(s, s->dev->hard_header_len); + return l4dde26_rx_callback(s->data, s->len, s->dev); + } return 0; } diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index b6670ed5..d06a8d6b 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -150,6 +150,7 @@ SRC_C_libdde_linux26.o.a += \ ################################################################## SRC_C_libdde_linux26_net.a += \ arch/l4/net.c \ + arch/l4/mach_glue.c \ drivers/net/mii.c \ net/core/dev.c \ net/core/dev_mcast.c \ diff --git a/libdde_linux26/lib/src/arch/l4/mach_glue.c b/libdde_linux26/lib/src/arch/l4/mach_glue.c new file mode 100644 index 00000000..9130c550 --- /dev/null +++ b/libdde_linux26/lib/src/arch/l4/mach_glue.c @@ -0,0 +1,85 @@ +#include +#include + +#define D_INVALID_SIZE 2507 +#define D_NO_MEMORY 2508 + +/* List of sk_buffs waiting to be freed. */ +static struct sk_buff_head skb_done_list; + +struct net_device *search_netdev (char *name) +{ + struct net_device *dev; + struct net *net; + + read_lock(&dev_base_lock); + for_each_net(net) { + for_each_netdev(net, dev) { + if (!strcmp (name, dev->name) + && dev->base_addr && dev->base_addr != 0xffe0) + goto end; + } + } +end: + read_unlock(&dev_base_lock); + return dev; +} + +int linux_pkg_xmit (char *pkg_data, int len, void *del_data, + int (*del_func) (struct sk_buff *, void *), + struct net_device *dev) +{ + struct sk_buff *skb; + + if (len == 0 || len > dev->mtu + dev->hard_header_len) + return D_INVALID_SIZE; + + /* Allocate a sk_buff. */ + skb = dev_alloc_skb (len); + if (!skb) + return D_NO_MEMORY; + + skb->del_data = del_data; + skb->pre_del_func = del_func; + + /* Copy user data. This is only required if it spans multiple pages. */ + skb->len = len; + skb->tail = skb->data + len; + skb->end = skb->tail; + + memcpy (skb->data, pkg_data, len); + + skb->dev = dev; + + return dev->netdev_ops->ndo_start_xmit(skb, dev); +} + +char *netdev_addr(struct net_device *dev) +{ + return dev->dev_addr; +} + +int netdev_flags(struct net_device *dev) +{ + return dev->flags; +} + +void *skb_reply(struct sk_buff *skb) +{ + return skb->del_data; +} + +void skb_done_head_init() +{ + skb_queue_head_init (&skb_done_list); +} + +struct sk_buff *skb_done_dequeue() +{ + return skb_dequeue (&skb_done_list); +} + +void skb_done_queue(struct sk_buff *skb) +{ + skb_queue_tail (&skb_done_list, skb); +} diff --git a/libdde_linux26/lib/src/net/core/skbuff.c b/libdde_linux26/lib/src/net/core/skbuff.c index 59b275b0..853b535b 100644 --- a/libdde_linux26/lib/src/net/core/skbuff.c +++ b/libdde_linux26/lib/src/net/core/skbuff.c @@ -421,6 +421,11 @@ static void skb_release_all(struct sk_buff *skb) void __kfree_skb(struct sk_buff *skb) { +#ifdef DDE_LINUX + if (skb->del_data && skb->pre_del_func + && skb->pre_del_func(skb, skb->del_data)) + return; +#endif skb_release_all(skb); kfree_skbmem(skb); } @@ -436,6 +441,12 @@ void kfree_skb(struct sk_buff *skb) { if (unlikely(!skb)) return; +#ifdef DDE_LINUX + if (atomic_read(&skb->users) == 0) { + __kfree_skb(skb); + return; + } +#endif if (likely(atomic_read(&skb->users) == 1)) smp_rmb(); else if (likely(!atomic_dec_and_test(&skb->users))) -- cgit v1.2.3 From a6f85451bd2b4e21e40fca89281859f6a71a53fd Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 29 Jan 2010 22:16:51 +0100 Subject: Reorganize Makefile. --- libdde_linux26/lib/src/Makefile | 210 ++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 105 deletions(-) (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index d06a8d6b..3743f91b 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -50,7 +50,7 @@ PRIVATE_INCDIR += $(CONTRIB)/drivers/pci $(PKGDIR)/lib/src/arch/l4 \ ################################################################## SRC_DDE = cli_sti.c fs.c hw-helpers.c init_task.c init.c pci.c power.c \ process.c res.c sched.c signal.c smp.c softirq.c timer.c \ - page_alloc.c kmem_cache.c kmalloc.c irq.c param.c \ + page_alloc.c kmem_cache.c kmalloc.c irq.c param.c \ vmalloc.c vmstat.c mm-helper.c # our implementation @@ -84,130 +84,130 @@ endif # + contrib stuff / slightly modified stuff SRC_C_libdde_linux26.o.a += \ - kernel/exit.c \ - kernel/kthread.c \ - kernel/mutex.c \ - kernel/notifier.c \ - kernel/resource.c \ - kernel/rwsem.c \ - kernel/sched.c \ - kernel/semaphore.c \ - kernel/sys.c \ - kernel/time.c \ - kernel/timer.c \ - kernel/wait.c \ - kernel/workqueue.c \ - lib/bitmap.c \ - lib/bitrev.c \ - lib/crc32.c \ - lib/ctype.c \ - lib/cpumask.c \ - lib/find_next_bit.c \ - lib/hexdump.c \ - lib/idr.c \ - lib/iomap.c \ - lib/hweight.c \ - lib/kasprintf.c \ - lib/kernel_lock.c \ - lib/klist.c \ - lib/kobject.c \ - lib/kref.c \ - lib/parser.c \ - lib/proportions.c \ - lib/radix-tree.c \ - lib/scatterlist.c \ - lib/sha1.c \ - lib/string.c \ - lib/vsprintf.c \ - mm/dmapool.c \ - mm/mempool.c \ - mm/swap.c \ - mm/util.c \ - drivers/base/attribute_container.c \ - drivers/base/bus.c \ - drivers/base/class.c \ - drivers/base/core.c \ - drivers/base/cpu.c \ - drivers/base/dd.c \ - drivers/base/devres.c \ - drivers/base/driver.c \ - drivers/base/init.c \ - drivers/base/map.c \ - drivers/base/platform.c \ - drivers/base/sys.c \ - drivers/pci/access.c \ - drivers/pci/bus.c \ - drivers/pci/hotplug-pci.c \ - drivers/pci/pci.c \ - drivers/pci/pci-driver.c \ - drivers/pci/probe.c \ - drivers/pci/search.c \ - drivers/pci/setup-bus.c \ - drivers/pci/setup-res.c + kernel/exit.c \ + kernel/kthread.c \ + kernel/mutex.c \ + kernel/notifier.c \ + kernel/resource.c \ + kernel/rwsem.c \ + kernel/sched.c \ + kernel/semaphore.c \ + kernel/sys.c \ + kernel/time.c \ + kernel/timer.c \ + kernel/wait.c \ + kernel/workqueue.c \ + lib/bitmap.c \ + lib/bitrev.c \ + lib/crc32.c \ + lib/ctype.c \ + lib/cpumask.c \ + lib/find_next_bit.c \ + lib/hexdump.c \ + lib/idr.c \ + lib/iomap.c \ + lib/hweight.c \ + lib/kasprintf.c \ + lib/kernel_lock.c \ + lib/klist.c \ + lib/kobject.c \ + lib/kref.c \ + lib/parser.c \ + lib/proportions.c \ + lib/radix-tree.c \ + lib/scatterlist.c \ + lib/sha1.c \ + lib/string.c \ + lib/vsprintf.c \ + mm/dmapool.c \ + mm/mempool.c \ + mm/swap.c \ + mm/util.c \ + drivers/base/attribute_container.c \ + drivers/base/bus.c \ + drivers/base/class.c \ + drivers/base/core.c \ + drivers/base/cpu.c \ + drivers/base/dd.c \ + drivers/base/devres.c \ + drivers/base/driver.c \ + drivers/base/init.c \ + drivers/base/map.c \ + drivers/base/platform.c \ + drivers/base/sys.c \ + drivers/pci/access.c \ + drivers/pci/bus.c \ + drivers/pci/hotplug-pci.c \ + drivers/pci/pci.c \ + drivers/pci/pci-driver.c \ + drivers/pci/probe.c \ + drivers/pci/search.c \ + drivers/pci/setup-bus.c \ + drivers/pci/setup-res.c ################################################################## # Sources for libdde_linux_net.a # ################################################################## SRC_C_libdde_linux26_net.a += \ - arch/l4/net.c \ - arch/l4/mach_glue.c \ - drivers/net/mii.c \ - net/core/dev.c \ - net/core/dev_mcast.c \ - net/core/ethtool.c \ - net/core/link_watch.c \ - net/core/neighbour.c \ - net/core/netevent.c \ - net/core/net-sysfs.c \ - net/core/net_namespace.c \ - net/core/rtnetlink.c \ - net/core/skbuff.c \ - net/core/skb_dma_map.c \ - net/core/utils.c \ - net/ethernet/eth.c \ - net/sched/sch_generic.c + arch/l4/net.c \ + arch/l4/mach_glue.c \ + drivers/net/mii.c \ + net/core/dev.c \ + net/core/dev_mcast.c \ + net/core/ethtool.c \ + net/core/link_watch.c \ + net/core/neighbour.c \ + net/core/netevent.c \ + net/core/net-sysfs.c \ + net/core/net_namespace.c \ + net/core/rtnetlink.c \ + net/core/skbuff.c \ + net/core/skb_dma_map.c \ + net/core/utils.c \ + net/ethernet/eth.c \ + net/sched/sch_generic.c ################################################################## # Sources for libdde_linux_sound.a # ################################################################## SRC_C_libdde_linux26_sound.a += \ - sound/sound_core.c \ - arch/l4/sound.c + sound/sound_core.c \ + arch/l4/sound.c ################################################################## # Sources for libdde_linux_block.a # ################################################################## # SRC_C_libdde_linux26_block.a += \ - arch/l4/inodes.c \ - block/blk-barrier.c \ - block/blk-core.c \ - block/blk-exec.c \ - block/blk-ioc.c \ - block/blk-merge.c \ - block/blk-settings.c \ - block/blk-softirq.c \ - block/blk-sysfs.c \ - block/blk-tag.c \ - block/blk-timeout.c \ - block/elevator.c \ - block/genhd.c \ - block/noop-iosched.c \ - block/ioctl.c \ - block/scsi_ioctl.c \ - mm/backing-dev.c \ - mm/bounce.c \ - mm/page-writeback.c \ - fs/bio.c \ - fs/block_dev.c \ - fs/buffer.c \ - fs/filesystems.c + arch/l4/inodes.c \ + block/blk-barrier.c \ + block/blk-core.c \ + block/blk-exec.c \ + block/blk-ioc.c \ + block/blk-merge.c \ + block/blk-settings.c \ + block/blk-softirq.c \ + block/blk-sysfs.c \ + block/blk-tag.c \ + block/blk-timeout.c \ + block/elevator.c \ + block/genhd.c \ + block/noop-iosched.c \ + block/ioctl.c \ + block/scsi_ioctl.c \ + mm/backing-dev.c \ + mm/bounce.c \ + mm/page-writeback.c \ + fs/bio.c \ + fs/block_dev.c \ + fs/buffer.c \ + fs/filesystems.c ################################################################## # Sources for libdde_linux_char.a # ################################################################## SRC_C_libdde_linux26_char.a += \ - arch/l4/inodes.c \ - fs/char_dev.c + arch/l4/inodes.c \ + fs/char_dev.c all:: lib/crc32.o : crc32table.h -- cgit v1.2.3 From 21bf6f025d94c2987dfe30a0b327b6dfab7a8bff Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Fri, 4 Jun 2010 16:51:24 +0200 Subject: support block devices in the DDE library. --- libdde_linux26/lib/src/Makefile | 3 +- libdde_linux26/lib/src/arch/l4/mach_glue.c | 87 ---------- libdde_linux26/lib/src/mach_glue/block.c | 77 +++++++++ libdde_linux26/lib/src/mach_glue/net.c | 87 ++++++++++ libmachdev/Makefile | 2 +- libmachdev/block.c | 250 +++++++++++++++++++++++++++++ libmachdev/mach_glue.h | 30 ++++ libmachdev/machdev.h | 1 + libmachdev/net.c | 19 +-- windhoek/Makefile | 4 +- windhoek/main.c | 1 + 11 files changed, 453 insertions(+), 108 deletions(-) delete mode 100644 libdde_linux26/lib/src/arch/l4/mach_glue.c create mode 100644 libdde_linux26/lib/src/mach_glue/block.c create mode 100644 libdde_linux26/lib/src/mach_glue/net.c create mode 100644 libmachdev/block.c create mode 100644 libmachdev/mach_glue.h (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 3743f91b..947f11b9 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -150,7 +150,7 @@ SRC_C_libdde_linux26.o.a += \ ################################################################## SRC_C_libdde_linux26_net.a += \ arch/l4/net.c \ - arch/l4/mach_glue.c \ + mach_glue/net.c \ drivers/net/mii.c \ net/core/dev.c \ net/core/dev_mcast.c \ @@ -180,6 +180,7 @@ SRC_C_libdde_linux26_sound.a += \ # SRC_C_libdde_linux26_block.a += \ arch/l4/inodes.c \ + mach_glue/block.c \ block/blk-barrier.c \ block/blk-core.c \ block/blk-exec.c \ diff --git a/libdde_linux26/lib/src/arch/l4/mach_glue.c b/libdde_linux26/lib/src/arch/l4/mach_glue.c deleted file mode 100644 index 48373a90..00000000 --- a/libdde_linux26/lib/src/arch/l4/mach_glue.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include - -/* List of sk_buffs waiting to be freed. */ -static struct sk_buff_head skb_done_list; - -struct net_device *search_netdev (char *name) -{ - struct net_device *dev; - struct net_device *found = NULL; - struct net *net; - - printk("search device %s\n", name); - read_lock(&dev_base_lock); - for_each_net(net) { - for_each_netdev(net, dev) { - printk("there is device %s, base addr: %x\n", - dev->name, dev->base_addr); - if (!strcmp (name, dev->name)) - { - found = dev; - goto end; - } - } - } -end: - read_unlock(&dev_base_lock); - return found; -} - -int linux_pkg_xmit (char *pkg_data, int len, void *del_data, - int (*del_func) (struct sk_buff *, void *), - struct net_device *dev) -{ - struct sk_buff *skb; - - if (len == 0 || len > dev->mtu + dev->hard_header_len) - return EINVAL; - - /* Allocate a sk_buff. */ - skb = dev_alloc_skb (len); - if (!skb) - return ENOMEM; - - skb->del_data = del_data; - skb->pre_del_func = del_func; - - /* Copy user data. This is only required if it spans multiple pages. */ - skb->len = len; - skb->tail = skb->data + len; - - memcpy (skb->data, pkg_data, len); - - skb->dev = dev; - - return dev_queue_xmit(skb); -} - -char *netdev_addr(struct net_device *dev) -{ - return dev->dev_addr; -} - -int netdev_flags(struct net_device *dev) -{ - return dev->flags; -} - -void *skb_reply(struct sk_buff *skb) -{ - return skb->del_data; -} - -void skb_done_head_init() -{ - skb_queue_head_init (&skb_done_list); -} - -struct sk_buff *skb_done_dequeue() -{ - return skb_dequeue (&skb_done_list); -} - -void skb_done_queue(struct sk_buff *skb) -{ - skb_queue_tail (&skb_done_list, skb); -} diff --git a/libdde_linux26/lib/src/mach_glue/block.c b/libdde_linux26/lib/src/mach_glue/block.c new file mode 100644 index 00000000..7eac7e46 --- /dev/null +++ b/libdde_linux26/lib/src/mach_glue/block.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +struct gendisk *find_disk_by_name (char *); +void dde_page_cache_add (struct page *); + +struct block_device *open_block_dev (char *name, int part, fmode_t mode) +{ + struct gendisk *disk = find_disk_by_name (name); + dev_t devid = MKDEV (disk->major, disk->first_minor + part); + return open_by_devnum (devid, mode); +} + +/* write a piece of data to a block device. + * DATA must be in one page. + * SECTORNR: the writing location in sectors. */ +int block_dev_write (struct block_device *dev, int sectornr, + char *data, int count, void (*write_done (int err))) +{ + int err = 0; + struct bio *bio; + struct page *page; + int i; + + void end_bio (struct bio *bio, int err) + { + write_done (err); + } + + assert (count <= PAGE_SIZE); + bio = bio_alloc (GFP_NOIO, 1); + if (bio == NULL) + { + err = ENOMEM; + goto out; + } + + page = kmalloc (sizeof (*page), GFP_KERNEL); + if (page == NULL) + { + err = ENOMEM; + goto out; + } + + bio->bi_sector = sectornr; + bio->bi_bdev = dev; + page->virtual = data; + dde_page_cache_add (page); + bio->bi_io_vec[0].bv_page = page; + bio->bi_io_vec[0].bv_len = count; + bio->bi_io_vec[0].bv_offset = (int) data & ~PAGE_MASK; + + bio->bi_vcnt = 1; + bio->bi_idx = 0; + bio->bi_size = count; + + bio->bi_end_io = end_bio; + bio->bi_private = NULL; + bio_get (bio); + submit_bio (WRITE, bio); + if (bio_flagged (bio, BIO_EOPNOTSUPP)) + { + err = -EOPNOTSUPP; + goto out; + } + bio_put (bio); +out: + if (err) + { + if (bio) + bio_put (bio); + kfree (page); + } + return err; +} diff --git a/libdde_linux26/lib/src/mach_glue/net.c b/libdde_linux26/lib/src/mach_glue/net.c new file mode 100644 index 00000000..48373a90 --- /dev/null +++ b/libdde_linux26/lib/src/mach_glue/net.c @@ -0,0 +1,87 @@ +#include +#include + +/* List of sk_buffs waiting to be freed. */ +static struct sk_buff_head skb_done_list; + +struct net_device *search_netdev (char *name) +{ + struct net_device *dev; + struct net_device *found = NULL; + struct net *net; + + printk("search device %s\n", name); + read_lock(&dev_base_lock); + for_each_net(net) { + for_each_netdev(net, dev) { + printk("there is device %s, base addr: %x\n", + dev->name, dev->base_addr); + if (!strcmp (name, dev->name)) + { + found = dev; + goto end; + } + } + } +end: + read_unlock(&dev_base_lock); + return found; +} + +int linux_pkg_xmit (char *pkg_data, int len, void *del_data, + int (*del_func) (struct sk_buff *, void *), + struct net_device *dev) +{ + struct sk_buff *skb; + + if (len == 0 || len > dev->mtu + dev->hard_header_len) + return EINVAL; + + /* Allocate a sk_buff. */ + skb = dev_alloc_skb (len); + if (!skb) + return ENOMEM; + + skb->del_data = del_data; + skb->pre_del_func = del_func; + + /* Copy user data. This is only required if it spans multiple pages. */ + skb->len = len; + skb->tail = skb->data + len; + + memcpy (skb->data, pkg_data, len); + + skb->dev = dev; + + return dev_queue_xmit(skb); +} + +char *netdev_addr(struct net_device *dev) +{ + return dev->dev_addr; +} + +int netdev_flags(struct net_device *dev) +{ + return dev->flags; +} + +void *skb_reply(struct sk_buff *skb) +{ + return skb->del_data; +} + +void skb_done_head_init() +{ + skb_queue_head_init (&skb_done_list); +} + +struct sk_buff *skb_done_dequeue() +{ + return skb_dequeue (&skb_done_list); +} + +void skb_done_queue(struct sk_buff *skb) +{ + skb_queue_tail (&skb_done_list, skb); +} diff --git a/libmachdev/Makefile b/libmachdev/Makefile index 2bd294ad..7475d041 100644 --- a/libmachdev/Makefile +++ b/libmachdev/Makefile @@ -20,7 +20,7 @@ makemode := library libname = libmachdev SRCS = deviceUser.c machUser.c net.c ds_routines.c queue.c trivfs_server.c \ - device_replyUser.c deviceServer.c notifyServer.c misc.c + device_replyUser.c deviceServer.c notifyServer.c misc.c block.c LCLHDRS = dev_hdr.h device_emul.h ds_routines.h vm_param.h \ util.h queue.h io_req.h if_ether.h machdev.h linux-errno.h \ errno-base.h diff --git a/libmachdev/block.c b/libmachdev/block.c new file mode 100644 index 00000000..54048fde --- /dev/null +++ b/libmachdev/block.c @@ -0,0 +1,250 @@ +/* + * Linux block driver support. + * + * 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 + +#include "mach_U.h" + +#include +#include + +#define MACH_INCLUDE + +#include + +#include "vm_param.h" +#include "device_reply_U.h" +#include "dev_hdr.h" +#include "util.h" +#include "mach_glue.h" + +/* One of these is associated with each open instance of a device. */ +struct block_data +{ + struct port_info port; /* device port */ + struct emul_device device; /* generic device structure */ + dev_mode_t mode; + struct block_device *dev; +}; + +/* Return a send right associated with network device ND. */ +static mach_port_t +dev_to_port (void *nd) +{ + return (nd + ? ports_get_send_right (nd) + : MACH_PORT_NULL); +} + +extern struct device_emulation_ops linux_block_emulation_ops; + +#define DISK_NAME_LEN 32 + +/* Parse the device NAME. + Set *SLICE to be the DOS partition and + *PART the BSD/Mach partition, if any. */ +static char * +translate_name (char *name, int *slice, int *part) +{ + char *p, *q, *end; + char *ret; + int disk_num; + + /* Parse name into name, unit, DOS partition (slice) and partition. */ + for (*slice = 0, *part = -1, p = name; isalpha (*p); p++) + ; + if (p == name || ! isdigit (*p)) + return NULL; + end = p; + disk_num = strtol (p, &p, 0); + if (disk_num < 0 || disk_num > 26) + return NULL; +// do +// p++; +// while (isdigit (*p)); + if (*p) + { + q = p; + if (*q == 's' && isdigit (*(q + 1))) + { + q++; + do + *slice = *slice * 10 + *q++ - '0'; + while (isdigit (*q)); + if (! *q) + goto find_major; + } + if (! isalpha (*q) || *(q + 1)) + return NULL; + *part = *q - 'a'; + } + +find_major: + ret = malloc (DISK_NAME_LEN); + sprintf (ret, "hd%c", 'a' + disk_num); + return ret; +} + +static io_return_t +device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, + dev_mode_t mode, char *name, device_t *devp) +{ + io_return_t err = D_SUCCESS; + struct block_data *bd = NULL; + int slice, part; + char *dev_name = NULL; + + dev_name = translate_name (name, &slice, &part); + + // TODO when the port isn't used by clients, it should be destroyed. + err = create_device_port (sizeof (*bd), &bd); + if (err) + { + ddekit_printf ("after create_device_port: cannot create a port\n"); + goto out; + } + bd->dev = open_block_dev (dev_name, slice, mode); + if (bd->dev < 0) + { + ddekit_printf ("open_block_dev fails with %d\n", bd->dev); + err = linux_to_mach_error (err); + goto out; + } + bd->device.emul_data = bd; + bd->device.emul_ops = &linux_block_emulation_ops; + bd->mode = mode; + +out: + free (dev_name); + if (err) + { + if (bd) + { + ports_destroy_right (bd); + bd = NULL; + } + } + else + *devp = ports_get_right (bd); + return err; +} + +static io_return_t +device_write (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, io_buf_ptr_t data, unsigned int count, + int *bytes_written) +{ + struct block_data *bd = d; + /* the number of pages that contain DATA. */ + int npages = (((int) data + count) - ((int) data & ~PAGE_MASK) + + PAGE_MASK) / PAGE_SIZE; + io_return_t err = D_SUCCESS; + int i; + int writes = 0; + + void write_done (int err) + { + int len = err ? 0 : count; + writes--; + if (writes == 0) + { + err = linux_to_mach_error (err); + ds_device_write_reply (reply_port, reply_port_type, err, len); + } + } + + /* the data is at the beginning of a page. */ + if ((int) data & ~PAGE_MASK) + return D_INVALID_OPERATION; + + if ((bd->mode & D_WRITE) == 0) + return D_INVALID_OPERATION; + + for (i = 0; i < npages; i++) + { + int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ? + PAGE_SIZE - ((int) data &~PAGE_MASK) : count; + + err = block_dev_write (bd->dev, bn, data, count, write_done); + if (err) + break; + bn += count >> 9; + data += size; + count -= size; + writes++; + } + if (writes) + return MIG_NO_REPLY; + return linux_to_mach_error (err); +} + +static io_return_t +device_read (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, int count, io_buf_ptr_t *data, + unsigned *bytes_read) +{ + struct block_data *bd = d; + + if ((bd->mode & D_READ) == 0) + return D_INVALID_OPERATION; + *bytes_read = 0; + return D_SUCCESS; +} + +static io_return_t +device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t *count) +{ + struct block_data *bd = (struct block_data *) d; + return D_SUCCESS; +} + +struct device_emulation_ops linux_block_emulation_ops = +{ + NULL, + NULL, + dev_to_port, + device_open, + NULL, + device_write, + NULL, + device_read, + NULL, + NULL, + device_get_status, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +void register_block() +{ + extern void reg_dev_emul (struct device_emulation_ops *ops); + reg_dev_emul (&linux_block_emulation_ops); +} diff --git a/libmachdev/mach_glue.h b/libmachdev/mach_glue.h new file mode 100644 index 00000000..6d0870ed --- /dev/null +++ b/libmachdev/mach_glue.h @@ -0,0 +1,30 @@ +#ifndef __MACH_GLUE_H__ +#define __MACH_GLUE_H__ + +/* network */ +#include + +struct sk_buff; +struct net_device; +void skb_done_queue(struct sk_buff *skb); +struct sk_buff *skb_done_dequeue(); +void *skb_reply(struct sk_buff *skb); +int netdev_flags(struct net_device *dev); +char *netdev_addr(struct net_device *dev); +int dev_change_flags (struct net_device *dev, short flags); +int linux_pkg_xmit (char *pkg_data, int len, void *del_data, + int (*del_func) (struct sk_buff *, void *), + struct net_device *dev); +struct net_device *search_netdev (char *name); +void kfree_skb (struct sk_buff *skb); +int dev_open(struct net_device *dev); +void *l4dde26_register_rx_callback(void *cb); +void skb_done_head_init(); + +/* block device */ +struct block_device; +struct block_device *open_block_dev (char *name, int part, dev_mode_t mode); +int block_dev_write (struct block_device *dev, int sectornr, + char *data, int count, void (*write_done) (int err)); + +#endif diff --git a/libmachdev/machdev.h b/libmachdev/machdev.h index 27c488a5..cfa4b2d4 100644 --- a/libmachdev/machdev.h +++ b/libmachdev/machdev.h @@ -26,6 +26,7 @@ void ds_server(void); void mach_device_init(void); void register_net(void); +void register_block(void); void trivfs_server(void); int trivfs_init(void); diff --git a/libmachdev/net.c b/libmachdev/net.c index b21d6333..8c435b4b 100644 --- a/libmachdev/net.c +++ b/libmachdev/net.c @@ -74,6 +74,7 @@ #include "dev_hdr.h" #include "if_ether.h" #include "util.h" +#include "mach_glue.h" #define ether_header ethhdr @@ -99,22 +100,6 @@ struct skb_reply int pkglen; }; -struct sk_buff; -void skb_done_queue(struct sk_buff *skb); -struct sk_buff *skb_done_dequeue(); -void *skb_reply(struct sk_buff *skb); -int netdev_flags(struct net_device *dev); -char *netdev_addr(struct net_device *dev); -int dev_change_flags (struct net_device *dev, short flags); -int linux_pkg_xmit (char *pkg_data, int len, void *del_data, - int (*del_func) (struct sk_buff *, void *), - struct net_device *dev); -struct net_device *search_netdev (char *name); -void kfree_skb (struct sk_buff *skb); -int dev_open(struct net_device *dev); -void *l4dde26_register_rx_callback(void *cb); -void skb_done_head_init(); - static struct net_data *nd_head; /* Forward declarations. */ @@ -337,7 +322,7 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, if_init_queues (ifp); #endif - if (err = dev_open(dev) < 0) + if ((err = dev_open(dev)) < 0) { fprintf (stderr, "after dev_open: cannot open the device\n"); err = linux_to_mach_error (err); diff --git a/windhoek/Makefile b/windhoek/Makefile index 6f355bb9..803e8dba 100644 --- a/windhoek/Makefile +++ b/windhoek/Makefile @@ -27,8 +27,8 @@ SRC_C += $(IDEFILES) \ $(CDROMFILES) \ $(PARTITIONFILES) -LIBS += --whole-archive -ldde_linux26_block --no-whole-archive \ - -ldde_linux26.o -lddekit ../libmachdev/libmachdev.a \ +LIBS += --whole-archive --no-whole-archive ../libmachdev/libmachdev.a \ + -ldde_linux26_block -ldde_linux26.o -lddekit \ -lfshelp -ltrivfs -lpciaccess -lthreads -lshouldbeinlibc \ -lports -lhurd-slab diff --git a/windhoek/main.c b/windhoek/main.c index 6c3cdb89..c4e88666 100644 --- a/windhoek/main.c +++ b/windhoek/main.c @@ -66,6 +66,7 @@ int main(int argc, const char **argv) printk("| ready to rumble.... |\n"); printk("+----------------------------------------+\n"); + register_block (); mach_device_init(); trivfs_init(); -- cgit v1.2.3 From b2ff0b48c49eed0ad2fb1b0bf825dac3d07c767e Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Wed, 9 Jun 2010 13:47:39 +0200 Subject: include more block IO scheduler. --- libdde_linux26/contrib/block/as-iosched.c | 2 + libdde_linux26/contrib/block/cfq-iosched.c | 1 + libdde_linux26/contrib/block/deadline-iosched.c | 1 + libdde_linux26/contrib/lib/rbtree.c | 397 ++++++++++++++++++++++++ libdde_linux26/lib/src/Makefile | 4 + 5 files changed, 405 insertions(+) create mode 100644 libdde_linux26/contrib/lib/rbtree.c (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/contrib/block/as-iosched.c b/libdde_linux26/contrib/block/as-iosched.c index 631f6f44..5b363ced 100644 --- a/libdde_linux26/contrib/block/as-iosched.c +++ b/libdde_linux26/contrib/block/as-iosched.c @@ -17,6 +17,8 @@ #include #include +#include + #define REQ_SYNC 1 #define REQ_ASYNC 0 diff --git a/libdde_linux26/contrib/block/cfq-iosched.c b/libdde_linux26/contrib/block/cfq-iosched.c index 664ebfd0..37c1fca9 100644 --- a/libdde_linux26/contrib/block/cfq-iosched.c +++ b/libdde_linux26/contrib/block/cfq-iosched.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * tunables diff --git a/libdde_linux26/contrib/block/deadline-iosched.c b/libdde_linux26/contrib/block/deadline-iosched.c index c4d991d4..9bb6f050 100644 --- a/libdde_linux26/contrib/block/deadline-iosched.c +++ b/libdde_linux26/contrib/block/deadline-iosched.c @@ -13,6 +13,7 @@ #include #include #include +#include /* * See Documentation/block/deadline-iosched.txt diff --git a/libdde_linux26/contrib/lib/rbtree.c b/libdde_linux26/contrib/lib/rbtree.c new file mode 100644 index 00000000..9956b996 --- /dev/null +++ b/libdde_linux26/contrib/lib/rbtree.c @@ -0,0 +1,397 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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 of the License, 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + linux/lib/rbtree.c +*/ + +#include +#include + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_right = right->rb_left)) + rb_set_parent(right->rb_left, node); + right->rb_left = node; + + rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_left = left->rb_right)) + rb_set_parent(left->rb_right, node); + left->rb_right = node; + + rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + rb_set_parent(node, left); +} + +void rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = rb_parent(node)) && rb_is_red(parent)) + { + gparent = rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + rb_set_black(root->rb_node); +} +EXPORT_SYMBOL(rb_insert_color); + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_right || rb_is_black(other->rb_right)) + { + struct rb_node *o_left; + if ((o_left = other->rb_left)) + rb_set_black(o_left); + rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_right) + rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_left || rb_is_black(other->rb_left)) + { + register struct rb_node *o_right; + if ((o_right = other->rb_right)) + rb_set_black(o_right); + rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_left) + rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + rb_set_black(node); +} + +void rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + child = node->rb_right; + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent == old) { + parent->rb_right = child; + parent = node; + } else + parent->rb_left = child; + + node->rb_parent_color = old->rb_parent_color; + node->rb_right = old->rb_right; + node->rb_left = old->rb_left; + + if (rb_parent(old)) + { + if (rb_parent(old)->rb_left == old) + rb_parent(old)->rb_left = node; + else + rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + rb_set_parent(old->rb_left, node); + if (old->rb_right) + rb_set_parent(old->rb_right, node); + goto color; + } + + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} +EXPORT_SYMBOL(rb_erase); + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *rb_first(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} +EXPORT_SYMBOL(rb_first); + +struct rb_node *rb_last(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} +EXPORT_SYMBOL(rb_last); + +struct rb_node *rb_next(const struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return (struct rb_node *)node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while ((parent = rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} +EXPORT_SYMBOL(rb_next); + +struct rb_node *rb_prev(const struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return (struct rb_node *)node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while ((parent = rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} +EXPORT_SYMBOL(rb_prev); + +void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new); + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} +EXPORT_SYMBOL(rb_replace_node); diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index 947f11b9..36af1365 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -119,6 +119,7 @@ SRC_C_libdde_linux26.o.a += \ lib/sha1.c \ lib/string.c \ lib/vsprintf.c \ + lib/rbtree.c \ mm/dmapool.c \ mm/mempool.c \ mm/swap.c \ @@ -196,6 +197,9 @@ SRC_C_libdde_linux26_block.a += \ block/noop-iosched.c \ block/ioctl.c \ block/scsi_ioctl.c \ + block/as-iosched.c \ + block/cfq-iosched.c \ + block/deadline-iosched.c \ mm/backing-dev.c \ mm/bounce.c \ mm/page-writeback.c \ -- 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 'libdde_linux26/lib/src/Makefile') 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 From 2b91d7ba805279f3f871f95d5d49c6c1b7d6b879 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Mon, 12 Jul 2010 09:47:31 +0200 Subject: Use Linux's udelay and ndelay. It's not very precise to implement udelay and ndelay with loops in the user space, but should be enough. --- libdde_linux26/lib/src/Makefile | 2 + libdde_linux26/lib/src/arch/l4/timer.c | 19 --- libdde_linux26/lib/src/arch/x86/lib/delay.c | 138 +++++++++++++++++++++ libdde_linux26/lib/src/init/calibrate.c | 182 ++++++++++++++++++++++++++++ 4 files changed, 322 insertions(+), 19 deletions(-) create mode 100644 libdde_linux26/lib/src/arch/x86/lib/delay.c create mode 100644 libdde_linux26/lib/src/init/calibrate.c (limited to 'libdde_linux26/lib/src/Makefile') diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile index ed53fdeb..358196bb 100644 --- a/libdde_linux26/lib/src/Makefile +++ b/libdde_linux26/lib/src/Makefile @@ -58,6 +58,7 @@ SRC_C_libdde_linux26.o.a = $(addprefix arch/l4/, $(SRC_DDE)) ifeq ($(ARCH), x86) SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/semaphore_32.S +SRC_S_libdde_linux26.o.a += $(ARCH_DIR)/lib/delay.o SRC_C_libdde_linux26.o.a += lib/rwsem.c SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/kernel/pci-dma.c SRC_C_libdde_linux26.o.a += $(ARCH_DIR)/kernel/pci-nommu.c @@ -120,6 +121,7 @@ SRC_C_libdde_linux26.o.a += \ lib/string.c \ lib/vsprintf.c \ lib/rbtree.c \ + init/calibrate.c \ mm/dmapool.c \ mm/mempool.c \ mm/swap.c \ diff --git a/libdde_linux26/lib/src/arch/l4/timer.c b/libdde_linux26/lib/src/arch/l4/timer.c index 2b657ab4..b85c83a9 100644 --- a/libdde_linux26/lib/src/arch/l4/timer.c +++ b/libdde_linux26/lib/src/arch/l4/timer.c @@ -126,25 +126,6 @@ void msleep(unsigned int msecs) ddekit_thread_msleep(msecs); } - -void __const_udelay(unsigned long xloops) -{ - ddekit_thread_usleep(xloops); -} - - -void __udelay(unsigned long usecs) -{ - ddekit_thread_usleep(usecs); -} - - -void __ndelay(unsigned long nsecs) -{ - ddekit_thread_nsleep(nsecs); -} - - void __init l4dde26_init_timers(void) { ddekit_init_timers(); diff --git a/libdde_linux26/lib/src/arch/x86/lib/delay.c b/libdde_linux26/lib/src/arch/x86/lib/delay.c new file mode 100644 index 00000000..6097c6bb --- /dev/null +++ b/libdde_linux26/lib/src/arch/x86/lib/delay.c @@ -0,0 +1,138 @@ +/* + * Precise Delay Loops for i386 + * + * Copyright (C) 1993 Linus Torvalds + * Copyright (C) 1997 Martin Mares + * Copyright (C) 2008 Jiri Hladky + * + * The __delay function must _NOT_ be inlined as its execution time + * depends wildly on alignment on many x86 processors. The additional + * jump magic is needed to get the timing stable on all the CPU's + * we have to worry about. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_SMP +# include +#endif +#include + +/* simple loop based delay: */ +static void delay_loop(unsigned long loops) +{ + asm volatile( + " test %0,%0 \n" + " jz 3f \n" + " jmp 1f \n" + + ".align 16 \n" + "1: jmp 2f \n" + + ".align 16 \n" + "2: dec %0 \n" + " jnz 2b \n" + "3: dec %0 \n" + + : /* we don't need output */ + :"a" (loops) + ); +} + +/* TSC based delay: */ +static void delay_tsc(unsigned long loops) +{ + unsigned long bclock, now; + int cpu; + + preempt_disable(); + cpu = smp_processor_id(); + rdtscl(bclock); + for (;;) { + rdtscl(now); + if ((now - bclock) >= loops) + break; + + /* Allow RT tasks to run */ + preempt_enable(); + rep_nop(); + preempt_disable(); + + /* + * It is possible that we moved to another CPU, and + * since TSC's are per-cpu we need to calculate + * that. The delay must guarantee that we wait "at + * least" the amount of time. Being moved to another + * CPU could make the wait longer but we just need to + * make sure we waited long enough. Rebalance the + * counter for this CPU. + */ + if (unlikely(cpu != smp_processor_id())) { + loops -= (now - bclock); + cpu = smp_processor_id(); + rdtscl(bclock); + } + } + preempt_enable(); +} + +/* + * Since we calibrate only once at boot, this + * function should be set once at boot and not changed + */ +static void (*delay_fn)(unsigned long) = delay_loop; + +void use_tsc_delay(void) +{ + delay_fn = delay_tsc; +} + +int __devinit read_current_timer(unsigned long *timer_val) +{ + if (delay_fn == delay_tsc) { + rdtscll(*timer_val); + return 0; + } + return -1; +} + +void __delay(unsigned long loops) +{ + delay_fn(loops); +} +EXPORT_SYMBOL(__delay); + +inline void __const_udelay(unsigned long xloops) +{ + int d0; + + xloops *= 4; + asm("mull %%edx" + :"=d" (xloops), "=&a" (d0) + :"1" (xloops), "0" + (loops_per_jiffy * (HZ/4))); + + __delay(++xloops); +} +EXPORT_SYMBOL(__const_udelay); + +void __udelay(unsigned long usecs) +{ + __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ +} +EXPORT_SYMBOL(__udelay); + +void __ndelay(unsigned long nsecs) +{ + __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ +} +EXPORT_SYMBOL(__ndelay); diff --git a/libdde_linux26/lib/src/init/calibrate.c b/libdde_linux26/lib/src/init/calibrate.c new file mode 100644 index 00000000..aede8e53 --- /dev/null +++ b/libdde_linux26/lib/src/init/calibrate.c @@ -0,0 +1,182 @@ +/* calibrate.c: default delay calibration + * + * Excised from init/main.c + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +unsigned long loops_per_jiffy = (1<<12); +EXPORT_SYMBOL(loops_per_jiffy); + +unsigned long lpj_fine; +unsigned long preset_lpj; +static int __init lpj_setup(char *str) +{ + preset_lpj = simple_strtoul(str,NULL,0); + return 1; +} + +__setup("lpj=", lpj_setup); + +#ifdef ARCH_HAS_READ_CURRENT_TIMER + +/* This routine uses the read_current_timer() routine and gets the + * loops per jiffy directly, instead of guessing it using delay(). + * Also, this code tries to handle non-maskable asynchronous events + * (like SMIs) + */ +#define DELAY_CALIBRATION_TICKS ((HZ < 100) ? 1 : (HZ/100)) +#define MAX_DIRECT_CALIBRATION_RETRIES 5 + +static unsigned long __cpuinit calibrate_delay_direct(void) +{ + unsigned long pre_start, start, post_start; + unsigned long pre_end, end, post_end; + unsigned long start_jiffies; + unsigned long timer_rate_min, timer_rate_max; + unsigned long good_timer_sum = 0; + unsigned long good_timer_count = 0; + int i; + + if (read_current_timer(&pre_start) < 0 ) + return 0; + + /* + * A simple loop like + * while ( jiffies < start_jiffies+1) + * start = read_current_timer(); + * will not do. As we don't really know whether jiffy switch + * happened first or timer_value was read first. And some asynchronous + * event can happen between these two events introducing errors in lpj. + * + * So, we do + * 1. pre_start <- When we are sure that jiffy switch hasn't happened + * 2. check jiffy switch + * 3. start <- timer value before or after jiffy switch + * 4. post_start <- When we are sure that jiffy switch has happened + * + * Note, we don't know anything about order of 2 and 3. + * Now, by looking at post_start and pre_start difference, we can + * check whether any asynchronous event happened or not + */ + + for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) { + pre_start = 0; + read_current_timer(&start); + start_jiffies = jiffies; + while (jiffies <= (start_jiffies + 1)) { + pre_start = start; + read_current_timer(&start); + } + read_current_timer(&post_start); + + pre_end = 0; + end = post_start; + while (jiffies <= + (start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) { + pre_end = end; + read_current_timer(&end); + } + read_current_timer(&post_end); + + timer_rate_max = (post_end - pre_start) / + DELAY_CALIBRATION_TICKS; + timer_rate_min = (pre_end - post_start) / + DELAY_CALIBRATION_TICKS; + + /* + * If the upper limit and lower limit of the timer_rate is + * >= 12.5% apart, redo calibration. + */ + if (pre_start != 0 && pre_end != 0 && + (timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) { + good_timer_count++; + good_timer_sum += timer_rate_max; + } + } + + if (good_timer_count) + return (good_timer_sum/good_timer_count); + + printk(KERN_WARNING "calibrate_delay_direct() failed to get a good " + "estimate for loops_per_jiffy.\nProbably due to long platform interrupts. Consider using \"lpj=\" boot option.\n"); + return 0; +} +#else +static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;} +#endif + +/* + * This is the number of bits of precision for the loops_per_jiffy. Each + * bit takes on average 1.5/HZ seconds. This (like the original) is a little + * better than 1% + * For the boot cpu we can skip the delay calibration and assign it a value + * calculated based on the timer frequency. + * For the rest of the CPUs we cannot assume that the timer frequency is same as + * the cpu frequency, hence do the calibration for those. + */ +#define LPS_PREC 8 + +void __cpuinit calibrate_delay(void) +{ + unsigned long ticks, loopbit; + int lps_precision = LPS_PREC; + + if (preset_lpj) { + loops_per_jiffy = preset_lpj; + printk(KERN_INFO + "Calibrating delay loop (skipped) preset value.. "); + } else if ((smp_processor_id() == 0) && lpj_fine) { + loops_per_jiffy = lpj_fine; + printk(KERN_INFO + "Calibrating delay loop (skipped), " + "value calculated using timer frequency.. "); + } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) { + printk(KERN_INFO + "Calibrating delay using timer specific routine.. "); + } else { + loops_per_jiffy = (1<<12); + + printk(KERN_INFO "Calibrating delay loop... "); + while ((loops_per_jiffy <<= 1) != 0) { + /* wait for "start of" clock tick */ + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + /* Go .. */ + ticks = jiffies; + __delay(loops_per_jiffy); + ticks = jiffies - ticks; + if (ticks) + break; + } + + /* + * Do a binary approximation to get loops_per_jiffy set to + * equal one clock (up to lps_precision bits) + */ + loops_per_jiffy >>= 1; + loopbit = loops_per_jiffy; + while (lps_precision-- && (loopbit >>= 1)) { + loops_per_jiffy |= loopbit; + ticks = jiffies; + while (ticks == jiffies) + /* nothing */; + ticks = jiffies; + __delay(loops_per_jiffy); + if (jiffies != ticks) /* longer than 1 tick */ + loops_per_jiffy &= ~loopbit; + } + } + printk(KERN_CONT "%lu.%02lu BogoMIPS (lpj=%lu)\n", + loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); +} + +core_initcall(calibrate_delay); -- cgit v1.2.3