Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1170393
  • 博文数量: 173
  • 博客积分: 4048
  • 博客等级:
  • 技术积分: 2679
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-12 18:53
文章分类

全部博文(173)

文章存档

2018年(1)

2016年(1)

2013年(1)

2012年(118)

2011年(52)

分类: 嵌入式

2012-03-29 14:34:20

如果使用nios2-linux-20100621.tar移植带mmu的linux系统,自己添加驱动程序时。编译时会出错:
"__copy_from_user" [~/mymod.ko] undefined!
或是运行insmod时出错:
insmod: can't insert 'mymod.ko': unknown symbol in module, or unknown parameter
主要是因为uaccess.c中没有对__copy_from_user进行EXPORT_SYMBOL
只要修改

linux-2.6/arch/nios2/mm/uaccess.c

linux-2.6/arch/nios2/include/asm/uaccess.h

这两个文件即可:

uaccess.c

点击(此处)折叠或打开

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License. See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Copyright (C) 2009, Wind River Systems Inc
  7.  * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
  8.  */

  9. #include <asm/uaccess.h>
  10. #include <linux/module.h>

  11. extern long __copy_from_user(void *to, const void __user *from, unsigned long n);
  12. asm(" .global    __copy_from_user \n"
  13.     " .type __copy_from_user, @function \n"
  14.     "__copy_from_user: \n"
  15.     " movi r2,7 \n"
  16.     " mov r3,r4 \n"
  17.     " bge    r2,r6,1f \n"
  18.     " xor    r2,r4,r5             \n"
  19.     " andi    r2,r2,3 \n"
  20.     " movi    r7,3 \n"
  21.     " beq    r2,zero,4f \n"
  22.     "1: addi r6,r6,-1 \n"
  23.     " movi    r2,-1 \n"
  24.     " beq    r6,r2,3f \n"
  25.     " mov    r7,r2 \n"
  26.     "2: ldbu r2,0(r5) \n"
  27.     " addi    r6,r6,-1 \n"
  28.     " addi    r5,r5,1 \n"
  29.     " stb    r2,0(r3) \n"
  30.     " addi    r3,r3,1 \n"
  31.     " bne    r6,r7,2b \n"
  32.     "3: \n"
  33.     " addi r2,r6,1 \n"
  34.     " ret \n"
  35.     "13:mov r2,r6 \n"
  36.     " ret \n"
  37.     "4: andi r2,r4,1 \n"
  38.     " cmpeq    r2,r2,zero \n"
  39.     " beq    r2,zero,7f \n"
  40.     "5: andi r2,r3,2 \n"
  41.     " beq    r2,zero,6f \n"
  42.     "9: ldhu    r2,0(r5) \n"
  43.     " addi    r6,r6,-2 \n"
  44.     " addi    r5,r5,2 \n"
  45.     " sth    r2,0(r3) \n"
  46.     " addi    r3,r3,2 \n"
  47.     "6: bge r7,r6,1b \n"
  48.     "10:ldw    r2,0(r5) \n"
  49.     " addi    r6,r6,-4 \n"
  50.     " addi    r5,r5,4 \n"
  51.     " stw    r2,0(r3) \n"
  52.     " addi    r3,r3,4 \n"
  53.     " br    6b \n"
  54.     "7: ldbu r2,0(r5) \n"
  55.     " addi    r6,r6,-1 \n"
  56.     " addi    r5,r5,1 \n"
  57.     " addi    r3,r4,1 \n"
  58.     " stb    r2,0(r4) \n"
  59.     " br    5b \n"
  60.     ".section __ex_table,\"a\" \n"
  61.     ".word 2b,3b \n"
  62.     ".word 9b,13b \n"
  63.     ".word 10b,13b \n"
  64.     ".word 7b,13b \n"
  65.     ".previous \n"
  66.    );
  67. EXPORT_SYMBOL(__copy_from_user);

  68. extern long __copy_to_user(void __user *to, const void *from, unsigned long n);
  69. asm(
  70.    " .global    __copy_to_user \n"
  71.    " .type __copy_to_user, @function \n"
  72.    "__copy_to_user: \n"
  73.    " movi r2,7 \n"
  74.    " mov r3,r4 \n"
  75.    " bge    r2,r6,1f \n"
  76.    " xor    r2,r4,r5 \n"
  77.    " andi    r2,r2,3 \n"
  78.    " movi    r7,3 \n"
  79.    " beq    r2,zero,4f \n"
  80. /* Bail if we try to copy zero bytes */
  81.    "1: addi r6,r6,-1 \n"
  82.    " movi    r2,-1 \n"
  83.    " beq    r6,r2,3f \n"
  84. /* Copy byte by byte for small copies and if src^dst != 0 */
  85.    " mov    r7,r2 \n"
  86.    "2: ldbu r2,0(r5) \n"
  87.    " addi    r5,r5,1 \n"
  88.    "9: stb    r2,0(r3)            \n"
  89.    " addi    r6,r6,-1            \n"
  90.    " addi    r3,r3,1                \n"
  91.    " bne    r6,r7,2b            \n"
  92.    "3: addi r2,r6,1            \n"
  93.    " ret \n"
  94.    "13:mov r2,r6 \n"
  95.    " ret \n"
  96. /* If 'to' is an odd address byte copy */
  97.    "4: andi r2,r4,1                \n"
  98.    " cmpeq    r2,r2,zero            \n"
  99.    " beq    r2,zero,7f            \n"
  100. /* If 'to' is not divideable by four copy halfwords */
  101.    "5: andi r2,r3,2                \n"
  102.    " beq    r2,zero,6f            \n"
  103.    " ldhu    r2,0(r5)            \n"
  104.    " addi    r5,r5,2                \n"
  105.    "10:sth    r2,0(r3)            \n"
  106.    " addi    r6,r6,-2            \n"
  107.    " addi    r3,r3,2                \n"
  108. /* Copy words */
  109.    "6: bge r7,r6,1b                \n"
  110.    " ldw    r2,0(r5)            \n"
  111.    " addi    r5,r5,4                \n"
  112.    "11:stw    r2,0(r3)            \n"
  113.    " addi    r6,r6,-4            \n"
  114.    " addi    r3,r3,4                \n"
  115.    " br    6b                \n"
  116. /* Copy remaining bytes */
  117.    "7: ldbu r2,0(r5)                \n"
  118.    " addi    r5,r5,1                \n"
  119.    " addi    r3,r4,1                \n"
  120.    "12: stb    r2,0(r4)            \n"
  121.    " addi    r6,r6,-1            \n"
  122.    " br    5b                \n"
  123.    ".section __ex_table,\"a\" \n"
  124.    ".word 9b,3b     \n"
  125.    ".word 10b,13b     \n"
  126.    ".word 11b,13b     \n"
  127.    ".word 12b,13b     \n"
  128.    ".previous \n");
  129. EXPORT_SYMBOL(__copy_to_user);

  130. long strncpy_from_user(char *__to, const char __user *__from, long __len)
  131. {
  132.     int l = strnlen_user(__from, __len);
  133.     int is_zt = 1;

  134.     if (l > __len) {
  135.         is_zt = 0;
  136.         l = __len;
  137.     }

  138.     if (l == 0 || copy_from_user(__to, __from, l))
  139.         return -EFAULT;

  140.     if (is_zt)
  141.         l--;
  142.     return l;
  143. }

  144. long strnlen_user(const char __user *s, long n)
  145. {
  146.     long i;

  147.     for (i = 0; i < n; i++) {
  148.         char c;
  149.         if (get_user(c, s + i) == -EFAULT)
  150.             return 0;
  151.         if (c == 0)
  152.             return i + 1;
  153.     }
  154.     return n + 1;
  155. }

