diff options
Diffstat (limited to 'scripts/mod')
| -rw-r--r-- | scripts/mod/.gitignore | 2 | ||||
| -rw-r--r-- | scripts/mod/Makefile | 32 | ||||
| -rw-r--r-- | scripts/mod/devicetable-offsets.c | 190 | ||||
| -rw-r--r-- | scripts/mod/file2alias.c | 992 | ||||
| -rw-r--r-- | scripts/mod/mk_elfconfig.c | 1 | ||||
| -rw-r--r-- | scripts/mod/modpost.c | 392 | ||||
| -rw-r--r-- | scripts/mod/modpost.h | 30 | ||||
| -rw-r--r-- | scripts/mod/sumversion.c | 25 | 
8 files changed, 1136 insertions, 528 deletions
diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore index e9b7abe7b95..3bd11b60317 100644 --- a/scripts/mod/.gitignore +++ b/scripts/mod/.gitignore @@ -1,4 +1,4 @@  elfconfig.h  mk_elfconfig  modpost - +devicetable-offsets.h diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index ff954f8168c..c11212ff351 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile @@ -3,9 +3,41 @@ always		:= $(hostprogs-y) empty.o  modpost-objs	:= modpost.o file2alias.o sumversion.o +devicetable-offsets-file := devicetable-offsets.h + +define sed-y +	"/^->/{s:->#\(.*\):/* \1 */:; \ +	s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ +	s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ +	s:->::; p;}" +endef + +quiet_cmd_offsets = GEN     $@ +define cmd_offsets +	(set -e; \ +	 echo "#ifndef __DEVICETABLE_OFFSETS_H__"; \ +	 echo "#define __DEVICETABLE_OFFSETS_H__"; \ +	 echo "/*"; \ +	 echo " * DO NOT MODIFY."; \ +	 echo " *"; \ +	 echo " * This file was generated by Kbuild"; \ +	 echo " *"; \ +	 echo " */"; \ +	 echo ""; \ +	 sed -ne $(sed-y) $<; \ +	 echo ""; \ +	 echo "#endif" ) > $@ +endef + +$(obj)/$(devicetable-offsets-file): $(obj)/devicetable-offsets.s +	$(call if_changed,offsets) + +targets += $(devicetable-offsets-file) devicetable-offsets.s +  # dependencies on generated files need to be listed explicitly  $(obj)/modpost.o $(obj)/file2alias.o $(obj)/sumversion.o: $(obj)/elfconfig.h +$(obj)/file2alias.o: $(obj)/$(devicetable-offsets-file)  quiet_cmd_elfconfig = MKELF   $@        cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@ diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c new file mode 100644 index 00000000000..f282516acc7 --- /dev/null +++ b/scripts/mod/devicetable-offsets.c @@ -0,0 +1,190 @@ +#include <linux/kbuild.h> +#include <linux/mod_devicetable.h> + +#define DEVID(devid) DEFINE(SIZE_##devid, sizeof(struct devid)) +#define DEVID_FIELD(devid, field) \ +	DEFINE(OFF_##devid##_##field, offsetof(struct devid, field)) + +int main(void) +{ +	DEVID(usb_device_id); +	DEVID_FIELD(usb_device_id, match_flags); +	DEVID_FIELD(usb_device_id, idVendor); +	DEVID_FIELD(usb_device_id, idProduct); +	DEVID_FIELD(usb_device_id, bcdDevice_lo); +	DEVID_FIELD(usb_device_id, bcdDevice_hi); +	DEVID_FIELD(usb_device_id, bDeviceClass); +	DEVID_FIELD(usb_device_id, bDeviceSubClass); +	DEVID_FIELD(usb_device_id, bDeviceProtocol); +	DEVID_FIELD(usb_device_id, bInterfaceClass); +	DEVID_FIELD(usb_device_id, bInterfaceSubClass); +	DEVID_FIELD(usb_device_id, bInterfaceProtocol); +	DEVID_FIELD(usb_device_id, bInterfaceNumber); + +	DEVID(hid_device_id); +	DEVID_FIELD(hid_device_id, bus); +	DEVID_FIELD(hid_device_id, group); +	DEVID_FIELD(hid_device_id, vendor); +	DEVID_FIELD(hid_device_id, product); + +	DEVID(ieee1394_device_id); +	DEVID_FIELD(ieee1394_device_id, match_flags); +	DEVID_FIELD(ieee1394_device_id, vendor_id); +	DEVID_FIELD(ieee1394_device_id, model_id); +	DEVID_FIELD(ieee1394_device_id, specifier_id); +	DEVID_FIELD(ieee1394_device_id, version); + +	DEVID(pci_device_id); +	DEVID_FIELD(pci_device_id, vendor); +	DEVID_FIELD(pci_device_id, device); +	DEVID_FIELD(pci_device_id, subvendor); +	DEVID_FIELD(pci_device_id, subdevice); +	DEVID_FIELD(pci_device_id, class); +	DEVID_FIELD(pci_device_id, class_mask); + +	DEVID(ccw_device_id); +	DEVID_FIELD(ccw_device_id, match_flags); +	DEVID_FIELD(ccw_device_id, cu_type); +	DEVID_FIELD(ccw_device_id, cu_model); +	DEVID_FIELD(ccw_device_id, dev_type); +	DEVID_FIELD(ccw_device_id, dev_model); + +	DEVID(ap_device_id); +	DEVID_FIELD(ap_device_id, dev_type); + +	DEVID(css_device_id); +	DEVID_FIELD(css_device_id, type); + +	DEVID(serio_device_id); +	DEVID_FIELD(serio_device_id, type); +	DEVID_FIELD(serio_device_id, proto); +	DEVID_FIELD(serio_device_id, id); +	DEVID_FIELD(serio_device_id, extra); + +	DEVID(acpi_device_id); +	DEVID_FIELD(acpi_device_id, id); + +	DEVID(pnp_device_id); +	DEVID_FIELD(pnp_device_id, id); + +	DEVID(pnp_card_device_id); +	DEVID_FIELD(pnp_card_device_id, devs); + +	DEVID(pcmcia_device_id); +	DEVID_FIELD(pcmcia_device_id, match_flags); +	DEVID_FIELD(pcmcia_device_id, manf_id); +	DEVID_FIELD(pcmcia_device_id, card_id); +	DEVID_FIELD(pcmcia_device_id, func_id); +	DEVID_FIELD(pcmcia_device_id, function); +	DEVID_FIELD(pcmcia_device_id, device_no); +	DEVID_FIELD(pcmcia_device_id, prod_id_hash); + +	DEVID(of_device_id); +	DEVID_FIELD(of_device_id, name); +	DEVID_FIELD(of_device_id, type); +	DEVID_FIELD(of_device_id, compatible); + +	DEVID(vio_device_id); +	DEVID_FIELD(vio_device_id, type); +	DEVID_FIELD(vio_device_id, compat); + +	DEVID(input_device_id); +	DEVID_FIELD(input_device_id, flags); +	DEVID_FIELD(input_device_id, bustype); +	DEVID_FIELD(input_device_id, vendor); +	DEVID_FIELD(input_device_id, product); +	DEVID_FIELD(input_device_id, version); +	DEVID_FIELD(input_device_id, evbit); +	DEVID_FIELD(input_device_id, keybit); +	DEVID_FIELD(input_device_id, relbit); +	DEVID_FIELD(input_device_id, absbit); +	DEVID_FIELD(input_device_id, mscbit); +	DEVID_FIELD(input_device_id, ledbit); +	DEVID_FIELD(input_device_id, sndbit); +	DEVID_FIELD(input_device_id, ffbit); +	DEVID_FIELD(input_device_id, swbit); + +	DEVID(eisa_device_id); +	DEVID_FIELD(eisa_device_id, sig); + +	DEVID(parisc_device_id); +	DEVID_FIELD(parisc_device_id, hw_type); +	DEVID_FIELD(parisc_device_id, hversion); +	DEVID_FIELD(parisc_device_id, hversion_rev); +	DEVID_FIELD(parisc_device_id, sversion); + +	DEVID(sdio_device_id); +	DEVID_FIELD(sdio_device_id, class); +	DEVID_FIELD(sdio_device_id, vendor); +	DEVID_FIELD(sdio_device_id, device); + +	DEVID(ssb_device_id); +	DEVID_FIELD(ssb_device_id, vendor); +	DEVID_FIELD(ssb_device_id, coreid); +	DEVID_FIELD(ssb_device_id, revision); + +	DEVID(bcma_device_id); +	DEVID_FIELD(bcma_device_id, manuf); +	DEVID_FIELD(bcma_device_id, id); +	DEVID_FIELD(bcma_device_id, rev); +	DEVID_FIELD(bcma_device_id, class); + +	DEVID(virtio_device_id); +	DEVID_FIELD(virtio_device_id, device); +	DEVID_FIELD(virtio_device_id, vendor); + +	DEVID(hv_vmbus_device_id); +	DEVID_FIELD(hv_vmbus_device_id, guid); + +	DEVID(i2c_device_id); +	DEVID_FIELD(i2c_device_id, name); + +	DEVID(spi_device_id); +	DEVID_FIELD(spi_device_id, name); + +	DEVID(dmi_system_id); +	DEVID_FIELD(dmi_system_id, matches); + +	DEVID(platform_device_id); +	DEVID_FIELD(platform_device_id, name); + +	DEVID(mdio_device_id); +	DEVID_FIELD(mdio_device_id, phy_id); +	DEVID_FIELD(mdio_device_id, phy_id_mask); + +	DEVID(zorro_device_id); +	DEVID_FIELD(zorro_device_id, id); + +	DEVID(isapnp_device_id); +	DEVID_FIELD(isapnp_device_id, vendor); +	DEVID_FIELD(isapnp_device_id, function); + +	DEVID(ipack_device_id); +	DEVID_FIELD(ipack_device_id, format); +	DEVID_FIELD(ipack_device_id, vendor); +	DEVID_FIELD(ipack_device_id, device); + +	DEVID(amba_id); +	DEVID_FIELD(amba_id, id); +	DEVID_FIELD(amba_id, mask); + +	DEVID(x86_cpu_id); +	DEVID_FIELD(x86_cpu_id, feature); +	DEVID_FIELD(x86_cpu_id, family); +	DEVID_FIELD(x86_cpu_id, model); +	DEVID_FIELD(x86_cpu_id, vendor); + +	DEVID(cpu_feature); +	DEVID_FIELD(cpu_feature, feature); + +	DEVID(mei_cl_device_id); +	DEVID_FIELD(mei_cl_device_id, name); + +	DEVID(rio_device_id); +	DEVID_FIELD(rio_device_id, did); +	DEVID_FIELD(rio_device_id, vid); +	DEVID_FIELD(rio_device_id, asm_did); +	DEVID_FIELD(rio_device_id, asm_vid); + +	return 0; +} diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 88f3f07205f..e614ef689ee 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -11,6 +11,7 @@   */  #include "modpost.h" +#include "devicetable-offsets.h"  /* We use the ELF typedefs for kernel_ulong_t but bite the bullet and   * use either stdint.h or inttypes.h for the rest. */ @@ -28,6 +29,7 @@ typedef Elf64_Addr	kernel_ulong_t;  #endif  #include <ctype.h> +#include <stdbool.h>  typedef uint32_t	__u32;  typedef uint16_t	__u16; @@ -38,6 +40,75 @@ typedef unsigned char	__u8;   * we handle those differences explicitly below */  #include "../../include/linux/mod_devicetable.h" +/* This array collects all instances that use the generic do_table */ +struct devtable { +	const char *device_id; /* name of table, __mod_<name>__*_device_table. */ +	unsigned long id_size; +	void *function; +}; + +#define ___cat(a,b) a ## b +#define __cat(a,b) ___cat(a,b) + +/* we need some special handling for this host tool running eventually on + * Darwin. The Mach-O section handling is a bit different than ELF section + * handling. The differnces in detail are: + *  a) we have segments which have sections + *  b) we need a API call to get the respective section symbols */ +#if defined(__MACH__) +#include <mach-o/getsect.h> + +#define INIT_SECTION(name)  do {					\ +		unsigned long name ## _len;				\ +		char *__cat(pstart_,name) = getsectdata("__TEXT",	\ +			#name, &__cat(name,_len));			\ +		char *__cat(pstop_,name) = __cat(pstart_,name) +	\ +			__cat(name, _len);				\ +		__cat(__start_,name) = (void *)__cat(pstart_,name);	\ +		__cat(__stop_,name) = (void *)__cat(pstop_,name);	\ +	} while (0) +#define SECTION(name)   __attribute__((section("__TEXT, " #name))) + +struct devtable **__start___devtable, **__stop___devtable; +#else +#define INIT_SECTION(name) /* no-op for ELF */ +#define SECTION(name)   __attribute__((section(#name))) + +/* We construct a table of pointers in an ELF section (pointers generally + * go unpadded by gcc).  ld creates boundary syms for us. */ +extern struct devtable *__start___devtable[], *__stop___devtable[]; +#endif /* __MACH__ */ + +#if !defined(__used) +# if __GNUC__ == 3 && __GNUC_MINOR__ < 3 +#  define __used			__attribute__((__unused__)) +# else +#  define __used			__attribute__((__used__)) +# endif +#endif + +/* Define a variable f that holds the value of field f of struct devid + * based at address m. + */ +#define DEF_FIELD(m, devid, f) \ +	typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f)) +/* Define a variable f that holds the address of field f of struct devid + * based at address m.  Due to the way typeof works, for a field of type + * T[N] the variable has type T(*)[N], _not_ T*. + */ +#define DEF_FIELD_ADDR(m, devid, f) \ +	typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) + +/* Add a table entry.  We test function type matches while we're here. */ +#define ADD_TO_DEVTABLE(device_id, type, function) \ +	static struct devtable __cat(devtable,__LINE__) = {	\ +		device_id + 0*sizeof((function)((const char *)NULL,	\ +						(void *)NULL,		\ +						(char *)NULL)),		\ +		SIZE_##type, (function) };				\ +	static struct devtable *SECTION(__devtable) __used \ +		__cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) +  #define ADD(str, sep, cond, field)                              \  do {                                                            \          strcat(str, sep);                                       \ @@ -60,7 +131,6 @@ static inline void add_wildcard(char *str)  		strcat(str + len, "*");  } -unsigned int cross_build = 0;  /**   * Check that sizeof(device_id type) are consistent with size of section   * in .o file. If in-consistent then userspace and kernel does not agree @@ -75,10 +145,9 @@ static void device_id_check(const char *modname, const char *device_id,  	int i;  	if (size % id_size || size < id_size) { -		if (cross_build != 0) -			return;  		fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " -		      "of the size of section __mod_%s_device_table=%lu.\n" +		      "of the size of " +		      "section __mod_%s__<identifier>_device_table=%lu.\n"  		      "Fix definition of struct %s_device_id "  		      "in mod_devicetable.h\n",  		      modname, device_id, id_size, device_id, size, device_id); @@ -100,18 +169,30 @@ static void device_id_check(const char *modname, const char *device_id,  }  /* USB is special because the bcdDevice can be matched against a numeric range */ -/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */ -static void do_usb_entry(struct usb_device_id *id, +/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ +static void do_usb_entry(void *symval,  			 unsigned int bcdDevice_initial, int bcdDevice_initial_digits,  			 unsigned char range_lo, unsigned char range_hi,  			 unsigned char max, struct module *mod)  {  	char alias[500]; +	DEF_FIELD(symval, usb_device_id, match_flags); +	DEF_FIELD(symval, usb_device_id, idVendor); +	DEF_FIELD(symval, usb_device_id, idProduct); +	DEF_FIELD(symval, usb_device_id, bcdDevice_lo); +	DEF_FIELD(symval, usb_device_id, bDeviceClass); +	DEF_FIELD(symval, usb_device_id, bDeviceSubClass); +	DEF_FIELD(symval, usb_device_id, bDeviceProtocol); +	DEF_FIELD(symval, usb_device_id, bInterfaceClass); +	DEF_FIELD(symval, usb_device_id, bInterfaceSubClass); +	DEF_FIELD(symval, usb_device_id, bInterfaceProtocol); +	DEF_FIELD(symval, usb_device_id, bInterfaceNumber); +  	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, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR, +	    idVendor); +	ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT, +	    idProduct);  	strcat(alias, "d");  	if (bcdDevice_initial_digits) @@ -130,30 +211,27 @@ static void do_usb_entry(struct usb_device_id *id,  				range_lo < 0x9 ? "[%X-9" : "[%X",  				range_lo);  			sprintf(alias + strlen(alias), -				range_hi > 0xA ? "a-%X]" : "%X]", -				range_lo); +				range_hi > 0xA ? "A-%X]" : "%X]", +				range_hi);  		}  	} -	if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1)) +	if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1))  		strcat(alias, "*"); -	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); +	ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, +	    bDeviceClass); +	ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, +	    bDeviceSubClass); +	ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, +	    bDeviceProtocol); +	ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, +	    bInterfaceClass); +	ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, +	    bInterfaceSubClass); +	ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, +	    bInterfaceProtocol); +	ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, +	    bInterfaceNumber);  	add_wildcard(alias);  	buf_printf(&mod->dev_table_buf, @@ -199,24 +277,28 @@ static unsigned int incbcd(unsigned int *bcd,  	return init;  } -static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) +static void do_usb_entry_multi(void *symval, struct module *mod)  {  	unsigned int devlo, devhi;  	unsigned char chi, clo, max;  	int ndigits; -	id->match_flags = TO_NATIVE(id->match_flags); -	id->idVendor = TO_NATIVE(id->idVendor); -	id->idProduct = TO_NATIVE(id->idProduct); +	DEF_FIELD(symval, usb_device_id, match_flags); +	DEF_FIELD(symval, usb_device_id, idVendor); +	DEF_FIELD(symval, usb_device_id, idProduct); +	DEF_FIELD(symval, usb_device_id, bcdDevice_lo); +	DEF_FIELD(symval, usb_device_id, bcdDevice_hi); +	DEF_FIELD(symval, usb_device_id, bDeviceClass); +	DEF_FIELD(symval, usb_device_id, bInterfaceClass); -	devlo = id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? -		TO_NATIVE(id->bcdDevice_lo) : 0x0U; -	devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? -		TO_NATIVE(id->bcdDevice_hi) : ~0x0U; +	devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? +		bcdDevice_lo : 0x0U; +	devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? +		bcdDevice_hi : ~0x0U;  	/* Figure out if this entry is in bcd or hex format */  	max = 0x9; /* Default to decimal format */ -	for (ndigits = 0 ; ndigits < sizeof(id->bcdDevice_lo) * 2 ; ndigits++) { +	for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) {  		clo = (devlo >> (ndigits << 2)) & 0xf;  		chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf;  		if (clo > max || chi > max) { @@ -229,11 +311,11 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)  	 * Some modules (visor) have empty slots as placeholder for  	 * run-time specification that results in catch-all alias  	 */ -	if (!(id->idVendor | id->idProduct | id->bDeviceClass | id->bInterfaceClass)) +	if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass))  		return;  	/* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ -	for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { +	for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) {  		clo = devlo & 0xf;  		chi = devhi & 0xf;  		if (chi > max)	/* If we are in bcd mode, truncate if necessary */ @@ -242,20 +324,20 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)  		devhi >>= 4;  		if (devlo == devhi || !ndigits) { -			do_usb_entry(id, devlo, ndigits, clo, chi, max, mod); +			do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod);  			break;  		}  		if (clo > 0x0) -			do_usb_entry(id, +			do_usb_entry(symval,  				     incbcd(&devlo, 1, max, -					    sizeof(id->bcdDevice_lo) * 2), +					    sizeof(bcdDevice_lo) * 2),  				     ndigits, clo, max, max, mod);  		if (chi < max) -			do_usb_entry(id, +			do_usb_entry(symval,  				     incbcd(&devhi, -1, max, -					    sizeof(id->bcdDevice_lo) * 2), +					    sizeof(bcdDevice_lo) * 2),  				     ndigits, 0x0, chi, max, mod);  	}  } @@ -264,7 +346,7 @@ static void do_usb_table(void *symval, unsigned long size,  			 struct module *mod)  {  	unsigned int i; -	const unsigned long id_size = sizeof(struct usb_device_id); +	const unsigned long id_size = SIZE_usb_device_id;  	device_id_check(mod->name, "usb", size, id_size, symval); @@ -277,76 +359,81 @@ static void do_usb_table(void *symval, unsigned long size,  /* Looks like: hid:bNvNpN */  static int do_hid_entry(const char *filename, -			     struct hid_device_id *id, char *alias) +			     void *symval, char *alias)  { -	id->bus = TO_NATIVE(id->bus); -	id->vendor = TO_NATIVE(id->vendor); -	id->product = TO_NATIVE(id->product); +	DEF_FIELD(symval, hid_device_id, bus); +	DEF_FIELD(symval, hid_device_id, group); +	DEF_FIELD(symval, hid_device_id, vendor); +	DEF_FIELD(symval, hid_device_id, product); -	sprintf(alias, "hid:b%04X", id->bus); -	ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); -	ADD(alias, "p", id->product != HID_ANY_ID, id->product); +	sprintf(alias, "hid:"); +	ADD(alias, "b", bus != HID_BUS_ANY, bus); +	ADD(alias, "g", group != HID_GROUP_ANY, group); +	ADD(alias, "v", vendor != HID_ANY_ID, vendor); +	ADD(alias, "p", product != HID_ANY_ID, product);  	return 1;  } +ADD_TO_DEVTABLE("hid", hid_device_id, do_hid_entry);  /* Looks like: ieee1394:venNmoNspNverN */  static int do_ieee1394_entry(const char *filename, -			     struct ieee1394_device_id *id, char *alias) +			     void *symval, char *alias)  { -	id->match_flags = TO_NATIVE(id->match_flags); -	id->vendor_id = TO_NATIVE(id->vendor_id); -	id->model_id = TO_NATIVE(id->model_id); -	id->specifier_id = TO_NATIVE(id->specifier_id); -	id->version = TO_NATIVE(id->version); +	DEF_FIELD(symval, ieee1394_device_id, match_flags); +	DEF_FIELD(symval, ieee1394_device_id, vendor_id); +	DEF_FIELD(symval, ieee1394_device_id, model_id); +	DEF_FIELD(symval, ieee1394_device_id, specifier_id); +	DEF_FIELD(symval, ieee1394_device_id, version);  	strcpy(alias, "ieee1394:"); -	ADD(alias, "ven", id->match_flags & IEEE1394_MATCH_VENDOR_ID, -	    id->vendor_id); -	ADD(alias, "mo", id->match_flags & IEEE1394_MATCH_MODEL_ID, -	    id->model_id); -	ADD(alias, "sp", id->match_flags & IEEE1394_MATCH_SPECIFIER_ID, -	    id->specifier_id); -	ADD(alias, "ver", id->match_flags & IEEE1394_MATCH_VERSION, -	    id->version); +	ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID, +	    vendor_id); +	ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID, +	    model_id); +	ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID, +	    specifier_id); +	ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION, +	    version);  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("ieee1394", ieee1394_device_id, do_ieee1394_entry);  /* Looks like: pci:vNdNsvNsdNbcNscNiN. */  static int do_pci_entry(const char *filename, -			struct pci_device_id *id, char *alias) +			void *symval, char *alias)  {  	/* Class field can be divided into these three. */  	unsigned char baseclass, subclass, interface,  		baseclass_mask, subclass_mask, interface_mask; -	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); +	DEF_FIELD(symval, pci_device_id, vendor); +	DEF_FIELD(symval, pci_device_id, device); +	DEF_FIELD(symval, pci_device_id, subvendor); +	DEF_FIELD(symval, pci_device_id, subdevice); +	DEF_FIELD(symval, pci_device_id, class); +	DEF_FIELD(symval, pci_device_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); - -	baseclass = (id->class) >> 16; -	baseclass_mask = (id->class_mask) >> 16; -	subclass = (id->class) >> 8; -	subclass_mask = (id->class_mask) >> 8; -	interface = id->class; -	interface_mask = id->class_mask; +	ADD(alias, "v", vendor != PCI_ANY_ID, vendor); +	ADD(alias, "d", device != PCI_ANY_ID, device); +	ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor); +	ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice); + +	baseclass = (class) >> 16; +	baseclass_mask = (class_mask) >> 16; +	subclass = (class) >> 8; +	subclass_mask = (class_mask) >> 8; +	interface = class; +	interface_mask = class_mask;  	if ((baseclass_mask != 0 && baseclass_mask != 0xFF)  	    || (subclass_mask != 0 && subclass_mask != 0xFF)  	    || (interface_mask != 0 && interface_mask != 0xFF)) {  		warn("Can't handle masks in %s:%04X\n", -		     filename, id->class_mask); +		     filename, class_mask);  		return 0;  	} @@ -356,95 +443,105 @@ static int do_pci_entry(const char *filename,  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("pci", pci_device_id, do_pci_entry);  /* looks like: "ccw:tNmNdtNdmN" */  static int do_ccw_entry(const char *filename, -			struct ccw_device_id *id, char *alias) +			void *symval, char *alias)  { -	id->match_flags = TO_NATIVE(id->match_flags); -	id->cu_type = TO_NATIVE(id->cu_type); -	id->cu_model = TO_NATIVE(id->cu_model); -	id->dev_type = TO_NATIVE(id->dev_type); -	id->dev_model = TO_NATIVE(id->dev_model); +	DEF_FIELD(symval, ccw_device_id, match_flags); +	DEF_FIELD(symval, ccw_device_id, cu_type); +	DEF_FIELD(symval, ccw_device_id, cu_model); +	DEF_FIELD(symval, ccw_device_id, dev_type); +	DEF_FIELD(symval, ccw_device_id, dev_model);  	strcpy(alias, "ccw:"); -	ADD(alias, "t", id->match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, -	    id->cu_type); -	ADD(alias, "m", id->match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, -	    id->cu_model); -	ADD(alias, "dt", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, -	    id->dev_type); -	ADD(alias, "dm", id->match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, -	    id->dev_model); +	ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, +	    cu_type); +	ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, +	    cu_model); +	ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, +	    dev_type); +	ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, +	    dev_model);  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("ccw", ccw_device_id, do_ccw_entry);  /* looks like: "ap:tN" */  static int do_ap_entry(const char *filename, -		       struct ap_device_id *id, char *alias) +		       void *symval, char *alias)  { -	sprintf(alias, "ap:t%02X*", id->dev_type); +	DEF_FIELD(symval, ap_device_id, dev_type); + +	sprintf(alias, "ap:t%02X*", dev_type);  	return 1;  } +ADD_TO_DEVTABLE("ap", ap_device_id, do_ap_entry);  /* looks like: "css:tN" */  static int do_css_entry(const char *filename, -			struct css_device_id *id, char *alias) +			void *symval, char *alias)  { -	sprintf(alias, "css:t%01X", id->type); +	DEF_FIELD(symval, css_device_id, type); + +	sprintf(alias, "css:t%01X", type);  	return 1;  } +ADD_TO_DEVTABLE("css", css_device_id, do_css_entry);  /* Looks like: "serio:tyNprNidNexN" */  static int do_serio_entry(const char *filename, -			  struct serio_device_id *id, char *alias) +			  void *symval, char *alias)  { -	id->type = TO_NATIVE(id->type); -	id->proto = TO_NATIVE(id->proto); -	id->id = TO_NATIVE(id->id); -	id->extra = TO_NATIVE(id->extra); +	DEF_FIELD(symval, serio_device_id, type); +	DEF_FIELD(symval, serio_device_id, proto); +	DEF_FIELD(symval, serio_device_id, id); +	DEF_FIELD(symval, serio_device_id, extra);  	strcpy(alias, "serio:"); -	ADD(alias, "ty", id->type != SERIO_ANY, id->type); -	ADD(alias, "pr", id->proto != SERIO_ANY, id->proto); -	ADD(alias, "id", id->id != SERIO_ANY, id->id); -	ADD(alias, "ex", id->extra != SERIO_ANY, id->extra); +	ADD(alias, "ty", type != SERIO_ANY, type); +	ADD(alias, "pr", proto != SERIO_ANY, proto); +	ADD(alias, "id", id != SERIO_ANY, id); +	ADD(alias, "ex", extra != SERIO_ANY, extra);  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry);  /* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */  static int do_acpi_entry(const char *filename, -			struct acpi_device_id *id, char *alias) +			void *symval, char *alias)  { -	sprintf(alias, "acpi*:%s:*", id->id); +	DEF_FIELD_ADDR(symval, acpi_device_id, id); +	sprintf(alias, "acpi*:%s:*", *id);  	return 1;  } +ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry);  /* looks like: "pnp:dD" */  static void do_pnp_device_entry(void *symval, unsigned long size,  				struct module *mod)  { -	const unsigned long id_size = sizeof(struct pnp_device_id); +	const unsigned long id_size = SIZE_pnp_device_id;  	const unsigned int count = (size / id_size)-1; -	const struct pnp_device_id *devs = symval;  	unsigned int i;  	device_id_check(mod->name, "pnp", size, id_size, symval);  	for (i = 0; i < count; i++) { -		const char *id = (char *)devs[i].id; -		char acpi_id[sizeof(devs[0].id)]; +		DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); +		char acpi_id[sizeof(*id)];  		int j;  		buf_printf(&mod->dev_table_buf, -			   "MODULE_ALIAS(\"pnp:d%s*\");\n", id); +			   "MODULE_ALIAS(\"pnp:d%s*\");\n", *id);  		/* fix broken pnp bus lowercasing */  		for (j = 0; j < sizeof(acpi_id); j++) -			acpi_id[j] = toupper(id[j]); +			acpi_id[j] = toupper((*id)[j]);  		buf_printf(&mod->dev_table_buf,  			   "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id);  	} @@ -454,19 +551,18 @@ static void do_pnp_device_entry(void *symval, unsigned long size,  static void do_pnp_card_entries(void *symval, unsigned long size,  				struct module *mod)  { -	const unsigned long id_size = sizeof(struct pnp_card_device_id); +	const unsigned long id_size = SIZE_pnp_card_device_id;  	const unsigned int count = (size / id_size)-1; -	const struct pnp_card_device_id *cards = symval;  	unsigned int i;  	device_id_check(mod->name, "pnp", size, id_size, symval);  	for (i = 0; i < count; i++) {  		unsigned int j; -		const struct pnp_card_device_id *card = &cards[i]; +		DEF_FIELD_ADDR(symval + i*id_size, pnp_card_device_id, devs);  		for (j = 0; j < PNP_MAX_DEVICES; j++) { -			const char *id = (char *)card->devs[j].id; +			const char *id = (char *)(*devs)[j].id;  			int i2, j2;  			int dup = 0; @@ -475,10 +571,10 @@ static void do_pnp_card_entries(void *symval, unsigned long size,  			/* find duplicate, already added value */  			for (i2 = 0; i2 < i && !dup; i2++) { -				const struct pnp_card_device_id *card2 = &cards[i2]; +				DEF_FIELD_ADDR(symval + i2*id_size, pnp_card_device_id, devs);  				for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { -					const char *id2 = (char *)card2->devs[j2].id; +					const char *id2 = (char *)(*devs)[j2].id;  					if (!id2[0])  						break; @@ -492,7 +588,7 @@ static void do_pnp_card_entries(void *symval, unsigned long size,  			/* add an individual alias for every device entry */  			if (!dup) { -				char acpi_id[sizeof(card->devs[0].id)]; +				char acpi_id[PNP_ID_LEN];  				int k;  				buf_printf(&mod->dev_table_buf, @@ -510,72 +606,76 @@ static void do_pnp_card_entries(void *symval, unsigned long size,  /* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */  static int do_pcmcia_entry(const char *filename, -			   struct pcmcia_device_id *id, char *alias) +			   void *symval, char *alias)  {  	unsigned int i; - -	id->match_flags = TO_NATIVE(id->match_flags); -	id->manf_id = TO_NATIVE(id->manf_id); -	id->card_id = TO_NATIVE(id->card_id); -	id->func_id = TO_NATIVE(id->func_id); -	id->function = TO_NATIVE(id->function); -	id->device_no = TO_NATIVE(id->device_no); +	DEF_FIELD(symval, pcmcia_device_id, match_flags); +	DEF_FIELD(symval, pcmcia_device_id, manf_id); +	DEF_FIELD(symval, pcmcia_device_id, card_id); +	DEF_FIELD(symval, pcmcia_device_id, func_id); +	DEF_FIELD(symval, pcmcia_device_id, function); +	DEF_FIELD(symval, pcmcia_device_id, device_no); +	DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash);  	for (i=0; i<4; i++) { -		id->prod_id_hash[i] = TO_NATIVE(id->prod_id_hash[i]); -       } - -       strcpy(alias, "pcmcia:"); -       ADD(alias, "m", id->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, -	   id->manf_id); -       ADD(alias, "c", id->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, -	   id->card_id); -       ADD(alias, "f", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, -	   id->func_id); -       ADD(alias, "fn", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, -	   id->function); -       ADD(alias, "pfn", id->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, -	   id->device_no); -       ADD(alias, "pa", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, id->prod_id_hash[0]); -       ADD(alias, "pb", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, id->prod_id_hash[1]); -       ADD(alias, "pc", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, id->prod_id_hash[2]); -       ADD(alias, "pd", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, id->prod_id_hash[3]); +		(*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]); +	} + +	strcpy(alias, "pcmcia:"); +	ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, +	    manf_id); +	ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, +	    card_id); +	ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, +	    func_id); +	ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, +	    function); +	ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, +	    device_no); +	ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]); +	ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]); +	ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]); +	ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]);  	add_wildcard(alias); -       return 1; +	return 1;  } +ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); - - -static int do_of_entry (const char *filename, struct of_device_id *of, char *alias) +static int do_of_entry (const char *filename, void *symval, char *alias)  { -    int len; -    char *tmp; -    len = sprintf (alias, "of:N%sT%s", -                    of->name[0] ? of->name : "*", -                    of->type[0] ? of->type : "*"); +	int len; +	char *tmp; +	DEF_FIELD_ADDR(symval, of_device_id, name); +	DEF_FIELD_ADDR(symval, of_device_id, type); +	DEF_FIELD_ADDR(symval, of_device_id, compatible); -    if (of->compatible[0]) -        sprintf (&alias[len], "%sC%s", -                     of->type[0] ? "*" : "", -                     of->compatible); +	len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*", +		      (*type)[0] ? *type : "*"); -    /* Replace all whitespace with underscores */ -    for (tmp = alias; tmp && *tmp; tmp++) -        if (isspace (*tmp)) -            *tmp = '_'; +	if (compatible[0]) +		sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "", +			*compatible); -    add_wildcard(alias); -    return 1; +	/* Replace all whitespace with underscores */ +	for (tmp = alias; tmp && *tmp; tmp++) +		if (isspace (*tmp)) +			*tmp = '_'; + +	add_wildcard(alias); +	return 1;  } +ADD_TO_DEVTABLE("of", of_device_id, do_of_entry); -static int do_vio_entry(const char *filename, struct vio_device_id *vio, +static int do_vio_entry(const char *filename, void *symval,  		char *alias)  {  	char *tmp; +	DEF_FIELD_ADDR(symval, vio_device_id, type); +	DEF_FIELD_ADDR(symval, vio_device_id, compat); -	sprintf(alias, "vio:T%sS%s", vio->type[0] ? vio->type : "*", -			vio->compat[0] ? vio->compat : "*"); +	sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*", +			(*compat)[0] ? *compat : "*");  	/* Replace all whitespace with underscores */  	for (tmp = alias; tmp && *tmp; tmp++) @@ -585,6 +685,7 @@ static int do_vio_entry(const char *filename, struct vio_device_id *vio,  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("vio", vio_device_id, do_vio_entry);  #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -593,147 +694,217 @@ static void do_input(char *alias,  {  	unsigned int i; +	for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++) +		arr[i] = TO_NATIVE(arr[i]);  	for (i = min; i < max; i++)  		if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG)))  			sprintf(alias + strlen(alias), "%X,*", i);  }  /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ -static int do_input_entry(const char *filename, struct input_device_id *id, +static int do_input_entry(const char *filename, void *symval,  			  char *alias)  { +	DEF_FIELD(symval, input_device_id, flags); +	DEF_FIELD(symval, input_device_id, bustype); +	DEF_FIELD(symval, input_device_id, vendor); +	DEF_FIELD(symval, input_device_id, product); +	DEF_FIELD(symval, input_device_id, version); +	DEF_FIELD_ADDR(symval, input_device_id, evbit); +	DEF_FIELD_ADDR(symval, input_device_id, keybit); +	DEF_FIELD_ADDR(symval, input_device_id, relbit); +	DEF_FIELD_ADDR(symval, input_device_id, absbit); +	DEF_FIELD_ADDR(symval, input_device_id, mscbit); +	DEF_FIELD_ADDR(symval, input_device_id, ledbit); +	DEF_FIELD_ADDR(symval, input_device_id, sndbit); +	DEF_FIELD_ADDR(symval, input_device_id, ffbit); +	DEF_FIELD_ADDR(symval, input_device_id, swbit); +  	sprintf(alias, "input:"); -	ADD(alias, "b", id->flags & INPUT_DEVICE_ID_MATCH_BUS, id->bustype); -	ADD(alias, "v", id->flags & INPUT_DEVICE_ID_MATCH_VENDOR, id->vendor); -	ADD(alias, "p", id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT, id->product); -	ADD(alias, "e", id->flags & INPUT_DEVICE_ID_MATCH_VERSION, id->version); +	ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); +	ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); +	ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); +	ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version);  	sprintf(alias + strlen(alias), "-e*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT) -		do_input(alias, id->evbit, 0, INPUT_DEVICE_ID_EV_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_EVBIT) +		do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX);  	sprintf(alias + strlen(alias), "k*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT) -		do_input(alias, id->keybit, +	if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT) +		do_input(alias, *keybit,  			 INPUT_DEVICE_ID_KEY_MIN_INTERESTING,  			 INPUT_DEVICE_ID_KEY_MAX);  	sprintf(alias + strlen(alias), "r*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_RELBIT) -		do_input(alias, id->relbit, 0, INPUT_DEVICE_ID_REL_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_RELBIT) +		do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX);  	sprintf(alias + strlen(alias), "a*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_ABSBIT) -		do_input(alias, id->absbit, 0, INPUT_DEVICE_ID_ABS_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT) +		do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX);  	sprintf(alias + strlen(alias), "m*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_MSCIT) -		do_input(alias, id->mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_MSCIT) +		do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX);  	sprintf(alias + strlen(alias), "l*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_LEDBIT) -		do_input(alias, id->ledbit, 0, INPUT_DEVICE_ID_LED_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT) +		do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX);  	sprintf(alias + strlen(alias), "s*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_SNDBIT) -		do_input(alias, id->sndbit, 0, INPUT_DEVICE_ID_SND_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT) +		do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX);  	sprintf(alias + strlen(alias), "f*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_FFBIT) -		do_input(alias, id->ffbit, 0, INPUT_DEVICE_ID_FF_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_FFBIT) +		do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX);  	sprintf(alias + strlen(alias), "w*"); -	if (id->flags & INPUT_DEVICE_ID_MATCH_SWBIT) -		do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX); +	if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) +		do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX);  	return 1;  } +ADD_TO_DEVTABLE("input", input_device_id, do_input_entry); -static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa, +static int do_eisa_entry(const char *filename, void *symval,  		char *alias)  { -	if (eisa->sig[0]) -		sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", eisa->sig); +	DEF_FIELD_ADDR(symval, eisa_device_id, sig); +	if (sig[0]) +		sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig);  	else  		strcat(alias, "*");  	return 1;  } +ADD_TO_DEVTABLE("eisa", eisa_device_id, do_eisa_entry);  /* Looks like: parisc:tNhvNrevNsvN */ -static int do_parisc_entry(const char *filename, struct parisc_device_id *id, +static int do_parisc_entry(const char *filename, void *symval,  		char *alias)  { -	id->hw_type = TO_NATIVE(id->hw_type); -	id->hversion = TO_NATIVE(id->hversion); -	id->hversion_rev = TO_NATIVE(id->hversion_rev); -	id->sversion = TO_NATIVE(id->sversion); +	DEF_FIELD(symval, parisc_device_id, hw_type); +	DEF_FIELD(symval, parisc_device_id, hversion); +	DEF_FIELD(symval, parisc_device_id, hversion_rev); +	DEF_FIELD(symval, parisc_device_id, sversion);  	strcpy(alias, "parisc:"); -	ADD(alias, "t", id->hw_type != PA_HWTYPE_ANY_ID, id->hw_type); -	ADD(alias, "hv", id->hversion != PA_HVERSION_ANY_ID, id->hversion); -	ADD(alias, "rev", id->hversion_rev != PA_HVERSION_REV_ANY_ID, id->hversion_rev); -	ADD(alias, "sv", id->sversion != PA_SVERSION_ANY_ID, id->sversion); +	ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); +	ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); +	ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); +	ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion);  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("parisc", parisc_device_id, do_parisc_entry);  /* Looks like: sdio:cNvNdN. */  static int do_sdio_entry(const char *filename, -			struct sdio_device_id *id, char *alias) +			void *symval, char *alias)  { -	id->class = TO_NATIVE(id->class); -	id->vendor = TO_NATIVE(id->vendor); -	id->device = TO_NATIVE(id->device); +	DEF_FIELD(symval, sdio_device_id, class); +	DEF_FIELD(symval, sdio_device_id, vendor); +	DEF_FIELD(symval, sdio_device_id, device);  	strcpy(alias, "sdio:"); -	ADD(alias, "c", id->class != (__u8)SDIO_ANY_ID, id->class); -	ADD(alias, "v", id->vendor != (__u16)SDIO_ANY_ID, id->vendor); -	ADD(alias, "d", id->device != (__u16)SDIO_ANY_ID, id->device); +	ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); +	ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); +	ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device);  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("sdio", sdio_device_id, do_sdio_entry);  /* Looks like: ssb:vNidNrevN. */  static int do_ssb_entry(const char *filename, -			struct ssb_device_id *id, char *alias) +			void *symval, char *alias)  { -	id->vendor = TO_NATIVE(id->vendor); -	id->coreid = TO_NATIVE(id->coreid); -	id->revision = TO_NATIVE(id->revision); +	DEF_FIELD(symval, ssb_device_id, vendor); +	DEF_FIELD(symval, ssb_device_id, coreid); +	DEF_FIELD(symval, ssb_device_id, revision);  	strcpy(alias, "ssb:"); -	ADD(alias, "v", id->vendor != SSB_ANY_VENDOR, id->vendor); -	ADD(alias, "id", id->coreid != SSB_ANY_ID, id->coreid); -	ADD(alias, "rev", id->revision != SSB_ANY_REV, id->revision); +	ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); +	ADD(alias, "id", coreid != SSB_ANY_ID, coreid); +	ADD(alias, "rev", revision != SSB_ANY_REV, revision); +	add_wildcard(alias); +	return 1; +} +ADD_TO_DEVTABLE("ssb", ssb_device_id, do_ssb_entry); + +/* Looks like: bcma:mNidNrevNclN. */ +static int do_bcma_entry(const char *filename, +			 void *symval, char *alias) +{ +	DEF_FIELD(symval, bcma_device_id, manuf); +	DEF_FIELD(symval, bcma_device_id, id); +	DEF_FIELD(symval, bcma_device_id, rev); +	DEF_FIELD(symval, bcma_device_id, class); + +	strcpy(alias, "bcma:"); +	ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); +	ADD(alias, "id", id != BCMA_ANY_ID, id); +	ADD(alias, "rev", rev != BCMA_ANY_REV, rev); +	ADD(alias, "cl", class != BCMA_ANY_CLASS, class);  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("bcma", bcma_device_id, do_bcma_entry);  /* Looks like: virtio:dNvN */ -static int do_virtio_entry(const char *filename, struct virtio_device_id *id, +static int do_virtio_entry(const char *filename, void *symval,  			   char *alias)  { -	id->device = TO_NATIVE(id->device); -	id->vendor = TO_NATIVE(id->vendor); +	DEF_FIELD(symval, virtio_device_id, device); +	DEF_FIELD(symval, virtio_device_id, vendor);  	strcpy(alias, "virtio:"); -	ADD(alias, "d", id->device != VIRTIO_DEV_ANY_ID, id->device); -	ADD(alias, "v", id->vendor != VIRTIO_DEV_ANY_ID, id->vendor); +	ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); +	ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor);  	add_wildcard(alias);  	return 1;  } +ADD_TO_DEVTABLE("virtio", virtio_device_id, do_virtio_entry); + +/* + * Looks like: vmbus:guid + * Each byte of the guid will be represented by two hex characters + * in the name. + */ + +static int do_vmbus_entry(const char *filename, void *symval, +			  char *alias) +{ +	int i; +	DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); +	char guid_name[(sizeof(*guid) + 1) * 2]; + +	for (i = 0; i < (sizeof(*guid) * 2); i += 2) +		sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2])); + +	strcpy(alias, "vmbus:"); +	strcat(alias, guid_name); + +	return 1; +} +ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry);  /* Looks like: i2c:S */ -static int do_i2c_entry(const char *filename, struct i2c_device_id *id, +static int do_i2c_entry(const char *filename, void *symval,  			char *alias)  { -	sprintf(alias, I2C_MODULE_PREFIX "%s", id->name); +	DEF_FIELD_ADDR(symval, i2c_device_id, name); +	sprintf(alias, I2C_MODULE_PREFIX "%s", *name);  	return 1;  } +ADD_TO_DEVTABLE("i2c", i2c_device_id, do_i2c_entry);  /* Looks like: spi:S */ -static int do_spi_entry(const char *filename, struct spi_device_id *id, +static int do_spi_entry(const char *filename, void *symval,  			char *alias)  { -	sprintf(alias, SPI_MODULE_PREFIX "%s", id->name); +	DEF_FIELD_ADDR(symval, spi_device_id, name); +	sprintf(alias, SPI_MODULE_PREFIX "%s", *name);  	return 1;  } +ADD_TO_DEVTABLE("spi", spi_device_id, do_spi_entry);  static const struct dmifield {  	const char *prefix; @@ -765,21 +936,21 @@ static void dmi_ascii_filter(char *d, const char *s)  } -static int do_dmi_entry(const char *filename, struct dmi_system_id *id, +static int do_dmi_entry(const char *filename, void *symval,  			char *alias)  {  	int i, j; - +	DEF_FIELD_ADDR(symval, dmi_system_id, matches);  	sprintf(alias, "dmi*");  	for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) {  		for (j = 0; j < 4; j++) { -			if (id->matches[j].slot && -			    id->matches[j].slot == dmi_fields[i].field) { +			if ((*matches)[j].slot && +			    (*matches)[j].slot == dmi_fields[i].field) {  				sprintf(alias + strlen(alias), ":%s*",  					dmi_fields[i].prefix);  				dmi_ascii_filter(alias + strlen(alias), -						 id->matches[j].substr); +						 (*matches)[j].substr);  				strcat(alias, "*");  			}  		} @@ -788,25 +959,30 @@ static int do_dmi_entry(const char *filename, struct dmi_system_id *id,  	strcat(alias, ":");  	return 1;  } +ADD_TO_DEVTABLE("dmi", dmi_system_id, do_dmi_entry);  static int do_platform_entry(const char *filename, -			     struct platform_device_id *id, char *alias) +			     void *symval, char *alias)  { -	sprintf(alias, PLATFORM_MODULE_PREFIX "%s", id->name); +	DEF_FIELD_ADDR(symval, platform_device_id, name); +	sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name);  	return 1;  } +ADD_TO_DEVTABLE("platform", platform_device_id, do_platform_entry);  static int do_mdio_entry(const char *filename, -			 struct mdio_device_id *id, char *alias) +			 void *symval, char *alias)  {  	int i; +	DEF_FIELD(symval, mdio_device_id, phy_id); +	DEF_FIELD(symval, mdio_device_id, phy_id_mask);  	alias += sprintf(alias, MDIO_MODULE_PREFIX);  	for (i = 0; i < 32; i++) { -		if (!((id->phy_id_mask >> (31-i)) & 1)) +		if (!((phy_id_mask >> (31-i)) & 1))  			*(alias++) = '?'; -		else if ((id->phy_id >> (31-i)) & 1) +		else if ((phy_id >> (31-i)) & 1)  			*(alias++) = '1';  		else  			*(alias++) = '0'; @@ -817,39 +993,196 @@ static int do_mdio_entry(const char *filename,  	return 1;  } +ADD_TO_DEVTABLE("mdio", mdio_device_id, do_mdio_entry);  /* Looks like: zorro:iN. */ -static int do_zorro_entry(const char *filename, struct zorro_device_id *id, +static int do_zorro_entry(const char *filename, void *symval,  			  char *alias)  { -	id->id = TO_NATIVE(id->id); +	DEF_FIELD(symval, zorro_device_id, id);  	strcpy(alias, "zorro:"); -	ADD(alias, "i", id->id != ZORRO_WILDCARD, id->id); +	ADD(alias, "i", id != ZORRO_WILDCARD, id);  	return 1;  } +ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry);  /* looks like: "pnp:dD" */  static int do_isapnp_entry(const char *filename, -			   struct isapnp_device_id *id, char *alias) +			   void *symval, char *alias)  { +	DEF_FIELD(symval, isapnp_device_id, vendor); +	DEF_FIELD(symval, isapnp_device_id, function);  	sprintf(alias, "pnp:d%c%c%c%x%x%x%x*", -		'A' + ((id->vendor >> 2) & 0x3f) - 1, -		'A' + (((id->vendor & 3) << 3) | ((id->vendor >> 13) & 7)) - 1, -		'A' + ((id->vendor >> 8) & 0x1f) - 1, -		(id->function >> 4) & 0x0f, id->function & 0x0f, -		(id->function >> 12) & 0x0f, (id->function >> 8) & 0x0f); +		'A' + ((vendor >> 2) & 0x3f) - 1, +		'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, +		'A' + ((vendor >> 8) & 0x1f) - 1, +		(function >> 4) & 0x0f, function & 0x0f, +		(function >> 12) & 0x0f, (function >> 8) & 0x0f);  	return 1;  } +ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry); -/* Ignore any prefix, eg. some architectures prepend _ */ -static inline int sym_is(const char *symbol, const char *name) +/* Looks like: "ipack:fNvNdN". */ +static int do_ipack_entry(const char *filename, +			  void *symval, char *alias)  { -	const char *match; +	DEF_FIELD(symval, ipack_device_id, format); +	DEF_FIELD(symval, ipack_device_id, vendor); +	DEF_FIELD(symval, ipack_device_id, device); +	strcpy(alias, "ipack:"); +	ADD(alias, "f", format != IPACK_ANY_FORMAT, format); +	ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); +	ADD(alias, "d", device != IPACK_ANY_ID, device); +	add_wildcard(alias); +	return 1; +} +ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry); -	match = strstr(symbol, name); -	if (!match) -		return 0; -	return match[strlen(name)] == '\0'; +/* + * Append a match expression for a single masked hex digit. + * outp points to a pointer to the character at which to append. + *	*outp is updated on return to point just after the appended text, + *	to facilitate further appending. + */ +static void append_nibble_mask(char **outp, +			       unsigned int nibble, unsigned int mask) +{ +	char *p = *outp; +	unsigned int i; + +	switch (mask) { +	case 0: +		*p++ = '?'; +		break; + +	case 0xf: +		p += sprintf(p, "%X",  nibble); +		break; + +	default: +		/* +		 * Dumbly emit a match pattern for all possible matching +		 * digits.  This could be improved in some cases using ranges, +		 * but it has the advantage of being trivially correct, and is +		 * often optimal. +		 */ +		*p++ = '['; +		for (i = 0; i < 0x10; i++) +			if ((i & mask) == nibble) +				p += sprintf(p, "%X", i); +		*p++ = ']'; +	} + +	/* Ensure that the string remains NUL-terminated: */ +	*p = '\0'; + +	/* Advance the caller's end-of-string pointer: */ +	*outp = p; +} + +/* + * looks like: "amba:dN" + * + * N is exactly 8 digits, where each is an upper-case hex digit, or + *	a ? or [] pattern matching exactly one digit. + */ +static int do_amba_entry(const char *filename, +			 void *symval, char *alias) +{ +	unsigned int digit; +	char *p = alias; +	DEF_FIELD(symval, amba_id, id); +	DEF_FIELD(symval, amba_id, mask); + +	if ((id & mask) != id) +		fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: " +		      "id=0x%08X, mask=0x%08X.  Please fix this driver.\n", +		      filename, id, mask); + +	p += sprintf(alias, "amba:d"); +	for (digit = 0; digit < 8; digit++) +		append_nibble_mask(&p, +				   (id >> (4 * (7 - digit))) & 0xf, +				   (mask >> (4 * (7 - digit))) & 0xf); + +	return 1; +} +ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); + +/* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* + * All fields are numbers. It would be nicer to use strings for vendor + * and feature, but getting those out of the build system here is too + * complicated. + */ + +static int do_x86cpu_entry(const char *filename, void *symval, +			   char *alias) +{ +	DEF_FIELD(symval, x86_cpu_id, feature); +	DEF_FIELD(symval, x86_cpu_id, family); +	DEF_FIELD(symval, x86_cpu_id, model); +	DEF_FIELD(symval, x86_cpu_id, vendor); + +	strcpy(alias, "cpu:type:x86,"); +	ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); +	ADD(alias, "fam", family != X86_FAMILY_ANY, family); +	ADD(alias, "mod", model  != X86_MODEL_ANY,  model); +	strcat(alias, ":feature:*"); +	if (feature != X86_FEATURE_ANY) +		sprintf(alias + strlen(alias), "%04X*", feature); +	return 1; +} +ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); + +/* LOOKS like cpu:type:*:feature:*FEAT* */ +static int do_cpu_entry(const char *filename, void *symval, char *alias) +{ +	DEF_FIELD(symval, cpu_feature, feature); + +	sprintf(alias, "cpu:type:*:feature:*%04X*", feature); +	return 1; +} +ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry); + +/* Looks like: mei:S */ +static int do_mei_entry(const char *filename, void *symval, +			char *alias) +{ +	DEF_FIELD_ADDR(symval, mei_cl_device_id, name); + +	sprintf(alias, MEI_CL_MODULE_PREFIX "%s", *name); + +	return 1; +} +ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); + +/* Looks like: rapidio:vNdNavNadN */ +static int do_rio_entry(const char *filename, +			void *symval, char *alias) +{ +	DEF_FIELD(symval, rio_device_id, did); +	DEF_FIELD(symval, rio_device_id, vid); +	DEF_FIELD(symval, rio_device_id, asm_did); +	DEF_FIELD(symval, rio_device_id, asm_vid); + +	strcpy(alias, "rapidio:"); +	ADD(alias, "v", vid != RIO_ANY_ID, vid); +	ADD(alias, "d", did != RIO_ANY_ID, did); +	ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); +	ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); + +	add_wildcard(alias); +	return 1; +} +ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry); + +/* Does namelen bytes of name exactly match the symbol? */ +static bool sym_is(const char *name, unsigned namelen, const char *symbol) +{ +	if (namelen != strlen(symbol)) +		return false; + +	return memcmp(name, symbol, namelen) == 0;  }  static void do_table(void *symval, unsigned long size, @@ -882,11 +1215,32 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,  {  	void *symval;  	char *zeros = NULL; +	const char *name, *identifier; +	unsigned int namelen;  	/* We're looking for a section relative symbol */  	if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections)  		return; +	/* We're looking for an object */ +	if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) +		return; + +	/* All our symbols are of form <prefix>__mod_<name>__<identifier>_device_table. */ +	name = strstr(symname, "__mod_"); +	if (!name) +		return; +	name += strlen("__mod_"); +	namelen = strlen(name); +	if (namelen < strlen("_device_table")) +		return; +	if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) +		return; +	identifier = strstr(name, "__"); +	if (!identifier) +		return; +	namelen = identifier - name; +  	/* Handle all-NULL symbols allocated into .bss */  	if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {  		zeros = calloc(1, sym->st_size); @@ -897,109 +1251,25 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,  			+ sym->st_value;  	} -	if (sym_is(symname, "__mod_pci_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct pci_device_id), "pci", -			 do_pci_entry, mod); -	else if (sym_is(symname, "__mod_usb_device_table")) -		/* special case to handle bcdDevice ranges */ +	/* First handle the "special" cases */ +	if (sym_is(name, namelen, "usb"))  		do_usb_table(symval, sym->st_size, mod); -	else if (sym_is(symname, "__mod_hid_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct hid_device_id), "hid", -			 do_hid_entry, mod); -	else if (sym_is(symname, "__mod_ieee1394_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct ieee1394_device_id), "ieee1394", -			 do_ieee1394_entry, mod); -	else if (sym_is(symname, "__mod_ccw_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct ccw_device_id), "ccw", -			 do_ccw_entry, mod); -	else if (sym_is(symname, "__mod_ap_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct ap_device_id), "ap", -			 do_ap_entry, mod); -	else if (sym_is(symname, "__mod_css_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct css_device_id), "css", -			 do_css_entry, mod); -	else if (sym_is(symname, "__mod_serio_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct serio_device_id), "serio", -			 do_serio_entry, mod); -	else if (sym_is(symname, "__mod_acpi_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct acpi_device_id), "acpi", -			 do_acpi_entry, mod); -	else if (sym_is(symname, "__mod_pnp_device_table")) +	else if (sym_is(name, namelen, "pnp"))  		do_pnp_device_entry(symval, sym->st_size, mod); -	else if (sym_is(symname, "__mod_pnp_card_device_table")) +	else if (sym_is(name, namelen, "pnp_card"))  		do_pnp_card_entries(symval, sym->st_size, mod); -	else if (sym_is(symname, "__mod_pcmcia_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct pcmcia_device_id), "pcmcia", -			 do_pcmcia_entry, mod); -        else if (sym_is(symname, "__mod_of_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct of_device_id), "of", -			 do_of_entry, mod); -        else if (sym_is(symname, "__mod_vio_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct vio_device_id), "vio", -			 do_vio_entry, mod); -	else if (sym_is(symname, "__mod_input_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct input_device_id), "input", -			 do_input_entry, mod); -	else if (sym_is(symname, "__mod_eisa_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct eisa_device_id), "eisa", -			 do_eisa_entry, mod); -	else if (sym_is(symname, "__mod_parisc_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct parisc_device_id), "parisc", -			 do_parisc_entry, mod); -	else if (sym_is(symname, "__mod_sdio_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct sdio_device_id), "sdio", -			 do_sdio_entry, mod); -	else if (sym_is(symname, "__mod_ssb_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct ssb_device_id), "ssb", -			 do_ssb_entry, mod); -	else if (sym_is(symname, "__mod_virtio_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct virtio_device_id), "virtio", -			 do_virtio_entry, mod); -	else if (sym_is(symname, "__mod_i2c_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct i2c_device_id), "i2c", -			 do_i2c_entry, mod); -	else if (sym_is(symname, "__mod_spi_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct spi_device_id), "spi", -			 do_spi_entry, mod); -	else if (sym_is(symname, "__mod_dmi_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct dmi_system_id), "dmi", -			 do_dmi_entry, mod); -	else if (sym_is(symname, "__mod_platform_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct platform_device_id), "platform", -			 do_platform_entry, mod); -	else if (sym_is(symname, "__mod_mdio_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct mdio_device_id), "mdio", -			 do_mdio_entry, mod); -	else if (sym_is(symname, "__mod_zorro_device_table")) -		do_table(symval, sym->st_size, -			 sizeof(struct zorro_device_id), "zorro", -			 do_zorro_entry, mod); -	else if (sym_is(symname, "__mod_isapnp_device_table")) -		do_table(symval, sym->st_size, -			sizeof(struct isapnp_device_id), "isa", -			do_isapnp_entry, mod); +	else { +		struct devtable **p; +		INIT_SECTION(__devtable); + +		for (p = __start___devtable; p < __stop___devtable; p++) { +			if (sym_is(name, namelen, (*p)->device_id)) { +				do_table(symval, sym->st_size, (*p)->id_size, +					 (*p)->device_id, (*p)->function, mod); +				break; +			} +		} +	}  	free(zeros);  } diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c index 639bca7ba55..a4fd71d71d6 100644 --- a/scripts/mod/mk_elfconfig.c +++ b/scripts/mod/mk_elfconfig.c @@ -54,4 +54,3 @@ main(int argc, char **argv)  	return 0;  } - diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 33122ca04e7..9d9c5b905b3 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -15,17 +15,13 @@  #include <stdio.h>  #include <ctype.h>  #include <string.h> +#include <limits.h> +#include <stdbool.h> +#include <errno.h>  #include "modpost.h"  #include "../../include/generated/autoconf.h"  #include "../../include/linux/license.h" - -/* Some toolchains use a `_' prefix for all user symbols. */ -#ifdef CONFIG_SYMBOL_PREFIX -#define MODULE_SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX -#else -#define MODULE_SYMBOL_PREFIX "" -#endif - +#include "../../include/linux/export.h"  /* Are we using CONFIG_MODVERSIONS? */  int modversions = 0; @@ -42,6 +38,8 @@ static int warn_unresolved = 0;  /* How a symbol is exported */  static int sec_mismatch_count = 0;  static int sec_mismatch_verbose = 1; +/* ignore missing files */ +static int ignore_missing_files;  enum export {  	export_plain,      export_unused,     export_gpl, @@ -85,6 +83,14 @@ PRINTF void merror(const char *fmt, ...)  	va_end(arglist);  } +static inline bool strends(const char *str, const char *postfix) +{ +	if (strlen(str) < strlen(postfix)) +		return false; + +	return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; +} +  static int is_vmlinux(const char *modname)  {  	const char *myname; @@ -120,20 +126,20 @@ static struct module *find_module(char *modname)  	return mod;  } -static struct module *new_module(char *modname) +static struct module *new_module(const char *modname)  {  	struct module *mod; -	char *p, *s; +	char *p;  	mod = NOFAIL(malloc(sizeof(*mod)));  	memset(mod, 0, sizeof(*mod));  	p = NOFAIL(strdup(modname));  	/* strip trailing .o */ -	s = strrchr(p, '.'); -	if (s != NULL) -		if (strcmp(s, ".o") == 0) -			*s = '\0'; +	if (strends(p, ".o")) { +		p[strlen(p) - 2] = '\0'; +		mod->is_dot_o = 1; +	}  	/* add to list */  	mod->name = p; @@ -158,7 +164,7 @@ struct symbol {  	unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */  	unsigned int kernel:1;     /* 1 if symbol is from kernel  				    *  (only for external modules) **/ -	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers */ +	unsigned int preloaded:1;  /* 1 if symbol from Module.symvers, or crc */  	enum export  export;       /* Type of export */  	char name[0];  }; @@ -254,6 +260,28 @@ static enum export export_no(const char *s)  	return export_unknown;  } +static const char *sec_name(struct elf_info *elf, int secindex); + +#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) + +static enum export export_from_secname(struct elf_info *elf, unsigned int sec) +{ +	const char *secname = sec_name(elf, sec); + +	if (strstarts(secname, "___ksymtab+")) +		return export_plain; +	else if (strstarts(secname, "___ksymtab_unused+")) +		return export_unused; +	else if (strstarts(secname, "___ksymtab_gpl+")) +		return export_gpl; +	else if (strstarts(secname, "___ksymtab_unused_gpl+")) +		return export_unused_gpl; +	else if (strstarts(secname, "___ksymtab_gpl_future+")) +		return export_gpl_future; +	else +		return export_unknown; +} +  static enum export export_from_sec(struct elf_info *elf, unsigned int sec)  {  	if (sec == elf->export_sec) @@ -288,7 +316,7 @@ static struct symbol *sym_add_exported(const char *name, struct module *mod,  			     s->module->name,  			     is_vmlinux(s->module->name) ?"":".ko");  		} else { -			/* In case Modules.symvers was out of date */ +			/* In case Module.symvers was out of date */  			s->module = mod;  		}  	} @@ -304,8 +332,11 @@ static void sym_update_crc(const char *name, struct module *mod,  {  	struct symbol *s = find_symbol(name); -	if (!s) +	if (!s) {  		s = new_symbol(name, mod, export); +		/* Don't complain when we find it later. */ +		s->preloaded = 1; +	}  	s->crc = crc;  	s->crc_valid = 1;  } @@ -313,17 +344,20 @@ static void sym_update_crc(const char *name, struct module *mod,  void *grab_file(const char *filename, unsigned long *size)  {  	struct stat st; -	void *map; +	void *map = MAP_FAILED;  	int fd;  	fd = open(filename, O_RDONLY); -	if (fd < 0 || fstat(fd, &st) != 0) +	if (fd < 0)  		return NULL; +	if (fstat(fd, &st)) +		goto failed;  	*size = st.st_size;  	map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); -	close(fd); +failed: +	close(fd);  	if (map == MAP_FAILED)  		return NULL;  	return map; @@ -379,6 +413,11 @@ static int parse_elf(struct elf_info *info, const char *filename)  	hdr = grab_file(filename, &info->size);  	if (!hdr) { +		if (ignore_missing_files) { +			fprintf(stderr, "%s: %s (ignored)\n", filename, +				strerror(errno)); +			return 0; +		}  		perror(filename);  		exit(1);  	} @@ -420,11 +459,10 @@ static int parse_elf(struct elf_info *info, const char *filename)  		return 0;  	} -	if (hdr->e_shnum == 0) { +	if (hdr->e_shnum == SHN_UNDEF) {  		/*  		 * There are more than 64k sections,  		 * read count from .sh_size. -		 * note: it doesn't need shndx2secindex()  		 */  		info->num_sections = TO_NATIVE(sechdrs[0].sh_size);  	} @@ -432,8 +470,7 @@ static int parse_elf(struct elf_info *info, const char *filename)  		info->num_sections = hdr->e_shnum;  	}  	if (hdr->e_shstrndx == SHN_XINDEX) { -		info->secindex_strings = -		    shndx2secindex(TO_NATIVE(sechdrs[0].sh_link)); +		info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);  	}  	else {  		info->secindex_strings = hdr->e_shstrndx; @@ -489,7 +526,7 @@ static int parse_elf(struct elf_info *info, const char *filename)  			    sechdrs[i].sh_offset;  			info->symtab_stop  = (void *)hdr +  			    sechdrs[i].sh_offset + sechdrs[i].sh_size; -			sh_link_idx = shndx2secindex(sechdrs[i].sh_link); +			sh_link_idx = sechdrs[i].sh_link;  			info->strtab       = (void *)hdr +  			    sechdrs[sh_link_idx].sh_offset;  		} @@ -516,11 +553,9 @@ static int parse_elf(struct elf_info *info, const char *filename)  	if (symtab_shndx_idx != ~0U) {  		Elf32_Word *p; -		if (symtab_idx != -		    shndx2secindex(sechdrs[symtab_shndx_idx].sh_link)) +		if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)  			fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", -			      filename, -			      shndx2secindex(sechdrs[symtab_shndx_idx].sh_link), +			      filename, sechdrs[symtab_shndx_idx].sh_link,  			      symtab_idx);  		/* Fix endianness */  		for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; @@ -539,7 +574,7 @@ static void parse_elf_finish(struct elf_info *info)  static int ignore_undef_symbol(struct elf_info *info, const char *symname)  {  	/* ignore __this_module, it will be resolved shortly */ -	if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) +	if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0)  		return 1;  	/* ignore global offset table */  	if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) @@ -549,37 +584,49 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)  		if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 ||  		    strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 ||  		    strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || -		    strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0) +		    strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 || +		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || +		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)  			return 1;  	if (info->hdr->e_machine == EM_PPC64)  		/* Special register function linked on all modules during final link of .ko */  		if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || -		    strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0) +		    strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || +		    strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || +		    strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)  			return 1;  	/* Do not ignore this symbol */  	return 0;  } -#define CRC_PFX     MODULE_SYMBOL_PREFIX "__crc_" -#define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_" +#define CRC_PFX     VMLINUX_SYMBOL_STR(__crc_) +#define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_)  static void handle_modversions(struct module *mod, struct elf_info *info,  			       Elf_Sym *sym, const char *symname)  {  	unsigned int crc; -	enum export export = export_from_sec(info, get_secindex(info, sym)); +	enum export export; + +	if ((!is_vmlinux(mod->name) || mod->is_dot_o) && +	    strncmp(symname, "__ksymtab", 9) == 0) +		export = export_from_secname(info, get_secindex(info, sym)); +	else +		export = export_from_sec(info, get_secindex(info, sym)); + +	/* CRC'd symbol */ +	if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { +		crc = (unsigned int) sym->st_value; +		sym_update_crc(symname + strlen(CRC_PFX), mod, crc, +				export); +	}  	switch (sym->st_shndx) {  	case SHN_COMMON: -		warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); -		break; -	case SHN_ABS: -		/* CRC'd symbol */ -		if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { -			crc = (unsigned int) sym->st_value; -			sym_update_crc(symname + strlen(CRC_PFX), mod, crc, -					export); -		} +		if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) { +			/* Should warn here, but modpost runs before the linker */ +		} else +			warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name);  		break;  	case SHN_UNDEF:  		/* undefined symbol */ @@ -608,14 +655,15 @@ static void handle_modversions(struct module *mod, struct elf_info *info,  		}  #endif -		if (memcmp(symname, MODULE_SYMBOL_PREFIX, -			   strlen(MODULE_SYMBOL_PREFIX)) == 0) { -			mod->unres = -			  alloc_symbol(symname + -			               strlen(MODULE_SYMBOL_PREFIX), -			               ELF_ST_BIND(sym->st_info) == STB_WEAK, -			               mod->unres); -		} +#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX +		if (symname[0] != '_') +			break; +		else +			symname++; +#endif +		mod->unres = alloc_symbol(symname, +					  ELF_ST_BIND(sym->st_info) == STB_WEAK, +					  mod->unres);  		break;  	default:  		/* All exported symbols */ @@ -623,9 +671,9 @@ static void handle_modversions(struct module *mod, struct elf_info *info,  			sym_add_exported(symname + strlen(KSYMTAB_PFX), mod,  					export);  		} -		if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0) +		if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0)  			mod->has_init = 1; -		if (strcmp(symname, MODULE_SYMBOL_PREFIX "cleanup_module") == 0) +		if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0)  			mod->has_cleanup = 1;  		break;  	} @@ -790,13 +838,21 @@ static const char *section_white_list[] =  {  	".comment*",  	".debug*", +	".cranges",		/* sh64 */ +	".zdebug*",		/* Compressed debug sections. */  	".GCC-command-line",	/* mn10300 */ +	".GCC.command.line",	/* record-gcc-switches, non mn10300 */  	".mdebug*",        /* alpha, score, mips etc. */  	".pdr",            /* alpha, score, mips etc. */  	".stab*",  	".note*",  	".got*",  	".toc*", +	".xt.prop",				 /* xtensa */ +	".xt.lit",         /* xtensa */ +	".arcextmap*",			/* arc */ +	".gnu.linkonce.arcext*",	/* arc : modules */ +	".gnu.lto*",  	NULL  }; @@ -806,7 +862,7 @@ static const char *section_white_list[] =   * without "ax" / "aw".   */  static void check_section(const char *modname, struct elf_info *elf, -                          Elf_Shdr *sechdr) +			  Elf_Shdr *sechdr)  {  	const char *sec = sech_name(elf, sechdr); @@ -824,36 +880,34 @@ static void check_section(const char *modname, struct elf_info *elf,  #define ALL_INIT_DATA_SECTIONS \ -	".init.setup$", ".init.rodata$", \ -	".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \ -	".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$" +	".init.setup$", ".init.rodata$", ".meminit.rodata$", \ +	".init.data$", ".meminit.data$"  #define ALL_EXIT_DATA_SECTIONS \ -	".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$" +	".exit.data$", ".memexit.data$"  #define ALL_INIT_TEXT_SECTIONS \ -	".init.text$", ".devinit.text$", ".cpuinit.text$", ".meminit.text$" +	".init.text$", ".meminit.text$"  #define ALL_EXIT_TEXT_SECTIONS \ -	".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" +	".exit.text$", ".memexit.text$" -#define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \ -	MEM_INIT_SECTIONS -#define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \ -	MEM_EXIT_SECTIONS +#define ALL_PCI_INIT_SECTIONS	\ +	".pci_fixup_early$", ".pci_fixup_header$", ".pci_fixup_final$", \ +	".pci_fixup_enable$", ".pci_fixup_resume$", \ +	".pci_fixup_resume_early$", ".pci_fixup_suspend$" + +#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS +#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS  #define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS  #define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS  #define DATA_SECTIONS ".data$", ".data.rel$" -#define TEXT_SECTIONS ".text$" +#define TEXT_SECTIONS ".text$", ".text.unlikely$"  #define INIT_SECTIONS      ".init.*" -#define DEV_INIT_SECTIONS  ".devinit.*" -#define CPU_INIT_SECTIONS  ".cpuinit.*"  #define MEM_INIT_SECTIONS  ".meminit.*"  #define EXIT_SECTIONS      ".exit.*" -#define DEV_EXIT_SECTIONS  ".devexit.*" -#define CPU_EXIT_SECTIONS  ".cpuexit.*"  #define MEM_EXIT_SECTIONS  ".memexit.*"  /* init data sections */ @@ -941,48 +995,20 @@ const struct sectioncheck sectioncheck[] = {  	.mismatch = DATA_TO_ANY_EXIT,  	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  }, -/* Do not reference init code/data from devinit/cpuinit/meminit code/data */ +/* Do not reference init code/data from meminit code/data */  {  	.fromsec = { ALL_XXXINIT_SECTIONS, NULL },  	.tosec   = { INIT_SECTIONS, NULL },  	.mismatch = XXXINIT_TO_SOME_INIT,  	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  }, -/* Do not reference cpuinit code/data from meminit code/data */ -{ -	.fromsec = { MEM_INIT_SECTIONS, NULL }, -	.tosec   = { CPU_INIT_SECTIONS, NULL }, -	.mismatch = XXXINIT_TO_SOME_INIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference meminit code/data from cpuinit code/data */ -{ -	.fromsec = { CPU_INIT_SECTIONS, NULL }, -	.tosec   = { MEM_INIT_SECTIONS, NULL }, -	.mismatch = XXXINIT_TO_SOME_INIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference exit code/data from devexit/cpuexit/memexit code/data */ +/* Do not reference exit code/data from memexit code/data */  {  	.fromsec = { ALL_XXXEXIT_SECTIONS, NULL },  	.tosec   = { EXIT_SECTIONS, NULL },  	.mismatch = XXXEXIT_TO_SOME_EXIT,  	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  }, -/* Do not reference cpuexit code/data from memexit code/data */ -{ -	.fromsec = { MEM_EXIT_SECTIONS, NULL }, -	.tosec   = { CPU_EXIT_SECTIONS, NULL }, -	.mismatch = XXXEXIT_TO_SOME_EXIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference memexit code/data from cpuexit code/data */ -{ -	.fromsec = { CPU_EXIT_SECTIONS, NULL }, -	.tosec   = { MEM_EXIT_SECTIONS, NULL }, -	.mismatch = XXXEXIT_TO_SOME_EXIT, -	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -},  /* Do not use exit code/data from init code */  {  	.fromsec = { ALL_INIT_SECTIONS, NULL }, @@ -997,6 +1023,12 @@ const struct sectioncheck sectioncheck[] = {  	.mismatch = ANY_EXIT_TO_ANY_INIT,  	.symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },  }, +{ +	.fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, +	.tosec   = { INIT_SECTIONS, NULL }, +	.mismatch = ANY_INIT_TO_ANY_EXIT, +	.symbol_white_list = { NULL }, +},  /* Do not export init/exit functions or data */  {  	.fromsec = { "__ksymtab*", NULL }, @@ -1045,8 +1077,6 @@ static const struct sectioncheck *section_mismatch(   * Pattern 2:   *   Many drivers utilise a *driver container with references to   *   add, remove, probe functions etc. - *   These functions may often be marked __devinit and we do not want to - *   warn here.   *   the pattern is identified by:   *   tosec   = init or exit section   *   fromsec = data section @@ -1205,7 +1235,6 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr,  /*   * Convert a section name to the function/data attribute   * .init.text => __init - * .cpuinit.data => __cpudata   * .memexitconst => __memconst   * etc.   * @@ -1247,6 +1276,19 @@ static int is_function(Elf_Sym *sym)  		return -1;  } +static void print_section_list(const char * const list[20]) +{ +	const char *const *s = list; + +	while (*s) { +		fprintf(stderr, "%s", *s); +		s++; +		if (*s) +			fprintf(stderr, ", "); +	} +	fprintf(stderr, "\n"); +} +  /*   * Print a warning about a section mismatch.   * Try to find symbols near it so user can find it. @@ -1254,12 +1296,12 @@ static int is_function(Elf_Sym *sym)   */  static void report_sec_mismatch(const char *modname,  				const struct sectioncheck *mismatch, -                                const char *fromsec, -                                unsigned long long fromaddr, -                                const char *fromsym, -                                int from_is_func, -                                const char *tosec, const char *tosym, -                                int to_is_func) +				const char *fromsec, +				unsigned long long fromaddr, +				const char *fromsym, +				int from_is_func, +				const char *tosec, const char *tosym, +				int to_is_func)  {  	const char *from, *from_p;  	const char *to, *to_p; @@ -1303,7 +1345,6 @@ static void report_sec_mismatch(const char *modname,  		break;  	case DATA_TO_ANY_INIT: {  		prl_to = sec2annotation(tosec); -		const char *const *s = mismatch->symbol_white_list;  		fprintf(stderr,  		"The variable %s references\n"  		"the %s %s%s%s\n" @@ -1311,9 +1352,7 @@ static void report_sec_mismatch(const char *modname,  		"variable with __init* or __refdata (see linux/init.h) "  		"or name the variable:\n",  		fromsym, to, prl_to, tosym, to_p); -		while (*s) -			fprintf(stderr, "%s, ", *s++); -		fprintf(stderr, "\n"); +		print_section_list(mismatch->symbol_white_list);  		free(prl_to);  		break;  	} @@ -1328,7 +1367,6 @@ static void report_sec_mismatch(const char *modname,  		break;  	case DATA_TO_ANY_EXIT: {  		prl_to = sec2annotation(tosec); -		const char *const *s = mismatch->symbol_white_list;  		fprintf(stderr,  		"The variable %s references\n"  		"the %s %s%s%s\n" @@ -1336,9 +1374,7 @@ static void report_sec_mismatch(const char *modname,  		"variable with __exit* (see linux/init.h) or "  		"name the variable:\n",  		fromsym, to, prl_to, tosym, to_p); -		while (*s) -			fprintf(stderr, "%s, ", *s++); -		fprintf(stderr, "\n"); +		print_section_list(mismatch->symbol_white_list);  		free(prl_to);  		break;  	} @@ -1405,7 +1441,7 @@ static void report_sec_mismatch(const char *modname,  }  static void check_section_mismatch(const char *modname, struct elf_info *elf, -                                   Elf_Rela *r, Elf_Sym *sym, const char *fromsec) +				   Elf_Rela *r, Elf_Sym *sym, const char *fromsec)  {  	const char *tosec;  	const struct sectioncheck *mismatch; @@ -1423,6 +1459,10 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,  		to = find_elf_symbol(elf, r->r_addend, sym);  		tosym = sym_name(elf, to); +		if (!strncmp(fromsym, "reference___initcall", +				sizeof("reference___initcall")-1)) +			return; +  		/* check whitelist - we may ignore it */  		if (secref_whitelist(mismatch,  					fromsec, fromsym, tosec, tosym)) { @@ -1438,10 +1478,10 @@ static unsigned int *reloc_location(struct elf_info *elf,  				    Elf_Shdr *sechdr, Elf_Rela *r)  {  	Elf_Shdr *sechdrs = elf->sechdrs; -	int section = shndx2secindex(sechdr->sh_info); +	int section = sechdr->sh_info;  	return (void *)elf->hdr + sechdrs[section].sh_offset + -		r->r_offset - sechdrs[section].sh_addr; +		r->r_offset;  }  static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) @@ -1463,6 +1503,23 @@ static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)  	return 0;  } +#ifndef R_ARM_CALL +#define R_ARM_CALL	28 +#endif +#ifndef R_ARM_JUMP24 +#define R_ARM_JUMP24	29 +#endif + +#ifndef	R_ARM_THM_CALL +#define	R_ARM_THM_CALL		10 +#endif +#ifndef	R_ARM_THM_JUMP24 +#define	R_ARM_THM_JUMP24	30 +#endif +#ifndef	R_ARM_THM_JUMP19 +#define	R_ARM_THM_JUMP19	51 +#endif +  static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)  {  	unsigned int r_typ = ELF_R_TYPE(r->r_info); @@ -1471,13 +1528,18 @@ static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)  	case R_ARM_ABS32:  		/* From ARM ABI: (S + A) | T */  		r->r_addend = (int)(long) -		              (elf->symtab_start + ELF_R_SYM(r->r_info)); +			      (elf->symtab_start + ELF_R_SYM(r->r_info));  		break;  	case R_ARM_PC24: +	case R_ARM_CALL: +	case R_ARM_JUMP24: +	case R_ARM_THM_CALL: +	case R_ARM_THM_JUMP24: +	case R_ARM_THM_JUMP19:  		/* From ARM ABI: ((S + A) | T) - P */  		r->r_addend = (int)(long)(elf->hdr + -		              sechdr->sh_offset + -		              (r->r_offset - sechdr->sh_addr)); +			      sechdr->sh_offset + +			      (r->r_offset - sechdr->sh_addr));  		break;  	default:  		return 1; @@ -1509,7 +1571,7 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)  }  static void section_rela(const char *modname, struct elf_info *elf, -                         Elf_Shdr *sechdr) +			 Elf_Shdr *sechdr)  {  	Elf_Sym  *sym;  	Elf_Rela *rela; @@ -1553,7 +1615,7 @@ static void section_rela(const char *modname, struct elf_info *elf,  }  static void section_rel(const char *modname, struct elf_info *elf, -                        Elf_Shdr *sechdr) +			Elf_Shdr *sechdr)  {  	Elf_Sym *sym;  	Elf_Rel *rel; @@ -1614,7 +1676,7 @@ static void section_rel(const char *modname, struct elf_info *elf,   * A module includes a number of sections that are discarded   * either when loaded or when used as built-in.   * For loaded modules all functions marked __init and all data - * marked __initdata will be discarded when the module has been intialized. + * marked __initdata will be discarded when the module has been initialized.   * Likewise for modules used built-in the sections marked __exit   * are discarded because __exit marked function are supposed to be called   * only when a module is unloaded which never happens for built-in modules. @@ -1623,7 +1685,7 @@ static void section_rel(const char *modname, struct elf_info *elf,   * be discarded and warns about it.   **/  static void check_sec_ref(struct module *mod, const char *modname, -                          struct elf_info *elf) +			  struct elf_info *elf)  {  	int i;  	Elf_Shdr *sechdrs = elf->sechdrs; @@ -1639,6 +1701,19 @@ static void check_sec_ref(struct module *mod, const char *modname,  	}  } +static char *remove_dot(char *s) +{ +	char *end; +	int n = strcspn(s, "."); + +	if (n > 0 && s[n] != 0) { +		strtoul(s + n + 1, &end, 10); +		if  (end > s + n + 1 && (*end == '.' || *end == 0)) +			s[n] = 0; +	} +	return s; +} +  static void read_symbols(char *modname)  {  	const char *symname; @@ -1677,7 +1752,7 @@ static void read_symbols(char *modname)  	}  	for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { -		symname = info.strtab + sym->st_name; +		symname = remove_dot(info.strtab + sym->st_name);  		handle_modversions(mod, &info, sym, symname);  		handle_moddevtable(mod, &info, sym, symname); @@ -1704,6 +1779,27 @@ static void read_symbols(char *modname)  		mod->unres = alloc_symbol("module_layout", 0, mod->unres);  } +static void read_symbols_from_files(const char *filename) +{ +	FILE *in = stdin; +	char fname[PATH_MAX]; + +	if (strcmp(filename, "-") != 0) { +		in = fopen(filename, "r"); +		if (!in) +			fatal("Can't open filenames file %s: %m", filename); +	} + +	while (fgets(fname, PATH_MAX, in) != NULL) { +		if (strends(fname, "\n")) +			fname[strlen(fname)-1] = '\0'; +		read_symbols(fname); +	} + +	if (in != stdin) +		fclose(in); +} +  #define SZ 500  /* We first write the generated file into memory using the @@ -1805,19 +1901,25 @@ static void add_header(struct buffer *b, struct module *mod)  	buf_printf(b, "\n");  	buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");  	buf_printf(b, "\n"); -	buf_printf(b, "struct module __this_module\n"); +	buf_printf(b, "__visible struct module __this_module\n");  	buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); -	buf_printf(b, " .name = KBUILD_MODNAME,\n"); +	buf_printf(b, "\t.name = KBUILD_MODNAME,\n");  	if (mod->has_init) -		buf_printf(b, " .init = init_module,\n"); +		buf_printf(b, "\t.init = init_module,\n");  	if (mod->has_cleanup)  		buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" -			      " .exit = cleanup_module,\n" +			      "\t.exit = cleanup_module,\n"  			      "#endif\n"); -	buf_printf(b, " .arch = MODULE_ARCH_INIT,\n"); +	buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");  	buf_printf(b, "};\n");  } +static void add_intree_flag(struct buffer *b, int is_intree) +{ +	if (is_intree) +		buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); +} +  static void add_staging_flag(struct buffer *b, const char *name)  {  	static const char *staging_dir = "drivers/staging"; @@ -1843,7 +1945,7 @@ static int add_versions(struct buffer *b, struct module *mod)  					     s->name, mod->name);  				} else {  					merror("\"%s\" [%s.ko] undefined!\n", -					          s->name, mod->name); +					       s->name, mod->name);  					err = 1;  				}  			} @@ -1870,7 +1972,8 @@ static int add_versions(struct buffer *b, struct module *mod)  				s->name, mod->name);  			continue;  		} -		buf_printf(b, "\t{ %#8x, \"%s\" },\n", s->crc, s->name); +		buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", +			   s->crc, s->name);  	}  	buf_printf(b, "};\n"); @@ -2010,8 +2113,10 @@ static void read_dump(const char *fname, unsigned int kernel)  		s->preloaded = 1;  		sym_update_crc(symname, mod, crc, export_no(export));  	} +	release_file(file, size);  	return;  fail: +	release_file(file, size);  	fatal("parse error in symbol dump file\n");  } @@ -2058,13 +2163,13 @@ int main(int argc, char **argv)  	struct module *mod;  	struct buffer buf = { };  	char *kernel_read = NULL, *module_read = NULL; -	char *dump_write = NULL; +	char *dump_write = NULL, *files_source = NULL;  	int opt;  	int err;  	struct ext_sym_list *extsym_iter;  	struct ext_sym_list *extsym_start = NULL; -	while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) { +	while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:")) != -1) {  		switch (opt) {  		case 'i':  			kernel_read = optarg; @@ -2073,9 +2178,6 @@ int main(int argc, char **argv)  			module_read = optarg;  			external_module = 1;  			break; -		case 'c': -			cross_build = 1; -			break;  		case 'e':  			external_module = 1;  			extsym_iter = @@ -2087,6 +2189,9 @@ int main(int argc, char **argv)  		case 'm':  			modversions = 1;  			break; +		case 'n': +			ignore_missing_files = 1; +			break;  		case 'o':  			dump_write = optarg;  			break; @@ -2099,6 +2204,9 @@ int main(int argc, char **argv)  		case 'S':  			sec_mismatch_verbose = 0;  			break; +		case 'T': +			files_source = optarg; +			break;  		case 'w':  			warn_unresolved = 1;  			break; @@ -2121,6 +2229,9 @@ int main(int argc, char **argv)  	while (optind < argc)  		read_symbols(argv[optind++]); +	if (files_source) +		read_symbols_from_files(files_source); +  	for (mod = modules; mod; mod = mod->next) {  		if (mod->skip)  			continue; @@ -2138,6 +2249,7 @@ int main(int argc, char **argv)  		buf.pos = 0;  		add_header(&buf, mod); +		add_intree_flag(&buf, !external_module);  		add_staging_flag(&buf, mod->name);  		err |= add_versions(&buf, mod);  		add_depends(&buf, mod, modules); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 0388cfccac8..168b43dc0a5 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -113,6 +113,7 @@ struct module {  	int has_cleanup;  	struct buffer dev_table_buf;  	char	     srcversion[25]; +	int is_dot_o;  };  struct elf_info { @@ -126,7 +127,7 @@ struct elf_info {  	Elf_Section  export_gpl_sec;  	Elf_Section  export_unused_gpl_sec;  	Elf_Section  export_gpl_future_sec; -	const char   *strtab; +	char         *strtab;  	char	     *modinfo;  	unsigned int modinfo_len; @@ -145,33 +146,22 @@ static inline int is_shndx_special(unsigned int i)  	return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;  } -/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus: - * shndx == 0               <=> sechdrs[0] - * ...... - * shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1] - * shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE] - * shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1] - * ...... - * fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff, - * so basically we map  0000..feff -> 0000..feff - *                      ff00..ffff -> (you are a bad boy, dont do it) - *                     10000..xxxx -> ff00..(xxxx-0x100) +/* + * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of + * the way to -256..-1, to avoid conflicting with real section + * indices.   */ -static inline unsigned int shndx2secindex(unsigned int i) -{ -	if (i <= SHN_HIRESERVE) -		return i; -	return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE); -} +#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))  /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */  static inline unsigned int get_secindex(const struct elf_info *info,  					const Elf_Sym *sym)  { +	if (is_shndx_special(sym->st_shndx)) +		return SPECIAL(sym->st_shndx);  	if (sym->st_shndx != SHN_XINDEX)  		return sym->st_shndx; -	return shndx2secindex(info->symtab_shndx_start[sym - -						       info->symtab_start]); +	return info->symtab_shndx_start[sym - info->symtab_start];  }  /* file2alias.c */ diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index ecf9c7dc182..944418da9fe 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -214,7 +214,7 @@ static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len)  	mctx->block[14] = mctx->byte_count << 3;  	mctx->block[15] = mctx->byte_count >> 29;  	le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - -	                  sizeof(uint64_t)) / sizeof(uint32_t)); +			  sizeof(uint64_t)) / sizeof(uint32_t));  	md4_transform(mctx->hash, mctx->block);  	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t)); @@ -300,8 +300,8 @@ static int is_static_library(const char *objfile)  		return 0;  } -/* We have dir/file.o.  Open dir/.file.o.cmd, look for deps_ line to - * figure out source file. */ +/* We have dir/file.o.  Open dir/.file.o.cmd, look for source_ and deps_ line + * to figure out source files. */  static int parse_source_files(const char *objfile, struct md4_ctx *md)  {  	char *cmd, *file, *line, *dir; @@ -340,6 +340,21 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)  	*/  	while ((line = get_next_line(&pos, file, flen)) != NULL) {  		char* p = line; + +		if (strncmp(line, "source_", sizeof("source_")-1) == 0) { +			p = strrchr(line, ' '); +			if (!p) { +				warn("malformed line: %s\n", line); +				goto out_file; +			} +			p++; +			if (!parse_file(p, md)) { +				warn("could not open %s: %s\n", +				     p, strerror(errno)); +				goto out_file; +			} +			continue; +		}  		if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) {  			check_files = 1;  			continue; @@ -352,7 +367,7 @@ static int parse_source_files(const char *objfile, struct md4_ctx *md)  			break;  		/* Terminate line at first space, to get rid of final ' \' */  		while (*p) { -                       if (isspace(*p)) { +			if (isspace(*p)) {  				*p = '\0';  				break;  			} @@ -401,7 +416,7 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen)  		basename = strrchr(modname, '/') + 1;  	else  		basename = modname; -	sprintf(filelist, "%s/%.*s.mod", modverdir, +	snprintf(filelist, sizeof(filelist), "%s/%.*s.mod", modverdir,  		(int) strlen(basename) - 2, basename);  	file = grab_file(filelist, &len);  | 
