[klibc] arm support for klibc The parts of klibc specific to the arm architecture. Signed-off-by: H. Peter Anvin --- commit 1bf73107f80f397f28312d3d0914edf1ef408170 tree d029c0b074cf846d476b91df7133b5cad7c27466 parent 2d5e59a159a077232e53a8d4b590f94a22ab80dc author H. Peter Anvin Sun, 02 Jul 2006 12:25:12 -0700 committer H. Peter Anvin Sun, 02 Jul 2006 12:25:12 -0700 usr/include/arch/arm/klibc/archconfig.h | 14 ++++ usr/include/arch/arm/klibc/archsetjmp.h | 14 ++++ usr/include/arch/arm/klibc/archsignal.h | 14 ++++ usr/include/arch/arm/klibc/archstat.h | 40 ++++++++++++ usr/include/arch/arm/klibc/asmmacros.h | 30 +++++++++ usr/klibc/arch/arm/MCONFIG | 36 +++++++++++ usr/klibc/arch/arm/Makefile.inc | 23 +++++++ usr/klibc/arch/arm/__muldi3.c | 15 +++++ usr/klibc/arch/arm/aeabi_nonsense.S | 9 +++ usr/klibc/arch/arm/crt0.S | 23 +++++++ usr/klibc/arch/arm/setjmp.S | 102 +++++++++++++++++++++++++++++++ usr/klibc/arch/arm/syscall.S | 61 +++++++++++++++++++ usr/klibc/arch/arm/sysstub.ph | 58 ++++++++++++++++++ usr/klibc/arch/arm/vfork.S | 60 ++++++++++++++++++ 14 files changed, 499 insertions(+), 0 deletions(-) diff --git a/usr/include/arch/arm/klibc/archconfig.h b/usr/include/arch/arm/klibc/archconfig.h new file mode 100644 index 0000000..e34bdb7 --- /dev/null +++ b/usr/include/arch/arm/klibc/archconfig.h @@ -0,0 +1,14 @@ +/* + * include/arch/arm/klibc/archconfig.h + * + * See include/klibc/sysconfig.h for the options that can be set in + * this file. + * + */ + +#ifndef _KLIBC_ARCHCONFIG_H +#define _KLIBC_ARCHCONFIG_H + +/* All defaults */ + +#endif /* _KLIBC_ARCHCONFIG_H */ diff --git a/usr/include/arch/arm/klibc/archsetjmp.h b/usr/include/arch/arm/klibc/archsetjmp.h new file mode 100644 index 0000000..88db8a1 --- /dev/null +++ b/usr/include/arch/arm/klibc/archsetjmp.h @@ -0,0 +1,14 @@ +/* + * arch/i386/include/klibc/archsetjmp.h + */ + +#ifndef _KLIBC_ARCHSETJMP_H +#define _KLIBC_ARCHSETJMP_H + +struct __jmp_buf { + unsigned int regs[10]; +}; + +typedef struct __jmp_buf jmp_buf[1]; + +#endif /* _SETJMP_H */ diff --git a/usr/include/arch/arm/klibc/archsignal.h b/usr/include/arch/arm/klibc/archsignal.h new file mode 100644 index 0000000..a589527 --- /dev/null +++ b/usr/include/arch/arm/klibc/archsignal.h @@ -0,0 +1,14 @@ +/* + * arch/arm/include/klibc/archsignal.h + * + * Architecture-specific signal definitions + * + */ + +#ifndef _KLIBC_ARCHSIGNAL_H +#define _KLIBC_ARCHSIGNAL_H + +#include +/* No special stuff for this architecture */ + +#endif diff --git a/usr/include/arch/arm/klibc/archstat.h b/usr/include/arch/arm/klibc/archstat.h new file mode 100644 index 0000000..95bbc9e --- /dev/null +++ b/usr/include/arch/arm/klibc/archstat.h @@ -0,0 +1,40 @@ +#ifndef _KLIBC_ARCHSTAT_H +#define _KLIBC_ARCHSTAT_H + +#include + +#define _STATBUF_ST_NSEC + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + * Note: The kernel zero's the padded region because glibc might read them + * in the hope that the kernel has stretched to using larger sizes. + */ + +struct stat { + __stdev64 (st_dev); + unsigned char __pad0[4]; + + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + __stdev64 (st_rdev); + unsigned char __pad3[4]; + + long long st_size; + unsigned long st_blksize; + + unsigned long long st_blocks; /* Number 512-byte blocks allocated. */ + + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + + unsigned long long st_ino; +}; + +#endif diff --git a/usr/include/arch/arm/klibc/asmmacros.h b/usr/include/arch/arm/klibc/asmmacros.h new file mode 100644 index 0000000..8a21c94 --- /dev/null +++ b/usr/include/arch/arm/klibc/asmmacros.h @@ -0,0 +1,30 @@ +/* + * usr/include/arch/arm/klibc/asmmacros.h + * + * Assembly macros used by ARM system call stubs + */ + +#ifndef _KLIBC_ASMMACROS_H +#define _KLIBC_ASMMACROS_H + +/* An immediate in ARM can be any 8-bit value rotated by an even number of bits */ + +#define ARM_VALID_IMM(x) \ + ((((x) & ~0x000000ff) == 0) || \ + (((x) & ~0x000003fc) == 0) || \ + (((x) & ~0x00000ff0) == 0) || \ + (((x) & ~0x00003fc0) == 0) || \ + (((x) & ~0x0000ff00) == 0) || \ + (((x) & ~0x0003fc00) == 0) || \ + (((x) & ~0x000ff000) == 0) || \ + (((x) & ~0x003fc000) == 0) || \ + (((x) & ~0x00ff0000) == 0) || \ + (((x) & ~0x03fc0000) == 0) || \ + (((x) & ~0x0ff00000) == 0) || \ + (((x) & ~0x3fc00000) == 0) || \ + (((x) & ~0xff000000) == 0) || \ + (((x) & ~0xfc000003) == 0) || \ + (((x) & ~0xf000000f) == 0) || \ + (((x) & ~0xc000003f) == 0)) + +#endif /* _KLIBC_ASMMACROS_H */ diff --git a/usr/klibc/arch/arm/MCONFIG b/usr/klibc/arch/arm/MCONFIG new file mode 100644 index 0000000..0023eee --- /dev/null +++ b/usr/klibc/arch/arm/MCONFIG @@ -0,0 +1,36 @@ +# -*- makefile -*- +# +# arch/arm/MCONFIG +# +# Special rules for this architecture. Note that this is actually +# included from the main Makefile, and that pathnames should be +# accordingly. +# + +CPU_ARCH := armv4 +CPU_TUNE := strongarm + +KLIBCOPTFLAGS = -Os -march=$(CPU_ARCH) -mtune=$(CPU_TUNE) +KLIBCBITSIZE = 32 +KLIBCREQFLAGS = -fno-exceptions +KLIBCSTRIPFLAGS += -R .ARM.exidx + +ifeq ($(CONFIG_KLIBC_THUMB),y) +CPU_ARCH := $(CPU_ARCH)t +KLIBCREQFLAGS += -mthumb +KLIBCLDFLAGS += --thumb-entry _start +KLIBCEMAIN = --thumb-entry _start +KLIBCREQFLAGS += -mabi=aapcs-linux +KLIBCSHAREDFLAGS = -Ttext 0x380200 +else +# Extra linkflags when building the shared version of the library +# This address needs to be reachable using normal inter-module +# calls, and work on the memory models for this architecture +KLIBCSHAREDFLAGS = -Ttext 0x01800200 +ifeq ($(CONFIG_AEABI),y) +KLIBCREQFLAGS += -mabi=aapcs-linux -mno-thumb-interwork +else +KLIBCREQFLAGS += -mabi=apcs-gnu -mno-thumb-interwork +endif +endif + diff --git a/usr/klibc/arch/arm/Makefile.inc b/usr/klibc/arch/arm/Makefile.inc new file mode 100644 index 0000000..62065df --- /dev/null +++ b/usr/klibc/arch/arm/Makefile.inc @@ -0,0 +1,23 @@ +# -*- makefile -*- +# +# arch/arm/Makefile.inc +# +# Special rules for this architecture. Note that this is actually +# included from the main Makefile, and that pathnames should be +# accordingly. +# + +KLIBCARCHOBJS = \ + arch/arm/setjmp.o \ + arch/arm/syscall.o \ + arch/arm/vfork.o \ + arch/arm/aeabi_nonsense.o \ + libgcc/__udivmodsi4.o \ + libgcc/__divdi3.o \ + libgcc/__moddi3.o \ + libgcc/__udivdi3.o \ + libgcc/__umoddi3.o \ + libgcc/__udivmoddi4.o \ + libgcc/__clzsi2.o \ + + diff --git a/usr/klibc/arch/arm/__muldi3.c b/usr/klibc/arch/arm/__muldi3.c new file mode 100644 index 0000000..3fdeb2b --- /dev/null +++ b/usr/klibc/arch/arm/__muldi3.c @@ -0,0 +1,15 @@ +#include + +uint64_t __muldi3(uint64_t a, uint64_t b) +{ + uint32_t al = (uint32_t)a; + uint32_t ah = (uint32_t)(a >> 32); + uint32_t bl = (uint32_t)b; + uint32_t bh = (uint32_t)(b >> 32); + uint64_t v; + + v = (uint64_t)al * bl; + v += (uint64_t)(al*bh+ah*bl) << 32; + + return v; +} diff --git a/usr/klibc/arch/arm/aeabi_nonsense.S b/usr/klibc/arch/arm/aeabi_nonsense.S new file mode 100644 index 0000000..c69eb11 --- /dev/null +++ b/usr/klibc/arch/arm/aeabi_nonsense.S @@ -0,0 +1,9 @@ + .text + .globl __aeabi_unwind_cpp_pr0 +__aeabi_unwind_cpp_pr0: + .globl __aeabi_unwind_cpp_pr1 +__aeabi_unwind_cpp_pr1: + .globl __aeabi_unwind_cpp_pr2 +__aeabi_unwind_cpp_pr2: + .globl __aeabi_unwind_cpp_pr3 +__aeabi_unwind_cpp_pr3: diff --git a/usr/klibc/arch/arm/crt0.S b/usr/klibc/arch/arm/crt0.S new file mode 100644 index 0000000..1e81f8e --- /dev/null +++ b/usr/klibc/arch/arm/crt0.S @@ -0,0 +1,23 @@ +# +# arch/arm/crt0.S +# +# void _start(void) +# { +# __libc_init(elf_structure, atexit_ptr); +# } +# + + .text + .balign 4 + .type _start,#function + .globl _start + +#ifdef __thumb__ + .thumb_func +#endif + +_start: mov r0, sp + mov r1, #0 + bl __libc_init + + .size _start,.-_start diff --git a/usr/klibc/arch/arm/setjmp.S b/usr/klibc/arch/arm/setjmp.S new file mode 100644 index 0000000..1841bc7 --- /dev/null +++ b/usr/klibc/arch/arm/setjmp.S @@ -0,0 +1,102 @@ +# +# arch/arm/setjmp.S +# +# setjmp/longjmp for the ARM architecture +# + +#ifndef __thumb__ + +# +# "Pure ARM" version +# +# The jmp_buf is assumed to contain the following, in order: +# r4 +# r5 +# r6 +# r7 +# r8 +# r9 +# r10 +# fp +# sp +# lr +# + + .text + .balign 4 + .globl setjmp + .type setjmp, #function +setjmp: + stmia r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr} + mov r0, #0 + mov pc, lr + .size setjmp,.-setjmp + + .text + .balign 4 + .globl longjmp + .type longjmp, #function +longjmp: + ldmia r0, {r4, r5, r6, r7, r8, r9, r10, fp, sp, lr} + mov r0, r1 + mov pc, lr + .size longjmp,.-longjmp + +#else /* __thumb__ */ + +# +# Thumb version +# +# The jmp_buf is assumed to contain the following, in order: +# lr +# r4 +# r5 +# r6 +# r7 +# r8 +# r9 +# r10 +# fp +# sp +# + + .text + .balign 4 + .globl setjmp + .type setjmp, #function + .thumb_func +setjmp: + mov r3, lr + stmia r0!, {r3, r4, r5, r6, r7} + mov r3, r8 + mov r4, r9 + mov r5, r10 + mov r6, fp + mov r7, sp + stmia r0!, {r3, r4, r5, r6, r7} + mov r0, #0 + mov pc, lr + .size setjmp,.-setjmp + + .text + .balign 4 + .globl longjmp + .type longjmp, #function + .thumb_func +longjmp: + mov r2, r0 + add r0, #5*4 + ldmia r0!, {r3, r4, r5, r6, r7} + mov r8, r3 + mov r9, r4 + mov r10, r5 + mov fp, r6 + mov sp, r7 + ldmia r2!, {r3, r4, r5, r6, r7} + mov r0, r1 + bne 1f + mov r0, #1 +1: mov pc, r3 + .size longjmp,.-longjmp + +#endif /* __thumb__ */ diff --git a/usr/klibc/arch/arm/syscall.S b/usr/klibc/arch/arm/syscall.S new file mode 100644 index 0000000..5bc291d --- /dev/null +++ b/usr/klibc/arch/arm/syscall.S @@ -0,0 +1,61 @@ +/* + * arch/arm/syscall.S + * + * System call common handling + */ + + .type __syscall_common,#function + .globl __syscall_common +#ifndef __thumb__ + /* ARM version - this is executed after the swi, unless + we are compiled in EABI mode */ + + .balign 4 +__syscall_common: +#ifdef __ARM_EABI__ + ldr r4, [sp,#16] + ldr r5, [sp,#20] + ldr r7, [lr] + swi 0 +#endif + cmn r0, #4096 + rsbcs r2, r0, #0 + ldrcs r3, 1f + mvncs r0, #0 + strcs r2, [r3] + ldmfd sp!,{r4,r5,r7,pc} + + .balign 4 +1: + .word errno + +#else + /* Thumb version - must still load r4 and r5 and run swi */ + + .thumb_func + .balign 2 +__syscall_common: + mov r7, lr + ldr r4, [sp,#16] + sub r7, #1 /* Remove the Thumb bit */ + ldr r5, [sp,#20] + ldrh r7, [r7] + swi 0 + ldr r1, 2f + cmp r0, r1 + bcc 1f + ldr r1, 3f + neg r2, r0 + mov r0, #1 + str r2, [r1] + neg r0, r0 +1: + pop {r4,r5,r7,pc} + + .balign 4 +2: + .word -4095 +3: + .word errno + +#endif diff --git a/usr/klibc/arch/arm/sysstub.ph b/usr/klibc/arch/arm/sysstub.ph new file mode 100644 index 0000000..d51ace1 --- /dev/null +++ b/usr/klibc/arch/arm/sysstub.ph @@ -0,0 +1,58 @@ +# -*- perl -*- +# +# arch/arm/sysstub.ph +# +# Script to generate system call stubs +# + + +sub make_sysstub($$$$$@) { + my($outputdir, $fname, $type, $sname, $stype, @args) = @_; + + open(OUT, '>', "${outputdir}/${fname}.S"); + print OUT "#include \n"; + print OUT "#include \n"; + + print OUT " .text\n"; + print OUT " .type ${fname}, #function\n"; + print OUT " .globl ${fname}\n"; + + print OUT "#ifndef __thumb__\n"; + + print OUT "#ifndef __ARM_EABI__\n"; + + # ARM version first + print OUT " .balign 4\n"; + print OUT "${fname}:\n"; + print OUT " stmfd sp!,{r4,r5,lr}\n"; + print OUT " ldr r4,[sp,#12]\n"; + print OUT " ldr r5,[sp,#16]\n"; + print OUT " swi # __NR_${sname}\n"; + print OUT " b __syscall_common\n"; + + print OUT "#else /* __ARM_EABI__ */\n"; + + # ARM EABI version + print out " .balign 4\n"; + print OUT "${fname}:\n"; + print OUT " stmfd sp!,{r4,r5,r7,lr}\n"; + print OUT " bl __syscall_common\n"; + print OUT " .word __NR_${sname}\n"; + + print OUT "#endif /* __ARM_EABI__ */\n"; + print OUT "#else /* __thumb__ */\n"; + + # Thumb version + print OUT " .balign 8\n"; + print OUT " .thumb_func\n"; + print OUT "${fname}:\n"; + print OUT " push {r4,r5,r7,lr}\n"; + print OUT " bl __syscall_common\n"; + print OUT " .short __NR_${sname}\n"; + + print OUT "#endif /* __thumb__*/\n"; + + print OUT " .size __syscall${i},.-__syscall${i}\n"; +} + +1; diff --git a/usr/klibc/arch/arm/vfork.S b/usr/klibc/arch/arm/vfork.S new file mode 100644 index 0000000..3b2d9f7 --- /dev/null +++ b/usr/klibc/arch/arm/vfork.S @@ -0,0 +1,60 @@ +/* + * arch/arm/vfork.S + * + * vfork - nasty system call which must not use the stack. + */ + +#include + + .type vfork,#function + .globl vfork +#ifndef __thumb__ + + .balign 4 +vfork: +#ifdef __ARM_EABI__ + mov r3, r7 + mov r7, # __NR_vfork + swi 0 + mov r7, r3 +#else + swi # __NR_vfork +#endif + cmn r0, #4096 + rsbcs r2, r0, #0 + ldrcs r3, 1f + mvncs r0, #0 + strcs r2, [r3] + mov pc, lr + + .balign 4 +1: + .word errno + +#else + + .thumb_func + .balign 2 +vfork: + mov r3, r7 + mov r7, # __NR_vfork + swi 0 + mov r7, r3 + ldr r1, 2f + cmp r0, r1 + bcc 1f + ldr r1, 3f + neg r2, r0 + mov r0, #1 + str r2, [r1] + neg r0, r0 +1: + mov pc, lr + + .balign 4 +2: + .word -4095 +3: + .word errno + +#endif