diff options
Diffstat (limited to 'arch/x86/include/asm/word-at-a-time.h')
-rw-r--r-- | arch/x86/include/asm/word-at-a-time.h | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h index 6fe6767b7124..e58f03b206c3 100644 --- a/arch/x86/include/asm/word-at-a-time.h +++ b/arch/x86/include/asm/word-at-a-time.h | |||
@@ -43,4 +43,37 @@ static inline unsigned long has_zero(unsigned long a) | |||
43 | return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80); | 43 | return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80); |
44 | } | 44 | } |
45 | 45 | ||
46 | /* | ||
47 | * Load an unaligned word from kernel space. | ||
48 | * | ||
49 | * In the (very unlikely) case of the word being a page-crosser | ||
50 | * and the next page not being mapped, take the exception and | ||
51 | * return zeroes in the non-existing part. | ||
52 | */ | ||
53 | static inline unsigned long load_unaligned_zeropad(const void *addr) | ||
54 | { | ||
55 | unsigned long ret, dummy; | ||
56 | |||
57 | asm( | ||
58 | "1:\tmov %2,%0\n" | ||
59 | "2:\n" | ||
60 | ".section .fixup,\"ax\"\n" | ||
61 | "3:\t" | ||
62 | "lea %2,%1\n\t" | ||
63 | "and %3,%1\n\t" | ||
64 | "mov (%1),%0\n\t" | ||
65 | "leal %2,%%ecx\n\t" | ||
66 | "andl %4,%%ecx\n\t" | ||
67 | "shll $3,%%ecx\n\t" | ||
68 | "shr %%cl,%0\n\t" | ||
69 | "jmp 2b\n" | ||
70 | ".previous\n" | ||
71 | _ASM_EXTABLE(1b, 3b) | ||
72 | :"=&r" (ret),"=&c" (dummy) | ||
73 | :"m" (*(unsigned long *)addr), | ||
74 | "i" (-sizeof(unsigned long)), | ||
75 | "i" (sizeof(unsigned long)-1)); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
46 | #endif /* _ASM_WORD_AT_A_TIME_H */ | 79 | #endif /* _ASM_WORD_AT_A_TIME_H */ |