at v6.12 17 kB view raw
1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * arch/arm/include/asm/assembler.h 4 * 5 * Copyright (C) 1996-2000 Russell King 6 * 7 * This file contains arm architecture specific defines 8 * for the different processors. 9 * 10 * Do not include any C declarations in this file - it is included by 11 * assembler source. 12 */ 13#ifndef __ASM_ASSEMBLER_H__ 14#define __ASM_ASSEMBLER_H__ 15 16#ifndef __ASSEMBLY__ 17#error "Only include this from assembly code" 18#endif 19 20#include <asm/ptrace.h> 21#include <asm/opcodes-virt.h> 22#include <asm/asm-offsets.h> 23#include <asm/page.h> 24#include <asm/pgtable.h> 25#include <asm/thread_info.h> 26#include <asm/uaccess-asm.h> 27 28#define IOMEM(x) (x) 29 30/* 31 * Endian independent macros for shifting bytes within registers. 32 */ 33#ifndef __ARMEB__ 34#define lspull lsr 35#define lspush lsl 36#define get_byte_0 lsl #0 37#define get_byte_1 lsr #8 38#define get_byte_2 lsr #16 39#define get_byte_3 lsr #24 40#define put_byte_0 lsl #0 41#define put_byte_1 lsl #8 42#define put_byte_2 lsl #16 43#define put_byte_3 lsl #24 44#else 45#define lspull lsl 46#define lspush lsr 47#define get_byte_0 lsr #24 48#define get_byte_1 lsr #16 49#define get_byte_2 lsr #8 50#define get_byte_3 lsl #0 51#define put_byte_0 lsl #24 52#define put_byte_1 lsl #16 53#define put_byte_2 lsl #8 54#define put_byte_3 lsl #0 55#endif 56 57/* Select code for any configuration running in BE8 mode */ 58#ifdef CONFIG_CPU_ENDIAN_BE8 59#define ARM_BE8(code...) code 60#else 61#define ARM_BE8(code...) 62#endif 63 64/* 65 * Data preload for architectures that support it 66 */ 67#if __LINUX_ARM_ARCH__ >= 5 68#define PLD(code...) code 69#else 70#define PLD(code...) 71#endif 72 73/* 74 * This can be used to enable code to cacheline align the destination 75 * pointer when bulk writing to memory. Experiments on StrongARM and 76 * XScale didn't show this a worthwhile thing to do when the cache is not 77 * set to write-allocate (this would need further testing on XScale when WA 78 * is used). 79 * 80 * On Feroceon there is much to gain however, regardless of cache mode. 81 */ 82#ifdef CONFIG_CPU_FEROCEON 83#define CALGN(code...) code 84#else 85#define CALGN(code...) 86#endif 87 88#define IMM12_MASK 0xfff 89 90/* the frame pointer used for stack unwinding */ 91ARM( fpreg .req r11 ) 92THUMB( fpreg .req r7 ) 93 94/* 95 * Enable and disable interrupts 96 */ 97#if __LINUX_ARM_ARCH__ >= 6 98 .macro disable_irq_notrace 99 cpsid i 100 .endm 101 102 .macro enable_irq_notrace 103 cpsie i 104 .endm 105#else 106 .macro disable_irq_notrace 107 msr cpsr_c, #PSR_I_BIT | SVC_MODE 108 .endm 109 110 .macro enable_irq_notrace 111 msr cpsr_c, #SVC_MODE 112 .endm 113#endif 114 115#if __LINUX_ARM_ARCH__ < 7 116 .macro dsb, args 117 mcr p15, 0, r0, c7, c10, 4 118 .endm 119 120 .macro isb, args 121 mcr p15, 0, r0, c7, c5, 4 122 .endm 123#endif 124 125 .macro asm_trace_hardirqs_off, save=1 126#if defined(CONFIG_TRACE_IRQFLAGS) 127 .if \save 128 stmdb sp!, {r0-r3, ip, lr} 129 .endif 130 bl trace_hardirqs_off 131 .if \save 132 ldmia sp!, {r0-r3, ip, lr} 133 .endif 134#endif 135 .endm 136 137 .macro asm_trace_hardirqs_on, cond=al, save=1 138#if defined(CONFIG_TRACE_IRQFLAGS) 139 /* 140 * actually the registers should be pushed and pop'd conditionally, but 141 * after bl the flags are certainly clobbered 142 */ 143 .if \save 144 stmdb sp!, {r0-r3, ip, lr} 145 .endif 146 bl\cond trace_hardirqs_on 147 .if \save 148 ldmia sp!, {r0-r3, ip, lr} 149 .endif 150#endif 151 .endm 152 153 .macro disable_irq, save=1 154 disable_irq_notrace 155 asm_trace_hardirqs_off \save 156 .endm 157 158 .macro enable_irq 159 asm_trace_hardirqs_on 160 enable_irq_notrace 161 .endm 162/* 163 * Save the current IRQ state and disable IRQs. Note that this macro 164 * assumes FIQs are enabled, and that the processor is in SVC mode. 165 */ 166 .macro save_and_disable_irqs, oldcpsr 167#ifdef CONFIG_CPU_V7M 168 mrs \oldcpsr, primask 169#else 170 mrs \oldcpsr, cpsr 171#endif 172 disable_irq 173 .endm 174 175 .macro save_and_disable_irqs_notrace, oldcpsr 176#ifdef CONFIG_CPU_V7M 177 mrs \oldcpsr, primask 178#else 179 mrs \oldcpsr, cpsr 180#endif 181 disable_irq_notrace 182 .endm 183 184/* 185 * Restore interrupt state previously stored in a register. We don't 186 * guarantee that this will preserve the flags. 187 */ 188 .macro restore_irqs_notrace, oldcpsr 189#ifdef CONFIG_CPU_V7M 190 msr primask, \oldcpsr 191#else 192 msr cpsr_c, \oldcpsr 193#endif 194 .endm 195 196 .macro restore_irqs, oldcpsr 197 tst \oldcpsr, #PSR_I_BIT 198 asm_trace_hardirqs_on cond=eq 199 restore_irqs_notrace \oldcpsr 200 .endm 201 202/* 203 * Assembly version of "adr rd, BSYM(sym)". This should only be used to 204 * reference local symbols in the same assembly file which are to be 205 * resolved by the assembler. Other usage is undefined. 206 */ 207 .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo 208 .macro badr\c, rd, sym 209#ifdef CONFIG_THUMB2_KERNEL 210 adr\c \rd, \sym + 1 211#else 212 adr\c \rd, \sym 213#endif 214 .endm 215 .endr 216 217/* 218 * Get current thread_info. 219 */ 220 .macro get_thread_info, rd 221 /* thread_info is the first member of struct task_struct */ 222 get_current \rd 223 .endm 224 225/* 226 * Increment/decrement the preempt count. 227 */ 228#ifdef CONFIG_PREEMPT_COUNT 229 .macro inc_preempt_count, ti, tmp 230 ldr \tmp, [\ti, #TI_PREEMPT] @ get preempt count 231 add \tmp, \tmp, #1 @ increment it 232 str \tmp, [\ti, #TI_PREEMPT] 233 .endm 234 235 .macro dec_preempt_count, ti, tmp 236 ldr \tmp, [\ti, #TI_PREEMPT] @ get preempt count 237 sub \tmp, \tmp, #1 @ decrement it 238 str \tmp, [\ti, #TI_PREEMPT] 239 .endm 240#else 241 .macro inc_preempt_count, ti, tmp 242 .endm 243 244 .macro dec_preempt_count, ti, tmp 245 .endm 246#endif 247 248#define USERL(l, x...) \ 2499999: x; \ 250 .pushsection __ex_table,"a"; \ 251 .align 3; \ 252 .long 9999b,l; \ 253 .popsection 254 255#define USER(x...) USERL(9001f, x) 256 257#ifdef CONFIG_SMP 258#define ALT_SMP(instr...) \ 2599998: instr 260/* 261 * Note: if you get assembler errors from ALT_UP() when building with 262 * CONFIG_THUMB2_KERNEL, you almost certainly need to use 263 * ALT_SMP( W(instr) ... ) 264 */ 265#define ALT_UP(instr...) \ 266 .pushsection ".alt.smp.init", "a" ;\ 267 .align 2 ;\ 268 .long 9998b - . ;\ 2699997: instr ;\ 270 .if . - 9997b == 2 ;\ 271 nop ;\ 272 .endif ;\ 273 .if . - 9997b != 4 ;\ 274 .error "ALT_UP() content must assemble to exactly 4 bytes";\ 275 .endif ;\ 276 .popsection 277#define ALT_UP_B(label) \ 278 .pushsection ".alt.smp.init", "a" ;\ 279 .align 2 ;\ 280 .long 9998b - . ;\ 281 W(b) . + (label - 9998b) ;\ 282 .popsection 283#else 284#define ALT_SMP(instr...) 285#define ALT_UP(instr...) instr 286#define ALT_UP_B(label) b label 287#endif 288 289 /* 290 * this_cpu_offset - load the per-CPU offset of this CPU into 291 * register 'rd' 292 */ 293 .macro this_cpu_offset, rd:req 294#ifdef CONFIG_SMP 295ALT_SMP(mrc p15, 0, \rd, c13, c0, 4) 296#ifdef CONFIG_CPU_V6 297ALT_UP_B(.L1_\@) 298.L0_\@: 299 .subsection 1 300.L1_\@: ldr_va \rd, __per_cpu_offset 301 b .L0_\@ 302 .previous 303#endif 304#else 305 mov \rd, #0 306#endif 307 .endm 308 309 /* 310 * set_current - store the task pointer of this CPU's current task 311 */ 312 .macro set_current, rn:req, tmp:req 313#if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 3149998: mcr p15, 0, \rn, c13, c0, 3 @ set TPIDRURO register 315#ifdef CONFIG_CPU_V6 316ALT_UP_B(.L0_\@) 317 .subsection 1 318.L0_\@: str_va \rn, __current, \tmp 319 b .L1_\@ 320 .previous 321.L1_\@: 322#endif 323#else 324 str_va \rn, __current, \tmp 325#endif 326 .endm 327 328 /* 329 * get_current - load the task pointer of this CPU's current task 330 */ 331 .macro get_current, rd:req 332#if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 3339998: mrc p15, 0, \rd, c13, c0, 3 @ get TPIDRURO register 334#ifdef CONFIG_CPU_V6 335ALT_UP_B(.L0_\@) 336 .subsection 1 337.L0_\@: ldr_va \rd, __current 338 b .L1_\@ 339 .previous 340.L1_\@: 341#endif 342#else 343 ldr_va \rd, __current 344#endif 345 .endm 346 347 /* 348 * reload_current - reload the task pointer of this CPU's current task 349 * into the TLS register 350 */ 351 .macro reload_current, t1:req, t2:req 352#if defined(CONFIG_CURRENT_POINTER_IN_TPIDRURO) || defined(CONFIG_SMP) 353#ifdef CONFIG_CPU_V6 354ALT_SMP(nop) 355ALT_UP_B(.L0_\@) 356#endif 357 ldr_this_cpu \t1, __entry_task, \t1, \t2 358 mcr p15, 0, \t1, c13, c0, 3 @ store in TPIDRURO 359.L0_\@: 360#endif 361 .endm 362 363/* 364 * Instruction barrier 365 */ 366 .macro instr_sync 367#if __LINUX_ARM_ARCH__ >= 7 368 isb 369#elif __LINUX_ARM_ARCH__ == 6 370 mcr p15, 0, r0, c7, c5, 4 371#endif 372 .endm 373 374/* 375 * SMP data memory barrier 376 */ 377 .macro smp_dmb mode 378#ifdef CONFIG_SMP 379#if __LINUX_ARM_ARCH__ >= 7 380 .ifeqs "\mode","arm" 381 ALT_SMP(dmb ish) 382 .else 383 ALT_SMP(W(dmb) ish) 384 .endif 385#elif __LINUX_ARM_ARCH__ == 6 386 ALT_SMP(mcr p15, 0, r0, c7, c10, 5) @ dmb 387#else 388#error Incompatible SMP platform 389#endif 390 .ifeqs "\mode","arm" 391 ALT_UP(nop) 392 .else 393 ALT_UP(W(nop)) 394 .endif 395#endif 396 .endm 397 398/* 399 * Raw SMP data memory barrier 400 */ 401 .macro __smp_dmb mode 402#if __LINUX_ARM_ARCH__ >= 7 403 .ifeqs "\mode","arm" 404 dmb ish 405 .else 406 W(dmb) ish 407 .endif 408#elif __LINUX_ARM_ARCH__ == 6 409 mcr p15, 0, r0, c7, c10, 5 @ dmb 410#else 411 .error "Incompatible SMP platform" 412#endif 413 .endm 414 415#if defined(CONFIG_CPU_V7M) 416 /* 417 * setmode is used to assert to be in svc mode during boot. For v7-M 418 * this is done in __v7m_setup, so setmode can be empty here. 419 */ 420 .macro setmode, mode, reg 421 .endm 422#elif defined(CONFIG_THUMB2_KERNEL) 423 .macro setmode, mode, reg 424 mov \reg, #\mode 425 msr cpsr_c, \reg 426 .endm 427#else 428 .macro setmode, mode, reg 429 msr cpsr_c, #\mode 430 .endm 431#endif 432 433/* 434 * Helper macro to enter SVC mode cleanly and mask interrupts. reg is 435 * a scratch register for the macro to overwrite. 436 * 437 * This macro is intended for forcing the CPU into SVC mode at boot time. 438 * you cannot return to the original mode. 439 */ 440.macro safe_svcmode_maskall reg:req 441#if __LINUX_ARM_ARCH__ >= 6 && !defined(CONFIG_CPU_V7M) 442 mrs \reg , cpsr 443 eor \reg, \reg, #HYP_MODE 444 tst \reg, #MODE_MASK 445 bic \reg , \reg , #MODE_MASK 446 orr \reg , \reg , #PSR_I_BIT | PSR_F_BIT | SVC_MODE 447THUMB( orr \reg , \reg , #PSR_T_BIT ) 448 bne 1f 449 orr \reg, \reg, #PSR_A_BIT 450 badr lr, 2f 451 msr spsr_cxsf, \reg 452 __MSR_ELR_HYP(14) 453 __ERET 4541: msr cpsr_c, \reg 4552: 456#else 457/* 458 * workaround for possibly broken pre-v6 hardware 459 * (akita, Sharp Zaurus C-1000, PXA270-based) 460 */ 461 setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, \reg 462#endif 463.endm 464 465/* 466 * STRT/LDRT access macros with ARM and Thumb-2 variants 467 */ 468#ifdef CONFIG_THUMB2_KERNEL 469 470 .macro usraccoff, instr, reg, ptr, inc, off, cond, abort, t=TUSER() 4719999: 472 .if \inc == 1 473 \instr\()b\t\cond\().w \reg, [\ptr, #\off] 474 .elseif \inc == 4 475 \instr\t\cond\().w \reg, [\ptr, #\off] 476 .else 477 .error "Unsupported inc macro argument" 478 .endif 479 480 .pushsection __ex_table,"a" 481 .align 3 482 .long 9999b, \abort 483 .popsection 484 .endm 485 486 .macro usracc, instr, reg, ptr, inc, cond, rept, abort 487 @ explicit IT instruction needed because of the label 488 @ introduced by the USER macro 489 .ifnc \cond,al 490 .if \rept == 1 491 itt \cond 492 .elseif \rept == 2 493 ittt \cond 494 .else 495 .error "Unsupported rept macro argument" 496 .endif 497 .endif 498 499 @ Slightly optimised to avoid incrementing the pointer twice 500 usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort 501 .if \rept == 2 502 usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort 503 .endif 504 505 add\cond \ptr, #\rept * \inc 506 .endm 507 508#else /* !CONFIG_THUMB2_KERNEL */ 509 510 .macro usracc, instr, reg, ptr, inc, cond, rept, abort, t=TUSER() 511 .rept \rept 5129999: 513 .if \inc == 1 514 \instr\()b\t\cond \reg, [\ptr], #\inc 515 .elseif \inc == 4 516 \instr\t\cond \reg, [\ptr], #\inc 517 .else 518 .error "Unsupported inc macro argument" 519 .endif 520 521 .pushsection __ex_table,"a" 522 .align 3 523 .long 9999b, \abort 524 .popsection 525 .endr 526 .endm 527 528#endif /* CONFIG_THUMB2_KERNEL */ 529 530 .macro strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f 531 usracc str, \reg, \ptr, \inc, \cond, \rept, \abort 532 .endm 533 534 .macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f 535 usracc ldr, \reg, \ptr, \inc, \cond, \rept, \abort 536 .endm 537 538/* Utility macro for declaring string literals */ 539 .macro string name:req, string 540 .type \name , #object 541\name: 542 .asciz "\string" 543 .size \name , . - \name 544 .endm 545 546 .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo 547 .macro ret\c, reg 548#if __LINUX_ARM_ARCH__ < 6 549 mov\c pc, \reg 550#else 551 .ifeqs "\reg", "lr" 552 bx\c \reg 553 .else 554 mov\c pc, \reg 555 .endif 556#endif 557 .endm 558 .endr 559 560 .macro ret.w, reg 561 ret \reg 562#ifdef CONFIG_THUMB2_KERNEL 563 nop 564#endif 565 .endm 566 567 .macro bug, msg, line 568#ifdef CONFIG_THUMB2_KERNEL 5691: .inst 0xde02 570#else 5711: .inst 0xe7f001f2 572#endif 573#ifdef CONFIG_DEBUG_BUGVERBOSE 574 .pushsection .rodata.str, "aMS", %progbits, 1 5752: .asciz "\msg" 576 .popsection 577 .pushsection __bug_table, "aw" 578 .align 2 579 .word 1b, 2b 580 .hword \line 581 .popsection 582#endif 583 .endm 584 585#ifdef CONFIG_KPROBES 586#define _ASM_NOKPROBE(entry) \ 587 .pushsection "_kprobe_blacklist", "aw" ; \ 588 .balign 4 ; \ 589 .long entry; \ 590 .popsection 591#else 592#define _ASM_NOKPROBE(entry) 593#endif 594 595 .macro __adldst_l, op, reg, sym, tmp, c 596 .if __LINUX_ARM_ARCH__ < 7 597 ldr\c \tmp, .La\@ 598 .subsection 1 599 .align 2 600.La\@: .long \sym - .Lpc\@ 601 .previous 602 .else 603 .ifnb \c 604 THUMB( ittt \c ) 605 .endif 606 movw\c \tmp, #:lower16:\sym - .Lpc\@ 607 movt\c \tmp, #:upper16:\sym - .Lpc\@ 608 .endif 609 610#ifndef CONFIG_THUMB2_KERNEL 611 .set .Lpc\@, . + 8 // PC bias 612 .ifc \op, add 613 add\c \reg, \tmp, pc 614 .else 615 \op\c \reg, [pc, \tmp] 616 .endif 617#else 618.Lb\@: add\c \tmp, \tmp, pc 619 /* 620 * In Thumb-2 builds, the PC bias depends on whether we are currently 621 * emitting into a .arm or a .thumb section. The size of the add opcode 622 * above will be 2 bytes when emitting in Thumb mode and 4 bytes when 623 * emitting in ARM mode, so let's use this to account for the bias. 624 */ 625 .set .Lpc\@, . + (. - .Lb\@) 626 627 .ifnc \op, add 628 \op\c \reg, [\tmp] 629 .endif 630#endif 631 .endm 632 633 /* 634 * mov_l - move a constant value or [relocated] address into a register 635 */ 636 .macro mov_l, dst:req, imm:req, cond 637 .if __LINUX_ARM_ARCH__ < 7 638 ldr\cond \dst, =\imm 639 .else 640 movw\cond \dst, #:lower16:\imm 641 movt\cond \dst, #:upper16:\imm 642 .endif 643 .endm 644 645 /* 646 * adr_l - adr pseudo-op with unlimited range 647 * 648 * @dst: destination register 649 * @sym: name of the symbol 650 * @cond: conditional opcode suffix 651 */ 652 .macro adr_l, dst:req, sym:req, cond 653 __adldst_l add, \dst, \sym, \dst, \cond 654 .endm 655 656 /* 657 * ldr_l - ldr <literal> pseudo-op with unlimited range 658 * 659 * @dst: destination register 660 * @sym: name of the symbol 661 * @cond: conditional opcode suffix 662 */ 663 .macro ldr_l, dst:req, sym:req, cond 664 __adldst_l ldr, \dst, \sym, \dst, \cond 665 .endm 666 667 /* 668 * str_l - str <literal> pseudo-op with unlimited range 669 * 670 * @src: source register 671 * @sym: name of the symbol 672 * @tmp: mandatory scratch register 673 * @cond: conditional opcode suffix 674 */ 675 .macro str_l, src:req, sym:req, tmp:req, cond 676 __adldst_l str, \src, \sym, \tmp, \cond 677 .endm 678 679 .macro __ldst_va, op, reg, tmp, sym, cond, offset 680#if __LINUX_ARM_ARCH__ >= 7 || \ 681 !defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \ 682 (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) 683 mov_l \tmp, \sym, \cond 684#else 685 /* 686 * Avoid a literal load, by emitting a sequence of ADD/LDR instructions 687 * with the appropriate relocations. The combined sequence has a range 688 * of -/+ 256 MiB, which should be sufficient for the core kernel and 689 * for modules loaded into the module region. 690 */ 691 .globl \sym 692 .reloc .L0_\@, R_ARM_ALU_PC_G0_NC, \sym 693 .reloc .L1_\@, R_ARM_ALU_PC_G1_NC, \sym 694 .reloc .L2_\@, R_ARM_LDR_PC_G2, \sym 695.L0_\@: sub\cond \tmp, pc, #8 - \offset 696.L1_\@: sub\cond \tmp, \tmp, #4 - \offset 697.L2_\@: 698#endif 699 \op\cond \reg, [\tmp, #\offset] 700 .endm 701 702 /* 703 * ldr_va - load a 32-bit word from the virtual address of \sym 704 */ 705 .macro ldr_va, rd:req, sym:req, cond, tmp, offset=0 706 .ifnb \tmp 707 __ldst_va ldr, \rd, \tmp, \sym, \cond, \offset 708 .else 709 __ldst_va ldr, \rd, \rd, \sym, \cond, \offset 710 .endif 711 .endm 712 713 /* 714 * str_va - store a 32-bit word to the virtual address of \sym 715 */ 716 .macro str_va, rn:req, sym:req, tmp:req, cond 717 __ldst_va str, \rn, \tmp, \sym, \cond, 0 718 .endm 719 720 /* 721 * ldr_this_cpu_armv6 - Load a 32-bit word from the per-CPU variable 'sym', 722 * without using a temp register. Supported in ARM mode 723 * only. 724 */ 725 .macro ldr_this_cpu_armv6, rd:req, sym:req 726 this_cpu_offset \rd 727 .globl \sym 728 .reloc .L0_\@, R_ARM_ALU_PC_G0_NC, \sym 729 .reloc .L1_\@, R_ARM_ALU_PC_G1_NC, \sym 730 .reloc .L2_\@, R_ARM_LDR_PC_G2, \sym 731 add \rd, \rd, pc 732.L0_\@: sub \rd, \rd, #4 733.L1_\@: sub \rd, \rd, #0 734.L2_\@: ldr \rd, [\rd, #4] 735 .endm 736 737 /* 738 * ldr_this_cpu - Load a 32-bit word from the per-CPU variable 'sym' 739 * into register 'rd', which may be the stack pointer, 740 * using 't1' and 't2' as general temp registers. These 741 * are permitted to overlap with 'rd' if != sp 742 */ 743 .macro ldr_this_cpu, rd:req, sym:req, t1:req, t2:req 744#ifndef CONFIG_SMP 745 ldr_va \rd, \sym, tmp=\t1 746#elif __LINUX_ARM_ARCH__ >= 7 || \ 747 !defined(CONFIG_ARM_HAS_GROUP_RELOCS) || \ 748 (defined(MODULE) && defined(CONFIG_ARM_MODULE_PLTS)) 749 this_cpu_offset \t1 750 mov_l \t2, \sym 751 ldr \rd, [\t1, \t2] 752#else 753 ldr_this_cpu_armv6 \rd, \sym 754#endif 755 .endm 756 757 /* 758 * rev_l - byte-swap a 32-bit value 759 * 760 * @val: source/destination register 761 * @tmp: scratch register 762 */ 763 .macro rev_l, val:req, tmp:req 764 .if __LINUX_ARM_ARCH__ < 6 765 eor \tmp, \val, \val, ror #16 766 bic \tmp, \tmp, #0x00ff0000 767 mov \val, \val, ror #8 768 eor \val, \val, \tmp, lsr #8 769 .else 770 rev \val, \val 771 .endif 772 .endm 773 774 .if __LINUX_ARM_ARCH__ < 6 775 .set .Lrev_l_uses_tmp, 1 776 .else 777 .set .Lrev_l_uses_tmp, 0 778 .endif 779 780 /* 781 * bl_r - branch and link to register 782 * 783 * @dst: target to branch to 784 * @c: conditional opcode suffix 785 */ 786 .macro bl_r, dst:req, c 787 .if __LINUX_ARM_ARCH__ < 6 788 mov\c lr, pc 789 mov\c pc, \dst 790 .else 791 blx\c \dst 792 .endif 793 .endm 794 795#endif /* __ASM_ASSEMBLER_H__ */