diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-09-27 18:20:14 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-09-27 18:20:14 +0000 |
commit | 44765bc62cb9ce9364fb2e7268c568775adf3852 (patch) | |
tree | a5d3922eaa81ead657e7e54fd78b45272c3cb756 /sys/arch/mips64 | |
parent | c4e0520e81b513d872bde4f70ff36805d66f64e9 (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.h | 50 | ||||
-rw-r--r-- | sys/arch/mips64/mips64/sys_machdep.c | 78 |
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; } |