code:
// SPDX-License-Identifier: GPL-2.0
#include <linux/termios_internal.h>

int user_termio_to_kernel_termios(struct ktermios *termios,
						struct termio __user *termio)
{
	struct termio v;
	bool canon;

	if (copy_from_user(&v, termio, sizeof(struct termio)))
		return -EFAULT;

	termios->c_iflag = (0xffff0000 & termios->c_iflag) | v.c_iflag;
	termios->c_oflag = (0xffff0000 & termios->c_oflag) | v.c_oflag;
	termios->c_cflag = (0xffff0000 & termios->c_cflag) | v.c_cflag;
	termios->c_lflag = (0xffff0000 & termios->c_lflag) | v.c_lflag;
	termios->c_line = (0xffff0000 & termios->c_lflag) | v.c_line;

	canon = v.c_lflag & ICANON;
	termios->c_cc[VINTR]  = v.c_cc[_VINTR];
	termios->c_cc[VQUIT]  = v.c_cc[_VQUIT];
	termios->c_cc[VERASE] = v.c_cc[_VERASE];
	termios->c_cc[VKILL]  = v.c_cc[_VKILL];
	termios->c_cc[VEOL2]  = v.c_cc[_VEOL2];
	termios->c_cc[VSWTC]  = v.c_cc[_VSWTC];
	termios->c_cc[canon ? VEOF : VMIN]  = v.c_cc[_VEOF];
	termios->c_cc[canon ? VEOL : VTIME] = v.c_cc[_VEOL];

	return 0;
}

int kernel_termios_to_user_termio(struct termio __user *termio,
						struct ktermios *termios)
{
	struct termio v;
	bool canon;

	memset(&v, 0, sizeof(struct termio));
	v.c_iflag = termios->c_iflag;
	v.c_oflag = termios->c_oflag;
	v.c_cflag = termios->c_cflag;
	v.c_lflag = termios->c_lflag;
	v.c_line = termios->c_line;

	canon = v.c_lflag & ICANON;
	v.c_cc[_VINTR]  = termios->c_cc[VINTR];
	v.c_cc[_VQUIT]  = termios->c_cc[VQUIT];
	v.c_cc[_VERASE] = termios->c_cc[VERASE];
	v.c_cc[_VKILL]  = termios->c_cc[VKILL];
	v.c_cc[_VEOF]   = termios->c_cc[canon ? VEOF : VMIN];
	v.c_cc[_VEOL]   = termios->c_cc[canon ? VEOL : VTIME];
	v.c_cc[_VEOL2]  = termios->c_cc[VEOL2];
	v.c_cc[_VSWTC]  = termios->c_cc[VSWTC];

	return copy_to_user(termio, &v, sizeof(struct termio));
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *  linux/arch/alpha/kernel/time.c
 *
 *  Copyright (C) 1991, 1992, 1995, 1999, 2000  Linus Torvalds
 *
 * This file contains the clocksource time handling.
 * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
 *		"A Kernel Model for Precision Timekeeping" by Dave Mills
 * 1997-01-09    Adrian Sun
 *      use interval timer if CONFIG_RTC=y
 * 1997-10-29    John Bowman (bowman@math.ualberta.ca)
 *      fixed tick loss calculation in timer_interrupt
 *      (round system clock to nearest tick instead of truncating)
 *      fixed algorithm in time_init for getting time from CMOS clock
 * 1999-04-16	Thorsten Kranzkowski (dl8bcu@gmx.net)
 *	fixed algorithm in do_gettimeofday() for calculating the precise time
 *	from processor cycle counter (now taking lost_ticks into account)
 * 2003-06-03	R. Scott Bailey <scott.bailey@eds.com>
 *	Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM
 */
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/bcd.h>
#include <linux/profile.h>
#include <linux/irq_work.h>

#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/hwrpb.h>

#include <linux/mc146818rtc.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>

#include "proto.h"
#include "irq_impl.h"

DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);

unsigned long est_cycle_freq;

#ifdef CONFIG_IRQ_WORK

DEFINE_PER_CPU(u8, irq_work_pending);

#define set_irq_work_pending_flag()  __this_cpu_write(irq_work_pending, 1)
#define test_irq_work_pending()      __this_cpu_read(irq_work_pending)
#define clear_irq_work_pending()     __this_cpu_write(irq_work_pending, 0)

void arch_irq_work_raise(void)
{
	set_irq_work_pending_flag();
}

#else  /* CONFIG_IRQ_WORK */

#define test_irq_work_pending()      0
#define clear_irq_work_pending()

#endif /* CONFIG_IRQ_WORK */

static inline __u32 rpcc(void)
{
	return __builtin_alpha_rpcc();
}

/*
 * The RTC as a clock_event_device primitive.
 */

static DEFINE_PER_CPU(struct clock_event_device, cpu_ce);

irqreturn_t
rtc_timer_interrupt(int irq, void *dev)
{
	int cpu = smp_processor_id();
	struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);

	/* Don't run the hook for UNUSED or SHUTDOWN.  */
	if (likely(clockevent_state_periodic(ce)))
		ce->event_handler(ce);

	if (test_irq_work_pending()) {
		clear_irq_work_pending();
		irq_work_run();
	}

	return IRQ_HANDLED;
}

static int
rtc_ce_set_next_event(unsigned long evt, struct clock_event_device *ce)
{
	/* This hook is for oneshot mode, which we don't support.  */
	return -EINVAL;
}

static void __init
init_rtc_clockevent(void)
{
	int cpu = smp_processor_id();
	struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);

	*ce = (struct clock_event_device){
		.name = "rtc",
		.features = CLOCK_EVT_FEAT_PERIODIC,
		.rating = 100,
		.cpumask = cpumask_of(cpu),
		.set_next_event = rtc_ce_set_next_event,
	};

	clockevents_config_and_register(ce, CONFIG_HZ, 0, 0);
}

/*
 * The QEMU clock as a clocksource primitive.
 */

static u64
qemu_cs_read(struct clocksource *cs)
{
	return qemu_get_vmtime();
}

static struct clocksource qemu_cs = {
	.name                   = "qemu",
	.rating                 = 400,
	.read                   = qemu_cs_read,
	.mask                   = CLOCKSOURCE_MASK(64),
	.flags                  = CLOCK_SOURCE_IS_CONTINUOUS,
	.max_idle_ns		= LONG_MAX
};

/*
 * The QEMU alarm as a clock_event_device primitive.
 */

static int qemu_ce_shutdown(struct clock_event_device *ce)
{
	/* The mode member of CE is updated for us in generic code.
	   Just make sure that the event is disabled.  */
	qemu_set_alarm_abs(0);
	return 0;
}

static int
qemu_ce_set_next_event(unsigned long evt, struct clock_event_device *ce)
{
	qemu_set_alarm_rel(evt);
	return 0;
}

static irqreturn_t
qemu_timer_interrupt(int irq, void *dev)
{
	int cpu = smp_processor_id();
	struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);

	ce->event_handler(ce);
	return IRQ_HANDLED;
}

static void __init
init_qemu_clockevent(void)
{
	int cpu = smp_processor_id();
	struct clock_event_device *ce = &per_cpu(cpu_ce, cpu);

	*ce = (struct clock_event_device){
		.name = "qemu",
		.features = CLOCK_EVT_FEAT_ONESHOT,
		.rating = 400,
		.cpumask = cpumask_of(cpu),
		.set_state_shutdown = qemu_ce_shutdown,
		.set_state_oneshot = qemu_ce_shutdown,
		.tick_resume = qemu_ce_shutdown,
		.set_next_event = qemu_ce_set_next_event,
	};

	clockevents_config_and_register(ce, NSEC_PER_SEC, 1000, LONG_MAX);
}

void __init
common_init_rtc(void)
{
	unsigned char x, sel = 0;

	/* Reset periodic interrupt frequency.  */
#if CONFIG_HZ == 1024 || CONFIG_HZ == 1200
 	x = CMOS_READ(RTC_FREQ_SELECT) & 0x3f;
	/* Test includes known working values on various platforms
	   where 0x26 is wrong; we refuse to change those. */
 	if (x != 0x26 && x != 0x25 && x != 0x19 && x != 0x06) {
		sel = RTC_REF_CLCK_32KHZ + 6;
	}
#elif CONFIG_HZ == 256 || CONFIG_HZ == 128 || CONFIG_HZ == 64 || CONFIG_HZ == 32
	sel = RTC_REF_CLCK_32KHZ + __builtin_ffs(32768 / CONFIG_HZ);
#else
# error "Unknown HZ from arch/alpha/Kconfig"
#endif
	if (sel) {
		printk(KERN_INFO "Setting RTC_FREQ to %d Hz (%x)\n",
		       CONFIG_HZ, sel);
		CMOS_WRITE(sel, RTC_FREQ_SELECT);
 	}

	/* Turn on periodic interrupts.  */
	x = CMOS_READ(RTC_CONTROL);
	if (!(x & RTC_PIE)) {
		printk("Turning on RTC interrupts.\n");
		x |= RTC_PIE;
		x &= ~(RTC_AIE | RTC_UIE);
		CMOS_WRITE(x, RTC_CONTROL);
	}
	(void) CMOS_READ(RTC_INTR_FLAGS);

	outb(0x36, 0x43);	/* pit counter 0: system timer */
	outb(0x00, 0x40);
	outb(0x00, 0x40);

	outb(0xb6, 0x43);	/* pit counter 2: speaker */
	outb(0x31, 0x42);
	outb(0x13, 0x42);

	init_rtc_irq(NULL);
}

#ifndef CONFIG_ALPHA_WTINT
/*
 * The RPCC as a clocksource primitive.
 *
 * While we have free-running timecounters running on all CPUs, and we make
 * a half-hearted attempt in init_rtc_rpcc_info to sync the timecounter
 * with the wall clock, that initialization isn't kept up-to-date across
 * different time counters in SMP mode.  Therefore we can only use this
 * method when there's only one CPU enabled.
 *
 * When using the WTINT PALcall, the RPCC may shift to a lower frequency,
 * or stop altogether, while waiting for the interrupt.  Therefore we cannot
 * use this method when WTINT is in use.
 */

static u64 read_rpcc(struct clocksource *cs)
{
	return rpcc();
}

static struct clocksource clocksource_rpcc = {
	.name                   = "rpcc",
	.rating                 = 300,
	.read                   = read_rpcc,
	.mask                   = CLOCKSOURCE_MASK(32),
	.flags                  = CLOCK_SOURCE_IS_CONTINUOUS
};
#endif /* ALPHA_WTINT */

/* Validate a computed cycle counter result against the known bounds for
   the given processor core.  There's too much brokenness in the way of
   timing hardware for any one method to work everywhere.  :-(

   Return 0 if the result cannot be trusted, otherwise return the argument.  */

static unsigned long __init
validate_cc_value(unsigned long cc)
{
	static struct bounds {
		unsigned int min, max;
	} cpu_hz[] __initdata = {
		[EV3_CPU]    = {   50000000,  200000000 },	/* guess */
		[EV4_CPU]    = {  100000000,  300000000 },
		[LCA4_CPU]   = {  100000000,  300000000 },	/* guess */
		[EV45_CPU]   = {  200000000,  300000000 },
		[EV5_CPU]    = {  250000000,  433000000 },
		[EV56_CPU]   = {  333000000,  667000000 },
		[PCA56_CPU]  = {  400000000,  600000000 },	/* guess */
		[PCA57_CPU]  = {  500000000,  600000000 },	/* guess */
		[EV6_CPU]    = {  466000000,  600000000 },
		[EV67_CPU]   = {  600000000,  750000000 },
		[EV68AL_CPU] = {  750000000,  940000000 },
		[EV68CB_CPU] = { 1000000000, 1333333333 },
		/* None of the following are shipping as of 2001-11-01.  */
		[EV68CX_CPU] = { 1000000000, 1700000000 },	/* guess */
		[EV69_CPU]   = { 1000000000, 1700000000 },	/* guess */
		[EV7_CPU]    = {  800000000, 1400000000 },	/* guess */
		[EV79_CPU]   = { 1000000000, 2000000000 },	/* guess */
	};

	/* Allow for some drift in the crystal.  10MHz is more than enough.  */
	const unsigned int deviation = 10000000;

	struct percpu_struct *cpu;
	unsigned int index;

	cpu = (struct percpu_struct *)((char*)hwrpb + hwrpb->processor_offset);
	index = cpu->type & 0xffffffff;

	/* If index out of bounds, no way to validate.  */
	if (index >= ARRAY_SIZE(cpu_hz))
		return cc;

	/* If index contains no data, no way to validate.  */
	if (cpu_hz[index].max == 0)
		return cc;

	if (cc < cpu_hz[index].min - deviation
	    || cc > cpu_hz[index].max + deviation)
		return 0;

	return cc;
}

/*
 * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
 * arch/i386/time.c.
 */

#define CALIBRATE_LATCH	0xffff
#define TIMEOUT_COUNT	0x100000

static unsigned long __init
calibrate_cc_with_pit(void)
{
	int cc, count = 0;

	/* Set the Gate high, disable speaker */
	outb((inb(0x61) & ~0x02) | 0x01, 0x61);

	/*
	 * Now let's take care of CTC channel 2
	 *
	 * Set the Gate high, program CTC channel 2 for mode 0,
	 * (interrupt on terminal count mode), binary count,
	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
	 */
	outb(0xb0, 0x43);		/* binary, mode 0, LSB/MSB, Ch 2 */
	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */

	cc = rpcc();
	do {
		count++;
	} while ((inb(0x61) & 0x20) == 0 && count < TIMEOUT_COUNT);
	cc = rpcc() - cc;

	/* Error: ECTCNEVERSET or ECPUTOOFAST.  */
	if (count <= 1 || count == TIMEOUT_COUNT)
		return 0;

	return ((long)cc * PIT_TICK_RATE) / (CALIBRATE_LATCH + 1);
}

/* The Linux interpretation of the CMOS clock register contents:
   When the Update-In-Progress (UIP) flag goes from 1 to 0, the
   RTC registers show the second which has precisely just started.
   Let's hope other operating systems interpret the RTC the same way.  */

static unsigned long __init
rpcc_after_update_in_progress(void)
{
	do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
	do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);

	return rpcc();
}

