Commit 87353814 authored by Kai Germaschewski's avatar Kai Germaschewski

Merge tp1.ruhr-uni-bochum.de:/scratch/kai/kernel/v2.5/linux-2.5

into tp1.ruhr-uni-bochum.de:/scratch/kai/kernel/v2.5/linux-2.5.make
parents e00b99de 2763b6bc
...@@ -405,30 +405,17 @@ $(SUBDIRS): prepare ...@@ -405,30 +405,17 @@ $(SUBDIRS): prepare
.PHONY: prepare .PHONY: prepare
prepare: include/linux/version.h include/asm include/config/MARKER prepare: include/linux/version.h include/asm include/config/MARKER
ifdef CONFIG_MODVERSIONS
ifdef KBUILD_MODULES ifdef KBUILD_MODULES
ifeq ($(origin SUBDIRS),file) ifeq ($(origin SUBDIRS),file)
$(Q)rm -rf $(MODVERDIR) $(Q)rm -rf $(MODVERDIR)
$(Q)mkdir $(MODVERDIR)
else else
@echo '*** Warning: Overriding SUBDIRS on the command line can cause' @echo '*** Warning: Overriding SUBDIRS on the command line can cause'
@echo '*** inconsistencies with module symbol versions' @echo '*** inconsistencies'
endif
endif endif
$(Q)mkdir -p $(MODVERDIR)
endif endif
@echo ' Starting the build. KBUILD_BUILTIN=$(KBUILD_BUILTIN) KBUILD_MODULES=$(KBUILD_MODULES)' @echo ' Starting the build. KBUILD_BUILTIN=$(KBUILD_BUILTIN) KBUILD_MODULES=$(KBUILD_MODULES)'
# We need to build init/vermagic.o before descending since all modules
# (*.ko) need it already
ifdef CONFIG_MODULES
prepare: init/vermagic.o
init/vermagic.o: include/linux/version.h
endif
# This can be used by arch/$ARCH/Makefile to preprocess # This can be used by arch/$ARCH/Makefile to preprocess
# their vmlinux.lds.S file # their vmlinux.lds.S file
...@@ -518,21 +505,15 @@ all: modules ...@@ -518,21 +505,15 @@ all: modules
# Build modules # Build modules
.PHONY: modules __modversions .PHONY: modules
modules: $(SUBDIRS) __modversions modules: $(SUBDIRS) $(if $(CONFIG_MODVERSIONS),vmlinux)
@echo ' Building modules, stage 2.';
ifdef CONFIG_MODVERSIONS $(Q)$(MAKE) -rR -f scripts/Makefile.modpost
__modversions: vmlinux $(SUBDIRS)
@echo ' Recording module symbol versions.';
$(Q)$(MAKE) -rR -f scripts/Makefile.modver
endif
# Install modules # Install modules
.PHONY: modules_install .PHONY: modules_install
modules_install: _modinst_ $(patsubst %, _modinst_%, $(SUBDIRS)) _modinst_post modules_install: _modinst_ _modinst_post
.PHONY: _modinst_ .PHONY: _modinst_
_modinst_: _modinst_:
...@@ -540,6 +521,7 @@ _modinst_: ...@@ -540,6 +521,7 @@ _modinst_:
@rm -f $(MODLIB)/build @rm -f $(MODLIB)/build
@mkdir -p $(MODLIB)/kernel @mkdir -p $(MODLIB)/kernel
@ln -s $(TOPDIR) $(MODLIB)/build @ln -s $(TOPDIR) $(MODLIB)/build
$(Q)$(MAKE) -rR -f scripts/Makefile.modinst
# If System.map exists, run depmod. This deliberately does not have a # If System.map exists, run depmod. This deliberately does not have a
# dependency on System.map since that would run the dependency tree on # dependency on System.map since that would run the dependency tree on
...@@ -552,13 +534,9 @@ else ...@@ -552,13 +534,9 @@ else
depmod_opts := -b $(INSTALL_MOD_PATH) -r depmod_opts := -b $(INSTALL_MOD_PATH) -r
endif endif
.PHONY: _modinst_post .PHONY: _modinst_post
_modinst_post: _modinst_post: _modinst_
if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi if [ -r System.map ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi
.PHONY: $(patsubst %, _modinst_%, $(SUBDIRS))
$(patsubst %, _modinst_%, $(SUBDIRS)) :
$(Q)$(MAKE) -rR -f scripts/Makefile.modinst obj=$(patsubst _modinst_%,%,$@)
else # CONFIG_MODULES else # CONFIG_MODULES
# Modules not configured # Modules not configured
......
/*
* Device tables which are exported to userspace via
* scripts/table2alias.c. You must keep that file in sync with this
* header.
*/
#ifndef LINUX_MOD_DEVICETABLE_H
#define LINUX_MOD_DEVICETABLE_H
#ifdef __KERNEL__
#include <linux/types.h>
typedef unsigned long kernel_ulong_t;
#endif
#define PCI_ANY_ID (~0)
struct pci_device_id {
__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
__u32 class, class_mask; /* (class,subclass,prog-if) triplet */
kernel_ulong_t driver_data; /* Data private to the driver */
};
/*
* Device table entry for "new style" table-driven USB drivers.
* User mode code can read these tables to choose which modules to load.
* Declare the table as a MODULE_DEVICE_TABLE.
*
* A probe() parameter will point to a matching entry from this table.
* Use the driver_info field for each match to hold information tied
* to that match: device quirks, etc.
*
* Terminate the driver's table with an all-zeroes entry.
* Use the flag values to control which fields are compared.
*/
/**
* struct usb_device_id - identifies USB devices for probing and hotplugging
* @match_flags: Bit mask controlling of the other fields are used to match
* against new devices. Any field except for driver_info may be used,
* although some only make sense in conjunction with other fields.
* This is usually set by a USB_DEVICE_*() macro, which sets all
* other fields in this structure except for driver_info.
* @idVendor: USB vendor ID for a device; numbers are assigned
* by the USB forum to its members.
* @idProduct: Vendor-assigned product ID.
* @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
* This is also used to identify individual product versions, for
* a range consisting of a single device.
* @bcdDevice_hi: High end of version number range. The range of product
* versions is inclusive.
* @bDeviceClass: Class of device; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Device classes specify behavior of all
* the interfaces on a devices.
* @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
* @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
* @bInterfaceClass: Class of interface; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Interface classes specify behavior only
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
*
* In most cases, drivers will create a table of device IDs by using
* USB_DEVICE(), or similar macros designed for that purpose.
* They will then export it to userspace using MODULE_DEVICE_TABLE(),
* and provide it to the USB core through their usb_driver structure.
*
* See the usb_match_id() function for information about how matches are
* performed. Briefly, you will normally use one of several macros to help
* construct these entries. Each entry you provide will either identify
* one or more specific products, or will identify a class of products
* which have agreed to behave the same. You should put the more specific
* matches towards the beginning of your table, so that driver_info can
* record quirks of specific products.
*/
struct usb_device_id {
/* which fields to match against? */
__u16 match_flags;
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* not matched against */
kernel_ulong_t driver_info;
};
/* Some useful macros to use to create struct usb_device_id */
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#endif /* LINUX_MOD_DEVICETABLE_H */
...@@ -57,13 +57,14 @@ search_extable(const struct exception_table_entry *first, ...@@ -57,13 +57,14 @@ search_extable(const struct exception_table_entry *first,
unsigned long value); unsigned long value);
#ifdef MODULE #ifdef MODULE
#define ___module_cat(a,b) a ## b
#define __module_cat(a,b) ___module_cat(a,b)
/* For userspace: you can also call me... */
#define MODULE_ALIAS(alias) \
static const char __module_cat(__alias_,__LINE__)[] \
__attribute__((section(".modinfo"),unused)) = "alias=" alias
/* For replacement modutils, use an alias not a pointer. */
#define MODULE_GENERIC_TABLE(gtype,name) \ #define MODULE_GENERIC_TABLE(gtype,name) \
static const unsigned long __module_##gtype##_size \
__attribute__ ((unused)) = sizeof(struct gtype##_id); \
static const struct gtype##_id * __module_##gtype##_table \
__attribute__ ((unused)) = name; \
extern const struct gtype##_id __mod_##gtype##_table \ extern const struct gtype##_id __mod_##gtype##_table \
__attribute__ ((unused, alias(__stringify(name)))) __attribute__ ((unused, alias(__stringify(name))))
...@@ -103,6 +104,7 @@ extern const struct gtype##_id __mod_##gtype##_table \ ...@@ -103,6 +104,7 @@ extern const struct gtype##_id __mod_##gtype##_table \
#else /* !MODULE */ #else /* !MODULE */
#define MODULE_ALIAS(alias)
#define MODULE_GENERIC_TABLE(gtype,name) #define MODULE_GENERIC_TABLE(gtype,name)
#define THIS_MODULE ((struct module *)0) #define THIS_MODULE ((struct module *)0)
#define MOD_INC_USE_COUNT do { } while (0) #define MOD_INC_USE_COUNT do { } while (0)
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#ifndef LINUX_PCI_H #ifndef LINUX_PCI_H
#define LINUX_PCI_H #define LINUX_PCI_H
#include <linux/mod_devicetable.h>
/* /*
* Under PCI, each device has 256 bytes of configuration address space, * Under PCI, each device has 256 bytes of configuration address space,
* of which the first 64 bytes are standardized as follows: * of which the first 64 bytes are standardized as follows:
...@@ -359,8 +361,6 @@ enum pci_mmap_state { ...@@ -359,8 +361,6 @@ enum pci_mmap_state {
#define DEVICE_COUNT_DMA 2 #define DEVICE_COUNT_DMA 2
#define DEVICE_COUNT_RESOURCE 12 #define DEVICE_COUNT_RESOURCE 12
#define PCI_ANY_ID (~0)
/* /*
* The pci_dev structure is used to describe PCI devices. * The pci_dev structure is used to describe PCI devices.
*/ */
...@@ -491,13 +491,6 @@ struct pbus_set_ranges_data ...@@ -491,13 +491,6 @@ struct pbus_set_ranges_data
unsigned long prefetch_start, prefetch_end; unsigned long prefetch_start, prefetch_end;
}; };
struct pci_device_id {
unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */
unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */
unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */
unsigned long driver_data; /* Data private to the driver */
};
struct pci_driver { struct pci_driver {
struct list_head node; struct list_head node;
char *name; char *name;
......
#ifndef __LINUX_USB_H #ifndef __LINUX_USB_H
#define __LINUX_USB_H #define __LINUX_USB_H
#include <linux/mod_devicetable.h>
#include <linux/usb_ch9.h> #include <linux/usb_ch9.h>
#define USB_MAJOR 180 #define USB_MAJOR 180
...@@ -314,99 +315,6 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size) ...@@ -314,99 +315,6 @@ static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/*
* Device table entry for "new style" table-driven USB drivers.
* User mode code can read these tables to choose which modules to load.
* Declare the table as a MODULE_DEVICE_TABLE.
*
* A probe() parameter will point to a matching entry from this table.
* Use the driver_info field for each match to hold information tied
* to that match: device quirks, etc.
*
* Terminate the driver's table with an all-zeroes entry.
* Use the flag values to control which fields are compared.
*/
/**
* struct usb_device_id - identifies USB devices for probing and hotplugging
* @match_flags: Bit mask controlling of the other fields are used to match
* against new devices. Any field except for driver_info may be used,
* although some only make sense in conjunction with other fields.
* This is usually set by a USB_DEVICE_*() macro, which sets all
* other fields in this structure except for driver_info.
* @idVendor: USB vendor ID for a device; numbers are assigned
* by the USB forum to its members.
* @idProduct: Vendor-assigned product ID.
* @bcdDevice_lo: Low end of range of vendor-assigned product version numbers.
* This is also used to identify individual product versions, for
* a range consisting of a single device.
* @bcdDevice_hi: High end of version number range. The range of product
* versions is inclusive.
* @bDeviceClass: Class of device; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Device classes specify behavior of all
* the interfaces on a devices.
* @bDeviceSubClass: Subclass of device; associated with bDeviceClass.
* @bDeviceProtocol: Protocol of device; associated with bDeviceClass.
* @bInterfaceClass: Class of interface; numbers are assigned
* by the USB forum. Products may choose to implement classes,
* or be vendor-specific. Interface classes specify behavior only
* of a given interface; other interfaces may support other classes.
* @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass.
* @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass.
* @driver_info: Holds information used by the driver. Usually it holds
* a pointer to a descriptor understood by the driver, or perhaps
* device flags.
*
* In most cases, drivers will create a table of device IDs by using
* USB_DEVICE(), or similar macros designed for that purpose.
* They will then export it to userspace using MODULE_DEVICE_TABLE(),
* and provide it to the USB core through their usb_driver structure.
*
* See the usb_match_id() function for information about how matches are
* performed. Briefly, you will normally use one of several macros to help
* construct these entries. Each entry you provide will either identify
* one or more specific products, or will identify a class of products
* which have agreed to behave the same. You should put the more specific
* matches towards the beginning of your table, so that driver_info can
* record quirks of specific products.
*/
struct usb_device_id {
/* which fields to match against? */
__u16 match_flags;
/* Used for product specific matches; range is inclusive */
__u16 idVendor;
__u16 idProduct;
__u16 bcdDevice_lo;
__u16 bcdDevice_hi;
/* Used for device class matches */
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
/* Used for interface class matches */
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
/* not matched against */
unsigned long driver_info;
};
/* Some useful macros to use to create struct usb_device_id */
#define USB_DEVICE_ID_MATCH_VENDOR 0x0001
#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002
#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004
#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008
#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010
#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020
#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040
#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#define USB_DEVICE_ID_MATCH_DEVICE (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) #define USB_DEVICE_ID_MATCH_DEVICE (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
#define USB_DEVICE_ID_MATCH_DEV_RANGE (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI) #define USB_DEVICE_ID_MATCH_DEV_RANGE (USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI)
#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE) #define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE)
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
#define MODULE_ARCH_VERMAGIC "" #define MODULE_ARCH_VERMAGIC ""
#endif #endif
const char vermagic[] __attribute__((section("__vermagic"))) = #define VERMAGIC_STRING \
UTS_RELEASE " " UTS_RELEASE " " \
MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT MODULE_ARCH_VERMAGIC MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT \
"gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__); MODULE_ARCH_VERMAGIC \
"gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
# #
obj-y := main.o version.o do_mounts.o initramfs.o obj-y := main.o version.o do_mounts.o initramfs.o
obj-$(CONFIG_MODULES) += vermagic.o
# files to be removed upon make clean # files to be removed upon make clean
clean-files := ../include/linux/compile.h clean-files := ../include/linux/compile.h
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/vermagic.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
...@@ -725,6 +726,8 @@ static int obsolete_params(const char *name, ...@@ -725,6 +726,8 @@ static int obsolete_params(const char *name,
} }
#endif /* CONFIG_OBSOLETE_MODPARM */ #endif /* CONFIG_OBSOLETE_MODPARM */
static const char vermagic[] = VERMAGIC_STRING;
#ifdef CONFIG_MODVERSIONS #ifdef CONFIG_MODVERSIONS
static int check_version(Elf_Shdr *sechdrs, static int check_version(Elf_Shdr *sechdrs,
unsigned int versindex, unsigned int versindex,
...@@ -768,6 +771,18 @@ static int check_version(Elf_Shdr *sechdrs, ...@@ -768,6 +771,18 @@ static int check_version(Elf_Shdr *sechdrs,
return 1; return 1;
} }
static inline int check_modstruct_version(Elf_Shdr *sechdrs,
unsigned int versindex,
struct module *mod)
{
unsigned int i;
struct kernel_symbol_group *ksg;
if (!__find_symbol("struct_module", &ksg, &i, 1))
BUG();
return check_version(sechdrs, versindex, "struct_module", mod, ksg, i);
}
/* First part is kernel version, which we ignore. */ /* First part is kernel version, which we ignore. */
static inline int same_magic(const char *amagic, const char *bmagic) static inline int same_magic(const char *amagic, const char *bmagic)
{ {
...@@ -786,6 +801,13 @@ static inline int check_version(Elf_Shdr *sechdrs, ...@@ -786,6 +801,13 @@ static inline int check_version(Elf_Shdr *sechdrs,
return 1; return 1;
} }
static inline int check_modstruct_version(Elf_Shdr *sechdrs,
unsigned int versindex,
struct module *mod)
{
return 1;
}
static inline int same_magic(const char *amagic, const char *bmagic) static inline int same_magic(const char *amagic, const char *bmagic)
{ {
return strcmp(amagic, bmagic) == 0; return strcmp(amagic, bmagic) == 0;
...@@ -1036,9 +1058,6 @@ static void set_license(struct module *mod, Elf_Shdr *sechdrs, int licenseidx) ...@@ -1036,9 +1058,6 @@ static void set_license(struct module *mod, Elf_Shdr *sechdrs, int licenseidx)
} }
} }
/* From init/vermagic.o */
extern char vermagic[];
/* Allocate and load the module: note that size of section 0 is always /* Allocate and load the module: note that size of section 0 is always
zero, and we rely on this for optional sections. */ zero, and we rely on this for optional sections. */
static struct module *load_module(void *umod, static struct module *load_module(void *umod,
...@@ -1185,6 +1204,12 @@ static struct module *load_module(void *umod, ...@@ -1185,6 +1204,12 @@ static struct module *load_module(void *umod,
} }
mod = (void *)sechdrs[modindex].sh_addr; mod = (void *)sechdrs[modindex].sh_addr;
/* Check module struct version now, before we try to use module. */
if (!check_modstruct_version(sechdrs, versindex, mod)) {
err = -ENOEXEC;
goto free_hdr;
}
/* This is allowed: modprobe --force will invalidate it. */ /* This is allowed: modprobe --force will invalidate it. */
if (!vmagindex) { if (!vmagindex) {
tainted |= TAINT_FORCED_MODULE; tainted |= TAINT_FORCED_MODULE;
...@@ -1455,9 +1480,9 @@ static const char *get_ksymbol(struct module *mod, ...@@ -1455,9 +1480,9 @@ static const char *get_ksymbol(struct module *mod,
/* At worse, next value is at end of module */ /* At worse, next value is at end of module */
if (within(addr, mod->module_init, mod->init_size)) if (within(addr, mod->module_init, mod->init_size))
nextval = (unsigned long)mod->module_core+mod->core_size; nextval = (unsigned long)mod->module_init + mod->init_size;
else else
nextval = (unsigned long)mod->module_init+mod->init_size; nextval = (unsigned long)mod->module_core + mod->core_size;
/* Scan for closest preceeding symbol, and next symbol. (ELF /* Scan for closest preceeding symbol, and next symbol. (ELF
starts real symbols at 1). */ starts real symbols at 1). */
...@@ -1630,3 +1655,9 @@ static int __init symbols_init(void) ...@@ -1630,3 +1655,9 @@ static int __init symbols_init(void)
} }
__initcall(symbols_init); __initcall(symbols_init);
#ifdef CONFIG_MODVERSIONS
/* Generate the signature for struct module here, too, for modversions. */
void struct_module(struct module *mod) { return; }
EXPORT_SYMBOL(struct_module);
#endif
...@@ -8,11 +8,26 @@ ...@@ -8,11 +8,26 @@
# docproc: Preprocess .tmpl file in order to generate .sgml documentation # docproc: Preprocess .tmpl file in order to generate .sgml documentation
# conmakehash: Create arrays for initializing the kernel console tables # conmakehash: Create arrays for initializing the kernel console tables
host-progs := fixdep split-include conmakehash docproc kallsyms host-progs := fixdep split-include conmakehash docproc kallsyms modpost \
build-targets := $(host-progs) mk_elfconfig
build-targets := $(host-progs) empty.o
modpost-objs := modpost.o file2alias.o
# Let clean descend into subdirs # Let clean descend into subdirs
subdir- := lxdialog kconfig subdir- := lxdialog kconfig
# fixdep is needed to compile other host programs # fixdep is needed to compile other host programs
$(addprefix $(obj)/,$(filter-out fixdep,$(host-progs))): $(obj)/fixdep $(addprefix $(obj)/,$(filter-out fixdep,$(host-progs))): $(obj)/fixdep
# dependencies on generated files need to be listed explicitly
$(obj)/modpost.o $(obj)/file2alias.o: $(obj)/elfconfig.h
quiet_cmd_elfconfig = MKELF $@
cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@
$(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE
$(call if_changed,elfconfig)
targets += $(obj)/elfconfig.h
...@@ -49,15 +49,12 @@ O_TARGET := $(obj)/built-in.o ...@@ -49,15 +49,12 @@ O_TARGET := $(obj)/built-in.o
endif endif
endif endif
ifdef CONFIG_MODVERSIONS # We keep a list of all modules in $(MODVERDIR)
modules := $(obj-m)
touch-module = @echo $(@:.o=.ko) > .tmp_versions/$(@F:.o=.mod) touch-module = @echo $(@:.o=.ko) > $(MODVERDIR)/$(@F:.o=.mod)
else
modules := $(obj-m:.o=.ko)
endif
__build: $(if $(KBUILD_BUILTIN),$(O_TARGET) $(L_TARGET) $(EXTRA_TARGETS)) \ __build: $(if $(KBUILD_BUILTIN),$(O_TARGET) $(L_TARGET) $(EXTRA_TARGETS)) \
$(if $(KBUILD_MODULES),$(modules)) \ $(if $(KBUILD_MODULES),$(obj-m)) \
$(subdir-ym) $(build-targets) $(subdir-ym) $(build-targets)
@: @:
...@@ -155,6 +152,8 @@ cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $< ...@@ -155,6 +152,8 @@ cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $<
quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ quiet_cmd_cc_o_c = CC $(quiet_modtag) $@
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
# Built-in and composite module parts
%.o: %.c FORCE %.o: %.c FORCE
ifdef CONFIG_MODVERSIONS ifdef CONFIG_MODVERSIONS
$(call if_changed_rule,vcc_o_c) $(call if_changed_rule,vcc_o_c)
...@@ -162,13 +161,14 @@ else ...@@ -162,13 +161,14 @@ else
$(call if_changed_dep,cc_o_c) $(call if_changed_dep,cc_o_c)
endif endif
# For modversioning, we need to special case single-part modules # Single-part modules are special since we need to mark them in $(MODVERDIR)
# to mark them in $(MODVERDIR)
ifdef CONFIG_MODVERSIONS
$(single-used-m): %.o: %.c FORCE $(single-used-m): %.o: %.c FORCE
$(touch-module) $(touch-module)
ifdef CONFIG_MODVERSIONS
$(call if_changed_rule,vcc_o_c) $(call if_changed_rule,vcc_o_c)
else
$(call if_changed_dep,cc_o_c)
endif endif
quiet_cmd_cc_lst_c = MKLST $@ quiet_cmd_cc_lst_c = MKLST $@
...@@ -199,7 +199,8 @@ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< ...@@ -199,7 +199,8 @@ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
%.o: %.S FORCE %.o: %.S FORCE
$(call if_changed_dep,as_o_S) $(call if_changed_dep,as_o_S)
targets += $(real-objs-y) $(real-objs-m) $(EXTRA_TARGETS) $(MAKECMDGOALS) targets += $(real-objs-y) $(real-objs-m) $(EXTRA_TARGETS) $(MAKECMDGOALS) \
$(build-targets)
# Build the compiled-in targets # Build the compiled-in targets
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
...@@ -267,29 +268,6 @@ $(multi-used-m) : %.o: $(multi-objs-m) FORCE ...@@ -267,29 +268,6 @@ $(multi-used-m) : %.o: $(multi-objs-m) FORCE
targets += $(multi-used-y) $(multi-used-m) targets += $(multi-used-y) $(multi-used-m)
#
# Rule to link modules ( .o -> .ko )
#
# With CONFIG_MODVERSIONS, generation of the final .ko is handled
# by scripts/Makefile.modver
ifndef CONFIG_MODVERSIONS
quiet_cmd_link_module = LD [M] $@
cmd_link_module = $(LD) $(ld_flags) $(LDFLAGS_MODULE) -o $@ $< init/vermagic.o
# Don't rebuilt vermagic.o unless we actually are in the init/ dir
ifneq ($(obj),init)
init/vermagic.o: ;
endif
$(single-used-m:.o=.ko) $(multi-used-m:.o=.ko): %.ko: %.o init/vermagic.o FORCE
$(call if_changed,link_module)
targets += $(single-used-m:.o=.ko) $(multi-used-m:.o=.ko)
endif
# Compile programs on the host # Compile programs on the host
# =========================================================================== # ===========================================================================
# host-progs := bin2hex # host-progs := bin2hex
......
...@@ -2,33 +2,38 @@ ...@@ -2,33 +2,38 @@
# Installing modules # Installing modules
# ========================================================================== # ==========================================================================
src := $(obj) .PHONY: __modinst
__modinst:
.PHONY: modules_install include scripts/Makefile.lib
modules_install:
include .config #
include $(obj)/Makefile __modules := $(shell cd $(MODVERDIR); cat *.mod)
modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
include scripts/Makefile.lib ifneq ($(filter-out $(modules),$(__modules)),)
$(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS, do not complain if something goes wrong.)
endif
# ========================================================================== .PHONY: $(modules)
__modinst: $(modules)
@:
# Modules built within the kernel tree
quiet_cmd_modules_install = INSTALL $(obj-m:.o=.ko) quiet_cmd_modules_install = INSTALL $(obj-m:.o=.ko)
cmd_modules_install = mkdir -p $(MODLIB)/kernel/$(obj); \ cmd_modules_install = mkdir -p $(MODLIB)/kernel/$(@D); \
cp $(obj-m:.o=.ko) $(MODLIB)/kernel/$(obj) cp $@ $(MODLIB)/kernel/$(@D)
modules_install: $(subdir-ym) $(filter-out ../% /%,$(modules)):
ifneq ($(obj-m:.o=.ko),)
$(call cmd,modules_install) $(call cmd,modules_install)
else
@:
endif
# Descending # Modules built outside just go into extra
# ---------------------------------------------------------------------------
quiet_cmd_modules_install_extra = INSTALL $(obj-m:.o=.ko)
cmd_modules_install_extra = mkdir -p $(MODLIB)/extra; \
cp $@ $(MODLIB)/extra
.PHONY: $(subdir-ym) $(filter ../% /%,$(modules)):
$(subdir-ym): $(call cmd,modules_install_extra)
$(Q)$(MAKE) -rR -f scripts/Makefile.modinst obj=$@
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
.PHONY: __modversions .PHONY: __modversions
__modversions: __modversions:
include .config
include scripts/Makefile.lib include scripts/Makefile.lib
# #
...@@ -26,9 +27,7 @@ quiet_cmd_ld_ko_o = LD [M] $@ ...@@ -26,9 +27,7 @@ quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
$(filter-out FORCE,$^) $(filter-out FORCE,$^)
init/vermagic.o: ; $(modules): %.ko :%.o %.mod.o FORCE
$(modules): %.ko :%.o %.ver.o init/vermagic.o FORCE
$(call if_changed,ld_ko_o) $(call if_changed,ld_ko_o)
targets += $(modules) targets += $(modules)
...@@ -36,54 +35,31 @@ targets += $(modules) ...@@ -36,54 +35,31 @@ targets += $(modules)
# Compile version info for unresolved symbols # Compile version info for unresolved symbols
quiet_cmd_cc_o_c = CC $@ quiet_cmd_cc_o_c = CC $@
cmd_cc_o_c = $(CC) $(CFLAGS) -c -o $@ $< cmd_cc_o_c = $(CC) $(CFLAGS) $(CFLAGS_MODULE) -c -o $@ $<
$(modules:.ko=.ver.o): %.ver.o: %.ver.c FORCE # We have a fake dependency on compile.h to make sure that we
$(call if_changed,cc_o_c) # notice if the compiler version changes under us.
targets += $(modules:.ko=.ver.o) $(modules:.ko=.mod.o): %.mod.o: %.mod.c include/linux/compile.h FORCE
$(call if_changed,cc_o_c)
# Generate C source with version info for unresolved symbols targets += $(modules:.ko=.mod.o)
define rule_mkver_o_c # All the .mod.c files are generated using the helper "modpost"
echo ' MKVER $@'; \
( echo "#include <linux/module.h>"; \
echo ""; \
echo "static const struct modversion_info ____versions[]"; \
echo "__attribute__((section(\"__versions\"))) = {"; \
for sym in `nm -u $<`; do \
grep "\"$$sym\"" .tmp_all-versions \
|| echo "*** Warning: $(<:.o=.ko): \"$$sym\" unresolved!" >&2;\
done; \
echo "};"; \
) > $@
endef
$(modules:.ko=.ver.c): %.ver.c: %.o .tmp_all-versions FORCE .PHONY: __modpost
$(call if_changed_rule,mkver_o_c)
targets += $(modules:.ko=.ver.c)) $(modules:.ko=.mod.c): __modpost ;
# Extract all checksums for all exported symbols # Extract all checksums for all exported symbols
export-objs := $(shell for m in vmlinux $(modules:.ko=.o); do objdump -h $$m | grep -q __ksymtab && echo $$m; done) quiet_cmd_modpost = MODPOST
cmd_modpost = scripts/modpost $^
cmd_gen-all-versions = mksyms $(export-objs)
define rule_gen-all-versions
echo ' MKSYMS $@'; \
for mod in $(export-objs); do \
modname=`basename $$mod`; \
nm $$mod \
| grep ' __crc_' \
| sed "s/\([^ ]*\) A __crc_\(.*\)/{ 0x\1, \"\2\" }, \/* $$modname *\//g;s/.* w __crc_\(.*\)/{ 0x0 , \"\1\" }, \/* $$modname *\//g"; \
done > $@; \
echo 'cmd_$@ := $(cmd_$(1))' > $(@D)/.$(@F).cmd
endef
.tmp_all-versions: $(export-objs) FORCE __modpost: $(wildcard vmlinux) $(modules:.ko=.o)
$(call if_changed_rule,gen-all-versions) $(call if_changed,modpost)
targets += .tmp_all-versions targets += __modpost
# Add FORCE to the prequisites of a target to force it to be always rebuilt. # Add FORCE to the prequisites of a target to force it to be always rebuilt.
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
......
/* empty file to figure out endianness / word size */
/* Simple code to turn various tables in an ELF file into alias definitions.
* This deals with kernel datastructures where they should be
* dealt with: in the kernel source.
*
* Copyright 2002-2003 Rusty Russell, IBM Corporation
* 2003 Kai Germaschewski
*
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*/
#include "modpost.h"
/* We use the ELF typedefs, since we can't rely on stdint.h being present. */
#if KERNEL_ELFCLASS == ELFCLASS32
typedef Elf32_Addr kernel_ulong_t;
#else
typedef Elf64_Addr kernel_ulong_t;
#endif
typedef Elf32_Word __u32;
typedef Elf32_Half __u16;
typedef unsigned char __u8;
/* Big exception to the "don't include kernel headers into userspace, which
* even potentially has different endianness and word sizes, since
* we handle those differences explicitly below */
#include "../include/linux/mod_devicetable.h"
#define ADD(str, sep, cond, field) \
do { \
strcat(str, sep); \
if (cond) \
sprintf(str + strlen(str), \
sizeof(field) == 1 ? "%02X" : \
sizeof(field) == 2 ? "%04X" : \
sizeof(field) == 4 ? "%08X" : "", \
field); \
else \
sprintf(str + strlen(str), "*"); \
} while(0)
/* Looks like "usb:vNpNdlNdhNdcNdscNdpNicNiscNipN" */
static int do_usb_entry(const char *filename,
struct usb_device_id *id, char *alias)
{
id->match_flags = TO_NATIVE(id->match_flags);
id->idVendor = TO_NATIVE(id->idVendor);
id->idProduct = TO_NATIVE(id->idProduct);
id->bcdDevice_lo = TO_NATIVE(id->bcdDevice_lo);
id->bcdDevice_hi = TO_NATIVE(id->bcdDevice_hi);
strcpy(alias, "usb:");
ADD(alias, "v", id->match_flags&USB_DEVICE_ID_MATCH_VENDOR,
id->idVendor);
ADD(alias, "p", id->match_flags&USB_DEVICE_ID_MATCH_PRODUCT,
id->idProduct);
ADD(alias, "dl", id->match_flags&USB_DEVICE_ID_MATCH_DEV_LO,
id->bcdDevice_lo);
ADD(alias, "dh", id->match_flags&USB_DEVICE_ID_MATCH_DEV_HI,
id->bcdDevice_hi);
ADD(alias, "dc", id->match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS,
id->bDeviceClass);
ADD(alias, "dsc",
id->match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS,
id->bDeviceSubClass);
ADD(alias, "dp",
id->match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
id->bDeviceProtocol);
ADD(alias, "ic",
id->match_flags&USB_DEVICE_ID_MATCH_INT_CLASS,
id->bInterfaceClass);
ADD(alias, "isc",
id->match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS,
id->bInterfaceSubClass);
ADD(alias, "ip",
id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL,
id->bInterfaceProtocol);
return 1;
}
/* Looks like: pci:vNdNsvNsdNcN. */
static int do_pci_entry(const char *filename,
struct pci_device_id *id, char *alias)
{
id->vendor = TO_NATIVE(id->vendor);
id->device = TO_NATIVE(id->device);
id->subvendor = TO_NATIVE(id->subvendor);
id->subdevice = TO_NATIVE(id->subdevice);
id->class = TO_NATIVE(id->class);
id->class_mask = TO_NATIVE(id->class_mask);
strcpy(alias, "pci:");
ADD(alias, "v", id->vendor != PCI_ANY_ID, id->vendor);
ADD(alias, "d", id->device != PCI_ANY_ID, id->device);
ADD(alias, "sv", id->subvendor != PCI_ANY_ID, id->subvendor);
ADD(alias, "sd", id->subdevice != PCI_ANY_ID, id->subdevice);
if (id->class_mask != 0 && id->class_mask != ~0) {
fprintf(stderr,
"*** Warning: Can't handle class_mask in %s:%04X\n",
filename, id->class_mask);
return 0;
}
ADD(alias, "c", id->class_mask == ~0, id->class);
return 1;
}
/* Ignore any prefix, eg. v850 prepends _ */
static inline int sym_is(const char *symbol, const char *name)
{
const char *match;
match = strstr(symbol, name);
if (!match)
return 0;
return match[strlen(symbol)] == '\0';
}
static void do_table(void *symval, unsigned long size,
unsigned long id_size,
void *function,
struct module *mod)
{
unsigned int i;
char alias[500];
int (*do_entry)(const char *, void *entry, char *alias) = function;
if (size % id_size || size < id_size) {
fprintf(stderr, "*** Warning: %s ids %lu bad size "
"(each on %lu)\n", mod->name, size, id_size);
}
/* Leave last one: it's the terminator. */
size -= id_size;
for (i = 0; i < size; i += id_size) {
if (do_entry(mod->name, symval+i, alias)) {
/* Always end in a wildcard, for future extension */
if (alias[strlen(alias)-1] != '*')
strcat(alias, "*");
buf_printf(&mod->dev_table_buf,
"MODULE_ALIAS(\"%s\");\n", alias);
}
}
}
/* Create MODULE_ALIAS() statements.
* At this time, we cannot write the actual output C source yet,
* so we write into the mod->dev_table_buf buffer. */
void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname)
{
void *symval;
/* We're looking for a section relative symbol */
if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum)
return;
symval = (void *)info->hdr
+ info->sechdrs[sym->st_shndx].sh_offset
+ sym->st_value;
if (sym_is(symname, "__mod_pci_device_table"))
do_table(symval, sym->st_size, sizeof(struct pci_device_id),
do_pci_entry, mod);
else if (sym_is(symname, "__mod_usb_device_table"))
do_table(symval, sym->st_size, sizeof(struct usb_device_id),
do_usb_entry, mod);
}
/* Now add out buffered information to the generated C source */
void add_moddevtable(struct buffer *buf, struct module *mod)
{
buf_printf(buf, "\n");
buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos);
free(mod->dev_table_buf.p);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <elf.h>
int
main(int argc, char **argv)
{
unsigned char ei[EI_NIDENT];
union { short s; char c[2]; } endian_test;
if (fread(ei, 1, EI_NIDENT, stdin) != EI_NIDENT) {
fprintf(stderr, "Error: input truncated\n");
return 1;
}
if (memcmp(ei, ELFMAG, SELFMAG) != 0) {
fprintf(stderr, "Error: not ELF\n");
return 1;
}
switch (ei[EI_CLASS]) {
case ELFCLASS32:
printf("#define KERNEL_ELFCLASS ELFCLASS32\n");
break;
case ELFCLASS64:
printf("#define KERNEL_ELFCLASS ELFCLASS64\n");
break;
default:
abort();
}
switch (ei[EI_DATA]) {
case ELFDATA2LSB:
printf("#define KERNEL_ELFDATA ELFDATA2LSB\n");
break;
case ELFDATA2MSB:
printf("#define KERNEL_ELFDATA ELFDATA2MSB\n");
break;
default:
abort();
}
if (sizeof(unsigned long) == 4) {
printf("#define HOST_ELFCLASS ELFCLASS32\n");
} else if (sizeof(unsigned long) == 8) {
printf("#define HOST_ELFCLASS ELFCLASS64\n");
}
endian_test.s = 0x0102;
if (memcmp(endian_test.c, "\x01\x02", 2) == 0)
printf("#define HOST_ELFDATA ELFDATA2MSB\n");
else if (memcmp(endian_test.c, "\x02\x01", 2) == 0)
printf("#define HOST_ELFDATA ELFDATA2LSB\n");
else
abort();
return 0;
}
/* Postprocess module symbol versions
*
* Copyright 2003 Kai Germaschewski
* 2002-2003 Rusty Russell, IBM Corporation
*
* Based in part on module-init-tools/depmod.c,file2alias
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Usage: modpost vmlinux module1.o module2.o ...
*/
#include "modpost.h"
/* Are we using CONFIG_MODVERSIONS? */
int modversions = 0;
/* Do we have vmlinux? */
int have_vmlinux = 0;
void
fatal(const char *fmt, ...)
{
va_list arglist;
fprintf(stderr, "FATAL: ");
va_start(arglist, fmt);
vfprintf(stderr, fmt, arglist);
va_end(arglist);
exit(1);
}
void
warn(const char *fmt, ...)
{
va_list arglist;
fprintf(stderr, "WARNING: ");
va_start(arglist, fmt);
vfprintf(stderr, fmt, arglist);
va_end(arglist);
}
#define NOFAIL(ptr) do_nofail((ptr), __FILE__, __LINE__, #ptr)
void *do_nofail(void *ptr, const char *file, int line, const char *expr)
{
if (!ptr) {
fatal("Memory allocation failure %s line %d: %s.\n",
file, line, expr);
}
return ptr;
}
/* A list of all modules we processed */
static struct module *modules;
struct module *
new_module(char *modname)
{
struct module *mod;
char *p;
/* strip trailing .o */
p = strstr(modname, ".o");
if (p)
*p = 0;
mod = NOFAIL(malloc(sizeof(*mod)));
memset(mod, 0, sizeof(*mod));
mod->name = modname;
/* add to list */
mod->next = modules;
modules = mod;
return mod;
}
/* A hash of all exported symbols,
* struct symbol is also used for lists of unresolved symbols */
#define SYMBOL_HASH_SIZE 1024
struct symbol {
struct symbol *next;
struct module *module;
unsigned int crc;
int crc_valid;
char name[0];
};
static struct symbol *symbolhash[SYMBOL_HASH_SIZE];
/* This is based on the hash agorithm from gdbm, via tdb */
static inline unsigned int tdb_hash(const char *name)
{
unsigned value; /* Used to compute the hash value. */
unsigned i; /* Used to cycle through random values. */
/* Set the initial value from the key size. */
for (value = 0x238F13AF * strlen(name), i=0; name[i]; i++)
value = (value + (((unsigned char *)name)[i] << (i*5 % 24)));
return (1103515243 * value + 12345);
}
/* Allocate a new symbols for use in the hash of exported symbols or
* the list of unresolved symbols per module */
struct symbol *
alloc_symbol(const char *name)
{
struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1));
memset(s, 0, sizeof(*s));
strcpy(s->name, name);
return s;
}
/* For the hash of exported symbols */
void
new_symbol(const char *name, struct module *module, unsigned int *crc)
{
unsigned int hash;
struct symbol *new = alloc_symbol(name);
new->module = module;
if (crc) {
new->crc = *crc;
new->crc_valid = 1;
}
hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
new->next = symbolhash[hash];
symbolhash[hash] = new;
}
struct symbol *
find_symbol(const char *name)
{
struct symbol *s;
/* For our purposes, .foo matches foo. PPC64 needs this. */
if (name[0] == '.')
name++;
for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s=s->next) {
if (strcmp(s->name, name) == 0)
return s;
}
return NULL;
}
/* Add an exported symbol - it may have already been added without a
* CRC, in this case just update the CRC */
void
add_exported_symbol(const char *name, struct module *module, unsigned int *crc)
{
struct symbol *s = find_symbol(name);
if (!s) {
new_symbol(name, modules, crc);
return;
}
if (crc) {
s->crc = *crc;
s->crc_valid = 1;
}
}
void *
grab_file(const char *filename, unsigned long *size)
{
struct stat st;
void *map;
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror(filename);
abort();
}
if (fstat(fd, &st) != 0) {
perror(filename);
abort();
}
*size = st.st_size;
map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
if (mmap == MAP_FAILED) {
perror(filename);
abort();
}
close(fd);
return map;
}
void
parse_elf(struct elf_info *info, const char *filename)
{
unsigned int i;
Elf_Ehdr *hdr = info->hdr;
Elf_Shdr *sechdrs;
Elf_Sym *sym;
hdr = grab_file(filename, &info->size);
info->hdr = hdr;
if (info->size < sizeof(*hdr))
goto truncated;
/* Fix endianness in ELF header */
hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
sechdrs = (void *)hdr + hdr->e_shoff;
info->sechdrs = sechdrs;
/* Fix endianness in section headers */
for (i = 0; i < hdr->e_shnum; i++) {
sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type);
sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset);
sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
}
/* Find symbol table. */
for (i = 1; i < hdr->e_shnum; i++) {
if (sechdrs[i].sh_offset > info->size)
goto truncated;
if (sechdrs[i].sh_type != SHT_SYMTAB)
continue;
info->symtab_start = (void *)hdr + sechdrs[i].sh_offset;
info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset
+ sechdrs[i].sh_size;
info->strtab = (void *)hdr +
sechdrs[sechdrs[i].sh_link].sh_offset;
}
if (!info->symtab_start) {
fprintf(stderr, "modpost: %s no symtab?\n", filename);
abort();
}
/* Fix endianness in symbols */
for (sym = info->symtab_start; sym < info->symtab_stop; sym++) {
sym->st_shndx = TO_NATIVE(sym->st_shndx);
sym->st_name = TO_NATIVE(sym->st_name);
sym->st_value = TO_NATIVE(sym->st_value);
sym->st_size = TO_NATIVE(sym->st_size);
}
return;
truncated:
fprintf(stderr, "modpost: %s is truncated.\n", filename);
abort();
}
void
parse_elf_finish(struct elf_info *info)
{
munmap(info->hdr, info->size);
}
void
handle_modversions(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname)
{
struct symbol *s;
switch (sym->st_shndx) {
case SHN_COMMON:
fprintf(stderr, "*** Warning: \"%s\" [%s] is COMMON symbol\n",
symname, mod->name);
break;
case SHN_ABS:
/* CRC'd symbol */
if (memcmp(symname, "__crc_", 6) == 0) {
add_exported_symbol(symname+6, mod, &sym->st_value);
modversions = 1;
}
break;
case SHN_UNDEF:
/* undefined symbol */
if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL)
break;
s = alloc_symbol(symname);
/* add to list */
s->next = mod->unres;
mod->unres = s;
break;
default:
/* All exported symbols */
if (memcmp(symname, "__ksymtab_", 10) == 0) {
add_exported_symbol(symname+10, mod, NULL);
}
break;
}
}
void
read_symbols(char *modname)
{
const char *symname;
struct module *mod;
struct elf_info info = { };
struct symbol *s;
Elf_Sym *sym;
/* When there's no vmlinux, don't print warnings about
* unresolved symbols (since there'll be too many ;) */
if (strcmp(modname, "vmlinux") == 0)
have_vmlinux = 1;
parse_elf(&info, modname);
mod = new_module(modname);
for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
symname = info.strtab + sym->st_name;
handle_modversions(mod, &info, sym, symname);
handle_moddevtable(mod, &info, sym, symname);
}
parse_elf_finish(&info);
/* Our trick to get versioning for struct_module - it's
* never passed as an argument to an exported function, so
* the automatic versioning doesn't pick it up, but it's really
* important anyhow */
if (modversions) {
s = alloc_symbol("struct_module");
/* add to list */
s->next = mod->unres;
mod->unres = s;
}
}
#define SZ 500
/* We first write the generated file into memory using the
* following helper, then compare to the file on disk and
* only update the later if anything changed */
void __attribute__((format(printf, 2, 3)))
buf_printf(struct buffer *buf, const char *fmt, ...)
{
char tmp[SZ];
int len;
va_list ap;
va_start(ap, fmt);
len = vsnprintf(tmp, SZ, fmt, ap);
if (buf->size - buf->pos < len + 1) {
buf->size += 128;
buf->p = realloc(buf->p, buf->size);
}
strncpy(buf->p + buf->pos, tmp, len + 1);
buf->pos += len;
va_end(ap);
}
void
buf_write(struct buffer *buf, const char *s, int len)
{
if (buf->size - buf->pos < len) {
buf->size += len;
buf->p = realloc(buf->p, buf->size);
}
strncpy(buf->p + buf->pos, s, len);
buf->pos += len;
}
/* Header for the generated file */
void
add_header(struct buffer *b)
{
buf_printf(b, "#include <linux/module.h>\n");
buf_printf(b, "#include <linux/vermagic.h>\n");
buf_printf(b, "\n");
buf_printf(b, "const char vermagic[]\n");
buf_printf(b, "__attribute__((section(\"__vermagic\"))) =\n");
buf_printf(b, "VERMAGIC_STRING;\n");
}
/* Record CRCs for unresolved symbols */
void
add_versions(struct buffer *b, struct module *mod)
{
struct symbol *s, *exp;
for (s = mod->unres; s; s = s->next) {
exp = find_symbol(s->name);
if (!exp || exp->module == mod) {
if (have_vmlinux)
fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
"undefined!\n", s->name, mod->name);
continue;
}
s->module = exp->module;
s->crc_valid = exp->crc_valid;
s->crc = exp->crc;
}
if (!modversions)
return;
buf_printf(b, "\n");
buf_printf(b, "static const struct modversion_info ____versions[]\n");
buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n");
for (s = mod->unres; s; s = s->next) {
if (!s->module) {
continue;
}
if (!s->crc_valid) {
fprintf(stderr, "*** Warning: \"%s\" [%s.ko] "
"has no CRC!\n",
s->name, mod->name);
continue;
}
buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name);
}
buf_printf(b, "};\n");
}
void
add_depends(struct buffer *b, struct module *mod, struct module *modules)
{
struct symbol *s;
struct module *m;
int first = 1;
for (m = modules; m; m = m->next) {
if (strcmp(m->name, "vmlinux") == 0)
m->seen = 1;
else
m->seen = 0;
}
buf_printf(b, "\n");
buf_printf(b, "static const char __module_depends[]\n");
buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
buf_printf(b, "\"depends=");
for (s = mod->unres; s; s = s->next) {
if (!s->module)
continue;
if (s->module->seen)
continue;
s->module->seen = 1;
buf_printf(b, "%s%s", first ? "" : ",",
strrchr(s->module->name, '/') + 1);
first = 0;
}
buf_printf(b, "\";\n");
}
void
write_if_changed(struct buffer *b, const char *fname)
{
char *tmp;
FILE *file;
struct stat st;
file = fopen(fname, "r");
if (!file)
goto write;
if (fstat(fileno(file), &st) < 0)
goto close_write;
if (st.st_size != b->pos)
goto close_write;
tmp = NOFAIL(malloc(b->pos));
if (fread(tmp, 1, b->pos, file) != b->pos)
goto free_write;
if (memcmp(tmp, b->p, b->pos) != 0)
goto free_write;
free(tmp);
fclose(file);
return;
free_write:
free(tmp);
close_write:
fclose(file);
write:
file = fopen(fname, "w");
if (!file) {
perror(fname);
exit(1);
}
if (fwrite(b->p, 1, b->pos, file) != b->pos) {
perror(fname);
exit(1);
}
fclose(file);
}
int
main(int argc, char **argv)
{
struct module *mod;
struct buffer buf = { };
char fname[SZ];
for (; argv[1]; argv++) {
read_symbols(argv[1]);
}
for (mod = modules; mod; mod = mod->next) {
if (strcmp(mod->name, "vmlinux") == 0)
continue;
buf.pos = 0;
add_header(&buf);
add_versions(&buf, mod);
add_depends(&buf, mod, modules);
add_moddevtable(&buf, mod);
sprintf(fname, "%s.mod.c", mod->name);
write_if_changed(&buf, fname);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <elf.h>
#include "elfconfig.h"
#if KERNEL_ELFCLASS == ELFCLASS32
#define Elf_Ehdr Elf32_Ehdr
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define ELF_ST_BIND ELF32_ST_BIND
#else
#define Elf_Ehdr Elf64_Ehdr
#define Elf_Shdr Elf64_Shdr
#define Elf_Sym Elf64_Sym
#define ELF_ST_BIND ELF64_ST_BIND
#endif
#if KERNEL_ELFDATA != HOST_ELFDATA
static void __endian(const void *src, void *dest, unsigned int size)
{
unsigned int i;
for (i = 0; i < size; i++)
((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1];
}
#define TO_NATIVE(x) \
({ \
typeof(x) __x; \
__endian(&(x), &(__x), sizeof(__x)); \
__x; \
})
#else /* endianness matches */
#define TO_NATIVE(x) (x)
#endif
struct buffer {
char *p;
int pos;
int size;
};
void __attribute__((format(printf, 2, 3)))
buf_printf(struct buffer *buf, const char *fmt, ...);
void
buf_write(struct buffer *buf, const char *s, int len);
struct module {
struct module *next;
const char *name;
struct symbol *unres;
int seen;
struct buffer dev_table_buf;
};
struct elf_info {
unsigned long size;
Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
Elf_Sym *symtab_start;
Elf_Sym *symtab_stop;
const char *strtab;
};
void handle_moddevtable(struct module *mod, struct elf_info *info,
Elf_Sym *sym, const char *symname);
void add_moddevtable(struct buffer *buf, struct module *mod);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment