code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 *	linux/arch/alpha/kernel/machvec_impl.h
 *
 *	Copyright (C) 1997, 1998  Richard Henderson
 *
 * This file has goodies to help simplify instantiation of machine vectors.
 */

/* Whee.  These systems don't have an HAE:
       IRONGATE, MARVEL, POLARIS, TSUNAMI, TITAN, WILDFIRE
   Fix things up for the GENERIC kernel by defining the HAE address
   to be that of the cache. Now we can read and write it as we like.  ;-)  */
#define IRONGATE_HAE_ADDRESS	(&alpha_mv.hae_cache)
#define MARVEL_HAE_ADDRESS	(&alpha_mv.hae_cache)
#define POLARIS_HAE_ADDRESS	(&alpha_mv.hae_cache)
#define TSUNAMI_HAE_ADDRESS	(&alpha_mv.hae_cache)
#define TITAN_HAE_ADDRESS	(&alpha_mv.hae_cache)
#define WILDFIRE_HAE_ADDRESS	(&alpha_mv.hae_cache)

#ifdef CIA_ONE_HAE_WINDOW
#define CIA_HAE_ADDRESS		(&alpha_mv.hae_cache)
#endif
#ifdef MCPCIA_ONE_HAE_WINDOW
#define MCPCIA_HAE_ADDRESS	(&alpha_mv.hae_cache)
#endif
#ifdef T2_ONE_HAE_WINDOW
#define T2_HAE_ADDRESS		(&alpha_mv.hae_cache)
#endif

/* Only a few systems don't define IACK_SC, handling all interrupts through
   the SRM console.  But splitting out that one case from IO() below
   seems like such a pain.  Define this to get things to compile.  */
#define JENSEN_IACK_SC		1
#define T2_IACK_SC		1
#define WILDFIRE_IACK_SC	1 /* FIXME */

/*
 * Some helpful macros for filling in the blanks.
 */

#define CAT1(x,y)  x##y
#define CAT(x,y)   CAT1(x,y)

#define DO_DEFAULT_RTC			.rtc_port = 0x70

#define DO_EV4_MMU							\
	.max_asn =			EV4_MAX_ASN,			\
	.mv_switch_mm =			ev4_switch_mm,			\
	.mv_activate_mm =		ev4_activate_mm,		\
	.mv_flush_tlb_current =		ev4_flush_tlb_current,		\
	.mv_flush_tlb_current_page =	ev4_flush_tlb_current_page

#define DO_EV5_MMU							\
	.max_asn =			EV5_MAX_ASN,			\
	.mv_switch_mm =			ev5_switch_mm,			\
	.mv_activate_mm =		ev5_activate_mm,		\
	.mv_flush_tlb_current =		ev5_flush_tlb_current,		\
	.mv_flush_tlb_current_page =	ev5_flush_tlb_current_page

#define DO_EV6_MMU							\
	.max_asn =			EV6_MAX_ASN,			\
	.mv_switch_mm =			ev5_switch_mm,			\
	.mv_activate_mm =		ev5_activate_mm,		\
	.mv_flush_tlb_current =		ev5_flush_tlb_current,		\
	.mv_flush_tlb_current_page =	ev5_flush_tlb_current_page

#define DO_EV7_MMU							\
	.max_asn =			EV6_MAX_ASN,			\
	.mv_switch_mm =			ev5_switch_mm,			\
	.mv_activate_mm =		ev5_activate_mm,		\
	.mv_flush_tlb_current =		ev5_flush_tlb_current,		\
	.mv_flush_tlb_current_page =	ev5_flush_tlb_current_page

#define IO_LITE(UP,low)							\
	.hae_register =		(unsigned long *) CAT(UP,_HAE_ADDRESS),	\
	.iack_sc =		CAT(UP,_IACK_SC),			\
	.mv_ioread8 =		CAT(low,_ioread8),			\
	.mv_ioread16 =		CAT(low,_ioread16),			\
	.mv_ioread32 =		CAT(low,_ioread32),			\
	.mv_ioread64 =		CAT(low,_ioread64),			\
	.mv_iowrite8 =		CAT(low,_iowrite8),			\
	.mv_iowrite16 =		CAT(low,_iowrite16),			\
	.mv_iowrite32 =		CAT(low,_iowrite32),			\
	.mv_iowrite64 =		CAT(low,_iowrite64),			\
	.mv_readb =		CAT(low,_readb),			\
	.mv_readw =		CAT(low,_readw),			\
	.mv_readl =		CAT(low,_readl),			\
	.mv_readq =		CAT(low,_readq),			\
	.mv_writeb =		CAT(low,_writeb),			\
	.mv_writew =		CAT(low,_writew),			\
	.mv_writel =		CAT(low,_writel),			\
	.mv_writeq =		CAT(low,_writeq),			\
	.mv_ioportmap =		CAT(low,_ioportmap),			\
	.mv_ioremap =		CAT(low,_ioremap),			\
	.mv_iounmap =		CAT(low,_iounmap),			\
	.mv_is_ioaddr =		CAT(low,_is_ioaddr),			\
	.mv_is_mmio =		CAT(low,_is_mmio)			\

#define IO(UP,low)							\
	IO_LITE(UP,low),						\
	.pci_ops =		&CAT(low,_pci_ops),			\
	.mv_pci_tbi =		CAT(low,_pci_tbi)

#define DO_APECS_IO	IO(APECS,apecs)
#define DO_CIA_IO	IO(CIA,cia)
#define DO_IRONGATE_IO	IO(IRONGATE,irongate)
#define DO_LCA_IO	IO(LCA,lca)
#define DO_MARVEL_IO	IO(MARVEL,marvel)
#define DO_MCPCIA_IO	IO(MCPCIA,mcpcia)
#define DO_POLARIS_IO	IO(POLARIS,polaris)
#define DO_T2_IO	IO(T2,t2)
#define DO_TSUNAMI_IO	IO(TSUNAMI,tsunami)
#define DO_TITAN_IO	IO(TITAN,titan)
#define DO_WILDFIRE_IO	IO(WILDFIRE,wildfire)

#define DO_PYXIS_IO	IO_LITE(CIA,cia_bwx), \
			.pci_ops = &cia_pci_ops, \
			.mv_pci_tbi = cia_pci_tbi

/*
 * In a GENERIC kernel, we have lots of these vectors floating about,
 * all but one of which we want to go away.  In a non-GENERIC kernel,
 * we want only one, ever.
 *
 * Accomplish this in the GENERIC kernel by putting all of the vectors
 * in the .init.data section where they'll go away.  We'll copy the
 * one we want to the real alpha_mv vector in setup_arch.
 *
 * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but
 * one of the vectors, which will not reside in .init.data.  We then
 * alias this one vector to alpha_mv, so no copy is needed.
 *
 * Upshot: set __initdata to nothing for non-GENERIC kernels.
 */

#ifdef CONFIG_ALPHA_GENERIC
#define __initmv __initdata
#define ALIAS_MV(x)
#else
#define __initmv __refdata

/* GCC actually has a syntax for defining aliases, but is under some
   delusion that you shouldn't be able to declare it extern somewhere
   else beforehand.  Fine.  We'll do it ourselves.  */
#if 0
#define ALIAS_MV(system) \
  struct alpha_machine_vector alpha_mv __attribute__((alias(#system "_mv"))); \
  EXPORT_SYMBOL(alpha_mv);
#else
#define ALIAS_MV(system) \
  asm(".global alpha_mv\nalpha_mv = " #system "_mv"); \
  EXPORT_SYMBOL(alpha_mv);
#endif
#endif /* GENERIC */


code:
// SPDX-License-Identifier: GPL-2.0-or-later
/*  Kernel module help for Alpha.
    Copyright (C) 2002 Richard Henderson.

*/
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>

#if 0
#define DEBUGP printk
#else
#define DEBUGP(fmt...)
#endif

/* Allocate the GOT at the end of the core sections.  */

struct got_entry {
	struct got_entry *next;
	Elf64_Sxword r_addend;
	int got_offset;
};

static inline void
process_reloc_for_got(Elf64_Rela *rela,
		      struct got_entry *chains, Elf64_Xword *poffset)
{
	unsigned long r_sym = ELF64_R_SYM (rela->r_info);
	unsigned long r_type = ELF64_R_TYPE (rela->r_info);
	Elf64_Sxword r_addend = rela->r_addend;
	struct got_entry *g;

	if (r_type != R_ALPHA_LITERAL)
		return;

	for (g = chains + r_sym; g ; g = g->next)
		if (g->r_addend == r_addend) {
			if (g->got_offset == 0) {
				g->got_offset = *poffset;
				*poffset += 8;
			}
			goto found_entry;
		}

	g = kmalloc (sizeof (*g), GFP_KERNEL);
	g->next = chains[r_sym].next;
	g->r_addend = r_addend;
	g->got_offset = *poffset;
	*poffset += 8;
	chains[r_sym].next = g;

 found_entry:
	/* Trick: most of the ELF64_R_TYPE field is unused.  There are
	   42 valid relocation types, and a 32-bit field.  Co-opt the
	   bits above 256 to store the got offset for this reloc.  */
	rela->r_info |= g->got_offset << 8;
}

int
module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs,
			  char *secstrings, struct module *me)
{
	struct got_entry *chains;
	Elf64_Rela *rela;
	Elf64_Shdr *esechdrs, *symtab, *s, *got;
	unsigned long nsyms, nrela, i;

	esechdrs = sechdrs + hdr->e_shnum;
	symtab = got = NULL;

	/* Find out how large the symbol table is.  Allocate one got_entry
	   head per symbol.  Normally this will be enough, but not always.
	   We'll chain different offsets for the symbol down each head.  */
	for (s = sechdrs; s < esechdrs; ++s)
		if (s->sh_type == SHT_SYMTAB)
			symtab = s;
		else if (!strcmp(".got", secstrings + s->sh_name)) {
			got = s;
			me->arch.gotsecindex = s - sechdrs;
		}

	if (!symtab) {
		printk(KERN_ERR "module %s: no symbol table\n", me->name);
		return -ENOEXEC;
	}
	if (!got) {
		printk(KERN_ERR "module %s: no got section\n", me->name);
		return -ENOEXEC;
	}

	nsyms = symtab->sh_size / sizeof(Elf64_Sym);
	chains = kcalloc(nsyms, sizeof(struct got_entry), GFP_KERNEL);
	if (!chains) {
		printk(KERN_ERR
		       "module %s: no memory for symbol chain buffer\n",
		       me->name);
		return -ENOMEM;
	}

	got->sh_size = 0;
	got->sh_addralign = 8;
	got->sh_type = SHT_NOBITS;

	/* Examine all LITERAL relocations to find out what GOT entries
	   are required.  This sizes the GOT section as well.  */
	for (s = sechdrs; s < esechdrs; ++s)
		if (s->sh_type == SHT_RELA) {
			nrela = s->sh_size / sizeof(Elf64_Rela);
			rela = (void *)hdr + s->sh_offset;
			for (i = 0; i < nrela; ++i)
				process_reloc_for_got(rela+i, chains,
						      &got->sh_size);
		}

	/* Free the memory we allocated.  */
	for (i = 0; i < nsyms; ++i) {
		struct got_entry *g, *n;
		for (g = chains[i].next; g ; g = n) {
			n = g->next;
			kfree(g);
		}
	}
	kfree(chains);

	return 0;
}

int
apply_relocate_add(Elf64_Shdr *sechdrs, const char *strtab,
		   unsigned int symindex, unsigned int relsec,
		   struct module *me)
{
	Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;
	unsigned long i, n = sechdrs[relsec].sh_size / sizeof(*rela);
	Elf64_Sym *symtab, *sym;
	void *base, *location;
	unsigned long got, gp;

	DEBUGP("Applying relocate section %u to %u\n", relsec,
	       sechdrs[relsec].sh_info);

	base = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr;
	symtab = (Elf64_Sym *)sechdrs[symindex].sh_addr;

	/* The small sections were sorted to the end of the segment.
	   The following should definitely cover them.  */
	gp = (u64)me->core_layout.base + me->core_layout.size - 0x8000;
	got = sechdrs[me->arch.gotsecindex].sh_addr;

	for (i = 0; i < n; i++) {
		unsigned long r_sym = ELF64_R_SYM (rela[i].r_info);
		unsigned long r_type = ELF64_R_TYPE (rela[i].r_info);
		unsigned long r_got_offset = r_type >> 8;
		unsigned long value, hi, lo;
		r_type &= 0xff;

		/* This is where to make the change.  */
		location = base + rela[i].r_offset;

		/* This is the symbol it is referring to.  Note that all
		   unresolved symbols have been resolved.  */
		sym = symtab + r_sym;
		value = sym->st_value + rela[i].r_addend;

		switch (r_type) {
		case R_ALPHA_NONE:
			break;
		case R_ALPHA_REFLONG:
			*(u32 *)location = value;
			break;
		case R_ALPHA_REFQUAD:
			/* BUG() can produce misaligned relocations. */
			((u32 *)location)[0] = value;
			((u32 *)location)[1] = value >> 32;
			break;
		case R_ALPHA_GPREL32:
			value -= gp;
			if ((int)value != value)
				goto reloc_overflow;
			*(u32 *)location = value;
			break;
		case R_ALPHA_LITERAL:
			hi = got + r_got_offset;
			lo = hi - gp;
			if ((short)lo != lo)
				goto reloc_overflow;
			*(u16 *)location = lo;
			*(u64 *)hi = value;
			break;
		case R_ALPHA_LITUSE:
			break;
		case R_ALPHA_GPDISP:
			value = gp - (u64)location;
			lo = (short)value;
			hi = (int)(value - lo);
			if (hi + lo != value)
				goto reloc_overflow;
			*(u16 *)location = hi >> 16;
			*(u16 *)(location + rela[i].r_addend) = lo;
			break;
		case R_ALPHA_BRSGP:
			/* BRSGP is only allowed to bind to local symbols.
			   If the section is undef, this means that the
			   value was resolved from somewhere else.  */
			if (sym->st_shndx == SHN_UNDEF)
				goto reloc_overflow;
			if ((sym->st_other & STO_ALPHA_STD_GPLOAD) ==
			    STO_ALPHA_STD_GPLOAD)
				/* Omit the prologue. */
				value += 8;
			fallthrough;
		case R_ALPHA_BRADDR:
			value -= (u64)location + 4;
			if (value & 3)
				goto reloc_overflow;
			value = (long)value >> 2;
			if (value + (1<<21) >= 1<<22)
				goto reloc_overflow;
			value &= 0x1fffff;
			value |= *(u32 *)location & ~0x1fffff;
			*(u32 *)location = value;
			break;
		case R_ALPHA_HINT:
			break;
		case R_ALPHA_SREL32:
			value -= (u64)location;
			if ((int)value != value)
				goto reloc_overflow;
			*(u32 *)location = value;
			break;
		case R_ALPHA_SREL64:
			value -= (u64)location;
			*(u64 *)location = value;
			break;
		case R_ALPHA_GPRELHIGH:
			value = (long)(value - gp + 0x8000) >> 16;
			if ((short) value != value)
				goto reloc_overflow;
			*(u16 *)location = value;
			break;
		case R_ALPHA_GPRELLOW:
			value -= gp;
			*(u16 *)location = value;
			break;
		case R_ALPHA_GPREL16:
			value -= gp;
			if ((short) value != value)
				goto reloc_overflow;
			*(u16 *)location = value;
			break;
		default:
			printk(KERN_ERR "module %s: Unknown relocation: %lu\n",
			       me->name, r_type);
			return -ENOEXEC;
		reloc_overflow:
			if (ELF64_ST_TYPE (sym->st_info) == STT_SECTION)
			  printk(KERN_ERR
			         "module %s: Relocation (type %lu) overflow vs section %d\n",
			         me->name, r_type, sym->st_shndx);
			else
			  printk(KERN_ERR
			         "module %s: Relocation (type %lu) overflow vs %s\n",
			         me->name, r_type, strtab + sym->st_name);
			return -ENOEXEC;
		}
	}

	return 0;
}

repo_name: angery/linux


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

/*
 * This file handles some of the stranger OSF/1 system call interfaces.
 * Some of the system calls expect a non-C calling standard, others have
 * special parameter blocks..
 */

#include <linux/errno.h>
#include <linux/sched/signal.h>
#include <linux/sched/mm.h>
#include <linux/sched/task_stack.h>
#include <linux/sched/cputime.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/utsname.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/major.h>
#include <linux/stat.h>
#include <linux/mman.h>
#include <linux/shm.h>
#include <linux/poll.h>
#include <linux/file.h>
#include <linux/types.h>
#include <linux/ipc.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/uio.h>
#include <linux/vfs.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>

#include <asm/fpu.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <asm/sysinfo.h>
#include <asm/thread_info.h>
#include <asm/hwrpb.h>
#include <asm/processor.h>

/*
 * Brk needs to return an error.  Still support Linux's brk(0) query idiom,
 * which OSF programs just shouldn't be doing.  We're still not quite
 * identical to OSF as we don't return 0 on success, but doing otherwise
 * would require changes to libc.  Hopefully this is good enough.
 */
SYSCALL_DEFINE1(osf_brk, unsigned long, brk)
{
	unsigned long retval = sys_brk(brk);
	if (brk && brk != retval)
		retval = -ENOMEM;
	return retval;
}

/*
 * This is pure guess-work..
 */
SYSCALL_DEFINE4(osf_set_program_attributes, unsigned long, text_start,
		unsigned long, text_len, unsigned long, bss_start,
		unsigned long, bss_len)
{
	struct mm_struct *mm;

	mm = current->mm;
	mm->end_code = bss_start + bss_len;
	mm->start_brk = bss_start + bss_len;
	mm->brk = bss_start + bss_len;
#if 0
	printk("set_program_attributes(%lx %lx %lx %lx)\n",
		text_start, text_len, bss_start, bss_len);
#endif
	return 0;
}

/*
 * OSF/1 directory handling functions...
 *
 * The "getdents()" interface is much more sane: the "basep" stuff is
 * braindamage (it can't really handle filesystems where the directory
 * offset differences aren't the same as "d_reclen").
 */
#define NAME_OFFSET	offsetof (struct osf_dirent, d_name)

struct osf_dirent {
	unsigned int d_ino;
	unsigned short d_reclen;
	unsigned short d_namlen;
	char d_name[1];
};

struct osf_dirent_callback {
	struct dir_context ctx;
	struct osf_dirent __user *dirent;
	long __user *basep;
	unsigned int count;
	int error;
};

static bool
osf_filldir(struct dir_context *ctx, const char *name, int namlen,
	    loff_t offset, u64 ino, unsigned int d_type)
{
	struct osf_dirent __user *dirent;
	struct osf_dirent_callback *buf =
		container_of(ctx, struct osf_dirent_callback, ctx);
	unsigned int reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32));
	unsigned int d_ino;

	buf->error = -EINVAL;	/* only used if we fail */
	if (reclen > buf->count)
		return false;
	d_ino = ino;
	if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
		buf->error = -EOVERFLOW;
		return false;
	}
	if (buf->basep) {
		if (put_user(offset, buf->basep))
			goto Efault;
		buf->basep = NULL;
	}
	dirent = buf->dirent;
	if (put_user(d_ino, &dirent->d_ino) ||
	    put_user(namlen, &dirent->d_namlen) ||
	    put_user(reclen, &dirent->d_reclen) ||
	    copy_to_user(dirent->d_name, name, namlen) ||
	    put_user(0, dirent->d_name + namlen))
		goto Efault;
	dirent = (void __user *)dirent + reclen;
	buf->dirent = dirent;
	buf->count -= reclen;
	return true;
Efault:
	buf->error = -EFAULT;
	return false;
}

SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
		struct osf_dirent __user *, dirent, unsigned int, count,
		long __user *, basep)
{
	int error;
	struct fd arg = fdget_pos(fd);
	struct osf_dirent_callback buf = {
		.ctx.actor = osf_filldir,
		.dirent = dirent,
		.basep = basep,
		.count = count
	};

	if (!arg.file)
		return -EBADF;

	error = iterate_dir(arg.file, &buf.ctx);
	if (error >= 0)
		error = buf.error;
	if (count != buf.count)
		error = count - buf.count;

	fdput_pos(arg);
	return error;
}

#undef NAME_OFFSET

SYSCALL_DEFINE6(osf_mmap, unsigned long, addr, unsigned long, len,
		unsigned long, prot, unsigned long, flags, unsigned long, fd,
		unsigned long, off)
{
	unsigned long ret = -EINVAL;

#if 0
	if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
		printk("%s: unimplemented OSF mmap flags %04lx\n",
			current->comm, flags);
#endif
	if ((off + PAGE_ALIGN(len)) < off)
		goto out;
	if (off & ~PAGE_MASK)
		goto out;
	ret = ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 out:
	return ret;
}

struct osf_stat {
	int		st_dev;
	int		st_pad1;
	unsigned	st_mode;
	unsigned short	st_nlink;
	short		st_nlink_reserved;
	unsigned	st_uid;
	unsigned	st_gid;
	int		st_rdev;
	int		st_ldev;
	long		st_size;
	int		st_pad2;
	int		st_uatime;
	int		st_pad3;
	int		st_umtime;
	int		st_pad4;
	int		st_uctime;
	int		st_pad5;
	int		st_pad6;
	unsigned	st_flags;
	unsigned	st_gen;
	long		st_spare[4];
	unsigned	st_ino;
	int		st_ino_reserved;
	int		st_atime;
	int		st_atime_reserved;
	int		st_mtime;
	int		st_mtime_reserved;
	int		st_ctime;
	int		st_ctime_reserved;
	long		st_blksize;
	long		st_blocks;
};

/*
 * The OSF/1 statfs structure is much larger, but this should
 * match the beginning, at least.
 */
struct osf_statfs {
	short f_type;
	short f_flags;
	int f_fsize;
	int f_bsize;
	int f_blocks;
	int f_bfree;
	int f_bavail;
	int f_files;
	int f_ffree;
	__kernel_fsid_t f_fsid;
};