void __init
time_init(void)
{
	unsigned int cc1, cc2;
	unsigned long cycle_freq, tolerance;
	long diff;

	if (alpha_using_qemu) {
		clocksource_register_hz(&qemu_cs, NSEC_PER_SEC);
		init_qemu_clockevent();
		init_rtc_irq(qemu_timer_interrupt);
		return;
	}

	/* Calibrate CPU clock -- attempt #1.  */
	if (!est_cycle_freq)
		est_cycle_freq = validate_cc_value(calibrate_cc_with_pit());

	cc1 = rpcc();

	/* Calibrate CPU clock -- attempt #2.  */
	if (!est_cycle_freq) {
		cc1 = rpcc_after_update_in_progress();
		cc2 = rpcc_after_update_in_progress();
		est_cycle_freq = validate_cc_value(cc2 - cc1);
		cc1 = cc2;
	}

	cycle_freq = hwrpb->cycle_freq;
	if (est_cycle_freq) {
		/* If the given value is within 250 PPM of what we calculated,
		   accept it.  Otherwise, use what we found.  */
		tolerance = cycle_freq / 4000;
		diff = cycle_freq - est_cycle_freq;
		if (diff < 0)
			diff = -diff;
		if ((unsigned long)diff > tolerance) {
			cycle_freq = est_cycle_freq;
			printk("HWRPB cycle frequency bogus.  "
			       "Estimated %lu Hz\n", cycle_freq);
		} else {
			est_cycle_freq = 0;
		}
	} else if (! validate_cc_value (cycle_freq)) {
		printk("HWRPB cycle frequency bogus, "
		       "and unable to estimate a proper value!\n");
	}

	/* See above for restrictions on using clocksource_rpcc.  */
#ifndef CONFIG_ALPHA_WTINT
	if (hwrpb->nr_processors == 1)
		clocksource_register_hz(&clocksource_rpcc, cycle_freq);
#endif

	/* Startup the timer source. */
	alpha_mv.init_rtc();
	init_rtc_clockevent();
}

/* Initialize the clock_event_device for secondary cpus.  */
#ifdef CONFIG_SMP
void __init
init_clockevent(void)
{
	if (alpha_using_qemu)
		init_qemu_clockevent();
	else
		init_rtc_clockevent();
}
#endif

repo_name: angery/linux


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * arch/alpha/kernel/traps.c
 *
 * (C) Copyright 1994 Linus Torvalds
 */

/*
 * This file initializes the trap entry points
 */

#include <linux/jiffies.h>
#include <linux/mm.h>
#include <linux/sched/signal.h>
#include <linux/sched/debug.h>
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/extable.h>
#include <linux/kallsyms.h>
#include <linux/ratelimit.h>

#include <asm/gentrap.h>
#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include <asm/sysinfo.h>
#include <asm/hwrpb.h>
#include <asm/mmu_context.h>
#include <asm/special_insns.h>

#include "proto.h"

/* Work-around for some SRMs which mishandle opDEC faults.  */

static int opDEC_fix;

static void
opDEC_check(void)
{
	__asm__ __volatile__ (
	/* Load the address of... */
	"	br	$16, 1f\n"
	/* A stub instruction fault handler.  Just add 4 to the
	   pc and continue.  */
	"	ldq	$16, 8($sp)\n"
	"	addq	$16, 4, $16\n"
	"	stq	$16, 8($sp)\n"
	"	call_pal %[rti]\n"
	/* Install the instruction fault handler.  */
	"1:	lda	$17, 3\n"
	"	call_pal %[wrent]\n"
	/* With that in place, the fault from the round-to-minf fp
	   insn will arrive either at the "lda 4" insn (bad) or one
	   past that (good).  This places the correct fixup in %0.  */
	"	lda %[fix], 0\n"
	"	cvttq/svm $f31,$f31\n"
	"	lda %[fix], 4"
	: [fix] "=r" (opDEC_fix)
	: [rti] "n" (PAL_rti), [wrent] "n" (PAL_wrent)
	: "$0", "$1", "$16", "$17", "$22", "$23", "$24", "$25");

	if (opDEC_fix)
		printk("opDEC fixup enabled.\n");
}

void
dik_show_regs(struct pt_regs *regs, unsigned long *r9_15)
{
	printk("pc = [<%016lx>]  ra = [<%016lx>]  ps = %04lx    %s\n",
	       regs->pc, regs->r26, regs->ps, print_tainted());
	printk("pc is at %pSR\n", (void *)regs->pc);
	printk("ra is at %pSR\n", (void *)regs->r26);
	printk("v0 = %016lx  t0 = %016lx  t1 = %016lx\n",
	       regs->r0, regs->r1, regs->r2);
	printk("t2 = %016lx  t3 = %016lx  t4 = %016lx\n",
 	       regs->r3, regs->r4, regs->r5);
	printk("t5 = %016lx  t6 = %016lx  t7 = %016lx\n",
	       regs->r6, regs->r7, regs->r8);

	if (r9_15) {
		printk("s0 = %016lx  s1 = %016lx  s2 = %016lx\n",
		       r9_15[9], r9_15[10], r9_15[11]);
		printk("s3 = %016lx  s4 = %016lx  s5 = %016lx\n",
		       r9_15[12], r9_15[13], r9_15[14]);
		printk("s6 = %016lx\n", r9_15[15]);
	}

	printk("a0 = %016lx  a1 = %016lx  a2 = %016lx\n",
	       regs->r16, regs->r17, regs->r18);
	printk("a3 = %016lx  a4 = %016lx  a5 = %016lx\n",
 	       regs->r19, regs->r20, regs->r21);
 	printk("t8 = %016lx  t9 = %016lx  t10= %016lx\n",
	       regs->r22, regs->r23, regs->r24);
	printk("t11= %016lx  pv = %016lx  at = %016lx\n",
	       regs->r25, regs->r27, regs->r28);
	printk("gp = %016lx  sp = %p\n", regs->gp, regs+1);
#if 0
__halt();
#endif
}

#if 0
static char * ireg_name[] = {"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
			   "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6",
			   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
			   "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"};
#endif

static void
dik_show_code(unsigned int *pc)
{
	long i;

	printk("Code:");
	for (i = -6; i < 2; i++) {
		unsigned int insn;
		if (__get_user(insn, (unsigned int __user *)pc + i))
			break;
		printk("%c%08x%c", i ? ' ' : '<', insn, i ? ' ' : '>');
	}
	printk("\n");
}

static void
dik_show_trace(unsigned long *sp, const char *loglvl)
{
	long i = 0;
	printk("%sTrace:\n", loglvl);
	while (0x1ff8 & (unsigned long) sp) {
		extern char _stext[], _etext[];
		unsigned long tmp = *sp;
		sp++;
		if (!is_kernel_text(tmp))
			continue;
		printk("%s[<%lx>] %pSR\n", loglvl, tmp, (void *)tmp);
		if (i > 40) {
			printk("%s ...", loglvl);
			break;
		}
	}
	printk("%s\n", loglvl);
}

static int kstack_depth_to_print = 24;

void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
{
	unsigned long *stack;
	int i;

	/*
	 * debugging aid: "show_stack(NULL, NULL, KERN_EMERG);" prints the
	 * back trace for this cpu.
	 */
	if(sp==NULL)
		sp=(unsigned long*)&sp;

	stack = sp;
	for(i=0; i < kstack_depth_to_print; i++) {
		if (((long) stack & (THREAD_SIZE-1)) == 0)
			break;
		if ((i % 4) == 0) {
			if (i)
				pr_cont("\n");
			printk("%s       ", loglvl);
		} else {
			pr_cont(" ");
		}
		pr_cont("%016lx", *stack++);
	}
	pr_cont("\n");
	dik_show_trace(sp, loglvl);
}

void
die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
{
	if (regs->ps & 8)
		return;
#ifdef CONFIG_SMP
	printk("CPU %d ", hard_smp_processor_id());
#endif
	printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err);
	dik_show_regs(regs, r9_15);
	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
	dik_show_trace((unsigned long *)(regs+1), KERN_DEFAULT);
	dik_show_code((unsigned int *)regs->pc);

	if (test_and_set_thread_flag (TIF_DIE_IF_KERNEL)) {
		printk("die_if_kernel recursion detected.\n");
		local_irq_enable();
		while (1);
	}
	make_task_dead(SIGSEGV);
}

#ifndef CONFIG_MATHEMU
static long dummy_emul(void) { return 0; }
long (*alpha_fp_emul_imprecise)(struct pt_regs *regs, unsigned long writemask)
  = (void *)dummy_emul;
EXPORT_SYMBOL_GPL(alpha_fp_emul_imprecise);
long (*alpha_fp_emul) (unsigned long pc)
  = (void *)dummy_emul;
EXPORT_SYMBOL_GPL(alpha_fp_emul);
#else
long alpha_fp_emul_imprecise(struct pt_regs *regs, unsigned long writemask);
long alpha_fp_emul (unsigned long pc);
#endif

asmlinkage void
do_entArith(unsigned long summary, unsigned long write_mask,
	    struct pt_regs *regs)
{
	long si_code = FPE_FLTINV;

	if (summary & 1) {
		/* Software-completion summary bit is set, so try to
		   emulate the instruction.  If the processor supports
		   precise exceptions, we don't have to search.  */
		if (!amask(AMASK_PRECISE_TRAP))
			si_code = alpha_fp_emul(regs->pc - 4);
		else
			si_code = alpha_fp_emul_imprecise(regs, write_mask);
		if (si_code == 0)
			return;
	}
	die_if_kernel("Arithmetic fault", regs, 0, NULL);

	send_sig_fault_trapno(SIGFPE, si_code, (void __user *) regs->pc, 0, current);
}

asmlinkage void
do_entIF(unsigned long type, struct pt_regs *regs)
{
	int signo, code;

	if ((regs->ps & ~IPL_MAX) == 0) {
		if (type == 1) {
			const unsigned int *data
			  = (const unsigned int *) regs->pc;
			printk("Kernel bug at %s:%d\n",
			       (const char *)(data[1] | (long)data[2] << 32),
			       data[0]);
		}
#ifdef CONFIG_ALPHA_WTINT
		if (type == 4) {
			/* If CALL_PAL WTINT is totally unsupported by the
			   PALcode, e.g. MILO, "emulate" it by overwriting
			   the insn.  */
			unsigned int *pinsn
			  = (unsigned int *) regs->pc - 1;
			if (*pinsn == PAL_wtint) {
				*pinsn = 0x47e01400; /* mov 0,$0 */
				imb();
				regs->r0 = 0;
				return;
			}
		}
#endif /* ALPHA_WTINT */
		die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
			      regs, type, NULL);
	}

	switch (type) {
	      case 0: /* breakpoint */
		if (ptrace_cancel_bpt(current)) {
			regs->pc -= 4;	/* make pc point to former bpt */
		}

		send_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc,
			       current);
		return;

	      case 1: /* bugcheck */
		send_sig_fault_trapno(SIGTRAP, TRAP_UNK,
				      (void __user *) regs->pc, 0, current);
		return;

	      case 2: /* gentrap */
		switch ((long) regs->r16) {
		case GEN_INTOVF:
			signo = SIGFPE;
			code = FPE_INTOVF;
			break;
		case GEN_INTDIV:
			signo = SIGFPE;
			code = FPE_INTDIV;
			break;
		case GEN_FLTOVF:
			signo = SIGFPE;
			code = FPE_FLTOVF;
			break;
		case GEN_FLTDIV:
			signo = SIGFPE;
			code = FPE_FLTDIV;
			break;
		case GEN_FLTUND:
			signo = SIGFPE;
			code = FPE_FLTUND;
			break;
		case GEN_FLTINV:
			signo = SIGFPE;
			code = FPE_FLTINV;
			break;
		case GEN_FLTINE:
			signo = SIGFPE;
			code = FPE_FLTRES;
			break;
		case GEN_ROPRAND:
			signo = SIGFPE;
			code = FPE_FLTUNK;
			break;

		case GEN_DECOVF:
		case GEN_DECDIV:
		case GEN_DECINV:
		case GEN_ASSERTERR:
		case GEN_NULPTRERR:
		case GEN_STKOVF:
		case GEN_STRLENERR:
		case GEN_SUBSTRERR:
		case GEN_RANGERR:
		case GEN_SUBRNG:
		case GEN_SUBRNG1:
		case GEN_SUBRNG2:
		case GEN_SUBRNG3:
		case GEN_SUBRNG4:
		case GEN_SUBRNG5:
		case GEN_SUBRNG6:
		case GEN_SUBRNG7:
		default:
			signo = SIGTRAP;
			code = TRAP_UNK;
			break;
		}

		send_sig_fault_trapno(signo, code, (void __user *) regs->pc,
				      regs->r16, current);
		return;

	      case 4: /* opDEC */
		if (implver() == IMPLVER_EV4) {
			long si_code;

			/* The some versions of SRM do not handle
			   the opDEC properly - they return the PC of the
			   opDEC fault, not the instruction after as the
			   Alpha architecture requires.  Here we fix it up.
			   We do this by intentionally causing an opDEC
			   fault during the boot sequence and testing if
			   we get the correct PC.  If not, we set a flag
			   to correct it every time through.  */
			regs->pc += opDEC_fix;

			/* EV4 does not implement anything except normal
			   rounding.  Everything else will come here as
			   an illegal instruction.  Emulate them.  */
			si_code = alpha_fp_emul(regs->pc - 4);
			if (si_code == 0)
				return;
			if (si_code > 0) {
				send_sig_fault_trapno(SIGFPE, si_code,
						      (void __user *) regs->pc,
						      0, current);
				return;
			}
		}
		break;

	      case 3: /* FEN fault */
		/* Irritating users can call PAL_clrfen to disable the
		   FPU for the process.  The kernel will then trap in
		   do_switch_stack and undo_switch_stack when we try
		   to save and restore the FP registers.

		   Given that GCC by default generates code that uses the
		   FP registers, PAL_clrfen is not useful except for DoS
		   attacks.  So turn the bleeding FPU back on and be done
		   with it.  */
		current_thread_info()->pcb.flags |= 1;
		__reload_thread(&current_thread_info()->pcb);
		return;

	      case 5: /* illoc */
	      default: /* unexpected instruction-fault type */
		      ;
	}

	send_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)regs->pc, current);
}

/* There is an ifdef in the PALcode in MILO that enables a
   "kernel debugging entry point" as an unprivileged call_pal.

   We don't want to have anything to do with it, but unfortunately
   several versions of MILO included in distributions have it enabled,
   and if we don't put something on the entry point we'll oops.  */

asmlinkage void
do_entDbg(struct pt_regs *regs)
{
	die_if_kernel("Instruction fault", regs, 0, NULL);

	force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)regs->pc);
}

/*
 * entUna has a different register layout to be reasonably simple. It
 * needs access to all the integer registers (the kernel doesn't use
 * fp-regs), and it needs to have them in order for simpler access.
 *
 * Due to the non-standard register layout (and because we don't want
 * to handle floating-point regs), user-mode unaligned accesses are
 * handled separately by do_entUnaUser below.
 *
 * Oh, btw, we don't handle the "gp" register correctly, but if we fault
 * on a gp-register unaligned load/store, something is _very_ wrong
 * in the kernel anyway..
 */
struct allregs {
	unsigned long regs[32];
	unsigned long ps, pc, gp, a0, a1, a2;
};

struct unaligned_stat {
	unsigned long count, va, pc;
} unaligned[2];

/* Macro for exception fixup code to access integer registers.  */
#define una_reg(r)  (_regs[(r) >= 16 && (r) <= 18 ? (r)+19 : (r)])

asmlinkage void
do_entUna(void * va, unsigned long opcode, unsigned long reg,
	  struct allregs *regs)
{
	long error, tmp1, tmp2, tmp3, tmp4;
	unsigned long pc = regs->pc - 4;
	unsigned long *_regs = regs->regs;
	const struct exception_table_entry *fixup;

