[klibc 04/31] alpha support for klibc

H. Peter Anvin
2006-06-28T05:18:43Z

The parts of klibc specific to the alpha architecture.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>

---
commit c3fe3fde33e77fa6c09cb43ca3783e6bf36ef895
tree ab9ab1f40c31a5d430a3e6fbc6ef33640004c0f9
parent 7e8269dfd52a48d7b5017a1aaac410e9656c8139
author H. Peter Anvin <hpa@zytor.com> Tue, 27 Jun 2006 20:50:27 -0700
committer H. Peter Anvin <hpa@zytor.com> Tue, 27 Jun 2006 20:50:27 -0700

usr/include/arch/alpha/klibc/archconfig.h | 15 ++++++
usr/include/arch/alpha/klibc/archsetjmp.h | 33 +++++++++++++
usr/include/arch/alpha/klibc/archsignal.h | 14 +++++
usr/include/arch/alpha/klibc/archstat.h | 28 +++++++++++
usr/include/arch/alpha/machine/asm.h | 44 +++++++++++++++++
usr/klibc/arch/alpha/MCONFIG | 16 ++++++
usr/klibc/arch/alpha/Makefile.inc | 60 +++++++++++++++++++++++
usr/klibc/arch/alpha/README-gcc | 22 +++++++++
usr/klibc/arch/alpha/crt0.S | 22 +++++++++
usr/klibc/arch/alpha/divide.c | 59 +++++++++++++++++++++++
usr/klibc/arch/alpha/pipe.S | 38 +++++++++++++++
usr/klibc/arch/alpha/setjmp.S | 75 +++++++++++++++++++++++++++++
usr/klibc/arch/alpha/syscall.S | 26 ++++++++++
usr/klibc/arch/alpha/sysdual.S | 33 +++++++++++++
usr/klibc/arch/alpha/sysstub.ph | 37 ++++++++++++++
15 files changed, 522 insertions(+), 0 deletions(-)