struct osf_statfs64 {
	short f_type;
	short f_flags;
	int f_pad1;
	int f_pad2;
	int f_pad3;
	int f_pad4;
	int f_pad5;
	int f_pad6;
	int f_pad7;
	__kernel_fsid_t f_fsid;
	u_short f_namemax;
	short f_reserved1;
	int f_spare[8];
	char f_pad8[90];
	char f_pad9[90];
	long mount_info[10];
	u_long f_flags2;
	long f_spare2[14];
	long f_fsize;
	long f_bsize;
	long f_blocks;
	long f_bfree;
	long f_bavail;
	long f_files;
	long f_ffree;
};

static int
linux_to_osf_stat(struct kstat *lstat, struct osf_stat __user *osf_stat)
{
	struct osf_stat tmp = { 0 };

	tmp.st_dev	= lstat->dev;
	tmp.st_mode	= lstat->mode;
	tmp.st_nlink	= lstat->nlink;
	tmp.st_uid	= from_kuid_munged(current_user_ns(), lstat->uid);
	tmp.st_gid	= from_kgid_munged(current_user_ns(), lstat->gid);
	tmp.st_rdev	= lstat->rdev;
	tmp.st_ldev	= lstat->rdev;
	tmp.st_size	= lstat->size;
	tmp.st_uatime	= lstat->atime.tv_nsec / 1000;
	tmp.st_umtime	= lstat->mtime.tv_nsec / 1000;
	tmp.st_uctime	= lstat->ctime.tv_nsec / 1000;
	tmp.st_ino	= lstat->ino;
	tmp.st_atime	= lstat->atime.tv_sec;
	tmp.st_mtime	= lstat->mtime.tv_sec;
	tmp.st_ctime	= lstat->ctime.tv_sec;
	tmp.st_blksize	= lstat->blksize;
	tmp.st_blocks	= lstat->blocks;

	return copy_to_user(osf_stat, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}

static int
linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_stat,
		    unsigned long bufsiz)
{
	struct osf_statfs tmp_stat;

	tmp_stat.f_type = linux_stat->f_type;
	tmp_stat.f_flags = 0;	/* mount flags */
	tmp_stat.f_fsize = linux_stat->f_frsize;
	tmp_stat.f_bsize = linux_stat->f_bsize;
	tmp_stat.f_blocks = linux_stat->f_blocks;
	tmp_stat.f_bfree = linux_stat->f_bfree;
	tmp_stat.f_bavail = linux_stat->f_bavail;
	tmp_stat.f_files = linux_stat->f_files;
	tmp_stat.f_ffree = linux_stat->f_ffree;
	tmp_stat.f_fsid = linux_stat->f_fsid;
	if (bufsiz > sizeof(tmp_stat))
		bufsiz = sizeof(tmp_stat);
	return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
}

static int
linux_to_osf_statfs64(struct kstatfs *linux_stat, struct osf_statfs64 __user *osf_stat,
		      unsigned long bufsiz)
{
	struct osf_statfs64 tmp_stat = { 0 };

	tmp_stat.f_type = linux_stat->f_type;
	tmp_stat.f_fsize = linux_stat->f_frsize;
	tmp_stat.f_bsize = linux_stat->f_bsize;
	tmp_stat.f_blocks = linux_stat->f_blocks;
	tmp_stat.f_bfree = linux_stat->f_bfree;
	tmp_stat.f_bavail = linux_stat->f_bavail;
	tmp_stat.f_files = linux_stat->f_files;
	tmp_stat.f_ffree = linux_stat->f_ffree;
	tmp_stat.f_fsid = linux_stat->f_fsid;
	if (bufsiz > sizeof(tmp_stat))
		bufsiz = sizeof(tmp_stat);
	return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
}

SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
		struct osf_statfs __user *, buffer, unsigned long, bufsiz)
{
	struct kstatfs linux_stat;
	int error = user_statfs(pathname, &linux_stat);
	if (!error)
		error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
	return error;
}

SYSCALL_DEFINE2(osf_stat, char __user *, name, struct osf_stat __user *, buf)
{
	struct kstat stat;
	int error;

	error = vfs_stat(name, &stat);
	if (error)
		return error;

	return linux_to_osf_stat(&stat, buf);
}

SYSCALL_DEFINE2(osf_lstat, char __user *, name, struct osf_stat __user *, buf)
{
	struct kstat stat;
	int error;

	error = vfs_lstat(name, &stat);
	if (error)
		return error;

	return linux_to_osf_stat(&stat, buf);
}

SYSCALL_DEFINE2(osf_fstat, int, fd, struct osf_stat __user *, buf)
{
	struct kstat stat;
	int error;

	error = vfs_fstat(fd, &stat);
	if (error)
		return error;

	return linux_to_osf_stat(&stat, buf);
}

SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,
		struct osf_statfs __user *, buffer, unsigned long, bufsiz)
{
	struct kstatfs linux_stat;
	int error = fd_statfs(fd, &linux_stat);
	if (!error)
		error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
	return error;
}

SYSCALL_DEFINE3(osf_statfs64, char __user *, pathname,
		struct osf_statfs64 __user *, buffer, unsigned long, bufsiz)
{
	struct kstatfs linux_stat;
	int error = user_statfs(pathname, &linux_stat);
	if (!error)
		error = linux_to_osf_statfs64(&linux_stat, buffer, bufsiz);
	return error;
}

SYSCALL_DEFINE3(osf_fstatfs64, unsigned long, fd,
		struct osf_statfs64 __user *, buffer, unsigned long, bufsiz)
{
	struct kstatfs linux_stat;
	int error = fd_statfs(fd, &linux_stat);
	if (!error)
		error = linux_to_osf_statfs64(&linux_stat, buffer, bufsiz);
	return error;
}

/*
 * Uhh.. OSF/1 mount parameters aren't exactly obvious..
 *
 * Although to be frank, neither are the native Linux/i386 ones..
 */
struct ufs_args {
	char __user *devname;
	int flags;
	uid_t exroot;
};

struct cdfs_args {
	char __user *devname;
	int flags;
	uid_t exroot;

	/* This has lots more here, which Linux handles with the option block
	   but I'm too lazy to do the translation into ASCII.  */
};

struct procfs_args {
	char __user *devname;
	int flags;
	uid_t exroot;
};

/*
 * We can't actually handle ufs yet, so we translate UFS mounts to
 * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS
 * layout is so braindead it's a major headache doing it.
 *
 * Just how long ago was it written? OTOH our UFS driver may be still
 * unhappy with OSF UFS. [CHECKME]
 */
static int
osf_ufs_mount(const char __user *dirname,
	      struct ufs_args __user *args, int flags)
{
	int retval;
	struct cdfs_args tmp;
	struct filename *devname;

	retval = -EFAULT;
	if (copy_from_user(&tmp, args, sizeof(tmp)))
		goto out;
	devname = getname(tmp.devname);
	retval = PTR_ERR(devname);
	if (IS_ERR(devname))
		goto out;
	retval = do_mount(devname->name, dirname, "ext2", flags, NULL);
	putname(devname);
 out:
	return retval;
}

static int
osf_cdfs_mount(const char __user *dirname,
	       struct cdfs_args __user *args, int flags)
{
	int retval;
	struct cdfs_args tmp;
	struct filename *devname;

	retval = -EFAULT;
	if (copy_from_user(&tmp, args, sizeof(tmp)))
		goto out;
	devname = getname(tmp.devname);
	retval = PTR_ERR(devname);
	if (IS_ERR(devname))
		goto out;
	retval = do_mount(devname->name, dirname, "iso9660", flags, NULL);
	putname(devname);
 out:
	return retval;
}

static int
osf_procfs_mount(const char __user *dirname,
		 struct procfs_args __user *args, int flags)
{
	struct procfs_args tmp;

	if (copy_from_user(&tmp, args, sizeof(tmp)))
		return -EFAULT;

	return do_mount("", dirname, "proc", flags, NULL);
}

SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, const char __user *, path,
		int, flag, void __user *, data)
{
	int retval;

	switch (typenr) {
	case 1:
		retval = osf_ufs_mount(path, data, flag);
		break;
	case 6:
		retval = osf_cdfs_mount(path, data, flag);
		break;
	case 9:
		retval = osf_procfs_mount(path, data, flag);
		break;
	default:
		retval = -EINVAL;
		printk("osf_mount(%ld, %x)\n", typenr, flag);
	}

	return retval;
}

SYSCALL_DEFINE1(osf_utsname, char __user *, name)
{
	char tmp[5 * 32];

	down_read(&uts_sem);
	memcpy(tmp + 0 * 32, utsname()->sysname, 32);
	memcpy(tmp + 1 * 32, utsname()->nodename, 32);
	memcpy(tmp + 2 * 32, utsname()->release, 32);
	memcpy(tmp + 3 * 32, utsname()->version, 32);
	memcpy(tmp + 4 * 32, utsname()->machine, 32);
	up_read(&uts_sem);

	if (copy_to_user(name, tmp, sizeof(tmp)))
		return -EFAULT;
	return 0;
}

SYSCALL_DEFINE0(getpagesize)
{
	return PAGE_SIZE;
}

SYSCALL_DEFINE0(getdtablesize)
{
	return sysctl_nr_open;
}

/*
 * For compatibility with OSF/1 only.  Use utsname(2) instead.
 */
SYSCALL_DEFINE2(osf_getdomainname, char __user *, name, int, namelen)
{
	int len;
	char *kname;
	char tmp[32];

	if (namelen < 0 || namelen > 32)
		namelen = 32;

	down_read(&uts_sem);
	kname = utsname()->domainname;
	len = strnlen(kname, namelen);
	len = min(len + 1, namelen);
	memcpy(tmp, kname, len);
	up_read(&uts_sem);

	if (copy_to_user(name, tmp, len))
		return -EFAULT;
	return 0;
}

/*
 * The following stuff should move into a header file should it ever
 * be labeled "officially supported."  Right now, there is just enough
 * support to avoid applications (such as tar) printing error
 * messages.  The attributes are not really implemented.
 */

/*
 * Values for Property list entry flag
 */
#define PLE_PROPAGATE_ON_COPY		0x1	/* cp(1) will copy entry
						   by default */
#define PLE_FLAG_MASK			0x1	/* Valid flag values */
#define PLE_FLAG_ALL			-1	/* All flag value */

struct proplistname_args {
	unsigned int pl_mask;
	unsigned int pl_numnames;
	char **pl_names;
};

union pl_args {
	struct setargs {
		char __user *path;
		long follow;
		long nbytes;
		char __user *buf;
	} set;
	struct fsetargs {
		long fd;
		long nbytes;
		char __user *buf;
	} fset;
	struct getargs {
		char __user *path;
		long follow;
		struct proplistname_args __user *name_args;
		long nbytes;
		char __user *buf;
		int __user *min_buf_size;
	} get;
	struct fgetargs {
		long fd;
		struct proplistname_args __user *name_args;
		long nbytes;
		char __user *buf;
		int __user *min_buf_size;
	} fget;
	struct delargs {
		char __user *path;
		long follow;
		struct proplistname_args __user *name_args;
	} del;
	struct fdelargs {
		long fd;
		struct proplistname_args __user *name_args;
	} fdel;
};

enum pl_code {
	PL_SET = 1, PL_FSET = 2,
	PL_GET = 3, PL_FGET = 4,
	PL_DEL = 5, PL_FDEL = 6
};

SYSCALL_DEFINE2(osf_proplist_syscall, enum pl_code, code,
		union pl_args __user *, args)
{
	long error;
	int __user *min_buf_size_ptr;