	unaligned[0].count++;
	unaligned[0].va = (unsigned long) va;
	unaligned[0].pc = pc;

	/* We don't want to use the generic get/put unaligned macros as
	   we want to trap exceptions.  Only if we actually get an
	   exception will we decide whether we should have caught it.  */

	switch (opcode) {
	case 0x0c: /* ldwu */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,1(%3)\n"
		"	extwl %1,%3,%1\n"
		"	extwh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto got_exception;
		una_reg(reg) = tmp1|tmp2;
		return;

	case 0x28: /* ldl */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,3(%3)\n"
		"	extll %1,%3,%1\n"
		"	extlh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto got_exception;
		una_reg(reg) = (int)(tmp1|tmp2);
		return;

	case 0x29: /* ldq */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,7(%3)\n"
		"	extql %1,%3,%1\n"
		"	extqh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto got_exception;
		una_reg(reg) = tmp1|tmp2;
		return;

	/* Note that the store sequences do not indicate that they change
	   memory because it _should_ be affecting nothing in this context.
	   (Otherwise we have other, much larger, problems.)  */
	case 0x0d: /* stw */
		__asm__ __volatile__(
		"1:	ldq_u %2,1(%5)\n"
		"2:	ldq_u %1,0(%5)\n"
		"	inswh %6,%5,%4\n"
		"	inswl %6,%5,%3\n"
		"	mskwh %2,%5,%2\n"
		"	mskwl %1,%5,%1\n"
		"	or %2,%4,%2\n"
		"	or %1,%3,%1\n"
		"3:	stq_u %2,1(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(una_reg(reg)), "0"(0));
		if (error)
			goto got_exception;
		return;

	case 0x2c: /* stl */
		__asm__ __volatile__(
		"1:	ldq_u %2,3(%5)\n"
		"2:	ldq_u %1,0(%5)\n"
		"	inslh %6,%5,%4\n"
		"	insll %6,%5,%3\n"
		"	msklh %2,%5,%2\n"
		"	mskll %1,%5,%1\n"
		"	or %2,%4,%2\n"
		"	or %1,%3,%1\n"
		"3:	stq_u %2,3(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(una_reg(reg)), "0"(0));
		if (error)
			goto got_exception;
		return;

	case 0x2d: /* stq */
		__asm__ __volatile__(
		"1:	ldq_u %2,7(%5)\n"
		"2:	ldq_u %1,0(%5)\n"
		"	insqh %6,%5,%4\n"
		"	insql %6,%5,%3\n"
		"	mskqh %2,%5,%2\n"
		"	mskql %1,%5,%1\n"
		"	or %2,%4,%2\n"
		"	or %1,%3,%1\n"
		"3:	stq_u %2,7(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(una_reg(reg)), "0"(0));
		if (error)
			goto got_exception;
		return;
	}

	printk("Bad unaligned kernel access at %016lx: %p %lx %lu\n",
		pc, va, opcode, reg);
	make_task_dead(SIGSEGV);

got_exception:
	/* Ok, we caught the exception, but we don't want it.  Is there
	   someone to pass it along to?  */
	if ((fixup = search_exception_tables(pc)) != 0) {
		unsigned long newpc;
		newpc = fixup_exception(una_reg, fixup, pc);

		printk("Forwarding unaligned exception at %lx (%lx)\n",
		       pc, newpc);

		regs->pc = newpc;
		return;
	}

	/*
	 * Yikes!  No one to forward the exception to.
	 * Since the registers are in a weird format, dump them ourselves.
 	 */

	printk("%s(%d): unhandled unaligned exception\n",
	       current->comm, task_pid_nr(current));

	printk("pc = [<%016lx>]  ra = [<%016lx>]  ps = %04lx\n",
	       pc, una_reg(26), regs->ps);
	printk("r0 = %016lx  r1 = %016lx  r2 = %016lx\n",
	       una_reg(0), una_reg(1), una_reg(2));
	printk("r3 = %016lx  r4 = %016lx  r5 = %016lx\n",
 	       una_reg(3), una_reg(4), una_reg(5));
	printk("r6 = %016lx  r7 = %016lx  r8 = %016lx\n",
	       una_reg(6), una_reg(7), una_reg(8));
	printk("r9 = %016lx  r10= %016lx  r11= %016lx\n",
	       una_reg(9), una_reg(10), una_reg(11));
	printk("r12= %016lx  r13= %016lx  r14= %016lx\n",
	       una_reg(12), una_reg(13), una_reg(14));
	printk("r15= %016lx\n", una_reg(15));
	printk("r16= %016lx  r17= %016lx  r18= %016lx\n",
	       una_reg(16), una_reg(17), una_reg(18));
	printk("r19= %016lx  r20= %016lx  r21= %016lx\n",
 	       una_reg(19), una_reg(20), una_reg(21));
 	printk("r22= %016lx  r23= %016lx  r24= %016lx\n",
	       una_reg(22), una_reg(23), una_reg(24));
	printk("r25= %016lx  r27= %016lx  r28= %016lx\n",
	       una_reg(25), una_reg(27), una_reg(28));
	printk("gp = %016lx  sp = %p\n", regs->gp, regs+1);

	dik_show_code((unsigned int *)pc);
	dik_show_trace((unsigned long *)(regs+1), KERN_DEFAULT);

	if (test_and_set_thread_flag (TIF_DIE_IF_KERNEL)) {
		printk("die_if_kernel recursion detected.\n");
		local_irq_enable();
		while (1);
	}
	make_task_dead(SIGSEGV);
}

/*
 * Convert an s-floating point value in memory format to the
 * corresponding value in register format.  The exponent
 * needs to be remapped to preserve non-finite values
 * (infinities, not-a-numbers, denormals).
 */
static inline unsigned long
s_mem_to_reg (unsigned long s_mem)
{
	unsigned long frac    = (s_mem >>  0) & 0x7fffff;
	unsigned long sign    = (s_mem >> 31) & 0x1;
	unsigned long exp_msb = (s_mem >> 30) & 0x1;
	unsigned long exp_low = (s_mem >> 23) & 0x7f;
	unsigned long exp;

	exp = (exp_msb << 10) | exp_low;	/* common case */
	if (exp_msb) {
		if (exp_low == 0x7f) {
			exp = 0x7ff;
		}
	} else {
		if (exp_low == 0x00) {
			exp = 0x000;
		} else {
			exp |= (0x7 << 7);
		}
	}
	return (sign << 63) | (exp << 52) | (frac << 29);
}

/*
 * Convert an s-floating point value in register format to the
 * corresponding value in memory format.
 */
static inline unsigned long
s_reg_to_mem (unsigned long s_reg)
{
	return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34);
}

/*
 * Handle user-level unaligned fault.  Handling user-level unaligned
 * faults is *extremely* slow and produces nasty messages.  A user
 * program *should* fix unaligned faults ASAP.
 *
 * Notice that we have (almost) the regular kernel stack layout here,
 * so finding the appropriate registers is a little more difficult
 * than in the kernel case.
 *
 * Finally, we handle regular integer load/stores only.  In
 * particular, load-linked/store-conditionally and floating point
 * load/stores are not supported.  The former make no sense with
 * unaligned faults (they are guaranteed to fail) and I don't think
 * the latter will occur in any decent program.
 *
 * Sigh. We *do* have to handle some FP operations, because GCC will
 * uses them as temporary storage for integer memory to memory copies.
 * However, we need to deal with stt/ldt and sts/lds only.
 */

#define OP_INT_MASK	( 1L << 0x28 | 1L << 0x2c   /* ldl stl */	\
			| 1L << 0x29 | 1L << 0x2d   /* ldq stq */	\
			| 1L << 0x0c | 1L << 0x0d   /* ldwu stw */	\
			| 1L << 0x0a | 1L << 0x0e ) /* ldbu stb */

#define OP_WRITE_MASK	( 1L << 0x26 | 1L << 0x27   /* sts stt */	\
			| 1L << 0x2c | 1L << 0x2d   /* stl stq */	\
			| 1L << 0x0d | 1L << 0x0e ) /* stw stb */

#define R(x)	((size_t) &((struct pt_regs *)0)->x)

static int unauser_reg_offsets[32] = {
	R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8),
	/* r9 ... r15 are stored in front of regs.  */
	-56, -48, -40, -32, -24, -16, -8,
	R(r16), R(r17), R(r18),
	R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26),
	R(r27), R(r28), R(gp),
	0, 0
};

#undef R

