gas_marco_advance
在查阅unicore的memcpy函数时,感觉学到了不少东西,今天把一周的东西整理下,留下了这个文档,方便以后查阅
文件 asm/hwcap.h
/*
* linux/arch/unicore/include/asm/hwcap.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#ifndef __UNICORE_HWCAP_H__
#define __UNICORE_HWCAP_H__
/*
* HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
*/
#define HWCAP_MSP 1
#define HWCAP_UNICORE16 2
#define HWCAP_CMOV 4
#define HWCAP_UNICORE_F64 8
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
/*
* This yields a mask that user programs can use to figure out what
* instruction set this cpu supports.
*/
#define ELF_HWCAP (elf_hwcap)
extern unsigned int elf_hwcap;
#endif
#endif
文件 asm/ptrace.h
/*
* linux/arch/unicore/include/asm/ptrace.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#ifndef __UNICORE_PTRACE_H__
#define __UNICORE_PTRACE_H__
#include <asm/hwcap.h>
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15
/* PTRACE_ATTACH is 16 */
/* PTRACE_DETACH is 17 */
/* 18~20 is unused */
#define PTRACE_OLDSETOPTIONS 21
#define PTRACE_GET_THREAD_AREA 22
#define PTRACE_SET_SYSCALL 23
/* PTRACE_SYSCALL is 24 */
#define PTRACE_GETVFPREGS 27
#define PTRACE_SETVFPREGS 28
/*
* PSR bits
*/
#define USER_MODE 0x00000010
#define REAL_MODE 0x00000011
#define INTR_MODE 0x00000012
#define PRIV_MODE 0x00000013
#define ABRT_MODE 0x00000017
#define EXTN_MODE 0x0000001b
#define SUSR_MODE 0x0000001f
#define MODE_MASK 0x0000001f
#define PSR_R_BIT 0x00000040
#define PSR_I_BIT 0x00000080
#define PSR_V_BIT0x10000000
#define PSR_C_BIT 0x20000000
#define PSR_Z_BIT 0x40000000
#define PSR_S_BIT 0x80000000
/*
* Groups of PSR bits
*/
#define PSR_f 0xff000000 /* Flags*/
#define PSR_s 0x00ff0000 /* Status*/
#define PSR_x 0x0000ff00 /* Extension*/
#define PSR_c 0x000000ff /* Control*/
/*
* These are 'magic' values for PTRACE_PEEKUSR that return info about where a
* process is located in memory.
*/
#define PT_TEXT_ADDR 0x10000
#define PT_DATA_ADDR 0x10004
#define PT_TEXT_END_ADDR 0x10008
#ifndef __ASSEMBLY__
/*
* This struct defines the way the registers are stored on the
* stack during a system call. Note that sizeof(struct pt_regs)
* has to be a multiple of 8.
*/
struct pt_regs {
long uregs[34];
};
#define UCreg_csr uregs[32]
#define UCreg_pc uregs[31]
#define UCreg_lr uregs[30]
#define UCreg_sp uregs[29]
#define UCreg_ip uregs[28]
#define UCreg_fp uregs[27]
#define UCreg_26 uregs[26]
#define UCreg_25 uregs[25]
#define UCreg_24 uregs[24]
#define UCreg_23 uregs[23]
#define UCreg_22 uregs[22]
#define UCreg_21 uregs[21]
#define UCreg_20 uregs[20]
#define UCreg_19 uregs[19]
#define UCreg_18 uregs[18]
#define UCreg_17 uregs[17]
#define UCreg_16 uregs[16]
#define UCreg_15 uregs[15]
#define UCreg_14 uregs[14]
#define UCreg_13 uregs[13]
#define UCreg_12 uregs[12]
#define UCreg_11 uregs[11]
#define UCreg_10 uregs[10]
#define UCreg_09 uregs[9]
#define UCreg_08 uregs[8]
#define UCreg_07 uregs[7]
#define UCreg_06 uregs[6]
#define UCreg_05 uregs[5]
#define UCreg_04 uregs[4]
#define UCreg_03 uregs[3]
#define UCreg_02 uregs[2]
#define UCreg_01 uregs[1]
#define UCreg_00 uregs[0]
#define UCreg_ORIG_00 uregs[33]
#ifdef __KERNEL__
#define user_mode(regs) \
(processor_mode(regs) == USER_MODE)
#define isa_mode(regs)
0
#define processor_mode(regs) \
((regs)->UCreg_csr & MODE_MASK)
#define interrupts_enabled(regs) \
(!((regs)->UCreg_csr & PSR_I_BIT))
#define fast_interrupts_enabled(regs) \
(!((regs)->UCreg_csr & PSR_R_BIT))
/* Are the current registers suitable for user mode?
* (used to maintain security in signal handlers)
*/
static inline int valid_user_regs(struct pt_regs *regs)
{
if (user_mode(regs) && (regs->UCreg_csr & PSR_I_BIT) == 0) {
regs->UCreg_csr &= ~(PSR_R_BIT);
return 1;
}
/*
* Force CSR to something logical...
*/
regs->UCreg_csr &= PSR_f | PSR_s | PSR_x | USER_MODE;
return 0;
}
#define instruction_pointer(regs) (regs)->UCreg_pc
#define profile_pc(regs) instruction_pointer(regs)
#define predicate(x) ((x) & 0xf0000000)
#define PREDICATE_ALWAYS 0xe0000000
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
#endif
文件 asm/assember.h
/*
* linux/arch/unicore/include/asm/assembler.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*
* Do not include any C declarations in this file - it is included by
* assembler source.
*/
#ifndef __ASSEMBLY__
#error "Only include this from assembly code"
#endif
#include <asm/ptrace.h>
/*
* Little Endian independent macros for shifting bytes within registers.
*/
#define pull >>
#define push <<
#define get_byte_0 << #0
#define get_byte_1 >> #8
#define get_byte_2 >> #16
#define get_byte_3 >> #24
#define put_byte_0 << #0
#define put_byte_1 << #8
#define put_byte_2 << #16
#define put_byte_3 << #24
/*
* Enable and disable interrupts
*/
.macro disable_irq_notrace, temp
mov \temp, asr
andn \temp, \temp, #0xFF
or \temp, \temp, #PSR_I_BIT | PRIV_MODE
mov.a
asr, \temp
.endm
.macro enable_irq_notrace, temp
mov \temp, asr
andn \temp, \temp, #0xFF
or \temp, \temp, #PRIV_MODE
mov.a
asr, \temp
.endm
.macro asm_trace_hardirqs_off
#if defined(CONFIG_TRACE_IRQFLAGS)
stm.w (ip, lr), [sp-]
stm.w (r0-r3), [sp-]
b.l trace_hardirqs_off
ldm.w
(r0-r3), [sp]+
ldm.w
(ip, lr), [sp]+
#endif
.endm
.macro asm_trace_hardirqs_on_cond, cond
#if defined(CONFIG_TRACE_IRQFLAGS)
/*
* actually the registers should be pushed and pop'd conditionally, but
* after bl the flags are certainly clobbered
*/
stm.w (ip, lr), [sp-]
stm.w (r0-r3), [sp-]
bl\cond trace_hardirqs_on
ldm.w
(r0-r3), [sp]+
ldm.w
(ip, lr), [sp]+
#endif
.endm
.macro asm_trace_hardirqs_on
asm_trace_hardirqs_on_cond al
.endm
.macro disable_irq, temp
disable_irq_notrace \temp
asm_trace_hardirqs_off
.endm
.macro enable_irq, temp
asm_trace_hardirqs_on
enable_irq_notrace \temp
.endm
/*
* Save the current IRQ state and disable IRQs. Note that this macro
* assumes FIQs are enabled, and that the processor is in SVC mode.
*/
.macro save_and_disable_irqs, oldcpsr, temp
mov \oldcpsr, asr
disable_irq \temp
.endm
/*
* Restore interrupt state previously stored in a register. We don't
* guarantee that this will preserve the flags.
*/
.macro restore_irqs_notrace, oldcpsr, temp
mov \temp, asr
mov.a
asr, \oldcpsr
mov.f
asr, \temp
.endm
.macro restore_irqs, oldcpsr, temp
cmpand.a \oldcpsr, #PSR_I_BIT
asm_trace_hardirqs_on_cond eq
restore_irqs_notrace \oldcpsr, \temp
.endm
#define USER(x...) \
9999: \
.section __ex_table,"ax"; \
.align 3; \
.long9999b,9001f; \
.previous \
.macro notcond, cond, nexti=.+8
.ifc \cond, eq
bne \nexti
.else;.ifc \cond, ne
beq \nexti
.else;.ifc \cond, ea
bub \nexti
.else;.ifc \cond, ub
bea \nexti
.else;.ifc \cond, fs
bns \nexti
.else;.ifc \cond, ns
bfs \nexti
.else;.ifc \cond, fv
bnv \nexti
.else;.ifc \cond, nv
bfv \nexti
.else;.ifc \cond, ua
beb \nexti
.else;.ifc \cond, eb
bua \nexti
.else;.ifc \cond, eg
bsl \nexti
.else;.ifc \cond, sl
beg \nexti
.else;.ifc \cond, sg
bel \nexti
.else;.ifc \cond, el
bsg \nexti
.else;.ifnc \cond, al
.error "Unknown cond in notcond macro argument"
.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif;.endif
.endm
.endif
.endif
.macro usracc, instr, reg, ptr, inc, cond, rept, abort
.rept \rept
notcond \cond, .+8
9999:
.if \inc == 1
\instr\()b.u \reg, [\ptr], #\inc
.elseif \inc == 4
\instr\()w.u \reg, [\ptr], #\inc
.else
.error "Unsupported inc macro argument"
.endif
.section __ex_table,"a"
.align
3
.long9999b, \abort
.previous
.endr
.endm
.macro strusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
usracc st, \reg, \ptr, \inc, \cond, \rept, \abort
.endm
.macro ldrusr, reg, ptr, inc, cond=al, rept=1, abort=9001f
usracc ld, \reg, \ptr, \inc, \cond, \rept, \abort
.endm
文件 asm/linkage.h
/
*
* linux/arch/unicore/include/asm/linkage.h
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
#ifndef __UNICORE_LINKAGE_H__
#define __UNICORE_LINKAGE_H__
#define __ALIGN .align 0
#define __ALIGN_STR ".align 0"
#define ENDPROC(name) \
.type name, %function; \
END(name)
#endif
文件 linux/linkage.h
#ifndef _LINUX_LINKAGE_H
#define _LINUX_LINKAGE_H
#include <linux/compiler.h>
#include <asm/linkage.h>
#ifdef __cplusplus
#define CPP_ASMLINKAGE extern "C"
#else
#define CPP_ASMLINKAGE
#endif
#ifndef asmlinkage
#define asmlinkage CPP_ASMLINKAGE
#endif
#ifndef asmregparm
# define asmregparm
#endif
#define __page_aligned_data __section(.data.page_aligned) __aligned(PAGE_SIZE)
#define __page_aligned_bss __section(.bss.page_aligned) __aligned(PAGE_SIZE)
/*
* For assembly routines.
*
* Note when using these that you must specify the appropriate
* alignment directives yourself
*/
#define __PAGE_ALIGNED_DATA
.section ".data.page_aligned", "aw"
#define __PAGE_ALIGNED_BSS .section ".bss.page_aligned", "aw"
/*
* This is used by architectures to keep arguments on the stack
* untouched by the compiler by keeping them live until the end.
* The argument stack may be owned by the assembly-language
* caller, not the callee, and gcc doesn't always understand
* that.
*
* We have the return value, and a maximum of six arguments.
*
* This should always be followed by a "return ret" for the
* protection to work (ie no more work that the compiler might
* end up needing stack temporaries for).
*/
/* Assembly files may be compiled with -traditional .. */
#ifndef __ASSEMBLY__
#ifndef asmlinkage_protect
# define asmlinkage_protect(n, ret, args...)
do { } while (0)
#endif
#endif
#ifndef __ALIGN
#define __ALIGN
.align 4,0x90
#define __ALIGN_STR ".align 4,0x90"
#endif
#ifdef __ASSEMBLY__
#ifndef LINKER_SCRIPT
#define ALIGN __ALIGN
#define ALIGN_STR __ALIGN_STR
#ifndef ENTRY
#define ENTRY(name) \
.globl name; \
ALIGN; \
name:
#endif
#endif /* LINKER_SCRIPT */
#ifndef WEAK
#define WEAK(name) \
.weak name; \
name:
#endif
#ifndef END
#define END(name) \
.size name, .-name
#endif
/* If symbol 'name' is treated as a subroutine (gets called, and returns)
* then please use ENDPROC to mark 'name' as STT_FUNC for the benefit of
* static analysis tools such as stack depth analyzer.
*/
#ifndef ENDPROC
#define ENDPROC(name) \
.type name, @function; \
END(name)
#endif
#endif
#define NORET_TYPE /**/
#define ATTRIB_NORET __attribute__((noreturn))
#define NORET_AND noreturn,
#endif
文件 lib/copy_from_user.S
/*
* linux/arch/unicore/lib/copy_from_user.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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/linkage.h>
#include <asm/assembler.h>
/*
* Prototype:
*
* size_t __copy_from_user(void *to, const void *from, size_t n)
*
* Purpose:
*
* copy a block to kernel memory from user memory
*
* Params:
*
* to = kernel memory
* from = user memory
* n = number of bytes to copy
*
* Return value:
*
* Number of bytes NOT copied.
*/
.macro ldr1w ptr reg abort
ldrusr \reg, \ptr, 4, abort=\abort
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
100: ldm.w (\reg1, \reg2, \reg3, \reg4), [\ptr]+
.section __ex_table, "a"
.align 3
.long 100b, \abort
.previous
.endm
.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
100:
ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.section __ex_table, "a"
.align 3
.long 100b, \abort
.previous
.endm
.macro ldr1b ptr reg cond=al abort
ldrusr \reg, \ptr, 1, \cond, abort=\abort
.endm
.macro str1w ptr reg abort
stw.w \reg, [\ptr]+, #4
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm
.macro str1b ptr reg cond=al abort
.ifnc \cond, al
b\cond 201f
b 202f
.endif
201:
stb.w \reg, [\ptr]+, #1
202:
.endm
.macro enter
mov r3, #0
stm.w (r0, r2, r3), [sp-]
.endm
.macro exit
add sp, sp, #8
ldm.w (r0), [sp]+
mov pc, lr
.endm
.text
ENTRY(__copy_from_user)
#include "copy_template.S"
ENDPROC(__copy_from_user)
.section .fixup,"ax"
.align 0
copy_abort_preamble
ldm.w (r1, r2), [sp]+
sub r3, r0, r1
rsub r1, r3, r2
stw r1, [sp]
b.l __memzero
ldw.w r0, [sp]+, #4
copy_abort_end
.previous
文件 lib/copy_to_user.S
/*
* linux/arch/unicore/lib/copy_to_user.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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/linkage.h>
#include <asm/assembler.h>
/*
* Prototype:
*
* size_t __copy_to_user(void *to, const void *from, size_t n)
*
* Purpose:
*
* copy a block to user memory from kernel memory
*
* Params:
*
* to = user memory
* from = kernel memory
* n = number of bytes to copy
*
* Return value:
*
* Number of bytes NOT copied.
*/
.macro ldr1w ptr reg abort
ldw.w \reg, [\ptr]+, #4
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
ldm.w (\reg1, \reg2, \reg3, \reg4), [\ptr]+
.endm
.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm
.macro ldr1b ptr reg cond=al abort
notcond \cond, .+8
ldb.w \reg, [\ptr]+, #1
.endm
.macro str1w ptr reg abort
strusr \reg, \ptr, 4, abort=\abort
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
100:
stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.section __ex_table, "a"
.long 100b, \abort
.previous
.endm
.macro str1b ptr reg cond=al abort
strusr \reg, \ptr, 1, \cond, abort=\abort
.endm
.macro enter
mov r3, #0
stm.w (r0, r2, r3), [sp-]
.endm
.macro exit
add sp, sp, #8
ldm.w (r0), [sp]+
mov pc, lr
.endm
.text
ENTRY(__copy_to_user_std)
WEAK(__copy_to_user)
#include "copy_template.S"
ENDPROC(__copy_to_user)
.section .fixup,"ax"
.align 0
copy_abort_preamble
ldm.w (r1, r2, r3), [sp]+
sub r0, r0, r1
rsub r0, r0, r2
copy_abort_end
.previous
文件 lib/copy_template.S
/*
* linux/arch/unicore/lib/copy_template.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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.
*/
/*
* Theory of operation
* -------------------
*
* This file provides the core code for a forward memory copy used in
* the implementation of memcopy(), copy_to_user() and copy_from_user().
*
* The including file must define the following accessor macros
* according to the need of the given function:
*
* ldr1w ptr reg abort
*
* This loads one word from 'ptr', stores it in 'reg' and increments
* 'ptr' to the next word. The 'abort' argument is used for fixup tables.
*
* ldr4w ptr reg1 reg2 reg3 reg4 abort
* ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
*
* This loads four or eight words starting from 'ptr', stores them
* in provided registers and increments 'ptr' past those words.
* The'abort' argument is used for fixup tables.
*
* ldr1b ptr reg cond abort
*
* Similar to ldr1w, but it loads a byte and increments 'ptr' one byte.
* It also must apply the condition code if provided, otherwise the
* "al" condition is assumed by default.
*
* str1w ptr reg abort
* str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
* str1b ptr reg cond abort
*
* Same as their ldr* counterparts, but data is stored to 'ptr' location
* rather than being loaded.
*
* enter
*
* Preserve the provided registers on the stack plus any additional
* data as needed by the implementation including this code. Called
* upon code entry.
*
* exit
*
* Restore registers with the values previously saved with the
* 'preserv' macro. Called upon code termination.
*/
enter
sub.ar2, r2, #4
bsl 8f
and.a
ip, r0, #3
bne 9f
and.a
ip, r1, #3
bne 10f
1:sub.ar2, r2, #(28)
stm.w (r5 - r8), [sp-]
bsl 5f
3:
4:
ldr8w r1, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
sub.ar2, r2, #32
str8w r0, r3, r4, r5, r6, r7, r8, r10, r11, abort=20f
beg 3b
5:
and.a
ip, r2, #28
rsub ip, ip, #32
beq 7f
add pc, pc, ip @ C is always clear here
nop
ldr1w r1, r3, abort=20f
ldr1w r1, r4, abort=20f
ldr1w r1, r5, abort=20f
ldr1w r1, r6, abort=20f
ldr1w r1, r7, abort=20f
ldr1w r1, r8, abort=20f
ldr1w r1, r11, abort=20f
add pc, pc, ip
nop
str1w r0, r3, abort=20f
str1w r0, r4, abort=20f
str1w r0, r5, abort=20f
str1w r0, r6, abort=20f
str1w r0, r7, abort=20f
str1w r0, r8, abort=20f
str1w r0, r11, abort=20f
7:
ldm.w (r5 - r8), [sp]+
8:
mov.a r2, r2 << #31
ldr1b r1, r3, ne, abort=21f
ldr1b r1, r4, ea, abort=21f
ldr1b r1, r10, ea, abort=21f
str1b r0, r3, ne, abort=21f
str1b r0, r4, ea, abort=21f
str1b r0, r10, ea, abort=21f
exit
9:
rsub ip, ip, #4
cmpsub.a ip, #2
ldr1b r1, r3, sg, abort=21f
ldr1b r1, r4, eg, abort=21f
ldr1b r1, r11, abort=21f
str1b r0, r3, sg, abort=21f
str1b r0, r4, eg, abort=21f
sub.ar2, r2, ip
str1b r0, r11, abort=21f
bsl 8b
and.a ip, r1, #3
beq 1b
10:
andn r1, r1, #3
cmpsub.a ip, #2
ldr1w r1, r11, abort=21f
beq 17f
bsg 18f
.macro
forward_copy_shift a b
sub.ar2, r2, #28
bsl 14f
11:
stm.w (r5 - r9), [sp-]
12:
ldr4w r1, r4, r5, r6, r7, abort=19f
mov r3, r11 pull #\a
sub.ar2, r2, #32
ldr4w r1, r8, r9, r10, r11, abort=19f
or r3, r3, r4 push #\b
mov r4, r4 pull #\a
or r4, r4, r5 push #\b
mov r5, r5 pull #\a
or r5, r5, r6 push #\b
mov r6, r6 pull #\a
or r6, r6, r7 push #\b
mov r7, r7 pull #\a
or r7, r7, r8 push #\b
mov r8, r8 pull #\a
or r8, r8, r9 push #\b
mov r9, r9 pull #\a
or r9, r9, r10 push #\b
mov r10, r10 pull #\a
or r10, r10, r11 push #\b
str8w r0, r3, r4, r5, r6, r7, r8, r9, r10, , abort=19f
beg 12b
ldm.w (r5 - r9), [sp]+
14:
and.a ip, r2, #28
beq 16f
15:
mov r3, r11 pull #\a
ldr1w r1, r11, abort=21f
sub.aip, ip, #4
or r3, r3, r11 push #\b
str1w r0, r3, abort=21f
bsg 15b
16:
sub r1, r1, #(\b / 8)
b 8b
.endm
forward_copy_shift a=8 b=24
17: forward_copy_shift a=16b=16
18: forward_copy_shift a=24b=8
/*
* Abort preamble and completion macros.
* If a fixup handler is required then those macros must surround it.
* It is assumed that the fixup code will handle the private part of
* the exit macro.
*/
.macro copy_abort_preamble
19:
ldm.w (r5 - r9), [sp]+
b 21f
299:
.word 0 @ store lr, to avoid function call in fixup
20:
ldm.w (r5 - r8), [sp]+
21:
adr r1, 299b
stw lr, [r1]
.endm
.macro copy_abort_end
adr lr, 299b
ldw pc, [lr]
.endm
文件 lib/memcpy.S
/*
* linux/arch/unicore/lib/memcpy.S
*
* Code specific to PKUnity SoC and UniCore ISA
* Fragments that appear the same as the files in arm or x86
*
* Copyright (C) 2001-2008 GUAN Xue-tao
*
* 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/linkage.h>
#include <asm/assembler.h>
.macro ldr1w ptr reg abort
ldw.w \reg, [\ptr]+, #4
.endm
.macro ldr4w ptr reg1 reg2 reg3 reg4 abort
ldm.w (\reg1, \reg2, \reg3, \reg4), [\ptr]+
.endm
.macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
ldm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm
.macro ldr1b ptr reg cond=al abort
.ifnc \cond, al
b\cond 201f
b 202f
.endif
201:
ldb.w \reg, [\ptr]+, #1
202:
.endm
.macro str1w ptr reg abort
stw.w \reg, [\ptr]+, #4
.endm
.macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort
stm.w (\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8), [\ptr]+
.endm
.macro str1b ptr reg cond=al abort
.ifnc \cond, al
b\cond 201f
b 202f
.endif
201:
stb.w \reg, [\ptr]+, #1
202:
.endm
.macro enter
stm.w (r0), [sp-]
.endm
.macro exit
ldm.w (r0), [sp]+
mov pc, lr
.endm
.text
/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
ENTRY(memcpy)
#include "copy_template.S"
ENDPROC(memcpy)