	switch (code) {
	case PL_SET:
		if (get_user(error, &args->set.nbytes))
			error = -EFAULT;
		break;
	case PL_FSET:
		if (get_user(error, &args->fset.nbytes))
			error = -EFAULT;
		break;
	case PL_GET:
		error = get_user(min_buf_size_ptr, &args->get.min_buf_size);
		if (error)
			break;
		error = put_user(0, min_buf_size_ptr);
		break;
	case PL_FGET:
		error = get_user(min_buf_size_ptr, &args->fget.min_buf_size);
		if (error)
			break;
		error = put_user(0, min_buf_size_ptr);
		break;
	case PL_DEL:
	case PL_FDEL:
		error = 0;
		break;
	default:
		error = -EOPNOTSUPP;
		break;
	}
	return error;
}

SYSCALL_DEFINE2(osf_sigstack, struct sigstack __user *, uss,
		struct sigstack __user *, uoss)
{
	unsigned long usp = rdusp();
	unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size;
	unsigned long oss_os = on_sig_stack(usp);
	int error;

	if (uss) {
		void __user *ss_sp;

		error = -EFAULT;
		if (get_user(ss_sp, &uss->ss_sp))
			goto out;

		/* If the current stack was set with sigaltstack, don't
		   swap stacks while we are on it.  */
		error = -EPERM;
		if (current->sas_ss_sp && on_sig_stack(usp))
			goto out;

		/* Since we don't know the extent of the stack, and we don't
		   track onstack-ness, but rather calculate it, we must
		   presume a size.  Ho hum this interface is lossy.  */
		current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ;
		current->sas_ss_size = SIGSTKSZ;
	}

	if (uoss) {
		error = -EFAULT;
		if (put_user(oss_sp, &uoss->ss_sp) ||
		    put_user(oss_os, &uoss->ss_onstack))
			goto out;
	}

	error = 0;
 out:
	return error;
}

SYSCALL_DEFINE3(osf_sysinfo, int, command, char __user *, buf, long, count)
{
	const char *sysinfo_table[] = {
		utsname()->sysname,
		utsname()->nodename,
		utsname()->release,
		utsname()->version,
		utsname()->machine,
		"alpha",	/* instruction set architecture */
		"dummy",	/* hardware serial number */
		"dummy",	/* hardware manufacturer */
		"dummy",	/* secure RPC domain */
	};
	unsigned long offset;
	const char *res;
	long len;
	char tmp[__NEW_UTS_LEN + 1];

	offset = command-1;
	if (offset >= ARRAY_SIZE(sysinfo_table)) {
		/* Digital UNIX has a few unpublished interfaces here */
		printk("sysinfo(%d)", command);
		return -EINVAL;
	}

	down_read(&uts_sem);
	res = sysinfo_table[offset];
	len = strlen(res)+1;
	if ((unsigned long)len > (unsigned long)count)
		len = count;
	memcpy(tmp, res, len);
	up_read(&uts_sem);
	if (copy_to_user(buf, tmp, len))
		return -EFAULT;
	return 0;
}

SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer,
		unsigned long, nbytes, int __user *, start, void __user *, arg)
{
	unsigned long w;
	struct percpu_struct *cpu;

	switch (op) {
	case GSI_IEEE_FP_CONTROL:
		/* Return current software fp control & status bits.  */
		/* Note that DU doesn't verify available space here.  */

 		w = current_thread_info()->ieee_state & IEEE_SW_MASK;
 		w = swcr_update_status(w, rdfpcr());
		if (put_user(w, (unsigned long __user *) buffer))
			return -EFAULT;
		return 0;

	case GSI_IEEE_STATE_AT_SIGNAL:
		/*
		 * Not sure anybody will ever use this weird stuff.  These
		 * ops can be used (under OSF/1) to set the fpcr that should
		 * be used when a signal handler starts executing.
		 */
		break;

 	case GSI_UACPROC:
		if (nbytes < sizeof(unsigned int))
			return -EINVAL;
		w = current_thread_info()->status & UAC_BITMASK;
		if (put_user(w, (unsigned int __user *)buffer))
			return -EFAULT;
 		return 1;

	case GSI_PROC_TYPE:
		if (nbytes < sizeof(unsigned long))
			return -EINVAL;
		cpu = (struct percpu_struct*)
		  ((char*)hwrpb + hwrpb->processor_offset);
		w = cpu->type;
		if (put_user(w, (unsigned long  __user*)buffer))
			return -EFAULT;
		return 1;

	case GSI_GET_HWRPB:
		if (nbytes > sizeof(*hwrpb))
			return -EINVAL;
		if (copy_to_user(buffer, hwrpb, nbytes) != 0)
			return -EFAULT;
		return 1;

	default:
		break;
	}

	return -EOPNOTSUPP;
}

SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer,
		unsigned long, nbytes, int __user *, start, void __user *, arg)
{
	switch (op) {
	case SSI_IEEE_FP_CONTROL: {
		unsigned long swcr, fpcr;
		unsigned int *state;

		/*
		 * Alpha Architecture Handbook 4.7.7.3:
		 * To be fully IEEE compiant, we must track the current IEEE
		 * exception state in software, because spurious bits can be
		 * set in the trap shadow of a software-complete insn.
		 */

		if (get_user(swcr, (unsigned long __user *)buffer))
			return -EFAULT;
		state = &current_thread_info()->ieee_state;

		/* Update software trap enable bits.  */
		*state = (*state & ~IEEE_SW_MASK) | (swcr & IEEE_SW_MASK);

		/* Update the real fpcr.  */
		fpcr = rdfpcr() & FPCR_DYN_MASK;
		fpcr |= ieee_swcr_to_fpcr(swcr);
		wrfpcr(fpcr);

		return 0;
	}

	case SSI_IEEE_RAISE_EXCEPTION: {
		unsigned long exc, swcr, fpcr, fex;
		unsigned int *state;

		if (get_user(exc, (unsigned long __user *)buffer))
			return -EFAULT;
		state = &current_thread_info()->ieee_state;
		exc &= IEEE_STATUS_MASK;

		/* Update software trap enable bits.  */
 		swcr = (*state & IEEE_SW_MASK) | exc;
		*state |= exc;

		/* Update the real fpcr.  */
		fpcr = rdfpcr();
		fpcr |= ieee_swcr_to_fpcr(swcr);
		wrfpcr(fpcr);

 		/* If any exceptions set by this call, and are unmasked,
		   send a signal.  Old exceptions are not signaled.  */
		fex = (exc >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr;
 		if (fex) {
			int si_code = FPE_FLTUNK;

			if (fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND;
			if (fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES;
			if (fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND;
			if (fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF;
			if (fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV;
			if (fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV;

			send_sig_fault_trapno(SIGFPE, si_code,
				       (void __user *)NULL,  /* FIXME */
				       0, current);
 		}
		return 0;
	}

	case SSI_IEEE_STATE_AT_SIGNAL:
	case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
		/*
		 * Not sure anybody will ever use this weird stuff.  These
		 * ops can be used (under OSF/1) to set the fpcr that should
		 * be used when a signal handler starts executing.
		 */
		break;

 	case SSI_NVPAIRS: {
		unsigned __user *p = buffer;
		unsigned i;

		for (i = 0, p = buffer; i < nbytes; ++i, p += 2) {
			unsigned v, w, status;

			if (get_user(v, p) || get_user(w, p + 1))
 				return -EFAULT;
 			switch (v) {
 			case SSIN_UACPROC:
				w &= UAC_BITMASK;
				status = current_thread_info()->status;
				status = (status & ~UAC_BITMASK) | w;
				current_thread_info()->status = status;
 				break;

 			default:
 				return -EOPNOTSUPP;
 			}
 		}
 		return 0;
	}

	case SSI_LMF:
		return 0;

	default:
		break;
	}

	return -EOPNOTSUPP;
}

/* Translations due to the fact that OSF's time_t is an int.  Which
   affects all sorts of things, like timeval and itimerval.  */

extern struct timezone sys_tz;

struct timeval32
{
    int tv_sec, tv_usec;
};

struct itimerval32
{
    struct timeval32 it_interval;
    struct timeval32 it_value;
};

static inline long
get_tv32(struct timespec64 *o, struct timeval32 __user *i)
{
	struct timeval32 tv;
	if (copy_from_user(&tv, i, sizeof(struct timeval32)))
		return -EFAULT;
	o->tv_sec = tv.tv_sec;
	o->tv_nsec = tv.tv_usec * NSEC_PER_USEC;
	return 0;
}

static inline long
put_tv32(struct timeval32 __user *o, struct timespec64 *i)
{
	return copy_to_user(o, &(struct timeval32){
				.tv_sec = i->tv_sec,
				.tv_usec = i->tv_nsec / NSEC_PER_USEC},
			    sizeof(struct timeval32));
}

static inline long
put_tv_to_tv32(struct timeval32 __user *o, struct __kernel_old_timeval *i)
{
	return copy_to_user(o, &(struct timeval32){
				.tv_sec = i->tv_sec,
				.tv_usec = i->tv_usec},
			    sizeof(struct timeval32));
}

static inline void
jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value)
{
	value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
	value->tv_sec = jiffies / HZ;
}

SYSCALL_DEFINE2(osf_gettimeofday, struct timeval32 __user *, tv,
		struct timezone __user *, tz)
{
	if (tv) {
		struct timespec64 kts;

		ktime_get_real_ts64(&kts);
		if (put_tv32(tv, &kts))
			return -EFAULT;
	}
	if (tz) {
		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
			return -EFAULT;
	}
	return 0;
}

SYSCALL_DEFINE2(osf_settimeofday, struct timeval32 __user *, tv,
		struct timezone __user *, tz)
{
	struct timespec64 kts;
	struct timezone ktz;

 	if (tv) {
		if (get_tv32(&kts, tv))
			return -EFAULT;
	}
	if (tz) {
		if (copy_from_user(&ktz, tz, sizeof(*tz)))
			return -EFAULT;
	}

	return do_sys_settimeofday64(tv ? &kts : NULL, tz ? &ktz : NULL);
}

asmlinkage long sys_ni_posix_timers(void);

SYSCALL_DEFINE2(osf_utimes, const char __user *, filename,
		struct timeval32 __user *, tvs)
{
	struct timespec64 tv[2];

	if (tvs) {
		if (get_tv32(&tv[0], &tvs[0]) ||
		    get_tv32(&tv[1], &tvs[1]))
			return -EFAULT;

		if (tv[0].tv_nsec < 0 || tv[0].tv_nsec >= 1000000000 ||
		    tv[1].tv_nsec < 0 || tv[1].tv_nsec >= 1000000000)
			return -EINVAL;
	}

	return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
}

SYSCALL_DEFINE5(osf_select, int, n, fd_set __user *, inp, fd_set __user *, outp,
		fd_set __user *, exp, struct timeval32 __user *, tvp)
{
	struct timespec64 end_time, *to = NULL;
	if (tvp) {
		struct timespec64 tv;
		to = &end_time;

		if (get_tv32(&tv, tvp))
		    	return -EFAULT;

		if (tv.tv_sec < 0 || tv.tv_nsec < 0)
			return -EINVAL;

		if (poll_select_set_timeout(to, tv.tv_sec, tv.tv_nsec))
			return -EINVAL;

	}

	/* OSF does not copy back the remaining time.  */
	return core_sys_select(n, inp, outp, exp, to);
}

struct rusage32 {
	struct timeval32 ru_utime;	/* user time used */
	struct timeval32 ru_stime;	/* system time used */
	long	ru_maxrss;		/* maximum resident set size */
	long	ru_ixrss;		/* integral shared memory size */
	long	ru_idrss;		/* integral unshared data size */
	long	ru_isrss;		/* integral unshared stack size */
	long	ru_minflt;		/* page reclaims */
	long	ru_majflt;		/* page faults */
	long	ru_nswap;		/* swaps */
	long	ru_inblock;		/* block input operations */
	long	ru_oublock;		/* block output operations */
	long	ru_msgsnd;		/* messages sent */
	long	ru_msgrcv;		/* messages received */
	long	ru_nsignals;		/* signals received */
	long	ru_nvcsw;		/* voluntary context switches */
	long	ru_nivcsw;		/* involuntary " */
};

SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru)
{
	struct rusage32 r;
	u64 utime, stime;
	unsigned long utime_jiffies, stime_jiffies;

	if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
		return -EINVAL;

	memset(&r, 0, sizeof(r));
	switch (who) {
	case RUSAGE_SELF:
		task_cputime(current, &utime, &stime);
		utime_jiffies = nsecs_to_jiffies(utime);
		stime_jiffies = nsecs_to_jiffies(stime);
		jiffies_to_timeval32(utime_jiffies, &r.ru_utime);
		jiffies_to_timeval32(stime_jiffies, &r.ru_stime);
		r.ru_minflt = current->min_flt;
		r.ru_majflt = current->maj_flt;
		break;
	case RUSAGE_CHILDREN:
		utime_jiffies = nsecs_to_jiffies(current->signal->cutime);
		stime_jiffies = nsecs_to_jiffies(current->signal->cstime);
		jiffies_to_timeval32(utime_jiffies, &r.ru_utime);
		jiffies_to_timeval32(stime_jiffies, &r.ru_stime);
		r.ru_minflt = current->signal->cmin_flt;
		r.ru_majflt = current->signal->cmaj_flt;
		break;
	}

	return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
}

SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options,
		struct rusage32 __user *, ur)
{
	struct rusage r;
	long err = kernel_wait4(pid, ustatus, options, &r);
	if (err <= 0)
		return err;
	if (!ur)
		return err;
	if (put_tv_to_tv32(&ur->ru_utime, &r.ru_utime))
		return -EFAULT;
	if (put_tv_to_tv32(&ur->ru_stime, &r.ru_stime))
		return -EFAULT;
	if (copy_to_user(&ur->ru_maxrss, &r.ru_maxrss,
	      sizeof(struct rusage32) - offsetof(struct rusage32, ru_maxrss)))
		return -EFAULT;
	return err;
}

/*
 * I don't know what the parameters are: the first one
 * seems to be a timeval pointer, and I suspect the second
 * one is the time remaining.. Ho humm.. No documentation.
 */
SYSCALL_DEFINE2(osf_usleep_thread, struct timeval32 __user *, sleep,
		struct timeval32 __user *, remain)
{
	struct timespec64 tmp;
	unsigned long ticks;

	if (get_tv32(&tmp, sleep))
		goto fault;

	ticks = timespec64_to_jiffies(&tmp);

	ticks = schedule_timeout_interruptible(ticks);

	if (remain) {
		jiffies_to_timespec64(ticks, &tmp);
		if (put_tv32(remain, &tmp))
			goto fault;
	}

	return 0;
 fault:
	return -EFAULT;
}

struct timex32 {
	unsigned int modes;	/* mode selector */
	long offset;		/* time offset (usec) */
	long freq;		/* frequency offset (scaled ppm) */
	long maxerror;		/* maximum error (usec) */
	long esterror;		/* estimated error (usec) */
	int status;		/* clock command/status */
	long constant;		/* pll time constant */
	long precision;		/* clock precision (usec) (read only) */
	long tolerance;		/* clock frequency tolerance (ppm)
				 * (read only)
				 */
	struct timeval32 time;	/* (read only) */
	long tick;		/* (modified) usecs between clock ticks */

	long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
	long jitter;            /* pps jitter (us) (ro) */
	int shift;              /* interval duration (s) (shift) (ro) */
	long stabil;            /* pps stability (scaled ppm) (ro) */
	long jitcnt;            /* jitter limit exceeded (ro) */
	long calcnt;            /* calibration intervals (ro) */
	long errcnt;            /* calibration errors (ro) */
	long stbcnt;            /* stability limit exceeded (ro) */

	int  :32; int  :32; int  :32; int  :32;
	int  :32; int  :32; int  :32; int  :32;
	int  :32; int  :32; int  :32; int  :32;
};

SYSCALL_DEFINE1(old_adjtimex, struct timex32 __user *, txc_p)
{
	struct __kernel_timex txc;
	int ret;

	/* copy relevant bits of struct timex. */
	if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) ||
	    copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) -
			   offsetof(struct timex32, tick)))
	  return -EFAULT;

	ret = do_adjtimex(&txc);
	if (ret < 0)
	  return ret;

	/* copy back to timex32 */
	if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) ||
	    (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) -
			  offsetof(struct timex32, tick))) ||
	    (put_user(txc.time.tv_sec, &txc_p->time.tv_sec)) ||
	    (put_user(txc.time.tv_usec, &txc_p->time.tv_usec)))
	  return -EFAULT;

	return ret;
}