asmlinkage void
do_entUnaUser(void __user * va, unsigned long opcode,
	      unsigned long reg, struct pt_regs *regs)
{
	static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);

	unsigned long tmp1, tmp2, tmp3, tmp4;
	unsigned long fake_reg, *reg_addr = &fake_reg;
	int si_code;
	long error;

	/* Check the UAC bits to decide what the user wants us to do
	   with the unaligned access.  */

	if (!(current_thread_info()->status & TS_UAC_NOPRINT)) {
		if (__ratelimit(&ratelimit)) {
			printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
			       current->comm, task_pid_nr(current),
			       regs->pc - 4, va, opcode, reg);
		}
	}
	if ((current_thread_info()->status & TS_UAC_SIGBUS))
		goto give_sigbus;
	/* Not sure why you'd want to use this, but... */
	if ((current_thread_info()->status & TS_UAC_NOFIX))
		return;

	/* Don't bother reading ds in the access check since we already
	   know that this came from the user.  Also rely on the fact that
	   the page at TASK_SIZE is unmapped and so can't be touched anyway. */
	if ((unsigned long)va >= TASK_SIZE)
		goto give_sigsegv;

	++unaligned[1].count;
	unaligned[1].va = (unsigned long)va;
	unaligned[1].pc = regs->pc - 4;

	if ((1L << opcode) & OP_INT_MASK) {
		/* it's an integer load/store */
		if (reg < 30) {
			reg_addr = (unsigned long *)
			  ((char *)regs + unauser_reg_offsets[reg]);
		} else if (reg == 30) {
			/* usp in PAL regs */
			fake_reg = rdusp();
		} else {
			/* zero "register" */
			fake_reg = 0;
		}
	}

	/* We don't want to use the generic get/put unaligned macros as
	   we want to trap exceptions.  Only if we actually get an
	   exception will we decide whether we should have caught it.  */

	switch (opcode) {
	case 0x0c: /* ldwu */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,1(%3)\n"
		"	extwl %1,%3,%1\n"
		"	extwh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto give_sigsegv;
		*reg_addr = tmp1|tmp2;
		break;

	case 0x22: /* lds */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,3(%3)\n"
		"	extll %1,%3,%1\n"
		"	extlh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto give_sigsegv;
		alpha_write_fp_reg(reg, s_mem_to_reg((int)(tmp1|tmp2)));
		return;

	case 0x23: /* ldt */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,7(%3)\n"
		"	extql %1,%3,%1\n"
		"	extqh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto give_sigsegv;
		alpha_write_fp_reg(reg, tmp1|tmp2);
		return;

	case 0x28: /* ldl */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,3(%3)\n"
		"	extll %1,%3,%1\n"
		"	extlh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto give_sigsegv;
		*reg_addr = (int)(tmp1|tmp2);
		break;

	case 0x29: /* ldq */
		__asm__ __volatile__(
		"1:	ldq_u %1,0(%3)\n"
		"2:	ldq_u %2,7(%3)\n"
		"	extql %1,%3,%1\n"
		"	extqh %2,%3,%2\n"
		"3:\n"
		EXC(1b,3b,%1,%0)
		EXC(2b,3b,%2,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
			: "r"(va), "0"(0));
		if (error)
			goto give_sigsegv;
		*reg_addr = tmp1|tmp2;
		break;

	/* Note that the store sequences do not indicate that they change
	   memory because it _should_ be affecting nothing in this context.
	   (Otherwise we have other, much larger, problems.)  */
	case 0x0d: /* stw */
		__asm__ __volatile__(
		"1:	ldq_u %2,1(%5)\n"
		"2:	ldq_u %1,0(%5)\n"
		"	inswh %6,%5,%4\n"
		"	inswl %6,%5,%3\n"
		"	mskwh %2,%5,%2\n"
		"	mskwl %1,%5,%1\n"
		"	or %2,%4,%2\n"
		"	or %1,%3,%1\n"
		"3:	stq_u %2,1(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(*reg_addr), "0"(0));
		if (error)
			goto give_sigsegv;
		return;

	case 0x26: /* sts */
		fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
		fallthrough;

	case 0x2c: /* stl */
		__asm__ __volatile__(
		"1:	ldq_u %2,3(%5)\n"
		"2:	ldq_u %1,0(%5)\n"
		"	inslh %6,%5,%4\n"
		"	insll %6,%5,%3\n"
		"	msklh %2,%5,%2\n"
		"	mskll %1,%5,%1\n"
		"	or %2,%4,%2\n"
		"	or %1,%3,%1\n"
		"3:	stq_u %2,3(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(*reg_addr), "0"(0));
		if (error)
			goto give_sigsegv;
		return;

	case 0x27: /* stt */
		fake_reg = alpha_read_fp_reg(reg);
		fallthrough;

	case 0x2d: /* stq */
		__asm__ __volatile__(
		"1:	ldq_u %2,7(%5)\n"
		"2:	ldq_u %1,0(%5)\n"
		"	insqh %6,%5,%4\n"
		"	insql %6,%5,%3\n"
		"	mskqh %2,%5,%2\n"
		"	mskql %1,%5,%1\n"
		"	or %2,%4,%2\n"
		"	or %1,%3,%1\n"
		"3:	stq_u %2,7(%5)\n"
		"4:	stq_u %1,0(%5)\n"
		"5:\n"
		EXC(1b,5b,%2,%0)
		EXC(2b,5b,%1,%0)
		EXC(3b,5b,$31,%0)
		EXC(4b,5b,$31,%0)
			: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
			  "=&r"(tmp3), "=&r"(tmp4)
			: "r"(va), "r"(*reg_addr), "0"(0));
		if (error)
			goto give_sigsegv;
		return;

	default:
		/* What instruction were you trying to use, exactly?  */
		goto give_sigbus;
	}

	/* Only integer loads should get here; everyone else returns early. */
	if (reg == 30)
		wrusp(fake_reg);
	return;

give_sigsegv:
	regs->pc -= 4;  /* make pc point to faulting insn */

	/* We need to replicate some of the logic in mm/fault.c,
	   since we don't have access to the fault code in the
	   exception handling return path.  */
	if ((unsigned long)va >= TASK_SIZE)
		si_code = SEGV_ACCERR;
	else {
		struct mm_struct *mm = current->mm;
		mmap_read_lock(mm);
		if (find_vma(mm, (unsigned long)va))
			si_code = SEGV_ACCERR;
		else
			si_code = SEGV_MAPERR;
		mmap_read_unlock(mm);
	}
	send_sig_fault(SIGSEGV, si_code, va, current);
	return;

give_sigbus:
	regs->pc -= 4;
	send_sig_fault(SIGBUS, BUS_ADRALN, va, current);
	return;
}

void
trap_init(void)
{
	/* Tell PAL-code what global pointer we want in the kernel.  */
	register unsigned long gptr __asm__("$29");
	wrkgp(gptr);

	/* Hack for Multia (UDB) and JENSEN: some of their SRMs have
	   a bug in the handling of the opDEC fault.  Fix it up if so.  */
	if (implver() == IMPLVER_EV4)
		opDEC_check();

	wrent(entArith, 1);
	wrent(entMM, 2);
	wrent(entIF, 3);
	wrent(entUna, 4);
	wrent(entSys, 5);
	wrent(entDbg, 6);
}


code:
/* SPDX-License-Identifier: GPL-2.0 */

#define EMITS_PT_NOTE
#define RO_EXCEPTION_TABLE_ALIGN	16

#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
#include <asm/cache.h>
#include <asm/page.h>
#include <asm/setup.h>

OUTPUT_FORMAT("elf64-alpha")
OUTPUT_ARCH(alpha)
ENTRY(__start)
PHDRS { text PT_LOAD; note PT_NOTE; }
jiffies = jiffies_64;
SECTIONS
{
#ifdef CONFIG_ALPHA_LEGACY_START_ADDRESS
	. = 0xfffffc0000310000;
#else
	. = 0xfffffc0001010000;
#endif

	_text = .;	/* Text and read-only data */
	.text : {
		HEAD_TEXT
		TEXT_TEXT
		SCHED_TEXT
		CPUIDLE_TEXT
		LOCK_TEXT
		*(.fixup)
		*(.gnu.warning)
	} :text
	swapper_pg_dir = SWAPPER_PGD;
	_etext = .;	/* End of text section */

	RO_DATA(4096)

	/* Will be freed after init */
	__init_begin = ALIGN(PAGE_SIZE);
	INIT_TEXT_SECTION(PAGE_SIZE)
	INIT_DATA_SECTION(16)
	PERCPU_SECTION(L1_CACHE_BYTES)
	/* Align to THREAD_SIZE rather than PAGE_SIZE here so any padding page
	   needed for the THREAD_SIZE aligned init_task gets freed after init */
	. = ALIGN(THREAD_SIZE);
	__init_end = .;
	/* Freed after init ends here */

	_sdata = .;	/* Start of rw data section */
	_data = .;
	RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)

	.got : {
		*(.got)
	}
	.sdata : {
		*(.sdata)
	}
	_edata = .;	/* End of data section */

	BSS_SECTION(0, 0, 0)
	_end = .;

	.mdebug 0 : {
		*(.mdebug)
	}
	.note 0 : {
		*(.note)
	}

	STABS_DEBUG
	DWARF_DEBUG
	ELF_DETAILS

	DISCARDS
}


code:
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for alpha-specific library files..
#

asflags-y := $(KBUILD_CFLAGS)
ccflags-y := -Werror

# Many of these routines have implementations tuned for ev6.
# Choose them iff we're targeting ev6 specifically.
ev6-$(CONFIG_ALPHA_EV6) := ev6-

# Several make use of the cttz instruction introduced in ev67.
ev67-$(CONFIG_ALPHA_EV67) := ev67-

lib-y =	__divqu.o __remqu.o __divlu.o __remlu.o \
	udiv-qrnnd.o \
	udelay.o \
	$(ev6-y)memset.o \
	$(ev6-y)memcpy.o \
	memmove.o \
	checksum.o \
	csum_partial_copy.o \
	$(ev67-y)strlen.o \
	stycpy.o \
	styncpy.o \
	$(ev67-y)strchr.o \
	$(ev67-y)strrchr.o \
	$(ev6-y)memchr.o \
	$(ev6-y)copy_user.o \
	$(ev6-y)clear_user.o \
	$(ev6-y)csum_ipv6_magic.o \
	$(ev6-y)clear_page.o \
	$(ev6-y)copy_page.o \
	fpreg.o \
	callback_srm.o srm_puts.o srm_printk.o \
	fls.o

# The division routines are built from single source, with different defines.
AFLAGS___divqu.o = -DDIV
AFLAGS___remqu.o =       -DREM
AFLAGS___divlu.o = -DDIV       -DINTSIZE
AFLAGS___remlu.o =       -DREM -DINTSIZE

$(addprefix $(obj)/,__divqu.o __remqu.o __divlu.o __remlu.o): \
						$(src)/$(ev6-y)divide.S FORCE
	$(call if_changed_rule,as_o_S)

# There are direct branches between {str*cpy,str*cat} and stx*cpy.
# Ensure the branches are within range by merging these objects.

LDFLAGS_stycpy.o := -r
LDFLAGS_styncpy.o := -r

$(obj)/stycpy.o: $(obj)/strcpy.o $(obj)/$(ev67-y)strcat.o \
		 $(obj)/$(ev6-y)stxcpy.o FORCE
	$(call if_changed,ld)

$(obj)/styncpy.o: $(obj)/strncpy.o $(obj)/$(ev67-y)strncat.o \
		 $(obj)/$(ev6-y)stxncpy.o FORCE
	$(call if_changed,ld)

path: arch/alpha/lib/Makefile


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 *	arch/alpha/lib/callback_srm.S
 */

#include <asm/console.h>
#include <asm/export.h>

.text
#define HWRPB_CRB_OFFSET 0xc0

#if defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC)
.align 4
srm_dispatch:
#if defined(CONFIG_ALPHA_GENERIC)
	ldl	$4,alpha_using_srm
	beq	$4,nosrm
#endif
	ldq	$0,hwrpb	# gp is set up by CALLBACK macro.
	ldl	$25,0($25)	# Pick up the wrapper data.
	mov	$20,$21		# Shift arguments right.
	mov	$19,$20
	ldq	$1,HWRPB_CRB_OFFSET($0)
	mov	$18,$19
	mov	$17,$18
	mov	$16,$17
	addq	$0,$1,$2	# CRB address
	ldq	$27,0($2)	# DISPATCH procedure descriptor (VMS call std)
	extwl	$25,0,$16	# SRM callback function code
	ldq	$3,8($27)	# call address
	extwl	$25,2,$25	# argument information (VMS calling std)
	jmp	($3)		# Return directly to caller of wrapper.

.align 4
.globl	srm_fixup
.ent	srm_fixup
srm_fixup:
	ldgp	$29,0($27)
#if defined(CONFIG_ALPHA_GENERIC)
	ldl	$4,alpha_using_srm
	beq	$4,nosrm
#endif
	ldq	$0,hwrpb
	ldq	$1,HWRPB_CRB_OFFSET($0)
	addq	$0,$1,$2	# CRB address
	ldq	$27,16($2)	# VA of FIXUP procedure descriptor
	ldq	$3,8($27)	# call address
	lda	$25,2($31)	# two integer arguments
	jmp	($3)		# Return directly to caller of srm_fixup.
.end    srm_fixup

#if defined(CONFIG_ALPHA_GENERIC)
.align 3
nosrm:
	lda	$0,-1($31)
	ret
#endif

#define CALLBACK(NAME, CODE, ARG_CNT) \
.align 4; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \
ldgp $29,0($27); br $25,srm_dispatch; .word CODE, ARG_CNT; .end callback_##NAME

#else /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */

#define CALLBACK(NAME, CODE, ARG_CNT) \
.align 3; .globl callback_##NAME; .ent callback_##NAME; callback_##NAME##: \
lda $0,-1($31); ret; .end callback_##NAME

.align 3
.globl	srm_fixup
.ent	srm_fixup
srm_fixup:
	lda	$0,-1($31)
	ret
.end	srm_fixup
#endif /* defined(CONFIG_ALPHA_SRM) || defined(CONFIG_ALPHA_GENERIC) */

CALLBACK(puts, CCB_PUTS, 4)
CALLBACK(open, CCB_OPEN, 3)
CALLBACK(close, CCB_CLOSE, 2)
CALLBACK(read, CCB_READ, 5)
CALLBACK(open_console, CCB_OPEN_CONSOLE, 1)
CALLBACK(close_console, CCB_CLOSE_CONSOLE, 1)
CALLBACK(getenv, CCB_GET_ENV, 4)
CALLBACK(setenv, CCB_SET_ENV, 4)
CALLBACK(getc, CCB_GETC, 2)
CALLBACK(reset_term, CCB_RESET_TERM, 2)
CALLBACK(term_int, CCB_SET_TERM_INT, 3)
CALLBACK(term_ctl, CCB_SET_TERM_CTL, 3)
CALLBACK(process_keycode, CCB_PROCESS_KEYCODE, 3)
CALLBACK(ioctl, CCB_IOCTL, 6)
CALLBACK(write, CCB_WRITE, 5)
CALLBACK(reset_env, CCB_RESET_ENV, 4)
CALLBACK(save_env, CCB_SAVE_ENV, 1)
CALLBACK(pswitch, CCB_PSWITCH, 3)
CALLBACK(bios_emul, CCB_BIOS_EMUL, 5)

EXPORT_SYMBOL(callback_getenv)
EXPORT_SYMBOL(callback_setenv)
EXPORT_SYMBOL(callback_save_env)

.data
__alpha_using_srm:		# For use by bootpheader
	.long 7			# value is not 1 for link debugging
	.weak alpha_using_srm; alpha_using_srm = __alpha_using_srm
__callback_init_done:		# For use by bootpheader
	.long 7			# value is not 1 for link debugging
	.weak callback_init_done; callback_init_done = __callback_init_done


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * arch/alpha/lib/checksum.c
 *
 * This file contains network checksum routines that are better done
 * in an architecture-specific manner due to speed..
 * Comments in other versions indicate that the algorithms are from RFC1071
 *
 * accelerated versions (and 21264 assembly versions ) contributed by
 *	Rick Gorton	<rick.gorton@alpha-processor.com>
 */

#include <linux/module.h>
#include <linux/string.h>

#include <asm/byteorder.h>

static inline unsigned short from64to16(unsigned long x)
{
	/* Using extract instructions is a bit more efficient
	   than the original shift/bitmask version.  */

	union {
		unsigned long	ul;
		unsigned int	ui[2];
		unsigned short	us[4];
	} in_v, tmp_v, out_v;

	in_v.ul = x;
	tmp_v.ul = (unsigned long) in_v.ui[0] + (unsigned long) in_v.ui[1];

	/* Since the bits of tmp_v.sh[3] are going to always be zero,
	   we don't have to bother to add that in.  */
	out_v.ul = (unsigned long) tmp_v.us[0] + (unsigned long) tmp_v.us[1]
			+ (unsigned long) tmp_v.us[2];

	/* Similarly, out_v.us[2] is always zero for the final add.  */
	return out_v.us[0] + out_v.us[1];
}

/*
 * computes the checksum of the TCP/UDP pseudo-header
 * returns a 16-bit checksum, already complemented.
 */
__sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
			  __u32 len, __u8 proto, __wsum sum)
{
	return (__force __sum16)~from64to16(
		(__force u64)saddr + (__force u64)daddr +
		(__force u64)sum + ((len + proto) << 8));
}
EXPORT_SYMBOL(csum_tcpudp_magic);

__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
			  __u32 len, __u8 proto, __wsum sum)
{
	unsigned long result;

	result = (__force u64)saddr + (__force u64)daddr +
		 (__force u64)sum + ((len + proto) << 8);

	/* Fold down to 32-bits so we don't lose in the typedef-less
	   network stack.  */
	/* 64 to 33 */
	result = (result & 0xffffffff) + (result >> 32);
	/* 33 to 32 */
	result = (result & 0xffffffff) + (result >> 32);
	return (__force __wsum)result;
}
EXPORT_SYMBOL(csum_tcpudp_nofold);

/*
 * Do a 64-bit checksum on an arbitrary memory area..
 *
 * This isn't a great routine, but it's not _horrible_ either. The
 * inner loop could be unrolled a bit further, and there are better
 * ways to do the carry, but this is reasonable.
 */
static inline unsigned long do_csum(const unsigned char * buff, int len)
{
	int odd, count;
	unsigned long result = 0;

	if (len <= 0)
		goto out;
	odd = 1 & (unsigned long) buff;
	if (odd) {
		result = *buff << 8;
		len--;
		buff++;
	}
	count = len >> 1;		/* nr of 16-bit words.. */
	if (count) {
		if (2 & (unsigned long) buff) {
			result += *(unsigned short *) buff;
			count--;
			len -= 2;
			buff += 2;
		}
		count >>= 1;		/* nr of 32-bit words.. */
		if (count) {
			if (4 & (unsigned long) buff) {
				result += *(unsigned int *) buff;
				count--;
				len -= 4;
				buff += 4;
			}
			count >>= 1;	/* nr of 64-bit words.. */
			if (count) {
				unsigned long carry = 0;
				do {
					unsigned long w = *(unsigned long *) buff;
					count--;
					buff += 8;
					result += carry;
					result += w;
					carry = (w > result);
				} while (count);
				result += carry;
				result = (result & 0xffffffff) + (result >> 32);
			}
			if (len & 4) {
				result += *(unsigned int *) buff;
				buff += 4;
			}
		}
		if (len & 2) {
			result += *(unsigned short *) buff;
			buff += 2;
		}
	}
	if (len & 1)
		result += *buff;
	result = from64to16(result);
	if (odd)
		result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
out:
	return result;
}

/*
 *	This is a version of ip_compute_csum() optimized for IP headers,
 *	which always checksum on 4 octet boundaries.
 */
__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
	return (__force __sum16)~do_csum(iph,ihl*4);
}
EXPORT_SYMBOL(ip_fast_csum);

/*
 * computes the checksum of a memory block at buff, length len,
 * and adds in "sum" (32-bit)
 *
 * returns a 32-bit number suitable for feeding into itself
 * or csum_tcpudp_magic
 *
 * this function must be called with even lengths, except
 * for the last fragment, which may be odd
 *
 * it's best to have buff aligned on a 32-bit boundary
 */
__wsum csum_partial(const void *buff, int len, __wsum sum)
{
	unsigned long result = do_csum(buff, len);

	/* add in old sum, and carry.. */
	result += (__force u32)sum;
	/* 32+c bits -> 32 bits */
	result = (result & 0xffffffff) + (result >> 32);
	return (__force __wsum)result;
}

EXPORT_SYMBOL(csum_partial);

/*
 * this routine is used for miscellaneous IP-like checksums, mainly
 * in icmp.c
 */
__sum16 ip_compute_csum(const void *buff, int len)
{
	return (__force __sum16)~from64to16(do_csum(buff,len));
}
EXPORT_SYMBOL(ip_compute_csum);


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/clear_page.S
 *
 * Zero an entire page.
 */
#include <asm/export.h>
	.text
	.align 4
	.global clear_page
	.ent clear_page
clear_page:
	.prologue 0

	lda	$0,128
	nop
	unop
	nop

1:	stq	$31,0($16)
	stq	$31,8($16)
	stq	$31,16($16)
	stq	$31,24($16)

	stq	$31,32($16)
	stq	$31,40($16)
	stq	$31,48($16)
	subq	$0,1,$0

	stq	$31,56($16)
	addq	$16,64,$16
	unop
	bne	$0,1b

	ret
	nop
	unop
	nop

	.end clear_page
	EXPORT_SYMBOL(clear_page)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/clear_user.S
 * Contributed by Richard Henderson <rth@tamu.edu>
 *
 * Zero user space, handling exceptions as we go.
 *
 * We have to make sure that $0 is always up-to-date and contains the
 * right "bytes left to zero" value (and that it is updated only _after_
 * a successful copy).  There is also some rather minor exception setup
 * stuff.
 */
