From e2414910f212c52d9d7c64c99a22863488ac5b48 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 26 Sep 2006 10:52:30 +0200 Subject: [PATCH] x86: Detect CFI support in the assembler at runtime ... instead of using a CONFIG option. The config option still controls if the resulting executable actually has unwind information. This is useful to prevent compilation errors when users select CONFIG_STACK_UNWIND on old binutils and also allows to use CFI in the future for non kernel debugging applications. Cc: jbeulich@novell.com Cc: sam@ravnborg.org Signed-off-by: Andi Kleen --- scripts/Kbuild.include | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'scripts') diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 3d523899fdc0..7adef12a0c26 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -63,6 +63,13 @@ as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \ -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \ else echo "$(2)"; fi ;) +# as-instr +# Usage: cflags-y += $(call as-instr, instr, option1, option2) + +as-instr = $(shell if echo -e "$(1)" | $(AS) -Z -o astest$$$$.out \ + 2>&1 >/dev/null ; then echo "$(2)"; else echo "$(3)"; fi; \ + rm -f astest$$$$.out) + # cc-option # Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586) -- cgit v1.2.3 From 4f7fd4d7a79193ceda4ce77f75e22917d33fa154 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Tue, 26 Sep 2006 10:52:39 +0200 Subject: [PATCH] Add the -fstack-protector option to the CFLAGS Add a feature check that checks that the gcc compiler has stack-protector support and has the bugfix for PR28281 to make this work in kernel mode. The easiest solution I could find was to have a shell script in scripts/ to do the detection; if needed we can make this fancier in the future without making the makefile too complex. Signed-off-by: Arjan van de Ven Signed-off-by: Andi Kleen CC: Andi Kleen CC: Sam Ravnborg --- arch/x86_64/Makefile | 3 +++ scripts/gcc-x86_64-has-stack-protector.sh | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 scripts/gcc-x86_64-has-stack-protector.sh (limited to 'scripts') diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index d6472ddf5f6e..2b8d07c70106 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -58,6 +58,9 @@ cflags-y += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,) cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) +cflags-$(CONFIG_CC_STACKPROTECTOR) += $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) -fstack-protector ) +cflags-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) -fstack-protector-all ) + CFLAGS += $(cflags-y) CFLAGS_KERNEL += $(cflags-kernel-y) AFLAGS += -m64 diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh new file mode 100644 index 000000000000..325c0a1b03b6 --- /dev/null +++ b/scripts/gcc-x86_64-has-stack-protector.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "int foo(void) { char X[200]; return 3; }" | $1 -S -xc -c -O0 -mcmodel=kernel -fstack-protector - -o - 2> /dev/null | grep -q "%gs" +if [ "$?" -eq "0" ] ; then + echo $2 +fi -- cgit v1.2.3 From adf1423698f00d00b267f7dca8231340ce7d65ef Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 26 Sep 2006 10:52:41 +0200 Subject: [PATCH] i386/x86-64: Work around gcc bug with noreturn functions in unwinder Current gcc generates calls not jumps to noreturn functions. When that happens the return address can point to the next function, which confuses the unwinder. This patch works around it by marking asynchronous exception frames in contrast normal call frames in the unwind information. Then teach the unwinder to decode this. For normal call frames the unwinder now subtracts one from the address which avoids this problem. The standard libgcc unwinder uses the same trick. It doesn't include adjustment of the printed address (i.e. for the original example, it'd still be kernel_math_error+0 that gets displayed, but the unwinder wouldn't get confused anymore. This only works with binutils 2.6.17+ and some versions of H.J.Lu's 2.6.16 unfortunately because earlier binutils don't support .cfi_signal_frame [AK: added automatic detection of the new binutils and wrote description] Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen --- arch/i386/Makefile | 4 ++++ arch/i386/kernel/entry.S | 4 ++++ arch/x86_64/Makefile | 4 ++++ arch/x86_64/ia32/ia32entry.S | 4 ++++ arch/x86_64/kernel/entry.S | 4 ++++ include/asm-i386/dwarf2.h | 7 +++++++ include/asm-i386/unwind.h | 5 +++++ include/asm-x86_64/dwarf2.h | 6 ++++++ include/asm-x86_64/unwind.h | 5 +++++ kernel/unwind.c | 35 ++++++++++++++++++++++++++++------- scripts/Kbuild.include | 4 ++-- 11 files changed, 73 insertions(+), 9 deletions(-) (limited to 'scripts') diff --git a/arch/i386/Makefile b/arch/i386/Makefile index 508cdbeb3a09..7cc0b189b82b 100644 --- a/arch/i386/Makefile +++ b/arch/i386/Makefile @@ -50,6 +50,10 @@ CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then echo $(call cc-op cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) +# is .cfi_signal_frame supported too? +cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) +AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) + CFLAGS += $(cflags-y) # Default subarch .c files diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index 284f2e908ad0..5a63d6fdb70e 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -183,18 +183,21 @@ VM_MASK = 0x00020000 #define RING0_INT_FRAME \ CFI_STARTPROC simple;\ + CFI_SIGNAL_FRAME;\ CFI_DEF_CFA esp, 3*4;\ /*CFI_OFFSET cs, -2*4;*/\ CFI_OFFSET eip, -3*4 #define RING0_EC_FRAME \ CFI_STARTPROC simple;\ + CFI_SIGNAL_FRAME;\ CFI_DEF_CFA esp, 4*4;\ /*CFI_OFFSET cs, -2*4;*/\ CFI_OFFSET eip, -3*4 #define RING0_PTREGS_FRAME \ CFI_STARTPROC simple;\ + CFI_SIGNAL_FRAME;\ CFI_DEF_CFA esp, OLDESP-EBX;\ /*CFI_OFFSET cs, CS-OLDESP;*/\ CFI_OFFSET eip, EIP-OLDESP;\ @@ -275,6 +278,7 @@ need_resched: # sysenter call handler stub ENTRY(sysenter_entry) CFI_STARTPROC simple + CFI_SIGNAL_FRAME CFI_DEF_CFA esp, 0 CFI_REGISTER esp, ebp movl TSS_sysenter_esp0(%esp),%esp diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile index 2b8d07c70106..1c0f18d4f887 100644 --- a/arch/x86_64/Makefile +++ b/arch/x86_64/Makefile @@ -58,6 +58,10 @@ cflags-y += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,) cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,) +# is .cfi_signal_frame supported too? +cflags-y += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,) +AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,) + cflags-$(CONFIG_CC_STACKPROTECTOR) += $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) -fstack-protector ) cflags-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) -fstack-protector-all ) diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S index 32fd32bea07c..b4aa875e175b 100644 --- a/arch/x86_64/ia32/ia32entry.S +++ b/arch/x86_64/ia32/ia32entry.S @@ -71,6 +71,7 @@ */ ENTRY(ia32_sysenter_target) CFI_STARTPROC32 simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,0 CFI_REGISTER rsp,rbp swapgs @@ -186,6 +187,7 @@ ENDPROC(ia32_sysenter_target) */ ENTRY(ia32_cstar_target) CFI_STARTPROC32 simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,PDA_STACKOFFSET CFI_REGISTER rip,rcx /*CFI_REGISTER rflags,r11*/ @@ -293,6 +295,7 @@ ia32_badarg: ENTRY(ia32_syscall) CFI_STARTPROC simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,SS+8-RIP /*CFI_REL_OFFSET ss,SS-RIP*/ CFI_REL_OFFSET rsp,RSP-RIP @@ -370,6 +373,7 @@ ENTRY(ia32_ptregs_common) popq %r11 CFI_ENDPROC CFI_STARTPROC32 simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,SS+8-ARGOFFSET CFI_REL_OFFSET rax,RAX-ARGOFFSET CFI_REL_OFFSET rcx,RCX-ARGOFFSET diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S index ea32688386fd..4cbc65290ae7 100644 --- a/arch/x86_64/kernel/entry.S +++ b/arch/x86_64/kernel/entry.S @@ -123,6 +123,7 @@ .macro CFI_DEFAULT_STACK start=1 .if \start CFI_STARTPROC simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,SS+8 .else CFI_DEF_CFA_OFFSET SS+8 @@ -207,6 +208,7 @@ END(ret_from_fork) ENTRY(system_call) CFI_STARTPROC simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,PDA_STACKOFFSET CFI_REGISTER rip,rcx /*CFI_REGISTER rflags,r11*/ @@ -324,6 +326,7 @@ END(system_call) */ ENTRY(int_ret_from_sys_call) CFI_STARTPROC simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,SS+8-ARGOFFSET /*CFI_REL_OFFSET ss,SS-ARGOFFSET*/ CFI_REL_OFFSET rsp,RSP-ARGOFFSET @@ -484,6 +487,7 @@ END(stub_rt_sigreturn) */ .macro _frame ref CFI_STARTPROC simple + CFI_SIGNAL_FRAME CFI_DEF_CFA rsp,SS+8-\ref /*CFI_REL_OFFSET ss,SS-\ref*/ CFI_REL_OFFSET rsp,RSP-\ref diff --git a/include/asm-i386/dwarf2.h b/include/asm-i386/dwarf2.h index 5d1a8db5a9b0..6d66398a307d 100644 --- a/include/asm-i386/dwarf2.h +++ b/include/asm-i386/dwarf2.h @@ -28,6 +28,12 @@ #define CFI_RESTORE_STATE .cfi_restore_state #define CFI_UNDEFINED .cfi_undefined +#ifdef CONFIG_AS_CFI_SIGNAL_FRAME +#define CFI_SIGNAL_FRAME .cfi_signal_frame +#else +#define CFI_SIGNAL_FRAME +#endif + #else /* Due to the structure of pre-exisiting code, don't use assembler line @@ -48,6 +54,7 @@ #define CFI_REMEMBER_STATE ignore #define CFI_RESTORE_STATE ignore #define CFI_UNDEFINED ignore +#define CFI_SIGNAL_FRAME ignore #endif diff --git a/include/asm-i386/unwind.h b/include/asm-i386/unwind.h index f0ac399bae3c..5031d693b89d 100644 --- a/include/asm-i386/unwind.h +++ b/include/asm-i386/unwind.h @@ -18,6 +18,7 @@ struct unwind_frame_info { struct pt_regs regs; struct task_struct *task; + unsigned call_frame:1; }; #define UNW_PC(frame) (frame)->regs.eip @@ -44,6 +45,10 @@ struct unwind_frame_info PTREGS_INFO(edi), \ PTREGS_INFO(eip) +#define UNW_DEFAULT_RA(raItem, dataAlign) \ + ((raItem).where == Memory && \ + !((raItem).value * (dataAlign) + 4)) + static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, /*const*/ struct pt_regs *regs) { diff --git a/include/asm-x86_64/dwarf2.h b/include/asm-x86_64/dwarf2.h index 2b9368365fad..eedc08526b0b 100644 --- a/include/asm-x86_64/dwarf2.h +++ b/include/asm-x86_64/dwarf2.h @@ -28,6 +28,11 @@ #define CFI_REMEMBER_STATE .cfi_remember_state #define CFI_RESTORE_STATE .cfi_restore_state #define CFI_UNDEFINED .cfi_undefined +#ifdef CONFIG_AS_CFI_SIGNAL_FRAME +#define CFI_SIGNAL_FRAME .cfi_signal_frame +#else +#define CFI_SIGNAL_FRAME +#endif #else @@ -45,6 +50,7 @@ #define CFI_REMEMBER_STATE # #define CFI_RESTORE_STATE # #define CFI_UNDEFINED # +#define CFI_SIGNAL_FRAME # #endif diff --git a/include/asm-x86_64/unwind.h b/include/asm-x86_64/unwind.h index 1f6e9bfb569e..b8fa5cb7ff88 100644 --- a/include/asm-x86_64/unwind.h +++ b/include/asm-x86_64/unwind.h @@ -18,6 +18,7 @@ struct unwind_frame_info { struct pt_regs regs; struct task_struct *task; + unsigned call_frame:1; }; #define UNW_PC(frame) (frame)->regs.rip @@ -57,6 +58,10 @@ struct unwind_frame_info PTREGS_INFO(r15), \ PTREGS_INFO(rip) +#define UNW_DEFAULT_RA(raItem, dataAlign) \ + ((raItem).where == Memory && \ + !((raItem).value * (dataAlign) + 8)) + static inline void arch_unw_init_frame_info(struct unwind_frame_info *info, /*const*/ struct pt_regs *regs) { diff --git a/kernel/unwind.c b/kernel/unwind.c index f69c804c8e62..3430475fcd88 100644 --- a/kernel/unwind.c +++ b/kernel/unwind.c @@ -603,6 +603,7 @@ int unwind(struct unwind_frame_info *frame) #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) const u32 *fde = NULL, *cie = NULL; const u8 *ptr = NULL, *end = NULL; + unsigned long pc = UNW_PC(frame) - frame->call_frame; unsigned long startLoc = 0, endLoc = 0, cfa; unsigned i; signed ptrType = -1; @@ -612,7 +613,7 @@ int unwind(struct unwind_frame_info *frame) if (UNW_PC(frame) == 0) return -EINVAL; - if ((table = find_table(UNW_PC(frame))) != NULL + if ((table = find_table(pc)) != NULL && !(table->size & (sizeof(*fde) - 1))) { unsigned long tableSize = table->size; @@ -647,7 +648,7 @@ int unwind(struct unwind_frame_info *frame) ptrType & DW_EH_PE_indirect ? ptrType : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); - if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc) + if (pc >= startLoc && pc < endLoc) break; cie = NULL; } @@ -657,16 +658,28 @@ int unwind(struct unwind_frame_info *frame) state.cieEnd = ptr; /* keep here temporarily */ ptr = (const u8 *)(cie + 2); end = (const u8 *)(cie + 1) + *cie; + frame->call_frame = 1; if ((state.version = *ptr) != 1) cie = NULL; /* unsupported version */ else if (*++ptr) { /* check if augmentation size is first (and thus present) */ if (*ptr == 'z') { - /* check for ignorable (or already handled) - * nul-terminated augmentation string */ - while (++ptr < end && *ptr) - if (strchr("LPR", *ptr) == NULL) + while (++ptr < end && *ptr) { + switch(*ptr) { + /* check for ignorable (or already handled) + * nul-terminated augmentation string */ + case 'L': + case 'P': + case 'R': + continue; + case 'S': + frame->call_frame = 0; + continue; + default: break; + } + break; + } } if (ptr >= end || *ptr) cie = NULL; @@ -755,7 +768,7 @@ int unwind(struct unwind_frame_info *frame) state.org = startLoc; memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); /* process instructions */ - if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state) + if (!processCFI(ptr, end, pc, ptrType, &state) || state.loc > endLoc || state.regs[retAddrReg].where == Nowhere || state.cfa.reg >= ARRAY_SIZE(reg_info) @@ -763,6 +776,11 @@ int unwind(struct unwind_frame_info *frame) || state.cfa.offs % sizeof(unsigned long)) return -EIO; /* update frame */ +#ifndef CONFIG_AS_CFI_SIGNAL_FRAME + if(frame->call_frame + && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign)) + frame->call_frame = 0; +#endif cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; startLoc = min((unsigned long)UNW_SP(frame), cfa); endLoc = max((unsigned long)UNW_SP(frame), cfa); @@ -866,6 +884,7 @@ int unwind_init_frame_info(struct unwind_frame_info *info, /*const*/ struct pt_regs *regs) { info->task = tsk; + info->call_frame = 0; arch_unw_init_frame_info(info, regs); return 0; @@ -879,6 +898,7 @@ int unwind_init_blocked(struct unwind_frame_info *info, struct task_struct *tsk) { info->task = tsk; + info->call_frame = 0; arch_unw_init_blocked(info); return 0; @@ -894,6 +914,7 @@ int unwind_init_running(struct unwind_frame_info *info, void *arg) { info->task = current; + info->call_frame = 0; return arch_unwind_init_running(info, callback, arg); } diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 7adef12a0c26..4f5ff19b992b 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -66,8 +66,8 @@ as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \ # as-instr # Usage: cflags-y += $(call as-instr, instr, option1, option2) -as-instr = $(shell if echo -e "$(1)" | $(AS) -Z -o astest$$$$.out \ - 2>&1 >/dev/null ; then echo "$(2)"; else echo "$(3)"; fi; \ +as-instr = $(shell if echo -e "$(1)" | $(AS) >/dev/null 2>&1 -W -Z -o astest$$$$.out ; \ + then echo "$(2)"; else echo "$(3)"; fi; \ rm -f astest$$$$.out) # cc-option -- cgit v1.2.3 From 07563c711fbc25389e58ab9c9f0b9de2fce56760 Mon Sep 17 00:00:00 2001 From: Michael Tokarev Date: Wed, 27 Sep 2006 01:50:56 -0700 Subject: [PATCH] EISA bus MODALIAS attributes support Add modalias attribute support for the almost forgotten now EISA bus and (at least some) EISA-aware modules. The modalias entry looks like (for an 3c509 NIC): eisa:sTCM5093 and the in-module alias like: eisa:sTCM5093* The patch moves struct eisa_device_id declaration from include/linux/eisa.h to include/linux/mod_devicetable.h (so that the former now #includes the latter), adds proper MODULE_DEVICE_TABLE(eisa, ...) statements for all drivers with EISA IDs I found (some drivers already have that DEVICE_TABLE declared), and adds recognision of __mod_eisa_device_table to scripts/mod/file2alias.c so that proper modules.alias will be generated. There's no support for /lib/modules/$kver/modules.eisamap, as it's not used by any existing tools, and because with in-kernel modalias mechanism those maps are obsolete anyway. The rationale for this patch is: a) to make EISA bus to act as other busses with modalias support, to unify driver loading b) to foget about EISA finally - with this patch, kernel (who still supports EISA) will be the only one who knows how to choose the necessary drivers for this bus ;) [akpm@osdl.org: fix the kbuild bit] Signed-off-by: Michael Tokarev Cc: Rusty Russell Cc: Randy Dunlap Acked-the-net-bits-by: Jeff Garzik Acked-the-tulip-bit-by: Valerie Henson Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/eisa/eisa-bus.c | 23 +++++++++++++++++++++++ drivers/net/3c509.c | 1 + drivers/net/3c59x.c | 1 + drivers/net/ne3210.c | 1 + drivers/net/tulip/de4x5.c | 1 + drivers/scsi/aha1740.c | 1 + drivers/scsi/aic7xxx/aic7770_osm.c | 3 ++- drivers/scsi/sim710.c | 1 + include/linux/eisa.h | 8 +------- include/linux/mod_devicetable.h | 12 ++++++++++++ scripts/mod/file2alias.c | 12 ++++++++++++ 11 files changed, 56 insertions(+), 8 deletions(-) (limited to 'scripts') diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c index 6078e2f58817..3a365e159d89 100644 --- a/drivers/eisa/eisa-bus.c +++ b/drivers/eisa/eisa-bus.c @@ -128,9 +128,23 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv) return 0; } +static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct eisa_device *edev = to_eisa_device(dev); + int i = 0; + int length = 0; + + add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, + "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig); + envp[i] = NULL; + return 0; +} + struct bus_type eisa_bus_type = { .name = "eisa", .match = eisa_bus_match, + .uevent = eisa_bus_uevent, }; int eisa_driver_register (struct eisa_driver *edrv) @@ -160,6 +174,14 @@ static ssize_t eisa_show_state (struct device *dev, struct device_attribute *att static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL); +static ssize_t eisa_show_modalias (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct eisa_device *edev = to_eisa_device (dev); + return sprintf (buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig); +} + +static DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL); + static int __init eisa_init_device (struct eisa_root_device *root, struct eisa_device *edev, int slot) @@ -209,6 +231,7 @@ static int __init eisa_register_device (struct eisa_device *edev) device_create_file (&edev->dev, &dev_attr_signature); device_create_file (&edev->dev, &dev_attr_enabled); + device_create_file (&edev->dev, &dev_attr_modalias); return 0; } diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 59c33925be62..b936373ab2a5 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -225,6 +225,7 @@ static struct eisa_device_id el3_eisa_ids[] = { { "TCM5095" }, { "" } }; +MODULE_DEVICE_TABLE(eisa, el3_eisa_ids); static int el3_eisa_probe (struct device *device); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index af301f09d674..df42e28cc80f 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -851,6 +851,7 @@ static struct eisa_device_id vortex_eisa_ids[] = { { "TCM5970", CH_3C597 }, { "" } }; +MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); static int vortex_eisa_probe(struct device *device); static int vortex_eisa_remove(struct device *device); diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 0fa8e4d22769..d66328975425 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -343,6 +343,7 @@ static struct eisa_device_id ne3210_ids[] = { { "NVL1801" }, { "" }, }; +MODULE_DEVICE_TABLE(eisa, ne3210_ids); static struct eisa_driver ne3210_eisa_driver = { .id_table = ne3210_ids, diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index e661d0a9cc64..fb5fa7d68888 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -2114,6 +2114,7 @@ static struct eisa_device_id de4x5_eisa_ids[] = { { "DEC4250", 0 }, /* 0 is the board name index... */ { "" } }; +MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids); static struct eisa_driver de4x5_eisa_driver = { .id_table = de4x5_eisa_ids, diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 0e4a7ebe300a..6b35ed8301e0 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -681,6 +681,7 @@ static struct eisa_device_id aha1740_ids[] = { { "ADP0400" }, /* 1744 */ { "" } }; +MODULE_DEVICE_TABLE(eisa, aha1740_ids); static struct eisa_driver aha1740_driver = { .id_table = aha1740_ids, diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index 867cbe23579b..1ac119733bac 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -132,7 +132,8 @@ static struct eisa_device_id aic7770_ids[] = { { "ADP7770", 5 }, /* AIC7770 generic */ { "" } }; - +MODULE_DEVICE_TABLE(eisa, aic7770_ids); + static struct eisa_driver aic7770_driver = { .id_table = aic7770_ids, .driver = { diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index b27e85428daa..551baccec523 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -282,6 +282,7 @@ static struct eisa_device_id sim710_eisa_ids[] = { { "HWP0C80" }, { "" } }; +MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids); static __init int sim710_eisa_probe(struct device *dev) diff --git a/include/linux/eisa.h b/include/linux/eisa.h index 4079242dced8..1ff7c1392525 100644 --- a/include/linux/eisa.h +++ b/include/linux/eisa.h @@ -3,8 +3,8 @@ #include #include +#include -#define EISA_SIG_LEN 8 #define EISA_MAX_SLOTS 8 #define EISA_MAX_RESOURCES 4 @@ -27,12 +27,6 @@ #define EISA_CONFIG_ENABLED 1 #define EISA_CONFIG_FORCED 2 -/* The EISA signature, in ASCII form, null terminated */ -struct eisa_device_id { - char sig[EISA_SIG_LEN]; - unsigned long driver_data; -}; - /* There is not much we can say about an EISA device, apart from * signature, slot number, and base address. dma_mask is set by * default to parent device mask..*/ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index f7ca0b09075d..e0c393cc7240 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -308,4 +308,16 @@ struct input_device_id { kernel_ulong_t driver_info; }; +/* EISA */ + +#define EISA_SIG_LEN 8 + +/* The EISA signature, in ASCII form, null terminated */ +struct eisa_device_id { + char sig[EISA_SIG_LEN]; + kernel_ulong_t driver_data; +}; + +#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s" + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index de76da80443f..f61c9ccef6aa 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -444,6 +444,14 @@ static int do_input_entry(const char *filename, struct input_device_id *id, return 1; } +static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa, + char *alias) +{ + if (eisa->sig[0]) + sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", eisa->sig); + return 1; +} + /* Ignore any prefix, eg. v850 prepends _ */ static inline int sym_is(const char *symbol, const char *name) { @@ -547,6 +555,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, 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); } /* Now add out buffered information to the generated C source */ -- cgit v1.2.3