/* Get an address range which is currently unmapped.  Similar to the
   generic version except that we know how to honor ADDR_LIMIT_32BIT.  */

static unsigned long
arch_get_unmapped_area_1(unsigned long addr, unsigned long len,
		         unsigned long limit)
{
	struct vm_unmapped_area_info info;

	info.flags = 0;
	info.length = len;
	info.low_limit = addr;
	info.high_limit = limit;
	info.align_mask = 0;
	info.align_offset = 0;
	return vm_unmapped_area(&info);
}

unsigned long
arch_get_unmapped_area(struct file *filp, unsigned long addr,
		       unsigned long len, unsigned long pgoff,
		       unsigned long flags)
{
	unsigned long limit;

	/* "32 bit" actually means 31 bit, since pointers sign extend.  */
	if (current->personality & ADDR_LIMIT_32BIT)
		limit = 0x80000000;
	else
		limit = TASK_SIZE;

	if (len > limit)
		return -ENOMEM;

	if (flags & MAP_FIXED)
		return addr;

	/* First, see if the given suggestion fits.

	   The OSF/1 loader (/sbin/loader) relies on us returning an
	   address larger than the requested if one exists, which is
	   a terribly broken way to program.

	   That said, I can see the use in being able to suggest not
	   merely specific addresses, but regions of memory -- perhaps
	   this feature should be incorporated into all ports?  */

	if (addr) {
		addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit);
		if (addr != (unsigned long) -ENOMEM)
			return addr;
	}

	/* Next, try allocating at TASK_UNMAPPED_BASE.  */
	addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE),
					 len, limit);
	if (addr != (unsigned long) -ENOMEM)
		return addr;

	/* Finally, try allocating in low memory.  */
	addr = arch_get_unmapped_area_1 (PAGE_SIZE, len, limit);

	return addr;
}

SYSCALL_DEFINE2(osf_getpriority, int, which, int, who)
{
	int prio = sys_getpriority(which, who);
	if (prio >= 0) {
		/* Return value is the unbiased priority, i.e. 20 - prio.
		   This does result in negative return values, so signal
		   no error */
		force_successful_syscall_return();
		prio = 20 - prio;
	}
	return prio;
}

SYSCALL_DEFINE0(getxuid)
{
	current_pt_regs()->r20 = sys_geteuid();
	return sys_getuid();
}

SYSCALL_DEFINE0(getxgid)
{
	current_pt_regs()->r20 = sys_getegid();
	return sys_getgid();
}

SYSCALL_DEFINE0(getxpid)
{
	current_pt_regs()->r20 = sys_getppid();
	return sys_getpid();
}

SYSCALL_DEFINE0(alpha_pipe)
{
	int fd[2];
	int res = do_pipe_flags(fd, 0);
	if (!res) {
		/* The return values are in $0 and $20.  */
		current_pt_regs()->r20 = fd[1];
		res = fd[0];
	}
	return res;
}

SYSCALL_DEFINE1(sethae, unsigned long, val)
{
	current_pt_regs()->hae = val;
	return 0;
}


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

#include "pc873xx.h"

static unsigned pc873xx_probelist[] = {0x398, 0x26e, 0};

static char *pc873xx_names[] = {
	"PC87303", "PC87306", "PC87312", "PC87332", "PC87334"
};

static unsigned int base, model;

unsigned int __init pc873xx_get_base(void)
{
	return base;
}

char *__init pc873xx_get_model(void)
{
	return pc873xx_names[model];
}

static unsigned char __init pc873xx_read(unsigned int base, int reg)
{
	outb(reg, base);
	return inb(base + 1);
}

static void __init pc873xx_write(unsigned int base, int reg, unsigned char data)
{
	unsigned long flags;

	local_irq_save(flags);
	outb(reg, base);
	outb(data, base + 1);
	outb(data, base + 1);		/* Must be written twice */
	local_irq_restore(flags);
}

int __init pc873xx_probe(void)
{
	int val, index = 0;

	while ((base = pc873xx_probelist[index++])) {

		if (request_region(base, 2, "Super IO PC873xx") == NULL)
			continue;

		val = pc873xx_read(base, REG_SID);
		if ((val & 0xf0) == 0x10) {
			model = PC87332;
			break;
		} else if ((val & 0xf8) == 0x70) {
			model = PC87306;
			break;
		} else if ((val & 0xf8) == 0x50) {
			model = PC87334;
			break;
		} else if ((val & 0xf8) == 0x40) {
			model = PC87303;
			break;
		}

		release_region(base, 2);
	}

	return (base == 0) ? -1 : 1;
}

void __init pc873xx_enable_epp19(void)
{
	unsigned char data;

	printk(KERN_INFO "PC873xx enabling EPP v1.9\n");
	data = pc873xx_read(base, REG_PCR);
	pc873xx_write(base, REG_PCR, (data & 0xFC) | 0x02);
}

void __init pc873xx_enable_ide(void)
{
	unsigned char data;

	printk(KERN_INFO "PC873xx enabling IDE interrupt\n");
	data = pc873xx_read(base, REG_FER);
	pc873xx_write(base, REG_FER, data | 0x40);
}


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

#ifndef _PC873xx_H_
#define _PC873xx_H_

/*
 * Control Register Values
 */
#define REG_FER	0x00
#define REG_FAR	0x01
#define REG_PTR	0x02
#define REG_FCR	0x03
#define REG_PCR	0x04
#define REG_KRR	0x05
#define REG_PMC	0x06
#define REG_TUP	0x07
#define REG_SID	0x08
#define REG_ASC	0x09
#define REG_IRC	0x0e

/*
 * Model numbers
 */
#define PC87303	0
#define PC87306	1
#define PC87312	2
#define PC87332	3
#define PC87334	4