#include <asm/export.h>

/* Allow an exception for an insn; exit if we get one.  */
#define EX(x,y...)			\
	99: x,##y;			\
	.section __ex_table,"a";	\
	.long 99b - .;			\
	lda $31, $exception-99b($31); 	\
	.previous

	.set noat
	.set noreorder
	.align 4

	.globl __clear_user
	.ent __clear_user
	.frame	$30, 0, $26
	.prologue 0

$loop:
	and	$1, 3, $4	# e0    :
	beq	$4, 1f		# .. e1 :

0:	EX( stq_u $31, 0($16) )	# e0    : zero one word
	subq	$0, 8, $0	# .. e1 :
	subq	$4, 1, $4	# e0    :
	addq	$16, 8, $16	# .. e1 :
	bne	$4, 0b		# e1    :
	unop			#       :

1:	bic	$1, 3, $1	# e0    :
	beq	$1, $tail	# .. e1 :

2:	EX( stq_u $31, 0($16) )	# e0    : zero four words
	subq	$0, 8, $0	# .. e1 :
	EX( stq_u $31, 8($16) )	# e0    :
	subq	$0, 8, $0	# .. e1 :
	EX( stq_u $31, 16($16) )	# e0    :
	subq	$0, 8, $0	# .. e1 :
	EX( stq_u $31, 24($16) )	# e0    :
	subq	$0, 8, $0	# .. e1 :
	subq	$1, 4, $1	# e0    :
	addq	$16, 32, $16	# .. e1 :
	bne	$1, 2b		# e1    :

$tail:
	bne	$2, 1f		# e1    : is there a tail to do?
	ret	$31, ($26), 1	# .. e1 :

1:	EX( ldq_u $5, 0($16) )	# e0    :
	clr	$0		# .. e1 :
	nop			# e1    :
	mskqh	$5, $0, $5	# e0    :
	EX( stq_u $5, 0($16) )	# e0    :
	ret	$31, ($26), 1	# .. e1 :

__clear_user:
	and	$17, $17, $0
	and	$16, 7, $4	# e0    : find dest misalignment
	beq	$0, $zerolength # .. e1 :
	addq	$0, $4, $1	# e0    : bias counter
	and	$1, 7, $2	# e1    : number of bytes in tail
	srl	$1, 3, $1	# e0    :
	beq	$4, $loop	# .. e1 :

	EX( ldq_u $5, 0($16) )	# e0    : load dst word to mask back in
	beq	$1, $oneword	# .. e1 : sub-word store?

	mskql	$5, $16, $5	# e0    : take care of misaligned head
	addq	$16, 8, $16	# .. e1 :
	EX( stq_u $5, -8($16) )	# e0    :
	addq	$0, $4, $0	# .. e1 : bytes left -= 8 - misalignment
	subq	$1, 1, $1	# e0    :
	subq	$0, 8, $0	# .. e1 :
	br	$loop		# e1    :
	unop			#       :

$oneword:
	mskql	$5, $16, $4	# e0    :
	mskqh	$5, $2, $5	# e0    :
	or	$5, $4, $5	# e1    :
	EX( stq_u $5, 0($16) )	# e0    :
	clr	$0		# .. e1 :

$zerolength:
$exception:
	ret	$31, ($26), 1	# .. e1 :

	.end __clear_user
	EXPORT_SYMBOL(__clear_user)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/copy_page.S
 *
 * Copy an entire page.
 */
#include <asm/export.h>
	.text
	.align 4
	.global copy_page
	.ent copy_page
copy_page:
	.prologue 0

	lda	$18,128
	nop
	unop
	nop

1:	ldq	$0,0($17)
	ldq	$1,8($17)
	ldq	$2,16($17)
	ldq	$3,24($17)

	ldq	$4,32($17)
	ldq	$5,40($17)
	ldq	$6,48($17)
	ldq	$7,56($17)

	stq	$0,0($16)
	subq	$18,1,$18
	stq	$1,8($16)
	addq	$17,64,$17

	stq	$2,16($16)
	stq	$3,24($16)
	stq	$4,32($16)
	stq	$5,40($16)

	stq	$6,48($16)
	stq	$7,56($16)
	addq	$16,64,$16
	bne	$18, 1b

	ret
	nop
	unop
	nop

	.end copy_page
	EXPORT_SYMBOL(copy_page)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/copy_user.S
 *
 * Copy to/from user space, handling exceptions as we go..  This
 * isn't exactly pretty.
 *
 * This is essentially the same as "memcpy()", but with a few twists.
 * Notably, we have to make sure that $0 is always up-to-date and
 * contains the right "bytes left to copy" value (and that it is updated
 * only _after_ a successful copy). There is also some rather minor
 * exception setup stuff..
 */

#include <asm/export.h>

/* Allow an exception for an insn; exit if we get one.  */
#define EXI(x,y...)			\
	99: x,##y;			\
	.section __ex_table,"a";	\
	.long 99b - .;			\
	lda $31, $exitin-99b($31);	\
	.previous

#define EXO(x,y...)			\
	99: x,##y;			\
	.section __ex_table,"a";	\
	.long 99b - .;			\
	lda $31, $exitout-99b($31);	\
	.previous

	.set noat
	.align 4
	.globl __copy_user
	.ent __copy_user
__copy_user:
	.prologue 0
	mov $18,$0
	and $16,7,$3
	beq $0,$35
	beq $3,$36
	subq $3,8,$3
	.align 4
$37:
	EXI( ldq_u $1,0($17) )
	EXO( ldq_u $2,0($16) )
	extbl $1,$17,$1
	mskbl $2,$16,$2
	insbl $1,$16,$1
	addq $3,1,$3
	bis $1,$2,$1
	EXO( stq_u $1,0($16) )
	subq $0,1,$0
	addq $16,1,$16
	addq $17,1,$17
	beq $0,$41
	bne $3,$37
$36:
	and $17,7,$1
	bic $0,7,$4
	beq $1,$43
	beq $4,$48
	EXI( ldq_u $3,0($17) )
	.align 4
$50:
	EXI( ldq_u $2,8($17) )
	subq $4,8,$4
	extql $3,$17,$3
	extqh $2,$17,$1
	bis $3,$1,$1
	EXO( stq $1,0($16) )
	addq $17,8,$17
	subq $0,8,$0
	addq $16,8,$16
	bis $2,$2,$3
	bne $4,$50
$48:
	beq $0,$41
	.align 4
$57:
	EXI( ldq_u $1,0($17) )
	EXO( ldq_u $2,0($16) )
	extbl $1,$17,$1
	mskbl $2,$16,$2
	insbl $1,$16,$1
	bis $1,$2,$1
	EXO( stq_u $1,0($16) )
	subq $0,1,$0
	addq $16,1,$16
	addq $17,1,$17
	bne $0,$57
	br $31,$41
	.align 4
$43:
	beq $4,$65
	.align 4
$66:
	EXI( ldq $1,0($17) )
	subq $4,8,$4
	EXO( stq $1,0($16) )
	addq $17,8,$17
	subq $0,8,$0
	addq $16,8,$16
	bne $4,$66
$65:
	beq $0,$41
	EXI( ldq $2,0($17) )
	EXO( ldq $1,0($16) )
	mskql $2,$0,$2
	mskqh $1,$0,$1
	bis $2,$1,$2
	EXO( stq $2,0($16) )
	bis $31,$31,$0
$41:
$35:
$exitin:
$exitout:
	ret $31,($26),1

	.end __copy_user
EXPORT_SYMBOL(__copy_user)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/csum_ipv6_magic.S
 * Contributed by Richard Henderson <rth@tamu.edu>
 *
 * unsigned short csum_ipv6_magic(struct in6_addr *saddr,
 *                                struct in6_addr *daddr,
 *                                __u32 len,
 *                                unsigned short proto,
 *                                unsigned int csum);
 *
 * Misalignment handling (which costs 16 instructions / 8 cycles)
 * added by Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 */

#include <asm/export.h>
	.globl csum_ipv6_magic
	.align 4
	.ent csum_ipv6_magic
	.frame $30,0,$26,0
csum_ipv6_magic:
	.prologue 0

	ldq_u	$0,0($16)	# e0    : load src & dst addr words
	zapnot	$20,15,$20	# .. e1 : zero extend incoming csum
	extqh	$18,1,$4	# e0    : byte swap len & proto while we wait
	ldq_u	$21,7($16)	# .. e1 : handle misalignment

	extbl	$18,1,$5	# e0	:
	ldq_u	$1,8($16)	# .. e1 :
	extbl	$18,2,$6	# e0 	:
	ldq_u	$22,15($16)	# .. e1 :

	extbl	$18,3,$18	# e0	:
	ldq_u	$2,0($17)	# .. e1 :
	sra	$4,32,$4	# e0	:
	ldq_u	$23,7($17)	# .. e1 :

	extql	$0,$16,$0	# e0	:
	ldq_u	$3,8($17)	# .. e1 :
	extqh	$21,$16,$21	# e0	:
	ldq_u	$24,15($17)	# .. e1 :

	sll	$5,16,$5	# e0	:
	or	$0,$21,$0	# .. e1 : 1st src word complete
	extql	$1,$16,$1	# e0	:
	addq	$20,$0,$20	# .. e1 : begin summing the words

	extqh	$22,$16,$22	# e0	:
	cmpult	$20,$0,$0	# .. e1 :
	sll	$6,8,$6		# e0	:
	or	$1,$22,$1	# .. e1 : 2nd src word complete

	extql	$2,$17,$2	# e0	:
	or	$4,$18,$18	# .. e1 :
	extqh	$23,$17,$23	# e0	:
	or	$5,$6,$5	# .. e1 :

	extql	$3,$17,$3	# e0	:
	or	$2,$23,$2	# .. e1 : 1st dst word complete
	extqh	$24,$17,$24	# e0	:
	or	$18,$5,$18	# .. e1 : len complete

	extwh	$19,7,$7	# e0    :
	or	$3,$24,$3	# .. e1 : 2nd dst word complete
	extbl	$19,1,$19	# e0    :
	addq	$20,$1,$20	# .. e1 :

	or	$19,$7,$19	# e0    :
	cmpult	$20,$1,$1	# .. e1 :
	sll	$19,48,$19	# e0    :
	nop			# .. e0 :

	sra	$19,32,$19	# e0    : proto complete
	addq	$20,$2,$20	# .. e1 :
	cmpult	$20,$2,$2	# e0    :
	addq	$20,$3,$20	# .. e1 :

	cmpult	$20,$3,$3	# e0    :
	addq	$20,$18,$20	# .. e1 :
	cmpult	$20,$18,$18	# e0    :
	addq	$20,$19,$20	# .. e1 :

	cmpult	$20,$19,$19	# e0    :
	addq	$0,$1,$0	# .. e1 : merge the carries back into the csum
	addq	$2,$3,$2	# e0    :
	addq	$18,$19,$18	# .. e1 :

	addq	$0,$2,$0	# e0    :
	addq	$20,$18,$20	# .. e1 :
	addq	$0,$20,$0	# e0    :
	unop			#       :

	extwl	$0,2,$2		# e0    : begin folding the 64-bit value
	zapnot	$0,3,$3		# .. e1 :
	extwl	$0,4,$1		# e0    :
	addq	$2,$3,$3	# .. e1 :

	extwl	$0,6,$0		# e0    :
	addq	$3,$1,$3	# .. e1 :
	addq	$0,$3,$0	# e0    :
	unop			#       :

	extwl	$0,2,$1		# e0    : fold 18-bit value
	zapnot	$0,3,$0		# .. e1 :
	addq	$0,$1,$0	# e0    :
	unop			#       :

	extwl	$0,2,$1		# e0    : fold 17-bit value
	zapnot	$0,3,$0		# .. e1 :
	addq	$0,$1,$0	# e0    :
	not	$0,$0		# .. e1 : and complement.

	zapnot	$0,3,$0		# e0    :
	ret			# .. e1 :

	.end csum_ipv6_magic
	EXPORT_SYMBOL(csum_ipv6_magic)


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * csum_partial_copy - do IP checksumming and copy
 *
 * (C) Copyright 1996 Linus Torvalds
 * accelerated versions (and 21264 assembly versions ) contributed by
 *	Rick Gorton	<rick.gorton@alpha-processor.com>
 *
 * Don't look at this too closely - you'll go mad. The things
 * we do for performance..
 */

#include <linux/types.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <net/checksum.h>

#define ldq_u(x,y) \
__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(const unsigned long *)(y)))

#define stq_u(x,y) \
__asm__ __volatile__("stq_u %1,%0":"=m" (*(unsigned long *)(y)):"r" (x))

#define extql(x,y,z) \
__asm__ __volatile__("extql %1,%2,%0":"=r" (z):"r" (x),"r" (y))

#define extqh(x,y,z) \
__asm__ __volatile__("extqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))

#define mskql(x,y,z) \
__asm__ __volatile__("mskql %1,%2,%0":"=r" (z):"r" (x),"r" (y))

#define mskqh(x,y,z) \
__asm__ __volatile__("mskqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))

#define insql(x,y,z) \
__asm__ __volatile__("insql %1,%2,%0":"=r" (z):"r" (x),"r" (y))

#define insqh(x,y,z) \
__asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y))

#define __get_word(insn,x,ptr)				\
({							\
	long __guu_err;					\
	__asm__ __volatile__(				\
	"1:	"#insn" %0,%2\n"			\
	"2:\n"						\
	EXC(1b,2b,%0,%1)				\
		: "=r"(x), "=r"(__guu_err)		\
		: "m"(__m(ptr)), "1"(0));		\
	__guu_err;					\
})

static inline unsigned short from64to16(unsigned long x)
{
	/* Using extract instructions is a bit more efficient
	   than the original shift/bitmask version.  */

	union {
		unsigned long	ul;
		unsigned int	ui[2];
		unsigned short	us[4];
	} in_v, tmp_v, out_v;

	in_v.ul = x;
	tmp_v.ul = (unsigned long) in_v.ui[0] + (unsigned long) in_v.ui[1];

	/* Since the bits of tmp_v.sh[3] are going to always be zero,
	   we don't have to bother to add that in.  */
	out_v.ul = (unsigned long) tmp_v.us[0] + (unsigned long) tmp_v.us[1]
			+ (unsigned long) tmp_v.us[2];

	/* Similarly, out_v.us[2] is always zero for the final add.  */
	return out_v.us[0] + out_v.us[1];
}

/*
 * Ok. This isn't fun, but this is the EASY case.
 */
static inline unsigned long
csum_partial_cfu_aligned(const unsigned long __user *src, unsigned long *dst,
			 long len)
{
	unsigned long checksum = ~0U;
	unsigned long carry = 0;

	while (len >= 0) {
		unsigned long word;
		if (__get_word(ldq, word, src))
			return 0;
		checksum += carry;
		src++;
		checksum += word;
		len -= 8;
		carry = checksum < word;
		*dst = word;
		dst++;
	}
	len += 8;
	checksum += carry;
	if (len) {
		unsigned long word, tmp;
		if (__get_word(ldq, word, src))
			return 0;
		tmp = *dst;
		mskql(word, len, word);
		checksum += word;
		mskqh(tmp, len, tmp);
		carry = checksum < word;
		*dst = word | tmp;
		checksum += carry;
	}
	return checksum;
}

