[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [microblaze-uclinux] loadable module support in petalinux kernel 2.6



Hi Erik,

Erik Hansen wrote:

On Tue, 2007-07-03 at 14:59 +1000, John Williams wrote:
The kernel infrastructure for loadable modules is not yet done for microblaze / 2.6.

It's on the radar, but no specific timeline. If you want to have a go at it, please do so!

last week I have started to implement module support for microblaze for
the 2.6 kernel, but I have not come far with that. Unfortunately I had
to postpone my efforts concerning due to a lack of time, I plan to
continue in a couple of weeks.

Thanks for that.  Here's what I had to change to get it going:

1. Your handling of the 64_PCREL was incorrect - you need to subtract the reloc value from the current location, to make it properly PC relative. This had me stumped for a while, and was the cause of your occasional lockups, as the CPU was diving off into random memory.

2. mb-gcc and mb-ld split the relocations between the text segment (embedded in the opcode) and the relocation table. So, it's necessary to pull the current symbol value from (*location), add the offset, then store it back in.

3. renamed microblazeksyms.c -> microblaze_ksyms.c in line with other architectures, and did what best cleanup I could in terms of symbols exported etc. No doubt there'll be a little more in there to come as this gets more widely tested.

Attached patches are:

 * microblaze_modules.patch - the core loadable module support

* platform_module_fixup.patch - a fixup to the handling of the platform_device initialisers, so that they work correctly when the associated device drivers are built as modules. See the comment at the top of microblaze?platform/common/Makefile for details.

both apply at -p0 from petalinux-v0.30-rcX/software

Finally, here's a sample session. I tested this with the ethernet, gpio and keypad device drivers, seems to work OK.

# insmod xilinx_gpio
Using /lib/modules/2.6.20-uc0/kernel/drivers/char/xilinx_gpio/xilinx_gpio.ko
xgpio0 #0 at 0x40040000 mapped to 0x40040000 device: 10,185 not using IRQ
xgpio1 #1 at 0x40060000 mapped to 0x40060000 device: 10,186 not using IRQ
# gpio-test -c
# rmmod xilinx_gpio
# gpio-test -c
/dev/gpio: No such device

Thanks Erik for kickstarting this.

Cheers,

John
Index: linux-2.6.x-petalogix/arch/microblaze/kernel/microblaze_ksyms.c
===================================================================
--- linux-2.6.x-petalogix/arch/microblaze/kernel/microblaze_ksyms.c	(revision 0)
+++ linux-2.6.x-petalogix/arch/microblaze/kernel/microblaze_ksyms.c	(revision 2875)
@@ -0,0 +1,124 @@
+/*
+ *  linux/arch/microblaze/kernel/microblazeksyms.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/cryptohash.h>
+#include <linux/delay.h>
+#include <linux/in6.h>
+#include <linux/syscalls.h>
+
+#include <asm/checksum.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler...  (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+extern void __ashldi3(void);
+extern void __ashrdi3(void);
+extern void __divsi3(void);
+extern void __lshrdi3(void);
+extern void __modsi3(void);
+extern void __muldi3(void);
+extern void __ucmpdi2(void);
+extern void __udivsi3(void);
+extern void __umodsi3(void);
+//extern void fpundefinstr(void);
+//extern void fp_enter(void);
+
+/*
+ * floating point math emulator support.
+ * These symbols will never change their calling convention...
+ */
+//EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter);
+//EXPORT_SYMBOL_ALIAS(fp_printk,printk);
+//EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
+//
+//EXPORT_SYMBOL(__backtrace);
+//
+//	/* platform dependent support */
+//EXPORT_SYMBOL(__udelay);
+//EXPORT_SYMBOL(__const_udelay);
+//
+//	/* networking */
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy);
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+EXPORT_SYMBOL(ip_compute_csum);
+
+	/* io */
+//#ifndef __raw_readsb
+//EXPORT_SYMBOL(__raw_readsb);
+//#endif
+//#ifndef __raw_readsw
+//EXPORT_SYMBOL(__raw_readsw);
+//#endif
+//#ifndef __raw_readsl
+//EXPORT_SYMBOL(__raw_readsl);
+//#endif
+//#ifndef __raw_writesb
+//EXPORT_SYMBOL(__raw_writesb);
+//#endif
+//#ifndef __raw_writesw
+//EXPORT_SYMBOL(__raw_writesw);
+//#endif
+//#ifndef __raw_writesl
+//EXPORT_SYMBOL(__raw_writesl);
+//#endif
+
+	/* string / mem functions */
+//EXPORT_SYMBOL(strchr);
+//EXPORT_SYMBOL(strrchr);
+
+#ifdef __HAVE_ARCH_MEMSET
+EXPORT_SYMBOL(memset);
+#endif
+
+#ifdef __HAVE_ARCH_MEMCPY
+EXPORT_SYMBOL(memcpy);
+#endif
+
+#ifdef __HAVE_ARCH_MEMMOVE
+EXPORT_SYMBOL(memmove);
+#endif
+
+//EXPORT_SYMBOL(memchr);
+//EXPORT_SYMBOL(__memzero);
+
+	/* user mem (segment) */
+//EXPORT_SYMBOL(__strnlen_user);
+//EXPORT_SYMBOL(__strncpy_from_user);
+
+	/* crypto hash */
+//EXPORT_SYMBOL(sha_transform);
+
+	/* gcc lib functions */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__ucmpdi2);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+
+	/* bitops */
+//EXPORT_SYMBOL(_set_bit_le);
+//EXPORT_SYMBOL(_test_and_set_bit_le);
+//EXPORT_SYMBOL(_clear_bit_le);
+//EXPORT_SYMBOL(_test_and_clear_bit_le);
+//EXPORT_SYMBOL(_change_bit_le);
+//EXPORT_SYMBOL(_test_and_change_bit_le);
+//EXPORT_SYMBOL(_find_first_zero_bit_le);
+//EXPORT_SYMBOL(_find_next_zero_bit_le);
+//EXPORT_SYMBOL(_find_first_bit_le);
+//EXPORT_SYMBOL(_find_next_bit_le);
Index: linux-2.6.x-petalogix/arch/microblaze/kernel/module.c
===================================================================
--- linux-2.6.x-petalogix/arch/microblaze/kernel/module.c	(revision 0)
+++ linux-2.6.x-petalogix/arch/microblaze/kernel/module.c	(revision 2875)
@@ -0,0 +1,145 @@
+/*
+ *  linux/arch/microblaze/kernel/module.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleloader.h>
+#include <linux/kernel.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+
+#include <asm/pgtable.h>
+
+#if 0
+#define DBPRINTK(...) printk(__VA_ARGS__)
+#else
+#define DBPRINTK(...)
+#endif
+
+void *module_alloc(unsigned long size)
+{
+	void *ret;
+	ret = (size == 0) ? NULL : vmalloc(size);
+	DBPRINTK("module_alloc (%08lx@%08lx)\n", size, (unsigned long int)ret);
+	return ret;
+}
+
+void module_free(struct module *module, void *region)
+{
+	DBPRINTK("module_free(%s,%08lx)\n",module->name, region);
+	vfree(region);
+}
+
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+			      Elf_Shdr *sechdrs,
+			      char *secstrings,
+			      struct module *mod)
+{
+	return 0;
+}
+
+int
+apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
+	       unsigned int relsec, struct module *module)
+{
+
+	printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n",
+	       module->name);
+	return -ENOEXEC;
+
+}
+
+int
+apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
+		   unsigned int symindex, unsigned int relsec, struct module *module)
+{
+
+	unsigned int i;
+	Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+	Elf32_Sym *sym;
+	unsigned long int *location;
+	unsigned long int locoffs;
+	unsigned long int value;
+	unsigned long int old_value;
+
+	DBPRINTK("Applying add relocation section %u to %u\n", 
+	       relsec, sechdrs[relsec].sh_info);
+
+	for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
+
+		location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + 
+				rela[i].r_offset;
+		sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + 
+			ELF32_R_SYM(rela[i].r_info);
+		value = sym->st_value + rela[i].r_addend;
+	
+		switch (ELF32_R_TYPE(rela[i].r_info)) {
+
+		/* Be careful! mb-gcc / mb-ld splits the relocs between the
+		   text and the reloc table.  In general this means we must
+		   read the current contents of (*location), add any offset
+		   then store the result back in */
+
+			case R_MICROBLAZE_32:
+				old_value=*location;
+				*location = value + old_value;
+				DBPRINTK("R_MICROBLAZE_32 (%08lx->%08lx)\n", 
+					old_value,value);
+				break;
+
+			case R_MICROBLAZE_64:
+				old_value=((location[0] & 0x0000FFFF) << 16 ) |
+					  ((location[1] & 0x0000FFFF));
+				value += old_value;
+				location[0] = (location[0] & 0xFFFF0000) | 
+						(value >> 16);
+				location[1] = (location[1] & 0xFFFF0000) | 
+						(value & 0xFFFF);
+				DBPRINTK("R_MICROBLAZE_64 (%08lx->%08lx)\n", 
+					old_value,value);
+				break;
+
+			case R_MICROBLAZE_64_PCREL:
+				locoffs = (location[0] & 0xFFFF) << 16 | 
+					(location[1] & 0xFFFF);
+				value -= (unsigned long int)(location) + 4 + 
+					locoffs;
+				location[0] = (location[0] & 0xFFFF0000) | 
+						(value >> 16);
+				location[1] = (location[1] & 0xFFFF0000) | 
+						(value & 0xFFFF);
+				DBPRINTK("R_MICROBLAZE_64_PCREL (%08lx)\n", 
+					value);
+				break;
+			
+			case R_MICROBLAZE_NONE:
+				DBPRINTK("R_MICROBLAZE_NONE\n");
+				break;
+	
+			default:
+				printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+				       module->name, ELF32_R_TYPE(rela->r_info));
+				return -ENOEXEC;
+		}
+	}
+	return 0;
+}
+
+int
+module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
+		struct module *module)
+{
+	return 0;
+}
+
+void
+module_arch_cleanup(struct module *mod)
+{
+}
Index: linux-2.6.x-petalogix/arch/microblaze/kernel/Makefile
===================================================================
--- linux-2.6.x-petalogix/arch/microblaze/kernel/Makefile	(revision 2874)
+++ linux-2.6.x-petalogix/arch/microblaze/kernel/Makefile	(revision 2875)
@@ -12,3 +12,4 @@
 obj-y += cpu/
 
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_MODULES)		+= microblaze_ksyms.o module.o
Index: linux-2.6.x-petalogix/arch/microblaze/platform/common/Makefile
===================================================================
--- linux-2.6.x-petalogix/arch/microblaze/platform/common/Makefile	(revision 2875)
+++ linux-2.6.x-petalogix/arch/microblaze/platform/common/Makefile	(revision 2876)
@@ -3,13 +3,22 @@
 #
 #
 