int pc873xx_probe(void);
unsigned int pc873xx_get_base(void);
char *pc873xx_get_model(void);
void pc873xx_enable_epp19(void);
void pc873xx_enable_ide(void);

#endif


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/pci-noop.c
 *
 * Stub PCI interfaces for Jensen-specific kernels.
 */

#include <linux/pci.h>
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/gfp.h>
#include <linux/capability.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/syscalls.h>

#include "proto.h"

/*
 * The PCI controller list.
 */

struct pci_controller *hose_head, **hose_tail = &hose_head;
struct pci_controller *pci_isa_hose;

struct pci_controller * __init
alloc_pci_controller(void)
{
	struct pci_controller *hose;

	hose = memblock_alloc(sizeof(*hose), SMP_CACHE_BYTES);
	if (!hose)
		panic("%s: Failed to allocate %zu bytes\n", __func__,
		      sizeof(*hose));

	*hose_tail = hose;
	hose_tail = &hose->next;

	return hose;
}

struct resource * __init
alloc_resource(void)
{
	void *ptr = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);

	if (!ptr)
		panic("%s: Failed to allocate %zu bytes\n", __func__,
		      sizeof(struct resource));

	return ptr;
}

SYSCALL_DEFINE3(pciconfig_iobase, long, which, unsigned long, bus,
		unsigned long, dfn)
{
	struct pci_controller *hose;

	/* from hose or from bus.devfn */
	if (which & IOBASE_FROM_HOSE) {
		for (hose = hose_head; hose; hose = hose->next)
			if (hose->index == bus)
				break;
		if (!hose)
			return -ENODEV;
	} else {
		/* Special hook for ISA access.  */
		if (bus == 0 && dfn == 0)
			hose = pci_isa_hose;
		else
			return -ENODEV;
	}

	switch (which & ~IOBASE_FROM_HOSE) {
	case IOBASE_HOSE:
		return hose->index;
	case IOBASE_SPARSE_MEM:
		return hose->sparse_mem_base;
	case IOBASE_DENSE_MEM:
		return hose->dense_mem_base;
	case IOBASE_SPARSE_IO:
		return hose->sparse_io_base;
	case IOBASE_DENSE_IO:
		return hose->dense_io_base;
	case IOBASE_ROOT_BUS:
		return hose->bus->number;
	}

	return -EOPNOTSUPP;
}

SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn,
		unsigned long, off, unsigned long, len, void __user *, buf)
{
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
	else
		return -ENODEV;
}

SYSCALL_DEFINE5(pciconfig_write, unsigned long, bus, unsigned long, dfn,
		unsigned long, off, unsigned long, len, void __user *, buf)
{
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
	else
		return -ENODEV;
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 * arch/alpha/kernel/pci-sysfs.c
 *
 * Copyright (C) 2009 Ivan Kokshaysky
 *
 * Alpha PCI resource files.
 *
 * Loosely based on generic HAVE_PCI_MMAP implementation in
 * drivers/pci/pci-sysfs.c
 */

#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/pci.h>

static int hose_mmap_page_range(struct pci_controller *hose,
				struct vm_area_struct *vma,
				enum pci_mmap_state mmap_type, int sparse)
{
	unsigned long base;

	if (mmap_type == pci_mmap_mem)
		base = sparse ? hose->sparse_mem_base : hose->dense_mem_base;
	else
		base = sparse ? hose->sparse_io_base : hose->dense_io_base;

	vma->vm_pgoff += base >> PAGE_SHIFT;

	return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
				  vma->vm_end - vma->vm_start,
				  vma->vm_page_prot);
}

static int __pci_mmap_fits(struct pci_dev *pdev, int num,
			   struct vm_area_struct *vma, int sparse)
{
	unsigned long nr, start, size;
	int shift = sparse ? 5 : 0;

	nr = vma_pages(vma);
	start = vma->vm_pgoff;
	size = ((pci_resource_len(pdev, num) - 1) >> (PAGE_SHIFT - shift)) + 1;

	if (start < size && size - start >= nr)
		return 1;
	WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on %s BAR %d "
		"(size 0x%08lx)\n",
		current->comm, sparse ? " sparse" : "", start, start + nr,
		pci_name(pdev), num, size);
	return 0;
}

/**
 * pci_mmap_resource - map a PCI resource into user memory space
 * @kobj: kobject for mapping
 * @attr: struct bin_attribute for the file being mapped
 * @vma: struct vm_area_struct passed into the mmap
 * @sparse: address space type
 *
 * Use the bus mapping routines to map a PCI resource into userspace.
 *
 * Return: %0 on success, negative error code otherwise
 */
static int pci_mmap_resource(struct kobject *kobj,
			     struct bin_attribute *attr,
			     struct vm_area_struct *vma, int sparse)
{
	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
	struct resource *res = attr->private;
	enum pci_mmap_state mmap_type;
	struct pci_bus_region bar;
	int i;

	for (i = 0; i < PCI_STD_NUM_BARS; i++)
		if (res == &pdev->resource[i])
			break;
	if (i >= PCI_STD_NUM_BARS)
		return -ENODEV;

	if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
		return -EINVAL;

	if (!__pci_mmap_fits(pdev, i, vma, sparse))
		return -EINVAL;

	pcibios_resource_to_bus(pdev->bus, &bar, res);
	vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
	mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;

	return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
}

static int pci_mmap_resource_sparse(struct file *filp, struct kobject *kobj,
				    struct bin_attribute *attr,
				    struct vm_area_struct *vma)
{
	return pci_mmap_resource(kobj, attr, vma, 1);
}

static int pci_mmap_resource_dense(struct file *filp, struct kobject *kobj,
				   struct bin_attribute *attr,
				   struct vm_area_struct *vma)
{
	return pci_mmap_resource(kobj, attr, vma, 0);
}

/**
 * pci_remove_resource_files - cleanup resource files
 * @pdev: pci_dev to cleanup
 *
 * If we created resource files for @dev, remove them from sysfs and
 * free their resources.
 */
void pci_remove_resource_files(struct pci_dev *pdev)
{
	int i;

	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
		struct bin_attribute *res_attr;

		res_attr = pdev->res_attr[i];
		if (res_attr) {
			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
			kfree(res_attr);
		}

		res_attr = pdev->res_attr_wc[i];
		if (res_attr) {
			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
			kfree(res_attr);
		}
	}
}

static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
{
	struct pci_bus_region bar;
	struct pci_controller *hose = pdev->sysdata;
	long dense_offset;
	unsigned long sparse_size;

	pcibios_resource_to_bus(pdev->bus, &bar, &pdev->resource[num]);

	/* All core logic chips have 4G sparse address space, except
	   CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM
	   definitions in asm/core_xxx.h files). This corresponds
	   to 128M or 512M of the bus space. */
	dense_offset = (long)(hose->dense_mem_base - hose->sparse_mem_base);
	sparse_size = dense_offset >= 0x400000000UL ? 0x20000000 : 0x8000000;

	return bar.end < sparse_size;
}

static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
			       char *suffix, struct bin_attribute *res_attr,
			       unsigned long sparse)
{
	size_t size = pci_resource_len(pdev, num);

	sprintf(name, "resource%d%s", num, suffix);
	res_attr->mmap = sparse ? pci_mmap_resource_sparse :
				  pci_mmap_resource_dense;
	res_attr->attr.name = name;
	res_attr->attr.mode = S_IRUSR | S_IWUSR;
	res_attr->size = sparse ? size << 5 : size;
	res_attr->private = &pdev->resource[num];
	return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
}

static int pci_create_attr(struct pci_dev *pdev, int num)
{
	/* allocate attribute structure, piggyback attribute name */
	int retval, nlen1, nlen2 = 0, res_count = 1;
	unsigned long sparse_base, dense_base;
	struct bin_attribute *attr;
	struct pci_controller *hose = pdev->sysdata;
	char *suffix, *attr_name;

	suffix = "";	/* Assume bwx machine, normal resourceN files. */
	nlen1 = 10;

	if (pdev->resource[num].flags & IORESOURCE_MEM) {
		sparse_base = hose->sparse_mem_base;
		dense_base = hose->dense_mem_base;
		if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
			sparse_base = 0;
			suffix = "_dense";
			nlen1 = 16;	/* resourceN_dense */
		}
	} else {
		sparse_base = hose->sparse_io_base;
		dense_base = hose->dense_io_base;
	}

	if (sparse_base) {
		suffix = "_sparse";
		nlen1 = 17;
		if (dense_base) {
			nlen2 = 16;	/* resourceN_dense */
			res_count = 2;
		}
	}

	attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
	if (!attr)
		return -ENOMEM;

	/* Create bwx, sparse or single dense file */
	attr_name = (char *)(attr + res_count);
	pdev->res_attr[num] = attr;
	retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
				     sparse_base);
	if (retval || res_count == 1)
		return retval;

	/* Create dense file */
	attr_name += nlen1;
	attr++;
	pdev->res_attr_wc[num] = attr;
	return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
}

/**
 * pci_create_resource_files - create resource files in sysfs for @pdev
 * @pdev: pci_dev in question
 *
 * Walk the resources in @dev creating files for each resource available.
 *
 * Return: %0 on success, or negative error code
 */
int pci_create_resource_files(struct pci_dev *pdev)
{
	int i;
	int retval;

	/* Expose the PCI resources from this device as files */
	for (i = 0; i < PCI_STD_NUM_BARS; i++) {

		/* skip empty resources */
		if (!pci_resource_len(pdev, i))
			continue;

		retval = pci_create_attr(pdev, i);
		if (retval) {
			pci_remove_resource_files(pdev);
			return retval;
		}
	}
	return 0;
}

/* Legacy I/O bus mapping stuff. */

static int __legacy_mmap_fits(struct pci_controller *hose,
			      struct vm_area_struct *vma,
			      unsigned long res_size, int sparse)
{
	unsigned long nr, start, size;

	nr = vma_pages(vma);
	start = vma->vm_pgoff;
	size = ((res_size - 1) >> PAGE_SHIFT) + 1;

	if (start < size && size - start >= nr)
		return 1;
	WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on hose %d "
		"(size 0x%08lx)\n",
		current->comm, sparse ? " sparse" : "", start, start + nr,
		hose->index, size);
	return 0;
}

static inline int has_sparse(struct pci_controller *hose,
			     enum pci_mmap_state mmap_type)
{
	unsigned long base;

	base = (mmap_type == pci_mmap_mem) ? hose->sparse_mem_base :
					     hose->sparse_io_base;

	return base != 0;
}

int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
			       enum pci_mmap_state mmap_type)
{
	struct pci_controller *hose = bus->sysdata;
	int sparse = has_sparse(hose, mmap_type);
	unsigned long res_size;

	res_size = (mmap_type == pci_mmap_mem) ? bus->legacy_mem->size :
						 bus->legacy_io->size;
	if (!__legacy_mmap_fits(hose, vma, res_size, sparse))
		return -EINVAL;

	return hose_mmap_page_range(hose, vma, mmap_type, sparse);
}

/**
 * pci_adjust_legacy_attr - adjustment of legacy file attributes
 * @bus: bus to create files under
 * @mmap_type: I/O port or memory
 *
 * Adjust file name and size for sparse mappings.
 */