/*
 * This is even less fun, but this is still reasonably
 * easy.
 */
static inline unsigned long
csum_partial_cfu_dest_aligned(const unsigned long __user *src,
			      unsigned long *dst,
			      unsigned long soff,
			      long len)
{
	unsigned long first;
	unsigned long word, carry;
	unsigned long lastsrc = 7+len+(unsigned long)src;
	unsigned long checksum = ~0U;

	if (__get_word(ldq_u, first,src))
		return 0;
	carry = 0;
	while (len >= 0) {
		unsigned long second;

		if (__get_word(ldq_u, second, src+1))
			return 0;
		extql(first, soff, word);
		len -= 8;
		src++;
		extqh(second, soff, first);
		checksum += carry;
		word |= first;
		first = second;
		checksum += word;
		*dst = word;
		dst++;
		carry = checksum < word;
	}
	len += 8;
	checksum += carry;
	if (len) {
		unsigned long tmp;
		unsigned long second;
		if (__get_word(ldq_u, second, lastsrc))
			return 0;
		tmp = *dst;
		extql(first, soff, word);
		extqh(second, soff, first);
		word |= first;
		mskql(word, len, word);
		checksum += word;
		mskqh(tmp, len, tmp);
		carry = checksum < word;
		*dst = word | tmp;
		checksum += carry;
	}
	return checksum;
}

/*
 * This is slightly less fun than the above..
 */
static inline unsigned long
csum_partial_cfu_src_aligned(const unsigned long __user *src,
			     unsigned long *dst,
			     unsigned long doff,
			     long len,
			     unsigned long partial_dest)
{
	unsigned long carry = 0;
	unsigned long word;
	unsigned long second_dest;
	unsigned long checksum = ~0U;

	mskql(partial_dest, doff, partial_dest);
	while (len >= 0) {
		if (__get_word(ldq, word, src))
			return 0;
		len -= 8;
		insql(word, doff, second_dest);
		checksum += carry;
		stq_u(partial_dest | second_dest, dst);
		src++;
		checksum += word;
		insqh(word, doff, partial_dest);
		carry = checksum < word;
		dst++;
	}
	len += 8;
	if (len) {
		checksum += carry;
		if (__get_word(ldq, word, src))
			return 0;
		mskql(word, len, word);
		len -= 8;
		checksum += word;
		insql(word, doff, second_dest);
		len += doff;
		carry = checksum < word;
		partial_dest |= second_dest;
		if (len >= 0) {
			stq_u(partial_dest, dst);
			if (!len) goto out;
			dst++;
			insqh(word, doff, partial_dest);
		}
		doff = len;
	}
	ldq_u(second_dest, dst);
	mskqh(second_dest, doff, second_dest);
	stq_u(partial_dest | second_dest, dst);
out:
	checksum += carry;
	return checksum;
}

/*
 * This is so totally un-fun that it's frightening. Don't
 * look at this too closely, you'll go blind.
 */
static inline unsigned long
csum_partial_cfu_unaligned(const unsigned long __user * src,
			   unsigned long * dst,
			   unsigned long soff, unsigned long doff,
			   long len, unsigned long partial_dest)
{
	unsigned long carry = 0;
	unsigned long first;
	unsigned long lastsrc;
	unsigned long checksum = ~0U;

	if (__get_word(ldq_u, first, src))
		return 0;
	lastsrc = 7+len+(unsigned long)src;
	mskql(partial_dest, doff, partial_dest);
	while (len >= 0) {
		unsigned long second, word;
		unsigned long second_dest;

		if (__get_word(ldq_u, second, src+1))
			return 0;
		extql(first, soff, word);
		checksum += carry;
		len -= 8;
		extqh(second, soff, first);
		src++;
		word |= first;
		first = second;
		insql(word, doff, second_dest);
		checksum += word;
		stq_u(partial_dest | second_dest, dst);
		carry = checksum < word;
		insqh(word, doff, partial_dest);
		dst++;
	}
	len += doff;
	checksum += carry;
	if (len >= 0) {
		unsigned long second, word;
		unsigned long second_dest;

		if (__get_word(ldq_u, second, lastsrc))
			return 0;
		extql(first, soff, word);
		extqh(second, soff, first);
		word |= first;
		first = second;
		mskql(word, len-doff, word);
		checksum += word;
		insql(word, doff, second_dest);
		carry = checksum < word;
		stq_u(partial_dest | second_dest, dst);
		if (len) {
			ldq_u(second_dest, dst+1);
			insqh(word, doff, partial_dest);
			mskqh(second_dest, len, second_dest);
			stq_u(partial_dest | second_dest, dst+1);
		}
		checksum += carry;
	} else {
		unsigned long second, word;
		unsigned long second_dest;

		if (__get_word(ldq_u, second, lastsrc))
			return 0;
		extql(first, soff, word);
		extqh(second, soff, first);
		word |= first;
		ldq_u(second_dest, dst);
		mskql(word, len-doff, word);
		checksum += word;
		mskqh(second_dest, len, second_dest);
		carry = checksum < word;
		insql(word, doff, word);
		stq_u(partial_dest | word | second_dest, dst);
		checksum += carry;
	}
	return checksum;
}

static __wsum __csum_and_copy(const void __user *src, void *dst, int len)
{
	unsigned long soff = 7 & (unsigned long) src;
	unsigned long doff = 7 & (unsigned long) dst;
	unsigned long checksum;

	if (!doff) {
		if (!soff)
			checksum = csum_partial_cfu_aligned(
				(const unsigned long __user *) src,
				(unsigned long *) dst, len-8);
		else
			checksum = csum_partial_cfu_dest_aligned(
				(const unsigned long __user *) src,
				(unsigned long *) dst,
				soff, len-8);
	} else {
		unsigned long partial_dest;
		ldq_u(partial_dest, dst);
		if (!soff)
			checksum = csum_partial_cfu_src_aligned(
				(const unsigned long __user *) src,
				(unsigned long *) dst,
				doff, len-8, partial_dest);
		else
			checksum = csum_partial_cfu_unaligned(
				(const unsigned long __user *) src,
				(unsigned long *) dst,
				soff, doff, len-8, partial_dest);
	}
	return (__force __wsum)from64to16 (checksum);
}

__wsum
csum_and_copy_from_user(const void __user *src, void *dst, int len)
{
	if (!access_ok(src, len))
		return 0;
	return __csum_and_copy(src, dst, len);
}

__wsum
csum_partial_copy_nocheck(const void *src, void *dst, int len)
{
	return __csum_and_copy((__force const void __user *)src,
						dst, len);
}
EXPORT_SYMBOL(csum_partial_copy_nocheck);


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/dbg_current.S
 * Contributed by Richard Henderson (rth@cygnus.com)
 *
 * Trap if we find current not correct.
 */

#include <asm/pal.h>

	.text
	.set noat

	.globl _mcount
	.ent _mcount
_mcount:
	.frame $30, 0, $28, 0
	.prologue 0

	lda	$0, -0x4000($30)
	cmpult	$8, $30, $1
	cmpule	$0, $30, $2
	and	$1, $2, $3
	bne	$3, 1f

	call_pal PAL_bugchk

1:	ret	$31, ($28), 1

	.end _mcount


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/dbg_stackcheck.S
 * Contributed by Richard Henderson (rth@tamu.edu)
 *
 * Verify that we have not overflowed the stack.  Oops if we have.
 */

#include <asm/asm-offsets.h>

	.text
	.set noat

	.align 3
	.globl _mcount
	.ent _mcount
_mcount:
	.frame $30, 0, $28, 0
	.prologue 0

	lda	$0, TASK_SIZE($8)
	cmpult	$30, $0, $0
	bne	$0, 1f
	ret	($28)
1:	stq	$31, -8($31)	# oops me, damn it.
	br	1b

	.end _mcount


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/dbg_stackkill.S
 * Contributed by Richard Henderson (rth@cygnus.com)
 *
 * Clobber the balance of the kernel stack, hoping to catch
 * uninitialized local variables in the act.
 */

#include <asm/asm-offsets.h>

	.text
	.set noat

	.align 5
	.globl _mcount
	.ent _mcount
_mcount:
	.frame $30, 0, $28, 0
	.prologue 0

	ldi	$0, 0xdeadbeef
	lda	$2, -STACK_SIZE
	sll	$0, 32, $1
	and	$30, $2, $2
	or	$0, $1, $0
	lda	$2, TASK_SIZE($2)
	cmpult	$2, $30, $1
	beq	$1, 2f
1:	stq	$0, 0($2)
	addq	$2, 8, $2
	cmpult	$2, $30, $1
	bne	$1, 1b
2:	ret	($28)

	.end _mcount


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/divide.S
 *
 * (C) 1995 Linus Torvalds
 *
 * Alpha division..
 */

/*
 * The alpha chip doesn't provide hardware division, so we have to do it
 * by hand.  The compiler expects the functions
 *
 *	__divqu: 64-bit unsigned long divide
 *	__remqu: 64-bit unsigned long remainder
 *	__divqs/__remqs: signed 64-bit
 *	__divlu/__remlu: unsigned 32-bit
 *	__divls/__remls: signed 32-bit
 *
 * These are not normal C functions: instead of the normal
 * calling sequence, these expect their arguments in registers
 * $24 and $25, and return the result in $27. Register $28 may
 * be clobbered (assembly temporary), anything else must be saved.
 *
 * In short: painful.
 *
 * This is a rather simple bit-at-a-time algorithm: it's very good
 * at dividing random 64-bit numbers, but the more usual case where
 * the divisor is small is handled better by the DEC algorithm
 * using lookup tables. This uses much less memory, though, and is
 * nicer on the cache.. Besides, I don't know the copyright status
 * of the DEC code.
 */

/*
 * My temporaries:
 *	$0 - current bit
 *	$1 - shifted divisor
 *	$2 - modulus/quotient
 *
 *	$23 - return address
 *	$24 - dividend
 *	$25 - divisor
 *
 *	$27 - quotient/modulus
 *	$28 - compare status
 */

#include <asm/export.h>
#define halt .long 0

/*
 * Select function type and registers
 */
#define mask	$0
#define divisor	$1
#define compare $28
#define tmp1	$3
#define tmp2	$4

#ifdef DIV
#define DIV_ONLY(x,y...) x,##y
#define MOD_ONLY(x,y...)
#define func(x) __div##x
#define modulus $2
#define quotient $27
#define GETSIGN(x) xor $24,$25,x
#define STACK 48
#else
#define DIV_ONLY(x,y...)
#define MOD_ONLY(x,y...) x,##y
#define func(x) __rem##x
#define modulus $27
#define quotient $2
#define GETSIGN(x) bis $24,$24,x
#define STACK 32
#endif

/*
 * For 32-bit operations, we need to extend to 64-bit
 */
#ifdef INTSIZE
#define ufunction func(lu)
#define sfunction func(l)
#define LONGIFY(x) zapnot x,15,x
#define SLONGIFY(x) addl x,0,x
#else
#define ufunction func(qu)
#define sfunction func(q)
#define LONGIFY(x)
#define SLONGIFY(x)
#endif

.set noat
.align	3
.globl	ufunction
.ent	ufunction
ufunction:
	subq	$30,STACK,$30
	.frame	$30,STACK,$23
	.prologue 0

7:	stq	$1, 0($30)
	bis	$25,$25,divisor
	stq	$2, 8($30)
	bis	$24,$24,modulus
	stq	$0,16($30)
	bis	$31,$31,quotient
	LONGIFY(divisor)
	stq	tmp1,24($30)
	LONGIFY(modulus)
	bis	$31,1,mask
	DIV_ONLY(stq tmp2,32($30))
	beq	divisor, 9f			/* div by zero */

#ifdef INTSIZE
	/*
	 * shift divisor left, using 3-bit shifts for
	 * 32-bit divides as we can't overflow. Three-bit
	 * shifts will result in looping three times less
	 * here, but can result in two loops more later.
	 * Thus using a large shift isn't worth it (and
	 * s8add pairs better than a sll..)
	 */
1:	cmpult	divisor,modulus,compare
	s8addq	divisor,$31,divisor
	s8addq	mask,$31,mask
	bne	compare,1b
#else
1:	cmpult	divisor,modulus,compare
	blt     divisor, 2f
	addq	divisor,divisor,divisor
	addq	mask,mask,mask
	bne	compare,1b
	unop
#endif

	/* ok, start to go right again.. */
2:	DIV_ONLY(addq quotient,mask,tmp2)
	srl	mask,1,mask
	cmpule	divisor,modulus,compare
	subq	modulus,divisor,tmp1
	DIV_ONLY(cmovne compare,tmp2,quotient)
	srl	divisor,1,divisor
	cmovne	compare,tmp1,modulus
	bne	mask,2b

9:	ldq	$1, 0($30)
	ldq	$2, 8($30)
	ldq	$0,16($30)
	ldq	tmp1,24($30)
	DIV_ONLY(ldq tmp2,32($30))
	addq	$30,STACK,$30
	ret	$31,($23),1
	.end	ufunction
EXPORT_SYMBOL(ufunction)

/*
 * Uhh.. Ugly signed division. I'd rather not have it at all, but
 * it's needed in some circumstances. There are different ways to
 * handle this, really. This does:
 * 	-a / b = a / -b = -(a / b)
 *	-a % b = -(a % b)
 *	a % -b = a % b
 * which is probably not the best solution, but at least should
 * have the property that (x/y)*y + (x%y) = x.
 */
.align 3
.globl	sfunction
.ent	sfunction
sfunction:
	subq	$30,STACK,$30
	.frame	$30,STACK,$23
	.prologue 0
	bis	$24,$25,$28
	SLONGIFY($28)
	bge	$28,7b
	stq	$24,0($30)
	subq	$31,$24,$28
	stq	$25,8($30)
	cmovlt	$24,$28,$24	/* abs($24) */
	stq	$23,16($30)
	subq	$31,$25,$28
	stq	tmp1,24($30)
	cmovlt	$25,$28,$25	/* abs($25) */
	unop
	bsr	$23,ufunction
	ldq	$24,0($30)
	ldq	$25,8($30)
	GETSIGN($28)
	subq	$31,$27,tmp1
	SLONGIFY($28)
	ldq	$23,16($30)
	cmovlt	$28,tmp1,$27
	ldq	tmp1,24($30)
	addq	$30,STACK,$30
	ret	$31,($23),1
	.end	sfunction
EXPORT_SYMBOL(sfunction)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/ev6-clear_page.S
 *
 * Zero an entire page.
 */
#include <asm/export.h>
        .text
        .align 4
        .global clear_page
        .ent clear_page
clear_page:
        .prologue 0

	lda	$0,128
	lda	$1,125
	addq	$16,64,$2
	addq	$16,128,$3

	addq	$16,192,$17
	wh64	($16)
	wh64	($2)
	wh64	($3)