diff --git a/usr/include/arch/alpha/klibc/archconfig.h b/usr/include/arch/alpha/klibc/archconfig.h
new file mode 100644
index 0000000..272fee0
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archconfig.h
@@ -0,0 +1,15 @@
+/*
+ * include/arch/alpha/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
+
+#define _KLIBC_USE_RT_SIG 1
+#define _KLIBC_STATFS_F_TYPE_64 0
+
+#endif /* _KLIBC_ARCHCONFIG_H */
diff --git a/usr/include/arch/alpha/klibc/archsetjmp.h b/usr/include/arch/alpha/klibc/archsetjmp.h
new file mode 100644
index 0000000..47638b3
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archsetjmp.h
@@ -0,0 +1,33 @@
+/*
+ * arch/alpha/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+ unsigned long __s0;
+ unsigned long __s1;
+ unsigned long __s2;
+ unsigned long __s3;
+ unsigned long __s4;
+ unsigned long __s5;
+ unsigned long __fp;
+ unsigned long __ra;
+ unsigned long __gp;
+ unsigned long __sp;
+
+ unsigned long __f2;
+ unsigned long __f3;
+ unsigned long __f4;
+ unsigned long __f5;
+ unsigned long __f6;
+ unsigned long __f7;
+ unsigned long __f8;
+ unsigned long __f9;
+};
+
+/* Must be an array so it will decay to a pointer when a function is called */
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _KLIBC_ARCHSETJMP_H */
diff --git a/usr/include/arch/alpha/klibc/archsignal.h b/usr/include/arch/alpha/klibc/archsignal.h
new file mode 100644
index 0000000..2193a35
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archsignal.h
@@ -0,0 +1,14 @@
+/*
+ * arch/alpha/include/klibc/archsignal.h
+ *
+ * Architecture-specific signal definitions
+ *
+ */
+
+#ifndef _KLIBC_ARCHSIGNAL_H
+#define _KLIBC_ARCHSIGNAL_H
+
+#include <asm/signal.h>
+/* No special stuff for this architecture */
+
+#endif
diff --git a/usr/include/arch/alpha/klibc/archstat.h b/usr/include/arch/alpha/klibc/archstat.h
new file mode 100644
index 0000000..66e29be
--- /dev/null
+++ b/usr/include/arch/alpha/klibc/archstat.h
@@ -0,0 +1,28 @@
+#ifndef _KLIBC_ARCHSTAT_H
+#define _KLIBC_ARCHSTAT_H
+
+#include <klibc/stathelp.h>
+
+#define _STATBUF_ST_NSEC
+
+struct stat {
+ __stdev64 (st_dev);
+ unsigned long st_ino;
+ __stdev64 (st_rdev);
+ long st_size;
+ unsigned long st_blocks;
+
+ unsigned int st_mode;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_blksize;
+ unsigned int st_nlink;
+ unsigned int __pad0;
+
+ struct timespec st_atim;
+ struct timespec st_mtim;
+ struct timespec st_ctim;
+ long __unused[3];
+};
+
+#endif
diff --git a/usr/include/arch/alpha/machine/asm.h b/usr/include/arch/alpha/machine/asm.h
new file mode 100644
index 0000000..c2ae4ed
--- /dev/null
+++ b/usr/include/arch/alpha/machine/asm.h
@@ -0,0 +1,44 @@
+/*
+ * machine/asm.h
+ */
+
+#ifndef _MACHINE_ASM_H
+#define _MACHINE_ASM_H
+
+/* Standard aliases for Alpha register names */
+
+#define v0 $0
+#define t0 $1
+#define t1 $2
+#define t2 $3
+#define t3 $4
+#define t4 $5
+#define t5 $6
+#define t6 $7
+#define t7 $8
+#define s0 $9
+#define s1 $10
+#define s2 $11
+#define s3 $12
+#define s4 $13
+#define s5 $14
+#define fp $15
+#define a0 $16
+#define a1 $17
+#define a2 $18
+#define a3 $19
+#define a4 $20
+#define a5 $21
+#define t8 $22
+#define t9 $23
+#define t10 $24
+#define t11 $25
+#define ra $26
+#define t12 $27 /* t12 and pv are both used for $27 */
+#define pv $27 /* t12 and pv are both used for $27 */
+#define at $28
+#define gp $29
+#define sp $30
+#define zero $31
+
+#endif /* _MACHINE_ASM_H */
diff --git a/usr/klibc/arch/alpha/MCONFIG b/usr/klibc/arch/alpha/MCONFIG
new file mode 100644
index 0000000..4420cdb
--- /dev/null
+++ b/usr/klibc/arch/alpha/MCONFIG
@@ -0,0 +1,16 @@
+# -*- makefile -*-
+#
+# arch/alpha/MCONFIG
+#
+# Build configuration for this architecture
+#
+
+KLIBCOPTFLAGS = -Os
+KLIBCBITSIZE = 64
+
+# 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
+# 7 GB - normal binaries start at 4.5 GB, and the stack is below
+# the binary.
+KLIBCSHAREDFLAGS = -Ttext 0x1c0000200
diff --git a/usr/klibc/arch/alpha/Makefile.inc b/usr/klibc/arch/alpha/Makefile.inc
new file mode 100644
index 0000000..9f51b7f
--- /dev/null
+++ b/usr/klibc/arch/alpha/Makefile.inc
@@ -0,0 +1,60 @@
+# -*- makefile -*-
+#
+# arch/alpha/Makefile.inc
+#
+# Special rules for this architecture. Note that this is actually
+# included from the main Makefile, and that pathnames should be
+# accordingly.
+#
+
+# Special CFLAGS for the divide code
+DIVCFLAGS = $(KLIBCREQFLAGS) $(KLIBCARCHREQFLAGS) \
+ -O3 -fomit-frame-pointer -fcall-saved-1 -fcall-saved-2 \
+ -fcall-saved-3 -fcall-saved-4 -fcall-saved-5 -fcall-saved-6 \
+ -fcall-saved-7 -fcall-saved-8 -ffixed-15 -fcall-saved-16 \
+ -fcall-saved-17 -fcall-saved-18 -fcall-saved-19 -fcall-saved-20 \
+ -fcall-saved-21 -fcall-saved-22 -ffixed-23 -fcall-saved-24 \
+ -ffixed-25 -ffixed-27
+
+KLIBCARCHOBJS := arch/$(KLIBCARCH)/pipe.o arch/$(KLIBCARCH)/setjmp.o
+KLIBCARCHOBJS += arch/$(KLIBCARCH)/syscall.o arch/$(KLIBCARCH)/sysdual.o
+
+DIVOBJS += arch/$(KLIBCARCH)/__divqu.o \
+ arch/$(KLIBCARCH)/__remqu.o \
+ arch/$(KLIBCARCH)/__divq.o \
+ arch/$(KLIBCARCH)/__remq.o \
+ arch/$(KLIBCARCH)/__divlu.o \
+ arch/$(KLIBCARCH)/__remlu.o \
+ arch/$(KLIBCARCH)/__divl.o \
+ arch/$(KLIBCARCH)/__reml.o
+
+KLIBCARCHOBJS += $(DIVOBJS)
+
+quiet_cmd_regswap = REGSWAP $@
+ cmd_regswap = sed -e 's/\$$0\b/$$27/g' -e 's/\$$24\b/$$99/g' \
+ -e 's/\$$16\b/$$24/g' -e 's/\$$17\b/$$25/g' \
+ -e 's/\$$26\b/$$23/g' -e 's/\$$99\b/$$16/g' < $< > $@
+
+# Use static pattern rule to avoid using a temporary file
+$(addprefix $(obj)/,$(DIVOBJS:.o=.S)): $(obj)/arch/$(KLIBCARCH)/%.S: \
+ $(obj)/arch/$(KLIBCARCH)/%.ss
+ $(call if_changed,regswap)
+
+quiet_cmd_genss = DIV-CC $@
+ cmd_genss = $(CC) $(DIVCFLAGS) $(FILE_CFLAGS) \
+ -DNAME=$(basename $(notdir $@)) -S -o $@ $<
+
+$(obj)/arch/$(KLIBCARCH)/%.ss: $(obj)/arch/$(KLIBCARCH)/divide.c
+ $(call if_changed,genss)
+
+$(obj)/arch/$(KLIBCARCH)/__divqu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=0 -DBITS=64
+$(obj)/arch/$(KLIBCARCH)/__remqu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=1 -DBITS=64
+$(obj)/arch/$(KLIBCARCH)/__divq.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=0 -DBITS=64
+$(obj)/arch/$(KLIBCARCH)/__remq.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=1 -DBITS=64
+$(obj)/arch/$(KLIBCARCH)/__divlu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=0 -DBITS=32
+$(obj)/arch/$(KLIBCARCH)/__remlu.ss: FILE_CFLAGS := -DSIGNED=0 -DREM=1 -DBITS=32
+$(obj)/arch/$(KLIBCARCH)/__divl.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=0 -DBITS=32
+$(obj)/arch/$(KLIBCARCH)/__reml.ss: FILE_CFLAGS := -DSIGNED=1 -DREM=1 -DBITS=32
+
+targets += $(DIVOBJS:.o=.S) $(DIVOBJS:.o=.ss)
+clean-files += $(DIVOBJS:.o=.S) $(DIVOBJS:.o=.ss)
diff --git a/usr/klibc/arch/alpha/README-gcc b/usr/klibc/arch/alpha/README-gcc
new file mode 100644
index 0000000..1d0052f
--- /dev/null
+++ b/usr/klibc/arch/alpha/README-gcc
@@ -0,0 +1,22 @@
+ The current Alpha chips don't provide hardware for integer
+ division. The C compiler expects the functions
+
+ __divqu: 64-bit unsigned long divide
+ __remqu: 64-bit unsigned long remainder
+ __divq/__remq: signed 64-bit
+ __divlu/__remlu: unsigned 32-bit
+ __divl/__reml: signed 32-bit
+
+ These are not normal C functions: instead of the normal calling
+ sequence, these expect their arguments in registers t10 and t11, and
+ return the result in t12 (aka pv). Register AT may be clobbered
+ (assembly temporary), anything else must be saved.
+
+ Furthermore, the return address is in t9 instead of ra.
+
+ Normal function Divide functions
+ --------------- ----------------
+ v0 ($0) t12/pv ($27)
+ a0 ($16) t10 ($24)
+ a1 ($17) t11 ($25)
+ ra ($26) t9 ($23)
diff --git a/usr/klibc/arch/alpha/crt0.S b/usr/klibc/arch/alpha/crt0.S
new file mode 100644
index 0000000..5e2babb
--- /dev/null
+++ b/usr/klibc/arch/alpha/crt0.S
@@ -0,0 +1,22 @@
+#
+# arch/alpha/crt0.S
+#
+
+ .text
+ .type _start,@function
+ .ent _start, 0
+ .globl _start
+_start:
+ .frame $30, 0, $26, 0
+ mov $31, $15
+ br $29, 1f
+1: ldgp $29, 0($29)
+ .prologue 0
+
+ lda $16, 0($30) # ELF data structure
+ lda $17, 0($0) # atexit pointer
+
+ jsr $26, __libc_init
+
+ .size _start,.-_start
+ .end _start
diff --git a/usr/klibc/arch/alpha/divide.c b/usr/klibc/arch/alpha/divide.c
new file mode 100644
index 0000000..c44254f
--- /dev/null
+++ b/usr/klibc/arch/alpha/divide.c
@@ -0,0 +1,59 @@
+#include <stdint.h>
+#include <asm/gentrap.h>
+#include <asm/pal.h>
+
+#if BITS == 64
+typedef uint64_t uint;
+typedef int64_t sint;
+#else
+typedef uint32_t uint;
+typedef int32_t sint;
+#endif
+
+#ifdef SIGNED
+typedef sint xint;
+#else
+typedef uint xint;
+#endif
+
+xint NAME(uint num, uint den)
+{
+ uint quot = 0, qbit = 1;
+ int minus = 0;
+ xint v;
+
+ if (den == 0) {
+ /* This is really $16, but $16 and $24 are exchanged by a script */
+ register unsigned long cause asm("$24") = GEN_INTDIV;
+ asm volatile ("call_pal %0"::"i" (PAL_gentrap), "r"(cause));
+ return 0; /* If trap returns... */
+ }
+#if SIGNED
+ if ((sint) (num ^ den) < 0)
+ minus = 1;
+ if ((sint) num < 0)
+ num = -num;
+ if ((sint) den < 0)
+ den = -den;
+#endif
+
+ /* Left-justify denominator and count shift */
+ while ((sint) den >= 0) {
+ den <<= 1;
+ qbit <<= 1;
+ }
+
+ while (qbit) {
+ if (den <= num) {
+ num -= den;
+ quot += qbit;
+ }
+ den >>= 1;
+ qbit >>= 1;
+ }
+
+ v = (xint) (REM ? num : quot);
+ if (minus)
+ v = -v;
+ return v;
+}
diff --git a/usr/klibc/arch/alpha/pipe.S b/usr/klibc/arch/alpha/pipe.S
new file mode 100644
index 0000000..ee72413
--- /dev/null
+++ b/usr/klibc/arch/alpha/pipe.S
@@ -0,0 +1,38 @@
+#
+# arch/alpha/pipe.S
+#
+
+#
+# pipe() on alpha returns both file descriptors in registers --
+# $0 (v0) and $20 (a4) respectively. This is unlike any other system call,
+# as far as I can tell.
+#
+
+#include <asm/unistd.h>
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type pipe, @function
+ .ent pipe, 0
+ .globl pipe
+pipe:
+ .frame sp,0,ra,0
+ lda v0, __NR_pipe
+ callsys
+ beq a3, 1f
+ br pv, 2f # pv <- pc
+2:
+ ldgp gp, 0(pv)
+ lda a1, errno
+ lda v0, -1(zero)
+ stl a3, 0(a1)
+ ret zero,(ra),1
+1:
+ stl v0, 0(a0)
+ lda v0, 0
+ stl a4, 4(a0)
+ ret zero,(ra),1
+
+ .size pipe,.-pipe
+ .end pipe
diff --git a/usr/klibc/arch/alpha/setjmp.S b/usr/klibc/arch/alpha/setjmp.S
new file mode 100644
index 0000000..ed604bd
--- /dev/null
+++ b/usr/klibc/arch/alpha/setjmp.S
@@ -0,0 +1,75 @@
+#
+# setjmp.S
+#
+
+#
+# The jmp_buf looks like:
+#
+# s0..5
+# fp
+# ra
+# gp
+# sp
+#
+
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type setjmp,@function
+ .ent setjmp, 0
+ .globl setjmp
+setjmp:
+ lda v0, 0(zero)
+ stq s0, 0(a0)
+ stq s1, 8(a0)
+ stq s2, 16(a0)
+ stq s3, 24(a0)
+ stq s4, 32(a0)
+ stq s5, 40(a0)
+ stq fp, 48(a0)
+ stq ra, 56(a0)
+ stq gp, 64(a0)
+ stq sp, 72(a0)
+ stt $f2, 80(a0)
+ stt $f3, 88(a0)
+ stt $f4, 96(a0)
+ stt $f5, 104(a0)
+ stt $f6, 112(a0)
+ stt $f7, 120(a0)
+ stt $f8, 128(a0)
+ stt $f9, 136(a0)
+ ret zero,(ra),1
+
+ .size setjmp,.-setjmp
+ .end setjmp
+
+ .type longjmp,@function
+ .ent longjmp, 0
+ .globl longjmp
+longjmp:
+ mov a1, v0
+ ldq s0, 0(a0)
+ ldq s1, 8(a0)
+ ldq s2, 16(a0)
+ ldq s3, 24(a0)
+ ldq s4, 32(a0)
+ ldq s5, 40(a0)
+ ldq fp, 48(a0)
+ ldq ra, 56(a0)
+ ldq gp, 64(a0)
+ ldq sp, 72(a0)
+ ldt $f2, 80(a0)
+ ldt $f3, 88(a0)
+ ldt $f4, 96(a0)
+ ldt $f5, 104(a0)
+ ldt $f6, 112(a0)
+ ldt $f7, 120(a0)
+ ldt $f8, 128(a0)
+ ldt $f9, 136(a0)
+ /* We're bound to get a mispredict here, but at least give us
+ a chance to get the return stack back in sync... */
+ ret zero,(ra),1
+
+ .size longjmp,.-longjmp
+ .end longjmp
diff --git a/usr/klibc/arch/alpha/syscall.S b/usr/klibc/arch/alpha/syscall.S
new file mode 100644
index 0000000..ae69ef2
--- /dev/null
+++ b/usr/klibc/arch/alpha/syscall.S
@@ -0,0 +1,26 @@
+#
+# arch/alpha/syscall.S
+#
+
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type __syscall_common,@function
+ .ent __syscall_common, 0
+ .globl __syscall_common
+__syscall_common:
+ .frame sp,0,ra,0
+ callsys
+ beq a3, 1f
+ br pv, 2f # pv <- pc
+2:
+ ldgp gp, 0(pv)
+ lda a1, errno
+ stl v0, 0(a1)
+ lda v0, -1(zero)
+1:
+ ret zero,(ra),1
+
+ .size __syscall_common,.-__syscall_common
+ .end __syscall_common
diff --git a/usr/klibc/arch/alpha/sysdual.S b/usr/klibc/arch/alpha/sysdual.S
new file mode 100644
index 0000000..1719e37
--- /dev/null
+++ b/usr/klibc/arch/alpha/sysdual.S
@@ -0,0 +1,33 @@
+#
+# arch/alpha/sysdual.S
+#
+
+#
+# Some system calls have an alternate return value in r20 (a4).
+# This system call stub is for system calls where that is
+# the "real" return value.
+#
+
+#include <machine/asm.h>
+
+ .text
+ .align 3
+ .type __syscall_dual1,@function
+ .ent __syscall_dual1, 0
+ .globl __syscall_dual1
+__syscall_dual1:
+ .frame sp,0,ra,0
+ callsys
+ mov v0, a4
+ beq a3, 1f
+ br pv, 2f # pv <- pc
+2:
+ ldgp gp, 0(pv)
+ lda a1, errno
+ lda v0, -1(zero)
+ stl a3, 0(a1)
+1:
+ ret zero,(ra),1
+
+ .size __syscall_dual1,.-__syscall_dual1
+ .end __syscall_dual1
diff --git a/usr/klibc/arch/alpha/sysstub.ph b/usr/klibc/arch/alpha/sysstub.ph
new file mode 100644
index 0000000..08b97e8
--- /dev/null
+++ b/usr/klibc/arch/alpha/sysstub.ph
@@ -0,0 +1,37 @@
+# -*- perl -*-
+#
+# arch/alpha/sysstub.ph
+#
+# Script to generate system call stubs
+#
+
+# On Alpha, most system calls follow the standard convention, with the
+# system call number in r0 (v0), return an error value in r19 (a3) as
+# well as the return value in r0 (v0).
+#
+# A few system calls are dual-return with the second return value in
+# r20 (a4).
+
+sub make_sysstub($$$$$@) {
+ my($outputdir, $fname, $type, $sname, $stype, @args) = @_;
+
+ $stype = $stype || 'common';
+ $stype = 'common' if ( $stype eq 'dual0' );
+
+ open(OUT, '>', "${outputdir}/${fname}.S");
+ print OUT "#include <asm/unistd.h>\n";
+ print OUT "#include <machine/asm.h>\n";
+ print OUT "\n";
+ print OUT "\t.text\n";
+ print OUT "\t.type ${fname},\@function\n";
+ print OUT "\t.ent\t${fname}, 0\n"; # What is this?
+ print OUT "\t.globl ${fname}\n";
+ print OUT "${fname}:\n";
+ print OUT "\tlda\tv0, __NR_${sname}(zero)\n";
+ print OUT "\tbr __syscall_${stype}\n";
+ print OUT "\t.size\t${fname},.-${fname}\n";
+ print OUT "\t.end\t${fname}\n";
+ close(OUT);
+}
+
+1;