-obj-$(CONFIG_MTD_PHYSMAP) += physmap-flash.o
-obj-$(CONFIG_XILINX_GPIO) += xgpio.o
-obj-$(CONFIG_XILINX_SPI)  += xspi.o
-obj-$(CONFIG_SERIAL_UARTLITE)  += xuartlite.o
-obj-$(CONFIG_XILINX_SYSACE)  += xsysace.o
-obj-$(CONFIG_INPUT_KEYPADDEV)  += xbtn_decoder.o
+# These are the platform device initialisers - even if the driver itself
+# is built as a module (-m), we really probably want these guys built as -y
+# So, build a local list of the -y and -m options, then concat and add them
+# to obj-y
 
+# Build a local list of -y and -m driver options.
+
+platobj-$(CONFIG_MTD_PHYSMAP) += physmap-flash.o
+platobj-$(CONFIG_XILINX_GPIO) += xgpio.o
+platobj-$(CONFIG_XILINX_SPI)  += xspi.o
+platobj-$(CONFIG_SERIAL_UARTLITE)  += xuartlite.o
+platobj-$(CONFIG_XILINX_SYSACE)  += xsysace.o
+platobj-$(CONFIG_INPUT_KEYPADDEV)  += xbtn_decoder.o
+
+obj-y += $(platobj-y) $(platobj-m)
+
 # Make these platform setup sources dependent on .config
 # This is necessary because fixdep is not smart enough to "look inside"
 # the device struct initialiser macros and find the real dependencies