uaccess.h:

点击(此处)折叠或打开

  1. /*
  2.  * User space memory access functions for Nios II
  3.  *
  4.  * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch>
  5.  * Copyright (C) 2009, Wind River Systems Inc
  6.  * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
  7.  *
  8.  * Based on asm/uaccess.h from m68knommu
  9.  *
  10.  * This file is subject to the terms and conditions of the GNU General Public
  11.  * License. See the file "COPYING" in the main directory of this archive
  12.  * for more details.
  13.  */

  14. #ifndef _ASM_NIOS2_UACCESS_H
  15. #define _ASM_NIOS2_UACCESS_H

  16. #include <linux/errno.h>
  17. #include <linux/thread_info.h>
  18. #include <linux/string.h>

  19. #include <asm/page.h>

  20. #define VERIFY_READ 0
  21. #define VERIFY_WRITE 1

  22. /*
  23.  * The exception table consists of pairs of addresses: the first is the
  24.  * address of an instruction that is allowed to fault, and the second is
  25.  * the address at which the program should continue. No registers are
  26.  * modified, so it is entirely up to the continuation code to figure out
  27.  * what to do.
  28.  *
  29.  * All the routines below use bits of fixup code that are out of line
  30.  * with the main instruction path. This means when everything is well,
  31.  * we don't even have to jump over them. Further, they do not intrude
  32.  * on our cache or tlb entries.
  33.  */
  34. struct exception_table_entry {
  35.     unsigned long insn;
  36.     unsigned long fixup;
  37. };

  38. #ifdef CONFIG_MMU
  39. extern int fixup_exception(struct pt_regs *regs);
  40. #endif

  41. /*
  42.  * Segment stuff
  43.  */
  44. #define MAKE_MM_SEG(s)        ((mm_segment_t) { (s) } )
  45. #define USER_DS            MAKE_MM_SEG(0x80000000UL)
  46. #define KERNEL_DS        MAKE_MM_SEG(0)

  47. #define get_ds()        (KERNEL_DS)

  48. #define get_fs()        (current_thread_info()->addr_limit)
  49. #define set_fs(seg)        (current_thread_info()->addr_limit = (seg))

  50. #define segment_eq(a, b)    ((a).seg == (b).seg)

  51. #ifdef CONFIG_MMU
  52. #define __access_ok(addr, len)            \
  53.     (((signed long)(((long)get_fs().seg) &    \
  54.             ((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0)
  55. #else
  56. static inline int __access_ok(unsigned long addr, unsigned long size)
  57. {
  58.     addr &= ~CONFIG_IO_REGION_BASE;    /* ignore 'uncached' bit */
  59.     return ((addr >= CONFIG_MEM_BASE) && ((addr + size) < memory_end));
  60. }
  61. #endif /* CONFIG_MMU */

  62. #define access_ok(type, addr, len)        \
  63.     likely(__access_ok((unsigned long)(addr), (unsigned long)(len)))

  64. #ifdef CONFIG_MMU
  65. # define __EX_TABLE_SECTION    ".section __ex_table,\"a\"\n"
  66. #else
  67. # define __EX_TABLE_SECTION    ".section .discard,\"a\"\n"
  68. #endif

  69. /*
  70.  * Zero Userspace
  71.  */

  72. static inline unsigned long __must_check __clear_user(void __user *to,
  73.                          unsigned long n)
  74. {
  75.     __asm__ __volatile__ (
  76.         "1: stb zero, 0(%1)\n"
  77.         " addi %0, %0, -1\n"
  78.         " addi %1, %1, 1\n"
  79.         " bne %0, zero, 1b\n"
  80.         "2:\n"
  81.         __EX_TABLE_SECTION
  82.         ".word 1b, 2b\n"
  83.         ".previous\n"
  84.         : "=r" (n), "=r" (to)
  85.         : "0" (n), "1" (to)
  86.     );

  87.     return n;
  88. }

  89. static inline unsigned long __must_check clear_user(void __user *to,
  90.                          unsigned long n)
  91. {
  92.     if (!access_ok(VERIFY_WRITE, to, n))
  93.         return n;
  94.     return __clear_user(to, n);
  95. }

  96. #ifdef CONFIG_MMU
  97. extern long __copy_from_user(void* to, const void __user *from, unsigned long n);
  98. extern long __copy_to_user(void __user *to, const void *from, unsigned long n);

  99. static inline long copy_from_user(void *to, const void __user *from, unsigned long n)
  100. {
  101.     if (!access_ok(VERIFY_READ, from, n))
  102.         return n;
  103.     return __copy_from_user(to, from, n);
  104. }

  105. static inline long copy_to_user(void __user *to, const void *from, unsigned long n)
  106. {
  107.     if (!access_ok(VERIFY_WRITE, to, n))
  108.         return n;
  109.     return __copy_to_user(to, from, n);
  110. }

  111. extern long strncpy_from_user(char *__to, const char __user *__from,
  112.                 long __len);
  113. extern long strnlen_user(const char __user *s, long n);

  114. #else /* CONFIG_MMU */
  115. # define copy_from_user(to, from, n)    (memcpy(to, from, n), 0)
  116. # define copy_to_user(to, from, n)    (memcpy(to, from, n), 0)

  117. # define __copy_from_user(to, from, n)    copy_from_user(to, from, n)
  118. # define __copy_to_user(to, from, n)    copy_to_user(to, from, n)

  119. static inline long strncpy_from_user(char *dst, const char *src, long count)
  120. {
  121.     char *tmp;
  122.     strncpy(dst, src, count);
  123.     for (tmp = dst; *tmp && count > 0; tmp++, count--)
  124.         ;
  125.     return(tmp - dst); /* DAVIDM should we count a NUL ? check getname */
  126. }

  127. /*
  128.  * Return the size of a string (including the ending 0)
  129.  *
  130.  * Return 0 on exception, a value greater than N if too long
  131.  */
  132. static inline long strnlen_user(const char *src, long n)
  133. {
  134.     return strlen(src) + 1; /* DAVIDM make safer */
  135. }

  136. #endif /* CONFIG_MMU */

  137. #define __copy_from_user_inatomic    __copy_from_user
  138. #define __copy_to_user_inatomic        __copy_to_user

  139. /*
  140.  * TODO: get_user/put_user stuff below can probably be the same for MMU and
  141.  * NOMMU.
  142.  */

  143. #ifdef CONFIG_MMU

  144. /* Optimized macros */
  145. #define __get_user_asm(val, insn, addr, err) \
  146.    { \
  147.                                                                      \
  148.       __asm__ __volatile__( \
  149.         " movi %0, %3 \n" \
  150.         "1: " insn " %1, 0(%2) \n" \
  151.         " movi %0, 0 \n" \
  152.         "2: \n" \
  153.         " .section __ex_table,\"a\" \n" \
  154.         " .word 1b, 2b \n" \
  155.         " .previous " \
  156.         : "=&r" (err), "=r" (val) \
  157.         : "r" (addr), "i" (-EFAULT)); \
  158.    }

  159. #define __get_user_unknown(val, size, ptr, err) do { \
  160.       err = 0; \
  161.       if(copy_from_user(&(val), ptr, size)) { \
  162.          err = -EFAULT; \
  163.       } \
  164.    } while(0)

  165. #define __get_user_common(val, size, ptr, err) \
  166.    do { \
  167.       switch (size) { \
  168.          case 1: __get_user_asm(val, "ldbu", ptr, err); break; \
  169.          case 2: __get_user_asm(val, "ldhu", ptr, err); break; \
  170.          case 4: __get_user_asm(val, "ldw", ptr, err); break; \
  171.          default: __get_user_unknown(val, size, ptr, err); break; \
  172.       } \
  173.    } while (0)

  174. #define __get_user(x,ptr) \
  175.    ({ \
  176.       long __gu_err = -EFAULT; \
  177.       const __typeof__(*(ptr)) __user * __gu_ptr = (ptr); \
  178.       unsigned long __gu_val; /* FIXME: should be __typeof__ */ \
  179.       __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err); \
  180.       (x) = (__typeof__(x))__gu_val; \
  181.       __gu_err; \
  182.    })

  183. #define get_user(x,ptr) \
  184.    ({ \
  185.       long __gu_err = -EFAULT; \
  186.       const __typeof__(*(ptr)) __user * __gu_ptr = (ptr); \
  187.       unsigned long __gu_val = 0; \
  188.       if (access_ok(VERIFY_READ, __gu_ptr, sizeof(*__gu_ptr)))        \
  189.          __get_user_common(__gu_val, sizeof(*__gu_ptr), __gu_ptr, __gu_err); \
  190.       (x) = (__typeof__(x))__gu_val; \
  191.       __gu_err; \
  192.    })

  193. #define __put_user_asm(val, insn, ptr,err) \
  194.    { \
  195.       __asm__ __volatile__( \
  196.         " movi %0, %3 \n" \
  197.         "1: " insn " %1, 0(%2) \n" \
  198.         " movi %0, 0 \n" \
  199.         "2: \n" \
  200.         " .section __ex_table,\"a\" \n" \
  201.         " .word 1b, 2b \n" \
  202.         " .previous \n" \
  203.         : "=&r" (err) \
  204.         : "r" (val), "r" (ptr), "i" (-EFAULT)); \
  205.    }

  206. #define put_user(x, ptr)                        \
  207. ({                                    \
  208.     long __pu_err = -EFAULT;                    \
  209.     __typeof__(*(ptr)) __user *__pu_ptr = (ptr);            \
  210.     __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x);        \
  211.     if (access_ok(VERIFY_WRITE, __pu_ptr, sizeof(*__pu_ptr))) {    \
  212.         switch (sizeof(*__pu_ptr)) {                \
  213.         case 1:                            \
  214.             __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \
  215.             break;                        \
  216.         case 2:                            \
  217.             __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \
  218.             break;                        \
  219.         case 4:                            \
  220.             __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \
  221.             break;                        \
  222.         default:                        \
  223.             /* XXX: This looks wrong... */            \
  224.             __pu_err = 0;                    \
  225.             if (copy_to_user(__pu_ptr, &(__pu_val), sizeof(*__pu_ptr))) \
  226.                 __pu_err = -EFAULT;            \
  227.             break;                        \
  228.         }                            \
  229.     }                                \
  230.     __pu_err;                            \
  231. })

  232. #define __put_user(x, ptr) put_user(x, ptr)

  233. #else /* CONFIG_MMU */

  234. /*
  235.  * These are the main single-value transfer routines. They automatically
  236.  * use the right size if we just have the right pointer type.
  237.  */

  238. #define put_user(x, ptr)                \
  239. ({                            \
  240.     int __pu_err = 0;                \
  241.     __typeof__(*(ptr)) __pu_val = (x);        \
  242.     switch (sizeof (*(ptr))) {            \
  243.     case 1:                        \
  244.     case 2:                        \
  245.     case 4:                        \
  246.     case 8:                        \
  247.         memcpy(ptr, &__pu_val, sizeof(*(ptr)));    \
  248.         break;                    \
  249.     default:                    \
  250.         __pu_err = __put_user_bad();        \
  251.         break;                    \
  252.     }                        \
  253.     __pu_err;                    \
  254. })
  255. #define __put_user(x, ptr) put_user(x, ptr)

  256. extern int __put_user_bad(void);

  257. #define get_user(x, ptr)                \
  258. ({                            \
  259.     int __gu_err = 0;                \
  260.     typeof(*(ptr)) __gu_val = 0;            \
  261.     switch (sizeof(*(ptr))) {            \
  262.     case 1:                        \
  263.     case 2:                        \
  264.     case 4:                        \
  265.     case 8:                        \
  266.         memcpy(&__gu_val, ptr, sizeof(*(ptr)));    \
  267.         break;                    \
  268.     default:                    \
  269.         __gu_val = 0;                \
  270.         __gu_err = __get_user_bad();        \
  271.         break;                    \
  272.     }                        \
  273.     (x) = __gu_val;                    \
  274.     __gu_err;                    \
  275. })
  276. #define __get_user(x, ptr) get_user(x, ptr)

  277. extern int __get_user_bad(void);

  278. #endif /* CONFIG_MMU */

  279. #endif /* _ASM_NIOS2_UACCESS_H */

阅读(2781) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

图片MM2012-03-30 01:08:55

是啊……自己添加驱动程序时。编译时会出错

图片MM2012-03-30 01:07:25

好长的代码呀……