[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