void pci_adjust_legacy_attr(struct pci_bus *bus, enum pci_mmap_state mmap_type)
{
	struct pci_controller *hose = bus->sysdata;

	if (!has_sparse(hose, mmap_type))
		return;

	if (mmap_type == pci_mmap_mem) {
		bus->legacy_mem->attr.name = "legacy_mem_sparse";
		bus->legacy_mem->size <<= 5;
	} else {
		bus->legacy_io->attr.name = "legacy_io_sparse";
		bus->legacy_io->size <<= 5;
	}
	return;
}

/* Legacy I/O bus read/write functions */
int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
{
	struct pci_controller *hose = bus->sysdata;

	port += hose->io_space->start;

	switch(size) {
	case 1:
		*((u8 *)val) = inb(port);
		return 1;
	case 2:
		if (port & 1)
			return -EINVAL;
		*((u16 *)val) = inw(port);
		return 2;
	case 4:
		if (port & 3)
			return -EINVAL;
		*((u32 *)val) = inl(port);
		return 4;
	}
	return -EINVAL;
}

int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
{
	struct pci_controller *hose = bus->sysdata;

	port += hose->io_space->start;

	switch(size) {
	case 1:
		outb(port, val);
		return 1;
	case 2:
		if (port & 1)
			return -EINVAL;
		outw(port, val);
		return 2;
	case 4:
		if (port & 3)
			return -EINVAL;
		outl(port, val);
		return 4;
	}
	return -EINVAL;
}


code:
// SPDX-License-Identifier: GPL-2.0
/*
 *	linux/arch/alpha/kernel/pci.c
 *
 * Extruded from code written by
 *	Dave Rusling (david.rusling@reo.mts.dec.com)
 *	David Mosberger (davidm@cs.arizona.edu)
 */

/* 2.3.x PCI/resources, 1999 Andrea Arcangeli <andrea@suse.de> */

/*
 * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
 *	     PCI-PCI bridges cleanup
 */
#include <linux/string.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/module.h>
#include <linux/cache.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <asm/machvec.h>

#include "proto.h"
#include "pci_impl.h"

/*
 * Some string constants used by the various core logics.
 */

const char *const pci_io_names[] = {
  "PCI IO bus 0", "PCI IO bus 1", "PCI IO bus 2", "PCI IO bus 3",
  "PCI IO bus 4", "PCI IO bus 5", "PCI IO bus 6", "PCI IO bus 7"
};

const char *const pci_mem_names[] = {
  "PCI mem bus 0", "PCI mem bus 1", "PCI mem bus 2", "PCI mem bus 3",
  "PCI mem bus 4", "PCI mem bus 5", "PCI mem bus 6", "PCI mem bus 7"
};

const char pci_hae0_name[] = "HAE0";

/*
 * If PCI_PROBE_ONLY in pci_flags is set, we don't change any PCI resource
 * assignments.
 */

/*
 * The PCI controller list.
 */

struct pci_controller *hose_head, **hose_tail = &hose_head;
struct pci_controller *pci_isa_hose;

/*
 * Quirks.
 */

static void quirk_isa_bridge(struct pci_dev *dev)
{
	dev->class = PCI_CLASS_BRIDGE_ISA << 8;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, quirk_isa_bridge);

static void quirk_cypress(struct pci_dev *dev)
{
	/* The Notorious Cy82C693 chip.  */

	/* The generic legacy mode IDE fixup in drivers/pci/probe.c
	   doesn't work correctly with the Cypress IDE controller as
	   it has non-standard register layout.  Fix that.  */
	if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) {
		dev->resource[2].start = dev->resource[3].start = 0;
		dev->resource[2].end = dev->resource[3].end = 0;
		dev->resource[2].flags = dev->resource[3].flags = 0;
		if (PCI_FUNC(dev->devfn) == 2) {
			dev->resource[0].start = 0x170;
			dev->resource[0].end = 0x177;
			dev->resource[1].start = 0x376;
			dev->resource[1].end = 0x376;
		}
	}

	/* The Cypress bridge responds on the PCI bus in the address range
	   0xffff0000-0xffffffff (conventional x86 BIOS ROM).  There is no
	   way to turn this off.  The bridge also supports several extended
	   BIOS ranges (disabled after power-up), and some consoles do turn
	   them on.  So if we use a large direct-map window, or a large SG
	   window, we must avoid the entire 0xfff00000-0xffffffff region.  */
	if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
		if (__direct_map_base + __direct_map_size >= 0xfff00000UL)
			__direct_map_size = 0xfff00000UL - __direct_map_base;
		else {
			struct pci_controller *hose = dev->sysdata;
			struct pci_iommu_arena *pci = hose->sg_pci;
			if (pci && pci->dma_base + pci->size >= 0xfff00000UL)
				pci->size = 0xfff00000UL - pci->dma_base;
		}
	}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, quirk_cypress);

/* Called for each device after PCI setup is done. */
static void pcibios_fixup_final(struct pci_dev *dev)
{
	unsigned int class = dev->class >> 8;

	if (class == PCI_CLASS_BRIDGE_ISA || class == PCI_CLASS_BRIDGE_EISA) {
		dev->dma_mask = MAX_ISA_DMA_ADDRESS - 1;
		isa_bridge = dev;
	}
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final);

/* Just declaring that the power-of-ten prefixes are actually the
   power-of-two ones doesn't make it true :) */
#define KB			1024
#define MB			(1024*KB)
#define GB			(1024*MB)

resource_size_t
pcibios_align_resource(void *data, const struct resource *res,
		       resource_size_t size, resource_size_t align)
{
	struct pci_dev *dev = data;
	struct pci_controller *hose = dev->sysdata;
	unsigned long alignto;
	resource_size_t start = res->start;

	if (res->flags & IORESOURCE_IO) {
		/* Make sure we start at our min on all hoses */
		if (start - hose->io_space->start < PCIBIOS_MIN_IO)
			start = PCIBIOS_MIN_IO + hose->io_space->start;

		/*
		 * Put everything into 0x00-0xff region modulo 0x400
		 */
		if (start & 0x300)
			start = (start + 0x3ff) & ~0x3ff;
	}
	else if	(res->flags & IORESOURCE_MEM) {
		/* Make sure we start at our min on all hoses */
		if (start - hose->mem_space->start < PCIBIOS_MIN_MEM)
			start = PCIBIOS_MIN_MEM + hose->mem_space->start;

		/*
		 * The following holds at least for the Low Cost
		 * Alpha implementation of the PCI interface:
		 *
		 * In sparse memory address space, the first
		 * octant (16MB) of every 128MB segment is
		 * aliased to the very first 16 MB of the
		 * address space (i.e., it aliases the ISA
		 * memory address space).  Thus, we try to
		 * avoid allocating PCI devices in that range.
		 * Can be allocated in 2nd-7th octant only.
		 * Devices that need more than 112MB of
		 * address space must be accessed through
		 * dense memory space only!
		 */

		/* Align to multiple of size of minimum base.  */
		alignto = max_t(resource_size_t, 0x1000, align);
		start = ALIGN(start, alignto);
		if (hose->sparse_mem_base && size <= 7 * 16*MB) {
			if (((start / (16*MB)) & 0x7) == 0) {
				start &= ~(128*MB - 1);
				start += 16*MB;
				start  = ALIGN(start, alignto);
			}
			if (start/(128*MB) != (start + size - 1)/(128*MB)) {
				start &= ~(128*MB - 1);
				start += (128 + 16)*MB;
				start  = ALIGN(start, alignto);
			}
		}
	}

	return start;
}
#undef KB
#undef MB
#undef GB

static int __init
pcibios_init(void)
{
	if (alpha_mv.init_pci)
		alpha_mv.init_pci();
	return 0;
}

subsys_initcall(pcibios_init);

#ifdef ALPHA_RESTORE_SRM_SETUP
/* Store PCI device configuration left by SRM here. */
struct pdev_srm_saved_conf
{
	struct pdev_srm_saved_conf *next;
	struct pci_dev *dev;
};

static struct pdev_srm_saved_conf *srm_saved_configs;

static void pdev_save_srm_config(struct pci_dev *dev)
{
	struct pdev_srm_saved_conf *tmp;
	static int printed = 0;

	if (!alpha_using_srm || pci_has_flag(PCI_PROBE_ONLY))
		return;

	if (!printed) {
		printk(KERN_INFO "pci: enabling save/restore of SRM state\n");
		printed = 1;
	}

	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
	if (!tmp) {
		printk(KERN_ERR "%s: kmalloc() failed!\n", __func__);
		return;
	}
	tmp->next = srm_saved_configs;
	tmp->dev = dev;

	pci_save_state(dev);

	srm_saved_configs = tmp;
}

void
pci_restore_srm_config(void)
{
	struct pdev_srm_saved_conf *tmp;

	/* No need to restore if probed only. */
	if (pci_has_flag(PCI_PROBE_ONLY))
		return;

	/* Restore SRM config. */
	for (tmp = srm_saved_configs; tmp; tmp = tmp->next) {
		pci_restore_state(tmp->dev);
	}
}
#else
#define pdev_save_srm_config(dev)	do {} while (0)
#endif

void pcibios_fixup_bus(struct pci_bus *bus)
{
	struct pci_dev *dev = bus->self;

	if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
	    (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
		pci_read_bridge_bases(bus);
	}

	list_for_each_entry(dev, &bus->devices, bus_list) {
		pdev_save_srm_config(dev);
	}
}

/*
 *  If we set up a device for bus mastering, we need to check the latency
 *  timer as certain firmware forgets to set it properly, as seen
 *  on SX164 and LX164 with SRM.
 */
void
pcibios_set_master(struct pci_dev *dev)
{
	u8 lat;
	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
	if (lat >= 16) return;
	printk("PCI: Setting latency timer of device %s to 64\n",
							pci_name(dev));
	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
}

void __init
pcibios_claim_one_bus(struct pci_bus *b)
{
	struct pci_dev *dev;
	struct pci_bus *child_bus;

	list_for_each_entry(dev, &b->devices, bus_list) {
		int i;

		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
			struct resource *r = &dev->resource[i];

			if (r->parent || !r->start || !r->flags)
				continue;
			if (pci_has_flag(PCI_PROBE_ONLY) ||
			    (r->flags & IORESOURCE_PCI_FIXED)) {
				if (pci_claim_resource(dev, i) == 0)
					continue;

				pci_claim_bridge_resource(dev, i);
			}
		}
	}

	list_for_each_entry(child_bus, &b->children, node)
		pcibios_claim_one_bus(child_bus);
}

static void __init
pcibios_claim_console_setup(void)
{
	struct pci_bus *b;

	list_for_each_entry(b, &pci_root_buses, node)
		pcibios_claim_one_bus(b);
}

