summaryrefslogtreecommitdiff
path: root/sys/arch/mips64
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2009-09-27 18:20:14 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2009-09-27 18:20:14 +0000
commit44765bc62cb9ce9364fb2e7268c568775adf3852 (patch)
treea5d3922eaa81ead657e7e54fd78b45272c3cb756 /sys/arch/mips64
parentc4e0520e81b513d872bde4f70ff36805d66f64e9 (diff)
Add an implementation of IRIX-compatible cacheflush() routine to mips ports,
needed for gcc -ftrampoline operation as well as by some third-party software. Although the implementation uses the sysarch() sysctl, the wrapper is added to libc as it was a direct system call (which it is on IRIX).
Diffstat (limited to 'sys/arch/mips64')
-rw-r--r--sys/arch/mips64/include/sysarch.h50
-rw-r--r--sys/arch/mips64/mips64/sys_machdep.c78
2 files changed, 126 insertions, 2 deletions
diff --git a/sys/arch/mips64/include/sysarch.h b/sys/arch/mips64/include/sysarch.h
new file mode 100644
index 00000000000..623d7191fca
--- /dev/null
+++ b/sys/arch/mips64/include/sysarch.h
@@ -0,0 +1,50 @@
+/* $OpenBSD: sysarch.h,v 1.1 2009/09/27 18:20:13 miod Exp $ */
+
+/*
+ * Copyright (c) 2009 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _MIPS64_SYSARCH_H_
+#define _MIPS64_SYSARCH_H_
+
+/*
+ * Architecture specific syscalls (mips64)
+ */
+
+#define MIPS64_CACHEFLUSH 0
+
+/*
+ * Argument structure and defines to mimic IRIX cacheflush() system call
+ */
+
+struct mips64_cacheflush_args {
+ vaddr_t va;
+ size_t sz;
+ int which;
+#define ICACHE 0x01
+#define DCACHE 0x02
+#define BCACHE (ICACHE | DCACHE)
+};
+
+#ifndef _KERNEL
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+int cacheflush(void *, int, int);
+int _flush_cache(char *, int, int);
+int sysarch(int, void *);
+__END_DECLS
+#endif /* _KERNEL */
+
+#endif /* _MIPS64_SYSARCH_H_ */
diff --git a/sys/arch/mips64/mips64/sys_machdep.c b/sys/arch/mips64/mips64/sys_machdep.c
index c3c71dbeaa8..e492c10e565 100644
--- a/sys/arch/mips64/mips64/sys_machdep.c
+++ b/sys/arch/mips64/mips64/sys_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_machdep.c,v 1.2 2005/08/01 15:43:12 miod Exp $ */
+/* $OpenBSD: sys_machdep.c,v 1.3 2009/09/27 18:20:13 miod Exp $ */
/*
* Copyright (c) 1992, 1993
@@ -50,6 +50,14 @@
#include <sys/mount.h>
#include <sys/syscallargs.h>
+#include <uvm/uvm.h>
+
+#include <mips64/sysarch.h>
+
+#include <machine/autoconf.h>
+
+int mips64_cacheflush(struct proc *, struct mips64_cacheflush_args *);
+
int
sys_sysarch(p, v, retval)
struct proc *p;
@@ -63,9 +71,75 @@ sys_sysarch(p, v, retval)
int error = 0;
switch(SCARG(uap, op)) {
+ case MIPS64_CACHEFLUSH:
+ {
+ struct mips64_cacheflush_args cfa;
+
+ if ((error = copyin(SCARG(uap, parms), &cfa, sizeof cfa)) != 0)
+ return error;
+ error = mips64_cacheflush(p, &cfa);
+ }
+ break;
default:
error = EINVAL;
break;
}
- return(error);
+
+ return error;
+}
+
+int
+mips64_cacheflush(struct proc *p, struct mips64_cacheflush_args *cfa)
+{
+ vaddr_t va;
+ paddr_t pa;
+ size_t sz, chunk;
+ struct vm_map *map = &p->p_vmspace->vm_map;
+ struct pmap *pm = map->pmap;
+ struct vm_map_entry *entry;
+ int rc = 0;
+
+ /*
+ * Sanity checks.
+ */
+ if ((cfa->which & BCACHE) != cfa->which)
+ return EINVAL;
+
+ if (cfa->which == 0)
+ return 0;
+
+ va = cfa->va;
+ sz = cfa->sz;
+ chunk = PAGE_SIZE - (va & PAGE_MASK);
+ vm_map_lock_read(map);
+ if (va < vm_map_min(map) || va + sz > vm_map_max(map) || va + sz < va)
+ rc = EFAULT;
+ else while (sz != 0) {
+ if (chunk > sz)
+ chunk = sz;
+
+ /*
+ * Check for a resident mapping first, this is faster than
+ * uvm_map_lookup_entry().
+ */
+ if (pmap_extract(pm, va, &pa) != 0) {
+ if (cfa->which & ICACHE)
+ Mips_InvalidateICache(va, chunk);
+ if (cfa->which & DCACHE)
+ Mips_HitSyncDCache(va, chunk);
+ } else {
+ if (uvm_map_lookup_entry(map, va, &entry) == FALSE) {
+ rc = EFAULT;
+ break;
+ }
+ /* else simply not resident at the moment */
+ }
+
+ va += chunk;
+ sz -= chunk;
+ chunk = PAGE_SIZE;
+ }
+ vm_map_unlock_read(map);
+
+ return rc;
}