1:	wh64	($17)
	stq	$31,0($16)
	subq	$0,1,$0
	subq	$1,1,$1

	stq	$31,8($16)
	stq	$31,16($16)
	addq	$17,64,$2
	nop

	stq	$31,24($16)
	stq	$31,32($16)
	cmovgt	$1,$2,$17
	nop

	stq	$31,40($16)
	stq	$31,48($16)
	nop
	nop

	stq	$31,56($16)
	addq	$16,64,$16
	nop
	bne	$0,1b

	ret
	nop
	nop
	nop

	.end clear_page
	EXPORT_SYMBOL(clear_page)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/ev6-clear_user.S
 * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
 *
 * Zero user space, handling exceptions as we go.
 *
 * We have to make sure that $0 is always up-to-date and contains the
 * right "bytes left to zero" value (and that it is updated only _after_
 * a successful copy).  There is also some rather minor exception setup
 * stuff.
 *
 * Much of the information about 21264 scheduling/coding comes from:
 *	Compiler Writer's Guide for the Alpha 21264
 *	abbreviated as 'CWG' in other comments here
 *	ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
 * Scheduling notation:
 *	E	- either cluster
 *	U	- upper subcluster; U0 - subcluster U0; U1 - subcluster U1
 *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
 * Try not to change the actual algorithm if possible for consistency.
 * Determining actual stalls (other than slotting) doesn't appear to be easy to do.
 * From perusing the source code context where this routine is called, it is
 * a fair assumption that significant fractions of entire pages are zeroed, so
 * it's going to be worth the effort to hand-unroll a big loop, and use wh64.
 * ASSUMPTION:
 *	The believed purpose of only updating $0 after a store is that a signal
 *	may come along during the execution of this chunk of code, and we don't
 *	want to leave a hole (and we also want to avoid repeating lots of work)
 */

#include <asm/export.h>
/* Allow an exception for an insn; exit if we get one.  */
#define EX(x,y...)			\
	99: x,##y;			\
	.section __ex_table,"a";	\
	.long 99b - .;			\
	lda $31, $exception-99b($31); 	\
	.previous

	.set noat
	.set noreorder
	.align 4

	.globl __clear_user
	.ent __clear_user
	.frame	$30, 0, $26
	.prologue 0

				# Pipeline info : Slotting & Comments
__clear_user:
	and	$17, $17, $0
	and	$16, 7, $4	# .. E  .. ..	: find dest head misalignment
	beq	$0, $zerolength # U  .. .. ..	:  U L U L

	addq	$0, $4, $1	# .. .. .. E	: bias counter
	and	$1, 7, $2	# .. .. E  ..	: number of misaligned bytes in tail
# Note - we never actually use $2, so this is a moot computation
# and we can rewrite this later...
	srl	$1, 3, $1	# .. E  .. ..	: number of quadwords to clear
	beq	$4, $headalign	# U  .. .. ..	: U L U L

/*
 * Head is not aligned.  Write (8 - $4) bytes to head of destination
 * This means $16 is known to be misaligned
 */
	EX( ldq_u $5, 0($16) )	# .. .. .. L	: load dst word to mask back in
	beq	$1, $onebyte	# .. .. U  ..	: sub-word store?
	mskql	$5, $16, $5	# .. U  .. ..	: take care of misaligned head
	addq	$16, 8, $16	# E  .. .. .. 	: L U U L

	EX( stq_u $5, -8($16) )	# .. .. .. L	:
	subq	$1, 1, $1	# .. .. E  ..	:
	addq	$0, $4, $0	# .. E  .. ..	: bytes left -= 8 - misalignment
	subq	$0, 8, $0	# E  .. .. ..	: U L U L

	.align	4
/*
 * (The .align directive ought to be a moot point)
 * values upon initial entry to the loop
 * $1 is number of quadwords to clear (zero is a valid value)
 * $2 is number of trailing bytes (0..7) ($2 never used...)
 * $16 is known to be aligned 0mod8
 */
$headalign:
	subq	$1, 16, $4	# .. .. .. E	: If < 16, we can not use the huge loop
	and	$16, 0x3f, $2	# .. .. E  ..	: Forward work for huge loop
	subq	$2, 0x40, $3	# .. E  .. ..	: bias counter (huge loop)
	blt	$4, $trailquad	# U  .. .. ..	: U L U L

/*
 * We know that we're going to do at least 16 quads, which means we are
 * going to be able to use the large block clear loop at least once.
 * Figure out how many quads we need to clear before we are 0mod64 aligned
 * so we can use the wh64 instruction.
 */

	nop			# .. .. .. E
	nop			# .. .. E  ..
	nop			# .. E  .. ..
	beq	$3, $bigalign	# U  .. .. ..	: U L U L : Aligned 0mod64

$alignmod64:
	EX( stq_u $31, 0($16) )	# .. .. .. L
	addq	$3, 8, $3	# .. .. E  ..
	subq	$0, 8, $0	# .. E  .. ..
	nop			# E  .. .. ..	: U L U L

	nop			# .. .. .. E
	subq	$1, 1, $1	# .. .. E  ..
	addq	$16, 8, $16	# .. E  .. ..
	blt	$3, $alignmod64	# U  .. .. ..	: U L U L

$bigalign:
/*
 * $0 is the number of bytes left
 * $1 is the number of quads left
 * $16 is aligned 0mod64
 * we know that we'll be taking a minimum of one trip through
 * CWG Section 3.7.6: do not expect a sustained store rate of > 1/cycle
 * We are _not_ going to update $0 after every single store.  That
 * would be silly, because there will be cross-cluster dependencies
 * no matter how the code is scheduled.  By doing it in slightly
 * staggered fashion, we can still do this loop in 5 fetches
 * The worse case will be doing two extra quads in some future execution,
 * in the event of an interrupted clear.
 * Assumes the wh64 needs to be for 2 trips through the loop in the future
 * The wh64 is issued on for the starting destination address for trip +2
 * through the loop, and if there are less than two trips left, the target
 * address will be for the current trip.
 */
	nop			# E :
	nop			# E :
	nop			# E :
	bis	$16,$16,$3	# E : U L U L : Initial wh64 address is dest
	/* This might actually help for the current trip... */

$do_wh64:
	wh64	($3)		# .. .. .. L1	: memory subsystem hint
	subq	$1, 16, $4	# .. .. E  ..	: Forward calculation - repeat the loop?
	EX( stq_u $31, 0($16) )	# .. L  .. ..
	subq	$0, 8, $0	# E  .. .. ..	: U L U L

	addq	$16, 128, $3	# E : Target address of wh64
	EX( stq_u $31, 8($16) )	# L :
	EX( stq_u $31, 16($16) )	# L :
	subq	$0, 16, $0	# E : U L L U

	nop			# E :
	EX( stq_u $31, 24($16) )	# L :
	EX( stq_u $31, 32($16) )	# L :
	subq	$0, 168, $5	# E : U L L U : two trips through the loop left?
	/* 168 = 192 - 24, since we've already completed some stores */

	subq	$0, 16, $0	# E :
	EX( stq_u $31, 40($16) )	# L :
	EX( stq_u $31, 48($16) )	# L :
	cmovlt	$5, $16, $3	# E : U L L U : Latency 2, extra mapping cycle

	subq	$1, 8, $1	# E :
	subq	$0, 16, $0	# E :
	EX( stq_u $31, 56($16) )	# L :
	nop			# E : U L U L

	nop			# E :
	subq	$0, 8, $0	# E :
	addq	$16, 64, $16	# E :
	bge	$4, $do_wh64	# U : U L U L

$trailquad:
	# zero to 16 quadwords left to store, plus any trailing bytes
	# $1 is the number of quadwords left to go.
	#
	nop			# .. .. .. E
	nop			# .. .. E  ..
	nop			# .. E  .. ..
	beq	$1, $trailbytes	# U  .. .. ..	: U L U L : Only 0..7 bytes to go

$onequad:
	EX( stq_u $31, 0($16) )	# .. .. .. L
	subq	$1, 1, $1	# .. .. E  ..
	subq	$0, 8, $0	# .. E  .. ..
	nop			# E  .. .. ..	: U L U L

	nop			# .. .. .. E
	nop			# .. .. E  ..
	addq	$16, 8, $16	# .. E  .. ..
	bgt	$1, $onequad	# U  .. .. ..	: U L U L

	# We have an unknown number of bytes left to go.
$trailbytes:
	nop			# .. .. .. E
	nop			# .. .. E  ..
	nop			# .. E  .. ..
	beq	$0, $zerolength	# U  .. .. ..	: U L U L

	# $0 contains the number of bytes left to copy (0..31)
	# so we will use $0 as the loop counter
	# We know for a fact that $0 > 0 zero due to previous context
$onebyte:
	EX( stb $31, 0($16) )	# .. .. .. L
	subq	$0, 1, $0	# .. .. E  ..	:
	addq	$16, 1, $16	# .. E  .. ..	:
	bgt	$0, $onebyte	# U  .. .. ..	: U L U L

$zerolength:
$exception:			# Destination for exception recovery(?)
	nop			# .. .. .. E	:
	nop			# .. .. E  ..	:
	nop			# .. E  .. ..	:
	ret	$31, ($26), 1	# L0 .. .. ..	: L U L U
	.end __clear_user
	EXPORT_SYMBOL(__clear_user)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/ev6-copy_page.S
 *
 * Copy an entire page.
 */

/* The following comparison of this routine vs the normal copy_page.S
   was written by an unnamed ev6 hardware designer and forwarded to me
   via Steven Hobbs <hobbs@steven.zko.dec.com>.

   First Problem: STQ overflows.
   -----------------------------

	It would be nice if EV6 handled every resource overflow efficiently,
	but for some it doesn't.  Including store queue overflows.  It causes
	a trap and a restart of the pipe.

	To get around this we sometimes use (to borrow a term from a VSSAD
	researcher) "aeration".  The idea is to slow the rate at which the
	processor receives valid instructions by inserting nops in the fetch
	path.  In doing so, you can prevent the overflow and actually make
	the code run faster.  You can, of course, take advantage of the fact
	that the processor can fetch at most 4 aligned instructions per cycle.

	I inserted enough nops to force it to take 10 cycles to fetch the
	loop code.  In theory, EV6 should be able to execute this loop in
	9 cycles but I was not able to get it to run that fast -- the initial
	conditions were such that I could not reach this optimum rate on
	(chaotic) EV6.  I wrote the code such that everything would issue
	in order.

   Second Problem: Dcache index matches.
   -------------------------------------

	If you are going to use this routine on random aligned pages, there
	is a 25% chance that the pages will be at the same dcache indices.
	This results in many nasty memory traps without care.

	The solution is to schedule the prefetches to avoid the memory
	conflicts.  I schedule the wh64 prefetches farther ahead of the
	read prefetches to avoid this problem.

   Third Problem: Needs more prefetching.
   --------------------------------------

	In order to improve the code I added deeper prefetching to take the
	most advantage of EV6's bandwidth.

	I also prefetched the read stream. Note that adding the read prefetch
	forced me to add another cycle to the inner-most kernel - up to 11
	from the original 8 cycles per iteration.  We could improve performance
	further by unrolling the loop and doing multiple prefetches per cycle.

   I think that the code below will be very robust and fast code for the
   purposes of copying aligned pages.  It is slower when both source and
   destination pages are in the dcache, but it is my guess that this is
   less important than the dcache miss case.  */

#include <asm/export.h>
	.text
	.align 4
	.global copy_page
	.ent copy_page
copy_page:
	.prologue 0

	/* Prefetch 5 read cachelines; write-hint 10 cache lines.  */
	wh64	($16)
	ldl	$31,0($17)
	ldl	$31,64($17)
	lda	$1,1*64($16)

	wh64	($1)
	ldl	$31,128($17)
	ldl	$31,192($17)
	lda	$1,2*64($16)

	wh64	($1)
	ldl	$31,256($17)
	lda	$18,118
	lda	$1,3*64($16)

	wh64	($1)
	nop
	lda	$1,4*64($16)
	lda	$2,5*64($16)

	wh64	($1)
	wh64	($2)
	lda	$1,6*64($16)
	lda	$2,7*64($16)

	wh64	($1)
	wh64	($2)
	lda	$1,8*64($16)
	lda	$2,9*64($16)

	wh64	($1)
	wh64	($2)
	lda	$19,10*64($16)
	nop

	/* Main prefetching/write-hinting loop.  */
1:	ldq	$0,0($17)
	ldq	$1,8($17)
	unop
	unop

	unop
	unop
	ldq	$2,16($17)
	ldq	$3,24($17)

	ldq	$4,32($17)
	ldq	$5,40($17)
	unop
	unop

	unop
	unop
	ldq	$6,48($17)
	ldq	$7,56($17)

	ldl	$31,320($17)
	unop
	unop
	unop

	/* This gives the extra cycle of aeration above the minimum.  */
	unop
	unop
	unop
	unop

	wh64	($19)
	unop
	unop
	unop

	stq	$0,0($16)
	subq	$18,1,$18
	stq	$1,8($16)
	unop

	unop
	stq	$2,16($16)
	addq	$17,64,$17
	stq	$3,24($16)

	stq	$4,32($16)
	stq	$5,40($16)
	addq	$19,64,$19
	unop

	stq	$6,48($16)
	stq	$7,56($16)
	addq	$16,64,$16
	bne	$18, 1b

	/* Prefetch the final 5 cache lines of the read stream.  */
	lda	$18,10
	ldl	$31,320($17)
	ldl	$31,384($17)
	ldl	$31,448($17)

	ldl	$31,512($17)
	ldl	$31,576($17)
	nop
	nop

	/* Non-prefetching, non-write-hinting cleanup loop for the
	   final 10 cache lines.  */
2:	ldq	$0,0($17)
	ldq	$1,8($17)
	ldq	$2,16($17)
	ldq	$3,24($17)

	ldq	$4,32($17)
	ldq	$5,40($17)
	ldq	$6,48($17)
	ldq	$7,56($17)

	stq	$0,0($16)
	subq	$18,1,$18
	stq	$1,8($16)
	addq	$17,64,$17

	stq	$2,16($16)
	stq	$3,24($16)
	stq	$4,32($16)
	stq	$5,40($16)

	stq	$6,48($16)
	stq	$7,56($16)
	addq	$16,64,$16
	bne	$18, 2b

	ret
	nop
	unop
	nop

	.end copy_page
	EXPORT_SYMBOL(copy_page)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/ev6-copy_user.S
 *
 * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
 *
 * Copy to/from user space, handling exceptions as we go..  This
 * isn't exactly pretty.
 *
 * This is essentially the same as "memcpy()", but with a few twists.
 * Notably, we have to make sure that $0 is always up-to-date and
 * contains the right "bytes left to copy" value (and that it is updated
 * only _after_ a successful copy). There is also some rather minor
 * exception setup stuff..
 *
 * Much of the information about 21264 scheduling/coding comes from:
 *	Compiler Writer's Guide for the Alpha 21264
 *	abbreviated as 'CWG' in other comments here
 *	ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
 * Scheduling notation:
 *	E	- either cluster
 *	U	- upper subcluster; U0 - subcluster U0; U1 - subcluster U1
 *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
 */