void __init
common_init_pci(void)
{
	struct pci_controller *hose;
	struct list_head resources;
	struct pci_host_bridge *bridge;
	struct pci_bus *bus;
	int ret, next_busno;
	int need_domain_info = 0;
	u32 pci_mem_end;
	u32 sg_base;
	unsigned long end;

	/* Scan all of the recorded PCI controllers.  */
	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
		sg_base = hose->sg_pci ? hose->sg_pci->dma_base : ~0;

		/* Adjust hose mem_space limit to prevent PCI allocations
		   in the iommu windows. */
		pci_mem_end = min((u32)__direct_map_base, sg_base) - 1;
		end = hose->mem_space->start + pci_mem_end;
		if (hose->mem_space->end > end)
			hose->mem_space->end = end;

		INIT_LIST_HEAD(&resources);
		pci_add_resource_offset(&resources, hose->io_space,
					hose->io_space->start);
		pci_add_resource_offset(&resources, hose->mem_space,
					hose->mem_space->start);

		bridge = pci_alloc_host_bridge(0);
		if (!bridge)
			continue;

		list_splice_init(&resources, &bridge->windows);
		bridge->dev.parent = NULL;
		bridge->sysdata = hose;
		bridge->busnr = next_busno;
		bridge->ops = alpha_mv.pci_ops;
		bridge->swizzle_irq = alpha_mv.pci_swizzle;
		bridge->map_irq = alpha_mv.pci_map_irq;

		ret = pci_scan_root_bus_bridge(bridge);
		if (ret) {
			pci_free_host_bridge(bridge);
			continue;
		}

		bus = hose->bus = bridge->bus;
		hose->need_domain_info = need_domain_info;
		next_busno = bus->busn_res.end + 1;
		/* Don't allow 8-bit bus number overflow inside the hose -
		   reserve some space for bridges. */
		if (next_busno > 224) {
			next_busno = 0;
			need_domain_info = 1;
		}
	}

	pcibios_claim_console_setup();

	pci_assign_unassigned_resources();
	for (hose = hose_head; hose; hose = hose->next) {
		bus = hose->bus;
		if (bus)
			pci_bus_add_devices(bus);
	}
}

struct pci_controller * __init
alloc_pci_controller(void)
{
	struct pci_controller *hose;

	hose = memblock_alloc(sizeof(*hose), SMP_CACHE_BYTES);
	if (!hose)
		panic("%s: Failed to allocate %zu bytes\n", __func__,
		      sizeof(*hose));

	*hose_tail = hose;
	hose_tail = &hose->next;

	return hose;
}

struct resource * __init
alloc_resource(void)
{
	void *ptr = memblock_alloc(sizeof(struct resource), SMP_CACHE_BYTES);

	if (!ptr)
		panic("%s: Failed to allocate %zu bytes\n", __func__,
		      sizeof(struct resource));

	return ptr;
}

/* Provide information on locations of various I/O regions in physical
   memory.  Do this on a per-card basis so that we choose the right hose.  */

SYSCALL_DEFINE3(pciconfig_iobase, long, which, unsigned long, bus,
		unsigned long, dfn)
{
	struct pci_controller *hose;
	struct pci_dev *dev;

	/* from hose or from bus.devfn */
	if (which & IOBASE_FROM_HOSE) {
		for(hose = hose_head; hose; hose = hose->next)
			if (hose->index == bus) break;
		if (!hose) return -ENODEV;
	} else {
		/* Special hook for ISA access.  */
		if (bus == 0 && dfn == 0) {
			hose = pci_isa_hose;
		} else {
			dev = pci_get_domain_bus_and_slot(0, bus, dfn);
			if (!dev)
				return -ENODEV;
			hose = dev->sysdata;
			pci_dev_put(dev);
		}
	}

	switch (which & ~IOBASE_FROM_HOSE) {
	case IOBASE_HOSE:
		return hose->index;
	case IOBASE_SPARSE_MEM:
		return hose->sparse_mem_base;
	case IOBASE_DENSE_MEM:
		return hose->dense_mem_base;
	case IOBASE_SPARSE_IO:
		return hose->sparse_io_base;
	case IOBASE_DENSE_IO:
		return hose->dense_io_base;
	case IOBASE_ROOT_BUS:
		return hose->bus->number;
	}

	return -EOPNOTSUPP;
}

/* Destroy an __iomem token.  Not copied from lib/iomap.c.  */

void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
{
	if (__is_mmio(addr))
		iounmap(addr);
}

EXPORT_SYMBOL(pci_iounmap);

/* FIXME: Some boxes have multiple ISA bridges! */
struct pci_dev *isa_bridge;
EXPORT_SYMBOL(isa_bridge);


code:
/* SPDX-License-Identifier: GPL-2.0 */
/*
 *	linux/arch/alpha/kernel/pci_impl.h
 *
 * This file contains declarations and inline functions for interfacing
 * with the PCI initialization routines.
 */

struct pci_dev;
struct pci_controller;
struct pci_iommu_arena;

/*
 * We can't just blindly use 64K for machines with EISA busses; they
 * may also have PCI-PCI bridges present, and then we'd configure the
 * bridge incorrectly.
 *
 * Also, we start at 0x8000 or 0x9000, in hopes to get all devices'
 * IO space areas allocated *before* 0xC000; this is because certain
 * BIOSes (Millennium for one) use PCI Config space "mechanism #2"
 * accesses to probe the bus. If a device's registers appear at 0xC000,
 * it may see an INx/OUTx at that address during BIOS emulation of the
 * VGA BIOS, and some cards, notably Adaptec 2940UW, take mortal offense.
 */

#define EISA_DEFAULT_IO_BASE	0x9000	/* start above 8th slot */
#define DEFAULT_IO_BASE		0x8000	/* start at 8th slot */

/*
 * We try to make the DEFAULT_MEM_BASE addresses *always* have more than
 * a single bit set. This is so that devices like the broken Myrinet card
 * will always have a PCI memory address that will never match a IDSEL
 * address in PCI Config space, which can cause problems with early rev cards.
 */

/*
 * An XL is AVANTI (APECS) family, *but* it has only 27 bits of ISA address
 * that get passed through the PCI<->ISA bridge chip. Although this causes
 * us to set the PCI->Mem window bases lower than normal, we still allocate
 * PCI bus devices' memory addresses *below* the low DMA mapping window,
 * and hope they fit below 64Mb (to avoid conflicts), and so that they can
 * be accessed via SPARSE space.
 *
 * We accept the risk that a broken Myrinet card will be put into a true XL
 * and thus can more easily run into the problem described below.
 */
#define XL_DEFAULT_MEM_BASE ((16+2)*1024*1024) /* 16M to 64M-1 is avail */

/*
 * APECS and LCA have only 34 bits for physical addresses, thus limiting PCI
 * bus memory addresses for SPARSE access to be less than 128Mb.
 */
#define APECS_AND_LCA_DEFAULT_MEM_BASE ((16+2)*1024*1024)

/*
 * Because MCPCIA and T2 core logic support more bits for
 * physical addresses, they should allow an expanded range of SPARSE
 * memory addresses.  However, we do not use them all, in order to
 * avoid the HAE manipulation that would be needed.
 */
#define MCPCIA_DEFAULT_MEM_BASE ((32+2)*1024*1024)
#define T2_DEFAULT_MEM_BASE ((16+1)*1024*1024)

/*
 * Because CIA and PYXIS have more bits for physical addresses,
 * they support an expanded range of SPARSE memory addresses.
 */
#define DEFAULT_MEM_BASE ((128+16)*1024*1024)

/* ??? Experimenting with no HAE for CIA.  */
#define CIA_DEFAULT_MEM_BASE ((32+2)*1024*1024)

#define IRONGATE_DEFAULT_MEM_BASE ((256*8-16)*1024*1024)

#define DEFAULT_AGP_APER_SIZE	(64*1024*1024)

/*
 * A small note about bridges and interrupts.  The DECchip 21050 (and
 * later) adheres to the PCI-PCI bridge specification.  This says that
 * the interrupts on the other side of a bridge are swizzled in the
 * following manner:
 *
 * Dev    Interrupt   Interrupt
 *        Pin on      Pin on
 *        Device      Connector
 *
 *   4    A           A
 *        B           B
 *        C           C
 *        D           D
 *
 *   5    A           B
 *        B           C
 *        C           D
 *        D           A
 *
 *   6    A           C
 *        B           D
 *        C           A
 *        D           B
 *
 *   7    A           D
 *        B           A
 *        C           B
 *        D           C
 *
 *   Where A = pin 1, B = pin 2 and so on and pin=0 = default = A.
 *   Thus, each swizzle is ((pin-1) + (device#-4)) % 4
 *
 *   pci_swizzle_interrupt_pin() swizzles for exactly one bridge.  The routine
 *   pci_common_swizzle() handles multiple bridges.  But there are a
 *   couple boards that do strange things.
 */

/* The following macro is used to implement the table-based irq mapping
   function for all single-bus Alphas.  */

#define COMMON_TABLE_LOOKUP						\
({ long _ctl_ = -1; 							\
   if (slot >= min_idsel && slot <= max_idsel && pin < irqs_per_slot)	\
     _ctl_ = irq_tab[slot - min_idsel][pin];				\
   _ctl_; })

/* A PCI IOMMU allocation arena.  There are typically two of these
   regions per bus.  */
/* ??? The 8400 has a 32-byte pte entry, and the entire table apparently
   lives directly on the host bridge (no tlb?).  We don't support this
   machine, but if we ever did, we'd need to parameterize all this quite
   a bit further.  Probably with per-bus operation tables.  */

struct pci_iommu_arena
{
	spinlock_t lock;
	struct pci_controller *hose;
#define IOMMU_INVALID_PTE 0x2 /* 32:63 bits MBZ */
#define IOMMU_RESERVED_PTE 0xface
	unsigned long *ptes;
	dma_addr_t dma_base;
	unsigned int size;
	unsigned int next_entry;
	unsigned int align_entry;
};

#if defined(CONFIG_ALPHA_SRM) && \
    (defined(CONFIG_ALPHA_CIA) || defined(CONFIG_ALPHA_LCA) || \
     defined(CONFIG_ALPHA_AVANTI))
# define NEED_SRM_SAVE_RESTORE
#else
# undef NEED_SRM_SAVE_RESTORE
#endif

#if defined(CONFIG_ALPHA_GENERIC) || defined(NEED_SRM_SAVE_RESTORE)
# define ALPHA_RESTORE_SRM_SETUP
#else
# undef ALPHA_RESTORE_SRM_SETUP
#endif

#ifdef ALPHA_RESTORE_SRM_SETUP
extern void pci_restore_srm_config(void);
#else
#define pci_restore_srm_config()	do {} while (0)
#endif

/* The hose list.  */
extern struct pci_controller *hose_head, **hose_tail;
extern struct pci_controller *pci_isa_hose;

extern unsigned long alpha_agpgart_size;

extern void common_init_pci(void);
#define common_swizzle pci_common_swizzle
extern struct pci_controller *alloc_pci_controller(void);
extern struct resource *alloc_resource(void);

extern struct pci_iommu_arena *iommu_arena_new_node(int,
						    struct pci_controller *,
					            dma_addr_t, unsigned long,
					            unsigned long);
extern struct pci_iommu_arena *iommu_arena_new(struct pci_controller *,
					       dma_addr_t, unsigned long,
					       unsigned long);
extern const char *const pci_io_names[];
extern const char *const pci_mem_names[];
extern const char pci_hae0_name[];

extern unsigned long size_for_memory(unsigned long max);

extern int iommu_reserve(struct pci_iommu_arena *, long, long);
extern int iommu_release(struct pci_iommu_arena *, long, long);
extern int iommu_bind(struct pci_iommu_arena *, long, long, struct page **);
extern int iommu_unbind(struct pci_iommu_arena *, long, long);