We offer two methods to load driver module into L1 and L2 SRAM.
Specify the proper function and variable attributes; here is a complete example:
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); int a __attribute__((l1_data)) = 1; /* Specify the global initialized variable 'a' saved in the L1 data bank A memory */ int b __attribute__((l1_data)); /* Specify the global uninitialized variable 'b' saved in L1 data bank A memory */ int c __attribute__((l1_data_B)) = 2; /* Specify the global initialized variable 'c' saved in L1 data bank B memory */ int d __attribute__((l1_data_B)); /* Specify the global uninitialized variable 'd' saved in L1 data bank B memory */ void l1_code_test(void)__attribute__((l1_text)); /* Sepcify the function 'l1_code_test' saved in L1 instruction memory */ int e __attribute__((l2_data)) = 3; /* Specify the global initialized variable 'e' saved in the L2 memory */ int f __attribute__((l2_bss)); /* Specify the global uninitialized variable 'f' saved in L2 memory */ void l2_code_test(void)__attribute__((l2)); /* Sepcify the function 'l2_code_test' saved in L2 memory */ void l1_code_test(void) { printk(KERN_ALERT "L1 Code test: code function addr = 0x%p\n", l1_code_test); } void l1_data_a_test(void) { printk(KERN_ALERT "L1 Data bank A test: data variable addr = 0x%p, data value is %d\n", &a, a); } void l1_bss_a_test(void) { printk(KERN_ALERT "L1 BSS bank A test: bss variable addr = 0x%p, bss value is %d\n", &b, b); } void l1_data_b_test(void) { printk(KERN_ALERT "L1 Data bank B test: data variable addr = 0x%p, data value is %d\n", &c, c); } void l1_bss_b_test(void) { printk(KERN_ALERT "L1 BSS bank B test: bss variable addr = 0x%p, bss value is %d\n", &d, d); } void l2_code_test(void) { printk(KERN_ALERT "L2 Code test: code function addr = 0x%p\n", l2_code_test); } void l2_data_test(void) { printk(KERN_ALERT "L2 data test: data variable addr = 0x%p, data value is %d\n", &e, e); } void l2_bss_test(void) { printk(KERN_ALERT "L2 BSS test: bss variable addr = 0x%p, bss value is %d\n", &f, f); } static int hello_init(void) { printk(KERN_ALERT "========Load module into L1 and L2 memory========\n"); l1_code_test(); l1_data_a_test(); l1_bss_a_test(); l1_data_b_test(); l1_bss_b_test(); l2_code_test(); l2_data_test(); l2_bss_test(); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world\n"); } module_init(hello_init); module_exit(hello_exit);
The running result is as follows:
root:~> insmod hello.ko ========Load module into L1 and L2 memory======== L1 Code test: code function addr = 0xffa00378 L1 Data bank A test: data variable addr = 0xff803e58, data value is 1 L1 BSS bank A test: bss variable addr = 0xff803e5c, bss value is 0 L1 Data bank B test: data variable addr = 0xff902580, data value is 2 L1 BSS bank B test: bss variable addr = 0xff902584, bss value is 0 L2 Code test: code function addr = 0xfeb00000 L2 Data test: data variable addr = 0xfeb03e58, data value is 3 L2 BSS test: bss variable addr = 0xfeb03e5c, bss value is 0
You can use the following options with the linker command. Nothing needs to be changed in the driver. The following flags work:
Here is the program “hello.c”
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); int a=1; int b; void sram_code_test(void); void sram_code_test(void) { printk(KERN_ALERT "Code test: code function addr = 0x%p\n", sram_code_test); } void sram_data_test(void) { printk(KERN_ALERT "Data test: data variable addr = 0x%p, data value is %d\n", &a, a); } void sram_bss_test(void) { printk(KERN_ALERT "BSS test: bss variable addr = 0x%p, bss value is %d\n", &b, b); } static int hello_init(void) { printk(KERN_ALERT "========Load module into L1 or L2 memory========\n"); sram_code_test(); sram_data_test(); sram_bss_test(); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world\n"); } module_init(hello_init); module_exit(hello_exit);
The Makefile is simple, one line is enough:
obj-m += hello.o
The following instruction tell you how to generate 'hello.ko':
$ make -C /home/aubrey/cvs/kernel/new/uClinux-dist/linux-2.6.x SUBDIRS=$PWD modules make: Entering directory `/home/aubrey/cvs/kernel/new/uClinux-dist/linux-2.6.x' CC [M] /tftpboot/module-example/hello.o Building modules, stage 2. MODPOST CC /tftpboot/module-example/hello.mod.o LD [M] /tftpboot/module-example/hello.ko make: Leaving directory `/home/aubrey/cvs/kernel/new/uClinux-dist/linux-2.6.x'
Here we get the hello.ko, now we re-link the object file to add the specific flags to the driver module:
$ bfin-uclinux-ld --code-in-l1 --data-in-l1 -r -o hello.ko hello.o hello.mod.o
Make sure the flags have been added
$ bfin-uclinux-readelf -h hello.ko ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: REL (Relocatable file) Machine: Analog Devices Blackfin Version: 0x1 Entry point address: 0x0 Start of program headers: 0 (bytes into file) Start of section headers: 1004 (bytes into file) Flags: 0x30, code in L1, data in L1 <===================== Here, make sure the flags are set Size of this header: 52 (bytes) Size of program headers: 0 (bytes) Number of program headers: 0 Size of section headers: 40 (bytes) Number of section headers: 13 Section header string table index: 10
The running result is as follows:
root:~> insmod hello.ko ========Load module into L1 or L2 memory======== Code test: code function addr = 0xffa003cc Data test: data variable addr = 0xff803e58, data value is 1 BSS test: bss variable addr = 0xff803e5c, bss value is 0