#include <asm/export.h>
/* Allow an exception for an insn; exit if we get one.  */
#define EXI(x,y...)			\
	99: x,##y;			\
	.section __ex_table,"a";	\
	.long 99b - .;			\
	lda $31, $exitin-99b($31);	\
	.previous

#define EXO(x,y...)			\
	99: x,##y;			\
	.section __ex_table,"a";	\
	.long 99b - .;			\
	lda $31, $exitout-99b($31);	\
	.previous

	.set noat
	.align 4
	.globl __copy_user
	.ent __copy_user
				# Pipeline info: Slotting & Comments
__copy_user:
	.prologue 0
	mov $18, $0		# .. .. .. E
	subq $18, 32, $1	# .. .. E. ..	: Is this going to be a small copy?
	nop			# .. E  .. ..
	beq $18, $zerolength	# U  .. .. ..	: U L U L

	and $16,7,$3		# .. .. .. E	: is leading dest misalignment
	ble $1, $onebyteloop	# .. .. U  ..	: 1st branch : small amount of data
	beq $3, $destaligned	# .. U  .. ..	: 2nd (one cycle fetcher stall)
	subq $3, 8, $3		# E  .. .. ..	: L U U L : trip counter
/*
 * The fetcher stall also hides the 1 cycle cross-cluster stall for $3 (L --> U)
 * This loop aligns the destination a byte at a time
 * We know we have at least one trip through this loop
 */
$aligndest:
	EXI( ldbu $1,0($17) )	# .. .. .. L	: Keep loads separate from stores
	addq $16,1,$16		# .. .. E  ..	: Section 3.8 in the CWG
	addq $3,1,$3		# .. E  .. ..	:
	nop			# E  .. .. ..	: U L U L

/*
 * the -1 is to compensate for the inc($16) done in a previous quadpack
 * which allows us zero dependencies within either quadpack in the loop
 */
	EXO( stb $1,-1($16) )	# .. .. .. L	:
	addq $17,1,$17		# .. .. E  ..	: Section 3.8 in the CWG
	subq $0,1,$0		# .. E  .. ..	:
	bne $3, $aligndest	# U  .. .. ..	: U L U L

/*
 * If we fell through into here, we have a minimum of 33 - 7 bytes
 * If we arrived via branch, we have a minimum of 32 bytes
 */
$destaligned:
	and $17,7,$1		# .. .. .. E	: Check _current_ source alignment
	bic $0,7,$4		# .. .. E  ..	: number bytes as a quadword loop
	EXI( ldq_u $3,0($17) )	# .. L  .. ..	: Forward fetch for fallthrough code
	beq $1,$quadaligned	# U  .. .. ..	: U L U L

/*
 * In the worst case, we've just executed an ldq_u here from 0($17)
 * and we'll repeat it once if we take the branch
 */

/* Misaligned quadword loop - not unrolled.  Leave it that way. */
$misquad:
	EXI( ldq_u $2,8($17) )	# .. .. .. L	:
	subq $4,8,$4		# .. .. E  ..	:
	extql $3,$17,$3		# .. U  .. ..	:
	extqh $2,$17,$1		# U  .. .. ..	: U U L L

	bis $3,$1,$1		# .. .. .. E	:
	EXO( stq $1,0($16) )	# .. .. L  ..	:
	addq $17,8,$17		# .. E  .. ..	:
	subq $0,8,$0		# E  .. .. ..	: U L L U

	addq $16,8,$16		# .. .. .. E	:
	bis $2,$2,$3		# .. .. E  ..	:
	nop			# .. E  .. ..	:
	bne $4,$misquad		# U  .. .. ..	: U L U L

	nop			# .. .. .. E
	nop			# .. .. E  ..
	nop			# .. E  .. ..
	beq $0,$zerolength	# U  .. .. ..	: U L U L

/* We know we have at least one trip through the byte loop */
	EXI ( ldbu $2,0($17) )	# .. .. .. L	: No loads in the same quad
	addq $16,1,$16		# .. .. E  ..	: as the store (Section 3.8 in CWG)
	nop			# .. E  .. ..	:
	br $31, $dirtyentry	# L0 .. .. ..	: L U U L
/* Do the trailing byte loop load, then hop into the store part of the loop */

/*
 * A minimum of (33 - 7) bytes to do a quad at a time.
 * Based upon the usage context, it's worth the effort to unroll this loop
 * $0 - number of bytes to be moved
 * $4 - number of bytes to move as quadwords
 * $16 is current destination address
 * $17 is current source address
 */
$quadaligned:
	subq	$4, 32, $2	# .. .. .. E	: do not unroll for small stuff
	nop			# .. .. E  ..
	nop			# .. E  .. ..
	blt	$2, $onequad	# U  .. .. ..	: U L U L

/*
 * There is a significant assumption here that the source and destination
 * addresses differ by more than 32 bytes.  In this particular case, a
 * sparsity of registers further bounds this to be a minimum of 8 bytes.
 * But if this isn't met, then the output result will be incorrect.
 * Furthermore, due to a lack of available registers, we really can't
 * unroll this to be an 8x loop (which would enable us to use the wh64
 * instruction memory hint instruction).
 */
$unroll4:
	EXI( ldq $1,0($17) )	# .. .. .. L
	EXI( ldq $2,8($17) )	# .. .. L  ..
	subq	$4,32,$4	# .. E  .. ..
	nop			# E  .. .. ..	: U U L L

	addq	$17,16,$17	# .. .. .. E
	EXO( stq $1,0($16) )	# .. .. L  ..
	EXO( stq $2,8($16) )	# .. L  .. ..
	subq	$0,16,$0	# E  .. .. ..	: U L L U

	addq	$16,16,$16	# .. .. .. E
	EXI( ldq $1,0($17) )	# .. .. L  ..
	EXI( ldq $2,8($17) )	# .. L  .. ..
	subq	$4, 32, $3	# E  .. .. ..	: U U L L : is there enough for another trip?

	EXO( stq $1,0($16) )	# .. .. .. L
	EXO( stq $2,8($16) )	# .. .. L  ..
	subq	$0,16,$0	# .. E  .. ..
	addq	$17,16,$17	# E  .. .. ..	: U L L U

	nop			# .. .. .. E
	nop			# .. .. E  ..
	addq	$16,16,$16	# .. E  .. ..
	bgt	$3,$unroll4	# U  .. .. ..	: U L U L

	nop
	nop
	nop
	beq	$4, $noquads

$onequad:
	EXI( ldq $1,0($17) )
	subq	$4,8,$4
	addq	$17,8,$17
	nop

	EXO( stq $1,0($16) )
	subq	$0,8,$0
	addq	$16,8,$16
	bne	$4,$onequad

$noquads:
	nop
	nop
	nop
	beq $0,$zerolength

/*
 * For small copies (or the tail of a larger copy), do a very simple byte loop.
 * There's no point in doing a lot of complex alignment calculations to try to
 * to quadword stuff for a small amount of data.
 *	$0 - remaining number of bytes left to copy
 *	$16 - current dest addr
 *	$17 - current source addr
 */

$onebyteloop:
	EXI ( ldbu $2,0($17) )	# .. .. .. L	: No loads in the same quad
	addq $16,1,$16		# .. .. E  ..	: as the store (Section 3.8 in CWG)
	nop			# .. E  .. ..	:
	nop			# E  .. .. ..	: U L U L

$dirtyentry:
/*
 * the -1 is to compensate for the inc($16) done in a previous quadpack
 * which allows us zero dependencies within either quadpack in the loop
 */
	EXO ( stb $2,-1($16) )	# .. .. .. L	:
	addq $17,1,$17		# .. .. E  ..	: quadpack as the load
	subq $0,1,$0		# .. E  .. ..	: change count _after_ copy
	bgt $0,$onebyteloop	# U  .. .. ..	: U L U L

$zerolength:
$exitin:
$exitout:			# Destination for exception recovery(?)
	nop			# .. .. .. E
	nop			# .. .. E  ..
	nop			# .. E  .. ..
	ret $31,($26),1		# L0 .. .. ..	: L U L U

	.end __copy_user
	EXPORT_SYMBOL(__copy_user)


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * arch/alpha/lib/ev6-csum_ipv6_magic.S
 * 21264 version contributed by Rick Gorton <rick.gorton@alpha-processor.com>
 *
 * unsigned short csum_ipv6_magic(struct in6_addr *saddr,
 *                                struct in6_addr *daddr,
 *                                __u32 len,
 *                                unsigned short proto,
 *                                unsigned int csum);
 *
 * Much of the information about 21264 scheduling/coding comes from:
 *	Compiler Writer's Guide for the Alpha 21264
 *	abbreviated as 'CWG' in other comments here
 *	ftp.digital.com/pub/Digital/info/semiconductor/literature/dsc-library.html
 * Scheduling notation:
 *	E	- either cluster
 *	U	- upper subcluster; U0 - subcluster U0; U1 - subcluster U1
 *	L	- lower subcluster; L0 - subcluster L0; L1 - subcluster L1
 * Try not to change the actual algorithm if possible for consistency.
 * Determining actual stalls (other than slotting) doesn't appear to be easy to do.
 *
 * unsigned short csum_ipv6_magic(struct in6_addr *saddr,
 *                                struct in6_addr *daddr,
 *                                __u32 len,
 *                                unsigned short proto,
 *                                unsigned int csum);
 *
 * Swap <proto> (takes form 0xaabb)
 * Then shift it left by 48, so result is:
 *	0xbbaa0000 00000000
 * Then turn it back into a sign extended 32-bit item
 *	0xbbaa0000
 *
 * Swap <len> (an unsigned int) using Mike Burrows' 7-instruction sequence
 * (we can't hide the 3-cycle latency of the unpkbw in the 6-instruction sequence)
 * Assume input takes form 0xAABBCCDD
 *
 * Finally, original 'folding' approach is to split the long into 4 unsigned shorts
 * add 4 ushorts, resulting in ushort/carry
 * add carry bits + ushort --> ushort
 * add carry bits + ushort --> ushort (in case the carry results in an overflow)
 * Truncate to a ushort.  (took 13 instructions)
 * From doing some testing, using the approach in checksum.c:from64to16()
 * results in the same outcome:
 * split into 2 uints, add those, generating a ulong
 * add the 3 low ushorts together, generating a uint
 * a final add of the 2 lower ushorts
 * truncating the result.
 *
 * Misalignment handling added by Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 * The cost is 16 instructions (~8 cycles), including two extra loads which
 * may cause additional delay in rare cases (load-load replay traps).
 */

#include <asm/export.h>
	.globl csum_ipv6_magic
	.align 4
	.ent csum_ipv6_magic
	.frame $30,0,$26,0
csum_ipv6_magic:
	.prologue 0

	ldq_u	$0,0($16)	# L : Latency: 3
	inslh	$18,7,$4	# U : 0000000000AABBCC
	ldq_u	$1,8($16)	# L : Latency: 3
	sll	$19,8,$7	# U : U L U L : 0x00000000 00aabb00

	and	$16,7,$6	# E : src misalignment
	ldq_u	$5,15($16)	# L : Latency: 3
	zapnot	$20,15,$20	# U : zero extend incoming csum
	ldq_u	$2,0($17)	# L : U L U L : Latency: 3

	extql	$0,$6,$0	# U :
	extqh	$1,$6,$22	# U :
	ldq_u	$3,8($17)	# L : Latency: 3
	sll	$19,24,$19	# U : U U L U : 0x000000aa bb000000

	cmoveq	$6,$31,$22	# E : src aligned?
	ldq_u	$23,15($17)	# L : Latency: 3
	inswl	$18,3,$18	# U : 000000CCDD000000
	addl	$19,$7,$19	# E : U L U L : <sign bits>bbaabb00

	or	$0,$22,$0	# E : 1st src word complete
	extql	$1,$6,$1	# U :
	or	$18,$4,$18	# E : 000000CCDDAABBCC
	extqh	$5,$6,$5	# U : L U L U

	and	$17,7,$6	# E : dst misalignment
	extql	$2,$6,$2	# U :
	or	$1,$5,$1	# E : 2nd src word complete
	extqh	$3,$6,$22	# U : L U L U :

	cmoveq	$6,$31,$22	# E : dst aligned?
	extql	$3,$6,$3	# U :
	addq	$20,$0,$20	# E : begin summing the words
	extqh	$23,$6,$23	# U : L U L U :

	srl	$18,16,$4	# U : 0000000000CCDDAA
	or	$2,$22,$2	# E : 1st dst word complete
	zap	$19,0x3,$19	# U : <sign bits>bbaa0000
	or	$3,$23,$3	# E : U L U L : 2nd dst word complete

	cmpult	$20,$0,$0	# E :
	addq	$20,$1,$20	# E :
	zapnot	$18,0xa,$18	# U : 00000000DD00BB00
	zap	$4,0xa,$4	# U : U U L L : 0000000000CC00AA

	or	$18,$4,$18	# E : 00000000DDCCBBAA
	nop			# E :
	cmpult	$20,$1,$1	# E :
	addq	$20,$2,$20	# E : U L U L

	cmpult	$20,$2,$2	# E :
	addq	$20,$3,$20	# E :
	cmpult	$20,$3,$3	# E : (1 cycle stall on $20)
	addq	$20,$18,$20	# E : U L U L (1 cycle stall on $20)

	cmpult	$20,$18,$18	# E :
	addq	$20,$19,$20	# E : (1 cycle stall on $20)
	addq	$0,$1,$0	# E : merge the carries back into the csum
	addq	$2,$3,$2	# E :

	cmpult	$20,$19,$19	# E :
	addq	$18,$19,$18	# E : (1 cycle stall on $19)
	addq	$0,$2,$0	# E :
	addq	$20,$18,$20	# E : U L U L :
		/* (1 cycle stall on $18, 2 cycles on $20) */

	addq	$0,$20,$0	# E :
	zapnot	$0,15,$1	# U : Start folding output (1 cycle stall on $0)
	nop			# E :
	srl	$0,32,$0	# U : U L U L : (1 cycle stall on $0)

	addq	$1,$0,$1	# E : Finished generating ulong
	extwl	$1,2,$2		# U : ushort[1] (1 cycle stall on $1)
	zapnot	$1,3,$0		# U : ushort[0] (1 cycle stall on $1)
	extwl	$1,4,$1		# U : ushort[2] (1 cycle stall on $1)

	addq	$0,$2,$0	# E
	addq	$0,$1,$3	# E : Finished generating uint
		/* (1 cycle stall on $0) */
	extwl	$3,2,$1		# U : ushort[1] (1 cycle stall on $3)
	nop			# E : L U L U

	addq	$1,$3,$0	# E : Final carry
	not	$0,$4		# E : complement (1 cycle stall on $0)
	zapnot	$4,3,$0		# U : clear upper garbage bits
		/* (1 cycle stall on $4) */
	ret			# L0 : L U L U

	.end csum_ipv6_magic
	EXPORT_SYMBOL(csum_ipv6_magic)