summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2004-02-01 05:09:50 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2004-02-01 05:09:50 +0000
commitbad76f195320d5f8fe71dd2cdd09b7e6448ae62f (patch)
treec56802223bbfc0fdd07d88de003f59f99c2b72cb
parent208090c7a2e143dac12badc41a13eb79a817928e (diff)
Arm port, NetBSD codebase stripped down, 32bit only support.
-rw-r--r--sys/arch/arm/arm/arm32_machdep.c614
-rw-r--r--sys/arch/arm/arm/arm_machdep.c272
-rw-r--r--sys/arch/arm/arm/ast.c132
-rw-r--r--sys/arch/arm/arm/atomic.S73
-rw-r--r--sys/arch/arm/arm/bcopy_page.S276
-rw-r--r--sys/arch/arm/arm/bcopyinout.S815
-rw-r--r--sys/arch/arm/arm/blockio.S588
-rw-r--r--sys/arch/arm/arm/bootconfig.c128
-rw-r--r--sys/arch/arm/arm/bus_dma.c1070
-rw-r--r--sys/arch/arm/arm/bus_space_asm_generic.S352
-rw-r--r--sys/arch/arm/arm/bus_space_notimpl.S160
-rw-r--r--sys/arch/arm/arm/conf.c525
-rw-r--r--sys/arch/arm/arm/copystr.S229
-rw-r--r--sys/arch/arm/arm/cpu.c587
-rw-r--r--sys/arch/arm/arm/cpufunc.c2168
-rw-r--r--sys/arch/arm/arm/cpufunc_asm.S151
-rw-r--r--sys/arch/arm/arm/cpufunc_asm_armv4.S67
-rw-r--r--sys/arch/arm/arm/cpufunc_asm_sa1.S314
-rw-r--r--sys/arch/arm/arm/cpuswitch.S1172
-rw-r--r--sys/arch/arm/arm/db_disasm.c77
-rw-r--r--sys/arch/arm/arm/db_interface.c476
-rw-r--r--sys/arch/arm/arm/db_machdep.c88
-rw-r--r--sys/arch/arm/arm/db_trace.c208
-rw-r--r--sys/arch/arm/arm/disassem.c682
-rw-r--r--sys/arch/arm/arm/disassem.h49
-rw-r--r--sys/arch/arm/arm/disksubr.c362
-rw-r--r--sys/arch/arm/arm/disksubr_mbr.c208
-rw-r--r--sys/arch/arm/arm/exception.S380
-rw-r--r--sys/arch/arm/arm/fault.c837
-rw-r--r--sys/arch/arm/arm/fiq.c177
-rw-r--r--sys/arch/arm/arm/fiq_subr.S116
-rw-r--r--sys/arch/arm/arm/fusu.S398
-rw-r--r--sys/arch/arm/arm/genassym.cf168
-rw-r--r--sys/arch/arm/arm/in_cksum_arm.S471
-rw-r--r--sys/arch/arm/arm/irq_dispatch.S155
-rw-r--r--sys/arch/arm/arm/locore.S215
-rw-r--r--sys/arch/arm/arm/mem.c249
-rw-r--r--sys/arch/arm/arm/pmap.c5131
-rw-r--r--sys/arch/arm/arm/process_machdep.c225
-rw-r--r--sys/arch/arm/arm/procfs_machdep.c23
-rw-r--r--sys/arch/arm/arm/setcpsr.S79
-rw-r--r--sys/arch/arm/arm/setstack.S93
-rw-r--r--sys/arch/arm/arm/sig_machdep.c384
-rw-r--r--sys/arch/arm/arm/sigcode.S62
-rw-r--r--sys/arch/arm/arm/softintr.c207
-rw-r--r--sys/arch/arm/arm/stubs.c215
-rw-r--r--sys/arch/arm/arm/sys_machdep.c119
-rw-r--r--sys/arch/arm/arm/syscall.c492
-rw-r--r--sys/arch/arm/arm/undefined.c329
-rw-r--r--sys/arch/arm/arm/vectors.S104
-rw-r--r--sys/arch/arm/arm/vm_machdep.c390
-rw-r--r--sys/arch/arm/arm/vm_machdep_arm.c100
-rw-r--r--sys/arch/arm/conf/files.arm141
-rw-r--r--sys/arch/arm/conf/files.footbridge22
-rw-r--r--sys/arch/arm/footbridge/dc21285mem.h90
-rw-r--r--sys/arch/arm/footbridge/dc21285reg.h393
-rw-r--r--sys/arch/arm/footbridge/footbridge.c293
-rw-r--r--sys/arch/arm/footbridge/footbridge.h17
-rw-r--r--sys/arch/arm/footbridge/footbridge_clock.c482
-rw-r--r--sys/arch/arm/footbridge/footbridge_com.c870
-rw-r--r--sys/arch/arm/footbridge/footbridge_com_io.c211
-rw-r--r--sys/arch/arm/footbridge/footbridge_intr.h215
-rw-r--r--sys/arch/arm/footbridge/footbridge_io.c321
-rw-r--r--sys/arch/arm/footbridge/footbridge_irqhandler.c482
-rw-r--r--sys/arch/arm/footbridge/footbridge_irqhandler.h60
-rw-r--r--sys/arch/arm/footbridge/footbridge_machdep.c66
-rw-r--r--sys/arch/arm/footbridge/footbridge_pci.c419
-rw-r--r--sys/arch/arm/footbridge/footbridgevar.h96
-rw-r--r--sys/arch/arm/footbridge/genassym.cf47
-rw-r--r--sys/arch/arm/footbridge/isa/ds1687reg.h129
-rw-r--r--sys/arch/arm/footbridge/isa/dsrtc.c279
-rw-r--r--sys/arch/arm/footbridge/isa/icu.h71
-rw-r--r--sys/arch/arm/footbridge/isa/isa_io.c321
-rw-r--r--sys/arch/arm/footbridge/isa/isa_io_asm.S342
-rw-r--r--sys/arch/arm/footbridge/isa/isa_machdep.c609
-rw-r--r--sys/arch/arm/footbridge/isa/sysbeep_isa.c90
-rw-r--r--sys/arch/arm/footbridge/todclock.c348
-rw-r--r--sys/arch/arm/footbridge/todclockvar.h56
-rw-r--r--sys/arch/arm/include/ansi.h109
-rw-r--r--sys/arch/arm/include/armreg.h353
-rw-r--r--sys/arch/arm/include/asm.h130
-rw-r--r--sys/arch/arm/include/atomic.h103
-rw-r--r--sys/arch/arm/include/blockio.h54
-rw-r--r--sys/arch/arm/include/bus.h1071
-rw-r--r--sys/arch/arm/include/cdefs.h13
-rw-r--r--sys/arch/arm/include/conf.h134
-rw-r--r--sys/arch/arm/include/cpu.h302
-rw-r--r--sys/arch/arm/include/cpuconf.h177
-rw-r--r--sys/arch/arm/include/cpufunc.h524
-rw-r--r--sys/arch/arm/include/db_machdep.h117
-rw-r--r--sys/arch/arm/include/disklabel.h151
-rw-r--r--sys/arch/arm/include/elf_abi.h7
-rw-r--r--sys/arch/arm/include/endian.h8
-rw-r--r--sys/arch/arm/include/fiq.h69
-rw-r--r--sys/arch/arm/include/float.h90
-rw-r--r--sys/arch/arm/include/fp.h87
-rw-r--r--sys/arch/arm/include/frame.h412
-rw-r--r--sys/arch/arm/include/ieee.h191
-rw-r--r--sys/arch/arm/include/ieeefp.h41
-rw-r--r--sys/arch/arm/include/internal_types.h6
-rw-r--r--sys/arch/arm/include/isa_machdep.h193
-rw-r--r--sys/arch/arm/include/katelib.h99
-rw-r--r--sys/arch/arm/include/limits.h54
-rw-r--r--sys/arch/arm/include/lock.h90
-rw-r--r--sys/arch/arm/include/machdep.h27
-rw-r--r--sys/arch/arm/include/math.h4
-rw-r--r--sys/arch/arm/include/param.h241
-rw-r--r--sys/arch/arm/include/pcb.h115
-rw-r--r--sys/arch/arm/include/pci_machdep.h103
-rw-r--r--sys/arch/arm/include/pio.h47
-rw-r--r--sys/arch/arm/include/pmap.h595
-rw-r--r--sys/arch/arm/include/proc.h51
-rw-r--r--sys/arch/arm/include/profile.h107
-rw-r--r--sys/arch/arm/include/pte.h246
-rw-r--r--sys/arch/arm/include/ptrace.h44
-rw-r--r--sys/arch/arm/include/reg.h55
-rw-r--r--sys/arch/arm/include/reloc.h53
-rw-r--r--sys/arch/arm/include/rtc.h84
-rw-r--r--sys/arch/arm/include/setjmp.h87
-rw-r--r--sys/arch/arm/include/signal.h134
-rw-r--r--sys/arch/arm/include/softintr.h106
-rw-r--r--sys/arch/arm/include/spinlock.h10
-rw-r--r--sys/arch/arm/include/swi.h23
-rw-r--r--sys/arch/arm/include/sysarch.h61
-rw-r--r--sys/arch/arm/include/trap.h71
-rw-r--r--sys/arch/arm/include/types.h119
-rw-r--r--sys/arch/arm/include/undefined.h89
-rw-r--r--sys/arch/arm/include/vmparam.h152
-rw-r--r--sys/arch/arm/mainbus/cpu_mainbus.c102
-rw-r--r--sys/arch/arm/mainbus/mainbus.c129
-rw-r--r--sys/arch/arm/mainbus/mainbus.h61
-rw-r--r--sys/arch/arm/mainbus/mainbus_io.c248
-rw-r--r--sys/arch/arm/mainbus/mainbus_io_asm.S113
133 files changed, 37294 insertions, 0 deletions
diff --git a/sys/arch/arm/arm/arm32_machdep.c b/sys/arch/arm/arm/arm32_machdep.c
new file mode 100644
index 00000000000..a045c0b81dc
--- /dev/null
+++ b/sys/arch/arm/arm/arm32_machdep.c
@@ -0,0 +1,614 @@
+/* $OpenBSD: arm32_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: arm32_machdep.c,v 1.42 2003/12/30 12:33:15 pk Exp $^I*/$
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Machine dependant functions for kernel setup
+ *
+ * Created : 17/09/94
+ * Updated : 18/04/01 updated for new wscons
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/reboot.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <sys/buf.h>
+#include <sys/msg.h>
+#include <sys/msgbuf.h>
+#include <sys/device.h>
+#include <uvm/uvm_extern.h>
+#include <sys/sysctl.h>
+
+#include <dev/cons.h>
+
+#include <arm/katelib.h>
+#include <arm/machdep.h>
+#include <machine/bootconfig.h>
+
+#include "rd.h"
+
+struct vm_map *exec_map = NULL;
+struct vm_map *phys_map = NULL;
+
+extern int physmem;
+caddr_t allocsys(caddr_t);
+
+#ifdef NBUF
+int nbuf = NBUF;
+#else
+int nbuf = 0;
+#endif
+
+#ifndef BUFCACHEPERCENT
+#define BUFCACHEPERCENT 5
+#endif
+
+#ifdef BUFPAGES
+int bufpages = BUFPAGES;
+#else
+int bufpages = 0;
+#endif
+int bufcachepercent = BUFCACHEPERCENT;
+
+int cold = 1;
+
+#if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE)
+extern size_t md_root_size; /* Memory disc size */
+#endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */
+
+pv_addr_t kernelstack;
+
+/* the following is used externally (sysctl_hw) */
+char machine[] = MACHINE; /* from <machine/param.h> */
+char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */
+
+/* Our exported CPU info; we can have only one. */
+struct cpu_info cpu_info_store;
+
+caddr_t msgbufaddr;
+extern paddr_t msgbufphys;
+
+int kernel_debug = 0;
+
+struct user *proc0paddr;
+
+/* exported variable to be filled in by the bootloaders */
+char *booted_kernel;
+
+
+/* Prototypes */
+
+void data_abort_handler __P((trapframe_t *frame));
+void prefetch_abort_handler __P((trapframe_t *frame));
+extern void configure __P((void));
+
+/*
+ * arm32_vector_init:
+ *
+ * Initialize the vector page, and select whether or not to
+ * relocate the vectors.
+ *
+ * NOTE: We expect the vector page to be mapped at its expected
+ * destination.
+ */
+void
+arm32_vector_init(vaddr_t va, int which)
+{
+ extern unsigned int page0[], page0_data[];
+ unsigned int *vectors = (int *) va;
+ unsigned int *vectors_data = vectors + (page0_data - page0);
+ int vec;
+
+ /*
+ * Loop through the vectors we're taking over, and copy the
+ * vector's insn and data word.
+ */
+ for (vec = 0; vec < ARM_NVEC; vec++) {
+ if ((which & (1 << vec)) == 0) {
+ /* Don't want to take over this vector. */
+ continue;
+ }
+ vectors[vec] = page0[vec];
+ vectors_data[vec] = page0_data[vec];
+ }
+
+ /* Now sync the vectors. */
+ cpu_icache_sync_range(va, (ARM_NVEC * 2) * sizeof(u_int));
+
+ vector_page = va;
+
+ if (va == ARM_VECTORS_HIGH) {
+ /*
+ * Assume the MD caller knows what it's doing here, and
+ * really does want the vector page relocated.
+ *
+ * Note: This has to be done here (and not just in
+ * cpu_setup()) because the vector page needs to be
+ * accessible *before* cpu_startup() is called.
+ * Think ddb(9) ...
+ *
+ * NOTE: If the CPU control register is not readable,
+ * this will totally fail! We'll just assume that
+ * any system that has high vector support has a
+ * readable CPU control register, for now. If we
+ * ever encounter one that does not, we'll have to
+ * rethink this.
+ */
+ cpu_control(CPU_CONTROL_VECRELOC, CPU_CONTROL_VECRELOC);
+ }
+}
+
+/*
+ * Debug function just to park the CPU
+ */
+
+void
+halt()
+{
+ while (1)
+ cpu_sleep(0);
+}
+
+
+/* Sync the discs and unmount the filesystems */
+
+void
+bootsync(void)
+{
+ static int bootsyncdone = 0;
+
+ if (bootsyncdone) return;
+
+ bootsyncdone = 1;
+
+ /* Make sure we can still manage to do things */
+ if (GetCPSR() & I32_bit) {
+ /*
+ * If we get here then boot has been called without RB_NOSYNC
+ * and interrupts were disabled. This means the boot() call
+ * did not come from a user process e.g. shutdown, but must
+ * have come from somewhere in the kernel.
+ */
+ IRQenable;
+ printf("Warning IRQ's disabled during boot()\n");
+ }
+
+ vfs_shutdown();
+}
+
+/*
+ * void cpu_startup(void)
+ *
+ * Machine dependant startup code.
+ *
+ */
+void
+cpu_startup()
+{
+ u_int loop;
+ paddr_t minaddr;
+ paddr_t maxaddr;
+ caddr_t sysbase;
+ caddr_t size;
+ vsize_t bufsize;
+ int base, residual;
+
+ proc0paddr = (struct user *)kernelstack.pv_va;
+ proc0.p_addr = proc0paddr;
+
+ /* Set the cpu control register */
+ cpu_setup(boot_args);
+
+ /* Lock down zero page */
+ vector_page_setprot(VM_PROT_READ);
+
+ /*
+ * Give pmap a chance to set up a few more things now the vm
+ * is initialised
+ */
+ pmap_postinit();
+
+ /*
+ * Initialize error message buffer (at end of core).
+ */
+
+ /* msgbufphys was setup during the secondary boot strap */
+ for (loop = 0; loop < btoc(MSGBUFSIZE); ++loop)
+ pmap_kenter_pa((vaddr_t)msgbufaddr + loop * PAGE_SIZE,
+ msgbufphys + loop * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE);
+ pmap_update(pmap_kernel());
+ initmsgbuf(msgbufaddr, round_page(MSGBUFSIZE));
+
+ /*
+ * Look at arguments passed to us and compute boothowto.
+ * Default to SINGLE and ASKNAME if no args or
+ * SINGLE and DFLTROOT if this is a ramdisk kernel.
+ */
+#ifdef RAMDISK_HOOKS
+ boothowto = RB_SINGLE | RB_DFLTROOT;
+#else
+ boothowto = RB_AUTOBOOT;
+#endif /* RAMDISK_HOOKS */
+
+ /*
+ * Identify ourselves for the msgbuf (everything printed earlier will
+ * not be buffered).
+ */
+ printf(version);
+
+ printf("real mem = %u (%uK)\n", ctob(physmem), ctob(physmem)/1024);
+
+
+ /*
+ * Find out how much space we need, allocate it,
+ * and then give everything true virtual addresses.
+ */
+ size = allocsys(NULL);
+ sysbase = (caddr_t)uvm_km_zalloc(kernel_map, round_page((vaddr_t)size));
+ if (sysbase == 0)
+ panic(
+ "cpu_startup: no room for system tables; %d bytes required",
+ (u_int)size);
+ if ((caddr_t)((allocsys(sysbase) - sysbase)) != size)
+ panic("cpu_startup: system table size inconsistency");
+
+ /*
+ * Now allocate buffers proper. They are different than the above
+ * in that they usually occupy more virtual memory than physical.
+ */
+ bufsize = MAXBSIZE * nbuf;
+ if (uvm_map(kernel_map, (vaddr_t *)&buffers, round_page(bufsize),
+ NULL, UVM_UNKNOWN_OFFSET, 0,
+ UVM_MAPFLAG(UVM_PROT_NONE, UVM_PROT_NONE, UVM_INH_NONE,
+ UVM_ADV_NORMAL, 0)) != 0)
+ panic("cpu_startup: cannot allocate UVM space for buffers");
+ minaddr = (vaddr_t)buffers;
+ if ((bufpages / nbuf) >= btoc(MAXBSIZE)) {
+ /* don't want to alloc more physical mem than needed */
+ bufpages = btoc(MAXBSIZE) * nbuf;
+ }
+
+ base = bufpages / nbuf;
+ residual = bufpages % nbuf;
+ for (loop = 0; loop < nbuf; ++loop) {
+ vsize_t curbufsize;
+ vaddr_t curbuf;
+ struct vm_page *pg;
+
+ /*
+ * Each buffer has MAXBSIZE bytes of VM space allocated. Of
+ * that MAXBSIZE space, we allocate and map (base+1) pages
+ * for the first "residual" buffers, and then we allocate
+ * "base" pages for the rest.
+ */
+ curbuf = (vaddr_t) buffers + (loop * MAXBSIZE);
+ curbufsize = NBPG * ((loop < residual) ? (base+1) : base);
+
+ while (curbufsize) {
+ pg = uvm_pagealloc(NULL, 0, NULL, 0);
+ if (pg == NULL)
+ panic("cpu_startup: not enough memory for buffer cache");
+ pmap_kenter_pa(curbuf, VM_PAGE_TO_PHYS(pg),
+ VM_PROT_READ|VM_PROT_WRITE);
+ curbuf += PAGE_SIZE;
+ curbufsize -= PAGE_SIZE;
+ }
+ }
+ pmap_update(pmap_kernel());
+
+ /*
+ * Allocate a submap for exec arguments. This map effectively
+ * limits the number of processes exec'ing at any time.
+ */
+ exec_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
+ 16*NCARGS, VM_MAP_PAGEABLE, FALSE, NULL);
+
+ /*
+ * Allocate a submap for physio
+ */
+ phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
+ VM_PHYS_SIZE, 0, FALSE, NULL);
+
+ /*
+ * Set up buffers, so they can be used to read disk labels.
+ */
+ bufinit();
+
+ printf("avail mem = %lu (%uK)\n", ptoa(uvmexp.free),
+ ptoa(uvmexp.free)/1024);
+ printf("using %d buffers containing %u bytes (%uK) of memory\n",
+ nbuf, bufpages * PAGE_SIZE, bufpages * PAGE_SIZE / 1024);
+
+ curpcb = &proc0.p_addr->u_pcb;
+ curpcb->pcb_flags = 0;
+ curpcb->pcb_un.un_32.pcb32_und_sp = (u_int)proc0.p_addr +
+ USPACE_UNDEF_STACK_TOP;
+ curpcb->pcb_un.un_32.pcb32_sp = (u_int)proc0.p_addr +
+ USPACE_SVC_STACK_TOP;
+ pmap_set_pcb_pagedir(pmap_kernel(), curpcb);
+
+ curpcb->pcb_tf = (struct trapframe *)curpcb->pcb_un.un_32.pcb32_sp - 1;
+}
+
+/*
+ * machine dependent system variables.
+ */
+
+int
+cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
+ int *name;
+ u_int namelen;
+ void *oldp;
+ size_t *oldlenp;
+ void *newp;
+ size_t newlen;
+ struct proc *p;
+{
+ /* all sysctl names at this level are terminal */
+ if (namelen != 1)
+ return (ENOTDIR); /* overloaded */
+
+ switch (name[0]) {
+ case CPU_DEBUG:
+ return(sysctl_int(oldp, oldlenp, newp, newlen, &kernel_debug));
+
+#if 0
+ case CPU_BOOTED_DEVICE:
+ if (booted_device != NULL)
+ return (sysctl_rdstring(oldp, oldlenp, newp,
+ booted_device->dv_xname));
+ return (EOPNOTSUPP);
+#endif
+
+ case CPU_CONSDEV: {
+ dev_t consdev;
+ if (cn_tab != NULL)
+ consdev = cn_tab->cn_dev;
+ else
+ consdev = NODEV;
+ return (sysctl_rdstruct(oldp, oldlenp, newp, &consdev,
+ sizeof consdev));
+ }
+ case CPU_BOOTED_KERNEL: {
+ if (booted_kernel != NULL && booted_kernel[0] != '\0')
+ return sysctl_rdstring(oldp, oldlenp, newp,
+ booted_kernel);
+ return (EOPNOTSUPP);
+ }
+
+ default:
+ return (EOPNOTSUPP);
+ }
+ /* NOTREACHED */
+}
+
+#if 0
+/*
+ * machine dependent system variables.
+ */
+static int
+sysctl_machdep_booted_device(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+
+ if (booted_device == NULL)
+ return (EOPNOTSUPP);
+
+ node = *rnode;
+ node.sysctl_data = booted_device->dv_xname;
+ node.sysctl_size = strlen(booted_device->dv_xname) + 1;
+ return (sysctl_lookup(SYSCTLFN_CALL(&node)));
+}
+
+static int
+sysctl_machdep_booted_kernel(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+
+ if (booted_kernel == NULL || booted_kernel[0] == '\0')
+ return (EOPNOTSUPP);
+
+ node = *rnode;
+ node.sysctl_data = booted_kernel;
+ node.sysctl_size = strlen(booted_kernel) + 1;
+ return (sysctl_lookup(SYSCTLFN_CALL(&node)));
+}
+
+static int
+sysctl_machdep_powersave(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node = *rnode;
+ int error, newval;
+
+ newval = cpu_do_powersave;
+ node.sysctl_data = &newval;
+ if (cpufuncs.cf_sleep == (void *) cpufunc_nullop)
+ node.sysctl_flags &= ~SYSCTL_READWRITE;
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp == NULL || newval == cpu_do_powersave)
+ return (error);
+
+ if (newval < 0 || newval > 1)
+ return (EINVAL);
+ cpu_do_powersave = newval;
+
+ return (0);
+}
+
+SYSCTL_SETUP(sysctl_machdep_setup, "sysctl machdep subtree setup")
+{
+
+ sysctl_createv(SYSCTL_PERMANENT,
+ CTLTYPE_NODE, "machdep", NULL,
+ NULL, 0, NULL, 0,
+ CTL_MACHDEP, CTL_EOL);
+
+ sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE,
+ CTLTYPE_INT, "debug", NULL,
+ NULL, 0, &kernel_debug, 0,
+ CTL_MACHDEP, CPU_DEBUG, CTL_EOL);
+ sysctl_createv(SYSCTL_PERMANENT,
+ CTLTYPE_STRING, "booted_device", NULL,
+ sysctl_machdep_booted_device, 0, NULL, 0,
+ CTL_MACHDEP, CPU_BOOTED_DEVICE, CTL_EOL);
+ sysctl_createv(SYSCTL_PERMANENT,
+ CTLTYPE_STRING, "booted_kernel", NULL,
+ sysctl_machdep_booted_kernel, 0, NULL, 0,
+ CTL_MACHDEP, CPU_BOOTED_KERNEL, CTL_EOL);
+ sysctl_createv(SYSCTL_PERMANENT,
+ CTLTYPE_STRUCT, "console_device", NULL,
+ sysctl_consdev, 0, NULL, sizeof(dev_t),
+ CTL_MACHDEP, CPU_CONSDEV, CTL_EOL);
+ sysctl_createv(SYSCTL_PERMANENT|SYSCTL_READWRITE,
+ CTLTYPE_INT, "powersave", NULL,
+ sysctl_machdep_powersave, 0, &cpu_do_powersave, 0,
+ CTL_MACHDEP, CPU_POWERSAVE, CTL_EOL);
+}
+#endif
+
+#if 0
+void
+parse_mi_bootargs(args)
+ char *args;
+{
+ int integer;
+
+ if (get_bootconf_option(args, "single", BOOTOPT_TYPE_BOOLEAN, &integer)
+ || get_bootconf_option(args, "-s", BOOTOPT_TYPE_BOOLEAN, &integer))
+ if (integer)
+ boothowto |= RB_SINGLE;
+ if (get_bootconf_option(args, "kdb", BOOTOPT_TYPE_BOOLEAN, &integer)
+ || get_bootconf_option(args, "-k", BOOTOPT_TYPE_BOOLEAN, &integer))
+ if (integer)
+ boothowto |= RB_KDB;
+ if (get_bootconf_option(args, "ask", BOOTOPT_TYPE_BOOLEAN, &integer)
+ || get_bootconf_option(args, "-a", BOOTOPT_TYPE_BOOLEAN, &integer))
+ if (integer)
+ boothowto |= RB_ASKNAME;
+
+#ifdef PMAP_DEBUG
+ if (get_bootconf_option(args, "pmapdebug", BOOTOPT_TYPE_INT, &integer)) {
+ pmap_debug_level = integer;
+ pmap_debug(pmap_debug_level);
+ }
+#endif /* PMAP_DEBUG */
+
+/* if (get_bootconf_option(args, "nbuf", BOOTOPT_TYPE_INT, &integer))
+ bufpages = integer;*/
+
+#if NMD > 0 && defined(MEMORY_DISK_HOOKS) && !defined(MEMORY_DISK_ROOT_SIZE)
+ if (get_bootconf_option(args, "memorydisc", BOOTOPT_TYPE_INT, &integer)
+ || get_bootconf_option(args, "memorydisk", BOOTOPT_TYPE_INT, &integer)) {
+ md_root_size = integer;
+ md_root_size *= 1024;
+ if (md_root_size < 32*1024)
+ md_root_size = 32*1024;
+ if (md_root_size > 2048*1024)
+ md_root_size = 2048*1024;
+ }
+#endif /* NMD && MEMORY_DISK_HOOKS && !MEMORY_DISK_ROOT_SIZE */
+
+ if (get_bootconf_option(args, "quiet", BOOTOPT_TYPE_BOOLEAN, &integer)
+ || get_bootconf_option(args, "-q", BOOTOPT_TYPE_BOOLEAN, &integer))
+ if (integer)
+ boothowto |= AB_QUIET;
+ if (get_bootconf_option(args, "verbose", BOOTOPT_TYPE_BOOLEAN, &integer)
+ || get_bootconf_option(args, "-v", BOOTOPT_TYPE_BOOLEAN, &integer))
+ if (integer)
+ boothowto |= AB_VERBOSE;
+}
+#endif
+
+/*
+ * Allocate space for system data structures. We are given
+ * a starting virtual address and we return a final virtual
+ * address; along the way we set each data structure pointer.
+ *
+ * We call allocsys() with 0 to find out how much space we want,
+ * allocate that much and fill it with zeroes, and then call
+ * allocsys() again with the correct base virtual address.
+ */
+caddr_t
+allocsys(caddr_t v)
+{
+
+#define valloc(name, type, num) \
+ v = (caddr_t)(((name) = (type *)v) + (num))
+
+#ifdef SYSVMSG
+ valloc(msgpool, char, msginfo.msgmax);
+ valloc(msgmaps, struct msgmap, msginfo.msgseg);
+ valloc(msghdrs, struct msg, msginfo.msgtql);
+ valloc(msqids, struct msqid_ds, msginfo.msgmni);
+#endif
+ /*
+ * Determine how many buffers to allocate. We use 10% of the
+ * first 2MB of memory, and 5% of the rest, with a minimum of 16
+ * buffers. We allocate 1/2 as many swap buffer headers as file
+ * i/o buffers.
+ */
+ if (bufpages == 0) {
+ if (physmem < btoc(2 * 1024 * 1024))
+ bufpages = physmem / 10;
+ else
+ bufpages = (btoc(2 * 1024 * 1024) + physmem) *
+ bufcachepercent / 100;
+ }
+ if (nbuf == 0) {
+ nbuf = bufpages;
+ if (nbuf < 16)
+ nbuf = 16;
+ }
+
+ /* Restrict to at most 35% filled kvm */
+ /* XXX - This needs UBC... */
+ if (nbuf >
+ (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) / MAXBSIZE * 35 / 100)
+ nbuf = (VM_MAX_KERNEL_ADDRESS-VM_MIN_KERNEL_ADDRESS) /
+ MAXBSIZE * 35 / 100;
+
+ /* More buffer pages than fits into the buffers is senseless. */
+ if (bufpages > nbuf * MAXBSIZE / PAGE_SIZE)
+ bufpages = nbuf * MAXBSIZE / PAGE_SIZE;
+
+ valloc(buf, struct buf, nbuf);
+ return v;
+}
diff --git a/sys/arch/arm/arm/arm_machdep.c b/sys/arch/arm/arm/arm_machdep.c
new file mode 100644
index 00000000000..c526411b1ec
--- /dev/null
+++ b/sys/arch/arm/arm/arm_machdep.c
@@ -0,0 +1,272 @@
+/* $OpenBSD: arm_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: arm_machdep.c,v 1.7 2003/10/25 19:44:42 scw Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <sys/exec.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+#include <sys/pool.h>
+
+#include <arm/cpufunc.h>
+
+#include <machine/pcb.h>
+#include <machine/vmparam.h>
+#include <machine/bus.h>
+
+static __inline struct trapframe *
+process_frame(struct proc *p)
+{
+
+ return (p->p_addr->u_pcb.pcb_tf);
+}
+
+/*
+ * The ARM architecture places the vector page at address 0.
+ * Later ARM architecture versions, however, allow it to be
+ * relocated to a high address (0xffff0000). This is primarily
+ * to support the Fast Context Switch Extension.
+ *
+ * This variable contains the address of the vector page. It
+ * defaults to 0; it only needs to be initialized if we enable
+ * relocated vectors.
+ */
+vaddr_t vector_page;
+
+/*
+ * Clear registers on exec
+ */
+
+void
+setregs(struct proc *p, struct exec_package *pack, u_long stack,
+ register_t *retval)
+{
+ struct trapframe *tf;
+
+ tf = p->p_addr->u_pcb.pcb_tf;
+
+ memset(tf, 0, sizeof(*tf));
+/* tf->tf_r0 = (u_int)p->p_proc->p_psstr; */
+ tf->tf_usr_sp = stack;
+ tf->tf_usr_lr = pack->ep_entry;
+ tf->tf_svc_lr = 0x77777777; /* Something we can see */
+ tf->tf_pc = pack->ep_entry;
+#ifdef __PROG32
+ tf->tf_spsr = PSR_USR32_MODE;
+#endif
+
+ p->p_addr->u_pcb.pcb_flags = 0;
+ retval[1] = 0;
+}
+
+#if 0
+/*
+ * startlwp:
+ *
+ * Start a new LWP.
+ */
+void
+startlwp(void *arg)
+{
+ int err;
+ ucontext_t *uc = arg;
+ struct lwp *l = curlwp;
+
+ err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
+#ifdef DIAGNOSTIC
+ if (err)
+ printf("Error %d from cpu_setmcontext.", err);
+#endif
+ pool_put(&lwp_uc_pool, uc);
+
+ userret(l);
+}
+
+/*
+ * XXX This is a terrible name.
+ */
+void
+upcallret(struct lwp *l)
+{
+
+ userret(l);
+}
+
+/*
+ * cpu_upcall:
+ *
+ * Send an an upcall to userland.
+ */
+void
+cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted, void *sas,
+ void *ap, void *sp, sa_upcall_t upcall)
+{
+ struct trapframe *tf;
+ struct saframe *sf, frame;
+
+ tf = process_frame(l);
+
+ /* Finally, copy out the rest of the frame. */
+#if 0 /* First 4 args in regs (see below). */
+ frame.sa_type = type;
+ frame.sa_sas = sas;
+ frame.sa_events = nevents;
+ frame.sa_interrupted = ninterrupted;
+#endif
+ frame.sa_arg = ap;
+
+ sf = (struct saframe *)sp - 1;
+ if (copyout(&frame, sf, sizeof(frame)) != 0) {
+ /* Copying onto the stack didn't work. Die. */
+ sigexit(l, SIGILL);
+ /* NOTREACHED */
+ }
+
+ tf->tf_r0 = type;
+ tf->tf_r1 = (int) sas;
+ tf->tf_r2 = nevents;
+ tf->tf_r3 = ninterrupted;
+ tf->tf_pc = (int) upcall;
+ tf->tf_usr_sp = (int) sf;
+ tf->tf_usr_lr = 0; /* no return */
+}
+#endif
+
+
+#define _CONCAT(A,B) A ## B
+#define __C(A,B) _CONCAT(A,B)
+
+#define BUS_SPACE_COPY_N(BYTES,TYPE) \
+void \
+__C(bus_space_copy_,BYTES)(bus_space_tag_t bst, bus_space_handle_t h1, \
+ bus_size_t o1, bus_space_handle_t h2, bus_size_t o2, \
+ bus_size_t c) \
+{ \
+ int i; \
+ \
+ if (h1 == h2 && o2 > o1) \
+ for (i = c-1; i >= 0; i--) \
+ __C(bus_space_write_,BYTES)(bst, h2, o2+(BYTES*i), \
+ __C(bus_space_read_,BYTES)(bst, h1, o1+(BYTES*i))); \
+ else \
+ for (i = 0; i < c; i++) \
+ __C(bus_space_write_,BYTES)(bst, h2, o2+(BYTES*i), \
+ __C(bus_space_read_,BYTES)(bst, h1, o1+(BYTES*i))); \
+}
+BUS_SPACE_COPY_N(1,u_int8_t)
+BUS_SPACE_COPY_N(2,u_int16_t)
+BUS_SPACE_COPY_N(4,u_int32_t)
+
+
+
+#if 0
+#define BUS_SPACE_READ_RAW_MULTI_N(BYTES,SHIFT,TYPE) \
+void \
+__C(bus_space_read_raw_multi_,BYTES)(bus_space_tag_t bst, \
+ bus_space_handle_t h, bus_addr_t o, u_int8_t *dst, bus_size_t size) \
+{ \
+ TYPE *src; \
+ TYPE *rdst = (TYPE *)dst; \
+ int i; \
+ int count = size >> SHIFT; \
+ \
+ src = (TYPE *)(h+o); \
+ for (i = 0; i < count; i++) { \
+ rdst[i] = *src; \
+ } \
+}
+BUS_SPACE_READ_RAW_MULTI_N(2,1,u_int16_t)
+BUS_SPACE_READ_RAW_MULTI_N(4,2,u_int32_t)
+
+#define BUS_SPACE_WRITE_RAW_MULTI_N(BYTES,SHIFT,TYPE) \
+void \
+__C(bus_space_write_raw_multi_,BYTES)( bus_space_tag_t bst, \
+ bus_space_handle_t h, bus_addr_t o, const u_int8_t *src, \
+ bus_size_t size) \
+{ \
+ int i; \
+ TYPE *dst; \
+ TYPE *rsrc = (TYPE *)src; \
+ int count = size >> SHIFT; \
+ \
+ dst = (TYPE *)(h+o); \
+ for (i = 0; i < count; i++) { \
+ *dst = rsrc[i]; \
+ } \
+}
+
+BUS_SPACE_WRITE_RAW_MULTI_N(2,1,u_int16_t)
+BUS_SPACE_WRITE_RAW_MULTI_N(4,2,u_int32_t)
+#endif
diff --git a/sys/arch/arm/arm/ast.c b/sys/arch/arm/arm/ast.c
new file mode 100644
index 00000000000..c10b0d006e9
--- /dev/null
+++ b/sys/arch/arm/arm/ast.c
@@ -0,0 +1,132 @@
+/* $OpenBSD: ast.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: ast.c,v 1.6 2003/10/31 16:44:34 cl Exp $ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the RiscBSD team.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTERS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * ast.c
+ *
+ * Code to handle ast's and returns to user mode
+ *
+ * Created : 11/10/94
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/acct.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/vmmeter.h>
+
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/cpu.h>
+
+#include <arm/cpufunc.h>
+
+#include <uvm/uvm_extern.h>
+
+#ifdef acorn26
+#include <machine/machdep.h>
+#endif
+
+/*
+ * Prototypes
+ */
+void ast __P((struct trapframe *));
+
+int want_resched = 0;
+extern int astpending;
+
+void
+userret(struct proc *p)
+{
+ int sig;
+
+ /* Take pending signals. */
+ while ((sig = (CURSIG(p))) != 0)
+ postsig(sig);
+
+ #if 0
+ /* XXX */
+ curcpu()->ci_schedstate.spc_curpriority = p->p_priority = p->p_usrpri;
+ #endif
+ pmap_update(p->p_vmspace->vm_map.pmap); /* XXX DSR help stability */
+}
+
+
+/*
+ * Handle asynchronous system traps.
+ * This is called from the irq handler to deliver signals
+ * and switch processes if required.
+ */
+
+void
+ast(struct trapframe *tf)
+{
+ struct proc *p = curproc;;
+
+#ifdef acorn26
+ /* Enable interrupts if they were enabled before the trap. */
+ if ((tf->tf_r15 & R15_IRQ_DISABLE) == 0)
+ int_on();
+#else
+ /* Interrupts were restored by exception_exit. */
+#endif
+
+ uvmexp.traps++;
+ uvmexp.softs++;
+
+#ifdef DEBUG
+ if (p == NULL)
+ panic("ast: no curproc!");
+ if (&p->p_addr->u_pcb == 0)
+ panic("ast: no pcb!");
+#endif
+
+ if (p->p_flag & P_OWEUPC) {
+ p->p_flag &= ~P_OWEUPC;
+ ADDUPROF(p);
+ }
+
+ /* Allow a forced task switch. */
+ if (want_resched)
+ preempt(0);
+
+ userret(p);
+}
+
+/* End of ast.c */
diff --git a/sys/arch/arm/arm/atomic.S b/sys/arch/arm/arm/atomic.S
new file mode 100644
index 00000000000..d5f64a656c0
--- /dev/null
+++ b/sys/arch/arm/arm/atomic.S
@@ -0,0 +1,73 @@
+/* $OpenBSD: atomic.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: atomic.S,v 1.1 2002/10/19 12:46:57 bsh Exp $ */
+
+
+/*
+ * Copyright (C) 1994-1997 Mark Brinicombe
+ * Copyright (C) 1994 Brini
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of Brini may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "assym.h"
+#include <machine/asm.h>
+#include <machine/atomic.h>
+#include <machine/cpu.h>
+
+#ifdef ATOMIC_SET_BIT_NONINLINE_REQUIRED
+/*
+ * Atomic bit set and clear functions
+ */
+
+#undef atomic_set_bit
+ENTRY(atomic_set_bit)
+ mrs r2, cpsr
+ orr r3, r2, #(I32_bit)
+ msr cpsr_all, r3
+
+ ldr r3, [r0]
+ orr r3, r3, r1
+ str r3, [r0]
+
+ msr cpsr_all, r2
+ mov pc, lr
+
+
+#undef atomic_clear_bit
+ENTRY(atomic_clear_bit)
+ mrs r2, cpsr
+ orr r3, r2, #(I32_bit)
+ msr cpsr_all, r3
+
+ ldr r3, [r0]
+ bic r3, r3, r1
+ str r3, [r0]
+
+ msr cpsr_all, r2
+ mov pc, lr
+
+#endif /* ATOMIC_SET_BIT_NONINLINE_REQUIRED */
diff --git a/sys/arch/arm/arm/bcopy_page.S b/sys/arch/arm/arm/bcopy_page.S
new file mode 100644
index 00000000000..3c8f1ae2ce6
--- /dev/null
+++ b/sys/arch/arm/arm/bcopy_page.S
@@ -0,0 +1,276 @@
+/* $OpenBSD: bcopy_page.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: bcopy_page.S,v 1.7 2003/10/13 21:03:13 scw Exp $ */
+
+
+/*
+ * Copyright (c) 1995 Scott Stevens
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Scott Stevens.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * bcopy_page.S
+ *
+ * page optimised bcopy and bzero routines
+ *
+ * Created : 08/04/95
+ */
+
+#include <machine/asm.h>
+
+#include "assym.h"
+
+#ifndef __XSCALE__
+
+/* #define BIG_LOOPS */
+
+/*
+ * bcopy_page(src, dest)
+ *
+ * Optimised copy page routine.
+ *
+ * On entry:
+ * r0 - src address
+ * r1 - dest address
+ *
+ * Requires:
+ * number of bytes per page (PAGE_SIZE) is a multiple of 512 (BIG_LOOPS), 128
+ * otherwise.
+ */
+
+#define CHUNK_SIZE 32
+
+#define PREFETCH_FIRST_CHUNK /* nothing */
+#define PREFETCH_NEXT_CHUNK /* nothing */
+
+#ifndef COPY_CHUNK
+#define COPY_CHUNK \
+ PREFETCH_NEXT_CHUNK ; \
+ ldmia r0!, {r3-r8,ip,lr} ; \
+ stmia r1!, {r3-r8,ip,lr}
+#endif /* ! COPY_CHUNK */
+
+#ifndef SAVE_REGS
+#define SAVE_REGS stmfd sp!, {r4-r8, lr}
+#define RESTORE_REGS ldmfd sp!, {r4-r8, pc}
+#endif
+
+ENTRY(bcopy_page)
+ PREFETCH_FIRST_CHUNK
+ SAVE_REGS
+#ifdef BIG_LOOPS
+ mov r2, #(PAGE_SIZE >> 9)
+#else
+ mov r2, #(PAGE_SIZE >> 7)
+#endif
+
+1:
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+
+#ifdef BIG_LOOPS
+ /* There is little point making the loop any larger; unless we are
+ running with the cache off, the load/store overheads will
+ completely dominate this loop. */
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+ COPY_CHUNK
+#endif
+ subs r2, r2, #1
+ bne 1b
+
+ RESTORE_REGS /* ...and return. */
+
+/*
+ * bzero_page(dest)
+ *
+ * Optimised zero page routine.
+ *
+ * On entry:
+ * r0 - dest address
+ *
+ * Requires:
+ * number of bytes per page (PAGE_SIZE) is a multiple of 512 (BIG_LOOPS), 128
+ * otherwise
+ */
+
+ENTRY(bzero_page)
+ stmfd sp!, {r4-r8, lr}
+#ifdef BIG_LOOPS
+ mov r2, #(PAGE_SIZE >> 9)
+#else
+ mov r2, #(PAGE_SIZE >> 7)
+#endif
+ mov r3, #0
+ mov r4, #0
+ mov r5, #0
+ mov r6, #0
+ mov r7, #0
+ mov r8, #0
+ mov ip, #0
+ mov lr, #0
+
+1:
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+
+#ifdef BIG_LOOPS
+ /* There is little point making the loop any larger; unless we are
+ running with the cache off, the load/store overheads will
+ completely dominate this loop. */
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+ stmia r0!, {r3-r8,ip,lr}
+
+#endif
+
+ subs r2, r2, #1
+ bne 1b
+
+ ldmfd sp!, {r4-r8, pc}
+
+#else /* __XSCALE__ */
+
+/*
+ * XSCALE version of bcopy_page
+ */
+ENTRY(bcopy_page)
+ pld [r0]
+ stmfd sp!, {r4, r5}
+ mov ip, #32
+ ldr r2, [r0], #0x04 /* 0x00 */
+ ldr r3, [r0], #0x04 /* 0x04 */
+1: pld [r0, #0x18] /* Prefetch 0x20 */
+ ldr r4, [r0], #0x04 /* 0x08 */
+ ldr r5, [r0], #0x04 /* 0x0c */
+ strd r2, [r1], #0x08
+ ldr r2, [r0], #0x04 /* 0x10 */
+ ldr r3, [r0], #0x04 /* 0x14 */
+ strd r4, [r1], #0x08
+ ldr r4, [r0], #0x04 /* 0x18 */
+ ldr r5, [r0], #0x04 /* 0x1c */
+ strd r2, [r1], #0x08
+ ldr r2, [r0], #0x04 /* 0x20 */
+ ldr r3, [r0], #0x04 /* 0x24 */
+ pld [r0, #0x18] /* Prefetch 0x40 */
+ strd r4, [r1], #0x08
+ ldr r4, [r0], #0x04 /* 0x28 */
+ ldr r5, [r0], #0x04 /* 0x2c */
+ strd r2, [r1], #0x08
+ ldr r2, [r0], #0x04 /* 0x30 */
+ ldr r3, [r0], #0x04 /* 0x34 */
+ strd r4, [r1], #0x08
+ ldr r4, [r0], #0x04 /* 0x38 */
+ ldr r5, [r0], #0x04 /* 0x3c */
+ strd r2, [r1], #0x08
+ ldr r2, [r0], #0x04 /* 0x40 */
+ ldr r3, [r0], #0x04 /* 0x44 */
+ pld [r0, #0x18] /* Prefetch 0x60 */
+ strd r4, [r1], #0x08
+ ldr r4, [r0], #0x04 /* 0x48 */
+ ldr r5, [r0], #0x04 /* 0x4c */
+ strd r2, [r1], #0x08
+ ldr r2, [r0], #0x04 /* 0x50 */
+ ldr r3, [r0], #0x04 /* 0x54 */
+ strd r4, [r1], #0x08
+ ldr r4, [r0], #0x04 /* 0x58 */
+ ldr r5, [r0], #0x04 /* 0x5c */
+ strd r2, [r1], #0x08
+ ldr r2, [r0], #0x04 /* 0x60 */
+ ldr r3, [r0], #0x04 /* 0x64 */
+ pld [r0, #0x18] /* Prefetch 0x80 */
+ strd r4, [r1], #0x08
+ ldr r4, [r0], #0x04 /* 0x68 */
+ ldr r5, [r0], #0x04 /* 0x6c */
+ strd r2, [r1], #0x08
+ ldr r2, [r0], #0x04 /* 0x70 */
+ ldr r3, [r0], #0x04 /* 0x74 */
+ strd r4, [r1], #0x08
+ ldr r4, [r0], #0x04 /* 0x78 */
+ ldr r5, [r0], #0x04 /* 0x7c */
+ strd r2, [r1], #0x08
+ subs ip, ip, #0x01
+ ldrgt r2, [r0], #0x04 /* 0x80 */
+ ldrgt r3, [r0], #0x04 /* 0x84 */
+ strd r4, [r1], #0x08
+ bgt 1b
+ ldmfd sp!, {r4, r5}
+ mov pc, lr
+
+/*
+ * XSCALE version of bzero_page
+ */
+ENTRY(bzero_page)
+ mov r1, #PAGE_SIZE
+ mov r2, #0
+ mov r3, #0
+1: strd r2, [r0], #8 /* 32 */
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ strd r2, [r0], #8 /* 64 */
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ strd r2, [r0], #8 /* 96 */
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ strd r2, [r0], #8 /* 128 */
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ strd r2, [r0], #8
+ subs r1, r1, #128
+ bne 1b
+ mov pc, lr
+#endif /* __XSCALE__ */
diff --git a/sys/arch/arm/arm/bcopyinout.S b/sys/arch/arm/arm/bcopyinout.S
new file mode 100644
index 00000000000..684a4d3ac68
--- /dev/null
+++ b/sys/arch/arm/arm/bcopyinout.S
@@ -0,0 +1,815 @@
+/* $OpenBSD: bcopyinout.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: bcopyinout.S,v 1.13 2003/10/31 16:54:05 scw Exp $ */
+
+/*
+ * Copyright (c) 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Allen Briggs for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "assym.h"
+
+#include <machine/asm.h>
+
+#ifdef __XSCALE__
+#include "bcopyinout_xscale.S"
+#else
+
+ .text
+ .align 0
+
+#ifdef MULTIPROCESSOR
+.Lcpu_info:
+ .word _C_LABEL(cpu_info)
+#else
+.Lcurpcb:
+ .word _C_LABEL(curpcb)
+#endif
+
+#ifdef __PROG32
+#define SAVE_REGS stmfd sp!, {r4-r11}
+#define RESTORE_REGS ldmfd sp!, {r4-r11}
+#else
+/* Need to save R14_svc because it'll get trampled if we take a page fault. */
+#define SAVE_REGS stmfd sp!, {r4-r11, r14}
+#define RESTORE_REGS ldmfd sp!, {r4-r11, r14}
+#endif
+
+#if defined(__XSCALE__)
+#define HELLOCPP #
+#define PREFETCH(rx,o) pld [ rx , HELLOCPP (o) ]
+#else
+#define PREFETCH(rx,o)
+#endif
+
+/*
+ * r0 = user space address
+ * r1 = kernel space address
+ * r2 = length
+ *
+ * Copies bytes from user space to kernel space
+ *
+ * We save/restore r4-r11:
+ * r4-r11 are scratch
+ */
+ENTRY(copyin)
+ /* Quick exit if length is zero */
+ teq r2, #0
+ moveq r0, #0
+ moveq pc, lr
+
+ SAVE_REGS
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r2, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r4, .Lcpu_info
+ ldr r4, [r4, r0, lsl #2]
+ ldr r4, [r4, #CI_CURPCB]
+ ldmfd sp!, {r0-r2, r14}
+#else
+ ldr r4, .Lcurpcb
+ ldr r4, [r4]
+#endif
+
+ ldr r5, [r4, #PCB_ONFAULT]
+ adr r3, .Lcopyfault
+ str r3, [r4, #PCB_ONFAULT]
+
+ PREFETCH(r0, 0)
+ PREFETCH(r1, 0)
+
+ /*
+ * If not too many bytes, take the slow path.
+ */
+ cmp r2, #0x08
+ blt .Licleanup
+
+ /*
+ * Align destination to word boundary.
+ */
+ and r6, r1, #0x3
+ ldr pc, [pc, r6, lsl #2]
+ b .Lialend
+ .word .Lialend
+ .word .Lial3
+ .word .Lial2
+ .word .Lial1
+.Lial3: ldrbt r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lial2: ldrbt r7, [r0], #1
+ sub r2, r2, #1
+ strb r7, [r1], #1
+.Lial1: ldrbt r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lialend:
+
+ /*
+ * If few bytes left, finish slow.
+ */
+ cmp r2, #0x08
+ blt .Licleanup
+
+ /*
+ * If source is not aligned, finish slow.
+ */
+ ands r3, r0, #0x03
+ bne .Licleanup
+
+ cmp r2, #0x60 /* Must be > 0x5f for unrolled cacheline */
+ blt .Licleanup8
+
+ /*
+ * Align destination to cacheline boundary.
+ * If source and destination are nicely aligned, this can be a big
+ * win. If not, it's still cheaper to copy in groups of 32 even if
+ * we don't get the nice cacheline alignment.
+ */
+ and r6, r1, #0x1f
+ ldr pc, [pc, r6]
+ b .Licaligned
+ .word .Licaligned
+ .word .Lical28
+ .word .Lical24
+ .word .Lical20
+ .word .Lical16
+ .word .Lical12
+ .word .Lical8
+ .word .Lical4
+.Lical28:ldrt r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+.Lical24:ldrt r7, [r0], #4
+ sub r2, r2, #4
+ str r7, [r1], #4
+.Lical20:ldrt r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+.Lical16:ldrt r7, [r0], #4
+ sub r2, r2, #4
+ str r7, [r1], #4
+.Lical12:ldrt r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+.Lical8:ldrt r7, [r0], #4
+ sub r2, r2, #4
+ str r7, [r1], #4
+.Lical4:ldrt r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+
+ /*
+ * We start with > 0x40 bytes to copy (>= 0x60 got us into this
+ * part of the code, and we may have knocked that down by as much
+ * as 0x1c getting aligned).
+ *
+ * This loop basically works out to:
+ * do {
+ * prefetch-next-cacheline(s)
+ * bytes -= 0x20;
+ * copy cacheline
+ * } while (bytes >= 0x40);
+ * bytes -= 0x20;
+ * copy cacheline
+ */
+.Licaligned:
+ PREFETCH(r0, 32)
+ PREFETCH(r1, 32)
+
+ sub r2, r2, #0x20
+
+ /* Copy a cacheline */
+ ldrt r10, [r0], #4
+ ldrt r11, [r0], #4
+ ldrt r6, [r0], #4
+ ldrt r7, [r0], #4
+ ldrt r8, [r0], #4
+ ldrt r9, [r0], #4
+ stmia r1!, {r10-r11}
+ ldrt r10, [r0], #4
+ ldrt r11, [r0], #4
+ stmia r1!, {r6-r11}
+
+ cmp r2, #0x40
+ bge .Licaligned
+
+ sub r2, r2, #0x20
+
+ /* Copy a cacheline */
+ ldrt r10, [r0], #4
+ ldrt r11, [r0], #4
+ ldrt r6, [r0], #4
+ ldrt r7, [r0], #4
+ ldrt r8, [r0], #4
+ ldrt r9, [r0], #4
+ stmia r1!, {r10-r11}
+ ldrt r10, [r0], #4
+ ldrt r11, [r0], #4
+ stmia r1!, {r6-r11}
+
+ cmp r2, #0x08
+ blt .Liprecleanup
+
+.Licleanup8:
+ ldrt r8, [r0], #4
+ ldrt r9, [r0], #4
+ sub r2, r2, #8
+ stmia r1!, {r8, r9}
+ cmp r2, #8
+ bge .Licleanup8
+
+.Liprecleanup:
+ /*
+ * If we're done, bail.
+ */
+ cmp r2, #0
+ beq .Lout
+
+.Licleanup:
+ and r6, r2, #0x3
+ ldr pc, [pc, r6, lsl #2]
+ b .Licend
+ .word .Lic4
+ .word .Lic1
+ .word .Lic2
+ .word .Lic3
+.Lic4: ldrbt r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lic3: ldrbt r7, [r0], #1
+ sub r2, r2, #1
+ strb r7, [r1], #1
+.Lic2: ldrbt r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lic1: ldrbt r7, [r0], #1
+ subs r2, r2, #1
+ strb r7, [r1], #1
+.Licend:
+ bne .Licleanup
+
+.Liout:
+ mov r0, #0
+
+ str r5, [r4, #PCB_ONFAULT]
+ RESTORE_REGS
+
+ mov pc, lr
+
+.Lcopyfault:
+ str r5, [r4, #PCB_ONFAULT]
+ RESTORE_REGS
+
+ mov pc, lr
+
+/*
+ * r0 = kernel space address
+ * r1 = user space address
+ * r2 = length
+ *
+ * Copies bytes from kernel space to user space
+ *
+ * We save/restore r4-r11:
+ * r4-r11 are scratch
+ */
+
+ENTRY(copyout)
+ /* Quick exit if length is zero */
+ teq r2, #0
+ moveq r0, #0
+ moveq pc, lr
+
+ SAVE_REGS
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r2, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r4, .Lcpu_info
+ ldr r4, [r4, r0, lsl #2]
+ ldr r4, [r4, #CI_CURPCB]
+ ldmfd sp!, {r0-r2, r14}
+#else
+ ldr r4, .Lcurpcb
+ ldr r4, [r4]
+#endif
+
+ ldr r5, [r4, #PCB_ONFAULT]
+ adr r3, .Lcopyfault
+ str r3, [r4, #PCB_ONFAULT]
+
+ PREFETCH(r0, 0)
+ PREFETCH(r1, 0)
+
+ /*
+ * If not too many bytes, take the slow path.
+ */
+ cmp r2, #0x08
+ blt .Lcleanup
+
+ /*
+ * Align destination to word boundary.
+ */
+ and r6, r1, #0x3
+ ldr pc, [pc, r6, lsl #2]
+ b .Lalend
+ .word .Lalend
+ .word .Lal3
+ .word .Lal2
+ .word .Lal1
+.Lal3: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strbt r6, [r1], #1
+.Lal2: ldrb r7, [r0], #1
+ sub r2, r2, #1
+ strbt r7, [r1], #1
+.Lal1: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strbt r6, [r1], #1
+.Lalend:
+
+ /*
+ * If few bytes left, finish slow.
+ */
+ cmp r2, #0x08
+ blt .Lcleanup
+
+ /*
+ * If source is not aligned, finish slow.
+ */
+ ands r3, r0, #0x03
+ bne .Lcleanup
+
+ cmp r2, #0x60 /* Must be > 0x5f for unrolled cacheline */
+ blt .Lcleanup8
+
+ /*
+ * Align source & destination to cacheline boundary.
+ */
+ and r6, r1, #0x1f
+ ldr pc, [pc, r6]
+ b .Lcaligned
+ .word .Lcaligned
+ .word .Lcal28
+ .word .Lcal24
+ .word .Lcal20
+ .word .Lcal16
+ .word .Lcal12
+ .word .Lcal8
+ .word .Lcal4
+.Lcal28:ldr r6, [r0], #4
+ sub r2, r2, #4
+ strt r6, [r1], #4
+.Lcal24:ldr r7, [r0], #4
+ sub r2, r2, #4
+ strt r7, [r1], #4
+.Lcal20:ldr r6, [r0], #4
+ sub r2, r2, #4
+ strt r6, [r1], #4
+.Lcal16:ldr r7, [r0], #4
+ sub r2, r2, #4
+ strt r7, [r1], #4
+.Lcal12:ldr r6, [r0], #4
+ sub r2, r2, #4
+ strt r6, [r1], #4
+.Lcal8: ldr r7, [r0], #4
+ sub r2, r2, #4
+ strt r7, [r1], #4
+.Lcal4: ldr r6, [r0], #4
+ sub r2, r2, #4
+ strt r6, [r1], #4
+
+ /*
+ * We start with > 0x40 bytes to copy (>= 0x60 got us into this
+ * part of the code, and we may have knocked that down by as much
+ * as 0x1c getting aligned).
+ *
+ * This loop basically works out to:
+ * do {
+ * prefetch-next-cacheline(s)
+ * bytes -= 0x20;
+ * copy cacheline
+ * } while (bytes >= 0x40);
+ * bytes -= 0x20;
+ * copy cacheline
+ */
+.Lcaligned:
+ PREFETCH(r0, 32)
+ PREFETCH(r1, 32)
+
+ sub r2, r2, #0x20
+
+ /* Copy a cacheline */
+ ldmia r0!, {r6-r11}
+ strt r6, [r1], #4
+ strt r7, [r1], #4
+ ldmia r0!, {r6-r7}
+ strt r8, [r1], #4
+ strt r9, [r1], #4
+ strt r10, [r1], #4
+ strt r11, [r1], #4
+ strt r6, [r1], #4
+ strt r7, [r1], #4
+
+ cmp r2, #0x40
+ bge .Lcaligned
+
+ sub r2, r2, #0x20
+
+ /* Copy a cacheline */
+ ldmia r0!, {r6-r11}
+ strt r6, [r1], #4
+ strt r7, [r1], #4
+ ldmia r0!, {r6-r7}
+ strt r8, [r1], #4
+ strt r9, [r1], #4
+ strt r10, [r1], #4
+ strt r11, [r1], #4
+ strt r6, [r1], #4
+ strt r7, [r1], #4
+
+ cmp r2, #0x08
+ blt .Lprecleanup
+
+.Lcleanup8:
+ ldmia r0!, {r8-r9}
+ sub r2, r2, #8
+ strt r8, [r1], #4
+ strt r9, [r1], #4
+ cmp r2, #8
+ bge .Lcleanup8
+
+.Lprecleanup:
+ /*
+ * If we're done, bail.
+ */
+ cmp r2, #0
+ beq .Lout
+
+.Lcleanup:
+ and r6, r2, #0x3
+ ldr pc, [pc, r6, lsl #2]
+ b .Lcend
+ .word .Lc4
+ .word .Lc1
+ .word .Lc2
+ .word .Lc3
+.Lc4: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strbt r6, [r1], #1
+.Lc3: ldrb r7, [r0], #1
+ sub r2, r2, #1
+ strbt r7, [r1], #1
+.Lc2: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strbt r6, [r1], #1
+.Lc1: ldrb r7, [r0], #1
+ subs r2, r2, #1
+ strbt r7, [r1], #1
+.Lcend:
+ bne .Lcleanup
+
+.Lout:
+ mov r0, #0
+
+ str r5, [r4, #PCB_ONFAULT]
+ RESTORE_REGS
+
+ mov pc, lr
+
+/*
+ * r0 = kernel space source address
+ * r1 = kernel space destination address
+ * r2 = length
+ *
+ * Copies bytes from kernel space to kernel space, aborting on page fault
+ *
+ * Copy of copyout, but without the ldrt/strt instructions.
+ */
+
+ENTRY(kcopy)
+ /* Quick exit if length is zero */
+ teq r2, #0
+ moveq r0, #0
+ moveq pc, lr
+
+ SAVE_REGS
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r2, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r4, .Lcpu_info
+ ldr r4, [r4, r0, lsl #2]
+ ldr r4, [r4, #CI_CURPCB]
+ ldmfd sp!, {r0-r2, r14}
+#else
+ ldr r4, .Lcurpcb
+ ldr r4, [r4]
+#endif
+
+ ldr r5, [r4, #PCB_ONFAULT]
+ adr r3, .Lcopyfault
+ str r3, [r4, #PCB_ONFAULT]
+
+ PREFETCH(r0, 0)
+ PREFETCH(r1, 0)
+
+ /*
+ * If not too many bytes, take the slow path.
+ */
+ cmp r2, #0x08
+ blt .Lkcleanup
+
+ /*
+ * Align destination to word boundary.
+ */
+ and r6, r1, #0x3
+ ldr pc, [pc, r6, lsl #2]
+ b .Lkalend
+ .word .Lkalend
+ .word .Lkal3
+ .word .Lkal2
+ .word .Lkal1
+.Lkal3: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lkal2: ldrb r7, [r0], #1
+ sub r2, r2, #1
+ strb r7, [r1], #1
+.Lkal1: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lkalend:
+
+ /*
+ * If few bytes left, finish slow.
+ */
+ cmp r2, #0x08
+ blt .Lkcleanup
+
+ /*
+ * If source is not aligned, finish slow.
+ */
+ ands r3, r0, #0x03
+ bne .Lkcleanup
+
+ cmp r2, #0x60 /* Must be > 0x5f for unrolled cacheline */
+ blt .Lkcleanup8
+
+ /*
+ * Align source & destination to cacheline boundary.
+ */
+ and r6, r1, #0x1f
+ ldr pc, [pc, r6]
+ b .Lkcaligned
+ .word .Lkcaligned
+ .word .Lkcal28
+ .word .Lkcal24
+ .word .Lkcal20
+ .word .Lkcal16
+ .word .Lkcal12
+ .word .Lkcal8
+ .word .Lkcal4
+.Lkcal28:ldr r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+.Lkcal24:ldr r7, [r0], #4
+ sub r2, r2, #4
+ str r7, [r1], #4
+.Lkcal20:ldr r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+.Lkcal16:ldr r7, [r0], #4
+ sub r2, r2, #4
+ str r7, [r1], #4
+.Lkcal12:ldr r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+.Lkcal8:ldr r7, [r0], #4
+ sub r2, r2, #4
+ str r7, [r1], #4
+.Lkcal4:ldr r6, [r0], #4
+ sub r2, r2, #4
+ str r6, [r1], #4
+
+ /*
+ * We start with > 0x40 bytes to copy (>= 0x60 got us into this
+ * part of the code, and we may have knocked that down by as much
+ * as 0x1c getting aligned).
+ *
+ * This loop basically works out to:
+ * do {
+ * prefetch-next-cacheline(s)
+ * bytes -= 0x20;
+ * copy cacheline
+ * } while (bytes >= 0x40);
+ * bytes -= 0x20;
+ * copy cacheline
+ */
+.Lkcaligned:
+ PREFETCH(r0, 32)
+ PREFETCH(r1, 32)
+
+ sub r2, r2, #0x20
+
+ /* Copy a cacheline */
+ ldmia r0!, {r6-r11}
+ stmia r1!, {r6, r7}
+ ldmia r0!, {r6, r7}
+ stmia r1!, {r8-r11}
+ stmia r1!, {r6, r7}
+
+ cmp r2, #0x40
+ bge .Lkcaligned
+
+ sub r2, r2, #0x20
+
+ /* Copy a cacheline */
+ ldmia r0!, {r6-r11}
+ stmia r1!, {r6-r7}
+ ldmia r0!, {r6-r7}
+ stmia r1!, {r8-r11}
+ stmia r1!, {r6-r7}
+
+ cmp r2, #0x08
+ blt .Lkprecleanup
+
+.Lkcleanup8:
+ ldmia r0!, {r8-r9}
+ sub r2, r2, #8
+ stmia r1!, {r8-r9}
+ cmp r2, #8
+ bge .Lkcleanup8
+
+.Lkprecleanup:
+ /*
+ * If we're done, bail.
+ */
+ cmp r2, #0
+ beq .Lkout
+
+.Lkcleanup:
+ and r6, r2, #0x3
+ ldr pc, [pc, r6, lsl #2]
+ b .Lkcend
+ .word .Lkc4
+ .word .Lkc1
+ .word .Lkc2
+ .word .Lkc3
+.Lkc4: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lkc3: ldrb r7, [r0], #1
+ sub r2, r2, #1
+ strb r7, [r1], #1
+.Lkc2: ldrb r6, [r0], #1
+ sub r2, r2, #1
+ strb r6, [r1], #1
+.Lkc1: ldrb r7, [r0], #1
+ subs r2, r2, #1
+ strb r7, [r1], #1
+.Lkcend:
+ bne .Lkcleanup
+
+.Lkout:
+ mov r0, #0
+
+ str r5, [r4, #PCB_ONFAULT]
+ RESTORE_REGS
+
+ mov pc, lr
+#endif /* !__XSCALE__ */
+
+#ifdef __PROG32
+/*
+ * int badaddr_read_1(const uint8_t *src, uint8_t *dest)
+ *
+ * Copies a single 8-bit value from src to dest, returning 0 on success,
+ * else EFAULT if a page fault occurred.
+ */
+ENTRY(badaddr_read_1)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0-r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+ ldr ip, [r2, #PCB_ONFAULT]
+ adr r3, 1f
+ str r3, [r2, #PCB_ONFAULT]
+ nop
+ nop
+ nop
+ ldrb r3, [r0]
+ nop
+ nop
+ nop
+ strb r3, [r1]
+ mov r0, #0 /* No fault */
+1: str ip, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * int badaddr_read_2(const uint16_t *src, uint16_t *dest)
+ *
+ * Copies a single 16-bit value from src to dest, returning 0 on success,
+ * else EFAULT if a page fault occurred.
+ */
+ENTRY(badaddr_read_2)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0-r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+ ldr ip, [r2, #PCB_ONFAULT]
+ adr r3, 1f
+ str r3, [r2, #PCB_ONFAULT]
+ nop
+ nop
+ nop
+ ldrh r3, [r0]
+ nop
+ nop
+ nop
+ strh r3, [r1]
+ mov r0, #0 /* No fault */
+1: str ip, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * int badaddr_read_4(const uint32_t *src, uint32_t *dest)
+ *
+ * Copies a single 32-bit value from src to dest, returning 0 on success,
+ * else EFAULT if a page fault occurred.
+ */
+ENTRY(badaddr_read_4)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0-r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+ ldr ip, [r2, #PCB_ONFAULT]
+ adr r3, 1f
+ str r3, [r2, #PCB_ONFAULT]
+ nop
+ nop
+ nop
+ ldr r3, [r0]
+ nop
+ nop
+ nop
+ str r3, [r1]
+ mov r0, #0 /* No fault */
+1: str ip, [r2, #PCB_ONFAULT]
+ mov pc, lr
+#endif /* __PROG32 */
diff --git a/sys/arch/arm/arm/blockio.S b/sys/arch/arm/arm/blockio.S
new file mode 100644
index 00000000000..590c3e6a7d4
--- /dev/null
+++ b/sys/arch/arm/arm/blockio.S
@@ -0,0 +1,588 @@
+/* $OpenBSD: blockio.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: blockio.S,v 1.5 2002/08/15 01:38:16 briggs Exp $ */
+
+/*
+ * Copyright (c) 2001 Ben Harris.
+ * Copyright (c) 1994 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * blockio.S
+ *
+ * optimised block read/write from/to IO routines.
+ *
+ * Created : 08/10/94
+ * Modified : 22/01/99 -- R.Earnshaw
+ * Faster, and small tweaks for StrongARM
+ */
+
+#include <machine/asm.h>
+
+RCSID("$NetBSD: blockio.S,v 1.4 2001/06/02 11:15:56 bjh21 Exp $")
+
+/*
+ * Read bytes from an I/O address into a block of memory
+ *
+ * r0 = address to read from (IO)
+ * r1 = address to write to (memory)
+ * r2 = length
+ */
+
+/* This code will look very familiar if you've read _memcpy(). */
+ENTRY(read_multi_1)
+ mov ip, sp
+ stmfd sp!, {fp, ip, lr, pc}
+ sub fp, ip, #4
+ subs r2, r2, #4 /* r2 = length - 4 */
+ blt .Lrm1_l4 /* less than 4 bytes */
+ ands r12, r1, #3
+ beq .Lrm1_main /* aligned destination */
+ rsb r12, r12, #4
+ cmp r12, #2
+ ldrb r3, [r0]
+ strb r3, [r1], #1
+ ldrgeb r3, [r0]
+ strgeb r3, [r1], #1
+ ldrgtb r3, [r0]
+ strgtb r3, [r1], #1
+ subs r2, r2, r12
+ blt .Lrm1_l4
+.Lrm1_main:
+.Lrm1loop:
+ ldrb r3, [r0]
+ ldrb r12, [r0]
+ orr r3, r3, r12, lsl #8
+ ldrb r12, [r0]
+ orr r3, r3, r12, lsl #16
+ ldrb r12, [r0]
+ orr r3, r3, r12, lsl #24
+ str r3, [r1], #4
+ subs r2, r2, #4
+ bge .Lrm1loop
+.Lrm1_l4:
+ adds r2, r2, #4 /* r2 = length again */
+ ldmeqdb fp, {fp, sp, pc}
+ moveq pc, r14
+ cmp r2, #2
+ ldrb r3, [r0]
+ strb r3, [r1], #1
+ ldrgeb r3, [r0]
+ strgeb r3, [r1], #1
+ ldrgtb r3, [r0]
+ strgtb r3, [r1], #1
+ ldmdb fp, {fp, sp, pc}
+
+/*
+ * Write bytes to an I/O address from a block of memory
+ *
+ * r0 = address to write to (IO)
+ * r1 = address to read from (memory)
+ * r2 = length
+ */
+
+/* This code will look very familiar if you've read _memcpy(). */
+ENTRY(write_multi_1)
+ mov ip, sp
+ stmfd sp!, {fp, ip, lr, pc}
+ sub fp, ip, #4
+ subs r2, r2, #4 /* r2 = length - 4 */
+ blt .Lwm1_l4 /* less than 4 bytes */
+ ands r12, r1, #3
+ beq .Lwm1_main /* aligned source */
+ rsb r12, r12, #4
+ cmp r12, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0]
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0]
+ ldrgtb r3, [r1], #1
+ strgtb r3, [r0]
+ subs r2, r2, r12
+ blt .Lwm1_l4
+.Lwm1_main:
+.Lwm1loop:
+ ldr r3, [r1], #4
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ mov r3, r3, lsr #8
+ strb r3, [r0]
+ subs r2, r2, #4
+ bge .Lwm1loop
+.Lwm1_l4:
+ adds r2, r2, #4 /* r2 = length again */
+ ldmeqdb fp, {fp, sp, pc}
+ cmp r2, #2
+ ldrb r3, [r1], #1
+ strb r3, [r0]
+ ldrgeb r3, [r1], #1
+ strgeb r3, [r0]
+ ldrgtb r3, [r1], #1
+ strgtb r3, [r0]
+ ldmdb fp, {fp, sp, pc}
+
+/*
+ * Reads short ints (16 bits) from an I/O address into a block of memory
+ *
+ * r0 = address to read from (IO)
+ * r1 = address to write to (memory)
+ * r2 = length
+ */
+
+ENTRY(insw)
+/* Make sure that we have a positive length */
+ cmp r2, #0x00000000
+ movle pc, lr
+
+/* If the destination address and the size is word aligned, do it fast */
+
+ tst r2, #0x00000001
+ tsteq r1, #0x00000003
+ beq .Lfastinsw
+
+/* Non aligned insw */
+
+.Linswloop:
+ ldr r3, [r0]
+ subs r2, r2, #0x00000001 /* Loop test in load delay slot */
+ strb r3, [r1], #0x0001
+ mov r3, r3, lsr #8
+ strb r3, [r1], #0x0001
+ bgt .Linswloop
+
+ mov pc, lr
+
+/* Word aligned insw */
+
+.Lfastinsw:
+
+.Lfastinswloop:
+ ldr r3, [r0, #0x0002] /* take advantage of nonaligned
+ * word accesses */
+ ldr ip, [r0]
+ mov r3, r3, lsr #16 /* Put the two shorts together */
+ orr r3, r3, ip, lsl #16
+ str r3, [r1], #0x0004 /* Store */
+ subs r2, r2, #0x00000002 /* Next */
+ bgt .Lfastinswloop
+
+ mov pc, lr
+
+
+/*
+ * Writes short ints (16 bits) from a block of memory to an I/O address
+ *
+ * r0 = address to write to (IO)
+ * r1 = address to read from (memory)
+ * r2 = length
+ */
+
+ENTRY(outsw)
+/* Make sure that we have a positive length */
+ cmp r2, #0x00000000
+ movle pc, lr
+
+/* If the destination address and the size is word aligned, do it fast */
+
+ tst r2, #0x00000001
+ tsteq r1, #0x00000003
+ beq .Lfastoutsw
+
+/* Non aligned outsw */
+
+.Loutswloop:
+ ldrb r3, [r1], #0x0001
+ ldrb ip, [r1], #0x0001
+ subs r2, r2, #0x00000001 /* Loop test in load delay slot */
+ orr r3, r3, ip, lsl #8
+ orr r3, r3, r3, lsl #16
+ str r3, [r0]
+ bgt .Loutswloop
+
+ mov pc, lr
+
+/* Word aligned outsw */
+
+.Lfastoutsw:
+
+.Lfastoutswloop:
+ ldr r3, [r1], #0x0004 /* r3 = (H)(L) */
+ subs r2, r2, #0x00000002 /* Loop test in load delay slot */
+
+ eor ip, r3, r3, lsr #16 /* ip = (H)(H^L) */
+ eor r3, r3, ip, lsl #16 /* r3 = (H^H^L)(L) = (L)(L) */
+ eor ip, ip, r3, lsr #16 /* ip = (H)(H^L^L) = (H)(H) */
+
+ str r3, [r0]
+ str ip, [r0]
+
+/* mov ip, r3, lsl #16
+ * orr ip, ip, ip, lsr #16
+ * str ip, [r0]
+ *
+ * mov ip, r3, lsr #16
+ * orr ip, ip, ip, lsl #16
+ * str ip, [r0]
+ */
+
+ bgt .Lfastoutswloop
+
+ mov pc, lr
+
+/*
+ * reads short ints (16 bits) from an I/O address into a block of memory
+ * with a length garenteed to be a multiple of 16 bytes
+ * with a word aligned destination address
+ *
+ * r0 = address to read from (IO)
+ * r1 = address to write to (memory)
+ * r2 = length
+ */
+
+ENTRY(insw16)
+/* Make sure that we have a positive length */
+ cmp r2, #0x00000000
+ movle pc, lr
+
+/* If the destination address is word aligned and the size suitably
+ aligned, do it fast */
+
+ tst r2, #0x00000007
+ tsteq r1, #0x00000003
+
+ bne _C_LABEL(insw)
+
+/* Word aligned insw */
+
+ stmfd sp!, {r4,r5,lr}
+
+.Linsw16loop:
+ ldr r3, [r0, #0x0002] /* take advantage of nonaligned
+ * word accesses */
+ ldr lr, [r0]
+ mov r3, r3, lsr #16 /* Put the two shorts together */
+ orr r3, r3, lr, lsl #16
+
+ ldr r4, [r0, #0x0002] /* take advantage of nonaligned
+ * word accesses */
+ ldr lr, [r0]
+ mov r4, r4, lsr #16 /* Put the two shorts together */
+ orr r4, r4, lr, lsl #16
+
+ ldr r5, [r0, #0x0002] /* take advantage of nonaligned
+ * word accesses */
+ ldr lr, [r0]
+ mov r5, r5, lsr #16 /* Put the two shorts together */
+ orr r5, r5, lr, lsl #16
+
+ ldr ip, [r0, #0x0002] /* take advantage of nonaligned
+ * word accesses */
+ ldr lr, [r0]
+ mov ip, ip, lsr #16 /* Put the two shorts together */
+ orr ip, ip, lr, lsl #16
+
+ stmia r1!, {r3-r5,ip}
+ subs r2, r2, #0x00000008 /* Next */
+ bgt .Linsw16loop
+
+ ldmfd sp!, {r4,r5,pc} /* Restore regs and go home */
+
+
+/*
+ * Writes short ints (16 bits) from a block of memory to an I/O address
+ *
+ * r0 = address to write to (IO)
+ * r1 = address to read from (memory)
+ * r2 = length
+ */
+
+ENTRY(outsw16)
+/* Make sure that we have a positive length */
+ cmp r2, #0x00000000
+ movle pc, lr
+
+/* If the destination address is word aligned and the size suitably
+ aligned, do it fast */
+
+ tst r2, #0x00000007
+ tsteq r1, #0x00000003
+
+ bne _C_LABEL(outsw)
+
+/* Word aligned outsw */
+
+ stmfd sp!, {r4,r5,lr}
+
+.Loutsw16loop:
+ ldmia r1!, {r4,r5,ip,lr}
+
+ eor r3, r4, r4, lsl #16 /* r3 = (A^B)(B) */
+ eor r4, r4, r3, lsr #16 /* r4 = (A)(B^A^B) = (A)(A) */
+ eor r3, r3, r4, lsl #16 /* r3 = (A^B^A)(B) = (B)(B) */
+ str r3, [r0]
+ str r4, [r0]
+
+/* mov r3, r4, lsl #16
+ * orr r3, r3, r3, lsr #16
+ * str r3, [r0]
+ *
+ * mov r3, r4, lsr #16
+ * orr r3, r3, r3, lsl #16
+ * str r3, [r0]
+ */
+
+ eor r3, r5, r5, lsl #16 /* r3 = (A^B)(B) */
+ eor r5, r5, r3, lsr #16 /* r4 = (A)(B^A^B) = (A)(A) */
+ eor r3, r3, r5, lsl #16 /* r3 = (A^B^A)(B) = (B)(B) */
+ str r3, [r0]
+ str r5, [r0]
+
+ eor r3, ip, ip, lsl #16 /* r3 = (A^B)(B) */
+ eor ip, ip, r3, lsr #16 /* r4 = (A)(B^A^B) = (A)(A) */
+ eor r3, r3, ip, lsl #16 /* r3 = (A^B^A)(B) = (B)(B) */
+ str r3, [r0]
+ str ip, [r0]
+
+ eor r3, lr, lr, lsl #16 /* r3 = (A^B)(B) */
+ eor lr, lr, r3, lsr #16 /* r4 = (A)(B^A^B) = (A)(A) */
+ eor r3, r3, lr, lsl #16 /* r3 = (A^B^A)(B) = (B)(B) */
+ str r3, [r0]
+ str lr, [r0]
+
+ subs r2, r2, #0x00000008
+ bgt .Loutsw16loop
+
+ ldmfd sp!, {r4,r5,pc} /* and go home */
+
+/*
+ * reads short ints (16 bits) from an I/O address into a block of memory
+ * The I/O address is assumed to be mapped multiple times in a block of
+ * 8 words.
+ * The destination address should be word aligned.
+ *
+ * r0 = address to read from (IO)
+ * r1 = address to write to (memory)
+ * r2 = length
+ */
+
+ENTRY(inswm8)
+/* Make sure that we have a positive length */
+ cmp r2, #0x00000000
+ movle pc, lr
+
+/* If the destination address is word aligned and the size suitably
+ aligned, do it fast */
+
+ tst r1, #0x00000003
+
+ bne _C_LABEL(insw)
+
+/* Word aligned insw */
+
+ stmfd sp!, {r4-r9,lr}
+
+ mov lr, #0xff000000
+ orr lr, lr, #0x00ff0000
+
+.Linswm8_loop8:
+ cmp r2, #8
+ bcc .Linswm8_l8
+
+ ldmia r0, {r3-r9,ip}
+
+ bic r3, r3, lr
+ orr r3, r3, r4, lsl #16
+ bic r5, r5, lr
+ orr r4, r5, r6, lsl #16
+ bic r7, r7, lr
+ orr r5, r7, r8, lsl #16
+ bic r9, r9, lr
+ orr r6, r9, ip, lsl #16
+
+ stmia r1!, {r3-r6}
+
+ subs r2, r2, #0x00000008 /* Next */
+ bne .Linswm8_loop8
+ beq .Linswm8_l1
+
+.Linswm8_l8:
+ cmp r2, #4
+ bcc .Linswm8_l4
+
+ ldmia r0, {r3-r6}
+
+ bic r3, r3, lr
+ orr r3, r3, r4, lsl #16
+ bic r5, r5, lr
+ orr r4, r5, r6, lsl #16
+
+ stmia r1!, {r3-r4}
+
+ subs r2, r2, #0x00000004
+ beq .Linswm8_l1
+
+.Linswm8_l4:
+ cmp r2, #2
+ bcc .Linswm8_l2
+
+ ldmia r0, {r3-r4}
+
+ bic r3, r3, lr
+ orr r3, r3, r4, lsl #16
+ str r3, [r1], #0x0004
+
+ subs r2, r2, #0x00000002
+ beq .Linswm8_l1
+
+.Linswm8_l2:
+ cmp r2, #1
+ bcc .Linswm8_l1
+
+ ldr r3, [r0]
+ subs r2, r2, #0x00000001 /* Test in load delay slot */
+ /* XXX, why don't we use result? */
+
+ strb r3, [r1], #0x0001
+ mov r3, r3, lsr #8
+ strb r3, [r1], #0x0001
+
+
+.Linswm8_l1:
+ ldmfd sp!, {r4-r9,pc} /* And go home */
+
+/*
+ * write short ints (16 bits) to an I/O address from a block of memory
+ * The I/O address is assumed to be mapped multiple times in a block of
+ * 8 words.
+ * The source address should be word aligned.
+ *
+ * r0 = address to read to (IO)
+ * r1 = address to write from (memory)
+ * r2 = length
+ */
+
+ENTRY(outswm8)
+/* Make sure that we have a positive length */
+ cmp r2, #0x00000000
+ movle pc, lr
+
+/* If the destination address is word aligned and the size suitably
+ aligned, do it fast */
+
+ tst r1, #0x00000003
+
+ bne _C_LABEL(outsw)
+
+/* Word aligned outsw */
+
+ stmfd sp!, {r4-r8,lr}
+
+.Loutswm8_loop8:
+ cmp r2, #8
+ bcc .Loutswm8_l8
+
+ ldmia r1!, {r3,r5,r7,ip}
+
+ eor r4, r3, r3, lsr #16 /* r4 = (A)(A^B) */
+ eor r3, r3, r4, lsl #16 /* r3 = (A^A^B)(B) = (B)(B) */
+ eor r4, r4, r3, lsr #16 /* r4 = (A)(B^A^B) = (A)(A) */
+
+ eor r6, r5, r5, lsr #16 /* r6 = (A)(A^B) */
+ eor r5, r5, r6, lsl #16 /* r5 = (A^A^B)(B) = (B)(B) */
+ eor r6, r6, r5, lsr #16 /* r6 = (A)(B^A^B) = (A)(A) */
+
+ eor r8, r7, r7, lsr #16 /* r8 = (A)(A^B) */
+ eor r7, r7, r8, lsl #16 /* r7 = (A^A^B)(B) = (B)(B) */
+ eor r8, r8, r7, lsr #16 /* r8 = (A)(B^A^B) = (A)(A) */
+
+ eor lr, ip, ip, lsr #16 /* lr = (A)(A^B) */
+ eor ip, ip, lr, lsl #16 /* ip = (A^A^B)(B) = (B)(B) */
+ eor lr, lr, ip, lsr #16 /* lr = (A)(B^A^B) = (A)(A) */
+
+ stmia r0, {r3-r8,ip,lr}
+
+ subs r2, r2, #0x00000008 /* Next */
+ bne .Loutswm8_loop8
+ beq .Loutswm8_l1
+
+.Loutswm8_l8:
+ cmp r2, #4
+ bcc .Loutswm8_l4
+
+ ldmia r1!, {r3-r4}
+
+ eor r6, r3, r3, lsr #16 /* r6 = (A)(A^B) */
+ eor r5, r3, r6, lsl #16 /* r5 = (A^A^B)(B) = (B)(B) */
+ eor r6, r6, r5, lsr #16 /* r6 = (A)(B^A^B) = (A)(A) */
+
+ eor r8, r4, r4, lsr #16 /* r8 = (A)(A^B) */
+ eor r7, r4, r8, lsl #16 /* r7 = (A^A^B)(B) = (B)(B) */
+ eor r8, r8, r7, lsr #16 /* r8 = (A)(B^A^B) = (A)(A) */
+
+ stmia r0, {r5-r8}
+
+ subs r2, r2, #0x00000004
+ beq .Loutswm8_l1
+
+.Loutswm8_l4:
+ cmp r2, #2
+ bcc .Loutswm8_l2
+
+ ldr r3, [r1], #0x0004 /* r3 = (A)(B) */
+ subs r2, r2, #0x00000002 /* Done test in Load delay slot */
+
+ eor r5, r3, r3, lsr #16 /* r5 = (A)(A^B)*/
+ eor r4, r3, r5, lsl #16 /* r4 = (A^A^B)(B) = (B)(B) */
+ eor r5, r5, r4, lsr #16 /* r5 = (A)(B^A^B) = (A)(A) */
+
+ stmia r0, {r4, r5}
+
+ beq .Loutswm8_l1
+
+.Loutswm8_l2:
+ cmp r2, #1
+ bcc .Loutswm8_l1
+
+ ldrb r3, [r1], #0x0001
+ ldrb r4, [r1], #0x0001
+ subs r2, r2, #0x00000001 /* Done test in load delay slot */
+ /* XXX This test isn't used? */
+ orr r3, r3, r4, lsl #8
+ orr r3, r3, r3, lsl #16
+ str r3, [r0]
+
+.Loutswm8_l1:
+ ldmfd sp!, {r4-r8,pc} /* And go home */
diff --git a/sys/arch/arm/arm/bootconfig.c b/sys/arch/arm/arm/bootconfig.c
new file mode 100644
index 00000000000..27ed4736fe6
--- /dev/null
+++ b/sys/arch/arm/arm/bootconfig.c
@@ -0,0 +1,128 @@
+/* $OpenBSD: bootconfig.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: bootconfig.c,v 1.2 2002/03/10 19:56:39 lukem Exp $ */
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <sys/systm.h>
+
+#include <machine/bootconfig.h>
+
+#include "rd.h"
+
+/*
+ * Function to identify and process different types of boot argument
+ */
+
+int
+get_bootconf_option(opts, opt, type, result)
+ char *opts;
+ char *opt;
+ int type;
+ void *result;
+{
+ char *ptr;
+ char *optstart;
+ int not;
+
+ ptr = opts;
+
+ while (*ptr) {
+ /* Find start of option */
+ while (*ptr == ' ' || *ptr == '\t')
+ ++ptr;
+
+ if (*ptr == 0)
+ break;
+
+ not = 0;
+
+ /* Is it a negate option */
+ if ((type & BOOTOPT_TYPE_MASK) == BOOTOPT_TYPE_BOOLEAN && *ptr == '!') {
+ not = 1;
+ ++ptr;
+ }
+
+ /* Find the end of option */
+ optstart = ptr;
+ while (*ptr != 0 && *ptr != ' ' && *ptr != '\t' && *ptr != '=')
+ ++ptr;
+
+ if ((*ptr == '=')
+ || (*ptr != '=' && ((type & BOOTOPT_TYPE_MASK) == BOOTOPT_TYPE_BOOLEAN))) {
+ /* compare the option */
+ if (strncmp(optstart, opt, (ptr - optstart)) == 0) {
+ /* found */
+
+ if (*ptr == '=')
+ ++ptr;
+
+#if 0
+/* BELCH */
+ switch(type & BOOTOPT_TYPE_MASK) {
+ case BOOTOPT_TYPE_BOOLEAN :
+ if (*(ptr - 1) == '=')
+ *((int *)result) = ((u_int)strtoul(ptr, NULL, 10) != 0);
+ else
+ *((int *)result) = !not;
+ break;
+ case BOOTOPT_TYPE_STRING :
+ *((char **)result) = ptr;
+ break;
+ case BOOTOPT_TYPE_INT :
+ *((int *)result) = (u_int)strtoul(ptr, NULL, 10);
+ break;
+ case BOOTOPT_TYPE_BININT :
+ *((int *)result) = (u_int)strtoul(ptr, NULL, 2);
+ break;
+ case BOOTOPT_TYPE_HEXINT :
+ *((int *)result) = (u_int)strtoul(ptr, NULL, 16);
+ break;
+ default:
+ return(0);
+ }
+#endif
+ return(1);
+ }
+ }
+ /* skip to next option */
+ while (*ptr != ' ' && *ptr != '\t' && *ptr != 0)
+ ++ptr;
+ }
+ return(0);
+}
diff --git a/sys/arch/arm/arm/bus_dma.c b/sys/arch/arm/arm/bus_dma.c
new file mode 100644
index 00000000000..b5334213d37
--- /dev/null
+++ b/sys/arch/arm/arm/bus_dma.c
@@ -0,0 +1,1070 @@
+/* $OpenBSD: bus_dma.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: bus_dma.c,v 1.38 2003/10/30 08:44:13 scw Exp $^I*/$
+
+/*-
+ * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _ARM32_BUS_DMA_PRIVATE
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/reboot.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/vnode.h>
+#include <sys/device.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+
+#include <arm/cpufunc.h>
+
+int _bus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int, paddr_t *, int *, int);
+struct arm32_dma_range *_bus_dma_inrange(struct arm32_dma_range *,
+ int, bus_addr_t);
+
+/*
+ * Check to see if the specified page is in an allowed DMA range.
+ */
+__inline struct arm32_dma_range *
+_bus_dma_inrange(struct arm32_dma_range *ranges, int nranges,
+ bus_addr_t curaddr)
+{
+ struct arm32_dma_range *dr;
+ int i;
+
+ for (i = 0, dr = ranges; i < nranges; i++, dr++) {
+ if (curaddr >= dr->dr_sysbase &&
+ round_page(curaddr) <= (dr->dr_sysbase + dr->dr_len))
+ return (dr);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Common function for DMA map creation. May be called by bus-specific
+ * DMA map creation functions.
+ */
+int
+_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
+ bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp)
+{
+ struct arm32_bus_dmamap *map;
+ void *mapstore;
+ size_t mapsize;
+
+#ifdef DEBUG_DMA
+ printf("dmamap_create: t=%p size=%lx nseg=%x msegsz=%lx boundary=%lx flags=%x\n",
+ t, size, nsegments, maxsegsz, boundary, flags);
+#endif /* DEBUG_DMA */
+
+ /*
+ * Allocate and initialize the DMA map. The end of the map
+ * is a variable-sized array of segments, so we allocate enough
+ * room for them in one shot.
+ *
+ * Note we don't preserve the WAITOK or NOWAIT flags. Preservation
+ * of ALLOCNOW notifies others that we've reserved these resources,
+ * and they are not to be freed.
+ *
+ * The bus_dmamap_t includes one bus_dma_segment_t, hence
+ * the (nsegments - 1).
+ */
+ mapsize = sizeof(struct arm32_bus_dmamap) +
+ (sizeof(bus_dma_segment_t) * (nsegments - 1));
+ if ((mapstore = malloc(mapsize, M_DEVBUF,
+ (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL)
+ return (ENOMEM);
+
+ memset(mapstore, 0, mapsize);
+ map = (struct arm32_bus_dmamap *)mapstore;
+ map->_dm_size = size;
+ map->_dm_segcnt = nsegments;
+ map->_dm_maxsegsz = maxsegsz;
+ map->_dm_boundary = boundary;
+ map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
+ map->_dm_origbuf = NULL;
+ map->_dm_buftype = ARM32_BUFTYPE_INVALID;
+ map->_dm_proc = NULL;
+ map->dm_mapsize = 0; /* no valid mappings */
+ map->dm_nsegs = 0;
+
+ *dmamp = map;
+#ifdef DEBUG_DMA
+ printf("dmamap_create:map=%p\n", map);
+#endif /* DEBUG_DMA */
+ return (0);
+}
+
+/*
+ * Common function for DMA map destruction. May be called by bus-specific
+ * DMA map destruction functions.
+ */
+void
+_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
+{
+
+#ifdef DEBUG_DMA
+ printf("dmamap_destroy: t=%p map=%p\n", t, map);
+#endif /* DEBUG_DMA */
+
+ /*
+ * Explicit unload.
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+ map->_dm_origbuf = NULL;
+ map->_dm_buftype = ARM32_BUFTYPE_INVALID;
+ map->_dm_proc = NULL;
+
+ free(map, M_DEVBUF);
+}
+
+/*
+ * Common function for loading a DMA map with a linear buffer. May
+ * be called by bus-specific DMA map load functions.
+ */
+int
+_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+ bus_size_t buflen, struct proc *p, int flags)
+{
+ paddr_t lastaddr;
+ int seg, error;
+
+#ifdef DEBUG_DMA
+ printf("dmamap_load: t=%p map=%p buf=%p len=%lx p=%p f=%d\n",
+ t, map, buf, buflen, p, flags);
+#endif /* DEBUG_DMA */
+
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+
+ if (buflen > map->_dm_size)
+ return (EINVAL);
+
+ /* _bus_dmamap_load_buffer() clears this if we're not... */
+ map->_dm_flags |= ARM32_DMAMAP_COHERENT;
+
+ seg = 0;
+ error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
+ &lastaddr, &seg, 1);
+ if (error == 0) {
+ map->dm_mapsize = buflen;
+ map->dm_nsegs = seg + 1;
+ map->_dm_origbuf = buf;
+ map->_dm_buftype = ARM32_BUFTYPE_LINEAR;
+ map->_dm_proc = p;
+ }
+#ifdef DEBUG_DMA
+ printf("dmamap_load: error=%d\n", error);
+#endif /* DEBUG_DMA */
+ return (error);
+}
+
+/*
+ * Like _bus_dmamap_load(), but for mbufs.
+ */
+int
+_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
+ int flags)
+{
+#if 0
+ struct arm32_dma_range *dr;
+#endif
+ paddr_t lastaddr;
+ int seg, error, first;
+ struct mbuf *m;
+
+#ifdef DEBUG_DMA
+ printf("dmamap_load_mbuf: t=%p map=%p m0=%p f=%d\n",
+ t, map, m0, flags);
+#endif /* DEBUG_DMA */
+
+ /*
+ * Make sure that on error condition we return "no valid mappings."
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+
+#ifdef DIAGNOSTIC
+ if ((m0->m_flags & M_PKTHDR) == 0)
+ panic("_bus_dmamap_load_mbuf: no packet header");
+#endif /* DIAGNOSTIC */
+
+ if (m0->m_pkthdr.len > map->_dm_size)
+ return (EINVAL);
+
+ /*
+ * Mbuf chains should almost never have coherent (i.e.
+ * un-cached) mappings, so clear that flag now.
+ */
+ map->_dm_flags &= ~ARM32_DMAMAP_COHERENT;
+
+ first = 1;
+ seg = 0;
+ error = 0;
+ for (m = m0; m != NULL && error == 0; m = m->m_next) {
+ error = _bus_dmamap_load_buffer(t, map, m->m_data, m->m_len,
+ NULL, flags, &lastaddr, &seg, first);
+ first = 0;
+ }
+ if (error == 0) {
+ map->dm_mapsize = m0->m_pkthdr.len;
+ map->dm_nsegs = seg + 1;
+ map->_dm_origbuf = m0;
+ map->_dm_buftype = ARM32_BUFTYPE_MBUF;
+ map->_dm_proc = NULL; /* always kernel */
+ }
+#ifdef DEBUG_DMA
+ printf("dmamap_load_mbuf: error=%d\n", error);
+#endif /* DEBUG_DMA */
+ return (error);
+}
+
+/*
+ * Like _bus_dmamap_load(), but for uios.
+ */
+int
+_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio,
+ int flags)
+{
+ paddr_t lastaddr;
+ int seg, i, error, first;
+ bus_size_t minlen, resid;
+ struct proc *p = NULL;
+ struct iovec *iov;
+ caddr_t addr;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings."
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+
+ resid = uio->uio_resid;
+ iov = uio->uio_iov;
+
+ if (uio->uio_segflg == UIO_USERSPACE) {
+ p = uio->uio_procp;
+#ifdef DIAGNOSTIC
+ if (p == NULL)
+ panic("_bus_dmamap_load_uio: USERSPACE but no proc");
+#endif
+ }
+
+ /* _bus_dmamap_load_buffer() clears this if we're not... */
+ map->_dm_flags |= ARM32_DMAMAP_COHERENT;
+
+ first = 1;
+ seg = 0;
+ error = 0;
+ for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
+ /*
+ * Now at the first iovec to load. Load each iovec
+ * until we have exhausted the residual count.
+ */
+ minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
+ addr = (caddr_t)iov[i].iov_base;
+
+ error = _bus_dmamap_load_buffer(t, map, addr, minlen,
+ p, flags, &lastaddr, &seg, first);
+ first = 0;
+
+ resid -= minlen;
+ }
+ if (error == 0) {
+ map->dm_mapsize = uio->uio_resid;
+ map->dm_nsegs = seg + 1;
+ map->_dm_origbuf = uio;
+ map->_dm_buftype = ARM32_BUFTYPE_UIO;
+ map->_dm_proc = p;
+ }
+ return (error);
+}
+
+/*
+ * Like _bus_dmamap_load(), but for raw memory allocated with
+ * bus_dmamem_alloc().
+ */
+int
+_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
+ bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
+{
+
+ panic("_bus_dmamap_load_raw: not implemented");
+}
+
+/*
+ * Common function for unloading a DMA map. May be called by
+ * bus-specific DMA map unload functions.
+ */
+void
+_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map)
+{
+
+#ifdef DEBUG_DMA
+ printf("dmamap_unload: t=%p map=%p\n", t, map);
+#endif /* DEBUG_DMA */
+
+ /*
+ * No resources to free; just mark the mappings as
+ * invalid.
+ */
+ map->dm_mapsize = 0;
+ map->dm_nsegs = 0;
+ map->_dm_origbuf = NULL;
+ map->_dm_buftype = ARM32_BUFTYPE_INVALID;
+ map->_dm_proc = NULL;
+}
+
+static __inline void
+_bus_dmamap_sync_linear(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
+ bus_size_t len, int ops)
+{
+ vaddr_t addr = (vaddr_t) map->_dm_origbuf;
+
+ addr += offset;
+
+ switch (ops) {
+ case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
+ cpu_dcache_wbinv_range(addr, len);
+ break;
+
+ case BUS_DMASYNC_PREREAD:
+ if (((addr | len) & arm_dcache_align_mask) == 0)
+ cpu_dcache_inv_range(addr, len);
+ else
+ cpu_dcache_wbinv_range(addr, len);
+ break;
+
+ case BUS_DMASYNC_PREWRITE:
+ cpu_dcache_wb_range(addr, len);
+ break;
+ }
+}
+
+static __inline void
+_bus_dmamap_sync_mbuf(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
+ bus_size_t len, int ops)
+{
+ struct mbuf *m, *m0 = map->_dm_origbuf;
+ bus_size_t minlen, moff;
+ vaddr_t maddr;
+
+ for (moff = offset, m = m0; m != NULL && len != 0;
+ m = m->m_next) {
+ /* Find the beginning mbuf. */
+ if (moff >= m->m_len) {
+ moff -= m->m_len;
+ continue;
+ }
+
+ /*
+ * Now at the first mbuf to sync; nail each one until
+ * we have exhausted the length.
+ */
+ minlen = m->m_len - moff;
+ if (len < minlen)
+ minlen = len;
+
+ maddr = mtod(m, vaddr_t);
+ maddr += moff;
+
+ /*
+ * We can save a lot of work here if we know the mapping
+ * is read-only at the MMU:
+ *
+ * If a mapping is read-only, no dirty cache blocks will
+ * exist for it. If a writable mapping was made read-only,
+ * we know any dirty cache lines for the range will have
+ * been cleaned for us already. Therefore, if the upper
+ * layer can tell us we have a read-only mapping, we can
+ * skip all cache cleaning.
+ *
+ * NOTE: This only works if we know the pmap cleans pages
+ * before making a read-write -> read-only transition. If
+ * this ever becomes non-true (e.g. Physically Indexed
+ * cache), this will have to be revisited.
+ */
+ switch (ops) {
+ case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
+ /* if (! M_ROMAP(m)) */{
+ cpu_dcache_wbinv_range(maddr, minlen);
+ break;
+ }
+ /* else FALLTHROUGH */
+
+ case BUS_DMASYNC_PREREAD:
+ if (((maddr | minlen) & arm_dcache_align_mask) == 0)
+ cpu_dcache_inv_range(maddr, minlen);
+ else
+ cpu_dcache_wbinv_range(maddr, minlen);
+ break;
+
+ case BUS_DMASYNC_PREWRITE:
+ /* if (! M_ROMAP(m)) */
+ cpu_dcache_wb_range(maddr, minlen);
+ break;
+ }
+ moff = 0;
+ len -= minlen;
+ }
+}
+
+static __inline void
+_bus_dmamap_sync_uio(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
+ bus_size_t len, int ops)
+{
+ struct uio *uio = map->_dm_origbuf;
+ struct iovec *iov;
+ bus_size_t minlen, ioff;
+ vaddr_t addr;
+
+ for (iov = uio->uio_iov, ioff = offset; len != 0; iov++) {
+ /* Find the beginning iovec. */
+ if (ioff >= iov->iov_len) {
+ ioff -= iov->iov_len;
+ continue;
+ }
+
+ /*
+ * Now at the first iovec to sync; nail each one until
+ * we have exhausted the length.
+ */
+ minlen = iov->iov_len - ioff;
+ if (len < minlen)
+ minlen = len;
+
+ addr = (vaddr_t) iov->iov_base;
+ addr += ioff;
+
+ switch (ops) {
+ case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE:
+ cpu_dcache_wbinv_range(addr, minlen);
+ break;
+
+ case BUS_DMASYNC_PREREAD:
+ if (((addr | minlen) & arm_dcache_align_mask) == 0)
+ cpu_dcache_inv_range(addr, minlen);
+ else
+ cpu_dcache_wbinv_range(addr, minlen);
+ break;
+
+ case BUS_DMASYNC_PREWRITE:
+ cpu_dcache_wb_range(addr, minlen);
+ break;
+ }
+ ioff = 0;
+ len -= minlen;
+ }
+}
+
+/*
+ * Common function for DMA map synchronization. May be called
+ * by bus-specific DMA map synchronization functions.
+ *
+ * This version works for the Virtually Indexed Virtually Tagged
+ * cache found on 32-bit ARM processors.
+ *
+ * XXX Should have separate versions for write-through vs.
+ * XXX write-back caches. We currently assume write-back
+ * XXX here, which is not as efficient as it could be for
+ * XXX the write-through case.
+ */
+void
+_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
+ bus_size_t len, int ops)
+{
+
+#ifdef DEBUG_DMA
+ printf("dmamap_sync: t=%p map=%p offset=%lx len=%lx ops=%x\n",
+ t, map, offset, len, ops);
+#endif /* DEBUG_DMA */
+
+ /*
+ * Mixing of PRE and POST operations is not allowed.
+ */
+ if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
+ (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
+ panic("_bus_dmamap_sync: mix PRE and POST");
+
+#ifdef DIAGNOSTIC
+ if (offset >= map->dm_mapsize)
+ panic("_bus_dmamap_sync: bad offset %lu (map size is %lu)",
+ offset, map->dm_mapsize);
+ if (len == 0 || (offset + len) > map->dm_mapsize)
+ panic("_bus_dmamap_sync: bad length");
+#endif
+
+ /*
+ * For a virtually-indexed write-back cache, we need
+ * to do the following things:
+ *
+ * PREREAD -- Invalidate the D-cache. We do this
+ * here in case a write-back is required by the back-end.
+ *
+ * PREWRITE -- Write-back the D-cache. Note that if
+ * we are doing a PREREAD|PREWRITE, we can collapse
+ * the whole thing into a single Wb-Inv.
+ *
+ * POSTREAD -- Nothing.
+ *
+ * POSTWRITE -- Nothing.
+ */
+
+ ops &= (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ if (ops == 0)
+ return;
+
+ /* Skip cache frobbing if mapping was COHERENT. */
+ if (map->_dm_flags & ARM32_DMAMAP_COHERENT) {
+ /* Drain the write buffer. */
+ cpu_drain_writebuf();
+ return;
+ }
+
+ /*
+ * If the mapping belongs to a non-kernel vmspace, and the
+ * vmspace has not been active since the last time a full
+ * cache flush was performed, we don't need to do anything.
+ */
+ if (__predict_false(map->_dm_proc != NULL &&
+ map->_dm_proc->p_vmspace->vm_map.pmap->pm_cstate.cs_cache_d == 0))
+ return;
+
+ switch (map->_dm_buftype) {
+ case ARM32_BUFTYPE_LINEAR:
+ _bus_dmamap_sync_linear(t, map, offset, len, ops);
+ break;
+
+ case ARM32_BUFTYPE_MBUF:
+ _bus_dmamap_sync_mbuf(t, map, offset, len, ops);
+ break;
+
+ case ARM32_BUFTYPE_UIO:
+ _bus_dmamap_sync_uio(t, map, offset, len, ops);
+ break;
+
+ case ARM32_BUFTYPE_RAW:
+ panic("_bus_dmamap_sync: ARM32_BUFTYPE_RAW");
+ break;
+
+ case ARM32_BUFTYPE_INVALID:
+ panic("_bus_dmamap_sync: ARM32_BUFTYPE_INVALID");
+ break;
+
+ default:
+ printf("unknown buffer type %d\n", map->_dm_buftype);
+ panic("_bus_dmamap_sync");
+ }
+
+ /* Drain the write buffer. */
+ cpu_drain_writebuf();
+}
+
+/*
+ * Common function for DMA-safe memory allocation. May be called
+ * by bus-specific DMA memory allocation functions.
+ */
+
+extern paddr_t physical_start;
+extern paddr_t physical_end;
+
+int
+_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
+ bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
+ int flags)
+{
+ struct arm32_dma_range *dr;
+ int error, i;
+
+#ifdef DEBUG_DMA
+ printf("dmamem_alloc t=%p size=%lx align=%lx boundary=%lx "
+ "segs=%p nsegs=%x rsegs=%p flags=%x\n", t, size, alignment,
+ boundary, segs, nsegs, rsegs, flags);
+#endif
+
+ if ((dr = t->_ranges) != NULL) {
+ error = ENOMEM;
+ for (i = 0; i < t->_nranges; i++, dr++) {
+ if (dr->dr_len == 0)
+ continue;
+ error = _bus_dmamem_alloc_range(t, size, alignment,
+ boundary, segs, nsegs, rsegs, flags,
+ trunc_page(dr->dr_sysbase),
+ trunc_page(dr->dr_sysbase + dr->dr_len));
+ if (error == 0)
+ break;
+ }
+ } else {
+ error = _bus_dmamem_alloc_range(t, size, alignment, boundary,
+ segs, nsegs, rsegs, flags, trunc_page(physical_start),
+ trunc_page(physical_end));
+ }
+
+#ifdef DEBUG_DMA
+ printf("dmamem_alloc: =%d\n", error);
+#endif
+
+ return(error);
+}
+
+/*
+ * Common function for freeing DMA-safe memory. May be called by
+ * bus-specific DMA memory free functions.
+ */
+void
+_bus_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs)
+{
+ struct vm_page *m;
+ bus_addr_t addr;
+ struct pglist mlist;
+ int curseg;
+
+#ifdef DEBUG_DMA
+ printf("dmamem_free: t=%p segs=%p nsegs=%x\n", t, segs, nsegs);
+#endif /* DEBUG_DMA */
+
+ /*
+ * Build a list of pages to free back to the VM system.
+ */
+ TAILQ_INIT(&mlist);
+ for (curseg = 0; curseg < nsegs; curseg++) {
+ for (addr = segs[curseg].ds_addr;
+ addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
+ addr += PAGE_SIZE) {
+ m = PHYS_TO_VM_PAGE(addr);
+ TAILQ_INSERT_TAIL(&mlist, m, pageq);
+ }
+ }
+ uvm_pglistfree(&mlist);
+}
+
+/*
+ * Common function for mapping DMA-safe memory. May be called by
+ * bus-specific DMA memory map functions.
+ */
+int
+_bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
+ size_t size, caddr_t *kvap, int flags)
+{
+ vaddr_t va;
+ bus_addr_t addr;
+ int curseg;
+ pt_entry_t *ptep/*, pte*/;
+
+#ifdef DEBUG_DMA
+ printf("dmamem_map: t=%p segs=%p nsegs=%x size=%lx flags=%x\n", t,
+ segs, nsegs, (unsigned long)size, flags);
+#endif /* DEBUG_DMA */
+
+ size = round_page(size);
+ va = uvm_km_valloc(kernel_map, size);
+
+ if (va == 0)
+ return (ENOMEM);
+
+ *kvap = (caddr_t)va;
+
+ for (curseg = 0; curseg < nsegs; curseg++) {
+ for (addr = segs[curseg].ds_addr;
+ addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
+ addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) {
+#ifdef DEBUG_DMA
+ printf("wiring p%lx to v%lx", addr, va);
+#endif /* DEBUG_DMA */
+ if (size == 0)
+ panic("_bus_dmamem_map: size botch");
+ pmap_enter(pmap_kernel(), va, addr,
+ VM_PROT_READ | VM_PROT_WRITE,
+ VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
+ /*
+ * If the memory must remain coherent with the
+ * cache then we must make the memory uncacheable
+ * in order to maintain virtual cache coherency.
+ * We must also guarantee the cache does not already
+ * contain the virtal addresses we are making
+ * uncacheable.
+ */
+ if (flags & BUS_DMA_COHERENT) {
+ cpu_dcache_wbinv_range(va, PAGE_SIZE);
+ cpu_drain_writebuf();
+ ptep = vtopte(va);
+ *ptep &= ~L2_S_CACHE_MASK;
+ PTE_SYNC(ptep);
+ tlb_flush();
+ }
+#ifdef DEBUG_DMA
+ ptep = vtopte(va);
+ printf(" pte=v%p *pte=%x\n", ptep, *ptep);
+#endif /* DEBUG_DMA */
+ }
+ }
+ pmap_update(pmap_kernel());
+#ifdef DEBUG_DMA
+ printf("dmamem_map: =%p\n", *kvap);
+#endif /* DEBUG_DMA */
+ return (0);
+}
+
+/*
+ * Common function for unmapping DMA-safe memory. May be called by
+ * bus-specific DMA memory unmapping functions.
+ */
+void
+_bus_dmamem_unmap(bus_dma_tag_t t, caddr_t kva, size_t size)
+{
+
+#ifdef DEBUG_DMA
+ printf("dmamem_unmap: t=%p kva=%p size=%lx\n", t, kva,
+ (unsigned long)size);
+#endif /* DEBUG_DMA */
+#ifdef DIAGNOSTIC
+ if ((u_long)kva & PGOFSET)
+ panic("_bus_dmamem_unmap");
+#endif /* DIAGNOSTIC */
+
+ size = round_page(size);
+ uvm_km_free(kernel_map, (vaddr_t)kva, size);
+}
+
+/*
+ * Common functin for mmap(2)'ing DMA-safe memory. May be called by
+ * bus-specific DMA mmap(2)'ing functions.
+ */
+paddr_t
+_bus_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
+ off_t off, int prot, int flags)
+{
+ int i;
+
+ for (i = 0; i < nsegs; i++) {
+#ifdef DIAGNOSTIC
+ if (off & PGOFSET)
+ panic("_bus_dmamem_mmap: offset unaligned");
+ if (segs[i].ds_addr & PGOFSET)
+ panic("_bus_dmamem_mmap: segment unaligned");
+ if (segs[i].ds_len & PGOFSET)
+ panic("_bus_dmamem_mmap: segment size not multiple"
+ " of page size");
+#endif /* DIAGNOSTIC */
+ if (off >= segs[i].ds_len) {
+ off -= segs[i].ds_len;
+ continue;
+ }
+
+ return (arm_btop((u_long)segs[i].ds_addr + off));
+ }
+
+ /* Page not found. */
+ return (-1);
+}
+
+/**********************************************************************
+ * DMA utility functions
+ **********************************************************************/
+
+/*
+ * Utility function to load a linear buffer. lastaddrp holds state
+ * between invocations (for multiple-buffer loads). segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ * first indicates if this is the first invocation of this function.
+ */
+int
+_bus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+ bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
+ int *segp, int first)
+{
+ struct arm32_dma_range *dr;
+ bus_size_t sgsize;
+ bus_addr_t curaddr, lastaddr, baddr, bmask;
+ vaddr_t vaddr = (vaddr_t)buf;
+ pd_entry_t *pde;
+ pt_entry_t pte;
+ int seg;
+ pmap_t pmap;
+ pt_entry_t *ptep;
+
+#ifdef DEBUG_DMA
+ printf("_bus_dmamem_load_buffer(buf=%p, len=%lx, flags=%d, 1st=%d)\n",
+ buf, buflen, flags, first);
+#endif /* DEBUG_DMA */
+
+ if (p != NULL)
+ pmap = p->p_vmspace->vm_map.pmap;
+ else
+ pmap = pmap_kernel();
+
+ lastaddr = *lastaddrp;
+ bmask = ~(map->_dm_boundary - 1);
+
+ for (seg = *segp; buflen > 0; ) {
+ /*
+ * Get the physical address for this segment.
+ *
+ * XXX Don't support checking for coherent mappings
+ * XXX in user address space.
+ */
+ if (__predict_true(pmap == pmap_kernel())) {
+ (void) pmap_get_pde_pte(pmap, vaddr, &pde, &ptep);
+ if (__predict_false(pmap_pde_section(pde))) {
+ curaddr = (*pde & L1_S_FRAME) |
+ (vaddr & L1_S_OFFSET);
+ if (*pde & L1_S_CACHE_MASK) {
+ map->_dm_flags &=
+ ~ARM32_DMAMAP_COHERENT;
+ }
+ } else {
+ pte = *ptep;
+ KDASSERT((pte & L2_TYPE_MASK) != L2_TYPE_INV);
+ if (__predict_false((pte & L2_TYPE_MASK)
+ == L2_TYPE_L)) {
+ curaddr = (pte & L2_L_FRAME) |
+ (vaddr & L2_L_OFFSET);
+ if (pte & L2_L_CACHE_MASK) {
+ map->_dm_flags &=
+ ~ARM32_DMAMAP_COHERENT;
+ }
+ } else {
+ curaddr = (pte & L2_S_FRAME) |
+ (vaddr & L2_S_OFFSET);
+ if (pte & L2_S_CACHE_MASK) {
+ map->_dm_flags &=
+ ~ARM32_DMAMAP_COHERENT;
+ }
+ }
+ }
+ } else {
+ (void) pmap_extract(pmap, vaddr, &curaddr);
+ map->_dm_flags &= ~ARM32_DMAMAP_COHERENT;
+ }
+
+ /*
+ * Make sure we're in an allowed DMA range.
+ */
+ if (t->_ranges != NULL) {
+ /* XXX cache last result? */
+ dr = _bus_dma_inrange(t->_ranges, t->_nranges,
+ curaddr);
+ if (dr == NULL)
+ return (EINVAL);
+
+ /*
+ * In a valid DMA range. Translate the physical
+ * memory address to an address in the DMA window.
+ */
+ curaddr = (curaddr - dr->dr_sysbase) + dr->dr_busbase;
+ }
+
+ /*
+ * Compute the segment size, and adjust counts.
+ */
+ sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET);
+ if (buflen < sgsize)
+ sgsize = buflen;
+
+ /*
+ * Make sure we don't cross any boundaries.
+ */
+ if (map->_dm_boundary > 0) {
+ baddr = (curaddr + map->_dm_boundary) & bmask;
+ if (sgsize > (baddr - curaddr))
+ sgsize = (baddr - curaddr);
+ }
+
+ /*
+ * Insert chunk into a segment, coalescing with
+ * previous segment if possible.
+ */
+ if (first) {
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ first = 0;
+ } else {
+ if (curaddr == lastaddr &&
+ (map->dm_segs[seg].ds_len + sgsize) <=
+ map->_dm_maxsegsz &&
+ (map->_dm_boundary == 0 ||
+ (map->dm_segs[seg].ds_addr & bmask) ==
+ (curaddr & bmask)))
+ map->dm_segs[seg].ds_len += sgsize;
+ else {
+ if (++seg >= map->_dm_segcnt)
+ break;
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ }
+ }
+
+ lastaddr = curaddr + sgsize;
+ vaddr += sgsize;
+ buflen -= sgsize;
+ }
+
+ *segp = seg;
+ *lastaddrp = lastaddr;
+
+ /*
+ * Did we fit?
+ */
+ if (buflen != 0)
+ return (EFBIG); /* XXX better return value here? */
+ return (0);
+}
+
+/*
+ * Allocate physical memory from the given physical address range.
+ * Called by DMA-safe memory allocation methods.
+ */
+int
+_bus_dmamem_alloc_range(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment,
+ bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs,
+ int flags, paddr_t low, paddr_t high)
+{
+ paddr_t curaddr, lastaddr;
+ struct vm_page *m;
+ struct pglist mlist;
+ int curseg, error;
+
+#ifdef DEBUG_DMA
+ printf("alloc_range: t=%p size=%lx align=%lx boundary=%lx segs=%p nsegs=%x rsegs=%p flags=%x lo=%lx hi=%lx\n",
+ t, size, alignment, boundary, segs, nsegs, rsegs, flags, low, high);
+#endif /* DEBUG_DMA */
+
+ /* Always round the size. */
+ size = round_page(size);
+
+ TAILQ_INIT(&mlist);
+ /*
+ * Allocate pages from the VM system.
+ */
+ error = uvm_pglistalloc(size, low, high, alignment, boundary,
+ &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
+ if (error)
+ return (error);
+
+ /*
+ * Compute the location, size, and number of segments actually
+ * returned by the VM code.
+ */
+ m = mlist.tqh_first;
+ curseg = 0;
+ lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
+ segs[curseg].ds_len = PAGE_SIZE;
+#ifdef DEBUG_DMA
+ printf("alloc: page %lx\n", lastaddr);
+#endif /* DEBUG_DMA */
+ m = m->pageq.tqe_next;
+
+ for (; m != NULL; m = m->pageq.tqe_next) {
+ curaddr = VM_PAGE_TO_PHYS(m);
+#ifdef DIAGNOSTIC
+ if (curaddr < low || curaddr >= high) {
+ printf("uvm_pglistalloc returned non-sensical"
+ " address 0x%lx\n", curaddr);
+ panic("_bus_dmamem_alloc_range");
+ }
+#endif /* DIAGNOSTIC */
+#ifdef DEBUG_DMA
+ printf("alloc: page %lx\n", curaddr);
+#endif /* DEBUG_DMA */
+ if (curaddr == (lastaddr + PAGE_SIZE))
+ segs[curseg].ds_len += PAGE_SIZE;
+ else {
+ curseg++;
+ segs[curseg].ds_addr = curaddr;
+ segs[curseg].ds_len = PAGE_SIZE;
+ }
+ lastaddr = curaddr;
+ }
+
+ *rsegs = curseg + 1;
+
+ return (0);
+}
+
+/*
+ * Check if a memory region intersects with a DMA range, and return the
+ * page-rounded intersection if it does.
+ */
+int
+arm32_dma_range_intersect(struct arm32_dma_range *ranges, int nranges,
+ paddr_t pa, psize_t size, paddr_t *pap, psize_t *sizep)
+{
+ struct arm32_dma_range *dr;
+ int i;
+
+ if (ranges == NULL)
+ return (0);
+
+ for (i = 0, dr = ranges; i < nranges; i++, dr++) {
+ if (dr->dr_sysbase <= pa &&
+ pa < (dr->dr_sysbase + dr->dr_len)) {
+ /*
+ * Beginning of region intersects with this range.
+ */
+ *pap = trunc_page(pa);
+ *sizep = round_page(min(pa + size,
+ dr->dr_sysbase + dr->dr_len) - pa);
+ return (1);
+ }
+ if (pa < dr->dr_sysbase && dr->dr_sysbase < (pa + size)) {
+ /*
+ * End of region intersects with this range.
+ */
+ *pap = trunc_page(dr->dr_sysbase);
+ *sizep = round_page(min((pa + size) - dr->dr_sysbase,
+ dr->dr_len));
+ return (1);
+ }
+ }
+
+ /* No intersection found. */
+ return (0);
+}
diff --git a/sys/arch/arm/arm/bus_space_asm_generic.S b/sys/arch/arm/arm/bus_space_asm_generic.S
new file mode 100644
index 00000000000..80817e5008b
--- /dev/null
+++ b/sys/arch/arm/arm/bus_space_asm_generic.S
@@ -0,0 +1,352 @@
+/* $OpenBSD: bus_space_asm_generic.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: bus_space_asm_generic.S,v 1.3 2003/03/27 19:46:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1997 Causality Limited.
+ * Copyright (c) 1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arm/asm.h>
+#include <arm/cpuconf.h>
+
+/*
+ * Generic bus_space functions.
+ */
+
+/*
+ * read single
+ */
+
+ENTRY(generic_bs_r_1)
+ ldrb r0, [r1, r2]
+ mov pc, lr
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_r_2)
+ ldrh r0, [r1, r2]
+ mov pc, lr
+#endif
+
+ENTRY(generic_bs_r_4)
+ ldr r0, [r1, r2]
+ mov pc, lr
+
+/*
+ * write single
+ */
+
+ENTRY(generic_bs_w_1)
+ strb r3, [r1, r2]
+ mov pc, lr
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_w_2)
+ strh r3, [r1, r2]
+ mov pc, lr
+#endif
+
+ENTRY(generic_bs_w_4)
+ str r3, [r1, r2]
+ mov pc, lr
+
+/*
+ * read multiple
+ */
+
+ENTRY(generic_bs_rm_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrb r3, [r0]
+ strb r3, [r1], #1
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_rm_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrh r3, [r0]
+ strh r3, [r1], #2
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+#endif
+
+ENTRY(generic_bs_rm_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldr r3, [r0]
+ str r3, [r1], #4
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+/*
+ * write multiple
+ */
+
+ENTRY(generic_bs_wm_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrb r3, [r1], #1
+ strb r3, [r0]
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_wm_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrh r3, [r1], #2
+ strh r3, [r0]
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+#endif
+
+ENTRY(generic_bs_wm_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldr r3, [r1], #4
+ str r3, [r0]
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+/*
+ * read region
+ */
+
+ENTRY(generic_bs_rr_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrb r3, [r0], #1
+ strb r3, [r1], #1
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_rr_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrh r3, [r0], #2
+ strh r3, [r1], #2
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+#endif
+
+ENTRY(generic_bs_rr_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldr r3, [r0], #4
+ str r3, [r1], #4
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+/*
+ * write region.
+ */
+
+ENTRY(generic_bs_wr_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_wr_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldrh r3, [r1], #2
+ strh r3, [r0], #2
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+#endif
+
+ENTRY(generic_bs_wr_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: ldr r3, [r1], #4
+ str r3, [r0], #4
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+/*
+ * set region
+ */
+
+ENTRY(generic_bs_sr_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: strb r1, [r0], #1
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_sr_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: strh r1, [r0], #2
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+#endif
+
+ENTRY(generic_bs_sr_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+1: str r1, [r0], #4
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+/*
+ * copy region
+ */
+
+#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
+ENTRY(generic_armv4_bs_c_2)
+ add r0, r1, r2
+ ldr r2, [sp, #0]
+ add r1, r2, r3
+ ldr r2, [sp, #4]
+ teq r2, #0
+ moveq pc, lr
+
+ cmp r0, r1
+ blt 2f
+
+1: ldrh r3, [r0], #2
+ strh r3, [r1], #2
+ subs r2, r2, #1
+ bne 1b
+
+ mov pc, lr
+
+2: add r0, r0, r2, lsl #1
+ add r1, r1, r2, lsl #1
+ sub r0, r0, #2
+ sub r1, r1, #2
+
+3: ldrh r3, [r0], #-2
+ strh r3, [r1], #-2
+ subs r2, r2, #1
+ bne 3b
+
+ mov pc, lr
+#endif
diff --git a/sys/arch/arm/arm/bus_space_notimpl.S b/sys/arch/arm/arm/bus_space_notimpl.S
new file mode 100644
index 00000000000..a0a51be2d47
--- /dev/null
+++ b/sys/arch/arm/arm/bus_space_notimpl.S
@@ -0,0 +1,160 @@
+/* $OpenBSD: bus_space_notimpl.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: bus_space_notimpl.S,v 1.2 2001/09/10 02:20:19 reinoud Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+/*
+ * BUS_SPACE - name of this bus space
+ */
+
+#define BUS_SPACE bs_notimpl
+
+#define __C(x,y) __CONCAT(x,y)
+#define __S(s) __STRING(s)
+#define NAME(func) __C(BUS_SPACE,__C(_bs_,func))
+#define LNAME(func) __C(L,NAME(func))
+
+#define __L(x) _C_LABEL(x)
+#define GLOBAL(func) .global __L(NAME(func))
+#define LABEL(func) __L(NAME(func)):
+#define LLABEL(func) LNAME(func):
+
+#define FTEXT(func,text) __S(__C(NAME(func),text))
+
+
+#define NOT_IMPL(func) \
+ GLOBAL(func) ; \
+LABEL(func) ; \
+ stmfd sp!, {r0-r3} ; \
+ adr r0, LNAME(__C(func,_text)) ; \
+ mov r1, sp ; \
+ b _C_LABEL(panic) ; \
+ ; \
+LLABEL(__C(func,_text)) ; \
+ .asciz FTEXT(func,: args at 0x%08x\n) ; \
+ .align 0 ;
+
+
+/*
+ * misc functions
+ */
+
+NOT_IMPL(mmap)
+
+
+/*
+ * Generic bus_space I/O functions
+ */
+
+/*
+ * read single
+ */
+
+NOT_IMPL(r_1)
+NOT_IMPL(r_2)
+NOT_IMPL(r_4)
+NOT_IMPL(r_8)
+
+/*
+ * write single
+ */
+
+NOT_IMPL(w_1)
+NOT_IMPL(w_2)
+NOT_IMPL(w_4)
+NOT_IMPL(w_8)
+
+/*
+ * read multiple
+ */
+
+NOT_IMPL(rm_1)
+NOT_IMPL(rm_2)
+NOT_IMPL(rm_4)
+NOT_IMPL(rm_8)
+
+/*
+ * write multiple
+ */
+
+NOT_IMPL(wm_1)
+NOT_IMPL(wm_2)
+NOT_IMPL(wm_4)
+NOT_IMPL(wm_8)
+
+/*
+ * read region
+ */
+
+NOT_IMPL(rr_1)
+NOT_IMPL(rr_2)
+NOT_IMPL(rr_4)
+NOT_IMPL(rr_8)
+
+/*
+ * write region
+ */
+
+NOT_IMPL(wr_1)
+NOT_IMPL(wr_2)
+NOT_IMPL(wr_4)
+NOT_IMPL(wr_8)
+
+/*
+ * set multiple
+ */
+
+NOT_IMPL(sm_1)
+NOT_IMPL(sm_2)
+NOT_IMPL(sm_4)
+NOT_IMPL(sm_8)
+
+/*
+ * set region
+ */
+
+NOT_IMPL(sr_1)
+NOT_IMPL(sr_2)
+NOT_IMPL(sr_4)
+NOT_IMPL(sr_8)
+
+/*
+ * copy
+ */
+
+NOT_IMPL(c_1)
+NOT_IMPL(c_2)
+NOT_IMPL(c_4)
+NOT_IMPL(c_8)
diff --git a/sys/arch/arm/arm/conf.c b/sys/arch/arm/arm/conf.c
new file mode 100644
index 00000000000..dd8a21bcf46
--- /dev/null
+++ b/sys/arch/arm/arm/conf.c
@@ -0,0 +1,525 @@
+/* $OpenBSD: conf.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: conf.c,v 1.10 2002/04/19 01:04:38 wiz Exp $ */
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * conf.c
+ *
+ * Character and Block Device configuration
+ * Console configuration
+ *
+ * Defines the structures cdevsw and constab
+ *
+ * Created : 17/09/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/conf.h>
+#include <sys/vnode.h>
+
+#include <machine/conf.h>
+
+/*
+ * From this point, these need to be MI foo.h files.
+ */
+
+/*
+ * Standard MI devices (e.g. ones in dev/ic)
+ */
+#include "com.h" /* NS164x0 serial ports */
+
+/*
+ * Standard pseudo-devices
+ */
+#include "bpfilter.h"
+#include "pf.h"
+#include "pty.h"
+#include "tun.h"
+
+/*
+ * Disk/Filesystem pseudo-devices
+ */
+#include "ccd.h" /* concatenated disk driver */
+#include "rd.h" /* memory disk driver */
+#include "raid.h" /* RAIDframe */
+#include "vnd.h" /* vnode disk driver */
+
+/*
+ * WD/ATA devices
+ */
+#include "wd.h"
+bdev_decl(wd);
+bdev_decl(sw);
+
+/*
+ * ISDN devices
+ */
+#ifdef CONF_HAVE_ISDN
+#include "isdn.h"
+#include "isdnctl.h"
+#include "isdntrc.h"
+#include "isdnbchan.h"
+#include "isdntel.h"
+#else
+#define NISDN 0
+#define NISDNCTL 0
+#define NISDNTRC 0
+#define NISDNBCHAN 0
+#define NISDNTEL 0
+#endif
+
+#ifdef CONF_HAVE_PCI
+#include "iop.h"
+#include "pci.h"
+#else
+#define NIOP 0
+#define NMLX 0
+#define NMLY 0
+#define NPCI 0
+#endif
+#define NAGP 0
+/*
+ * SCSI/ATAPI devices
+ */
+#include "sd.h"
+#include "st.h"
+#include "cd.h"
+#include "ch.h"
+#include "uk.h"
+#include "ss.h"
+
+/*
+ * Audio devices
+ */
+#include "audio.h"
+#include "midi.h"
+#include "sequencer.h"
+
+/*
+ * USB devices
+ */
+#include "usb.h"
+#include "ucom.h"
+#include "ugen.h"
+#include "uhid.h"
+#include "ulpt.h"
+#include "urio.h"
+#include "uscanner.h"
+
+/*
+ * WSCONS devices
+ */
+#include "wsdisplay.h"
+/*
+#include "wsfont.h"
+*/
+#include "wskbd.h"
+#include "wsmouse.h"
+#include "wsmux.h"
+cdev_decl(wskbd);
+cdev_decl(wsmouse);
+
+#include "lpt.h"
+
+#include "radio.h"
+cdev_decl(radio);
+
+#include <arm/conf.h>
+
+/* Block devices */
+
+struct bdevsw bdevsw[] = {
+ bdev_lkm_dummy(), /* 0: */
+ bdev_swap_init(1, sw), /* 1: swap pseudo-device */
+ bdev_lkm_dummy(), /* 2: */
+ bdev_lkm_dummy(), /* 3: */
+ bdev_lkm_dummy(), /* 4: */
+ bdev_lkm_dummy(), /* 5: */
+ bdev_lkm_dummy(), /* 6: */
+ bdev_lkm_dummy(), /* 7: */
+ bdev_lkm_dummy(), /* 8: */
+ bdev_lkm_dummy(), /* 9: */
+ bdev_lkm_dummy(), /* 10: */
+ bdev_lkm_dummy(), /* 11: */
+ bdev_lkm_dummy(), /* 12: */
+ bdev_lkm_dummy(), /* 13: */
+ bdev_lkm_dummy(), /* 14: */
+ bdev_lkm_dummy(), /* 15: */
+ bdev_disk_init(NWD,wd), /* 16: Internal IDE disk */
+ bdev_lkm_dummy(), /* 17: */
+ bdev_disk_init(NRD,rd), /* 18: memory disk */
+ bdev_disk_init(NVND,vnd), /* 19: vnode disk driver */
+ bdev_lkm_dummy(), /* 20: */
+ bdev_disk_init(NCCD,ccd), /* 21: concatenated disk driver */
+ bdev_lkm_dummy(), /* 22: */
+ bdev_lkm_dummy(), /* 23: */
+ bdev_disk_init(NSD,sd), /* 24: SCSI disk */
+ bdev_tape_init(NST,st), /* 25: SCSI tape */
+ bdev_disk_init(NCD,cd), /* 26: SCSI cdrom */
+ bdev_lkm_dummy(), /* 27: */
+ bdev_lkm_dummy(), /* 28: */
+ bdev_lkm_dummy(), /* 29: */
+ bdev_lkm_dummy(), /* 30: */
+ bdev_lkm_dummy(), /* 31: */
+ bdev_lkm_dummy(), /* 32: */
+ bdev_lkm_dummy(), /* 33: */
+ bdev_lkm_dummy(), /* 34: */
+ bdev_lkm_dummy(), /* 35: */
+ bdev_lkm_dummy(), /* 36: */
+ bdev_lkm_dummy(), /* 37: */
+ bdev_lkm_dummy(), /* 38: */
+ bdev_lkm_dummy(), /* 39: */
+ bdev_lkm_dummy(), /* 40: */
+ bdev_lkm_dummy(), /* 41: */
+ bdev_lkm_dummy(), /* 42: */
+ bdev_lkm_dummy(), /* 43: */
+ bdev_lkm_dummy(), /* 44: */
+ bdev_lkm_dummy(), /* 45: */
+ bdev_lkm_dummy(), /* 46: */
+ bdev_lkm_dummy(), /* 47: */
+ bdev_lkm_dummy(), /* 48: */
+ bdev_lkm_dummy(), /* 49: */
+ bdev_lkm_dummy(), /* 50: */
+ bdev_lkm_dummy(), /* 51: */
+ bdev_lkm_dummy(), /* 52: */
+ bdev_lkm_dummy(), /* 53: */
+ bdev_lkm_dummy(), /* 54: */
+ bdev_lkm_dummy(), /* 55: */
+ bdev_lkm_dummy(), /* 56: */
+ bdev_lkm_dummy(), /* 57: */
+ bdev_lkm_dummy(), /* 58: */
+ bdev_lkm_dummy(), /* 59: */
+ bdev_lkm_dummy(), /* 60: */
+ bdev_lkm_dummy(), /* 61: */
+ bdev_lkm_dummy(), /* 62: */
+ bdev_lkm_dummy(), /* 63: */
+ bdev_lkm_dummy(), /* 64: */
+ bdev_lkm_dummy(), /* 65: */
+ bdev_lkm_dummy(), /* 66: */
+ bdev_lkm_dummy(), /* 67: */
+ bdev_lkm_dummy(), /* 68: */
+ bdev_lkm_dummy(), /* 69: */
+ bdev_lkm_dummy(), /* 70: */
+ bdev_disk_init(NRAID,raid), /* 71: RAIDframe disk driver */
+ bdev_lkm_dummy(), /* 72: */
+ bdev_lkm_dummy(), /* 73: */
+ bdev_lkm_dummy(), /* 74: */
+ bdev_lkm_dummy(), /* 75: */
+ bdev_lkm_dummy(), /* 76: */
+ bdev_lkm_dummy(), /* 77: */
+ bdev_lkm_dummy(), /* 78: */
+ bdev_lkm_dummy(), /* 79: */
+ bdev_lkm_dummy(), /* 80: */
+ bdev_lkm_dummy(), /* 81: */
+ bdev_lkm_dummy(), /* 82: */
+ bdev_lkm_dummy(), /* 83: */
+ bdev_lkm_dummy(), /* 84: */
+ bdev_lkm_dummy(), /* 85: */
+ bdev_lkm_dummy(), /* 86: */
+ bdev_lkm_dummy(), /* 87: */
+ bdev_lkm_dummy(), /* 88: */
+ bdev_lkm_dummy(), /* 89: */
+ bdev_lkm_dummy(), /* 90: */
+ bdev_lkm_dummy(), /* 91: */
+ bdev_lkm_dummy(), /* 93: */
+ bdev_lkm_dummy(), /* 94: */
+ bdev_lkm_dummy(), /* 95: */
+ bdev_lkm_dummy(), /* 96: */
+ bdev_lkm_dummy(), /* 97: */
+};
+
+/* Character devices */
+cdev_decl(isdn);
+cdev_decl(isdnctl);
+cdev_decl(isdntrc);
+cdev_decl(isdnbchan);
+cdev_decl(isdntel);
+#define ptstty ptytty
+#define ptsioctl ptyioctl
+#define ptctty ptytty
+#define ptcioctl ptyioctl
+
+struct cdevsw cdevsw[] = {
+ cdev_cn_init(1,cn), /* 0: virtual console */
+ cdev_ctty_init(1,ctty), /* 1: controlling terminal */
+ cdev_mm_init(1,mm), /* 2: /dev/{null,mem,kmem,...} */
+ cdev_swap_init(1,sw), /* 3: /dev/drum (swap pseudo-device) */
+ cdev_tty_init(NPTY,pts), /* 4: pseudo-tty slave */
+ cdev_ptc_init(NPTY,ptc), /* 5: pseudo-tty master */
+ cdev_log_init(1,log), /* 6: /dev/klog */
+ cdev_fd_init(1,filedesc), /* 7: file descriptor pseudo-device */
+ cdev_lkm_dummy(), /* 8: */
+ cdev_lpt_init(NLPT,lpt), /* 9: parallel printer */
+ cdev_lkm_dummy(), /* 10: */
+ cdev_lkm_dummy(), /* 11: */
+ cdev_tty_init(NCOM,com), /* 12: serial port */
+ cdev_lkm_dummy(), /* 13: */
+ cdev_lkm_dummy(), /* 14: */
+ cdev_lkm_dummy(), /* 15: */
+ cdev_disk_init(NWD,wd), /* 16: ST506/ESDI/IDE disk */
+ cdev_lkm_dummy(), /* 17: */
+ cdev_disk_init(NRD,rd), /* 18: ram disk driver */
+ cdev_disk_init(NVND,vnd), /* 19: vnode disk driver */
+ cdev_lkm_dummy(), /* 20: */
+ cdev_disk_init(NCCD,ccd), /* 21: concatenated disk driver */
+ cdev_bpftun_init(NBPFILTER,bpf), /* 22: Berkeley packet filter */
+ cdev_lkm_dummy(), /* 23: */
+ cdev_disk_init(NSD,sd), /* 24: SCSI disk */
+ cdev_tape_init(NST,st), /* 25: SCSI tape */
+ cdev_disk_init(NCD,cd), /* 26: SCSI CD-ROM */
+ cdev_ch_init(NCH,ch), /* 27: SCSI autochanger */
+ cdev_uk_init(NUK,uk), /* 28: SCSI unknown */
+ cdev_scanner_init(NSS,ss), /* 29: SCSI scanner */
+ cdev_lkm_dummy(), /* 30: */
+ cdev_lkm_dummy(), /* 31: */
+ cdev_lkm_dummy(), /* 32: */
+ cdev_bpftun_init(NTUN,tun), /* 33: network tunnel */
+ cdev_lkm_dummy(), /* 34: */
+ cdev_lkm_init(NLKM,lkm), /* 35: loadable module driver */
+ cdev_audio_init(NAUDIO,audio), /* 36: generic audio I/O */
+ cdev_notdef(), /* 37: removed cpu device */
+ cdev_notdef(), /* 38: removed cpu device */
+ cdev_lkm_dummy(), /* 39: reserved */
+ cdev_lkm_dummy(), /* 40: reserved */
+ cdev_lkm_dummy(), /* 41: reserved */
+ cdev_lkm_dummy(), /* 42: reserved */
+ cdev_lkm_dummy(), /* 43: reserved */
+ cdev_lkm_dummy(), /* 44: reserved */
+ cdev_lkm_dummy(), /* 45: reserved */
+ cdev_pf_init(NPF,pf), /* 39: packet filter */
+ cdev_lkm_dummy(), /* 47: reserved */
+ cdev_lkm_dummy(), /* 48: reserved */
+ cdev_lkm_dummy(), /* 49: reserved */
+ cdev_lkm_dummy(), /* 50: reserved */
+ cdev_notdef(), /* 51: reserved */
+ cdev_notdef(), /* 52: reserved */
+ cdev_notdef(), /* 53: reserved */
+ cdev_tty_init(NFCOM,fcom), /* 54: FOOTBRIDGE console */
+ cdev_lkm_dummy(), /* 55: Reserved for bypass device */
+ cdev_notdef(), /* 56: reserved */
+ cdev_midi_init(NMIDI,midi), /* 57: MIDI I/O */
+ cdev_midi_init(NSEQUENCER,sequencer), /* 58: sequencer I/O */
+ cdev_notdef(), /* 59: reserved */
+ cdev_wsdisplay_init(NWSDISPLAY,wsdisplay), /* 60: frame buffers, etc.*/
+ cdev_mouse_init(NWSKBD,wskbd), /* 61: keyboards */
+ cdev_mouse_init(NWSMOUSE,wsmouse), /* 62: mice */
+ cdev_mouse_init(NWSMUX,wsmux), /* 63: ws multiplexor */
+ cdev_usb_init(NUSB,usb), /* 64: USB controller */
+ cdev_usbdev_init(NUHID,uhid), /* 65: USB generic HID */
+ cdev_lpt_init(NULPT,ulpt), /* 66: USB printer */
+ cdev_urio_init(NURIO,urio), /* 67: Diamond Rio 500 */
+ cdev_tty_init(NUCOM,ucom), /* 68: USB tty */
+ cdev_usbdev_init(NUSCANNER,uscanner), /* 69: USB scanner */
+ cdev_usbdev_init(NUGEN,ugen), /* 70: USB generic driver */
+ cdev_disk_init(NRAID,raid), /* 71: RAIDframe disk driver */
+ cdev_lkm_dummy(), /* 72: reserved */
+ cdev_lkm_dummy(), /* 73: reserved */
+ cdev_lkm_dummy(), /* 74: reserved */
+ cdev_lkm_dummy(), /* 75: reserved */
+ cdev_lkm_dummy(), /* 76: reserved */
+ cdev_notdef(), /* 77: removed device */
+ cdev_notdef(), /* 78: removed device */
+ cdev_notdef(), /* 79: removed device */
+ cdev_notdef(), /* 80: removed device */
+ cdev_notdef(), /* 81: removed device */
+ cdev_notdef(), /* 82: removed device */
+ cdev_notdef(), /* 83: removed device */
+ cdev_notdef(), /* 84: removed device */
+ cdev_notdef(), /* 85: removed device */
+ cdev_notdef(), /* 86: removed device */
+ cdev_notdef(), /* 87: removed device */
+ cdev_notdef(), /* 88: removed device */
+ cdev_notdef(), /* 89: removed device */
+ cdev_notdef(), /* 90: removed device */
+ cdev_notdef(), /* 91: removed device */
+ cdev_notdef(), /* 92: removed device */
+ cdev_notdef(), /* 93: removed device */
+ cdev_notdef(), /* 94: removed device */
+ cdev_notdef(), /* 95: removed device */
+ cdev_notdef(), /* 96: removed device */
+ cdev_radio_init(NRADIO,radio), /* 97: generic radio I/O */
+};
+
+int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]);
+int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]);
+
+int mem_no = 2; /* major device number of memory special file */
+
+/*
+ * Swapdev is a fake device implemented
+ * in sw.c used only internally to get to swstrategy.
+ * It cannot be provided to the users, because the
+ * swstrategy routine munches the b_dev and b_blkno entries
+ * before calling the appropriate driver. This would horribly
+ * confuse, e.g. the hashing routines. Instead, /dev/drum is
+ * provided as a character (raw) device.
+ */
+dev_t swapdev = makedev(1, 0);
+
+/*
+ * Returns true if dev is /dev/mem or /dev/kmem.
+ */
+int
+iskmemdev(dev)
+ dev_t dev;
+{
+ return (major(dev) == mem_no && minor(dev) < 2);
+}
+
+/*
+ * Returns true if dev is /dev/zero.
+ */
+int
+iszerodev(dev)
+ dev_t dev;
+{
+ return (major(dev) == mem_no && minor(dev) == 3);
+}
+
+
+int chrtoblktbl[] = {
+/* XXXX This needs to be dynamic for LKMs. */
+ /*VCHR*/ /*VBLK*/
+ /* 0 */ NODEV,
+ /* 1 */ 1,
+ /* 2 */ NODEV,
+ /* 3 */ NODEV,
+ /* 4 */ NODEV,
+ /* 5 */ NODEV,
+ /* 6 */ NODEV,
+ /* 7 */ NODEV,
+ /* 8 */ NODEV,
+ /* 9 */ NODEV,
+ /* 10 */ NODEV,
+ /* 11 */ NODEV,
+ /* 12 */ NODEV,
+ /* 13 */ NODEV,
+ /* 14 */ NODEV,
+ /* 15 */ NODEV,
+ /* 16 */ 16,
+ /* 17 */ 17,
+ /* 18 */ 18,
+ /* 19 */ 19,
+ /* 20 */ NODEV,
+ /* 21 */ 21,
+ /* 22 */ NODEV,
+ /* 23 */ NODEV,
+ /* 24 */ 24,
+ /* 25 */ 25,
+ /* 26 */ 26,
+ /* 27 */ NODEV,
+ /* 28 */ NODEV,
+ /* 29 */ NODEV,
+ /* 30 */ NODEV,
+ /* 31 */ NODEV,
+ /* 32 */ NODEV,
+ /* 33 */ NODEV,
+ /* 34 */ NODEV,
+ /* 35 */ NODEV,
+ /* 36 */ NODEV,
+ /* 37 */ NODEV,
+ /* 38 */ NODEV,
+ /* 39 */ NODEV,
+ /* 40 */ NODEV,
+ /* 41 */ NODEV,
+ /* 42 */ NODEV,
+ /* 43 */ NODEV,
+ /* 44 */ NODEV,
+ /* 45 */ NODEV,
+ /* 46 */ NODEV,
+ /* 47 */ NODEV,
+ /* 48 */ NODEV,
+ /* 49 */ NODEV,
+ /* 50 */ NODEV,
+ /* 51 */ NODEV,
+ /* 52 */ NODEV,
+ /* 53 */ NODEV,
+ /* 54 */ NODEV,
+ /* 55 */ NODEV,
+ /* 56 */ NODEV,
+ /* 57 */ NODEV,
+ /* 58 */ NODEV,
+ /* 59 */ NODEV,
+ /* 60 */ NODEV,
+ /* 61 */ NODEV,
+ /* 62 */ NODEV,
+ /* 63 */ NODEV,
+ /* 64 */ NODEV,
+ /* 65 */ NODEV,
+ /* 66 */ NODEV,
+ /* 67 */ NODEV,
+ /* 68 */ NODEV,
+ /* 69 */ NODEV,
+ /* 70 */ NODEV,
+ /* 71 */ 71,
+ /* 72 */ NODEV,
+ /* 73 */ NODEV,
+ /* 74 */ NODEV,
+ /* 75 */ NODEV,
+ /* 76 */ NODEV,
+ /* 77 */ NODEV,
+ /* 78 */ NODEV,
+ /* 79 */ NODEV,
+ /* 80 */ NODEV,
+ /* 81 */ NODEV,
+ /* 82 */ NODEV,
+ /* 83 */ NODEV,
+ /* 84 */ NODEV,
+ /* 85 */ NODEV,
+ /* 86 */ NODEV,
+ /* 87 */ NODEV,
+ /* 88 */ NODEV,
+ /* 89 */ NODEV,
+ /* 90 */ NODEV,
+ /* 91 */ NODEV,
+ /* 92 */ 92,
+ /* 93 */ NODEV,
+ /* 94 */ NODEV,
+ /* 95 */ NODEV,
+ /* 96 */ NODEV,
+ /* 97 */ NODEV,
+};
+int nchrtoblktbl = sizeof(chrtoblktbl) / sizeof(chrtoblktbl[0]);
+
+
+dev_t
+getnulldev()
+{
+ return makedev(mem_no, 2);
+}
diff --git a/sys/arch/arm/arm/copystr.S b/sys/arch/arm/arm/copystr.S
new file mode 100644
index 00000000000..c7d0e87696e
--- /dev/null
+++ b/sys/arch/arm/arm/copystr.S
@@ -0,0 +1,229 @@
+/* $OpenBSD: copystr.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: copystr.S,v 1.8 2002/10/13 14:54:48 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * copystr.S
+ *
+ * optimised and fault protected copystr functions
+ *
+ * Created : 16/05/95
+ */
+
+#include "assym.h"
+#include <machine/asm.h>
+#include <sys/errno.h>
+
+ .text
+ .align 0
+#ifdef MULTIPROCESSOR
+.Lcpu_info:
+ .word _C_LABEL(cpu_info)
+#else
+.Lcurpcb:
+ .word _C_LABEL(curpcb)
+#endif
+
+/*
+ * r0 - from
+ * r1 - to
+ * r2 - maxlens
+ * r3 - lencopied
+ *
+ * Copy string from r0 to r1
+ */
+ENTRY(copystr)
+ stmfd sp!, {r4-r5} /* stack is 8 byte aligned */
+ teq r2, #0x00000000
+ mov r5, #0x00000000
+ moveq r0, #ENAMETOOLONG
+ beq 2f
+
+1: ldrb r4, [r0], #0x0001
+ add r5, r5, #0x00000001
+ teq r4, #0x00000000
+ strb r4, [r1], #0x0001
+ teqne r5, r2
+ bne 1b
+
+ teq r4, #0x00000000
+ moveq r0, #0x00000000
+ movne r0, #ENAMETOOLONG
+
+2: teq r3, #0x00000000
+ strne r5, [r3]
+
+ ldmfd sp!, {r4-r5} /* stack is 8 byte aligned */
+ mov pc, lr
+
+#ifdef __PROG32
+#define SAVE_REGS stmfd sp!, {r4-r6}
+#define RESTORE_REGS ldmfd sp!, {r4-r6}
+#else
+/* Need to save R14_svc because it'll get trampled if we take a page fault. */
+#define SAVE_REGS stmfd sp!, {r4-r6, r14}
+#define RESTORE_REGS ldmfd sp!, {r4-r6, r14}
+#endif
+
+/*
+ * r0 - user space address
+ * r1 - kernel space address
+ * r2 - maxlens
+ * r3 - lencopied
+ *
+ * Copy string from user space to kernel space
+ */
+ENTRY(copyinstr)
+ SAVE_REGS
+
+ teq r2, #0x00000000
+ mov r6, #0x00000000
+ moveq r0, #ENAMETOOLONG
+ beq 2f
+
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r3, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r4, .Lcpu_info
+ ldr r4, [r4, r0, lsl #2]
+ ldr r4, [r4, #CI_CURPCB]
+ ldmfd sp!, {r0-r3, r14}
+#else
+ ldr r4, .Lcurpcb
+ ldr r4, [r4]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r4, #0x00000000
+ beq .Lcopystrpcbfault
+#endif
+
+ adr r5, .Lcopystrfault
+ str r5, [r4, #PCB_ONFAULT]
+
+1: ldrbt r5, [r0], #0x0001
+ add r6, r6, #0x00000001
+ teq r5, #0x00000000
+ strb r5, [r1], #0x0001
+ teqne r6, r2
+ bne 1b
+
+ mov r0, #0x00000000
+ str r0, [r4, #PCB_ONFAULT]
+
+ teq r5, #0x00000000
+ moveq r0, #0x00000000
+ movne r0, #ENAMETOOLONG
+
+2: teq r3, #0x00000000
+ strne r6, [r3]
+
+ RESTORE_REGS
+ mov pc, lr
+
+/*
+ * r0 - kernel space address
+ * r1 - user space address
+ * r2 - maxlens
+ * r3 - lencopied
+ *
+ * Copy string from kernel space to user space
+ */
+ENTRY(copyoutstr)
+ SAVE_REGS
+
+ teq r2, #0x00000000
+ mov r6, #0x00000000
+ moveq r0, #ENAMETOOLONG
+ beq 2f
+
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0-r3, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r4, .Lcpu_info
+ ldr r4, [r4, r0, lsl #2]
+ ldr r4, [r4, #CI_CURPCB]
+ ldmfd sp!, {r0-r3, r14}
+#else
+ ldr r4, .Lcurpcb
+ ldr r4, [r4]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r4, #0x00000000
+ beq .Lcopystrpcbfault
+#endif
+
+ adr r5, .Lcopystrfault
+ str r5, [r4, #PCB_ONFAULT]
+
+1: ldrb r5, [r0], #0x0001
+ add r6, r6, #0x00000001
+ teq r5, #0x00000000
+ strbt r5, [r1], #0x0001
+ teqne r6, r2
+ bne 1b
+
+ mov r0, #0x00000000
+ str r0, [r4, #PCB_ONFAULT]
+
+ teq r5, #0x00000000
+ moveq r0, #0x00000000
+ movne r0, #ENAMETOOLONG
+
+2: teq r3, #0x00000000
+ strne r6, [r3]
+
+ RESTORE_REGS
+ mov pc, lr
+
+/* A fault occurred during the copy */
+.Lcopystrfault:
+ mov r1, #0x00000000
+ str r1, [r4, #PCB_ONFAULT]
+ RESTORE_REGS
+ mov pc, lr
+
+#ifdef DIAGNOSTIC
+.Lcopystrpcbfault:
+ mov r2, r1
+ mov r1, r0
+ adr r0, Lcopystrpcbfaulttext
+ bic sp, sp, #7 /* align stack to 8 bytes */
+ b _C_LABEL(panic)
+
+Lcopystrpcbfaulttext:
+ .asciz "No valid PCB during copyinoutstr() addr1=%08x addr2=%08x\n"
+ .align 0
+#endif
diff --git a/sys/arch/arm/arm/cpu.c b/sys/arch/arm/arm/cpu.c
new file mode 100644
index 00000000000..8bfe63a3256
--- /dev/null
+++ b/sys/arch/arm/arm/cpu.c
@@ -0,0 +1,587 @@
+/* $OpenBSD: cpu.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: cpu.c,v 1.54 2003/10/26 23:11:15 chris Exp $^I*/$
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe.
+ * Copyright (c) 1995 Brini.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * cpu.c
+ *
+ * Probing and configuration for the master cpu
+ *
+ * Created : 10/10/95
+ */
+
+#include <sys/param.h>
+
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <uvm/uvm_extern.h>
+#include <machine/cpu.h>
+
+#include <arm/cpuconf.h>
+#include <arm/undefined.h>
+
+#ifdef ARMFPE
+#include <machine/bootconfig.h> /* For boot args */
+#include <arm/fpe-arm/armfpe.h>
+#endif
+
+char cpu_model[256];
+
+/* Prototypes */
+void identify_arm_cpu(struct device *dv, struct cpu_info *);
+
+/*
+ * Identify the master (boot) CPU
+ */
+
+void
+cpu_attach(struct device *dv)
+{
+ int usearmfpe;
+
+ usearmfpe = 1; /* when compiled in, its enabled by default */
+
+ curcpu()->ci_dev = dv;
+
+ /* Get the cpu ID from coprocessor 15 */
+
+ curcpu()->ci_arm_cpuid = cpu_id();
+ curcpu()->ci_arm_cputype = curcpu()->ci_arm_cpuid & CPU_ID_CPU_MASK;
+ curcpu()->ci_arm_cpurev =
+ curcpu()->ci_arm_cpuid & CPU_ID_REVISION_MASK;
+
+ identify_arm_cpu(dv, curcpu());
+
+ if (curcpu()->ci_arm_cputype == CPU_ID_SA110 &&
+ curcpu()->ci_arm_cpurev < 3) {
+ printf("%s: SA-110 with bugged STM^ instruction\n",
+ dv->dv_xname);
+ }
+
+#ifdef CPU_ARM8
+ if ((curcpu()->ci_arm_cpuid & CPU_ID_CPU_MASK) == CPU_ID_ARM810) {
+ int clock = arm8_clock_config(0, 0);
+ char *fclk;
+ aprint_normal("%s: ARM810 cp15=%02x", dv->dv_xname, clock);
+ aprint_normal(" clock:%s", (clock & 1) ? " dynamic" : "");
+ aprint_normal("%s", (clock & 2) ? " sync" : "");
+ switch ((clock >> 2) & 3) {
+ case 0:
+ fclk = "bus clock";
+ break;
+ case 1:
+ fclk = "ref clock";
+ break;
+ case 3:
+ fclk = "pll";
+ break;
+ default:
+ fclk = "illegal";
+ break;
+ }
+ aprint_normal(" fclk source=%s\n", fclk);
+ }
+#endif
+
+#ifdef ARMFPE
+ /*
+ * Ok now we test for an FPA
+ * At this point no floating point emulator has been installed.
+ * This means any FP instruction will cause undefined exception.
+ * We install a temporay coproc 1 handler which will modify
+ * undefined_test if it is called.
+ * We then try to read the FP status register. If undefined_test
+ * has been decremented then the instruction was not handled by
+ * an FPA so we know the FPA is missing. If undefined_test is
+ * still 1 then we know the instruction was handled by an FPA.
+ * We then remove our test handler and look at the
+ * FP status register for identification.
+ */
+
+ /*
+ * Ok if ARMFPE is defined and the boot options request the
+ * ARM FPE then it will be installed as the FPE.
+ * This is just while I work on integrating the new FPE.
+ * It means the new FPE gets installed if compiled int (ARMFPE
+ * defined) and also gives me a on/off option when I boot in
+ * case the new FPE is causing panics.
+ */
+
+
+ if (boot_args)
+ get_bootconf_option(boot_args, "armfpe",
+ BOOTOPT_TYPE_BOOLEAN, &usearmfpe);
+ if (usearmfpe)
+ initialise_arm_fpe();
+#endif
+}
+
+enum cpu_class {
+ CPU_CLASS_NONE,
+ CPU_CLASS_ARM2,
+ CPU_CLASS_ARM2AS,
+ CPU_CLASS_ARM3,
+ CPU_CLASS_ARM6,
+ CPU_CLASS_ARM7,
+ CPU_CLASS_ARM7TDMI,
+ CPU_CLASS_ARM8,
+ CPU_CLASS_ARM9TDMI,
+ CPU_CLASS_ARM9ES,
+ CPU_CLASS_ARM10E,
+ CPU_CLASS_SA1,
+ CPU_CLASS_XSCALE
+};
+
+static const char * const generic_steppings[16] = {
+ "rev 0", "rev 1", "rev 2", "rev 3",
+ "rev 4", "rev 5", "rev 6", "rev 7",
+ "rev 8", "rev 9", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const sa110_steppings[16] = {
+ "rev 0", "step J", "step K", "step S",
+ "step T", "rev 5", "rev 6", "rev 7",
+ "rev 8", "rev 9", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const sa1100_steppings[16] = {
+ "rev 0", "step B", "step C", "rev 3",
+ "rev 4", "rev 5", "rev 6", "rev 7",
+ "step D", "step E", "rev 10" "step G",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const sa1110_steppings[16] = {
+ "step A-0", "rev 1", "rev 2", "rev 3",
+ "step B-0", "step B-1", "step B-2", "step B-3",
+ "step B-4", "step B-5", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const ixp12x0_steppings[16] = {
+ "(IXP1200 step A)", "(IXP1200 step B)",
+ "rev 2", "(IXP1200 step C)",
+ "(IXP1200 step D)", "(IXP1240/1250 step A)",
+ "(IXP1240 step B)", "(IXP1250 step B)",
+ "rev 8", "rev 9", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const xscale_steppings[16] = {
+ "step A-0", "step A-1", "step B-0", "step C-0",
+ "step D-0", "rev 5", "rev 6", "rev 7",
+ "rev 8", "rev 9", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const i80321_steppings[16] = {
+ "step A-0", "step B-0", "rev 2", "rev 3",
+ "rev 4", "rev 5", "rev 6", "rev 7",
+ "rev 8", "rev 9", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const pxa2x0_steppings[16] = {
+ "step A-0", "step A-1", "step B-0", "step B-1",
+ "step B-2", "step C-0", "rev 6", "rev 7",
+ "rev 8", "rev 9", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+static const char * const ixp425_steppings[16] = {
+ "step 0", "rev 1", "rev 2", "rev 3",
+ "rev 4", "rev 5", "rev 6", "rev 7",
+ "rev 8", "rev 9", "rev 10", "rev 11",
+ "rev 12", "rev 13", "rev 14", "rev 15",
+};
+
+struct cpuidtab {
+ u_int32_t cpuid;
+ enum cpu_class cpu_class;
+ const char *cpu_name;
+ const char * const *cpu_steppings;
+};
+
+const struct cpuidtab cpuids[] = {
+ { CPU_ID_ARM2, CPU_CLASS_ARM2, "ARM2",
+ generic_steppings },
+ { CPU_ID_ARM250, CPU_CLASS_ARM2AS, "ARM250",
+ generic_steppings },
+
+ { CPU_ID_ARM3, CPU_CLASS_ARM3, "ARM3",
+ generic_steppings },
+
+ { CPU_ID_ARM600, CPU_CLASS_ARM6, "ARM600",
+ generic_steppings },
+ { CPU_ID_ARM610, CPU_CLASS_ARM6, "ARM610",
+ generic_steppings },
+ { CPU_ID_ARM620, CPU_CLASS_ARM6, "ARM620",
+ generic_steppings },
+
+ { CPU_ID_ARM700, CPU_CLASS_ARM7, "ARM700",
+ generic_steppings },
+ { CPU_ID_ARM710, CPU_CLASS_ARM7, "ARM710",
+ generic_steppings },
+ { CPU_ID_ARM7500, CPU_CLASS_ARM7, "ARM7500",
+ generic_steppings },
+ { CPU_ID_ARM710A, CPU_CLASS_ARM7, "ARM710a",
+ generic_steppings },
+ { CPU_ID_ARM7500FE, CPU_CLASS_ARM7, "ARM7500FE",
+ generic_steppings },
+ { CPU_ID_ARM710T, CPU_CLASS_ARM7TDMI, "ARM710T",
+ generic_steppings },
+ { CPU_ID_ARM720T, CPU_CLASS_ARM7TDMI, "ARM720T",
+ generic_steppings },
+ { CPU_ID_ARM740T8K, CPU_CLASS_ARM7TDMI, "ARM740T (8 KB cache)",
+ generic_steppings },
+ { CPU_ID_ARM740T4K, CPU_CLASS_ARM7TDMI, "ARM740T (4 KB cache)",
+ generic_steppings },
+
+ { CPU_ID_ARM810, CPU_CLASS_ARM8, "ARM810",
+ generic_steppings },
+
+ { CPU_ID_ARM920T, CPU_CLASS_ARM9TDMI, "ARM920T",
+ generic_steppings },
+ { CPU_ID_ARM922T, CPU_CLASS_ARM9TDMI, "ARM922T",
+ generic_steppings },
+ { CPU_ID_ARM940T, CPU_CLASS_ARM9TDMI, "ARM940T",
+ generic_steppings },
+ { CPU_ID_ARM946ES, CPU_CLASS_ARM9ES, "ARM946E-S",
+ generic_steppings },
+ { CPU_ID_ARM966ES, CPU_CLASS_ARM9ES, "ARM966E-S",
+ generic_steppings },
+ { CPU_ID_ARM966ESR1, CPU_CLASS_ARM9ES, "ARM966E-S",
+ generic_steppings },
+ { CPU_ID_TI925T, CPU_CLASS_ARM9TDMI, "TI ARM925T",
+ generic_steppings },
+
+ { CPU_ID_ARM1020E, CPU_CLASS_ARM10E, "ARM1020E",
+ generic_steppings },
+ { CPU_ID_ARM1022ES, CPU_CLASS_ARM10E, "ARM1022E-S",
+ generic_steppings },
+
+ { CPU_ID_SA110, CPU_CLASS_SA1, "SA-110",
+ sa110_steppings },
+ { CPU_ID_SA1100, CPU_CLASS_SA1, "SA-1100",
+ sa1100_steppings },
+ { CPU_ID_SA1110, CPU_CLASS_SA1, "SA-1110",
+ sa1110_steppings },
+
+ { CPU_ID_IXP1200, CPU_CLASS_SA1, "IXP1200",
+ ixp12x0_steppings },
+
+ { CPU_ID_80200, CPU_CLASS_XSCALE, "i80200",
+ xscale_steppings },
+
+ { CPU_ID_80321_400, CPU_CLASS_XSCALE, "i80321 400MHz",
+ i80321_steppings },
+ { CPU_ID_80321_600, CPU_CLASS_XSCALE, "i80321 600MHz",
+ i80321_steppings },
+ { CPU_ID_80321_400_B0, CPU_CLASS_XSCALE, "i80321 400MHz",
+ i80321_steppings },
+ { CPU_ID_80321_600_B0, CPU_CLASS_XSCALE, "i80321 600MHz",
+ i80321_steppings },
+
+ { CPU_ID_PXA250A, CPU_CLASS_XSCALE, "PXA250",
+ pxa2x0_steppings },
+ { CPU_ID_PXA210A, CPU_CLASS_XSCALE, "PXA210",
+ pxa2x0_steppings },
+ { CPU_ID_PXA250B, CPU_CLASS_XSCALE, "PXA250",
+ pxa2x0_steppings },
+ { CPU_ID_PXA210B, CPU_CLASS_XSCALE, "PXA210",
+ pxa2x0_steppings },
+ { CPU_ID_PXA250C, CPU_CLASS_XSCALE, "PXA250",
+ pxa2x0_steppings },
+ { CPU_ID_PXA210C, CPU_CLASS_XSCALE, "PXA210",
+ pxa2x0_steppings },
+
+ { CPU_ID_IXP425_533, CPU_CLASS_XSCALE, "IXP425 533MHz",
+ ixp425_steppings },
+ { CPU_ID_IXP425_400, CPU_CLASS_XSCALE, "IXP425 400MHz",
+ ixp425_steppings },
+ { CPU_ID_IXP425_266, CPU_CLASS_XSCALE, "IXP425 266MHz",
+ ixp425_steppings },
+
+ { 0, CPU_CLASS_NONE, NULL, NULL }
+};
+
+struct cpu_classtab {
+ const char *class_name;
+ const char *class_option;
+};
+
+const struct cpu_classtab cpu_classes[] = {
+ { "unknown", NULL }, /* CPU_CLASS_NONE */
+ { "ARM2", "CPU_ARM2" }, /* CPU_CLASS_ARM2 */
+ { "ARM2as", "CPU_ARM250" }, /* CPU_CLASS_ARM2AS */
+ { "ARM3", "CPU_ARM3" }, /* CPU_CLASS_ARM3 */
+ { "ARM6", "CPU_ARM6" }, /* CPU_CLASS_ARM6 */
+ { "ARM7", "CPU_ARM7" }, /* CPU_CLASS_ARM7 */
+ { "ARM7TDMI", "CPU_ARM7TDMI" }, /* CPU_CLASS_ARM7TDMI */
+ { "ARM8", "CPU_ARM8" }, /* CPU_CLASS_ARM8 */
+ { "ARM9TDMI", NULL }, /* CPU_CLASS_ARM9TDMI */
+ { "ARM9E-S", NULL }, /* CPU_CLASS_ARM9ES */
+ { "ARM10E", "CPU_ARM10" }, /* CPU_CLASS_ARM10E */
+ { "SA-1", "CPU_SA110" }, /* CPU_CLASS_SA1 */
+ { "XScale", "CPU_XSCALE_..." }, /* CPU_CLASS_XSCALE */
+};
+
+/*
+ * Report the type of the specified arm processor. This uses the generic and
+ * arm specific information in the cpu structure to identify the processor.
+ * The remaining fields in the cpu structure are filled in appropriately.
+ */
+
+static const char * const wtnames[] = {
+ "write-through",
+ "write-back",
+ "write-back",
+ "**unknown 3**",
+ "**unknown 4**",
+ "write-back-locking", /* XXX XScale-specific? */
+ "write-back-locking-A",
+ "write-back-locking-B",
+ "**unknown 8**",
+ "**unknown 9**",
+ "**unknown 10**",
+ "**unknown 11**",
+ "**unknown 12**",
+ "**unknown 13**",
+ "**unknown 14**",
+ "**unknown 15**",
+};
+
+void
+identify_arm_cpu(struct device *dv, struct cpu_info *ci)
+{
+ u_int cpuid;
+ enum cpu_class cpu_class = CPU_CLASS_NONE;
+ int i;
+
+ cpuid = ci->ci_arm_cpuid;
+
+ if (cpuid == 0) {
+ printf("Processor failed probe - no CPU ID\n");
+ return;
+ }
+
+ for (i = 0; cpuids[i].cpuid != 0; i++)
+ if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
+ cpu_class = cpuids[i].cpu_class;
+ snprintf(cpu_model, sizeof(cpu_model),
+ "%s %s (%s core)", cpuids[i].cpu_name,
+ cpuids[i].cpu_steppings[cpuid &
+ CPU_ID_REVISION_MASK],
+ cpu_classes[cpu_class].class_name);
+ break;
+ }
+
+ if (cpuids[i].cpuid == 0)
+ snprintf(cpu_model, sizeof(cpu_model),
+ "unknown CPU (ID = 0x%x)", cpuid);
+
+ printf(": %s\n", cpu_model);
+
+ printf("%s:", dv->dv_xname);
+
+ switch (cpu_class) {
+ case CPU_CLASS_ARM6:
+ case CPU_CLASS_ARM7:
+ case CPU_CLASS_ARM7TDMI:
+ case CPU_CLASS_ARM8:
+ if ((ci->ci_ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
+ printf(" IDC disabled");
+ else
+ printf(" IDC enabled");
+ break;
+ case CPU_CLASS_ARM9TDMI:
+ case CPU_CLASS_ARM10E:
+ case CPU_CLASS_SA1:
+ case CPU_CLASS_XSCALE:
+ if ((ci->ci_ctrl & CPU_CONTROL_DC_ENABLE) == 0)
+ printf(" DC disabled");
+ else
+ printf(" DC enabled");
+ if ((ci->ci_ctrl & CPU_CONTROL_IC_ENABLE) == 0)
+ printf(" IC disabled");
+ else
+ printf(" IC enabled");
+ break;
+ default:
+ break;
+ }
+ if ((ci->ci_ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
+ printf(" WB disabled");
+ else
+ printf(" WB enabled");
+
+ if (ci->ci_ctrl & CPU_CONTROL_LABT_ENABLE)
+ printf(" LABT");
+ else
+ printf(" EABT");
+
+ if (ci->ci_ctrl & CPU_CONTROL_BPRD_ENABLE)
+ printf(" branch prediction enabled");
+
+ printf("\n");
+
+ /* Print cache info. */
+ if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
+ goto skip_pcache;
+
+ if (arm_pcache_unified) {
+ printf("%s: %dKB/%dB %d-way %s unified cache\n",
+ dv->dv_xname, arm_pdcache_size / 1024,
+ arm_pdcache_line_size, arm_pdcache_ways,
+ wtnames[arm_pcache_type]);
+ } else {
+ printf("%s: %dKB/%dB %d-way Instruction cache\n",
+ dv->dv_xname, arm_picache_size / 1024,
+ arm_picache_line_size, arm_picache_ways);
+ printf("%s: %dKB/%dB %d-way %s Data cache\n",
+ dv->dv_xname, arm_pdcache_size / 1024,
+ arm_pdcache_line_size, arm_pdcache_ways,
+ wtnames[arm_pcache_type]);
+ }
+
+ skip_pcache:
+
+ switch (cpu_class) {
+#ifdef CPU_ARM2
+ case CPU_CLASS_ARM2:
+#endif
+#ifdef CPU_ARM250
+ case CPU_CLASS_ARM2AS:
+#endif
+#ifdef CPU_ARM3
+ case CPU_CLASS_ARM3:
+#endif
+#ifdef CPU_ARM6
+ case CPU_CLASS_ARM6:
+#endif
+#ifdef CPU_ARM7
+ case CPU_CLASS_ARM7:
+#endif
+#ifdef CPU_ARM7TDMI
+ case CPU_CLASS_ARM7TDMI:
+#endif
+#ifdef CPU_ARM8
+ case CPU_CLASS_ARM8:
+#endif
+#ifdef CPU_ARM9
+ case CPU_CLASS_ARM9TDMI:
+#endif
+#ifdef CPU_ARM10
+ case CPU_CLASS_ARM10E:
+#endif
+#if defined(CPU_SA110) || defined(CPU_SA1100) || \
+ defined(CPU_SA1110) || defined(CPU_IXP12X0)
+ case CPU_CLASS_SA1:
+#endif
+#if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425)
+ case CPU_CLASS_XSCALE:
+#endif
+ break;
+ default:
+ if (cpu_classes[cpu_class].class_option != NULL)
+ printf("%s: %s does not fully support this CPU."
+ "\n", dv->dv_xname, ostype);
+ else {
+ printf("%s: This kernel does not fully support "
+ "this CPU.\n", dv->dv_xname);
+ printf("%s: Recompile with \"options %s\" to "
+ "correct this.\n", dv->dv_xname,
+ cpu_classes[cpu_class].class_option);
+ }
+ break;
+ }
+
+}
+#ifdef MULTIPROCESSOR
+int
+cpu_alloc_idlepcb(struct cpu_info *ci)
+{
+ vaddr_t uaddr;
+ struct pcb *pcb;
+ struct trapframe *tf;
+ int error;
+
+ /*
+ * Generate a kernel stack and PCB (in essence, a u-area) for the
+ * new CPU.
+ */
+ if (uvm_uarea_alloc(&uaddr)) {
+ error = uvm_fault_wire(kernel_map, uaddr, uaddr + USPACE,
+ VM_FAULT_WIRE, VM_PROT_READ | VM_PROT_WRITE);
+ if (error)
+ return error;
+ }
+ ci->ci_idlepcb = pcb = (struct pcb *)uaddr;
+
+ /*
+ * This code is largely derived from cpu_fork(), with which it
+ * should perhaps be shared.
+ */
+
+ /* Copy the pcb */
+ *pcb = proc0.p_addr->u_pcb;
+
+ /* Set up the undefined stack for the process. */
+ pcb->pcb_un.un_32.pcb32_und_sp = uaddr + USPACE_UNDEF_STACK_TOP;
+ pcb->pcb_un.un_32.pcb32_sp = uaddr + USPACE_SVC_STACK_TOP;
+
+#ifdef STACKCHECKS
+ /* Fill the undefined stack with a known pattern */
+ memset(((u_char *)uaddr) + USPACE_UNDEF_STACK_BOTTOM, 0xdd,
+ (USPACE_UNDEF_STACK_TOP - USPACE_UNDEF_STACK_BOTTOM));
+ /* Fill the kernel stack with a known pattern */
+ memset(((u_char *)uaddr) + USPACE_SVC_STACK_BOTTOM, 0xdd,
+ (USPACE_SVC_STACK_TOP - USPACE_SVC_STACK_BOTTOM));
+#endif /* STACKCHECKS */
+
+ pcb->pcb_tf = tf =
+ (struct trapframe *)pcb->pcb_un.un_32.pcb32_sp - 1;
+ *tf = *proc0.p_addr->u_pcb.pcb_tf;
+ return 0;
+}
+#endif /* MULTIPROCESSOR */
+
+/* End of cpu.c */
diff --git a/sys/arch/arm/arm/cpufunc.c b/sys/arch/arm/arm/cpufunc.c
new file mode 100644
index 00000000000..04e41f5dbeb
--- /dev/null
+++ b/sys/arch/arm/arm/cpufunc.c
@@ -0,0 +1,2168 @@
+/* $OpenBSD: cpufunc.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: cpufunc.c,v 1.65 2003/11/05 12:53:15 scw Exp $ */
+
+/*
+ * arm7tdmi support code Copyright (c) 2001 John Fremlin
+ * arm8 support code Copyright (c) 1997 ARM Limited
+ * arm8 support code Copyright (c) 1997 Causality Limited
+ * arm9 support code Copyright (C) 2001 ARM Ltd
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Causality Limited.
+ * 4. The name of Causality Limited may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * cpufuncs.c
+ *
+ * C functions for supporting CPU / MMU / TLB specific operations.
+ *
+ * Created : 30/01/97
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <machine/cpu.h>
+#include <machine/bootconfig.h>
+
+#include <uvm/uvm.h>
+
+#include <arm/cpuconf.h>
+#include <arm/cpufunc.h>
+
+#ifdef CPU_XSCALE_80200
+#include <arm/xscale/i80200reg.h>
+#include <arm/xscale/i80200var.h>
+#endif
+
+#ifdef CPU_XSCALE_80321
+#include <arm/xscale/i80321reg.h>
+#include <arm/xscale/i80321var.h>
+#endif
+
+#ifdef CPU_XSCALE_IXP425
+#include <arm/xscale/ixp425reg.h>
+#include <arm/xscale/ixp425var.h>
+#endif
+
+#if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321)
+#include <arm/xscale/xscalereg.h>
+#endif
+
+#if defined(PERFCTRS)
+struct arm_pmc_funcs *arm_pmc;
+#endif
+
+/* PRIMARY CACHE VARIABLES */
+int arm_picache_size;
+int arm_picache_line_size;
+int arm_picache_ways;
+
+int arm_pdcache_size; /* and unified */
+int arm_pdcache_line_size;
+int arm_pdcache_ways;
+
+int arm_pcache_type;
+int arm_pcache_unified;
+
+int arm_dcache_align;
+int arm_dcache_align_mask;
+
+/* 1 == use cpu_sleep(), 0 == don't */
+int cpu_do_powersave;
+
+#ifdef CPU_ARM3
+struct cpu_functions arm3_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ arm3_control, /* control */
+ NULL, /* domain */
+ NULL, /* setttb */
+ NULL, /* faultstatus */
+ NULL, /* faultaddress */
+
+ /* TLB functions */
+
+ cpufunc_nullop, /* tlb_flushID */
+ (void *)cpufunc_nullop, /* tlb_flushID_SE */
+ cpufunc_nullop, /* tlb_flushI */
+ (void *)cpufunc_nullop, /* tlb_flushI_SE */
+ cpufunc_nullop, /* tlb_flushD */
+ (void *)cpufunc_nullop, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ cpufunc_nullop, /* icache_sync_all */
+ (void *) cpufunc_nullop, /* icache_sync_range */
+
+ arm3_cache_flush, /* dcache_wbinv_all */
+ (void *)arm3_cache_flush, /* dcache_wbinv_range */
+ (void *)arm3_cache_flush, /* dcache_inv_range */
+ (void *)cpufunc_nullop, /* dcache_wb_range */
+
+ arm3_cache_flush, /* idcache_wbinv_all */
+ (void *)arm3_cache_flush, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ cpufunc_nullop, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ early_abort_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ NULL, /* context_switch */
+
+ (void *)cpufunc_nullop /* cpu setup */
+
+};
+#endif /* CPU_ARM3 */
+
+#ifdef CPU_ARM6
+struct cpu_functions arm6_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* domain */
+ arm67_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ arm67_tlb_flush, /* tlb_flushID */
+ arm67_tlb_purge, /* tlb_flushID_SE */
+ arm67_tlb_flush, /* tlb_flushI */
+ arm67_tlb_purge, /* tlb_flushI_SE */
+ arm67_tlb_flush, /* tlb_flushD */
+ arm67_tlb_purge, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ cpufunc_nullop, /* icache_sync_all */
+ (void *) cpufunc_nullop, /* icache_sync_range */
+
+ arm67_cache_flush, /* dcache_wbinv_all */
+ (void *)arm67_cache_flush, /* dcache_wbinv_range */
+ (void *)arm67_cache_flush, /* dcache_inv_range */
+ (void *)cpufunc_nullop, /* dcache_wb_range */
+
+ arm67_cache_flush, /* idcache_wbinv_all */
+ (void *)arm67_cache_flush, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ cpufunc_nullop, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+#ifdef ARM6_LATE_ABORT
+ late_abort_fixup, /* dataabt_fixup */
+#else
+ early_abort_fixup, /* dataabt_fixup */
+#endif
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ arm67_context_switch, /* context_switch */
+
+ arm6_setup /* cpu setup */
+
+};
+#endif /* CPU_ARM6 */
+
+#ifdef CPU_ARM7
+struct cpu_functions arm7_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* domain */
+ arm67_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ arm67_tlb_flush, /* tlb_flushID */
+ arm67_tlb_purge, /* tlb_flushID_SE */
+ arm67_tlb_flush, /* tlb_flushI */
+ arm67_tlb_purge, /* tlb_flushI_SE */
+ arm67_tlb_flush, /* tlb_flushD */
+ arm67_tlb_purge, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ cpufunc_nullop, /* icache_sync_all */
+ (void *)cpufunc_nullop, /* icache_sync_range */
+
+ arm67_cache_flush, /* dcache_wbinv_all */
+ (void *)arm67_cache_flush, /* dcache_wbinv_range */
+ (void *)arm67_cache_flush, /* dcache_inv_range */
+ (void *)cpufunc_nullop, /* dcache_wb_range */
+
+ arm67_cache_flush, /* idcache_wbinv_all */
+ (void *)arm67_cache_flush, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ cpufunc_nullop, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ late_abort_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ arm67_context_switch, /* context_switch */
+
+ arm7_setup /* cpu setup */
+
+};
+#endif /* CPU_ARM7 */
+
+#ifdef CPU_ARM7TDMI
+struct cpu_functions arm7tdmi_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* domain */
+ arm7tdmi_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ arm7tdmi_tlb_flushID, /* tlb_flushID */
+ arm7tdmi_tlb_flushID_SE, /* tlb_flushID_SE */
+ arm7tdmi_tlb_flushID, /* tlb_flushI */
+ arm7tdmi_tlb_flushID_SE, /* tlb_flushI_SE */
+ arm7tdmi_tlb_flushID, /* tlb_flushD */
+ arm7tdmi_tlb_flushID_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ cpufunc_nullop, /* icache_sync_all */
+ (void *)cpufunc_nullop, /* icache_sync_range */
+
+ arm7tdmi_cache_flushID, /* dcache_wbinv_all */
+ (void *)arm7tdmi_cache_flushID, /* dcache_wbinv_range */
+ (void *)arm7tdmi_cache_flushID, /* dcache_inv_range */
+ (void *)cpufunc_nullop, /* dcache_wb_range */
+
+ arm7tdmi_cache_flushID, /* idcache_wbinv_all */
+ (void *)arm7tdmi_cache_flushID, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ cpufunc_nullop, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ late_abort_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ arm7tdmi_context_switch, /* context_switch */
+
+ arm7tdmi_setup /* cpu setup */
+
+};
+#endif /* CPU_ARM7TDMI */
+
+#ifdef CPU_ARM8
+struct cpu_functions arm8_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* domain */
+ arm8_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ arm8_tlb_flushID, /* tlb_flushID */
+ arm8_tlb_flushID_SE, /* tlb_flushID_SE */
+ arm8_tlb_flushID, /* tlb_flushI */
+ arm8_tlb_flushID_SE, /* tlb_flushI_SE */
+ arm8_tlb_flushID, /* tlb_flushD */
+ arm8_tlb_flushID_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ cpufunc_nullop, /* icache_sync_all */
+ (void *)cpufunc_nullop, /* icache_sync_range */
+
+ arm8_cache_purgeID, /* dcache_wbinv_all */
+ (void *)arm8_cache_purgeID, /* dcache_wbinv_range */
+/*XXX*/ (void *)arm8_cache_purgeID, /* dcache_inv_range */
+ (void *)arm8_cache_cleanID, /* dcache_wb_range */
+
+ arm8_cache_purgeID, /* idcache_wbinv_all */
+ (void *)arm8_cache_purgeID, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ cpufunc_nullop, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ cpufunc_null_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ arm8_context_switch, /* context_switch */
+
+ arm8_setup /* cpu setup */
+};
+#endif /* CPU_ARM8 */
+
+#ifdef CPU_ARM9
+struct cpu_functions arm9_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* Domain */
+ arm9_setttb, /* Setttb */
+ cpufunc_faultstatus, /* Faultstatus */
+ cpufunc_faultaddress, /* Faultaddress */
+
+ /* TLB functions */
+
+ armv4_tlb_flushID, /* tlb_flushID */
+ arm9_tlb_flushID_SE, /* tlb_flushID_SE */
+ armv4_tlb_flushI, /* tlb_flushI */
+ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */
+ armv4_tlb_flushD, /* tlb_flushD */
+ armv4_tlb_flushD_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ arm9_cache_syncI, /* icache_sync_all */
+ arm9_cache_syncI_rng, /* icache_sync_range */
+
+ /* ...cache in write-though mode... */
+ arm9_cache_flushD, /* dcache_wbinv_all */
+ arm9_cache_flushD_rng, /* dcache_wbinv_range */
+ arm9_cache_flushD_rng, /* dcache_inv_range */
+ (void *)cpufunc_nullop, /* dcache_wb_range */
+
+ arm9_cache_flushID, /* idcache_wbinv_all */
+ arm9_cache_flushID_rng, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ armv4_drain_writebuf, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ cpufunc_null_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ arm9_context_switch, /* context_switch */
+
+ arm9_setup /* cpu setup */
+
+};
+#endif /* CPU_ARM9 */
+
+#ifdef CPU_ARM10
+struct cpu_functions arm10_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* Domain */
+ arm10_setttb, /* Setttb */
+ cpufunc_faultstatus, /* Faultstatus */
+ cpufunc_faultaddress, /* Faultaddress */
+
+ /* TLB functions */
+
+ armv4_tlb_flushID, /* tlb_flushID */
+ arm10_tlb_flushID_SE, /* tlb_flushID_SE */
+ armv4_tlb_flushI, /* tlb_flushI */
+ arm10_tlb_flushI_SE, /* tlb_flushI_SE */
+ armv4_tlb_flushD, /* tlb_flushD */
+ armv4_tlb_flushD_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ arm10_icache_sync_all, /* icache_sync_all */
+ arm10_icache_sync_range, /* icache_sync_range */
+
+ arm10_dcache_wbinv_all, /* dcache_wbinv_all */
+ arm10_dcache_wbinv_range, /* dcache_wbinv_range */
+ arm10_dcache_inv_range, /* dcache_inv_range */
+ arm10_dcache_wb_range, /* dcache_wb_range */
+
+ arm10_idcache_wbinv_all, /* idcache_wbinv_all */
+ arm10_idcache_wbinv_range, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ armv4_drain_writebuf, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ cpufunc_null_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ arm10_context_switch, /* context_switch */
+
+ arm10_setup /* cpu setup */
+
+};
+#endif /* CPU_ARM10 */
+
+#ifdef CPU_SA110
+struct cpu_functions sa110_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* domain */
+ sa1_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ armv4_tlb_flushID, /* tlb_flushID */
+ sa1_tlb_flushID_SE, /* tlb_flushID_SE */
+ armv4_tlb_flushI, /* tlb_flushI */
+ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */
+ armv4_tlb_flushD, /* tlb_flushD */
+ armv4_tlb_flushD_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ sa1_cache_syncI, /* icache_sync_all */
+ sa1_cache_syncI_rng, /* icache_sync_range */
+
+ sa1_cache_purgeD, /* dcache_wbinv_all */
+ sa1_cache_purgeD_rng, /* dcache_wbinv_range */
+/*XXX*/ sa1_cache_purgeD_rng, /* dcache_inv_range */
+ sa1_cache_cleanD_rng, /* dcache_wb_range */
+
+ sa1_cache_purgeID, /* idcache_wbinv_all */
+ sa1_cache_purgeID_rng, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ armv4_drain_writebuf, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ cpufunc_null_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ sa110_context_switch, /* context_switch */
+
+ sa110_setup /* cpu setup */
+};
+#endif /* CPU_SA110 */
+
+#if defined(CPU_SA1100) || defined(CPU_SA1110)
+struct cpu_functions sa11x0_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* domain */
+ sa1_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ armv4_tlb_flushID, /* tlb_flushID */
+ sa1_tlb_flushID_SE, /* tlb_flushID_SE */
+ armv4_tlb_flushI, /* tlb_flushI */
+ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */
+ armv4_tlb_flushD, /* tlb_flushD */
+ armv4_tlb_flushD_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ sa1_cache_syncI, /* icache_sync_all */
+ sa1_cache_syncI_rng, /* icache_sync_range */
+
+ sa1_cache_purgeD, /* dcache_wbinv_all */
+ sa1_cache_purgeD_rng, /* dcache_wbinv_range */
+/*XXX*/ sa1_cache_purgeD_rng, /* dcache_inv_range */
+ sa1_cache_cleanD_rng, /* dcache_wb_range */
+
+ sa1_cache_purgeID, /* idcache_wbinv_all */
+ sa1_cache_purgeID_rng, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ sa11x0_drain_readbuf, /* flush_prefetchbuf */
+ armv4_drain_writebuf, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ sa11x0_cpu_sleep, /* sleep */
+
+ /* Soft functions */
+
+ cpufunc_null_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ sa11x0_context_switch, /* context_switch */
+
+ sa11x0_setup /* cpu setup */
+};
+#endif /* CPU_SA1100 || CPU_SA1110 */
+
+#ifdef CPU_IXP12X0
+struct cpu_functions ixp12x0_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ cpufunc_nullop, /* cpwait */
+
+ /* MMU functions */
+
+ cpufunc_control, /* control */
+ cpufunc_domains, /* domain */
+ sa1_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ armv4_tlb_flushID, /* tlb_flushID */
+ sa1_tlb_flushID_SE, /* tlb_flushID_SE */
+ armv4_tlb_flushI, /* tlb_flushI */
+ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */
+ armv4_tlb_flushD, /* tlb_flushD */
+ armv4_tlb_flushD_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ sa1_cache_syncI, /* icache_sync_all */
+ sa1_cache_syncI_rng, /* icache_sync_range */
+
+ sa1_cache_purgeD, /* dcache_wbinv_all */
+ sa1_cache_purgeD_rng, /* dcache_wbinv_range */
+/*XXX*/ sa1_cache_purgeD_rng, /* dcache_inv_range */
+ sa1_cache_cleanD_rng, /* dcache_wb_range */
+
+ sa1_cache_purgeID, /* idcache_wbinv_all */
+ sa1_cache_purgeID_rng, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ ixp12x0_drain_readbuf, /* flush_prefetchbuf */
+ armv4_drain_writebuf, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ (void *)cpufunc_nullop, /* sleep */
+
+ /* Soft functions */
+
+ cpufunc_null_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ ixp12x0_context_switch, /* context_switch */
+
+ ixp12x0_setup /* cpu setup */
+};
+#endif /* CPU_IXP12X0 */
+
+#if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425)
+struct cpu_functions xscale_cpufuncs = {
+ /* CPU functions */
+
+ cpufunc_id, /* id */
+ xscale_cpwait, /* cpwait */
+
+ /* MMU functions */
+
+ xscale_control, /* control */
+ cpufunc_domains, /* domain */
+ xscale_setttb, /* setttb */
+ cpufunc_faultstatus, /* faultstatus */
+ cpufunc_faultaddress, /* faultaddress */
+
+ /* TLB functions */
+
+ armv4_tlb_flushID, /* tlb_flushID */
+ xscale_tlb_flushID_SE, /* tlb_flushID_SE */
+ armv4_tlb_flushI, /* tlb_flushI */
+ (void *)armv4_tlb_flushI, /* tlb_flushI_SE */
+ armv4_tlb_flushD, /* tlb_flushD */
+ armv4_tlb_flushD_SE, /* tlb_flushD_SE */
+
+ /* Cache operations */
+
+ xscale_cache_syncI, /* icache_sync_all */
+ xscale_cache_syncI_rng, /* icache_sync_range */
+
+ xscale_cache_purgeD, /* dcache_wbinv_all */
+ xscale_cache_purgeD_rng, /* dcache_wbinv_range */
+ xscale_cache_flushD_rng, /* dcache_inv_range */
+ xscale_cache_cleanD_rng, /* dcache_wb_range */
+
+ xscale_cache_purgeID, /* idcache_wbinv_all */
+ xscale_cache_purgeID_rng, /* idcache_wbinv_range */
+
+ /* Other functions */
+
+ cpufunc_nullop, /* flush_prefetchbuf */
+ armv4_drain_writebuf, /* drain_writebuf */
+ cpufunc_nullop, /* flush_brnchtgt_C */
+ (void *)cpufunc_nullop, /* flush_brnchtgt_E */
+
+ xscale_cpu_sleep, /* sleep */
+
+ /* Soft functions */
+
+ cpufunc_null_fixup, /* dataabt_fixup */
+ cpufunc_null_fixup, /* prefetchabt_fixup */
+
+ xscale_context_switch, /* context_switch */
+
+ xscale_setup /* cpu setup */
+};
+#endif
+/* CPU_XSCALE_80200 || CPU_XSCALE_80321 || CPU_XSCALE_PXA2X0 || CPU_XSCALE_IXP425 */
+
+/*
+ * Global constants also used by locore.s
+ */
+
+struct cpu_functions cpufuncs;
+u_int cputype;
+u_int cpu_reset_needs_v4_MMU_disable; /* flag used in locore.s */
+
+#if defined(CPU_ARM7TDMI) || defined(CPU_ARM8) || defined(CPU_ARM9) || \
+ defined (CPU_ARM10) || \
+ defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425)
+static void get_cachetype_cp15 __P((void));
+
+/* Additional cache information local to this file. Log2 of some of the
+ above numbers. */
+static int arm_dcache_l2_nsets;
+static int arm_dcache_l2_assoc;
+static int arm_dcache_l2_linesize;
+
+static void
+get_cachetype_cp15()
+{
+ u_int ctype, isize, dsize;
+ u_int multiplier;
+
+ __asm __volatile("mrc p15, 0, %0, c0, c0, 1"
+ : "=r" (ctype));
+
+ /*
+ * ...and thus spake the ARM ARM:
+ *
+ * If an <opcode2> value corresponding to an unimplemented or
+ * reserved ID register is encountered, the System Control
+ * processor returns the value of the main ID register.
+ */
+ if (ctype == cpufunc_id())
+ goto out;
+
+ if ((ctype & CPU_CT_S) == 0)
+ arm_pcache_unified = 1;
+
+ /*
+ * If you want to know how this code works, go read the ARM ARM.
+ */
+
+ arm_pcache_type = CPU_CT_CTYPE(ctype);
+
+ if (arm_pcache_unified == 0) {
+ isize = CPU_CT_ISIZE(ctype);
+ multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
+ arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
+ if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
+ if (isize & CPU_CT_xSIZE_M)
+ arm_picache_line_size = 0; /* not present */
+ else
+ arm_picache_ways = 1;
+ } else {
+ arm_picache_ways = multiplier <<
+ (CPU_CT_xSIZE_ASSOC(isize) - 1);
+ }
+ arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
+ }
+
+ dsize = CPU_CT_DSIZE(ctype);
+ multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
+ arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
+ if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
+ if (dsize & CPU_CT_xSIZE_M)
+ arm_pdcache_line_size = 0; /* not present */
+ else
+ arm_pdcache_ways = 1;
+ } else {
+ arm_pdcache_ways = multiplier <<
+ (CPU_CT_xSIZE_ASSOC(dsize) - 1);
+ }
+ arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
+
+ arm_dcache_align = arm_pdcache_line_size;
+
+ arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2;
+ arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3;
+ arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) -
+ CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize);
+
+ out:
+ arm_dcache_align_mask = arm_dcache_align - 1;
+}
+#endif /* ARM7TDMI || ARM8 || ARM9 || XSCALE */
+
+#if defined(CPU_ARM2) || defined(CPU_ARM250) || defined(CPU_ARM3) || \
+ defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_SA110) || \
+ defined(CPU_SA1100) || defined(CPU_SA1110) || defined(CPU_IXP12X0)
+/* Cache information for CPUs without cache type registers. */
+struct cachetab {
+ u_int32_t ct_cpuid;
+ int ct_pcache_type;
+ int ct_pcache_unified;
+ int ct_pdcache_size;
+ int ct_pdcache_line_size;
+ int ct_pdcache_ways;
+ int ct_picache_size;
+ int ct_picache_line_size;
+ int ct_picache_ways;
+};
+
+struct cachetab cachetab[] = {
+ /* cpuid, cache type, u, dsiz, ls, wy, isiz, ls, wy */
+ { CPU_ID_ARM2, 0, 1, 0, 0, 0, 0, 0, 0 },
+ { CPU_ID_ARM250, 0, 1, 0, 0, 0, 0, 0, 0 },
+ { CPU_ID_ARM3, CPU_CT_CTYPE_WT, 1, 4096, 16, 64, 0, 0, 0 },
+ { CPU_ID_ARM610, CPU_CT_CTYPE_WT, 1, 4096, 16, 64, 0, 0, 0 },
+ { CPU_ID_ARM710, CPU_CT_CTYPE_WT, 1, 8192, 32, 4, 0, 0, 0 },
+ { CPU_ID_ARM7500, CPU_CT_CTYPE_WT, 1, 4096, 16, 4, 0, 0, 0 },
+ { CPU_ID_ARM710A, CPU_CT_CTYPE_WT, 1, 8192, 16, 4, 0, 0, 0 },
+ { CPU_ID_ARM7500FE, CPU_CT_CTYPE_WT, 1, 4096, 16, 4, 0, 0, 0 },
+ /* XXX is this type right for SA-1? */
+ { CPU_ID_SA110, CPU_CT_CTYPE_WB1, 0, 16384, 32, 32, 16384, 32, 32 },
+ { CPU_ID_SA1100, CPU_CT_CTYPE_WB1, 0, 8192, 32, 32, 16384, 32, 32 },
+ { CPU_ID_SA1110, CPU_CT_CTYPE_WB1, 0, 8192, 32, 32, 16384, 32, 32 },
+ { CPU_ID_IXP1200, CPU_CT_CTYPE_WB1, 0, 16384, 32, 32, 16384, 32, 32 }, /* XXX */
+ { 0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+static void get_cachetype_table __P((void));
+
+static void
+get_cachetype_table()
+{
+ int i;
+ u_int32_t cpuid = cpufunc_id();
+
+ for (i = 0; cachetab[i].ct_cpuid != 0; i++) {
+ if (cachetab[i].ct_cpuid == (cpuid & CPU_ID_CPU_MASK)) {
+ arm_pcache_type = cachetab[i].ct_pcache_type;
+ arm_pcache_unified = cachetab[i].ct_pcache_unified;
+ arm_pdcache_size = cachetab[i].ct_pdcache_size;
+ arm_pdcache_line_size =
+ cachetab[i].ct_pdcache_line_size;
+ arm_pdcache_ways = cachetab[i].ct_pdcache_ways;
+ arm_picache_size = cachetab[i].ct_picache_size;
+ arm_picache_line_size =
+ cachetab[i].ct_picache_line_size;
+ arm_picache_ways = cachetab[i].ct_picache_ways;
+ }
+ }
+ arm_dcache_align = arm_pdcache_line_size;
+
+ arm_dcache_align_mask = arm_dcache_align - 1;
+}
+
+#endif /* ARM2 || ARM250 || ARM3 || ARM6 || ARM7 || SA110 || SA1100 || SA1111 || IXP12X0 */
+
+/*
+ * Cannot panic here as we may not have a console yet ...
+ */
+
+int
+set_cpufuncs()
+{
+ cputype = cpufunc_id();
+ cputype &= CPU_ID_CPU_MASK;
+
+ /*
+ * NOTE: cpu_do_powersave defaults to off. If we encounter a
+ * CPU type where we want to use it by default, then we set it.
+ */
+
+#ifdef CPU_ARM3
+ if ((cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD &&
+ (cputype & 0x00000f00) == 0x00000300) {
+ cpufuncs = arm3_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 0;
+ get_cachetype_table();
+ return 0;
+ }
+#endif /* CPU_ARM3 */
+#ifdef CPU_ARM6
+ if ((cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD &&
+ (cputype & 0x00000f00) == 0x00000600) {
+ cpufuncs = arm6_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 0;
+ get_cachetype_table();
+ pmap_pte_init_generic();
+ return 0;
+ }
+#endif /* CPU_ARM6 */
+#ifdef CPU_ARM7
+ if ((cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD &&
+ CPU_ID_IS7(cputype) &&
+ (cputype & CPU_ID_7ARCH_MASK) == CPU_ID_7ARCH_V3) {
+ cpufuncs = arm7_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 0;
+ get_cachetype_table();
+ pmap_pte_init_generic();
+ return 0;
+ }
+#endif /* CPU_ARM7 */
+#ifdef CPU_ARM7TDMI
+ if ((cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD &&
+ CPU_ID_IS7(cputype) &&
+ (cputype & CPU_ID_7ARCH_MASK) == CPU_ID_7ARCH_V4T) {
+ cpufuncs = arm7tdmi_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 0;
+ get_cachetype_cp15();
+ pmap_pte_init_generic();
+ return 0;
+ }
+#endif
+#ifdef CPU_ARM8
+ if ((cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD &&
+ (cputype & 0x0000f000) == 0x00008000) {
+ cpufuncs = arm8_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 0; /* XXX correct? */
+ get_cachetype_cp15();
+ pmap_pte_init_arm8();
+ return 0;
+ }
+#endif /* CPU_ARM8 */
+#ifdef CPU_ARM9
+ if (((cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_ARM_LTD ||
+ (cputype & CPU_ID_IMPLEMENTOR_MASK) == CPU_ID_TI) &&
+ (cputype & 0x0000f000) == 0x00009000) {
+ cpufuncs = arm9_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 1; /* V4 or higher */
+ get_cachetype_cp15();
+ pmap_pte_init_arm9();
+ return 0;
+ }
+#endif /* CPU_ARM9 */
+#ifdef CPU_ARM10
+ if (/* cputype == CPU_ID_ARM1020T || */
+ cputype == CPU_ID_ARM1020E) {
+ /*
+ * Select write-through cacheing (this isn't really an
+ * option on ARM1020T).
+ */
+ cpufuncs = arm10_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 1; /* V4 or higher */
+ get_cachetype_cp15();
+ arm10_dcache_sets_inc = 1U << arm_dcache_l2_linesize;
+ arm10_dcache_sets_max =
+ (1U << (arm_dcache_l2_linesize + arm_dcache_l2_nsets)) -
+ arm10_dcache_sets_inc;
+ arm10_dcache_index_inc = 1U << (32 - arm_dcache_l2_assoc);
+ arm10_dcache_index_max = 0U - arm10_dcache_index_inc;
+ pmap_pte_init_generic();
+ return 0;
+ }
+#endif /* CPU_ARM10 */
+#ifdef CPU_SA110
+ if (cputype == CPU_ID_SA110) {
+ cpufuncs = sa110_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 1; /* SA needs it */
+ get_cachetype_table();
+ pmap_pte_init_sa1();
+ return 0;
+ }
+#endif /* CPU_SA110 */
+#ifdef CPU_SA1100
+ if (cputype == CPU_ID_SA1100) {
+ cpufuncs = sa11x0_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 1; /* SA needs it */
+ get_cachetype_table();
+ pmap_pte_init_sa1();
+
+ /* Use powersave on this CPU. */
+ cpu_do_powersave = 1;
+
+ return 0;
+ }
+#endif /* CPU_SA1100 */
+#ifdef CPU_SA1110
+ if (cputype == CPU_ID_SA1110) {
+ cpufuncs = sa11x0_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 1; /* SA needs it */
+ get_cachetype_table();
+ pmap_pte_init_sa1();
+
+ /* Use powersave on this CPU. */
+ cpu_do_powersave = 1;
+
+ return 0;
+ }
+#endif /* CPU_SA1110 */
+#ifdef CPU_IXP12X0
+ if (cputype == CPU_ID_IXP1200) {
+ cpufuncs = ixp12x0_cpufuncs;
+ cpu_reset_needs_v4_MMU_disable = 1;
+ get_cachetype_table();
+ pmap_pte_init_sa1();
+ return 0;
+ }
+#endif /* CPU_IXP12X0 */
+#ifdef CPU_XSCALE_80200
+ if (cputype == CPU_ID_80200) {
+ int rev = cpufunc_id() & CPU_ID_REVISION_MASK;
+
+ i80200_icu_init();
+
+ /*
+ * Reset the Performance Monitoring Unit to a
+ * pristine state:
+ * - CCNT, PMN0, PMN1 reset to 0
+ * - overflow indications cleared
+ * - all counters disabled
+ */
+ __asm __volatile("mcr p14, 0, %0, c0, c0, 0"
+ :
+ : "r" (PMNC_P|PMNC_C|PMNC_PMN0_IF|PMNC_PMN1_IF|
+ PMNC_CC_IF));
+
+#if defined(XSCALE_CCLKCFG)
+ /*
+ * Crank CCLKCFG to maximum legal value.
+ */
+ __asm __volatile ("mcr p14, 0, %0, c6, c0, 0"
+ :
+ : "r" (XSCALE_CCLKCFG));
+#endif
+
+ /*
+ * XXX Disable ECC in the Bus Controller Unit; we
+ * don't really support it, yet. Clear any pending
+ * error indications.
+ */
+ __asm __volatile("mcr p13, 0, %0, c0, c1, 0"
+ :
+ : "r" (BCUCTL_E0|BCUCTL_E1|BCUCTL_EV));
+
+ cpufuncs = xscale_cpufuncs;
+#if defined(PERFCTRS)
+ xscale_pmu_init();
+#endif
+
+ /*
+ * i80200 errata: Step-A0 and A1 have a bug where
+ * D$ dirty bits are not cleared on "invalidate by
+ * address".
+ *
+ * Workaround: Clean cache line before invalidating.
+ */
+ if (rev == 0 || rev == 1)
+ cpufuncs.cf_dcache_inv_range = xscale_cache_purgeD_rng;
+
+ cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */
+ get_cachetype_cp15();
+ pmap_pte_init_xscale();
+ return 0;
+ }
+#endif /* CPU_XSCALE_80200 */
+#ifdef CPU_XSCALE_80321
+ if (cputype == CPU_ID_80321_400 || cputype == CPU_ID_80321_600 ||
+ cputype == CPU_ID_80321_400_B0 || cputype == CPU_ID_80321_600_B0) {
+ i80321_icu_init();
+
+ /*
+ * Reset the Performance Monitoring Unit to a
+ * pristine state:
+ * - CCNT, PMN0, PMN1 reset to 0
+ * - overflow indications cleared
+ * - all counters disabled
+ */
+ __asm __volatile("mcr p14, 0, %0, c0, c0, 0"
+ :
+ : "r" (PMNC_P|PMNC_C|PMNC_PMN0_IF|PMNC_PMN1_IF|
+ PMNC_CC_IF));
+
+ cpufuncs = xscale_cpufuncs;
+#if defined(PERFCTRS)
+ xscale_pmu_init();
+#endif
+
+ cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */
+ get_cachetype_cp15();
+ pmap_pte_init_xscale();
+ return 0;
+ }
+#endif /* CPU_XSCALE_80321 */
+#ifdef CPU_XSCALE_PXA2X0
+ /* ignore core revision to test PXA2xx CPUs */
+ if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA250 ||
+ (cputype & ~CPU_ID_XSCALE_COREREV_MASK) == CPU_ID_PXA210) {
+
+ cpufuncs = xscale_cpufuncs;
+#if defined(PERFCTRS)
+ xscale_pmu_init();
+#endif
+
+ cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */
+ get_cachetype_cp15();
+ pmap_pte_init_xscale();
+
+ /* Use powersave on this CPU. */
+ cpu_do_powersave = 1;
+
+ return 0;
+ }
+#endif /* CPU_XSCALE_PXA2X0 */
+#ifdef CPU_XSCALE_IXP425
+ if (cputype == CPU_ID_IXP425_533 || cputype == CPU_ID_IXP425_400 ||
+ cputype == CPU_ID_IXP425_266) {
+ ixp425_icu_init();
+
+ cpufuncs = xscale_cpufuncs;
+#if defined(PERFCTRS)
+ xscale_pmu_init();
+#endif
+
+ cpu_reset_needs_v4_MMU_disable = 1; /* XScale needs it */
+ get_cachetype_cp15();
+ pmap_pte_init_xscale();
+
+ return 0;
+ }
+#endif /* CPU_XSCALE_IXP425 */
+ /*
+ * Bzzzz. And the answer was ...
+ */
+ panic("No support for this CPU type (%08x) in kernel", cputype);
+ return(ARCHITECTURE_NOT_PRESENT);
+}
+
+/*
+ * Fixup routines for data and prefetch aborts.
+ *
+ * Several compile time symbols are used
+ *
+ * DEBUG_FAULT_CORRECTION - Print debugging information during the
+ * correction of registers after a fault.
+ * ARM6_LATE_ABORT - ARM6 supports both early and late aborts
+ * when defined should use late aborts
+ */
+
+
+/*
+ * Null abort fixup routine.
+ * For use when no fixup is required.
+ */
+int
+cpufunc_null_fixup(arg)
+ void *arg;
+{
+ return(ABORT_FIXUP_OK);
+}
+
+
+#if defined(CPU_ARM2) || defined(CPU_ARM250) || defined(CPU_ARM3) || \
+ defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7TDMI)
+
+#ifdef DEBUG_FAULT_CORRECTION
+#define DFC_PRINTF(x) printf x
+#define DFC_DISASSEMBLE(x) disassemble(x)
+#else
+#define DFC_PRINTF(x) /* nothing */
+#define DFC_DISASSEMBLE(x) /* nothing */
+#endif
+
+/*
+ * "Early" data abort fixup.
+ *
+ * For ARM2, ARM2as, ARM3 and ARM6 (in early-abort mode). Also used
+ * indirectly by ARM6 (in late-abort mode) and ARM7[TDMI].
+ *
+ * In early aborts, we may have to fix up LDM, STM, LDC and STC.
+ */
+int
+early_abort_fixup(arg)
+ void *arg;
+{
+ trapframe_t *frame = arg;
+ u_int fault_pc;
+ u_int fault_instruction;
+ int saved_lr = 0;
+
+ if ((frame->tf_spsr & PSR_MODE) == PSR_SVC32_MODE) {
+
+ /* Ok an abort in SVC mode */
+
+ /*
+ * Copy the SVC r14 into the usr r14 - The usr r14 is garbage
+ * as the fault happened in svc mode but we need it in the
+ * usr slot so we can treat the registers as an array of ints
+ * during fixing.
+ * NOTE: This PC is in the position but writeback is not
+ * allowed on r15.
+ * Doing it like this is more efficient than trapping this
+ * case in all possible locations in the following fixup code.
+ */
+
+ saved_lr = frame->tf_usr_lr;
+ frame->tf_usr_lr = frame->tf_svc_lr;
+
+ /*
+ * Note the trapframe does not have the SVC r13 so a fault
+ * from an instruction with writeback to r13 in SVC mode is
+ * not allowed. This should not happen as the kstack is
+ * always valid.
+ */
+ }
+
+ /* Get fault address and status from the CPU */
+
+ fault_pc = frame->tf_pc;
+ fault_instruction = *((volatile unsigned int *)fault_pc);
+
+ /* Decode the fault instruction and fix the registers as needed */
+
+ if ((fault_instruction & 0x0e000000) == 0x08000000) {
+ int base;
+ int loop;
+ int count;
+ int *registers = &frame->tf_r0;
+
+ DFC_PRINTF(("LDM/STM\n"));
+ DFC_DISASSEMBLE(fault_pc);
+ if (fault_instruction & (1 << 21)) {
+ DFC_PRINTF(("This instruction must be corrected\n"));
+ base = (fault_instruction >> 16) & 0x0f;
+ if (base == 15)
+ return ABORT_FIXUP_FAILED;
+ /* Count registers transferred */
+ count = 0;
+ for (loop = 0; loop < 16; ++loop) {
+ if (fault_instruction & (1<<loop))
+ ++count;
+ }
+ DFC_PRINTF(("%d registers used\n", count));
+ DFC_PRINTF(("Corrected r%d by %d bytes ",
+ base, count * 4));
+ if (fault_instruction & (1 << 23)) {
+ DFC_PRINTF(("down\n"));
+ registers[base] -= count * 4;
+ } else {
+ DFC_PRINTF(("up\n"));
+ registers[base] += count * 4;
+ }
+ }
+ } else if ((fault_instruction & 0x0e000000) == 0x0c000000) {
+ int base;
+ int offset;
+ int *registers = &frame->tf_r0;
+
+ /* REGISTER CORRECTION IS REQUIRED FOR THESE INSTRUCTIONS */
+
+ DFC_DISASSEMBLE(fault_pc);
+
+ /* Only need to fix registers if write back is turned on */
+
+ if ((fault_instruction & (1 << 21)) != 0) {
+ base = (fault_instruction >> 16) & 0x0f;
+ if (base == 13 &&
+ (frame->tf_spsr & PSR_MODE) == PSR_SVC32_MODE)
+ return ABORT_FIXUP_FAILED;
+ if (base == 15)
+ return ABORT_FIXUP_FAILED;
+
+ offset = (fault_instruction & 0xff) << 2;
+ DFC_PRINTF(("r%d=%08x\n", base, registers[base]));
+ if ((fault_instruction & (1 << 23)) != 0)
+ offset = -offset;
+ registers[base] += offset;
+ DFC_PRINTF(("r%d=%08x\n", base, registers[base]));
+ }
+ } else if ((fault_instruction & 0x0e000000) == 0x0c000000)
+ return ABORT_FIXUP_FAILED;
+
+ if ((frame->tf_spsr & PSR_MODE) == PSR_SVC32_MODE) {
+
+ /* Ok an abort in SVC mode */
+
+ /*
+ * Copy the SVC r14 into the usr r14 - The usr r14 is garbage
+ * as the fault happened in svc mode but we need it in the
+ * usr slot so we can treat the registers as an array of ints
+ * during fixing.
+ * NOTE: This PC is in the position but writeback is not
+ * allowed on r15.
+ * Doing it like this is more efficient than trapping this
+ * case in all possible locations in the prior fixup code.
+ */
+
+ frame->tf_svc_lr = frame->tf_usr_lr;
+ frame->tf_usr_lr = saved_lr;
+
+ /*
+ * Note the trapframe does not have the SVC r13 so a fault
+ * from an instruction with writeback to r13 in SVC mode is
+ * not allowed. This should not happen as the kstack is
+ * always valid.
+ */
+ }
+
+ return(ABORT_FIXUP_OK);
+}
+#endif /* CPU_ARM2/250/3/6/7 */
+
+
+#if (defined(CPU_ARM6) && defined(ARM6_LATE_ABORT)) || defined(CPU_ARM7) || \
+ defined(CPU_ARM7TDMI)
+/*
+ * "Late" (base updated) data abort fixup
+ *
+ * For ARM6 (in late-abort mode) and ARM7.
+ *
+ * In this model, all data-transfer instructions need fixing up. We defer
+ * LDM, STM, LDC and STC fixup to the early-abort handler.
+ */
+int
+late_abort_fixup(arg)
+ void *arg;
+{
+ trapframe_t *frame = arg;
+ u_int fault_pc;
+ u_int fault_instruction;
+ int saved_lr = 0;
+
+ if ((frame->tf_spsr & PSR_MODE) == PSR_SVC32_MODE) {
+
+ /* Ok an abort in SVC mode */
+
+ /*
+ * Copy the SVC r14 into the usr r14 - The usr r14 is garbage
+ * as the fault happened in svc mode but we need it in the
+ * usr slot so we can treat the registers as an array of ints
+ * during fixing.
+ * NOTE: This PC is in the position but writeback is not
+ * allowed on r15.
+ * Doing it like this is more efficient than trapping this
+ * case in all possible locations in the following fixup code.
+ */
+
+ saved_lr = frame->tf_usr_lr;
+ frame->tf_usr_lr = frame->tf_svc_lr;
+
+ /*
+ * Note the trapframe does not have the SVC r13 so a fault
+ * from an instruction with writeback to r13 in SVC mode is
+ * not allowed. This should not happen as the kstack is
+ * always valid.
+ */
+ }
+
+ /* Get fault address and status from the CPU */
+
+ fault_pc = frame->tf_pc;
+ fault_instruction = *((volatile unsigned int *)fault_pc);
+
+ /* Decode the fault instruction and fix the registers as needed */
+
+ /* Was is a swap instruction ? */
+
+ if ((fault_instruction & 0x0fb00ff0) == 0x01000090) {
+ DFC_DISASSEMBLE(fault_pc);
+ } else if ((fault_instruction & 0x0c000000) == 0x04000000) {
+
+ /* Was is a ldr/str instruction */
+ /* This is for late abort only */
+
+ int base;
+ int offset;
+ int *registers = &frame->tf_r0;
+
+ DFC_DISASSEMBLE(fault_pc);
+
+ /* This is for late abort only */
+
+ if ((fault_instruction & (1 << 24)) == 0
+ || (fault_instruction & (1 << 21)) != 0) {
+ /* postindexed ldr/str with no writeback */
+
+ base = (fault_instruction >> 16) & 0x0f;
+ if (base == 13 &&
+ (frame->tf_spsr & PSR_MODE) == PSR_SVC32_MODE)
+ return ABORT_FIXUP_FAILED;
+ if (base == 15)
+ return ABORT_FIXUP_FAILED;
+ DFC_PRINTF(("late abt fix: r%d=%08x : ",
+ base, registers[base]));
+ if ((fault_instruction & (1 << 25)) == 0) {
+ /* Immediate offset - easy */
+
+ offset = fault_instruction & 0xfff;
+ if ((fault_instruction & (1 << 23)))
+ offset = -offset;
+ registers[base] += offset;
+ DFC_PRINTF(("imm=%08x ", offset));
+ } else {
+ /* offset is a shifted register */
+ int shift;
+
+ offset = fault_instruction & 0x0f;
+ if (offset == base)
+ return ABORT_FIXUP_FAILED;
+
+ /*
+ * Register offset - hard we have to
+ * cope with shifts !
+ */
+ offset = registers[offset];
+
+ if ((fault_instruction & (1 << 4)) == 0)
+ /* shift with amount */
+ shift = (fault_instruction >> 7) & 0x1f;
+ else {
+ /* shift with register */
+ if ((fault_instruction & (1 << 7)) != 0)
+ /* undefined for now so bail out */
+ return ABORT_FIXUP_FAILED;
+ shift = ((fault_instruction >> 8) & 0xf);
+ if (base == shift)
+ return ABORT_FIXUP_FAILED;
+ DFC_PRINTF(("shift reg=%d ", shift));
+ shift = registers[shift];
+ }
+ DFC_PRINTF(("shift=%08x ", shift));
+ switch (((fault_instruction >> 5) & 0x3)) {
+ case 0 : /* Logical left */
+ offset = (int)(((u_int)offset) << shift);
+ break;
+ case 1 : /* Logical Right */
+ if (shift == 0) shift = 32;
+ offset = (int)(((u_int)offset) >> shift);
+ break;
+ case 2 : /* Arithmetic Right */
+ if (shift == 0) shift = 32;
+ offset = (int)(((int)offset) >> shift);
+ break;
+ case 3 : /* Rotate right (rol or rxx) */
+ return ABORT_FIXUP_FAILED;
+ break;
+ }
+
+ DFC_PRINTF(("abt: fixed LDR/STR with "
+ "register offset\n"));
+ if ((fault_instruction & (1 << 23)))
+ offset = -offset;
+ DFC_PRINTF(("offset=%08x ", offset));
+ registers[base] += offset;
+ }
+ DFC_PRINTF(("r%d=%08x\n", base, registers[base]));
+ }
+ }
+
+ if ((frame->tf_spsr & PSR_MODE) == PSR_SVC32_MODE) {
+
+ /* Ok an abort in SVC mode */
+
+ /*
+ * Copy the SVC r14 into the usr r14 - The usr r14 is garbage
+ * as the fault happened in svc mode but we need it in the
+ * usr slot so we can treat the registers as an array of ints
+ * during fixing.
+ * NOTE: This PC is in the position but writeback is not
+ * allowed on r15.
+ * Doing it like this is more efficient than trapping this
+ * case in all possible locations in the prior fixup code.
+ */
+
+ frame->tf_svc_lr = frame->tf_usr_lr;
+ frame->tf_usr_lr = saved_lr;
+
+ /*
+ * Note the trapframe does not have the SVC r13 so a fault
+ * from an instruction with writeback to r13 in SVC mode is
+ * not allowed. This should not happen as the kstack is
+ * always valid.
+ */
+ }
+
+ /*
+ * Now let the early-abort fixup routine have a go, in case it
+ * was an LDM, STM, LDC or STC that faulted.
+ */
+
+ return early_abort_fixup(arg);
+}
+#endif /* CPU_ARM6(LATE)/7/7TDMI */
+
+/*
+ * CPU Setup code
+ */
+
+#if defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7TDMI) || \
+ defined(CPU_ARM8) || defined (CPU_ARM9) || defined(CPU_SA110) || \
+ defined(CPU_SA1100) || defined(CPU_SA1110) || \
+ defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425)
+
+#define IGN 0
+#define OR 1
+#define BIC 2
+
+struct cpu_option {
+ char *co_name;
+ int co_falseop;
+ int co_trueop;
+ int co_value;
+};
+
+static u_int parse_cpu_options __P((char *, struct cpu_option *, u_int));
+
+static u_int
+parse_cpu_options(args, optlist, cpuctrl)
+ char *args;
+ struct cpu_option *optlist;
+ u_int cpuctrl;
+{
+ int integer;
+
+ if (args == NULL)
+ return(cpuctrl);
+
+ while (optlist->co_name) {
+ if (get_bootconf_option(args, optlist->co_name,
+ BOOTOPT_TYPE_BOOLEAN, &integer)) {
+ if (integer) {
+ if (optlist->co_trueop == OR)
+ cpuctrl |= optlist->co_value;
+ else if (optlist->co_trueop == BIC)
+ cpuctrl &= ~optlist->co_value;
+ } else {
+ if (optlist->co_falseop == OR)
+ cpuctrl |= optlist->co_value;
+ else if (optlist->co_falseop == BIC)
+ cpuctrl &= ~optlist->co_value;
+ }
+ }
+ ++optlist;
+ }
+ return(cpuctrl);
+}
+#endif /* CPU_ARM6 || CPU_ARM7 || CPU_ARM7TDMI || CPU_ARM8 || CPU_SA110 */
+
+#if defined (CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7TDMI) \
+ || defined(CPU_ARM8)
+struct cpu_option arm678_options[] = {
+#ifdef COMPAT_12
+ { "nocache", IGN, BIC, CPU_CONTROL_IDC_ENABLE },
+ { "nowritebuf", IGN, BIC, CPU_CONTROL_WBUF_ENABLE },
+#endif /* COMPAT_12 */
+ { "cpu.cache", BIC, OR, CPU_CONTROL_IDC_ENABLE },
+ { "cpu.nocache", OR, BIC, CPU_CONTROL_IDC_ENABLE },
+ { "cpu.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "cpu.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+#endif /* CPU_ARM6 || CPU_ARM7 || CPU_ARM7TDMI || CPU_ARM8 */
+
+#ifdef CPU_ARM6
+struct cpu_option arm6_options[] = {
+ { "arm6.cache", BIC, OR, CPU_CONTROL_IDC_ENABLE },
+ { "arm6.nocache", OR, BIC, CPU_CONTROL_IDC_ENABLE },
+ { "arm6.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "arm6.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+arm6_setup(args)
+ char *args;
+{
+ int cpuctrl, cpuctrlmask;
+
+ /* Set up default control registers bits */
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IDC_ENABLE | CPU_CONTROL_WBUF_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IDC_ENABLE | CPU_CONTROL_WBUF_ENABLE
+ | CPU_CONTROL_ROM_ENABLE | CPU_CONTROL_BEND_ENABLE
+ | CPU_CONTROL_AFLT_ENABLE;
+
+#ifdef ARM6_LATE_ABORT
+ cpuctrl |= CPU_CONTROL_LABT_ENABLE;
+#endif /* ARM6_LATE_ABORT */
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, arm678_options, cpuctrl);
+ cpuctrl = parse_cpu_options(args, arm6_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+ cpu_control(0xffffffff, cpuctrl);
+}
+#endif /* CPU_ARM6 */
+
+#ifdef CPU_ARM7
+struct cpu_option arm7_options[] = {
+ { "arm7.cache", BIC, OR, CPU_CONTROL_IDC_ENABLE },
+ { "arm7.nocache", OR, BIC, CPU_CONTROL_IDC_ENABLE },
+ { "arm7.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "arm7.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+#ifdef COMPAT_12
+ { "fpaclk2", BIC, OR, CPU_CONTROL_CPCLK },
+#endif /* COMPAT_12 */
+ { "arm700.fpaclk", BIC, OR, CPU_CONTROL_CPCLK },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+arm7_setup(args)
+ char *args;
+{
+ int cpuctrl, cpuctrlmask;
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IDC_ENABLE | CPU_CONTROL_WBUF_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IDC_ENABLE | CPU_CONTROL_WBUF_ENABLE
+ | CPU_CONTROL_CPCLK | CPU_CONTROL_LABT_ENABLE
+ | CPU_CONTROL_ROM_ENABLE | CPU_CONTROL_BEND_ENABLE
+ | CPU_CONTROL_AFLT_ENABLE;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, arm678_options, cpuctrl);
+ cpuctrl = parse_cpu_options(args, arm7_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+ cpu_control(0xffffffff, cpuctrl);
+}
+#endif /* CPU_ARM7 */
+
+#ifdef CPU_ARM7TDMI
+struct cpu_option arm7tdmi_options[] = {
+ { "arm7.cache", BIC, OR, CPU_CONTROL_IDC_ENABLE },
+ { "arm7.nocache", OR, BIC, CPU_CONTROL_IDC_ENABLE },
+ { "arm7.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "arm7.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+#ifdef COMPAT_12
+ { "fpaclk2", BIC, OR, CPU_CONTROL_CPCLK },
+#endif /* COMPAT_12 */
+ { "arm700.fpaclk", BIC, OR, CPU_CONTROL_CPCLK },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+arm7tdmi_setup(args)
+ char *args;
+{
+ int cpuctrl;
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IDC_ENABLE | CPU_CONTROL_WBUF_ENABLE;
+
+ cpuctrl = parse_cpu_options(args, arm678_options, cpuctrl);
+ cpuctrl = parse_cpu_options(args, arm7tdmi_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+ cpu_control(0xffffffff, cpuctrl);
+}
+#endif /* CPU_ARM7TDMI */
+
+#ifdef CPU_ARM8
+struct cpu_option arm8_options[] = {
+ { "arm8.cache", BIC, OR, CPU_CONTROL_IDC_ENABLE },
+ { "arm8.nocache", OR, BIC, CPU_CONTROL_IDC_ENABLE },
+ { "arm8.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "arm8.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+#ifdef COMPAT_12
+ { "branchpredict", BIC, OR, CPU_CONTROL_BPRD_ENABLE },
+#endif /* COMPAT_12 */
+ { "cpu.branchpredict", BIC, OR, CPU_CONTROL_BPRD_ENABLE },
+ { "arm8.branchpredict", BIC, OR, CPU_CONTROL_BPRD_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+arm8_setup(args)
+ char *args;
+{
+ int integer;
+ int cpuctrl, cpuctrlmask;
+ int clocktest;
+ int setclock = 0;
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IDC_ENABLE | CPU_CONTROL_WBUF_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IDC_ENABLE | CPU_CONTROL_WBUF_ENABLE
+ | CPU_CONTROL_BPRD_ENABLE | CPU_CONTROL_ROM_ENABLE
+ | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, arm678_options, cpuctrl);
+ cpuctrl = parse_cpu_options(args, arm8_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ /* Get clock configuration */
+ clocktest = arm8_clock_config(0, 0) & 0x0f;
+
+ /* Special ARM8 clock and test configuration */
+ if (get_bootconf_option(args, "arm8.clock.reset", BOOTOPT_TYPE_BOOLEAN, &integer)) {
+ clocktest = 0;
+ setclock = 1;
+ }
+ if (get_bootconf_option(args, "arm8.clock.dynamic", BOOTOPT_TYPE_BOOLEAN, &integer)) {
+ if (integer)
+ clocktest |= 0x01;
+ else
+ clocktest &= ~(0x01);
+ setclock = 1;
+ }
+ if (get_bootconf_option(args, "arm8.clock.sync", BOOTOPT_TYPE_BOOLEAN, &integer)) {
+ if (integer)
+ clocktest |= 0x02;
+ else
+ clocktest &= ~(0x02);
+ setclock = 1;
+ }
+ if (get_bootconf_option(args, "arm8.clock.fast", BOOTOPT_TYPE_BININT, &integer)) {
+ clocktest = (clocktest & ~0xc0) | (integer & 3) << 2;
+ setclock = 1;
+ }
+ if (get_bootconf_option(args, "arm8.test", BOOTOPT_TYPE_BININT, &integer)) {
+ clocktest |= (integer & 7) << 5;
+ setclock = 1;
+ }
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+ cpu_control(0xffffffff, cpuctrl);
+
+ /* Set the clock/test register */
+ if (setclock)
+ arm8_clock_config(0x7f, clocktest);
+}
+#endif /* CPU_ARM8 */
+
+#ifdef CPU_ARM9
+struct cpu_option arm9_options[] = {
+ { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "cpu.nocache", OR, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "arm9.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "arm9.icache", BIC, OR, CPU_CONTROL_IC_ENABLE },
+ { "arm9.dcache", BIC, OR, CPU_CONTROL_DC_ENABLE },
+ { "cpu.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "cpu.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+ { "arm9.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+arm9_setup(args)
+ char *args;
+{
+ int cpuctrl, cpuctrlmask;
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE
+ | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE
+ | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE
+ | CPU_CONTROL_CPCLK;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, arm9_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+ cpu_control(0xffffffff, cpuctrl);
+
+}
+#endif /* CPU_ARM9 */
+
+#ifdef CPU_ARM10
+struct cpu_option arm10_options[] = {
+ { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "cpu.nocache", OR, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "arm10.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "arm10.icache", BIC, OR, CPU_CONTROL_IC_ENABLE },
+ { "arm10.dcache", BIC, OR, CPU_CONTROL_DC_ENABLE },
+ { "cpu.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "cpu.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+ { "arm10.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+arm10_setup(args)
+ char *args;
+{
+ int cpuctrl, cpuctrlmask;
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_BPRD_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE
+ | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE
+ | CPU_CONTROL_BPRD_ENABLE
+ | CPU_CONTROL_ROUNDROBIN | CPU_CONTROL_CPCLK;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, arm10_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Now really make sure they are clean. */
+ asm volatile ("mcr\tp15, 0, r0, c7, c7, 0" : : );
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+ cpu_control(0xffffffff, cpuctrl);
+
+ /* And again. */
+ cpu_idcache_wbinv_all();
+}
+#endif /* CPU_ARM10 */
+
+#ifdef CPU_SA110
+struct cpu_option sa110_options[] = {
+#ifdef COMPAT_12
+ { "nocache", IGN, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "nowritebuf", IGN, BIC, CPU_CONTROL_WBUF_ENABLE },
+#endif /* COMPAT_12 */
+ { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "cpu.nocache", OR, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "sa110.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "sa110.icache", BIC, OR, CPU_CONTROL_IC_ENABLE },
+ { "sa110.dcache", BIC, OR, CPU_CONTROL_DC_ENABLE },
+ { "cpu.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "cpu.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+ { "sa110.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+sa110_setup(args)
+ char *args;
+{
+ int cpuctrl, cpuctrlmask;
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE
+ | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE
+ | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE
+ | CPU_CONTROL_CPCLK;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, sa110_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+/* cpu_control(cpuctrlmask, cpuctrl);*/
+ cpu_control(0xffffffff, cpuctrl);
+
+ /*
+ * enable clockswitching, note that this doesn't read or write to r0,
+ * r0 is just to make it valid asm
+ */
+ __asm ("mcr 15, 0, r0, c15, c1, 2");
+}
+#endif /* CPU_SA110 */
+
+#if defined(CPU_SA1100) || defined(CPU_SA1110)
+struct cpu_option sa11x0_options[] = {
+#ifdef COMPAT_12
+ { "nocache", IGN, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "nowritebuf", IGN, BIC, CPU_CONTROL_WBUF_ENABLE },
+#endif /* COMPAT_12 */
+ { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "cpu.nocache", OR, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "sa11x0.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "sa11x0.icache", BIC, OR, CPU_CONTROL_IC_ENABLE },
+ { "sa11x0.dcache", BIC, OR, CPU_CONTROL_DC_ENABLE },
+ { "cpu.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "cpu.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+ { "sa11x0.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+sa11x0_setup(args)
+ char *args;
+{
+ int cpuctrl, cpuctrlmask;
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE
+ | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE
+ | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE
+ | CPU_CONTROL_CPCLK | CPU_CONTROL_VECRELOC;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, sa11x0_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ if (vector_page == ARM_VECTORS_HIGH)
+ cpuctrl |= CPU_CONTROL_VECRELOC;
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ cpu_control(0xffffffff, cpuctrl);
+}
+#endif /* CPU_SA1100 || CPU_SA1110 */
+
+#if defined(CPU_IXP12X0)
+struct cpu_option ixp12x0_options[] = {
+ { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "cpu.nocache", OR, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "ixp12x0.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "ixp12x0.icache", BIC, OR, CPU_CONTROL_IC_ENABLE },
+ { "ixp12x0.dcache", BIC, OR, CPU_CONTROL_DC_ENABLE },
+ { "cpu.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { "cpu.nowritebuf", OR, BIC, CPU_CONTROL_WBUF_ENABLE },
+ { "ixp12x0.writebuf", BIC, OR, CPU_CONTROL_WBUF_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+ixp12x0_setup(args)
+ char *args;
+{
+ int cpuctrl, cpuctrlmask;
+
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE;
+
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_AFLT_ENABLE
+ | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_WBUF_ENABLE
+ | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_ROM_ENABLE | CPU_CONTROL_IC_ENABLE
+ | CPU_CONTROL_VECRELOC;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, ixp12x0_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ if (vector_page == ARM_VECTORS_HIGH)
+ cpuctrl |= CPU_CONTROL_VECRELOC;
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /* Set the control register */
+ curcpu()->ci_ctrl = cpuctrl;
+ /* cpu_control(0xffffffff, cpuctrl); */
+ cpu_control(cpuctrlmask, cpuctrl);
+}
+#endif /* CPU_IXP12X0 */
+
+#if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425)
+struct cpu_option xscale_options[] = {
+#ifdef COMPAT_12
+ { "branchpredict", BIC, OR, CPU_CONTROL_BPRD_ENABLE },
+ { "nocache", IGN, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+#endif /* COMPAT_12 */
+ { "cpu.branchpredict", BIC, OR, CPU_CONTROL_BPRD_ENABLE },
+ { "cpu.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "cpu.nocache", OR, BIC, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "xscale.branchpredict", BIC, OR, CPU_CONTROL_BPRD_ENABLE },
+ { "xscale.cache", BIC, OR, (CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE) },
+ { "xscale.icache", BIC, OR, CPU_CONTROL_IC_ENABLE },
+ { "xscale.dcache", BIC, OR, CPU_CONTROL_DC_ENABLE },
+ { NULL, IGN, IGN, 0 }
+};
+
+void
+xscale_setup(args)
+ char *args;
+{
+ uint32_t auxctl;
+ int cpuctrl, cpuctrlmask;
+
+ /*
+ * The XScale Write Buffer is always enabled. Our option
+ * is to enable/disable coalescing. Note that bits 6:3
+ * must always be enabled.
+ */
+
+ cpuctrl = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_LABT_ENABLE
+ | CPU_CONTROL_BPRD_ENABLE;
+ cpuctrlmask = CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_32BP_ENABLE
+ | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_SYST_ENABLE
+ | CPU_CONTROL_IC_ENABLE | CPU_CONTROL_DC_ENABLE
+ | CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_ROM_ENABLE
+ | CPU_CONTROL_BEND_ENABLE | CPU_CONTROL_AFLT_ENABLE
+ | CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_BPRD_ENABLE
+ | CPU_CONTROL_CPCLK | CPU_CONTROL_VECRELOC;
+
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+ cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+
+ cpuctrl = parse_cpu_options(args, xscale_options, cpuctrl);
+
+#ifdef __ARMEB__
+ cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+
+ if (vector_page == ARM_VECTORS_HIGH)
+ cpuctrl |= CPU_CONTROL_VECRELOC;
+
+ /* Clear out the cache */
+ cpu_idcache_wbinv_all();
+
+ /*
+ * Set the control register. Note that bits 6:3 must always
+ * be set to 1.
+ */
+ curcpu()->ci_ctrl = cpuctrl;
+/* cpu_control(cpuctrlmask, cpuctrl);*/
+ cpu_control(0xffffffff, cpuctrl);
+
+ /* Make sure write coalescing is turned on */
+ __asm __volatile("mrc p15, 0, %0, c1, c0, 1"
+ : "=r" (auxctl));
+#ifdef XSCALE_NO_COALESCE_WRITES
+ auxctl |= XSCALE_AUXCTL_K;
+#else
+ auxctl &= ~XSCALE_AUXCTL_K;
+#endif
+ __asm __volatile("mcr p15, 0, %0, c1, c0, 1"
+ : : "r" (auxctl));
+}
+#endif /* CPU_XSCALE_80200 || CPU_XSCALE_80321 || CPU_XSCALE_PXA2X0 || CPU_XSCALE_IXP425 */
diff --git a/sys/arch/arm/arm/cpufunc_asm.S b/sys/arch/arm/arm/cpufunc_asm.S
new file mode 100644
index 00000000000..2e36bada941
--- /dev/null
+++ b/sys/arch/arm/arm/cpufunc_asm.S
@@ -0,0 +1,151 @@
+/* $OpenBSD: cpufunc_asm.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: cpufunc_asm.S,v 1.12 2003/09/06 09:14:52 rearnsha Exp $ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Causality Limited.
+ * 4. The name of Causality Limited may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * cpufunc.S
+ *
+ * Assembly functions for CPU / MMU / TLB specific operations
+ *
+ * Created : 30/01/97
+ */
+
+#include <machine/cpu.h>
+#include <machine/asm.h>
+
+ .text
+ .align 0
+
+ENTRY(cpufunc_nullop)
+ mov pc, lr
+
+/*
+ * Generic functions to read the internal coprocessor registers
+ *
+ * Currently these registers are :
+ * c0 - CPU ID
+ * c5 - Fault status
+ * c6 - Fault address
+ *
+ */
+
+ENTRY(cpufunc_id)
+ mrc p15, 0, r0, c0, c0, 0
+ mov pc, lr
+
+ENTRY(cpu_get_control)
+ mrc p15, 0, r0, c1, c0, 0
+ mov pc, lr
+
+ENTRY(cpu_read_cache_config)
+ mrc p15, 0, r0, c0, c0, 1
+ mov pc, lr
+
+ENTRY(cpufunc_faultstatus)
+ mrc p15, 0, r0, c5, c0, 0
+ mov pc, lr
+
+ENTRY(cpufunc_faultaddress)
+ mrc p15, 0, r0, c6, c0, 0
+ mov pc, lr
+
+
+/*
+ * Generic functions to write the internal coprocessor registers
+ *
+ *
+ * Currently these registers are
+ * c1 - CPU Control
+ * c3 - Domain Access Control
+ *
+ * All other registers are CPU architecture specific
+ */
+
+#if 0 /* See below. */
+ENTRY(cpufunc_control)
+ mcr p15, 0, r0, c1, c0, 0
+ mov pc, lr
+#endif
+
+ENTRY(cpufunc_domains)
+ mcr p15, 0, r0, c3, c0, 0
+ mov pc, lr
+
+/*
+ * Generic functions to read/modify/write the internal coprocessor registers
+ *
+ *
+ * Currently these registers are
+ * c1 - CPU Control
+ *
+ * All other registers are CPU architecture specific
+ */
+
+ENTRY(cpufunc_control)
+ mrc p15, 0, r3, c1, c0, 0 /* Read the control register */
+ bic r2, r3, r0 /* Clear bits */
+ eor r2, r2, r1 /* XOR bits */
+
+ teq r2, r3 /* Only write if there is a change */
+ mcrne p15, 0, r2, c1, c0, 0 /* Write new control register */
+ mov r0, r3 /* Return old value */
+ mov pc, lr
+
+/*
+ * other potentially useful software functions are:
+ * clean D cache entry and flush I cache entry
+ * for the moment use cache_purgeID_E
+ */
+
+/* Random odd functions */
+
+/*
+ * Function to get the offset of a stored program counter from the
+ * instruction doing the store. This offset is defined to be the same
+ * for all STRs and STMs on a given implementation. Code based on
+ * section 2.4.3 of the ARM ARM (2nd Ed.), with modifications to work
+ * in 26-bit modes as well.
+ */
+ENTRY(get_pc_str_offset)
+ mov ip, sp
+ stmfd sp!, {fp, ip, lr, pc}
+ sub fp, ip, #4
+ sub sp, sp, #4
+ mov r1, pc /* R1 = addr of following STR */
+ mov r0, r0
+ str pc, [sp] /* [SP] = . + offset */
+ ldr r0, [sp]
+ sub r0, r0, r1
+ ldmdb fp, {fp, sp, pc}
diff --git a/sys/arch/arm/arm/cpufunc_asm_armv4.S b/sys/arch/arm/arm/cpufunc_asm_armv4.S
new file mode 100644
index 00000000000..35089398b4c
--- /dev/null
+++ b/sys/arch/arm/arm/cpufunc_asm_armv4.S
@@ -0,0 +1,67 @@
+/* $OpenBSD: cpufunc_asm_armv4.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: cpufunc_asm_armv4.S,v 1.1 2001/11/10 23:14:09 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001 ARM Limited
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Causality Limited.
+ * 4. The name of Causality Limited may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * ARM9 assembly functions for CPU / MMU / TLB specific operations
+ */
+
+#include <machine/cpu.h>
+#include <machine/asm.h>
+
+/*
+ * TLB functions
+ */
+ENTRY(armv4_tlb_flushID)
+ mcr p15, 0, r0, c8, c7, 0 /* flush I+D tlb */
+ mov pc, lr
+
+ENTRY(armv4_tlb_flushI)
+ mcr p15, 0, r0, c8, c5, 0 /* flush I tlb */
+ mov pc, lr
+
+ENTRY(armv4_tlb_flushD)
+ mcr p15, 0, r0, c8, c6, 0 /* flush D tlb */
+ mov pc, lr
+
+ENTRY(armv4_tlb_flushD_SE)
+ mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */
+ mov pc, lr
+
+/*
+ * Other functions
+ */
+ENTRY(armv4_drain_writebuf)
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+ mov pc, lr
diff --git a/sys/arch/arm/arm/cpufunc_asm_sa1.S b/sys/arch/arm/arm/cpufunc_asm_sa1.S
new file mode 100644
index 00000000000..01db708e61c
--- /dev/null
+++ b/sys/arch/arm/arm/cpufunc_asm_sa1.S
@@ -0,0 +1,314 @@
+/* $OpenBSD: cpufunc_asm_sa1.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: cpufunc_asm_sa1.S,v 1.8 2002/08/17 16:36:32 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Causality Limited.
+ * 4. The name of Causality Limited may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * SA-1 assembly functions for CPU / MMU / TLB specific operations
+ */
+
+#include <machine/cpu.h>
+#include <machine/asm.h>
+
+.Lblock_userspace_access:
+ .word _C_LABEL(block_userspace_access)
+
+/*
+ * Functions to set the MMU Translation Table Base register
+ *
+ * We need to clean and flush the cache as it uses virtual
+ * addresses that are about to change.
+ */
+ENTRY(sa1_setttb)
+#ifdef CACHE_CLEAN_BLOCK_INTR
+ mrs r3, cpsr_all
+ orr r1, r3, #(I32_bit | F32_bit)
+ msr cpsr_all, r1
+#else
+ ldr r3, .Lblock_userspace_access
+ ldr r2, [r3]
+ orr r1, r2, #1
+ str r1, [r3]
+#endif
+ stmfd sp!, {r0-r3, lr}
+ bl _C_LABEL(sa1_cache_cleanID)
+ ldmfd sp!, {r0-r3, lr}
+ mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */
+ mcr p15, 0, r0, c7, c10, 4 /* drain write and fill buffer */
+
+ /* Write the TTB */
+ mcr p15, 0, r0, c2, c0, 0
+
+ /* If we have updated the TTB we must flush the TLB */
+ mcr p15, 0, r0, c8, c7, 0 /* invalidate I+D TLB */
+
+ /* The cleanID above means we only need to flush the I cache here */
+ mcr p15, 0, r0, c7, c5, 0 /* invalidate I$ and BTB */
+
+ /* Make sure that pipeline is emptied */
+ mov r0, r0
+ mov r0, r0
+#ifdef CACHE_CLEAN_BLOCK_INTR
+ msr cpsr_all, r3
+#else
+ str r2, [r3]
+#endif
+ mov pc, lr
+
+/*
+ * TLB functions
+ */
+ENTRY(sa1_tlb_flushID_SE)
+ mcr p15, 0, r0, c8, c6, 1 /* flush D tlb single entry */
+ mcr p15, 0, r0, c8, c5, 0 /* flush I tlb */
+ mov pc, lr
+
+/*
+ * Cache functions
+ */
+ENTRY(sa1_cache_flushID)
+ mcr p15, 0, r0, c7, c7, 0 /* flush I+D cache */
+ mov pc, lr
+
+ENTRY(sa1_cache_flushI)
+ mcr p15, 0, r0, c7, c5, 0 /* flush I cache */
+ mov pc, lr
+
+ENTRY(sa1_cache_flushD)
+ mcr p15, 0, r0, c7, c6, 0 /* flush D cache */
+ mov pc, lr
+
+ENTRY(sa1_cache_flushD_SE)
+ mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
+ mov pc, lr
+
+ENTRY(sa1_cache_cleanD_E)
+ mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
+ mov pc, lr
+
+/*
+ * Information for the SA-1 cache clean/purge functions:
+ *
+ * * Virtual address of the memory region to use
+ * * Size of memory region
+ */
+ .data
+
+ .global _C_LABEL(sa1_cache_clean_addr)
+_C_LABEL(sa1_cache_clean_addr):
+ .word 0xf0000000
+
+ .global _C_LABEL(sa1_cache_clean_size)
+_C_LABEL(sa1_cache_clean_size):
+#if defined(CPU_SA1100) || defined(CPU_SA1110)
+ .word 0x00004000
+#else
+ .word 0x00008000
+#endif
+
+ .text
+
+.Lsa1_cache_clean_addr:
+ .word _C_LABEL(sa1_cache_clean_addr)
+.Lsa1_cache_clean_size:
+ .word _C_LABEL(sa1_cache_clean_size)
+
+#ifdef CACHE_CLEAN_BLOCK_INTR
+#define SA1_CACHE_CLEAN_BLOCK \
+ mrs r3, cpsr_all ; \
+ orr r0, r3, #(I32_bit | F32_bit) ; \
+ msr cpsr_all, r0
+
+#define SA1_CACHE_CLEAN_UNBLOCK \
+ msr cpsr_all, r3
+#else
+#define SA1_CACHE_CLEAN_BLOCK \
+ ldr r3, .Lblock_userspace_access ; \
+ ldr ip, [r3] ; \
+ orr r0, ip, #1 ; \
+ str r0, [r3]
+
+#define SA1_CACHE_CLEAN_UNBLOCK \
+ str ip, [r3]
+#endif /* CACHE_CLEAN_BLOCK_INTR */
+
+#ifdef DOUBLE_CACHE_CLEAN_BANK
+#define SA1_DOUBLE_CACHE_CLEAN_BANK \
+ eor r0, r0, r1 ; \
+ str r0, [r2]
+#else
+#define SA1_DOUBLE_CACHE_CLEAN_BANK /* nothing */
+#endif /* DOUBLE_CACHE_CLEAN_BANK */
+
+#define SA1_CACHE_CLEAN_PROLOGUE \
+ SA1_CACHE_CLEAN_BLOCK ; \
+ ldr r2, .Lsa1_cache_clean_addr ; \
+ ldmia r2, {r0, r1} ; \
+ SA1_DOUBLE_CACHE_CLEAN_BANK
+
+#define SA1_CACHE_CLEAN_EPILOGUE \
+ SA1_CACHE_CLEAN_UNBLOCK
+
+ENTRY_NP(sa1_cache_syncI)
+ENTRY_NP(sa1_cache_purgeID)
+ mcr p15, 0, r0, c7, c5, 0 /* flush I cache (D cleaned below) */
+ENTRY_NP(sa1_cache_cleanID)
+ENTRY_NP(sa1_cache_purgeD)
+ENTRY(sa1_cache_cleanD)
+ SA1_CACHE_CLEAN_PROLOGUE
+
+1: ldr r2, [r0], #32
+ subs r1, r1, #32
+ bne 1b
+
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+
+ SA1_CACHE_CLEAN_EPILOGUE
+ mov pc, lr
+
+ENTRY(sa1_cache_purgeID_E)
+ mcr p15, 0, r0, c7, c10, 1 /* clean dcache entry */
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+ mcr p15, 0, r0, c7, c5, 0 /* flush I cache */
+ mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
+ mov pc, lr
+
+ENTRY(sa1_cache_purgeD_E)
+ mcr p15, 0, r0, c7, c10, 1 /* clean dcache entry */
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+ mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
+ mov pc, lr
+
+/*
+ * Soft functions
+ */
+/* sa1_cache_syncI is identical to sa1_cache_purgeID */
+
+ENTRY(sa1_cache_cleanID_rng)
+ENTRY(sa1_cache_cleanD_rng)
+ cmp r1, #0x4000
+ bcs _C_LABEL(sa1_cache_cleanID)
+
+ and r2, r0, #0x1f
+ add r1, r1, r2
+ bic r0, r0, #0x1f
+
+1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
+ add r0, r0, #32
+ subs r1, r1, #32
+ bhi 1b
+
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+ mov pc, lr
+
+ENTRY(sa1_cache_purgeID_rng)
+ cmp r1, #0x4000
+ bcs _C_LABEL(sa1_cache_purgeID)
+
+ and r2, r0, #0x1f
+ add r1, r1, r2
+ bic r0, r0, #0x1f
+
+1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
+ mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
+ add r0, r0, #32
+ subs r1, r1, #32
+ bhi 1b
+
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+ mcr p15, 0, r0, c7, c5, 0 /* flush I cache */
+ mov pc, lr
+
+ENTRY(sa1_cache_purgeD_rng)
+ cmp r1, #0x4000
+ bcs _C_LABEL(sa1_cache_purgeD)
+
+ and r2, r0, #0x1f
+ add r1, r1, r2
+ bic r0, r0, #0x1f
+
+1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
+ mcr p15, 0, r0, c7, c6, 1 /* flush D cache single entry */
+ add r0, r0, #32
+ subs r1, r1, #32
+ bhi 1b
+
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+ mov pc, lr
+
+ENTRY(sa1_cache_syncI_rng)
+ cmp r1, #0x4000
+ bcs _C_LABEL(sa1_cache_syncI)
+
+ and r2, r0, #0x1f
+ add r1, r1, r2
+ bic r0, r0, #0x1f
+
+1: mcr p15, 0, r0, c7, c10, 1 /* clean D cache entry */
+ add r0, r0, #32
+ subs r1, r1, #32
+ bhi 1b
+
+ mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */
+ mcr p15, 0, r0, c7, c5, 0 /* flush I cache */
+
+ mov pc, lr
+
+/*
+ * Context switch.
+ *
+ * These is the CPU-specific parts of the context switcher cpu_switch()
+ * These functions actually perform the TTB reload.
+ *
+ * NOTE: Special calling convention
+ * r1, r4-r13 must be preserved
+ */
+#if defined(CPU_SA110)
+ENTRY(sa110_context_switch)
+ /*
+ * CF_CACHE_PURGE_ID will *ALWAYS* be called prior to this.
+ * Thus the data cache will contain only kernel data and the
+ * instruction cache will contain only kernel code, and all
+ * kernel mappings are shared by all processes.
+ */
+
+ /* Write the TTB */
+ mcr p15, 0, r0, c2, c0, 0
+
+ /* If we have updated the TTB we must flush the TLB */
+ mcr p15, 0, r0, c8, c7, 0 /* flush the I+D tlb */
+
+ /* Make sure that pipeline is emptied */
+ mov r0, r0
+ mov r0, r0
+ mov pc, lr
+#endif
diff --git a/sys/arch/arm/arm/cpuswitch.S b/sys/arch/arm/arm/cpuswitch.S
new file mode 100644
index 00000000000..743540537d4
--- /dev/null
+++ b/sys/arch/arm/arm/cpuswitch.S
@@ -0,0 +1,1172 @@
+/* $OpenBSD: cpuswitch.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: cpuswitch.S,v 1.41 2003/11/15 08:44:18 scw Exp $ */$
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * cpuswitch.S
+ *
+ * cpu switching functions
+ *
+ * Created : 15/10/94
+ */
+
+#include "assym.h"
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/asm.h>
+
+/* LINTSTUB: include <sys/param.h> */
+
+#undef IRQdisable
+#undef IRQenable
+
+/*
+ * New experimental definitions of IRQdisable and IRQenable
+ * These keep FIQ's enabled since FIQ's are special.
+ */
+
+#define IRQdisable \
+ mrs r14, cpsr ; \
+ orr r14, r14, #(I32_bit) ; \
+ msr cpsr_c, r14 ; \
+
+#define IRQenable \
+ mrs r14, cpsr ; \
+ bic r14, r14, #(I32_bit) ; \
+ msr cpsr_c, r14 ; \
+
+/*
+ * These are used for switching the translation table/DACR.
+ * Since the vector page can be invalid for a short time, we must
+ * disable both regular IRQs *and* FIQs.
+ *
+ * XXX: This is not necessary if the vector table is relocated.
+ */
+#define IRQdisableALL \
+ mrs r14, cpsr ; \
+ orr r14, r14, #(I32_bit | F32_bit) ; \
+ msr cpsr_c, r14
+
+#define IRQenableALL \
+ mrs r14, cpsr ; \
+ bic r14, r14, #(I32_bit | F32_bit) ; \
+ msr cpsr_c, r14
+
+ .text
+
+.Lwhichqs:
+ .word _C_LABEL(whichqs)
+
+.Lqs:
+ .word _C_LABEL(qs)
+
+/*
+ * On entry
+ * r0 = process
+ */
+
+ENTRY(setrunqueue)
+ /*
+ * Local register usage
+ * r0 = process
+ * r1 = queue
+ * r2 = &qs[queue] and temp
+ * r3 = temp
+ * r12 = whichqs
+ */
+#ifdef DIAGNOSTIC
+ ldr r1, [r0, #(P_BACK)]
+ teq r1, #0x00000000
+ bne Lsetrunqueue_erg
+
+ ldr r1, [r0, #(P_WCHAN)]
+ teq r1, #0x00000000
+ bne Lsetrunqueue_erg
+#endif
+
+ /* Get the priority of the queue */
+ ldrb r1, [r0, #(P_PRIORITY)]
+ mov r1, r1, lsr #2
+
+ /* Indicate that there is a process on this queue */
+ ldr r12, .Lwhichqs
+ ldr r2, [r12]
+ mov r3, #0x00000001
+ mov r3, r3, lsl r1
+ orr r2, r2, r3
+ str r2, [r12]
+
+ /* Get the address of the queue */
+ ldr r2, .Lqs
+ add r1, r2, r1, lsl # 3
+
+ /* Hook the process in */
+ str r1, [r0, #(P_FORW)]
+ ldr r2, [r1, #(P_BACK)]
+
+ str r0, [r1, #(P_BACK)]
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq Lsetrunqueue_erg
+#endif
+ str r0, [r2, #(P_FORW)]
+ str r2, [r0, #(P_BACK)]
+
+ mov pc, lr
+
+#ifdef DIAGNOSTIC
+Lsetrunqueue_erg:
+ mov r2, r1
+ mov r1, r0
+ add r0, pc, #Ltext1 - . - 8
+ bl _C_LABEL(printf)
+
+ ldr r2, .Lqs
+ ldr r1, [r2]
+ add r0, pc, #Ltext2 - . - 8
+ b _C_LABEL(panic)
+
+Ltext1:
+ .asciz "setrunqueue : %08x %08x\n"
+Ltext2:
+ .asciz "setrunqueue : [qs]=%08x qs=%08x\n"
+ .align 0
+#endif
+
+/*
+ * On entry
+ * r0 = process
+ */
+
+ENTRY(remrunqueue)
+ /*
+ * Local register usage
+ * r0 = oldproc
+ * r1 = queue
+ * r2 = &qs[queue] and scratch
+ * r3 = scratch
+ * r12 = whichqs
+ */
+
+ /* Get the priority of the queue */
+ ldrb r1, [r0, #(P_PRIORITY)]
+ mov r1, r1, lsr #2
+
+ /* Unhook the process */
+ ldr r2, [r0, #(P_FORW)]
+ ldr r3, [r0, #(P_BACK)]
+
+ str r3, [r2, #(P_BACK)]
+ str r2, [r3, #(P_FORW)]
+
+ /* If the queue is now empty clear the queue not empty flag */
+ teq r2, r3
+
+ /* This could be reworked to avoid the use of r4 */
+ ldreq r12, .Lwhichqs
+ ldreq r2, [r12]
+ moveq r3, #0x00000001
+ moveq r3, r3, lsl r1
+ biceq r2, r2, r3
+ streq r2, [r12]
+
+ /* Remove the back pointer for the process */
+ mov r1, #0x00000000
+ str r1, [r0, #(P_BACK)]
+
+ mov pc, lr
+
+
+/*
+ * cpuswitch()
+ *
+ * preforms a process context switch.
+ * This function has several entry points
+ */
+
+#ifdef MULTIPROCESSOR
+.Lcpu_info_store:
+ .word _C_LABEL(cpu_info_store)
+.Lcurproc:
+ /* FIXME: This is bogus in the general case. */
+ .word _C_LABEL(cpu_info_store) + CI_CURLWP
+
+.Lcurpcb:
+ .word _C_LABEL(cpu_info_store) + CI_CURPCB
+#else
+.Lcurproc:
+ .word _C_LABEL(curproc)
+
+.Lcurpcb:
+ .word _C_LABEL(curpcb)
+#endif
+
+.Lwant_resched:
+ .word _C_LABEL(want_resched)
+
+.Lcpufuncs:
+ .word _C_LABEL(cpufuncs)
+
+#ifndef MULTIPROCESSOR
+ .data
+ .global _C_LABEL(curpcb)
+_C_LABEL(curpcb):
+ .word 0x00000000
+ .text
+#endif
+
+.Lblock_userspace_access:
+ .word _C_LABEL(block_userspace_access)
+
+.Lcpu_do_powersave:
+ .word _C_LABEL(cpu_do_powersave)
+
+.Lpmap_kernel_cstate:
+ .word (kernel_pmap_store + PMAP_CSTATE)
+
+.Llast_cache_state_ptr:
+ .word _C_LABEL(pmap_cache_state)
+
+/*
+ * Idle loop, exercised while waiting for a process to wake up.
+ *
+ * NOTE: When we jump back to .Lswitch_search, we must have a
+ * pointer to whichqs in r7, which is what it is when we arrive
+ * here.
+ */
+/* LINTSTUB: Ignore */
+ASENTRY_NP(idle)
+ ldr r6, .Lcpu_do_powersave
+ IRQenable /* Enable interrupts */
+ ldr r6, [r6] /* r6 = cpu_do_powersave */
+
+#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ bl _C_LABEL(sched_unlock_idle)
+#endif
+
+ /* Drop to spl0 (returns the current spl level in r0). */
+#ifdef __NEWINTR
+ mov r0, #(IPL_NONE)
+ bl _C_LABEL(_spllower)
+#else /* ! __NEWINTR */
+ mov r0, #(_SPL_0)
+ bl _C_LABEL(splx)
+#endif /* __NEWINTR */
+
+ teq r6, #0 /* cpu_do_powersave non zero? */
+ ldrne r6, .Lcpufuncs
+ mov r4, r0 /* Old interrupt level to r4 */
+ ldrne r6, [r6, #(CF_SLEEP)]
+
+ /*
+ * Main idle loop.
+ * r6 points to power-save idle function if required, else NULL.
+ */
+1: ldr r3, [r7] /* r3 = sched_whichqs */
+ teq r3, #0
+ bne 2f /* We have work to do */
+ teq r6, #0 /* Powersave idle? */
+ beq 1b /* Nope. Just sit-n-spin. */
+
+ /*
+ * Before going into powersave idle mode, disable interrupts
+ * and check sched_whichqs one more time.
+ */
+ IRQdisableALL
+ ldr r3, [r7]
+ mov r0, #0
+ teq r3, #0 /* sched_whichqs still zero? */
+ moveq lr, pc
+ moveq pc, r6 /* If so, do powersave idle */
+ IRQenableALL
+ b 1b /* Back around */
+
+ /*
+ * sched_whichqs indicates that at least one proc is ready to run.
+ * Restore the original interrupt priority level, grab the
+ * scheduler lock if necessary, and jump back into cpu_switch.
+ */
+2: mov r0, r4
+#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ bl _C_LABEL(splx)
+ adr lr, .Lswitch_search
+ b _C_LABEL(sched_lock_idle)
+#else
+ adr lr, .Lswitch_search
+ b _C_LABEL(splx)
+#endif
+
+
+/*
+ * Find a new lwp to run, save the current context and
+ * load the new context
+ *
+ * Arguments:
+ * r0 'struct proc *' of the current LWP
+ */
+
+ENTRY(cpu_switch)
+/*
+ * Local register usage. Some of these registers are out of date.
+ * r1 = oldproc
+ * r2 = spl level
+ * r3 = whichqs
+ * r4 = queue
+ * r5 = &qs[queue]
+ * r6 = newlwp
+ * r7 = scratch
+ */
+ stmfd sp!, {r4-r7, lr}
+
+ /*
+ * Indicate that there is no longer a valid process (curlwp = 0).
+ * Zero the current PCB pointer while we're at it.
+ */
+ ldr r7, .Lcurproc
+ ldr r6, .Lcurpcb
+ mov r2, #0x00000000
+ str r2, [r7] /* curproc = NULL */
+ str r2, [r6] /* curpcb = NULL */
+
+ /* stash the old proc while we call functions */
+ mov r5, r0
+
+ /* First phase : find a new proc */
+ ldr r7, .Lwhichqs
+
+ /* rem: r5 = old proc */
+ /* rem: r7 = &whichqs */
+
+.Lswitch_search:
+ IRQdisable
+
+ /* Do we have any active queues */
+ ldr r3, [r7]
+
+ /* If not we must idle until we do. */
+ teq r3, #0x00000000
+ beq _ASM_LABEL(idle)
+
+ /* put old proc back in r1 */
+ mov r1, r5
+
+ /* rem: r1 = old proc */
+ /* rem: r3 = whichqs */
+ /* rem: interrupts are disabled */
+
+ /* used further down, saves SA stall */
+ ldr r6, .Lqs
+
+ /*
+ * We have found an active queue. Currently we do not know which queue
+ * is active just that one of them is.
+ */
+ /* Non-Xscale version of the ffs algorithm devised by d.seal and
+ * posted to comp.sys.arm on 16 Feb 1994.
+ */
+ rsb r5, r3, #0
+ ands r0, r3, r5
+
+#ifndef __XSCALE__
+ adr r5, .Lcpu_switch_ffs_table
+
+ /* X = R0 */
+ orr r4, r0, r0, lsl #4 /* r4 = X * 0x11 */
+ orr r4, r4, r4, lsl #6 /* r4 = X * 0x451 */
+ rsb r4, r4, r4, lsl #16 /* r4 = X * 0x0450fbaf */
+
+ /* now lookup in table indexed on top 6 bits of a4 */
+ ldrb r4, [ r5, r4, lsr #26 ]
+
+#else /* __XSCALE__ */
+ clz r4, r0
+ rsb r4, r4, #31
+#endif /* __XSCALE__ */
+
+ /* rem: r0 = bit mask of chosen queue (1 << r4) */
+ /* rem: r1 = old proc */
+ /* rem: r3 = whichqs */
+ /* rem: r4 = queue number */
+ /* rem: interrupts are disabled */
+
+ /* Get the address of the queue (&qs[queue]) */
+ add r5, r6, r4, lsl #3
+
+ /*
+ * Get the proc from the queue and place the next process in
+ * the queue at the head. This basically unlinks the lwp at
+ * the head of the queue.
+ */
+ ldr r6, [r5, #(P_FORW)]
+
+#ifdef DIAGNOSTIC
+ cmp r6, r5
+ beq .Lswitch_bogons
+#endif
+
+ /* rem: r6 = new proc */
+ ldr r7, [r6, #(P_FORW)]
+ str r7, [r5, #(P_FORW)]
+
+ /*
+ * Test to see if the queue is now empty. If the head of the queue
+ * points to the queue itself then there are no more procs in
+ * the queue. We can therefore clear the queue not empty flag held
+ * in r3.
+ */
+
+ teq r5, r7
+ biceq r3, r3, r0
+
+ /* rem: r0 = bit mask of chosen queue (1 << r4) - NOT NEEDED AN MORE */
+
+ /* Fix the back pointer for the lwp now at the head of the queue. */
+ ldr r0, [r6, #(P_BACK)]
+ str r0, [r7, #(P_BACK)]
+
+ /* Update the RAM copy of the queue not empty flags word. */
+ ldreq r7, .Lwhichqs
+ streq r3, [r7]
+
+ /* rem: r1 = old proc */
+ /* rem: r3 = whichqs - NOT NEEDED ANY MORE */
+ /* rem: r4 = queue number - NOT NEEDED ANY MORE */
+ /* rem: r6 = new proc */
+ /* rem: interrupts are disabled */
+
+ /* Clear the want_resched flag */
+ ldr r7, .Lwant_resched
+ mov r0, #0x00000000
+ str r0, [r7]
+
+ /*
+ * Clear the back pointer of the proc we have removed from
+ * the head of the queue. The new proc is isolated now.
+ */
+ str r0, [r6, #(P_BACK)]
+
+#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ /*
+ * unlock the sched_lock, but leave interrupts off, for now.
+ */
+ mov r7, r1
+ bl _C_LABEL(sched_unlock_idle)
+ mov r1, r7
+#endif
+
+
+.Lswitch_resume:
+ /* rem: r1 = old proc */
+ /* rem: r4 = return value [not used if came from cpu_switchto()] */
+ /* rem: r6 = new process */
+ /* rem: interrupts are disabled */
+
+#ifdef MULTIPROCESSOR
+ /* XXX use curcpu() */
+ ldr r0, .Lcpu_info_store
+ str r0, [r6, #(P_CPU)]
+#else
+ /* l->l_cpu initialized in fork1() for single-processor */
+#endif
+
+#if 0
+ /* Process is now on a processor. */
+ mov r0, #LSONPROC /* l->l_stat = LSONPROC */
+ str r0, [r6, #(P_STAT)]
+#endif
+
+ /* We have a new curproc now so make a note it */
+ ldr r7, .Lcurproc
+ str r6, [r7]
+
+ /* Hook in a new pcb */
+ ldr r7, .Lcurpcb
+ ldr r0, [r6, #(P_ADDR)]
+ str r0, [r7]
+
+ /* At this point we can allow IRQ's again. */
+ IRQenable
+
+ /* rem: r1 = old proc */
+ /* rem: r4 = return value */
+ /* rem: r6 = new process */
+ /* rem: interrupts are enabled */
+
+ /*
+ * If the new process is the same as the process that called
+ * cpu_switch() then we do not need to save and restore any
+ * contexts. This means we can make a quick exit.
+ * The test is simple if curproc on entry (now in r1) is the
+ * same as the proc removed from the queue we can jump to the exit.
+ */
+ teq r1, r6
+ moveq r4, #0x00000000 /* default to "didn't switch" */
+ beq .Lswitch_return
+
+ /*
+ * At this point, we are guaranteed to be switching to
+ * a new proc.
+ */
+ mov r4, #0x00000001
+
+ /* Remember the old proc in r0 */
+ mov r0, r1
+
+ /*
+ * If the old proc on entry to cpu_switch was zero then the
+ * process that called it was exiting. This means that we do
+ * not need to save the current context. Instead we can jump
+ * straight to restoring the context for the new process.
+ */
+ teq r0, #0x00000000
+ beq .Lswitch_exited
+
+ /* rem: r0 = old proc */
+ /* rem: r4 = return value */
+ /* rem: r6 = new process */
+ /* rem: interrupts are enabled */
+
+ /* Stage two : Save old context */
+
+ /* Get the user structure for the old proc. */
+ ldr r1, [r0, #(P_ADDR)]
+
+ /* Save all the registers in the old proc's pcb */
+#ifndef __XSCALE__
+ add r7, r1, #(PCB_R8)
+ stmia r7, {r8-r13}
+#else
+ strd r8, [r1, #(PCB_R8)]
+ strd r10, [r1, #(PCB_R10)]
+ strd r12, [r1, #(PCB_R12)]
+#endif
+
+ /*
+ * NOTE: We can now use r8-r13 until it is time to restore
+ * them for the new process.
+ */
+
+ /* Remember the old PCB. */
+ mov r8, r1
+
+ /* r1 now free! */
+
+ /* Get the user structure for the new process in r9 */
+ ldr r9, [r6, #(P_ADDR)]
+
+ /*
+ * This can be optimised... We know we want to go from SVC32
+ * mode to UND32 mode
+ */
+ mrs r3, cpsr
+ bic r2, r3, #(PSR_MODE)
+ orr r2, r2, #(PSR_UND32_MODE | I32_bit)
+ msr cpsr_c, r2
+
+ str sp, [r8, #(PCB_UND_SP)]
+
+ msr cpsr_c, r3 /* Restore the old mode */
+
+ /* rem: r0 = old proc */
+ /* rem: r4 = return value */
+ /* rem: r6 = new process */
+ /* rem: r8 = old PCB */
+ /* rem: r9 = new PCB */
+ /* rem: interrupts are enabled */
+
+ /* What else needs to be saved Only FPA stuff when that is supported */
+
+ /* Third phase : restore saved context */
+
+ /* rem: r0 = old proc */
+ /* rem: r4 = return value */
+ /* rem: r6 = new proc */
+ /* rem: r8 = old PCB */
+ /* rem: r9 = new PCB */
+ /* rem: interrupts are enabled */
+
+ /*
+ * Get the new L1 table pointer into r11. If we're switching to
+ * an LWP with the same address space as the outgoing one, we can
+ * skip the cache purge and the TTB load.
+ *
+ * To avoid data dep stalls that would happen anyway, we try
+ * and get some useful work done in the mean time.
+ */
+ ldr r10, [r8, #(PCB_PAGEDIR)] /* r10 = old L1 */
+ ldr r11, [r9, #(PCB_PAGEDIR)] /* r11 = new L1 */
+
+ ldr r0, [r8, #(PCB_DACR)] /* r0 = old DACR */
+ ldr r1, [r9, #(PCB_DACR)] /* r1 = new DACR */
+ ldr r8, [r9, #(PCB_CSTATE)] /* r8 = &new_pmap->pm_cstate */
+ ldr r5, .Llast_cache_state_ptr /* Previous thread's cstate */
+
+ teq r10, r11 /* Same L1? */
+ ldr r5, [r5]
+ cmpeq r0, r1 /* Same DACR? */
+ beq .Lcs_context_switched /* yes! */
+
+ ldr r3, .Lblock_userspace_access
+ mov r12, #0
+ cmp r5, #0 /* No last vm? (switch_exit) */
+ beq .Lcs_cache_purge_skipped /* No, we can skip cache flsh */
+
+ mov r2, #DOMAIN_CLIENT
+ cmp r1, r2, lsl #(PMAP_DOMAIN_KERNEL * 2) /* Sw to kernel thread? */
+ beq .Lcs_cache_purge_skipped /* Yup. Don't flush cache */
+
+ cmp r5, r8 /* Same userland VM space? */
+ ldrneb r12, [r5, #(CS_CACHE_ID)] /* Last VM space cache state */
+
+ /*
+ * We're definately switching to a new userland VM space,
+ * and the previous userland VM space has yet to be flushed
+ * from the cache/tlb.
+ *
+ * r12 holds the previous VM space's cs_cache_id state
+ */
+ tst r12, #0xff /* Test cs_cache_id */
+ beq .Lcs_cache_purge_skipped /* VM space is not in cache */
+
+ /*
+ * Definately need to flush the cache.
+ * Mark the old VM space as NOT being resident in the cache.
+ */
+ mov r2, #0x00000000
+ strb r2, [r5, #(CS_CACHE_ID)]
+ strb r2, [r5, #(CS_CACHE_D)]
+
+ /*
+ * Don't allow user space access between the purge and the switch.
+ */
+ mov r2, #0x00000001
+ str r2, [r3]
+
+ stmfd sp!, {r0-r3}
+ ldr r1, .Lcpufuncs
+ mov lr, pc
+ ldr pc, [r1, #CF_IDCACHE_WBINV_ALL]
+ ldmfd sp!, {r0-r3}
+
+.Lcs_cache_purge_skipped:
+ /* rem: r1 = new DACR */
+ /* rem: r3 = &block_userspace_access */
+ /* rem: r4 = return value */
+ /* rem: r5 = &old_pmap->pm_cstate (or NULL) */
+ /* rem: r6 = new proc */
+ /* rem: r8 = &new_pmap->pm_cstate */
+ /* rem: r9 = new PCB */
+ /* rem: r10 = old L1 */
+ /* rem: r11 = new L1 */
+
+ mov r2, #0x00000000
+ ldr r7, [r9, #(PCB_PL1VEC)]
+
+ /*
+ * At this point we need to kill IRQ's again.
+ *
+ * XXXSCW: Don't need to block FIQs if vectors have been relocated
+ */
+ IRQdisableALL
+
+ /*
+ * Interrupts are disabled so we can allow user space accesses again
+ * as none will occur until interrupts are re-enabled after the
+ * switch.
+ */
+ str r2, [r3]
+
+ /*
+ * Ensure the vector table is accessible by fixing up the L1
+ */
+ cmp r7, #0 /* No need to fixup vector table? */
+ ldrne r2, [r7] /* But if yes, fetch current value */
+ ldrne r0, [r9, #(PCB_L1VEC)] /* Fetch new vector_page value */
+ mcr p15, 0, r1, c3, c0, 0 /* Update DACR for new context */
+ cmpne r2, r0 /* Stuffing the same value? */
+#ifndef PMAP_INCLUDE_PTE_SYNC
+ strne r0, [r7] /* Nope, update it */
+#else
+ beq .Lcs_same_vector
+ str r0, [r7] /* Otherwise, update it */
+
+ /*
+ * Need to sync the cache to make sure that last store is
+ * visible to the MMU.
+ */
+ ldr r2, .Lcpufuncs
+ mov r0, r7
+ mov r1, #4
+ mov lr, pc
+ ldr pc, [r2, #CF_DCACHE_WB_RANGE]
+
+.Lcs_same_vector:
+#endif /* PMAP_INCLUDE_PTE_SYNC */
+
+ cmp r10, r11 /* Switching to the same L1? */
+ ldr r10, .Lcpufuncs
+ beq .Lcs_same_l1 /* Yup. */
+
+ /*
+ * Do a full context switch, including full TLB flush.
+ */
+ mov r0, r11
+ mov lr, pc
+ ldr pc, [r10, #CF_CONTEXT_SWITCH]
+
+ /*
+ * Mark the old VM space as NOT being resident in the TLB
+ */
+ mov r2, #0x00000000
+ cmp r5, #0
+ strneh r2, [r5, #(CS_TLB_ID)]
+ b .Lcs_context_switched
+
+ /*
+ * We're switching to a different process in the same L1.
+ * In this situation, we only need to flush the TLB for the
+ * vector_page mapping, and even then only if r7 is non-NULL.
+ */
+.Lcs_same_l1:
+ cmp r7, #0
+ movne r0, #0 /* We *know* vector_page's VA is 0x0 */
+ movne lr, pc
+ ldrne pc, [r10, #CF_TLB_FLUSHID_SE]
+
+.Lcs_context_switched:
+ /* rem: r8 = &new_pmap->pm_cstate */
+
+ /* XXXSCW: Safe to re-enable FIQs here */
+
+ /*
+ * The new VM space is live in the cache and TLB.
+ * Update its cache/tlb state, and if it's not the kernel
+ * pmap, update the 'last cache state' pointer.
+ */
+ mov r2, #-1
+ ldr r5, .Lpmap_kernel_cstate
+ ldr r0, .Llast_cache_state_ptr
+ str r2, [r8, #(CS_ALL)]
+ cmp r5, r8
+ strne r8, [r0]
+
+ /* rem: r4 = return value */
+ /* rem: r6 = new proc */
+ /* rem: r9 = new PCB */
+
+ /*
+ * This can be optimised... We know we want to go from SVC32
+ * mode to UND32 mode
+ */
+ mrs r3, cpsr
+ bic r2, r3, #(PSR_MODE)
+ orr r2, r2, #(PSR_UND32_MODE)
+ msr cpsr_c, r2
+
+ ldr sp, [r9, #(PCB_UND_SP)]
+
+ msr cpsr_c, r3 /* Restore the old mode */
+
+ /* Restore all the save registers */
+#ifndef __XSCALE__
+ add r7, r9, #PCB_R8
+ ldmia r7, {r8-r13}
+
+ sub r7, r7, #PCB_R8 /* restore PCB pointer */
+#else
+ mov r7, r9
+ ldr r8, [r7, #(PCB_R8)]
+ ldr r9, [r7, #(PCB_R9)]
+ ldr r10, [r7, #(PCB_R10)]
+ ldr r11, [r7, #(PCB_R11)]
+ ldr r12, [r7, #(PCB_R12)]
+ ldr r13, [r7, #(PCB_SP)]
+#endif
+
+#if 0
+ ldr r5, [r6, #(L_PROC)] /* fetch the proc for below */
+#else
+ mov r5, r6
+#endif
+
+ /* rem: r4 = return value */
+ /* rem: r5 = new proc's proc */
+ /* rem: r6 = new proc */
+ /* rem: r7 = new pcb */
+
+#ifdef ARMFPE
+ add r0, r7, #(USER_SIZE) & 0x00ff
+ add r0, r0, #(USER_SIZE) & 0xff00
+ bl _C_LABEL(arm_fpe_core_changecontext)
+#endif
+
+ /* We can enable interrupts again */
+ IRQenableALL
+
+ /* rem: r4 = return value */
+ /* rem: r5 = new proc's proc */
+ /* rem: r6 = new proc */
+ /* rem: r7 = new PCB */
+
+#if 0
+ /*
+ * Check for restartable atomic sequences (RAS).
+ */
+
+ ldr r2, [r5, #(P_RASLIST)]
+ ldr r1, [r7, #(PCB_TF)] /* r1 = trapframe (used below) */
+ teq r2, #0 /* p->p_nras == 0? */
+ bne .Lswitch_do_ras /* no, check for one */
+#endif
+
+.Lswitch_return:
+ /* cpu_switch returns 1 == switched, 0 == didn't switch */
+ mov r0, r4
+
+ /*
+ * Pull the registers that got pushed when either savectx() or
+ * cpu_switch() was called and return.
+ */
+ ldmfd sp!, {r4-r7, pc}
+
+#if 0
+.Lswitch_do_ras:
+ ldr r1, [r1, #(TF_PC)] /* second ras_lookup() arg */
+ mov r0, r5 /* first ras_lookup() arg */
+ bl _C_LABEL(ras_lookup)
+ cmn r0, #1 /* -1 means "not in a RAS" */
+ ldrne r1, [r7, #(PCB_TF)]
+ strne r0, [r1, #(TF_PC)]
+ b .Lswitch_return
+#endif
+
+.Lswitch_exited:
+ /*
+ * We skip the cache purge because switch_exit() already did it.
+ * Load up registers the way .Lcs_cache_purge_skipped expects.
+ * Userpsace access already blocked by switch_exit().
+ */
+ ldr r9, [r6, #(P_ADDR)] /* r9 = new PCB */
+ ldr r3, .Lblock_userspace_access
+ mrc p15, 0, r10, c2, c0, 0 /* r10 = old L1 */
+ mov r5, #0 /* No previous cache state */
+ ldr r1, [r9, #(PCB_DACR)] /* r1 = new DACR */
+ ldr r8, [r9, #(PCB_CSTATE)] /* r8 = new cache state */
+ ldr r11, [r9, #(PCB_PAGEDIR)] /* r11 = new L1 */
+ b .Lcs_cache_purge_skipped
+
+
+#ifdef DIAGNOSTIC
+.Lswitch_bogons:
+ adr r0, .Lswitch_panic_str
+ bl _C_LABEL(panic)
+1: nop
+ b 1b
+
+.Lswitch_panic_str:
+ .asciz "cpu_switch: sched_qs empty with non-zero sched_whichqs!\n"
+#endif
+
+/*
+ * cpu_switchto(struct proc *current, struct proc *next)
+ * Switch to the specified next LWP
+ * Arguments:
+ *
+ * r0 'struct proc *' of the current LWP
+ * r1 'struct proc *' of the LWP to switch to
+ */
+ENTRY(cpu_switchto)
+ stmfd sp!, {r4-r7, lr}
+
+ mov r6, r1 /* save new proc */
+
+#if defined(LOCKDEBUG)
+ mov r5, r0 /* save old proc */
+ bl _C_LABEL(sched_unlock_idle)
+ mov r1, r5
+#else
+ mov r1, r0
+#endif
+
+ IRQdisable
+
+ /*
+ * Okay, set up registers the way cpu_switch() wants them,
+ * and jump into the middle of it (where we bring up the
+ * new process).
+ *
+ * r1 = old proc (r6 = new proc)
+ */
+ b .Lswitch_resume
+
+/*
+ * void switch_exit(struct proc *l, struct proc *l0,
+ * void (*exit)(struct proc *));
+ * Switch to proc0's saved context and deallocate the address space and kernel
+ * stack for l. Then jump into cpu_switch(), as if we were in proc0 all along.
+ */
+
+/* LINTSTUB: Func: void switch_exit(struct proc *l, struct proc *l0,
+ void (*func)(struct proc *)) */
+ENTRY(switch_exit)
+ /*
+ * The process is going away, so we can use callee-saved
+ * registers here without having to save them.
+ */
+
+ mov r4, r0
+ ldr r0, .Lcurproc
+
+ mov r5, r1
+ ldr r1, .Lblock_userspace_access
+
+ mov r6, r2
+
+ /*
+ * r4 = proc
+ * r5 = proc0
+ * r6 = exit func
+ */
+
+ mov r2, #0x00000000 /* curproc = NULL */
+ str r2, [r0]
+
+ /*
+ * We're about to clear both the cache and the TLB.
+ * Make sure to zap the 'last cache state' pointer since the
+ * pmap might be about to go away. Also ensure the outgoing
+ * VM space's cache state is marked as NOT resident in the
+ * cache, and that proc0's cache state IS resident.
+ */
+ ldr r7, [r4, #(P_ADDR)] /* r7 = old proc's PCB */
+ ldr r0, .Llast_cache_state_ptr /* Last userland cache state */
+ ldr r9, [r7, #(PCB_CSTATE)] /* Fetch cache state pointer */
+ ldr r3, [r5, #(P_ADDR)] /* r3 = proc0's PCB */
+ str r2, [r0] /* No previous cache state */
+ str r2, [r9, #(CS_ALL)] /* Zap old proc's cache state */
+ ldr r3, [r3, #(PCB_CSTATE)] /* proc0's cache state */
+ mov r2, #-1
+ str r2, [r3, #(CS_ALL)] /* proc0 is in da cache! */
+
+ /*
+ * Don't allow user space access between the purge and the switch.
+ */
+ mov r2, #0x00000001
+ str r2, [r1]
+
+ /* Switch to proc0 context */
+
+ ldr r9, .Lcpufuncs
+ mov lr, pc
+ ldr pc, [r9, #CF_IDCACHE_WBINV_ALL]
+
+ ldr r0, [r7, #(PCB_PL1VEC)]
+ ldr r1, [r7, #(PCB_DACR)]
+
+ /*
+ * r0 = Pointer to L1 slot for vector_page (or NULL)
+ * r1 = proc0's DACR
+ * r4 = proc we're switching from
+ * r5 = proc0
+ * r6 = exit func
+ * r7 = proc0's PCB
+ * r9 = cpufuncs
+ */
+
+ IRQdisableALL
+
+ /*
+ * Ensure the vector table is accessible by fixing up proc0's L1
+ */
+ cmp r0, #0 /* No need to fixup vector table? */
+ ldrne r3, [r0] /* But if yes, fetch current value */
+ ldrne r2, [r7, #(PCB_L1VEC)] /* Fetch new vector_page value */
+ mcr p15, 0, r1, c3, c0, 0 /* Update DACR for proc0's context */
+ cmpne r3, r2 /* Stuffing the same value? */
+ strne r2, [r0] /* Store if not. */
+
+#ifdef PMAP_INCLUDE_PTE_SYNC
+ /*
+ * Need to sync the cache to make sure that last store is
+ * visible to the MMU.
+ */
+ movne r1, #4
+ movne lr, pc
+ ldrne pc, [r9, #CF_DCACHE_WB_RANGE]
+#endif /* PMAP_INCLUDE_PTE_SYNC */
+
+ /*
+ * Note: We don't do the same optimisation as cpu_switch() with
+ * respect to avoiding flushing the TLB if we're switching to
+ * the same L1 since this process' VM space may be about to go
+ * away, so we don't want *any* turds left in the TLB.
+ */
+
+ /* Switch the memory to the new process */
+ ldr r0, [r7, #(PCB_PAGEDIR)]
+ mov lr, pc
+ ldr pc, [r9, #CF_CONTEXT_SWITCH]
+
+ ldr r0, .Lcurpcb
+
+ /* Restore all the save registers */
+#ifndef __XSCALE__
+ add r1, r7, #PCB_R8
+ ldmia r1, {r8-r13}
+#else
+ ldr r8, [r7, #(PCB_R8)]
+ ldr r9, [r7, #(PCB_R9)]
+ ldr r10, [r7, #(PCB_R10)]
+ ldr r11, [r7, #(PCB_R11)]
+ ldr r12, [r7, #(PCB_R12)]
+ ldr r13, [r7, #(PCB_SP)]
+#endif
+ str r7, [r0] /* curpcb = proc0's PCB */
+
+ IRQenableALL
+
+ /*
+ * Schedule the vmspace and stack to be freed.
+ */
+ mov r0, r4 /* {proc_}exit2(l) */
+ mov lr, pc
+ mov pc, r6
+
+#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ bl _C_LABEL(sched_lock_idle)
+#endif
+
+ ldr r7, .Lwhichqs /* r7 = &whichqs */
+ mov r5, #0x00000000 /* r5 = old proc = NULL */
+ b .Lswitch_search
+
+/* LINTSTUB: Func: void savectx(struct pcb *pcb) */
+ENTRY(savectx)
+ /*
+ * r0 = pcb
+ */
+
+ /* Push registers.*/
+ stmfd sp!, {r4-r7, lr}
+
+ /* Store all the registers in the process's pcb */
+#ifndef __XSCALE__
+ add r2, r0, #(PCB_R8)
+ stmia r2, {r8-r13}
+#else
+ strd r8, [r0, #(PCB_R8)]
+ strd r10, [r0, #(PCB_R10)]
+ strd r12, [r0, #(PCB_R12)]
+#endif
+
+ /* Pull the regs of the stack */
+ ldmfd sp!, {r4-r7, pc}
+
+ENTRY(proc_trampoline)
+#ifdef __NEWINTR
+ mov r0, #(IPL_NONE)
+ bl _C_LABEL(_spllower)
+#else /* ! __NEWINTR */
+ mov r0, #(_SPL_0)
+ bl _C_LABEL(splx)
+#endif /* __NEWINTR */
+
+#ifdef MULTIPROCESSOR
+ bl _C_LABEL(proc_trampoline_mp)
+#endif
+ mov r0, r5
+ mov r1, sp
+ mov lr, pc
+ mov pc, r4
+
+ /* Kill irq's */
+ mrs r0, cpsr
+ orr r0, r0, #(I32_bit)
+ msr cpsr_c, r0
+
+ PULLFRAME
+
+ movs pc, lr /* Exit */
+
+#ifndef __XSCALE__
+ .type .Lcpu_switch_ffs_table, _ASM_TYPE_OBJECT;
+.Lcpu_switch_ffs_table:
+/* same as ffs table but all nums are -1 from that */
+/* 0 1 2 3 4 5 6 7 */
+ .byte 0, 0, 1, 12, 2, 6, 0, 13 /* 0- 7 */
+ .byte 3, 0, 7, 0, 0, 0, 0, 14 /* 8-15 */
+ .byte 10, 4, 0, 0, 8, 0, 0, 25 /* 16-23 */
+ .byte 0, 0, 0, 0, 0, 21, 27, 15 /* 24-31 */
+ .byte 31, 11, 5, 0, 0, 0, 0, 0 /* 32-39 */
+ .byte 9, 0, 0, 24, 0, 0, 20, 26 /* 40-47 */
+ .byte 30, 0, 0, 0, 0, 23, 0, 19 /* 48-55 */
+ .byte 29, 0, 22, 18, 28, 17, 16, 0 /* 56-63 */
+#endif /* !__XSCALE_ */
diff --git a/sys/arch/arm/arm/db_disasm.c b/sys/arch/arm/arm/db_disasm.c
new file mode 100644
index 00000000000..071fab0d269
--- /dev/null
+++ b/sys/arch/arm/arm/db_disasm.c
@@ -0,0 +1,77 @@
+/* $OpenBSD: db_disasm.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: db_disasm.c,v 1.4 2003/07/15 00:24:38 lukem Exp $ */
+
+/*
+ * Copyright (c) 1996 Mark Brinicombe.
+ * Copyright (c) 1996 Brini.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <machine/db_machdep.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_output.h>
+#include <ddb/db_access.h>
+
+#include <arch/arm/arm/disassem.h>
+
+/* Glue code to interface db_disasm to the generic ARM disassembler */
+
+static db_expr_t db_disasm_read_word(db_expr_t);
+static void db_disasm_printaddr(db_expr_t);
+
+static const disasm_interface_t db_disasm_interface = {
+ db_disasm_read_word, db_disasm_printaddr, db_printf
+};
+
+static db_expr_t
+db_disasm_read_word(db_expr_t address)
+{
+
+ return db_get_value(address, 4, 0);
+}
+
+static void
+db_disasm_printaddr(db_expr_t address)
+{
+
+ db_printsym((db_addr_t)address, DB_STGY_ANY, db_printf);
+}
+
+vaddr_t
+db_disasm(vaddr_t loc, boolean_t altfmt)
+{
+
+ return disasm(&db_disasm_interface, loc, altfmt);
+}
+
+/* End of db_disasm.c */
diff --git a/sys/arch/arm/arm/db_interface.c b/sys/arch/arm/arm/db_interface.c
new file mode 100644
index 00000000000..3580ca72658
--- /dev/null
+++ b/sys/arch/arm/arm/db_interface.c
@@ -0,0 +1,476 @@
+/* $OpenBSD: db_interface.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: db_interface.c,v 1.34 2003/10/26 23:11:15 chris Exp $^I*/$
+
+/*
+ * Copyright (c) 1996 Scott K. Stevens
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ *
+ * From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
+ */
+
+/*
+ * Interface to new debugger.
+ */
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+#include <sys/systm.h> /* just for boothowto */
+#include <sys/exec.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <arm/db_machdep.h>
+#include <arm/katelib.h>
+#include <arm/undefined.h>
+#include <ddb/db_access.h>
+#include <ddb/db_command.h>
+#include <ddb/db_output.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_interface.h>
+#include <dev/cons.h>
+
+static long nil;
+
+int db_access_und_sp (struct db_variable *, db_expr_t *, int);
+int db_access_abt_sp (struct db_variable *, db_expr_t *, int);
+int db_access_irq_sp (struct db_variable *, db_expr_t *, int);
+u_int db_fetch_reg (int, db_regs_t *);
+
+int db_trapper (u_int, u_int, trapframe_t *, int);
+
+struct db_variable db_regs[] = {
+ { "spsr", (long *)&DDB_REGS->tf_spsr, FCN_NULL, },
+ { "r0", (long *)&DDB_REGS->tf_r0, FCN_NULL, },
+ { "r1", (long *)&DDB_REGS->tf_r1, FCN_NULL, },
+ { "r2", (long *)&DDB_REGS->tf_r2, FCN_NULL, },
+ { "r3", (long *)&DDB_REGS->tf_r3, FCN_NULL, },
+ { "r4", (long *)&DDB_REGS->tf_r4, FCN_NULL, },
+ { "r5", (long *)&DDB_REGS->tf_r5, FCN_NULL, },
+ { "r6", (long *)&DDB_REGS->tf_r6, FCN_NULL, },
+ { "r7", (long *)&DDB_REGS->tf_r7, FCN_NULL, },
+ { "r8", (long *)&DDB_REGS->tf_r8, FCN_NULL, },
+ { "r9", (long *)&DDB_REGS->tf_r9, FCN_NULL, },
+ { "r10", (long *)&DDB_REGS->tf_r10, FCN_NULL, },
+ { "r11", (long *)&DDB_REGS->tf_r11, FCN_NULL, },
+ { "r12", (long *)&DDB_REGS->tf_r12, FCN_NULL, },
+ { "usr_sp", (long *)&DDB_REGS->tf_usr_sp, FCN_NULL, },
+ { "usr_lr", (long *)&DDB_REGS->tf_usr_lr, FCN_NULL, },
+ { "svc_sp", (long *)&DDB_REGS->tf_svc_sp, FCN_NULL, },
+ { "svc_lr", (long *)&DDB_REGS->tf_svc_lr, FCN_NULL, },
+ { "pc", (long *)&DDB_REGS->tf_pc, FCN_NULL, },
+ { "und_sp", (long *)&nil, db_access_und_sp, },
+ { "abt_sp", (long *)&nil, db_access_abt_sp, },
+ { "irq_sp", (long *)&nil, db_access_irq_sp, },
+};
+
+extern label_t *db_recover;
+
+struct db_variable * db_eregs = db_regs + sizeof(db_regs)/sizeof(db_regs[0]);
+
+int db_active = 0;
+
+int
+db_access_und_sp(struct db_variable *vp, db_expr_t *valp, int rw)
+{
+
+ if (rw == DB_VAR_GET)
+ *valp = get_stackptr(PSR_UND32_MODE);
+ return(0);
+}
+
+int
+db_access_abt_sp(struct db_variable *vp, db_expr_t *valp, int rw)
+{
+
+ if (rw == DB_VAR_GET)
+ *valp = get_stackptr(PSR_ABT32_MODE);
+ return(0);
+}
+
+int
+db_access_irq_sp(struct db_variable *vp, db_expr_t *valp, int rw)
+{
+
+ if (rw == DB_VAR_GET)
+ *valp = get_stackptr(PSR_IRQ32_MODE);
+ return(0);
+}
+
+#ifdef DDB
+/*
+ * kdb_trap - field a TRACE or BPT trap
+ */
+int
+kdb_trap(int type, db_regs_t *regs)
+{
+ int s;
+
+ switch (type) {
+ case T_BREAKPOINT: /* breakpoint */
+ case -1: /* keyboard interrupt */
+ break;
+ default:
+ if (db_recover != 0) {
+ /* This will longjmp back into db_command_loop() */
+ db_error("Faulted in DDB; continuing...\n");
+ /*NOTREACHED*/
+ }
+ }
+
+ /* Should switch to kdb`s own stack here. */
+
+ ddb_regs = *regs;
+
+ s = splhigh();
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, 0/*code*/);
+ cnpollc(FALSE);
+ db_active--;
+ splx(s);
+
+ *regs = ddb_regs;
+
+ return (1);
+}
+#endif
+
+
+static int db_validate_address(vaddr_t addr);
+
+static int
+db_validate_address(vaddr_t addr)
+{
+ struct proc *p = curproc;
+ struct pmap *pmap;
+
+ if (!p || !p->p_vmspace || !p->p_vmspace->vm_map.pmap ||
+#ifndef ARM32_NEW_VM_LAYOUT
+ addr >= VM_MAXUSER_ADDRESS
+#else
+ addr >= VM_MIN_KERNEL_ADDRESS
+#endif
+ )
+ pmap = pmap_kernel();
+ else
+ pmap = p->p_vmspace->vm_map.pmap;
+
+ return (pmap_extract(pmap, addr, NULL) == FALSE);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+void
+db_read_bytes(addr, size, data)
+ vaddr_t addr;
+ size_t size;
+ char *data;
+{
+ char *src = (char *)addr;
+
+ if (db_validate_address((u_int)src)) {
+ db_printf("address %p is invalid\n", src);
+ return;
+ }
+
+ if (size == 4 && (addr & 3) == 0 && ((u_int32_t)data & 3) == 0) {
+ *((int*)data) = *((int*)src);
+ return;
+ }
+
+ if (size == 2 && (addr & 1) == 0 && ((u_int32_t)data & 1) == 0) {
+ *((short*)data) = *((short*)src);
+ return;
+ }
+
+ while (size-- > 0) {
+ if (db_validate_address((u_int)src)) {
+ db_printf("address %p is invalid\n", src);
+ return;
+ }
+ *data++ = *src++;
+ }
+}
+
+static void
+db_write_text(vaddr_t addr, size_t size, char *data)
+{
+ struct pmap *pmap = pmap_kernel();
+ pd_entry_t *pde, oldpde, tmppde;
+ pt_entry_t *pte, oldpte, tmppte;
+ vaddr_t pgva;
+ size_t limit, savesize;
+ char *dst;
+
+ /* XXX: gcc */
+ oldpte = 0;
+
+ if ((savesize = size) == 0)
+ return;
+
+ dst = (char *) addr;
+
+ do {
+ /* Get the PDE of the current VA. */
+ if (pmap_get_pde_pte(pmap, (vaddr_t) dst, &pde, &pte) == FALSE)
+ goto no_mapping;
+ switch ((oldpde = *pde) & L1_TYPE_MASK) {
+ case L1_TYPE_S:
+ pgva = (vaddr_t)dst & L1_S_FRAME;
+ limit = L1_S_SIZE - ((vaddr_t)dst & L1_S_OFFSET);
+
+ tmppde = oldpde | L1_S_PROT_W;
+ *pde = tmppde;
+ PTE_SYNC(pde);
+ break;
+
+ case L1_TYPE_C:
+ pgva = (vaddr_t)dst & L2_S_FRAME;
+ limit = L2_S_SIZE - ((vaddr_t)dst & L2_S_OFFSET);
+
+ if (pte == NULL)
+ goto no_mapping;
+ oldpte = *pte;
+ tmppte = oldpte | L2_S_PROT_W;
+ *pte = tmppte;
+ PTE_SYNC(pte);
+ break;
+
+ default:
+ no_mapping:
+ printf(" address 0x%08lx not a valid page\n",
+ (vaddr_t) dst);
+ return;
+ }
+ cpu_tlb_flushD_SE(pgva);
+ cpu_cpwait();
+
+ if (limit > size)
+ limit = size;
+ size -= limit;
+
+ /*
+ * Page is now writable. Do as much access as we
+ * can in this page.
+ */
+ for (; limit > 0; limit--)
+ *dst++ = *data++;
+
+ /*
+ * Restore old mapping permissions.
+ */
+ switch (oldpde & L1_TYPE_MASK) {
+ case L1_TYPE_S:
+ *pde = oldpde;
+ PTE_SYNC(pde);
+ break;
+
+ case L1_TYPE_C:
+ *pte = oldpte;
+ PTE_SYNC(pte);
+ break;
+ }
+ cpu_tlb_flushD_SE(pgva);
+ cpu_cpwait();
+
+ } while (size != 0);
+
+ /* Sync the I-cache. */
+ cpu_icache_sync_range(addr, savesize);
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ */
+void
+db_write_bytes(vaddr_t addr, size_t size, char *data)
+{
+ extern char etext[];
+ extern char kernel_text[];
+ char *dst;
+ size_t loop;
+
+ /* If any part is in kernel text, use db_write_text() */
+ if (addr >= (vaddr_t) kernel_text && addr < (vaddr_t) etext) {
+ db_write_text(addr, size, data);
+ return;
+ }
+
+ dst = (char *)addr;
+ loop = size;
+ while (loop-- > 0) {
+ if (db_validate_address((u_int)dst)) {
+ db_printf("address %p is invalid\n", dst);
+ return;
+ }
+ *dst++ = *data++;
+ }
+ /* make sure the caches and memory are in sync */
+ cpu_icache_sync_range(addr, size);
+
+ /* In case the current page tables have been modified ... */
+ cpu_tlb_flushID();
+ cpu_cpwait();
+}
+
+void
+Debugger(void)
+{
+ asm(".word 0xe7ffffff");
+}
+
+const struct db_command db_machine_command_table[] = {
+ { "frame", db_show_frame_cmd, 0, NULL },
+ { "panic", db_show_panic_cmd, 0, NULL },
+#ifdef ARM32_DB_COMMANDS
+ ARM32_DB_COMMANDS,
+#endif
+ { NULL, NULL, 0, NULL }
+};
+
+int
+db_trapper(u_int addr, u_int inst, trapframe_t *frame, int fault_code)
+{
+
+ if (fault_code == 0) {
+ if ((inst & ~INSN_COND_MASK) == (BKPT_INST & ~INSN_COND_MASK)) {
+ kdb_trap(T_BREAKPOINT, frame);
+ frame->tf_pc += INSN_SIZE;
+ } else
+ kdb_trap(-1, frame);
+ } else
+ return (1);
+ return (0);
+}
+
+extern u_int esym;
+extern u_int end;
+
+static struct undefined_handler db_uh;
+
+void
+db_machine_init(void)
+{
+ /*
+ * We get called before malloc() is available, so supply a static
+ * struct undefined_handler.
+ */
+ db_uh.uh_handler = db_trapper;
+ install_coproc_handler_static(0, &db_uh);
+}
+
+u_int
+db_fetch_reg(int reg, db_regs_t *db_regs)
+{
+
+ switch (reg) {
+ case 0:
+ return (db_regs->tf_r0);
+ case 1:
+ return (db_regs->tf_r1);
+ case 2:
+ return (db_regs->tf_r2);
+ case 3:
+ return (db_regs->tf_r3);
+ case 4:
+ return (db_regs->tf_r4);
+ case 5:
+ return (db_regs->tf_r5);
+ case 6:
+ return (db_regs->tf_r6);
+ case 7:
+ return (db_regs->tf_r7);
+ case 8:
+ return (db_regs->tf_r8);
+ case 9:
+ return (db_regs->tf_r9);
+ case 10:
+ return (db_regs->tf_r10);
+ case 11:
+ return (db_regs->tf_r11);
+ case 12:
+ return (db_regs->tf_r12);
+ case 13:
+ return (db_regs->tf_svc_sp);
+ case 14:
+ return (db_regs->tf_svc_lr);
+ case 15:
+ return (db_regs->tf_pc);
+ default:
+ panic("db_fetch_reg: botch");
+ }
+}
+
+db_addr_t
+db_branch_taken(u_int insn, db_addr_t pc, db_regs_t *db_regs)
+{
+ u_int addr, nregs;
+
+ switch ((insn >> 24) & 0xf) {
+ case 0xa: /* b ... */
+ case 0xb: /* bl ... */
+ addr = ((insn << 2) & 0x03ffffff);
+ if (addr & 0x02000000)
+ addr |= 0xfc000000;
+ return (pc + 8 + addr);
+ case 0x7: /* ldr pc, [pc, reg, lsl #2] */
+ addr = db_fetch_reg(insn & 0xf, db_regs);
+ addr = pc + 8 + (addr << 2);
+ db_read_bytes(addr, 4, (char *)&addr);
+ return (addr);
+ case 0x1: /* mov pc, reg */
+ addr = db_fetch_reg(insn & 0xf, db_regs);
+ return (addr);
+ case 0x8: /* ldmxx reg, {..., pc} */
+ case 0x9:
+ addr = db_fetch_reg((insn >> 16) & 0xf, db_regs);
+ nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555);
+ nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333);
+ nregs = (nregs + (nregs >> 4)) & 0x0f0f;
+ nregs = (nregs + (nregs >> 8)) & 0x001f;
+ switch ((insn >> 23) & 0x3) {
+ case 0x0: /* ldmda */
+ addr = addr - 0;
+ break;
+ case 0x1: /* ldmia */
+ addr = addr + 0 + ((nregs - 1) << 2);
+ break;
+ case 0x2: /* ldmdb */
+ addr = addr - 4;
+ break;
+ case 0x3: /* ldmib */
+ addr = addr + 4 + ((nregs - 1) << 2);
+ break;
+ }
+ db_read_bytes(addr, 4, (char *)&addr);
+ return (addr);
+ default:
+ panic("branch_taken: botch");
+ }
+}
diff --git a/sys/arch/arm/arm/db_machdep.c b/sys/arch/arm/arm/db_machdep.c
new file mode 100644
index 00000000000..781ea3c387d
--- /dev/null
+++ b/sys/arch/arm/arm/db_machdep.c
@@ -0,0 +1,88 @@
+/* $OpenBSD: db_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: db_machdep.c,v 1.8 2003/07/15 00:24:41 lukem Exp $^I*/$
+
+/*
+ * Copyright (c) 1996 Mark Brinicombe
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/systm.h>
+
+#include <arm/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_output.h>
+
+
+void
+db_show_panic_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ int s;
+
+ s = splhigh();
+
+ db_printf("Panic string: %s\n", panicstr);
+
+ (void)splx(s);
+}
+
+
+void
+db_show_frame_cmd(addr, have_addr, count, modif)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+{
+ struct trapframe *frame;
+
+ if (!have_addr) {
+ db_printf("frame address must be specified\n");
+ return;
+ }
+
+ frame = (struct trapframe *)addr;
+
+ db_printf("frame address = %08x ", (u_int)frame);
+ db_printf("spsr=%08x\n", frame->tf_spsr);
+ db_printf("r0 =%08x r1 =%08x r2 =%08x r3 =%08x\n",
+ frame->tf_r0, frame->tf_r1, frame->tf_r2, frame->tf_r3);
+ db_printf("r4 =%08x r5 =%08x r6 =%08x r7 =%08x\n",
+ frame->tf_r4, frame->tf_r5, frame->tf_r6, frame->tf_r7);
+ db_printf("r8 =%08x r9 =%08x r10=%08x r11=%08x\n",
+ frame->tf_r8, frame->tf_r9, frame->tf_r10, frame->tf_r11);
+ db_printf("r12=%08x r13=%08x r14=%08x r15=%08x\n",
+ frame->tf_r12, frame->tf_usr_sp, frame->tf_usr_lr, frame->tf_pc);
+ db_printf("slr=%08x\n", frame->tf_svc_lr);
+}
diff --git a/sys/arch/arm/arm/db_trace.c b/sys/arch/arm/arm/db_trace.c
new file mode 100644
index 00000000000..e43d464ee19
--- /dev/null
+++ b/sys/arch/arm/arm/db_trace.c
@@ -0,0 +1,208 @@
+/* $OpenBSD: db_trace.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2000, 2001 Ben Harris
+ * Copyright (c) 1996 Scott K. Stevens
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <arm/armreg.h>
+#include <arm/cpufunc.h>
+#include <machine/db_machdep.h>
+
+#include <ddb/db_access.h>
+#include <ddb/db_interface.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_output.h>
+
+db_regs_t ddb_regs;
+
+#define INKERNEL(va) (((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS)
+
+/*
+ * APCS stack frames are awkward beasts, so I don't think even trying to use
+ * a structure to represent them is a good idea.
+ *
+ * Here's the diagram from the APCS. Increasing address is _up_ the page.
+ *
+ * save code pointer [fp] <- fp points to here
+ * return link value [fp, #-4]
+ * return sp value [fp, #-8]
+ * return fp value [fp, #-12]
+ * [saved v7 value]
+ * [saved v6 value]
+ * [saved v5 value]
+ * [saved v4 value]
+ * [saved v3 value]
+ * [saved v2 value]
+ * [saved v1 value]
+ * [saved a4 value]
+ * [saved a3 value]
+ * [saved a2 value]
+ * [saved a1 value]
+ *
+ * The save code pointer points twelve bytes beyond the start of the
+ * code sequence (usually a single STM) that created the stack frame.
+ * We have to disassemble it if we want to know which of the optional
+ * fields are actually present.
+ */
+
+#define FR_SCP (0)
+#define FR_RLV (-1)
+#define FR_RSP (-2)
+#define FR_RFP (-3)
+
+void
+db_stack_trace_print(addr, have_addr, count, modif, pr)
+ db_expr_t addr;
+ int have_addr;
+ db_expr_t count;
+ char *modif;
+ int (*pr) __P((const char *, ...));
+{
+ u_int32_t *frame, *lastframe;
+ char c, *cp = modif;
+ boolean_t kernel_only = TRUE;
+ boolean_t trace_thread = FALSE;
+ int scp_offset;
+
+ while ((c = *cp++) != 0) {
+ if (c == 'u')
+ kernel_only = FALSE;
+ if (c == 't')
+ trace_thread = TRUE;
+ }
+
+ if (!have_addr)
+ frame = (u_int32_t *)(DDB_REGS->tf_r11);
+ else {
+ if (trace_thread) {
+ struct proc *p;
+ struct user *u;
+ (*pr) ("trace: pid %d ", (int)addr);
+ p = pfind(addr);
+ if (p == NULL) {
+ (*pr)("not found\n");
+ return;
+ }
+ if (!(p->p_flag & P_INMEM)) {
+ (*pr)("swapped out\n");
+ return;
+ }
+ u = p->p_addr;
+#ifdef acorn26
+ frame = (u_int32_t *)(u->u_pcb.pcb_sf->sf_r11);
+#else
+ frame = (u_int32_t *)(u->u_pcb.pcb_un.un_32.pcb32_r11);
+#endif
+ (*pr)("at %p\n", frame);
+ } else
+ frame = (u_int32_t *)(addr);
+ }
+ lastframe = NULL;
+ scp_offset = -(get_pc_str_offset() >> 2);
+
+ while (count-- && frame != NULL) {
+ db_addr_t scp;
+ u_int32_t savecode;
+ int r;
+ u_int32_t *rp;
+ const char *sep;
+
+ /*
+ * In theory, the SCP isn't guaranteed to be in the function
+ * that generated the stack frame. We hope for the best.
+ */
+#ifdef __PROG26
+ scp = frame[FR_SCP] & R15_PC;
+#else
+ scp = frame[FR_SCP];
+#endif
+
+ db_printsym(scp, DB_STGY_PROC, pr);
+ (*pr)("\n\t");
+#ifdef __PROG26
+ (*pr)("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC);
+ db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC, pr);
+ (*pr)(")\n");
+#else
+ (*pr)("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]);
+ db_printsym(frame[FR_RLV], DB_STGY_PROC, pr);
+ (*pr)(")\n");
+#endif
+ (*pr)("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]);
+
+ savecode = ((u_int32_t *)scp)[scp_offset];
+ if ((savecode & 0x0e100000) == 0x08000000) {
+ /* Looks like an STM */
+ rp = frame - 4;
+ sep = "\n\t";
+ for (r = 10; r >= 0; r--) {
+ if (savecode & (1 << r)) {
+ (*pr)("%sr%d=0x%08x",
+ sep, r, *rp--);
+ sep = (frame - rp) % 4 == 2 ?
+ "\n\t" : " ";
+ }
+ }
+ }
+
+ (*pr)("\n");
+
+ /*
+ * Switch to next frame up
+ */
+ if (frame[FR_RFP] == 0)
+ break; /* Top of stack */
+
+ lastframe = frame;
+ frame = (u_int32_t *)(frame[FR_RFP]);
+
+ if (INKERNEL((int)frame)) {
+ /* staying in kernel */
+ if (frame <= lastframe) {
+ (*pr)("Bad frame pointer: %p\n", frame);
+ break;
+ }
+ } else if (INKERNEL((int)lastframe)) {
+ /* switch from user to kernel */
+ if (kernel_only)
+ break; /* kernel stack only */
+ } else {
+ /* in user */
+ if (frame <= lastframe) {
+ (*pr)("Bad user frame pointer: %p\n",
+ frame);
+ break;
+ }
+ }
+ }
+}
diff --git a/sys/arch/arm/arm/disassem.c b/sys/arch/arm/arm/disassem.c
new file mode 100644
index 00000000000..14a3d54ac94
--- /dev/null
+++ b/sys/arch/arm/arm/disassem.c
@@ -0,0 +1,682 @@
+/* $OpenBSD: disassem.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: disassem.c,v 1.14 2003/03/27 16:58:36 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1996 Mark Brinicombe.
+ * Copyright (c) 1996 Brini.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * db_disasm.c
+ *
+ * Kernel disassembler
+ *
+ * Created : 10/02/96
+ *
+ * Structured after the sparc/sparc/db_disasm.c by David S. Miller &
+ * Paul Kranenburg
+ *
+ * This code is not complete. Not all instructions are disassembled.
+ */
+
+#include <sys/param.h>
+
+#include <sys/systm.h>
+#include <machine/db_machdep.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_variables.h>
+#include <ddb/db_interface.h>
+#include <arch/arm/arm/disassem.h>
+
+/*
+ * General instruction format
+ *
+ * insn[cc][mod] [operands]
+ *
+ * Those fields with an uppercase format code indicate that the field
+ * follows directly after the instruction before the separator i.e.
+ * they modify the instruction rather than just being an operand to
+ * the instruction. The only exception is the writeback flag which
+ * follows a operand.
+ *
+ *
+ * 2 - print Operand 2 of a data processing instruction
+ * d - destination register (bits 12-15)
+ * n - n register (bits 16-19)
+ * s - s register (bits 8-11)
+ * o - indirect register rn (bits 16-19) (used by swap)
+ * m - m register (bits 0-3)
+ * a - address operand of ldr/str instruction
+ * l - register list for ldm/stm instruction
+ * f - 1st fp operand (register) (bits 12-14)
+ * g - 2nd fp operand (register) (bits 16-18)
+ * h - 3rd fp operand (register/immediate) (bits 0-4)
+ * b - branch address
+ * t - thumb branch address (bits 24, 0-23)
+ * k - breakpoint comment (bits 0-3, 8-19)
+ * X - block transfer type
+ * Y - block transfer type (r13 base)
+ * c - comment field bits(0-23)
+ * p - saved or current status register
+ * F - PSR transfer fields
+ * D - destination-is-r15 (P) flag on TST, TEQ, CMP, CMN
+ * L - co-processor transfer size
+ * S - set status flag
+ * P - fp precision
+ * Q - fp precision (for ldf/stf)
+ * R - fp rounding
+ * v - co-processor data transfer registers + addressing mode
+ * W - writeback flag
+ * x - instruction in hex
+ * # - co-processor number
+ * y - co-processor data processing registers
+ * z - co-processor register transfer registers
+ */
+
+struct arm32_insn {
+ u_int mask;
+ u_int pattern;
+ char* name;
+ char* format;
+};
+
+static const struct arm32_insn arm32_i[] = {
+ { 0x0fffffff, 0x0ff00000, "imb", "c" }, /* Before swi */
+ { 0x0fffffff, 0x0ff00001, "imbrange", "c" }, /* Before swi */
+ { 0x0f000000, 0x0f000000, "swi", "c" },
+ { 0xfe000000, 0xfa000000, "blx", "t" }, /* Before b and bl */
+ { 0x0f000000, 0x0a000000, "b", "b" },
+ { 0x0f000000, 0x0b000000, "bl", "b" },
+ { 0x0fe000f0, 0x00000090, "mul", "Snms" },
+ { 0x0fe000f0, 0x00200090, "mla", "Snmsd" },
+ { 0x0fe000f0, 0x00800090, "umull", "Sdnms" },
+ { 0x0fe000f0, 0x00c00090, "smull", "Sdnms" },
+ { 0x0fe000f0, 0x00a00090, "umlal", "Sdnms" },
+ { 0x0fe000f0, 0x00e00090, "smlal", "Sdnms" },
+ { 0x0d700000, 0x04200000, "strt", "daW" },
+ { 0x0d700000, 0x04300000, "ldrt", "daW" },
+ { 0x0d700000, 0x04600000, "strbt", "daW" },
+ { 0x0d700000, 0x04700000, "ldrbt", "daW" },
+ { 0x0c500000, 0x04000000, "str", "daW" },
+ { 0x0c500000, 0x04100000, "ldr", "daW" },
+ { 0x0c500000, 0x04400000, "strb", "daW" },
+ { 0x0c500000, 0x04500000, "ldrb", "daW" },
+ { 0x0e1f0000, 0x080d0000, "stm", "YnWl" },/* separate out r13 base */
+ { 0x0e1f0000, 0x081d0000, "ldm", "YnWl" },/* separate out r13 base */
+ { 0x0e100000, 0x08000000, "stm", "XnWl" },
+ { 0x0e100000, 0x08100000, "ldm", "XnWl" },
+ { 0x0e1000f0, 0x00100090, "ldrb", "de" },
+ { 0x0e1000f0, 0x00000090, "strb", "de" },
+ { 0x0e1000f0, 0x001000d0, "ldrsb", "de" },
+ { 0x0e1000f0, 0x001000b0, "ldrh", "de" },
+ { 0x0e1000f0, 0x000000b0, "strh", "de" },
+ { 0x0e1000f0, 0x001000f0, "ldrsh", "de" },
+ { 0x0f200090, 0x00200090, "und", "x" }, /* Before data processing */
+ { 0x0e1000d0, 0x000000d0, "und", "x" }, /* Before data processing */
+ { 0x0ff00ff0, 0x01000090, "swp", "dmo" },
+ { 0x0ff00ff0, 0x01400090, "swpb", "dmo" },
+ { 0x0fbf0fff, 0x010f0000, "mrs", "dp" }, /* Before data processing */
+ { 0x0fb0fff0, 0x0120f000, "msr", "pFm" },/* Before data processing */
+ { 0x0fb0f000, 0x0320f000, "msr", "pF2" },/* Before data processing */
+ { 0x0ffffff0, 0x012fff10, "bx", "m" },
+ { 0x0fff0ff0, 0x016f0f10, "clz", "dm" },
+ { 0x0ffffff0, 0x012fff30, "blx", "m" },
+ { 0xfff000f0, 0xe1200070, "bkpt", "k" },
+ { 0x0de00000, 0x00000000, "and", "Sdn2" },
+ { 0x0de00000, 0x00200000, "eor", "Sdn2" },
+ { 0x0de00000, 0x00400000, "sub", "Sdn2" },
+ { 0x0de00000, 0x00600000, "rsb", "Sdn2" },
+ { 0x0de00000, 0x00800000, "add", "Sdn2" },
+ { 0x0de00000, 0x00a00000, "adc", "Sdn2" },
+ { 0x0de00000, 0x00c00000, "sbc", "Sdn2" },
+ { 0x0de00000, 0x00e00000, "rsc", "Sdn2" },
+ { 0x0df00000, 0x01100000, "tst", "Dn2" },
+ { 0x0df00000, 0x01300000, "teq", "Dn2" },
+ { 0x0de00000, 0x01400000, "cmp", "Dn2" },
+ { 0x0de00000, 0x01600000, "cmn", "Dn2" },
+ { 0x0de00000, 0x01800000, "orr", "Sdn2" },
+ { 0x0de00000, 0x01a00000, "mov", "Sd2" },
+ { 0x0de00000, 0x01c00000, "bic", "Sdn2" },
+ { 0x0de00000, 0x01e00000, "mvn", "Sd2" },
+ { 0x0ff08f10, 0x0e000100, "adf", "PRfgh" },
+ { 0x0ff08f10, 0x0e100100, "muf", "PRfgh" },
+ { 0x0ff08f10, 0x0e200100, "suf", "PRfgh" },
+ { 0x0ff08f10, 0x0e300100, "rsf", "PRfgh" },
+ { 0x0ff08f10, 0x0e400100, "dvf", "PRfgh" },
+ { 0x0ff08f10, 0x0e500100, "rdf", "PRfgh" },
+ { 0x0ff08f10, 0x0e600100, "pow", "PRfgh" },
+ { 0x0ff08f10, 0x0e700100, "rpw", "PRfgh" },
+ { 0x0ff08f10, 0x0e800100, "rmf", "PRfgh" },
+ { 0x0ff08f10, 0x0e900100, "fml", "PRfgh" },
+ { 0x0ff08f10, 0x0ea00100, "fdv", "PRfgh" },
+ { 0x0ff08f10, 0x0eb00100, "frd", "PRfgh" },
+ { 0x0ff08f10, 0x0ec00100, "pol", "PRfgh" },
+ { 0x0f008f10, 0x0e000100, "fpbop", "PRfgh" },
+ { 0x0ff08f10, 0x0e008100, "mvf", "PRfh" },
+ { 0x0ff08f10, 0x0e108100, "mnf", "PRfh" },
+ { 0x0ff08f10, 0x0e208100, "abs", "PRfh" },
+ { 0x0ff08f10, 0x0e308100, "rnd", "PRfh" },
+ { 0x0ff08f10, 0x0e408100, "sqt", "PRfh" },
+ { 0x0ff08f10, 0x0e508100, "log", "PRfh" },
+ { 0x0ff08f10, 0x0e608100, "lgn", "PRfh" },
+ { 0x0ff08f10, 0x0e708100, "exp", "PRfh" },
+ { 0x0ff08f10, 0x0e808100, "sin", "PRfh" },
+ { 0x0ff08f10, 0x0e908100, "cos", "PRfh" },
+ { 0x0ff08f10, 0x0ea08100, "tan", "PRfh" },
+ { 0x0ff08f10, 0x0eb08100, "asn", "PRfh" },
+ { 0x0ff08f10, 0x0ec08100, "acs", "PRfh" },
+ { 0x0ff08f10, 0x0ed08100, "atn", "PRfh" },
+ { 0x0f008f10, 0x0e008100, "fpuop", "PRfh" },
+ { 0x0e100f00, 0x0c000100, "stf", "QLv" },
+ { 0x0e100f00, 0x0c100100, "ldf", "QLv" },
+ { 0x0ff00f10, 0x0e000110, "flt", "PRgd" },
+ { 0x0ff00f10, 0x0e100110, "fix", "PRdh" },
+ { 0x0ff00f10, 0x0e200110, "wfs", "d" },
+ { 0x0ff00f10, 0x0e300110, "rfs", "d" },
+ { 0x0ff00f10, 0x0e400110, "wfc", "d" },
+ { 0x0ff00f10, 0x0e500110, "rfc", "d" },
+ { 0x0ff0ff10, 0x0e90f110, "cmf", "PRgh" },
+ { 0x0ff0ff10, 0x0eb0f110, "cnf", "PRgh" },
+ { 0x0ff0ff10, 0x0ed0f110, "cmfe", "PRgh" },
+ { 0x0ff0ff10, 0x0ef0f110, "cnfe", "PRgh" },
+ { 0xff100010, 0xfe000010, "mcr2", "#z" },
+ { 0x0f100010, 0x0e000010, "mcr", "#z" },
+ { 0xff100010, 0xfe100010, "mrc2", "#z" },
+ { 0x0f100010, 0x0e100010, "mrc", "#z" },
+ { 0xff000010, 0xfe000000, "cdp2", "#y" },
+ { 0x0f000010, 0x0e000000, "cdp", "#y" },
+ { 0xfe100090, 0xfc100000, "ldc2", "L#v" },
+ { 0x0e100090, 0x0c100000, "ldc", "L#v" },
+ { 0xfe100090, 0xfc000000, "stc2", "L#v" },
+ { 0x0e100090, 0x0c000000, "stc", "L#v" },
+ { 0x00000000, 0x00000000, NULL, NULL }
+};
+
+static char const arm32_insn_conditions[][4] = {
+ "eq", "ne", "cs", "cc",
+ "mi", "pl", "vs", "vc",
+ "hi", "ls", "ge", "lt",
+ "gt", "le", "", "nv"
+};
+
+static char const insn_block_transfers[][4] = {
+ "da", "ia", "db", "ib"
+};
+
+static char const insn_stack_block_transfers[][4] = {
+ "ed", "ea", "fd", "fa"
+};
+
+static char const op_shifts[][4] = {
+ "lsl", "lsr", "asr", "ror"
+};
+
+static char const insn_fpa_rounding[][2] = {
+ "", "p", "m", "z"
+};
+
+static char const insn_fpa_precision[][2] = {
+ "s", "d", "e", "p"
+};
+
+static char const insn_fpaconstants[][8] = {
+ "0.0", "1.0", "2.0", "3.0",
+ "4.0", "5.0", "0.5", "10.0"
+};
+
+#define insn_condition(x) arm32_insn_conditions[(x >> 28) & 0x0f]
+#define insn_blktrans(x) insn_block_transfers[(x >> 23) & 3]
+#define insn_stkblktrans(x) insn_stack_block_transfers[(x >> 23) & 3]
+#define op2_shift(x) op_shifts[(x >> 5) & 3]
+#define insn_fparnd(x) insn_fpa_rounding[(x >> 5) & 0x03]
+#define insn_fpaprec(x) insn_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 1]
+#define insn_fpaprect(x) insn_fpa_precision[(((x >> 21) & 2)|(x >> 15)) & 1]
+#define insn_fpaimm(x) insn_fpaconstants[x & 0x07]
+
+/* Local prototypes */
+static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
+static void disasm_print_reglist(const disasm_interface_t *di, u_int insn);
+static void disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn,
+ u_int loc);
+static void disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn,
+ u_int loc);
+static void disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn,
+ u_int loc);
+static db_expr_t disassemble_readword(db_expr_t address);
+static void disassemble_printaddr(db_expr_t address);
+
+vaddr_t
+disasm(const disasm_interface_t *di, vaddr_t loc, int altfmt)
+{
+ struct arm32_insn *i_ptr = (struct arm32_insn *)&arm32_i;
+
+ u_int insn;
+ int matchp;
+ int branch;
+ char* f_ptr;
+ int fmt;
+
+ fmt = 0;
+ matchp = 0;
+ insn = di->di_readword(loc);
+
+/* di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/
+
+ while (i_ptr->name) {
+ if ((insn & i_ptr->mask) == i_ptr->pattern) {
+ matchp = 1;
+ break;
+ }
+ i_ptr++;
+ }
+
+ if (!matchp) {
+ di->di_printf("und%s\t%08x\n", insn_condition(insn), insn);
+ return(loc + INSN_SIZE);
+ }
+
+ /* If instruction forces condition code, don't print it. */
+ if ((i_ptr->mask & 0xf0000000) == 0xf0000000)
+ di->di_printf("%s", i_ptr->name);
+ else
+ di->di_printf("%s%s", i_ptr->name, insn_condition(insn));
+
+ f_ptr = i_ptr->format;
+
+ /* Insert tab if there are no instruction modifiers */
+
+ if (*(f_ptr) < 'A' || *(f_ptr) > 'Z') {
+ ++fmt;
+ di->di_printf("\t");
+ }
+
+ while (*f_ptr) {
+ switch (*f_ptr) {
+ /* 2 - print Operand 2 of a data processing instruction */
+ case '2':
+ if (insn & 0x02000000) {
+ int rotate= ((insn >> 7) & 0x1e);
+
+ di->di_printf("#0x%08x",
+ (insn & 0xff) << (32 - rotate) |
+ (insn & 0xff) >> rotate);
+ } else {
+ disasm_register_shift(di, insn);
+ }
+ break;
+ /* d - destination register (bits 12-15) */
+ case 'd':
+ di->di_printf("r%d", ((insn >> 12) & 0x0f));
+ break;
+ /* D - insert 'p' if Rd is R15 */
+ case 'D':
+ if (((insn >> 12) & 0x0f) == 15)
+ di->di_printf("p");
+ break;
+ /* n - n register (bits 16-19) */
+ case 'n':
+ di->di_printf("r%d", ((insn >> 16) & 0x0f));
+ break;
+ /* s - s register (bits 8-11) */
+ case 's':
+ di->di_printf("r%d", ((insn >> 8) & 0x0f));
+ break;
+ /* o - indirect register rn (bits 16-19) (used by swap) */
+ case 'o':
+ di->di_printf("[r%d]", ((insn >> 16) & 0x0f));
+ break;
+ /* m - m register (bits 0-4) */
+ case 'm':
+ di->di_printf("r%d", ((insn >> 0) & 0x0f));
+ break;
+ /* a - address operand of ldr/str instruction */
+ case 'a':
+ disasm_insn_ldrstr(di, insn, loc);
+ break;
+ /* e - address operand of ldrh/strh instruction */
+ case 'e':
+ disasm_insn_ldrhstrh(di, insn, loc);
+ break;
+ /* l - register list for ldm/stm instruction */
+ case 'l':
+ disasm_print_reglist(di, insn);
+ break;
+ /* f - 1st fp operand (register) (bits 12-14) */
+ case 'f':
+ di->di_printf("f%d", (insn >> 12) & 7);
+ break;
+ /* g - 2nd fp operand (register) (bits 16-18) */
+ case 'g':
+ di->di_printf("f%d", (insn >> 16) & 7);
+ break;
+ /* h - 3rd fp operand (register/immediate) (bits 0-4) */
+ case 'h':
+ if (insn & (1 << 3))
+ di->di_printf("#%s", insn_fpaimm(insn));
+ else
+ di->di_printf("f%d", insn & 7);
+ break;
+ /* b - branch address */
+ case 'b':
+ branch = ((insn << 2) & 0x03ffffff);
+ if (branch & 0x02000000)
+ branch |= 0xfc000000;
+ di->di_printaddr(loc + 8 + branch);
+ break;
+ /* t - blx address */
+ case 't':
+ branch = ((insn << 2) & 0x03ffffff) |
+ (insn >> 23 & 0x00000002);
+ if (branch & 0x02000000)
+ branch |= 0xfc000000;
+ di->di_printaddr(loc + 8 + branch);
+ break;
+ /* X - block transfer type */
+ case 'X':
+ di->di_printf("%s", insn_blktrans(insn));
+ break;
+ /* Y - block transfer type (r13 base) */
+ case 'Y':
+ di->di_printf("%s", insn_stkblktrans(insn));
+ break;
+ /* c - comment field bits(0-23) */
+ case 'c':
+ di->di_printf("0x%08x", (insn & 0x00ffffff));
+ break;
+ /* k - breakpoint comment (bits 0-3, 8-19) */
+ case 'k':
+ di->di_printf("0x%04x",
+ (insn & 0x000fff00) >> 4 | (insn & 0x0000000f));
+ break;
+ /* p - saved or current status register */
+ case 'p':
+ if (insn & 0x00400000)
+ di->di_printf("spsr");
+ else
+ di->di_printf("cpsr");
+ break;
+ /* F - PSR transfer fields */
+ case 'F':
+ di->di_printf("_");
+ if (insn & (1 << 16))
+ di->di_printf("c");
+ if (insn & (1 << 17))
+ di->di_printf("x");
+ if (insn & (1 << 18))
+ di->di_printf("s");
+ if (insn & (1 << 19))
+ di->di_printf("f");
+ break;
+ /* B - byte transfer flag */
+ case 'B':
+ if (insn & 0x00400000)
+ di->di_printf("b");
+ break;
+ /* L - co-processor transfer size */
+ case 'L':
+ if (insn & (1 << 22))
+ di->di_printf("l");
+ break;
+ /* S - set status flag */
+ case 'S':
+ if (insn & 0x00100000)
+ di->di_printf("s");
+ break;
+ /* P - fp precision */
+ case 'P':
+ di->di_printf("%s", insn_fpaprec(insn));
+ break;
+ /* Q - fp precision (for ldf/stf) */
+ case 'Q':
+ break;
+ /* R - fp rounding */
+ case 'R':
+ di->di_printf("%s", insn_fparnd(insn));
+ break;
+ /* W - writeback flag */
+ case 'W':
+ if (insn & (1 << 21))
+ di->di_printf("!");
+ break;
+ /* # - co-processor number */
+ case '#':
+ di->di_printf("p%d", (insn >> 8) & 0x0f);
+ break;
+ /* v - co-processor data transfer registers+addressing mode */
+ case 'v':
+ disasm_insn_ldcstc(di, insn, loc);
+ break;
+ /* x - instruction in hex */
+ case 'x':
+ di->di_printf("0x%08x", insn);
+ break;
+ /* y - co-processor data processing registers */
+ case 'y':
+ di->di_printf("%d, ", (insn >> 20) & 0x0f);
+
+ di->di_printf("c%d, c%d, c%d", (insn >> 12) & 0x0f,
+ (insn >> 16) & 0x0f, insn & 0x0f);
+
+ di->di_printf(", %d", (insn >> 5) & 0x07);
+ break;
+ /* z - co-processor register transfer registers */
+ case 'z':
+ di->di_printf("%d, ", (insn >> 21) & 0x07);
+ di->di_printf("r%d, c%d, c%d, %d",
+ (insn >> 12) & 0x0f, (insn >> 16) & 0x0f,
+ insn & 0x0f, (insn >> 5) & 0x07);
+
+/* if (((insn >> 5) & 0x07) != 0)
+ di->di_printf(", %d", (insn >> 5) & 0x07);*/
+ break;
+ default:
+ di->di_printf("[%c - unknown]", *f_ptr);
+ break;
+ }
+ if (*(f_ptr+1) >= 'A' && *(f_ptr+1) <= 'Z')
+ ++f_ptr;
+ else if (*(++f_ptr)) {
+ ++fmt;
+ if (fmt == 1)
+ di->di_printf("\t");
+ else
+ di->di_printf(", ");
+ }
+ };
+
+ di->di_printf("\n");
+
+ return(loc + INSN_SIZE);
+}
+
+
+static void
+disasm_register_shift(const disasm_interface_t *di, u_int insn)
+{
+ di->di_printf("r%d", (insn & 0x0f));
+ if ((insn & 0x00000ff0) == 0)
+ ;
+ else if ((insn & 0x00000ff0) == 0x00000060)
+ di->di_printf(", rrx");
+ else {
+ if (insn & 0x10)
+ di->di_printf(", %s r%d", op2_shift(insn),
+ (insn >> 8) & 0x0f);
+ else
+ di->di_printf(", %s #%d", op2_shift(insn),
+ (insn >> 7) & 0x1f);
+ }
+}
+
+
+static void
+disasm_print_reglist(const disasm_interface_t *di, u_int insn)
+{
+ int loop;
+ int start;
+ int comma;
+
+ di->di_printf("{");
+ start = -1;
+ comma = 0;
+
+ for (loop = 0; loop < 17; ++loop) {
+ if (start != -1) {
+ if (loop == 16 || !(insn & (1 << loop))) {
+ if (comma)
+ di->di_printf(", ");
+ else
+ comma = 1;
+ if (start == loop - 1)
+ di->di_printf("r%d", start);
+ else
+ di->di_printf("r%d-r%d", start, loop - 1);
+ start = -1;
+ }
+ } else {
+ if (insn & (1 << loop))
+ start = loop;
+ }
+ }
+ di->di_printf("}");
+
+ if (insn & (1 << 22))
+ di->di_printf("^");
+}
+
+static void
+disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn, u_int loc)
+{
+ int offset;
+
+ offset = insn & 0xfff;
+ if ((insn & 0x032f0000) == 0x010f0000) {
+ /* rA = pc, immediate index */
+ if (insn & 0x00800000)
+ loc += offset;
+ else
+ loc -= offset;
+ di->di_printaddr(loc + 8);
+ } else {
+ di->di_printf("[r%d", (insn >> 16) & 0x0f);
+ if ((insn & 0x03000fff) != 0x01000000) {
+ di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
+ if (!(insn & 0x00800000))
+ di->di_printf("-");
+ if (insn & (1 << 25))
+ disasm_register_shift(di, insn);
+ else
+ di->di_printf("#0x%03x", offset);
+ }
+ if (insn & (1 << 24))
+ di->di_printf("]");
+ }
+}
+
+static void
+disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn, u_int loc)
+{
+ int offset;
+
+ offset = ((insn & 0xf00) >> 4) | (insn & 0xf);
+ if ((insn & 0x004f0000) == 0x004f0000) {
+ /* rA = pc, immediate index */
+ if (insn & 0x00800000)
+ loc += offset;
+ else
+ loc -= offset;
+ di->di_printaddr(loc + 8);
+ } else {
+ di->di_printf("[r%d", (insn >> 16) & 0x0f);
+ if ((insn & 0x01400f0f) != 0x01400000) {
+ di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
+ if (!(insn & 0x00800000))
+ di->di_printf("-");
+ if (insn & (1 << 22))
+ di->di_printf("#0x%02x", offset);
+ else
+ di->di_printf("r%d", (insn & 0x0f));
+ }
+ if (insn & (1 << 24))
+ di->di_printf("]");
+ }
+}
+
+static void
+disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int loc)
+{
+ if (((insn >> 8) & 0xf) == 1)
+ di->di_printf("f%d, ", (insn >> 12) & 0x07);
+ else
+ di->di_printf("c%d, ", (insn >> 12) & 0x0f);
+
+ di->di_printf("[r%d", (insn >> 16) & 0x0f);
+
+ di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
+
+ if (!(insn & (1 << 23)))
+ di->di_printf("-");
+
+ di->di_printf("#0x%03x", (insn & 0xff) << 2);
+
+ if (insn & (1 << 24))
+ di->di_printf("]");
+
+ if (insn & (1 << 21))
+ di->di_printf("!");
+}
+
+static db_expr_t
+disassemble_readword(db_expr_t address)
+{
+ return(*((u_int *)address));
+}
+
+static void
+disassemble_printaddr(db_expr_t address)
+{
+ printf("0x%08x", address);
+}
+
+static const disasm_interface_t disassemble_di = {
+ disassemble_readword, disassemble_printaddr, printf
+};
+
+void
+disassemble(u_int address)
+{
+
+ (void)disasm(&disassemble_di, address, 0);
+}
+
+/* End of disassem.c */
diff --git a/sys/arch/arm/arm/disassem.h b/sys/arch/arm/arm/disassem.h
new file mode 100644
index 00000000000..1352864fd50
--- /dev/null
+++ b/sys/arch/arm/arm/disassem.h
@@ -0,0 +1,49 @@
+/* $OpenBSD: disassem.h,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: disassem.h,v 1.4 2001/03/04 04:15:58 matt Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Define the interface structure required by the disassembler.
+ */
+
+typedef struct {
+ db_expr_t (*di_readword)(db_expr_t);
+ void (*di_printaddr)(db_expr_t);
+ int (*di_printf)(const char *, ...);
+} disasm_interface_t;
+
+/* Prototypes for callable functions */
+
+vaddr_t disasm(const disasm_interface_t *, vaddr_t, int);
+void disassemble(u_int);
diff --git a/sys/arch/arm/arm/disksubr.c b/sys/arch/arm/arm/disksubr.c
new file mode 100644
index 00000000000..150dc5bca43
--- /dev/null
+++ b/sys/arch/arm/arm/disksubr.c
@@ -0,0 +1,362 @@
+/* $OpenBSD: disksubr.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */
+
+/*
+ * Copyright (c) 1996 Theo de Raadt
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/syslog.h>
+#include <sys/disk.h>
+
+#define b_cylin b_resid
+
+void
+dk_establish(struct disk *dk, struct device *dev)
+{
+}
+
+int
+try_mbr_label(dev_t dev, void (*strat)(struct buf *), struct buf *bp,
+ struct disklabel *lp, struct cpu_disklabel *osdep, char **pmsg,
+ int *bsdpartoff);
+
+
+/*
+ * Attempt to read a disk label from a device
+ * using the indicated strategy routine.
+ * The label must be partly set up before this:
+ * secpercyl, secsize and anything required for a block i/o read
+ * operation in the driver's strategy/start routines
+ * must be filled in before calling us.
+ *
+ * Returns null on success and an error string on failure.
+ */
+char *
+readdisklabel(dev_t dev, void (*strat)(struct buf *),
+ struct disklabel *lp, struct cpu_disklabel *osdep, int spoofonly)
+{
+ struct buf *bp;
+ struct disklabel *dlp;
+ char *msg = NULL;
+ int partoff, i, found;
+
+ /* minimal requirements for archtypal disk label */
+ if (lp->d_secsize == 0)
+ lp->d_secsize = DEV_BSIZE;
+ if (lp->d_secperunit == 0)
+ lp->d_secperunit = 0x1fffffff;
+ lp->d_npartitions = RAW_PART + 1;
+ for (i = 0; i < RAW_PART; i++) {
+ lp->d_partitions[i].p_size = 0;
+ lp->d_partitions[i].p_offset = 0;
+ }
+ if (lp->d_partitions[i].p_size == 0)
+ lp->d_partitions[i].p_size = 0x1fffffff;
+ lp->d_partitions[i].p_offset = 0;
+
+ /* get a buffer and initialize it */
+ bp = geteblk((int)lp->d_secsize);
+ bp->b_dev = dev;
+
+ partoff = -1;
+
+ found = try_mbr_label(dev, strat, bp, lp, osdep, &msg,
+ &partoff);
+ /* if no partition found, return */
+ if (found == 0 || partoff == -1) {
+ /* no special partition table found try raw labeled disk. */
+ partoff = LABELSECTOR;
+ }
+
+ /* don't read the on-disk label if we are in spoofed-only mode */
+ if (spoofonly)
+ goto done;
+
+ /* next, dig out disk label */
+ bp->b_blkno = partoff;
+ bp->b_cylin = partoff/lp->d_secpercyl; /* XXX */
+ bp->b_bcount = lp->d_secsize;
+ bp->b_flags = B_BUSY | B_READ;
+ (*strat)(bp);
+
+ /* if successful, locate disk label within block and validate */
+ if (biowait(bp)) {
+ /* XXX we return the faked label built so far */
+ msg = "disk label I/O error";
+ goto done;
+ }
+
+ for (dlp = (struct disklabel *)bp->b_data;
+ dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize -
+ sizeof(*dlp));
+ dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
+ if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
+ if (msg == NULL)
+ msg = "no disk label";
+ } else if (dlp->d_npartitions > MAXPARTITIONS ||
+ dkcksum(dlp) != 0)
+ msg = "disk label corrupted";
+ else {
+ *lp = *dlp;
+ msg = NULL;
+ break;
+ }
+ }
+
+ if (msg) {
+#if defined(CD9660)
+ if (iso_disklabelspoof(dev, strat, lp) == 0)
+ msg = NULL;
+#endif
+ goto done;
+ }
+
+done:
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ return (msg);
+}
+
+/*
+ * Check new disk label for sensibility
+ * before setting it.
+ */
+int
+setdisklabel(struct disklabel *olp, struct disklabel *nlp, u_long openmask,
+ struct cpu_disklabel *osdep)
+{
+ int i;
+ struct partition *opp, *npp;
+
+ /* sanity clause */
+ if (nlp->d_secpercyl == 0 || nlp->d_secsize == 0 ||
+ (nlp->d_secsize % DEV_BSIZE) != 0)
+ return(EINVAL);
+
+ /* special case to allow disklabel to be invalidated */
+ if (nlp->d_magic == 0xffffffff) {
+ *olp = *nlp;
+ return (0);
+ }
+
+ if (nlp->d_magic != DISKMAGIC || nlp->d_magic2 != DISKMAGIC ||
+ dkcksum(nlp) != 0)
+ return (EINVAL);
+
+ /* XXX missing check if other dos partitions will be overwritten */
+
+ while (openmask != 0) {
+ i = ffs(openmask) - 1;
+ openmask &= ~(1 << i);
+ if (nlp->d_npartitions <= i)
+ return (EBUSY);
+ opp = &olp->d_partitions[i];
+ npp = &nlp->d_partitions[i];
+ if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
+ return (EBUSY);
+ /*
+ * Copy internally-set partition information
+ * if new label doesn't include it. XXX
+ */
+ if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
+ npp->p_fstype = opp->p_fstype;
+ npp->p_fsize = opp->p_fsize;
+ npp->p_frag = opp->p_frag;
+ npp->p_cpg = opp->p_cpg;
+ }
+ }
+ nlp->d_checksum = 0;
+ nlp->d_checksum = dkcksum(nlp);
+ *olp = *nlp;
+ return (0);
+}
+
+
+/*
+ * Write disk label back to device after modification.
+ * XXX cannot handle OpenBSD partitions in extended partitions!
+ */
+int
+writedisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp,
+ struct cpu_disklabel *osdep)
+{
+ struct dos_partition *dp = osdep->dosparts, *dp2;
+ struct buf *bp;
+ struct disklabel *dlp;
+ int error, dospartoff, cyl, i;
+ int ourpart = -1;
+
+ /* get a buffer and initialize it */
+ bp = geteblk((int)lp->d_secsize);
+ bp->b_dev = dev;
+
+ /* do dos partitions in the process of getting disklabel? */
+ dospartoff = 0;
+ cyl = LABELSECTOR / lp->d_secpercyl;
+ if (dp) {
+ /* read master boot record */
+ bp->b_blkno = DOSBBSECTOR;
+ bp->b_bcount = lp->d_secsize;
+ bp->b_flags = B_BUSY | B_READ;
+ bp->b_cylin = DOSBBSECTOR / lp->d_secpercyl;
+ (*strat)(bp);
+
+ if ((error = biowait(bp)) != 0)
+ goto done;
+
+ /* XXX how do we check veracity/bounds of this? */
+ bcopy(bp->b_data + DOSPARTOFF, dp,
+ NDOSPART * sizeof(*dp));
+
+ for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++)
+ if (get_le(&dp2->dp_size) && dp2->dp_typ ==
+ DOSPTYP_OPENBSD)
+ ourpart = i;
+ for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++)
+ if (get_le(&dp2->dp_size) && dp2->dp_typ ==
+ DOSPTYP_FREEBSD)
+ ourpart = i;
+ for (dp2=dp, i=0; i < NDOSPART && ourpart == -1; i++, dp2++)
+ if (get_le(&dp2->dp_size) && dp2->dp_typ ==
+ DOSPTYP_NETBSD)
+ ourpart = i;
+
+ if (ourpart != -1) {
+ dp2 = &dp[ourpart];
+
+ /*
+ * need sector address for SCSI/IDE,
+ * cylinder for ESDI/ST506/RLL
+ */
+ dospartoff = get_le(&dp2->dp_start);
+ cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect);
+ }
+ }
+
+ /* next, dig out disk label */
+ bp->b_blkno = dospartoff + LABELSECTOR;
+ bp->b_cylin = cyl;
+ bp->b_bcount = lp->d_secsize;
+ bp->b_flags = B_BUSY | B_READ;
+ (*strat)(bp);
+
+ /* if successful, locate disk label within block and validate */
+ if ((error = biowait(bp)) != 0)
+ goto done;
+ for (dlp = (struct disklabel *)bp->b_data;
+ dlp <= (struct disklabel *)(bp->b_data + lp->d_secsize -
+ sizeof(*dlp));
+ dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
+ if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
+ dkcksum(dlp) == 0) {
+ *dlp = *lp;
+ bp->b_flags = B_BUSY | B_WRITE;
+ (*strat)(bp);
+ error = biowait(bp);
+ goto done;
+ }
+ }
+
+ /* Write it in the regular place. */
+ *(struct disklabel *)bp->b_data = *lp;
+ bp->b_flags = B_BUSY | B_WRITE;
+ (*strat)(bp);
+ error = biowait(bp);
+ goto done;
+
+done:
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ return (error);
+}
+
+/*
+ * Determine the size of the transfer, and make sure it is
+ * within the boundaries of the partition. Adjust transfer
+ * if needed, and signal errors or early completion.
+ */
+int
+bounds_check_with_label(struct buf *bp, struct disklabel *lp,
+ struct cpu_disklabel *osdep, int wlabel)
+{
+#define blockpersec(count, lp) ((count) * (((lp)->d_secsize) / DEV_BSIZE))
+ struct partition *p = lp->d_partitions + DISKPART(bp->b_dev);
+ int labelsector = blockpersec(lp->d_partitions[RAW_PART].p_offset, lp) +
+ LABELSECTOR;
+ int sz = howmany(bp->b_bcount, DEV_BSIZE);
+
+ /* avoid division by zero */
+ if (lp->d_secpercyl == 0) {
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+
+ if (bp->b_blkno + sz > blockpersec(p->p_size, lp)) {
+ sz = blockpersec(p->p_size, lp) - bp->b_blkno;
+ if (sz == 0) {
+ /* If exactly at end of disk, return EOF. */
+ bp->b_resid = bp->b_bcount;
+ goto done;
+ }
+ if (sz < 0) {
+ /* If past end of disk, return EINVAL. */
+ bp->b_error = EINVAL;
+ goto bad;
+ }
+ /* Otherwise, truncate request. */
+ bp->b_bcount = sz << DEV_BSHIFT;
+ }
+
+ /* Overwriting disk label? */
+ if (bp->b_blkno + blockpersec(p->p_offset, lp) <= labelsector &&
+#if LABELSECTOR != 0
+ bp->b_blkno + blockpersec(p->p_offset, lp) + sz > labelsector &&
+#endif
+ (bp->b_flags & B_READ) == 0 && !wlabel) {
+ bp->b_error = EROFS;
+ goto bad;
+ }
+
+ /* calculate cylinder for disksort to order transfers with */
+ bp->b_cylin = (bp->b_blkno + blockpersec(p->p_offset, lp)) /
+ lp->d_secpercyl;
+ return (1);
+
+bad:
+ bp->b_flags |= B_ERROR;
+done:
+ return (0);
+}
diff --git a/sys/arch/arm/arm/disksubr_mbr.c b/sys/arch/arm/arm/disksubr_mbr.c
new file mode 100644
index 00000000000..f300eb25edb
--- /dev/null
+++ b/sys/arch/arm/arm/disksubr_mbr.c
@@ -0,0 +1,208 @@
+/* $OpenBSD: disksubr_mbr.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */
+
+/*
+ * Copyright (c) 1996 Theo de Raadt
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ufs_disksubr.c 7.16 (Berkeley) 5/4/91
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/device.h>
+#include <sys/disklabel.h>
+#include <sys/syslog.h>
+#include <sys/disk.h>
+
+#define b_cylin b_resid
+
+#define BOOT_MAGIC 0xAA55
+#define BOOT_MAGIC_OFF (DOSPARTOFF+NDOSPART*sizeof(struct dos_partition))
+
+int
+try_mbr_label(dev_t dev, void (*strat)(struct buf *), struct buf *bp,
+ struct disklabel *lp, struct cpu_disklabel *osdep, char **pmsg,
+ int *bsdpartoff);
+int
+try_mbr_label(dev_t dev, void (*strat)(struct buf *), struct buf *bp,
+ struct disklabel *lp, struct cpu_disklabel *osdep, char **pmsg,
+ int *bsdpartoff)
+{
+ struct dos_partition *dp = osdep->dosparts, *dp2;
+ char *cp;
+ int cyl, n = 0, i, ourpart = -1;
+ int dospartoff = -1;
+
+ /* MBR type disklabel */
+ /* do dos partitions in the process of getting disklabel? */
+ cyl = LABELSECTOR / lp->d_secpercyl;
+ if (dp) {
+ daddr_t part_blkno = DOSBBSECTOR;
+ unsigned long extoff = 0;
+ int wander = 1, loop = 0;
+
+ /*
+ * Read dos partition table, follow extended partitions.
+ * Map the partitions to disklabel entries i-p
+ */
+ while (wander && n < 8 && loop < 8) {
+ loop++;
+ wander = 0;
+ if (part_blkno < extoff)
+ part_blkno = extoff;
+
+ /* read boot record */
+ bp->b_blkno = part_blkno;
+ bp->b_bcount = lp->d_secsize;
+ bp->b_flags = B_BUSY | B_READ;
+ bp->b_cylin = part_blkno / lp->d_secpercyl;
+ (*strat)(bp);
+
+ /* if successful, wander through dos partition table */
+ if (biowait(bp)) {
+ *pmsg = "dos partition I/O error";
+ return 0;
+ }
+ bcopy(bp->b_data + DOSPARTOFF, dp, NDOSPART * sizeof(*dp));
+
+ if (ourpart == -1) {
+ /* Search for our MBR partition */
+ for (dp2=dp, i=0; i < NDOSPART && ourpart == -1;
+ i++, dp2++)
+ if (get_le(&dp2->dp_size) &&
+ dp2->dp_typ == DOSPTYP_OPENBSD)
+ ourpart = i;
+ for (dp2=dp, i=0; i < NDOSPART && ourpart == -1;
+ i++, dp2++)
+ if (get_le(&dp2->dp_size) &&
+ dp2->dp_typ == DOSPTYP_FREEBSD)
+ ourpart = i;
+ for (dp2=dp, i=0; i < NDOSPART && ourpart == -1;
+ i++, dp2++)
+ if (get_le(&dp2->dp_size) &&
+ dp2->dp_typ == DOSPTYP_NETBSD)
+ ourpart = i;
+ if (ourpart == -1)
+ goto donot;
+ /*
+ * This is our MBR partition. need sector address
+ * for SCSI/IDE, cylinder for ESDI/ST506/RLL
+ */
+ dp2 = &dp[ourpart];
+ dospartoff = get_le(&dp2->dp_start) + part_blkno;
+ cyl = DPCYL(dp2->dp_scyl, dp2->dp_ssect);
+
+ /* XXX build a temporary disklabel */
+ lp->d_partitions[0].p_size = get_le(&dp2->dp_size);
+ lp->d_partitions[0].p_offset =
+ get_le(&dp2->dp_start) + part_blkno;
+ if (lp->d_ntracks == 0)
+ lp->d_ntracks = dp2->dp_ehd + 1;
+ if (lp->d_nsectors == 0)
+ lp->d_nsectors = DPSECT(dp2->dp_esect);
+ if (lp->d_secpercyl == 0)
+ lp->d_secpercyl = lp->d_ntracks *
+ lp->d_nsectors;
+ }
+donot:
+ /*
+ * In case the disklabel read below fails, we want to
+ * provide a fake label in i-p.
+ */
+ for (dp2=dp, i=0; i < NDOSPART && n < 8; i++, dp2++) {
+ struct partition *pp = &lp->d_partitions[8+n];
+
+ if (dp2->dp_typ == DOSPTYP_OPENBSD)
+ continue;
+ if (get_le(&dp2->dp_size) > lp->d_secperunit)
+ continue;
+ if (get_le(&dp2->dp_size))
+ pp->p_size = get_le(&dp2->dp_size);
+ if (get_le(&dp2->dp_start))
+ pp->p_offset =
+ get_le(&dp2->dp_start) + part_blkno;
+
+ switch (dp2->dp_typ) {
+ case DOSPTYP_UNUSED:
+ for (cp = (char *)dp2;
+ cp < (char *)(dp2 + 1); cp++)
+ if (*cp)
+ break;
+ /*
+ * Was it all zeroes? If so, it is
+ * an unused entry that we don't
+ * want to show.
+ */
+ if (cp == (char *)(dp2 + 1))
+ continue;
+ lp->d_partitions[8 + n++].p_fstype =
+ FS_UNUSED;
+ break;
+
+ case DOSPTYP_LINUX:
+ pp->p_fstype = FS_EXT2FS;
+ n++;
+ break;
+
+ case DOSPTYP_FAT12:
+ case DOSPTYP_FAT16S:
+ case DOSPTYP_FAT16B:
+ case DOSPTYP_FAT16C:
+ case DOSPTYP_FAT32:
+ pp->p_fstype = FS_MSDOS;
+ n++;
+ break;
+ case DOSPTYP_EXTEND:
+ case DOSPTYP_EXTENDL:
+ part_blkno = get_le(&dp2->dp_start) + extoff;
+ if (!extoff) {
+ extoff = get_le(&dp2->dp_start);
+ part_blkno = 0;
+ }
+ wander = 1;
+ break;
+ default:
+ pp->p_fstype = FS_OTHER;
+ n++;
+ break;
+ }
+ }
+ }
+ lp->d_bbsize = 8192;
+ lp->d_sbsize = 64*1024; /* XXX ? */
+ lp->d_npartitions = MAXPARTITIONS;
+ }
+
+ /* if not partitions found return failure */
+ if (n == 0 && dospartoff == -1)
+ return 0;
+ *bsdpartoff = dospartoff + LABELSECTOR;
+ return 1;
+}
diff --git a/sys/arch/arm/arm/exception.S b/sys/arch/arm/arm/exception.S
new file mode 100644
index 00000000000..d0fedb6da45
--- /dev/null
+++ b/sys/arch/arm/arm/exception.S
@@ -0,0 +1,380 @@
+/* $OpenBSD: exception.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: exception.S,v 1.13 2003/10/31 16:30:15 scw Exp $^I*/$
+
+/*
+ * Copyright (c) 1994-1997 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * exception.S
+ *
+ * Low level handlers for exception vectors
+ *
+ * Created : 24/09/94
+ *
+ * Based on kate/display/abort.s
+ */
+
+#include <machine/asm.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include "assym.h"
+
+ .text
+ .align 0
+
+AST_ALIGNMENT_FAULT_LOCALS
+
+/*
+ * reset_entry:
+ *
+ * Handler for Reset exception.
+ */
+ASENTRY_NP(reset_entry)
+ adr r0, Lreset_panicmsg
+ mov r1, lr
+ bl _C_LABEL(panic)
+ /* NOTREACHED */
+Lreset_panicmsg:
+ .asciz "Reset vector called, LR = 0x%08x"
+ .balign 4
+
+/*
+ * swi_entry
+ *
+ * Handler for the Software Interrupt exception.
+ */
+ASENTRY_NP(swi_entry)
+ PUSHFRAME
+ ENABLE_ALIGNMENT_FAULTS
+
+ mov r0, sp /* Pass the frame to any function */
+ bl _C_LABEL(swi_handler) /* It's a SWI ! */
+
+ DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
+ PULLFRAME
+ movs pc, lr /* Exit */
+
+/*
+ * prefetch_abort_entry:
+ *
+ * Handler for the Prefetch Abort exception.
+ */
+ASENTRY_NP(prefetch_abort_entry)
+#ifdef __XSCALE__
+ nop /* Make absolutely sure any pending */
+ nop /* imprecise aborts have occurred. */
+#endif
+ sub lr, lr, #0x00000004 /* Adjust the lr */
+
+ PUSHFRAMEINSVC
+ ENABLE_ALIGNMENT_FAULTS
+
+ ldr r1, Lprefetch_abort_handler_address
+ adr lr, exception_exit
+ mov r0, sp /* pass the stack pointer as r0 */
+ ldr pc, [r1]
+
+Lprefetch_abort_handler_address:
+ .word _C_LABEL(prefetch_abort_handler_address)
+
+ .data
+ .global _C_LABEL(prefetch_abort_handler_address)
+
+_C_LABEL(prefetch_abort_handler_address):
+ .word abortprefetch
+
+ .text
+abortprefetch:
+ adr r0, abortprefetchmsg
+ b _C_LABEL(panic)
+
+abortprefetchmsg:
+ .asciz "abortprefetch"
+ .align 0
+
+/*
+ * data_abort_entry:
+ *
+ * Handler for the Data Abort exception.
+ */
+ASENTRY_NP(data_abort_entry)
+#ifdef __XSCALE__
+ nop /* Make absolutely sure any pending */
+ nop /* imprecise aborts have occurred. */
+#endif
+ sub lr, lr, #0x00000008 /* Adjust the lr */
+
+ PUSHFRAMEINSVC /* Push trap frame and switch */
+ /* to SVC32 mode */
+ ENABLE_ALIGNMENT_FAULTS
+
+ ldr r1, Ldata_abort_handler_address
+ adr lr, exception_exit
+ mov r0, sp /* pass the stack pointer as r0 */
+ ldr pc, [r1]
+
+Ldata_abort_handler_address:
+ .word _C_LABEL(data_abort_handler_address)
+
+ .data
+ .global _C_LABEL(data_abort_handler_address)
+_C_LABEL(data_abort_handler_address):
+ .word abortdata
+
+ .text
+abortdata:
+ adr r0, abortdatamsg
+ b _C_LABEL(panic)
+
+abortdatamsg:
+ .asciz "abortdata"
+ .align 0
+
+/*
+ * address_exception_entry:
+ *
+ * Handler for the Address Exception exception.
+ *
+ * NOTE: This exception isn't really used on arm32. We
+ * print a warning message to the console and then treat
+ * it like a Data Abort.
+ */
+ASENTRY_NP(address_exception_entry)
+ mrs r1, cpsr_all
+ mrs r2, spsr_all
+ mov r3, lr
+ adr r0, Laddress_exception_msg
+ bl _C_LABEL(printf) /* XXX CLOBBERS LR!! */
+ b data_abort_entry
+Laddress_exception_msg:
+ .asciz "Address Exception CPSR=0x%08x SPSR=0x%08x LR=0x%08x\n"
+ .balign 4
+
+/*
+ * General exception exit handler
+ * (Placed here to be within range of all the references to it)
+ *
+ * It exits straight away if not returning to USR mode.
+ * This loops around delivering any pending ASTs.
+ * Interrupts are disabled at suitable points to avoid ASTs
+ * being posted between testing and exit to user mode.
+ *
+ * This function uses PULLFRAMEFROMSVCANDEXIT and
+ * DO_AST_AND_RESTORE_ALIGNMENT_FAULTS thus should
+ * only be called if the exception handler used PUSHFRAMEINSVC
+ * followed by ENABLE_ALIGNMENT_FAULTS.
+ */
+
+exception_exit:
+ DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
+ PULLFRAMEFROMSVCANDEXIT
+
+/*
+ * undefined_entry:
+ *
+ * Handler for the Undefined Instruction exception.
+ *
+ * We indirect the undefined vector via the handler address
+ * in the data area. Entry to the undefined handler must
+ * look like direct entry from the vector.
+ */
+ASENTRY_NP(undefined_entry)
+#ifdef IPKDB
+/*
+ * IPKDB must be hooked in at the earliest possible entry point.
+ *
+ */
+/*
+ * Make room for all registers saving real r0-r7 and r15.
+ * The remaining registers are updated later.
+ */
+ stmfd sp!, {r0,r1} /* psr & spsr */
+ stmfd sp!, {lr} /* pc */
+ stmfd sp!, {r0-r14} /* r0-r7, r8-r14 */
+/*
+ * Get previous psr.
+ */
+ mrs r7, cpsr_all
+ mrs r0, spsr_all
+ str r0, [sp, #(16*4)]
+/*
+ * Test for user mode.
+ */
+ tst r0, #0xf
+ bne .Lprenotuser_push
+ add r1, sp, #(8*4)
+ stmia r1,{r8-r14}^ /* store user mode r8-r14*/
+ b .Lgoipkdb
+/*
+ * Switch to previous mode to get r8-r13.
+ */
+.Lprenotuser_push:
+ orr r0, r0, #(I32_bit) /* disable interrupts */
+ msr cpsr_all, r0
+ mov r1, r8
+ mov r2, r9
+ mov r3, r10
+ mov r4, r11
+ mov r5, r12
+ mov r6, r13
+ msr cpsr_all, r7 /* back to undefined mode */
+ add r8, sp, #(8*4)
+ stmia r8, {r1-r6} /* r8-r13 */
+/*
+ * Now back to previous mode to get r14 and spsr.
+ */
+ msr cpsr_all, r0
+ mov r1, r14
+ mrs r2, spsr
+ msr cpsr_all, r7 /* back to undefined mode */
+ str r1, [sp, #(14*4)] /* r14 */
+ str r2, [sp, #(17*4)] /* spsr */
+/*
+ * Now to IPKDB.
+ */
+.Lgoipkdb:
+ mov r0, sp
+ bl _C_LABEL(ipkdb_trap_glue)
+ ldr r1, .Lipkdb_trap_return
+ str r0,[r1]
+
+/*
+ * Have to load all registers from the stack.
+ *
+ * Start with spsr and pc.
+ */
+ ldr r0, [sp, #(16*4)] /* spsr */
+ ldr r1, [sp, #(15*4)] /* r15 */
+ msr spsr_all, r0
+ mov r14, r1
+/*
+ * Test for user mode.
+ */
+ tst r0, #0xf
+ bne .Lprenotuser_pull
+ add r1, sp, #(8*4)
+ ldmia r1, {r8-r14}^ /* load user mode r8-r14 */
+ b .Lpull_r0r7
+.Lprenotuser_pull:
+/*
+ * Now previous mode spsr and r14.
+ */
+ ldr r1, [sp, #(17*4)] /* spsr */
+ ldr r2, [sp, #(14*4)] /* r14 */
+ orr r0, r0, #(I32_bit)
+ msr cpsr_all, r0 /* switch to previous mode */
+ msr spsr_all, r1
+ mov r14, r2
+ msr cpsr_all, r7 /* back to undefined mode */
+/*
+ * Now r8-r13.
+ */
+ add r8, sp, #(8*4)
+ ldmia r8, {r1-r6} /* r8-r13 */
+ msr cpsr_all, r0
+ mov r8, r1
+ mov r9, r2
+ mov r10, r3
+ mov r11, r4
+ mov r12, r5
+ mov r13, r6
+ msr cpsr_all, r7
+.Lpull_r0r7:
+/*
+ * Now the rest of the registers.
+ */
+ ldr r1,Lipkdb_trap_return
+ ldr r0,[r1]
+ tst r0,r0
+ ldmfd sp!, {r0-r7} /* r0-r7 */
+ add sp, sp, #(10*4) /* adjust sp */
+
+/*
+ * Did IPKDB handle it?
+ */
+ movnes pc, lr /* return */
+
+#endif
+ stmfd sp!, {r0, r1}
+ ldr r0, Lundefined_handler_indirection
+ ldr r1, [sp], #0x0004
+ str r1, [r0, #0x0000]
+ ldr r1, [sp], #0x0004
+ str r1, [r0, #0x0004]
+ ldmia r0, {r0, r1, pc}
+
+#ifdef IPKDB
+Lipkdb_trap_return:
+ .word Lipkdb_trap_return_data
+#endif
+
+Lundefined_handler_indirection:
+ .word Lundefined_handler_indirection_data
+
+/*
+ * assembly bounce code for calling the kernel
+ * undefined instruction handler. This uses
+ * a standard trap frame and is called in SVC mode.
+ */
+
+ENTRY_NP(undefinedinstruction_bounce)
+ PUSHFRAMEINSVC
+ ENABLE_ALIGNMENT_FAULTS
+
+ mov r0, sp
+ adr lr, exception_exit
+ b _C_LABEL(undefinedinstruction)
+
+ .data
+ .align 0
+
+#ifdef IPKDB
+Lipkdb_trap_return_data:
+ .word 0
+#endif
+
+/*
+ * Indirection data
+ * 2 words use for preserving r0 and r1
+ * 3rd word contains the undefined handler address.
+ */
+
+Lundefined_handler_indirection_data:
+ .word 0
+ .word 0
+
+ .global _C_LABEL(undefined_handler_address)
+_C_LABEL(undefined_handler_address):
+ .word _C_LABEL(undefinedinstruction_bounce)
diff --git a/sys/arch/arm/arm/fault.c b/sys/arch/arm/arm/fault.c
new file mode 100644
index 00000000000..0841d4d66f4
--- /dev/null
+++ b/sys/arch/arm/arm/fault.c
@@ -0,0 +1,837 @@
+/* $OpenBSD: fault.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: fault.c,v 1.46 2004/01/21 15:39:21 skrll Exp $^I*/$
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1994-1997 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * fault.c
+ *
+ * Fault handlers
+ *
+ * Created : 28/11/94
+ */
+
+#include <sys/types.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/kernel.h>
+#include <sys/signalvar.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <arm/cpuconf.h>
+
+#include <machine/frame.h>
+#include <arm/katelib.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+#if defined(DDB) || defined(KGDB)
+#include <machine/db_machdep.h>
+#ifdef KGDB
+#include <sys/kgdb.h>
+#endif
+#if !defined(DDB)
+#define kdb_trap kgdb_trap
+#endif
+#endif
+
+#include <arch/arm/arm/disassem.h>
+#include <arm/machdep.h>
+
+extern char fusubailout[];
+
+#ifdef DEBUG
+int last_fault_code; /* For the benefit of pmap_fault_fixup() */
+#endif
+
+#if defined(CPU_ARM3) || defined(CPU_ARM6) || \
+ defined(CPU_ARM7) || defined(CPU_ARM7TDMI)
+/* These CPUs may need data/prefetch abort fixups */
+#define CPU_ABORT_FIXUP_REQUIRED
+#endif
+
+struct sigdata {
+ int signo;
+ int code;
+ vaddr_t addr;
+ int trap;
+};
+
+struct data_abort {
+ int (*func)(trapframe_t *, u_int, u_int, struct proc *,
+ struct sigdata *);
+ const char *desc;
+};
+
+static int dab_fatal(trapframe_t *, u_int, u_int, struct proc *,
+ struct sigdata *sd);
+static int dab_align(trapframe_t *, u_int, u_int, struct proc *,
+ struct sigdata *sd);
+static int dab_buserr(trapframe_t *, u_int, u_int, struct proc *,
+ struct sigdata *sd);
+
+static const struct data_abort data_aborts[] = {
+ {dab_fatal, "Vector Exception"},
+ {dab_align, "Alignment Fault 1"},
+ {dab_fatal, "Terminal Exception"},
+ {dab_align, "Alignment Fault 3"},
+ {dab_buserr, "External Linefetch Abort (S)"},
+ {NULL, "Translation Fault (S)"},
+ {dab_buserr, "External Linefetch Abort (P)"},
+ {NULL, "Translation Fault (P)"},
+ {dab_buserr, "External Non-Linefetch Abort (S)"},
+ {NULL, "Domain Fault (S)"},
+ {dab_buserr, "External Non-Linefetch Abort (P)"},
+ {NULL, "Domain Fault (P)"},
+ {dab_buserr, "External Translation Abort (L1)"},
+ {NULL, "Permission Fault (S)"},
+ {dab_buserr, "External Translation Abort (L2)"},
+ {NULL, "Permission Fault (P)"}
+};
+
+/* Determine if a fault came from user mode */
+#define TRAP_USERMODE(tf) ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE)
+
+/* Determine if 'x' is a permission fault */
+#define IS_PERMISSION_FAULT(x) \
+ (((1 << ((x) & FAULT_TYPE_MASK)) & \
+ ((1 << FAULT_PERM_P) | (1 << FAULT_PERM_S))) != 0)
+
+static __inline int
+data_abort_fixup(trapframe_t *tf, u_int fsr, u_int far, struct proc *l)
+{
+#ifdef CPU_ABORT_FIXUP_REQUIRED
+ int error;
+
+ /* Call the cpu specific data abort fixup routine */
+ error = cpu_dataabt_fixup(tf);
+ if (__predict_true(error != ABORT_FIXUP_FAILED))
+ return (error);
+
+ /*
+ * Oops, couldn't fix up the instruction
+ */
+ printf("data_abort_fixup: fixup for %s mode data abort failed.\n",
+ TRAP_USERMODE(tf) ? "user" : "kernel");
+ printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc,
+ *((u_int *)tf->tf_pc));
+ disassemble(tf->tf_pc);
+
+ /* Die now if this happened in kernel mode */
+ if (!TRAP_USERMODE(tf))
+ dab_fatal(tf, fsr, far, l, NULL);
+
+ return (error);
+#else
+ return (ABORT_FIXUP_OK);
+#endif /* CPU_ABORT_FIXUP_REQUIRED */
+}
+
+void
+data_abort_handler(trapframe_t *tf)
+{
+ struct vm_map *map;
+ struct pcb *pcb;
+ struct proc *p;
+ u_int user, far, fsr;
+ vm_prot_t ftype;
+ void *onfault;
+ vaddr_t va;
+ int error;
+ union sigval sv;
+ struct sigdata sd;
+
+ /* Grab FAR/FSR before enabling interrupts */
+ far = cpu_faultaddress();
+ fsr = cpu_faultstatus();
+
+ /* Update vmmeter statistics */
+ uvmexp.traps++;
+
+ /* Re-enable interrupts if they were enabled previously */
+ if (__predict_true((tf->tf_spsr & I32_bit) == 0))
+ enable_interrupts(I32_bit);
+
+ /* Get the current proc structure or proc0 if there is none */
+ p = (curproc != NULL) ? curproc : &proc0;
+
+ /* Data abort came from user mode? */
+ user = TRAP_USERMODE(tf);
+
+ /* Grab the current pcb */
+ pcb = &p->p_addr->u_pcb;
+
+ /* Invoke the appropriate handler, if necessary */
+ if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) {
+ if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, p,
+ &sd)) {
+ printf("data abort trap fsr %x far %x pc %x\n",
+ fsr, far, tf->tf_pc);
+ goto do_trapsignal;
+ }
+ goto out;
+ }
+
+ /*
+ * At this point, we're dealing with one of the following data aborts:
+ *
+ * FAULT_TRANS_S - Translation -- Section
+ * FAULT_TRANS_P - Translation -- Page
+ * FAULT_DOMAIN_S - Domain -- Section
+ * FAULT_DOMAIN_P - Domain -- Page
+ * FAULT_PERM_S - Permission -- Section
+ * FAULT_PERM_P - Permission -- Page
+ *
+ * These are the main virtual memory-related faults signalled by
+ * the MMU.
+ */
+
+ /* fusubailout is used by [fs]uswintr to avoid page faulting */
+ if (__predict_false(pcb->pcb_onfault == fusubailout)) {
+ tf->tf_r0 = EFAULT;
+ tf->tf_pc = (register_t)pcb->pcb_onfault;
+ return;
+ }
+
+ if (user)
+ p->p_addr->u_pcb.pcb_tf = tf;
+
+ /*
+ * Make sure the Program Counter is sane. We could fall foul of
+ * someone executing Thumb code, in which case the PC might not
+ * be word-aligned. This would cause a kernel alignment fault
+ * further down if we have to decode the current instruction.
+ * XXX: It would be nice to be able to support Thumb at some point.
+ */
+ if (__predict_false((tf->tf_pc & 3) != 0)) {
+ if (user) {
+ /*
+ * Give the user an illegal instruction signal.
+ */
+ /* Deliver a SIGILL to the process */
+ sd.signo = SIGILL;
+ sd.code = ILL_ILLOPC;
+ sd.addr = far;
+ sd.trap = fsr;
+ goto do_trapsignal;
+ }
+
+ /*
+ * The kernel never executes Thumb code.
+ */
+ printf("\ndata_abort_fault: Misaligned Kernel-mode "
+ "Program Counter\n");
+ dab_fatal(tf, fsr, far, p, NULL);
+ }
+
+ /* See if the cpu state needs to be fixed up */
+ switch (data_abort_fixup(tf, fsr, far, p)) {
+ case ABORT_FIXUP_RETURN:
+ return;
+ case ABORT_FIXUP_FAILED:
+ /* Deliver a SIGILL to the process */
+ sd.signo = SIGILL;
+ sd.code = ILL_ILLOPC;
+ sd.addr = far;
+ sd.trap = fsr;
+ goto do_trapsignal;
+ default:
+ break;
+ }
+
+ va = trunc_page((vaddr_t)far);
+
+ /*
+ * It is only a kernel address space fault iff:
+ * 1. user == 0 and
+ * 2. pcb_onfault not set or
+ * 3. pcb_onfault set and not LDRT/LDRBT/STRT/STRBT instruction.
+ */
+ if (user == 0 && (va >= VM_MIN_KERNEL_ADDRESS ||
+ (va < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW)) &&
+ __predict_true((pcb->pcb_onfault == NULL ||
+ (ReadWord(tf->tf_pc) & 0x05200000) != 0x04200000))) {
+ map = kernel_map;
+
+ /* Was the fault due to the FPE/IPKDB ? */
+ if (__predict_false((tf->tf_spsr & PSR_MODE)==PSR_UND32_MODE)) {
+ sd.signo = SIGSEGV;
+ sd.code = SEGV_ACCERR;
+ sd.addr = far;
+ sd.trap = fsr;
+
+ /*
+ * Force exit via userret()
+ * This is necessary as the FPE is an extension to
+ * userland that actually runs in a priveledged mode
+ * but uses USR mode permissions for its accesses.
+ */
+ user = 1;
+ goto do_trapsignal;
+ }
+ } else {
+ map = &p->p_vmspace->vm_map;
+#if 0
+ if (l->l_flag & L_SA) {
+ KDASSERT(l->l_proc->p_sa != NULL);
+ l->l_proc->p_sa->sa_vp_faultaddr = (vaddr_t)far;
+ l->l_flag |= L_SA_PAGEFAULT;
+ }
+#endif
+ }
+
+ /*
+ * We need to know whether the page should be mapped
+ * as R or R/W. The MMU does not give us the info as
+ * to whether the fault was caused by a read or a write.
+ *
+ * However, we know that a permission fault can only be
+ * the result of a write to a read-only location, so
+ * we can deal with those quickly.
+ *
+ * Otherwise we need to disassemble the instruction
+ * responsible to determine if it was a write.
+ */
+ if (IS_PERMISSION_FAULT(fsr))
+ ftype = VM_PROT_WRITE;
+ else {
+ u_int insn = ReadWord(tf->tf_pc);
+
+ if (((insn & 0x0c100000) == 0x04000000) || /* STR/STRB */
+ ((insn & 0x0e1000b0) == 0x000000b0) || /* STRH/STRD */
+ ((insn & 0x0a100000) == 0x08000000)) /* STM/CDT */
+ ftype = VM_PROT_WRITE;
+ else
+ if ((insn & 0x0fb00ff0) == 0x01000090) /* SWP */
+ ftype = VM_PROT_READ | VM_PROT_WRITE;
+ else
+ ftype = VM_PROT_READ;
+ }
+
+ /*
+ * See if the fault is as a result of ref/mod emulation,
+ * or domain mismatch.
+ */
+#ifdef DEBUG
+ last_fault_code = fsr;
+#endif
+ if (pmap_fault_fixup(map->pmap, va, ftype, user)) {
+#if 0
+ if (map != kernel_map)
+ p->p_flag &= ~L_SA_PAGEFAULT;
+#endif
+ goto out;
+ }
+
+ if (__predict_false(current_intr_depth > 0)) {
+ if (pcb->pcb_onfault) {
+ tf->tf_r0 = EINVAL;
+ tf->tf_pc = (register_t) pcb->pcb_onfault;
+ return;
+ }
+ printf("\nNon-emulated page fault with intr_depth > 0\n");
+ dab_fatal(tf, fsr, far, p, NULL);
+ }
+
+ onfault = pcb->pcb_onfault;
+ pcb->pcb_onfault = NULL;
+ error = uvm_fault(map, va, 0, ftype);
+ pcb->pcb_onfault = onfault;
+
+#if 0
+ if (map != kernel_map)
+ p->p_flag &= ~L_SA_PAGEFAULT;
+#endif
+
+ if (__predict_true(error == 0)) {
+ if (user)
+ uvm_grow(p, va); /* Record any stack growth */
+ goto out;
+ }
+
+ if (user == 0) {
+ if (pcb->pcb_onfault) {
+ tf->tf_r0 = error;
+ tf->tf_pc = (register_t) pcb->pcb_onfault;
+ return;
+ }
+
+ printf("\nuvm_fault(%p, %lx, %x, 0) -> %x\n", map, va, ftype,
+ error);
+ dab_fatal(tf, fsr, far, p, NULL);
+ }
+
+
+ sv.sival_ptr = (u_int32_t *)far;
+ if (error == ENOMEM) {
+ printf("UVM: pid %d (%s), uid %d killed: "
+ "out of swap\n", p->p_pid, p->p_comm,
+ (p->p_cred && p->p_ucred) ?
+ p->p_ucred->cr_uid : -1);
+ sd.signo = SIGKILL;
+ } else
+ sd.signo = SIGSEGV;
+
+ sd.code = (error == EACCES) ? SEGV_ACCERR : SEGV_MAPERR;
+ sd.addr = far;
+ sd.trap = fsr;
+do_trapsignal:
+ sv.sival_int = sd.addr;
+ trapsignal(p, sd.signo, sd.trap, sd.code, sv);
+out:
+ /* If returning to user mode, make sure to invoke userret() */
+ if (user)
+ userret(p);
+}
+
+/*
+ * dab_fatal() handles the following data aborts:
+ *
+ * FAULT_WRTBUF_0 - Vector Exception
+ * FAULT_WRTBUF_1 - Terminal Exception
+ *
+ * We should never see these on a properly functioning system.
+ *
+ * This function is also called by the other handlers if they
+ * detect a fatal problem.
+ *
+ * Note: If 'l' is NULL, we assume we're dealing with a prefetch abort.
+ */
+static int
+dab_fatal(trapframe_t *tf, u_int fsr, u_int far, struct proc *p,
+ struct sigdata *sd)
+{
+ const char *mode;
+
+ mode = TRAP_USERMODE(tf) ? "user" : "kernel";
+
+ if (p != NULL) {
+ printf("Fatal %s mode data abort: '%s'\n", mode,
+ data_aborts[fsr & FAULT_TYPE_MASK].desc);
+ printf("trapframe: %p\nFSR=%08x, FAR=", tf, fsr);
+ if ((fsr & FAULT_IMPRECISE) == 0)
+ printf("%08x, ", far);
+ else
+ printf("Invalid, ");
+ printf("spsr=%08x\n", tf->tf_spsr);
+ } else {
+ printf("Fatal %s mode prefetch abort at 0x%08x\n",
+ mode, tf->tf_pc);
+ printf("trapframe: %p, spsr=%08x\n", tf, tf->tf_spsr);
+ }
+
+ printf("r0 =%08x, r1 =%08x, r2 =%08x, r3 =%08x\n",
+ tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3);
+ printf("r4 =%08x, r5 =%08x, r6 =%08x, r7 =%08x\n",
+ tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7);
+ printf("r8 =%08x, r9 =%08x, r10=%08x, r11=%08x\n",
+ tf->tf_r8, tf->tf_r9, tf->tf_r10, tf->tf_r11);
+ printf("r12=%08x, ", tf->tf_r12);
+
+ if (TRAP_USERMODE(tf))
+ printf("usp=%08x, ulr=%08x",
+ tf->tf_usr_sp, tf->tf_usr_lr);
+ else
+ printf("ssp=%08x, slr=%08x",
+ tf->tf_svc_sp, tf->tf_svc_lr);
+ printf(", pc =%08x\n\n", tf->tf_pc);
+
+#if defined(DDB) || defined(KGDB)
+ kdb_trap(T_FAULT, tf);
+#endif
+ panic("Fatal abort");
+ /*NOTREACHED*/
+}
+
+/*
+ * dab_align() handles the following data aborts:
+ *
+ * FAULT_ALIGN_0 - Alignment fault
+ * FAULT_ALIGN_0 - Alignment fault
+ *
+ * These faults are fatal if they happen in kernel mode. Otherwise, we
+ * deliver a bus error to the process.
+ */
+static int
+dab_align(trapframe_t *tf, u_int fsr, u_int far, struct proc *p,
+ struct sigdata *sd)
+{
+ union sigval sv;
+
+ /* Alignment faults are always fatal if they occur in kernel mode */
+ if (!TRAP_USERMODE(tf))
+ dab_fatal(tf, fsr, far, p, NULL);
+
+ /* pcb_onfault *must* be NULL at this point */
+ KDASSERT(p->p_addr->u_pcb.pcb_onfault == NULL);
+
+ /* See if the cpu state needs to be fixed up */
+ (void) data_abort_fixup(tf, fsr, far, p);
+
+ /* Deliver a bus error signal to the process */
+ sd->signo = SIGBUS;
+ sd->code = BUS_ADRALN;
+ sd->addr = far;
+ sd->trap = fsr;
+
+ p->p_addr->u_pcb.pcb_tf = tf;
+
+ sv.sival_ptr = (u_int32_t *)far;
+ trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
+
+ return (1);
+}
+
+/*
+ * dab_buserr() handles the following data aborts:
+ *
+ * FAULT_BUSERR_0 - External Abort on Linefetch -- Section
+ * FAULT_BUSERR_1 - External Abort on Linefetch -- Page
+ * FAULT_BUSERR_2 - External Abort on Non-linefetch -- Section
+ * FAULT_BUSERR_3 - External Abort on Non-linefetch -- Page
+ * FAULT_BUSTRNL1 - External abort on Translation -- Level 1
+ * FAULT_BUSTRNL2 - External abort on Translation -- Level 2
+ *
+ * If pcb_onfault is set, flag the fault and return to the handler.
+ * If the fault occurred in user mode, give the process a SIGBUS.
+ *
+ * Note: On XScale, FAULT_BUSERR_0, FAULT_BUSERR_1, and FAULT_BUSERR_2
+ * can be flagged as imprecise in the FSR. This causes a real headache
+ * since some of the machine state is lost. In this case, tf->tf_pc
+ * may not actually point to the offending instruction. In fact, if
+ * we've taken a double abort fault, it generally points somewhere near
+ * the top of "data_abort_entry" in exception.S.
+ *
+ * In all other cases, these data aborts are considered fatal.
+ */
+static int
+dab_buserr(trapframe_t *tf, u_int fsr, u_int far, struct proc *p,
+ struct sigdata *sd)
+{
+ struct pcb *pcb = &p->p_addr->u_pcb;
+
+#ifdef __XSCALE__
+ if ((fsr & FAULT_IMPRECISE) != 0 &&
+ (tf->tf_spsr & PSR_MODE) == PSR_ABT32_MODE) {
+ /*
+ * Oops, an imprecise, double abort fault. We've lost the
+ * r14_abt/spsr_abt values corresponding to the original
+ * abort, and the spsr saved in the trapframe indicates
+ * ABT mode.
+ */
+ tf->tf_spsr &= ~PSR_MODE;
+
+ /*
+ * We use a simple heuristic to determine if the double abort
+ * happened as a result of a kernel or user mode access.
+ * If the current trapframe is at the top of the kernel stack,
+ * the fault _must_ have come from user mode.
+ */
+ if (tf != ((trapframe_t *)pcb->pcb_un.un_32.pcb32_sp) - 1) {
+ /*
+ * Kernel mode. We're either about to die a
+ * spectacular death, or pcb_onfault will come
+ * to our rescue. Either way, the current value
+ * of tf->tf_pc is irrelevant.
+ */
+ tf->tf_spsr |= PSR_SVC32_MODE;
+ if (pcb->pcb_onfault == NULL)
+ printf("\nKernel mode double abort!\n");
+ } else {
+ /*
+ * User mode. We've lost the program counter at the
+ * time of the fault (not that it was accurate anyway;
+ * it's not called an imprecise fault for nothing).
+ * About all we can do is copy r14_usr to tf_pc and
+ * hope for the best. The process is about to get a
+ * SIGBUS, so it's probably history anyway.
+ */
+ tf->tf_spsr |= PSR_USR32_MODE;
+ tf->tf_pc = tf->tf_usr_lr;
+ }
+ }
+
+ /* FAR is invalid for imprecise exceptions */
+ if ((fsr & FAULT_IMPRECISE) != 0)
+ far = 0;
+#endif /* __XSCALE__ */
+
+ if (pcb->pcb_onfault) {
+ KDASSERT(TRAP_USERMODE(tf) == 0);
+ tf->tf_r0 = EFAULT;
+ tf->tf_pc = (register_t) pcb->pcb_onfault;
+ return (0);
+ }
+
+ /* See if the cpu state needs to be fixed up */
+ (void) data_abort_fixup(tf, fsr, far, p);
+
+ /*
+ * At this point, if the fault happened in kernel mode, we're toast
+ */
+ if (!TRAP_USERMODE(tf))
+ dab_fatal(tf, fsr, far, p, NULL);
+
+ /* Deliver a bus error signal to the process */
+ sd->signo = SIGBUS;
+ sd->code = BUS_ADRERR;
+ sd->addr = far;
+ sd->trap = fsr;
+
+ p->p_addr->u_pcb.pcb_tf = tf;
+
+ return (1);
+}
+
+static __inline int
+prefetch_abort_fixup(trapframe_t *tf)
+{
+#ifdef CPU_ABORT_FIXUP_REQUIRED
+ int error;
+
+ /* Call the cpu specific prefetch abort fixup routine */
+ error = cpu_prefetchabt_fixup(tf);
+ if (__predict_true(error != ABORT_FIXUP_FAILED))
+ return (error);
+
+ /*
+ * Oops, couldn't fix up the instruction
+ */
+ printf(
+ "prefetch_abort_fixup: fixup for %s mode prefetch abort failed.\n",
+ TRAP_USERMODE(tf) ? "user" : "kernel");
+ printf("pc = 0x%08x, opcode 0x%08x, insn = ", tf->tf_pc,
+ *((u_int *)tf->tf_pc));
+ disassemble(tf->tf_pc);
+
+ /* Die now if this happened in kernel mode */
+ if (!TRAP_USERMODE(tf))
+ dab_fatal(tf, 0, tf->tf_pc, NULL, NULL);
+
+ return (error);
+#else
+ return (ABORT_FIXUP_OK);
+#endif /* CPU_ABORT_FIXUP_REQUIRED */
+}
+
+/*
+ * void prefetch_abort_handler(trapframe_t *tf)
+ *
+ * Abort handler called when instruction execution occurs at
+ * a non existent or restricted (access permissions) memory page.
+ * If the address is invalid and we were in SVC mode then panic as
+ * the kernel should never prefetch abort.
+ * If the address is invalid and the page is mapped then the user process
+ * does no have read permission so send it a signal.
+ * Otherwise fault the page in and try again.
+ */
+void
+prefetch_abort_handler(trapframe_t *tf)
+{
+ struct proc *p;
+ struct vm_map *map;
+ vaddr_t fault_pc, va;
+ int error;
+ union sigval sv;
+
+ /* Update vmmeter statistics */
+ uvmexp.traps++;
+
+ /*
+ * Enable IRQ's (disabled by the abort) This always comes
+ * from user mode so we know interrupts were not disabled.
+ * But we check anyway.
+ */
+ if (__predict_true((tf->tf_spsr & I32_bit) == 0))
+ enable_interrupts(I32_bit);
+
+ /* See if the cpu state needs to be fixed up */
+ switch (prefetch_abort_fixup(tf)) {
+ case ABORT_FIXUP_RETURN:
+ return;
+ case ABORT_FIXUP_FAILED:
+ /* Deliver a SIGILL to the process */
+ sv.sival_ptr = (u_int32_t *) tf->tf_pc;
+ trapsignal(p, SIGILL, BUS_ADRERR, ILL_ILLOPC, sv);
+
+ p = curproc;
+ p->p_addr->u_pcb.pcb_tf = tf;
+
+ goto do_trapsignal;
+ default:
+ break;
+ }
+
+ /* Prefetch aborts cannot happen in kernel mode */
+ if (__predict_false(!TRAP_USERMODE(tf)))
+ dab_fatal(tf, 0, tf->tf_pc, NULL, NULL);
+
+ /* Get fault address */
+ fault_pc = tf->tf_pc;
+ p = curproc;
+ p->p_addr->u_pcb.pcb_tf = tf;
+
+ /* Ok validate the address, can only execute in USER space */
+ if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS ||
+ (fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) {
+ sv.sival_ptr = (u_int32_t *)fault_pc;
+ trapsignal(p, SIGSEGV, 0, SEGV_ACCERR, sv);
+ goto do_trapsignal;
+ }
+
+ map = &p->p_vmspace->vm_map;
+ va = trunc_page(fault_pc);
+
+ /*
+ * See if the pmap can handle this fault on its own...
+ */
+#ifdef DEBUG
+ last_fault_code = -1;
+#endif
+ if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1))
+ goto out;
+
+#ifdef DIAGNOSTIC
+ if (__predict_false(current_intr_depth > 0)) {
+ printf("\nNon-emulated prefetch abort with intr_depth > 0\n");
+ dab_fatal(tf, 0, tf->tf_pc, NULL, NULL);
+ }
+#endif
+
+ error = uvm_fault(map, va, 0, VM_PROT_READ);
+ if (__predict_true(error == 0))
+ goto out;
+
+ sv.sival_ptr = (u_int32_t *) fault_pc;
+ if (error == ENOMEM) {
+ printf("UVM: pid %d (%s), uid %d killed: "
+ "out of swap\n", p->p_pid, p->p_comm,
+ (p->p_cred && p->p_ucred) ?
+ p->p_ucred->cr_uid : -1);
+ trapsignal(p, SIGKILL, 0, SEGV_MAPERR, sv);
+ } else
+ trapsignal(p, SIGSEGV, 0, SEGV_MAPERR, sv);
+
+do_trapsignal:
+
+out:
+ userret(p);
+}
+
+/*
+ * Tentatively read an 8, 16, or 32-bit value from 'addr'.
+ * If the read succeeds, the value is written to 'rptr' and zero is returned.
+ * Else, return EFAULT.
+ */
+int
+badaddr_read(void *addr, size_t size, void *rptr)
+{
+ extern int badaddr_read_1(const uint8_t *, uint8_t *);
+ extern int badaddr_read_2(const uint16_t *, uint16_t *);
+ extern int badaddr_read_4(const uint32_t *, uint32_t *);
+ union {
+ uint8_t v1;
+ uint16_t v2;
+ uint32_t v4;
+ } u;
+ int rv;
+
+ cpu_drain_writebuf();
+
+ /* Read from the test address. */
+ switch (size) {
+ case sizeof(uint8_t):
+ rv = badaddr_read_1(addr, &u.v1);
+ if (rv == 0 && rptr)
+ *(uint8_t *) rptr = u.v1;
+ break;
+
+ case sizeof(uint16_t):
+ rv = badaddr_read_2(addr, &u.v2);
+ if (rv == 0 && rptr)
+ *(uint16_t *) rptr = u.v2;
+ break;
+
+ case sizeof(uint32_t):
+ rv = badaddr_read_4(addr, &u.v4);
+ if (rv == 0 && rptr)
+ *(uint32_t *) rptr = u.v4;
+ break;
+
+ default:
+ panic("badaddr: invalid size (%lu)", (u_long) size);
+ }
+
+ /* Return EFAULT if the address was invalid, else zero */
+ return (rv);
+}
diff --git a/sys/arch/arm/arm/fiq.c b/sys/arch/arm/arm/fiq.c
new file mode 100644
index 00000000000..076675aa641
--- /dev/null
+++ b/sys/arch/arm/arm/fiq.c
@@ -0,0 +1,177 @@
+/* $OpenBSD: fiq.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: fiq.c,v 1.5 2002/04/03 23:33:27 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <arm/cpufunc.h>
+#include <arm/fiq.h>
+
+#ifdef __PROG32
+#include <uvm/uvm.h>
+#endif
+
+TAILQ_HEAD(, fiqhandler) fiqhandler_stack =
+ TAILQ_HEAD_INITIALIZER(fiqhandler_stack);
+
+extern char fiqvector[];
+extern char fiq_nullhandler[], fiq_nullhandler_end[];
+
+#ifdef __PROG32
+#define IRQ_BIT I32_bit
+#define FIQ_BIT F32_bit
+#else
+#define IRQ_BIT R15_IRQ_DISABLE
+#define FIQ_BIT R15_FIQ_DISABLE
+#endif /* __PROG32 */
+
+/*
+ * fiq_installhandler:
+ *
+ * Actually install the FIQ handler down at the FIQ vector.
+ *
+ * Note: If the FIQ is invoked via an extra layer of
+ * indirection, the actual FIQ code store lives in the
+ * data segment, so there is no need to manipulate
+ * the vector page's protection.
+ */
+static void
+fiq_installhandler(void *func, size_t size)
+{
+#if defined(__PROG32) && !defined(__ARM_FIQ_INDIRECT)
+ vector_page_setprot(VM_PROT_READ|VM_PROT_WRITE);
+#endif
+
+ memcpy(fiqvector, func, size);
+
+#ifdef __PROG32
+#if !defined(__ARM_FIQ_INDIRECT)
+ vector_page_setprot(VM_PROT_READ);
+#endif
+ cpu_icache_sync_range((vaddr_t) fiqvector, size);
+#endif
+}
+
+/*
+ * fiq_claim:
+ *
+ * Claim the FIQ vector.
+ */
+int
+fiq_claim(struct fiqhandler *fh)
+{
+ struct fiqhandler *ofh;
+ u_int oldirqstate;
+ int error = 0;
+
+ if (fh->fh_size > 0x100)
+ return (EFBIG);
+
+ oldirqstate = disable_interrupts(FIQ_BIT);
+
+ if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) {
+ if ((ofh->fh_flags & FH_CANPUSH) == 0) {
+ error = EBUSY;
+ goto out;
+ }
+
+ /* Save the previous FIQ handler's registers. */
+ if (ofh->fh_regs != NULL)
+ fiq_getregs(ofh->fh_regs);
+ }
+
+ /* Set FIQ mode registers to ours. */
+ if (fh->fh_regs != NULL)
+ fiq_setregs(fh->fh_regs);
+
+ TAILQ_INSERT_HEAD(&fiqhandler_stack, fh, fh_list);
+
+ /* Now copy the actual handler into place. */
+ fiq_installhandler(fh->fh_func, fh->fh_size);
+
+ /* Make sure FIQs are enabled when we return. */
+ oldirqstate &= ~FIQ_BIT;
+
+ out:
+ restore_interrupts(oldirqstate);
+ return (error);
+}
+
+/*
+ * fiq_release:
+ *
+ * Release the FIQ vector.
+ */
+void
+fiq_release(struct fiqhandler *fh)
+{
+ u_int oldirqstate;
+ struct fiqhandler *ofh;
+
+ oldirqstate = disable_interrupts(FIQ_BIT);
+
+ /*
+ * If we are the currently active FIQ handler, then we
+ * need to save our registers and pop the next one back
+ * into the vector.
+ */
+ if (fh == TAILQ_FIRST(&fiqhandler_stack)) {
+ if (fh->fh_regs != NULL)
+ fiq_getregs(fh->fh_regs);
+ TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list);
+ if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) {
+ if (ofh->fh_regs != NULL)
+ fiq_setregs(ofh->fh_regs);
+ fiq_installhandler(ofh->fh_func, ofh->fh_size);
+ }
+ } else
+ TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list);
+
+ if (TAILQ_FIRST(&fiqhandler_stack) == NULL) {
+ /* Copy the NULL handler back down into the vector. */
+ fiq_installhandler(fiq_nullhandler,
+ (size_t)(fiq_nullhandler_end - fiq_nullhandler));
+
+ /* Make sure FIQs are disabled when we return. */
+ oldirqstate |= FIQ_BIT;
+ }
+
+ restore_interrupts(oldirqstate);
+}
diff --git a/sys/arch/arm/arm/fiq_subr.S b/sys/arch/arm/arm/fiq_subr.S
new file mode 100644
index 00000000000..dfdc543c5ff
--- /dev/null
+++ b/sys/arch/arm/arm/fiq_subr.S
@@ -0,0 +1,116 @@
+/* $OpenBSD: fiq_subr.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: fiq_subr.S,v 1.3 2002/04/12 18:50:31 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "assym.h"
+
+#include <arm/armreg.h>
+#include <arm/asm.h>
+#include <arm/cpuconf.h>
+
+/*
+ * MODE_CHANGE_NOP should be inserted between a mode change and a
+ * banked register (R8--R15) access.
+ */
+#if defined(CPU_ARM2) || defined(CPU_ARM250)
+#define MODE_CHANGE_NOP mov r0, r0
+#else
+#define MODE_CHANGE_NOP /* Data sheet says ARM3 doesn't need it */
+#endif
+
+#ifdef __PROG32
+#define SWITCH_TO_FIQ_MODE \
+ mrs r2, cpsr_all ; \
+ mov r3, r2 ; \
+ bic r2, r2, #(PSR_MODE) ; \
+ orr r2, r2, #(PSR_FIQ32_MODE) ; \
+ msr cpsr_all, r2
+#else
+#define SWITCH_TO_FIQ_MODE ; \
+ mov r1, r15 ; \
+ bic r2, r1, #(R15_MODE) ; \
+ teqp r2, #(R15_MODE_FIQ) ; \
+ MODE_CHANGE_NOP
+#endif /* __PROG32 */
+
+#ifdef __PROG32
+#define BACK_TO_SVC_MODE \
+ msr cpsr_all, r3
+#else
+#define BACK_TO_SVC_MODE ; \
+ teqp r1, #0 ; \
+ MODE_CHANGE_NOP
+#endif /* __PROG32 */
+
+/*
+ * fiq_getregs:
+ *
+ * Fetch the FIQ mode banked registers into the fiqhandler
+ * structure.
+ */
+ENTRY(fiq_getregs)
+ SWITCH_TO_FIQ_MODE
+
+ stmia r0, {r8-r13}
+
+ BACK_TO_SVC_MODE
+ mov pc, lr
+
+/*
+ * fiq_setregs:
+ *
+ * Load the FIQ mode banked registers from the fiqhandler
+ * structure.
+ */
+ENTRY(fiq_setregs)
+ SWITCH_TO_FIQ_MODE
+
+ ldmia r0, {r8-r13}
+
+ BACK_TO_SVC_MODE
+ mov pc, lr
+
+/*
+ * fiq_nullhandler:
+ *
+ * Null handler copied down to the FIQ vector when the last
+ * FIQ handler is removed.
+ */
+ .global _C_LABEL(fiq_nullhandler), _C_LABEL(fiq_nullhandler_end)
+_C_LABEL(fiq_nullhandler):
+ subs pc, lr, #4
+_C_LABEL(fiq_nullhandler_end):
diff --git a/sys/arch/arm/arm/fusu.S b/sys/arch/arm/arm/fusu.S
new file mode 100644
index 00000000000..300219843d7
--- /dev/null
+++ b/sys/arch/arm/arm/fusu.S
@@ -0,0 +1,398 @@
+/* $OpenBSD: fusu.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: exception.S,v 1.13 2003/10/31 16:30:15 scw Exp $^I*/$
+
+
+/*
+ * Copyright (c) 1996-1998 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "assym.h"
+#include <machine/asm.h>
+
+#ifdef MULTIPROCESSOR
+.Lcpu_info:
+ .word _C_LABEL(cpu_info)
+#else
+.Lcurpcb:
+ .word _C_LABEL(curpcb)
+#endif
+
+/*
+ * fuword(caddr_t uaddr);
+ * Fetch an int from the user's address space.
+ */
+
+ENTRY(fuword)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r1, .Lfusufault
+ str r1, [r2, #PCB_ONFAULT]
+
+ ldrt r3, [r0]
+
+ mov r1, #0x00000000
+ str r1, [r2, #PCB_ONFAULT]
+ mov r0, r3
+ mov pc, lr
+
+/*
+ * fusword(caddr_t uaddr);
+ * Fetch a short from the user's address space.
+ */
+
+ENTRY(fusword)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r1, .Lfusufault
+ str r1, [r2, #PCB_ONFAULT]
+
+ ldrbt r3, [r0], #1
+ ldrbt ip, [r0]
+#ifdef __ARMEB__
+ orr r0, ip, r3, asl #8
+#else
+ orr r0, r3, ip, asl #8
+#endif
+ mov r1, #0x00000000
+ str r1, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * fuswintr(caddr_t uaddr);
+ * Fetch a short from the user's address space. Can be called during an
+ * interrupt.
+ */
+
+ENTRY(fuswintr)
+ ldr r2, Lblock_userspace_access
+ ldr r2, [r2]
+ teq r2, #0
+ mvnne r0, #0x00000000
+ movne pc, lr
+
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r1, _C_LABEL(fusubailout)
+ str r1, [r2, #PCB_ONFAULT]
+
+ ldrbt r3, [r0], #1
+ ldrbt ip, [r0]
+#ifdef __ARMEB__
+ orr r0, ip, r3, asl #8
+#else
+ orr r0, r3, ip, asl #8
+#endif
+
+ mov r1, #0x00000000
+ str r1, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+Lblock_userspace_access:
+ .word _C_LABEL(block_userspace_access)
+
+ .data
+ .align 0
+ .global _C_LABEL(block_userspace_access)
+_C_LABEL(block_userspace_access):
+ .word 0
+ .text
+
+/*
+ * fubyte(caddr_t uaddr);
+ * Fetch a byte from the user's address space.
+ */
+
+ENTRY(fubyte)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r1, .Lfusufault
+ str r1, [r2, #PCB_ONFAULT]
+
+ ldrbt r3, [r0]
+
+ mov r1, #0x00000000
+ str r1, [r2, #PCB_ONFAULT]
+ mov r0, r3
+ mov pc, lr
+
+/*
+ * Handle faults from [fs]u*(). Clean up and return -1.
+ */
+
+.Lfusufault:
+ mov r0, #0x00000000
+ str r0, [r2, #PCB_ONFAULT]
+ mvn r0, #0x00000000
+ mov pc, lr
+
+/*
+ * Handle faults from [fs]u*(). Clean up and return -1. This differs from
+ * fusufault() in that trap() will recognise it and return immediately rather
+ * than trying to page fault.
+ */
+
+/* label must be global as fault.c references it */
+ .global _C_LABEL(fusubailout)
+_C_LABEL(fusubailout):
+ mov r0, #0x00000000
+ str r0, [r2, #PCB_ONFAULT]
+ mvn r0, #0x00000000
+ mov pc, lr
+
+#ifdef DIAGNOSTIC
+/*
+ * Handle earlier faults from [fs]u*(), due to no pcb
+ */
+
+.Lfusupcbfault:
+ mov r1, r0
+ adr r0, fusupcbfaulttext
+ b _C_LABEL(panic)
+
+fusupcbfaulttext:
+ .asciz "Yikes - no valid PCB during fusuxxx() addr=%08x\n"
+ .align 0
+#endif
+
+/*
+ * suword(caddr_t uaddr, int x);
+ * Store an int in the user's address space.
+ */
+
+ENTRY(suword)
+#ifdef MULTIPROCESSOR
+ /* XXX Probably not appropriate for non-Hydra SMPs */
+ stmfd sp!, {r0, r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r3, .Lfusufault
+ str r3, [r2, #PCB_ONFAULT]
+
+ strt r1, [r0]
+
+ mov r0, #0x00000000
+ str r0, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * suswintr(caddr_t uaddr, short x);
+ * Store a short in the user's address space. Can be called during an
+ * interrupt.
+ */
+
+ENTRY(suswintr)
+ ldr r2, Lblock_userspace_access
+ ldr r2, [r2]
+ teq r2, #0
+ mvnne r0, #0x00000000
+ movne pc, lr
+
+#ifdef MULTIPROCESSOR
+ stmfd sp!, {r0, r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r3, _C_LABEL(fusubailout)
+ str r3, [r2, #PCB_ONFAULT]
+
+#ifdef __ARMEB__
+ mov ip, r1, lsr #8
+ strbt ip, [r0], #1
+#else
+ strbt r1, [r0], #1
+ mov r1, r1, lsr #8
+#endif
+ strbt r1, [r0]
+
+ mov r0, #0x00000000
+ str r0, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * susword(caddr_t uaddr, short x);
+ * Store a short in the user's address space.
+ */
+
+ENTRY(susword)
+#ifdef MULTIPROCESSOR
+ stmfd sp!, {r0, r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r3, .Lfusufault
+ str r3, [r2, #PCB_ONFAULT]
+
+#ifdef __ARMEB__
+ mov ip, r1, lsr #8
+ strbt ip, [r0], #1
+#else
+ strbt r1, [r0], #1
+ mov r1, r1, lsr #8
+#endif
+ strbt r1, [r0]
+
+ mov r0, #0x00000000
+ str r0, [r2, #PCB_ONFAULT]
+ mov pc, lr
+
+/*
+ * subyte(caddr_t uaddr, char x);
+ * Store a byte in the user's address space.
+ */
+
+ENTRY(subyte)
+#ifdef MULTIPROCESSOR
+ stmfd sp!, {r0, r1, r14}
+ bl _C_LABEL(cpu_number)
+ ldr r2, .Lcpu_info
+ ldr r2, [r2, r0, lsl #2]
+ ldr r2, [r2, #CI_CURPCB]
+ ldmfd sp!, {r0, r1, r14}
+#else
+ ldr r2, .Lcurpcb
+ ldr r2, [r2]
+#endif
+
+
+#ifdef DIAGNOSTIC
+ teq r2, #0x00000000
+ beq .Lfusupcbfault
+#endif
+
+ adr r3, .Lfusufault
+ str r3, [r2, #PCB_ONFAULT]
+
+ strbt r1, [r0]
+
+ mov r0, #0x00000000
+ str r0, [r2, #PCB_ONFAULT]
+ mov pc, lr
diff --git a/sys/arch/arm/arm/genassym.cf b/sys/arch/arm/arm/genassym.cf
new file mode 100644
index 00000000000..0a4dff53536
--- /dev/null
+++ b/sys/arch/arm/arm/genassym.cf
@@ -0,0 +1,168 @@
+# $OpenBSD: genassym.cf,v 1.1 2004/02/01 05:09:48 drahn Exp $
+# $NetBSD: genassym.cf,v 1.27 2003/11/04 10:33:16 dsl Exp$
+
+# Copyright (c) 1982, 1990 The Regents of the University of California.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# William Jolitz.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+include <sys/param.h>
+include <sys/proc.h>
+include <sys/systm.h>
+include <sys/mbuf.h>
+include <sys/resourcevar.h>
+include <sys/device.h>
+include <sys/user.h>
+include <sys/signal.h>
+include <sys/mbuf.h>
+include <sys/socketvar.h>
+include <netinet/in.h>
+include <netinet/in_systm.h>
+include <netinet/ip.h>
+include <netinet/ip6.h>
+include <netinet/ip_var.h>
+
+include <machine/cpu.h>
+include <uvm/uvm_extern.h>
+
+include <arm/fiq.h>
+
+include <machine/pmap.h>
+include <machine/frame.h>
+include <machine/vmparam.h>
+
+define __PROG32 1
+ifdef __ARM_FIQ_INDIRECT
+define __ARM_FIQ_INDIRECT 1
+endif
+
+define VM_MIN_ADDRESS VM_MIN_ADDRESS
+define VM_MAXUSER_ADDRESS VM_MAXUSER_ADDRESS
+
+define DOMAIN_CLIENT DOMAIN_CLIENT
+define PMAP_DOMAIN_KERNEL PMAP_DOMAIN_KERNEL
+
+ifdef PMAP_INCLUDE_PTE_SYNC
+define PMAP_INCLUDE_PTE_SYNC 1
+endif
+
+define PAGE_SIZE PAGE_SIZE
+define UPAGES UPAGES
+define PAGE_SHIFT PAGE_SHIFT
+
+# Important offsets into the lwp and proc structs & associated constants
+define P_TRACED P_TRACED
+define P_PROFIL P_PROFIL
+
+define P_FORW offsetof(struct proc, p_forw)
+define P_BACK offsetof(struct proc, p_back)
+define P_ADDR offsetof(struct proc, p_addr)
+define P_PRIORITY offsetof(struct proc, p_priority)
+define P_WCHAN offsetof(struct proc, p_wchan)
+define P_STAT offsetof(struct proc, p_stat)
+
+define PCB_TF offsetof(struct pcb, pcb_tf)
+define PCB_PAGEDIR offsetof(struct pcb, pcb_pagedir)
+define PCB_PL1VEC offsetof(struct pcb, pcb_pl1vec)
+define PCB_L1VEC offsetof(struct pcb, pcb_l1vec)
+define PCB_DACR offsetof(struct pcb, pcb_dacr)
+define PCB_CSTATE offsetof(struct pcb, pcb_cstate)
+define PCB_FLAGS offsetof(struct pcb, pcb_flags)
+define PCB_R8 offsetof(struct pcb, pcb_un.un_32.pcb32_r8)
+define PCB_R9 offsetof(struct pcb, pcb_un.un_32.pcb32_r9)
+define PCB_R10 offsetof(struct pcb, pcb_un.un_32.pcb32_r10)
+define PCB_R11 offsetof(struct pcb, pcb_un.un_32.pcb32_r11)
+define PCB_R12 offsetof(struct pcb, pcb_un.un_32.pcb32_r12)
+define PCB_SP offsetof(struct pcb, pcb_un.un_32.pcb32_sp)
+define PCB_LR offsetof(struct pcb, pcb_un.un_32.pcb32_lr)
+define PCB_PC offsetof(struct pcb, pcb_un.un_32.pcb32_pc)
+define PCB_UND_SP offsetof(struct pcb, pcb_un.un_32.pcb32_und_sp)
+define PCB_ONFAULT offsetof(struct pcb, pcb_onfault)
+define PCB_NOALIGNFLT PCB_NOALIGNFLT
+
+define USER_SIZE sizeof(struct user)
+
+define V_TRAP offsetof(struct uvmexp, traps)
+define V_INTR offsetof(struct uvmexp, intrs)
+define V_SOFT offsetof(struct uvmexp, softs)
+
+define VM_MAP offsetof(struct vmspace, vm_map)
+define VM_PMAP offsetof(struct vmspace, vm_map.pmap)
+
+define CS_TLB_ID offsetof(union pmap_cache_state, cs_tlb_id)
+define CS_TLB_D offsetof(union pmap_cache_state, cs_tlb_d)
+define CS_TLB offsetof(union pmap_cache_state, cs_tlb)
+define CS_CACHE_ID offsetof(union pmap_cache_state, cs_cache_id)
+define CS_CACHE_D offsetof(union pmap_cache_state, cs_cache_d)
+define CS_CACHE offsetof(union pmap_cache_state, cs_cache)
+define CS_ALL offsetof(union pmap_cache_state, cs_all)
+define PMAP_CSTATE offsetof(struct pmap, pm_cstate)
+
+define PR_BASE offsetof(struct uprof, pr_base)
+define PR_SIZE offsetof(struct uprof, pr_size)
+define PR_OFF offsetof(struct uprof, pr_off)
+define PR_SCALE offsetof(struct uprof, pr_scale)
+
+define SIGTRAP SIGTRAP
+define SIGEMT SIGEMT
+
+define SIGF_SC offsetof(struct sigframe, sf_sc)
+
+define TF_R0 offsetof(struct trapframe, tf_r0)
+define TF_R10 offsetof(struct trapframe, tf_r10)
+define TF_PC offsetof(struct trapframe, tf_pc)
+
+define PROCSIZE sizeof(struct proc)
+define TRAPFRAMESIZE sizeof(struct trapframe)
+
+define CF_IDCACHE_WBINV_ALL offsetof(struct cpu_functions, cf_idcache_wbinv_all)
+define CF_DCACHE_WB_RANGE offsetof(struct cpu_functions, cf_dcache_wb_range)
+define CF_TLB_FLUSHID_SE offsetof(struct cpu_functions, cf_tlb_flushID_SE)
+define CF_CONTEXT_SWITCH offsetof(struct cpu_functions, cf_context_switch)
+define CF_SLEEP offsetof(struct cpu_functions, cf_sleep)
+define CF_CONTROL offsetof(struct cpu_functions, cf_control)
+
+#define CI_CURPRIORITY offsetof(struct cpu_info, ci_schedstate.spc_curpriority)
+ifdef MULTIPROCESSOR
+define CI_CURLWP offsetof(struct cpu_info, ci_curlwp)
+define CI_CURPCB offsetof(struct cpu_info, ci_curpcb)
+endif
+if defined(COMPAT_15) && defined(EXEC_AOUT)
+define CI_CTRL offsetof(struct cpu_info, ci_ctrl)
+endif
+
+# Constants required for in_cksum() and friends.
+define M_LEN offsetof(struct mbuf, m_len)
+define M_DATA offsetof(struct mbuf, m_data)
+define M_NEXT offsetof(struct mbuf, m_next)
+define IP_SRC offsetof(struct ip, ip_src)
+define IP_DST offsetof(struct ip, ip_dst)
diff --git a/sys/arch/arm/arm/in_cksum_arm.S b/sys/arch/arm/arm/in_cksum_arm.S
new file mode 100644
index 00000000000..cde73dc4d36
--- /dev/null
+++ b/sys/arch/arm/arm/in_cksum_arm.S
@@ -0,0 +1,471 @@
+/* $OpenBSD: in_cksum_arm.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: in_cksum_arm.S,v 1.3 2003/11/26 10:31:53 rearnsha Exp $ */
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Hand-optimised in_cksum() and in4_cksum() implementations for ARM/Xscale
+ */
+
+#include <machine/asm.h>
+#include "assym.h"
+
+
+/*
+ * int in_cksum(struct mbuf *m, int len)
+ *
+ * Entry:
+ * r0 m
+ * r1 len
+ *
+ * NOTE: Assumes 'm' is *never* NULL.
+ */
+/* LINTSTUB: Func: int in_cksum(struct mbuf *, int) */
+ENTRY(in_cksum)
+ stmfd sp!, {r4-r11,lr}
+ mov r8, #0x00
+ mov r9, r1
+ mov r10, #0x00
+ mov ip, r0
+
+.Lin_cksum_loop:
+ ldr r1, [ip, #(M_LEN)]
+ ldr r0, [ip, #(M_DATA)]
+ ldr ip, [ip, #(M_NEXT)]
+.Lin_cksum_entry4:
+ cmp r9, r1
+ movlt r1, r9
+ sub r9, r9, r1
+ eor r11, r10, r0
+ add r10, r10, r1
+ adds r2, r1, #0x00
+ blne _ASM_LABEL(L_cksumdata)
+ tst r11, #0x01
+ movne r2, r2, ror #8
+ adds r8, r8, r2
+ adc r8, r8, #0x00
+ cmp ip, #0x00
+ bne .Lin_cksum_loop
+
+ mov r1, #0xff
+ orr r1, r1, #0xff00
+ and r0, r8, r1
+ add r0, r0, r8, lsr #16
+ add r0, r0, r0, lsr #16
+ and r0, r0, r1
+ eor r0, r0, r1
+ ldmfd sp!, {r4-r11,pc}
+
+
+#if 0
+ /* ALSO IN in4_cksum.c */
+#ifdef INET
+/*
+ * int in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len)
+ *
+ * Entry:
+ * r0 m
+ * r1 nxt
+ * r2 off
+ * r3 len
+ */
+/* LINTSTUB: Func: int in4_cksum(struct mbuf *, u_int8_t, int, int) */
+ENTRY(in4_cksum)
+ stmfd sp!, {r4-r11,lr}
+ mov r8, #0x00 /* Accumulate sum in r8 */
+
+ /*
+ * First, deal with a pseudo header, if present
+ */
+ ldr r6, [r0, #(M_DATA)]
+ cmp r1, #0x00
+ beq .Lin4_cksum_skip_entry
+
+#ifdef __XSCALE__
+ pld [r6, #(IP_SRC)]
+#endif
+ add r4, r6, #(IP_SRC)
+ ands r4, r4, #0x03
+ add r8, r1, r3 /* sum = nxt + len */
+ addne pc, pc, r4, lsl #5 /* Handle alignment of pseudo header */
+
+ /* 0x00: Data 32-bit aligned */
+ ldr r5, [r6, #(IP_SRC)]
+ ldr r4, [r6, #(IP_DST)]
+ b .Lin4_cksum_add_ips
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* 0x01: Data 8-bit aligned */
+ ldr r4, [r6, #(IP_SRC - 1)] /* BE:r4 = x012 LE:r4 = 210x */
+ ldr r5, [r6, #(IP_SRC + 3)] /* BE:r5 = 3456 LE:r5 = 6543 */
+ ldrb r7, [r6, #(IP_SRC + 7)] /* r7 = ...7 */
+#ifdef __ARMEB__
+ mov r4, r4, lsl #8 /* r4 = 012. */
+ orr r4, r4, r5, lsr #24 /* r4 = 0123 */
+ orr r5, r7, r5, lsl #8 /* r5 = 4567 */
+ b .Lin4_cksum_add_ips
+ nop
+#else
+ mov r4, r4, lsr #8 /* r4 = .210 */
+ orr r4, r4, r5, lsl #24 /* r4 = 3210 */
+ mov r5, r5, lsr #8 /* r5 = .654 */
+ orr r5, r5, r7, lsl #24 /* r5 = 7654 */
+ b .Lin4_cksum_add_ips
+#endif
+
+ /* 0x02: Data 16-bit aligned */
+#ifdef __XSCALE__
+ ldrh r5, [r6, #(IP_SRC)] /* BE:r5 = ..01 LE:r5 = ..10 */
+ ldrh r7, [r6, #(IP_DST + 2)] /* BE:r7 = ..67 LE:r7 = ..76 */
+ ldr r4, [r6, #(IP_SRC + 2)] /* BE:r4 = 2345 LE:r4 = 5432 */
+ orr r5, r7, r5, lsl #16 /* BE:r5 = 0167 LE:r5 = 1076 */
+ b .Lin4_cksum_add_ips
+ nop
+ nop
+ nop
+#else
+ ldr r4, [r6, #(IP_SRC - 2)] /* r4 = 10xx */
+ ldr r7, [r6, #(IP_DST - 2)] /* r7 = xx76 */
+ ldr r5, [r6, #(IP_SRC + 2)] /* r5 = 5432 */
+ mov r4, r4, lsr #16 /* r4 = ..10 */
+ orr r4, r4, r7, lsl #16 /* r4 = 7610 */
+ b .Lin4_cksum_add_ips
+ nop
+ nop
+#endif
+
+ /* 0x03: Data 8-bit aligned */
+ ldrb r4, [r6, #(IP_SRC)] /* r4 = ...0 */
+ ldr r5, [r6, #(IP_SRC + 1)] /* BE:r5 = 1234 LE:r5 = 4321 */
+ ldr r7, [r6, #(IP_SRC + 5)] /* BE:r7 = 567x LE:r7 = x765 */
+#ifdef __ARMEB__
+ mov r4, r4, lsl #24 /* r4 = 0... */
+ orr r4, r4, r5, lsr #8 /* r4 = 0123 */
+ mov r5, r5, lsl #24 /* r5 = 4... */
+ orr r5, r5, r7, lsr #8 /* r5 = 4567 */
+#else
+ orr r4, r4, r5, lsl #8 /* r4 = 3210 */
+ mov r5, r5, lsr #24 /* r4 = ...4 */
+ orr r5, r5, r7, lsl #8 /* r5 = 7654 */
+#endif
+ /* FALLTHROUGH */
+
+.Lin4_cksum_add_ips:
+ adds r5, r5, r4
+#ifndef __ARMEB__
+ adcs r8, r5, r8, lsl #8
+#else
+ adcs r8, r5, r8
+#endif
+ adc r8, r8, #0x00
+ mov r1, #0x00
+ b .Lin4_cksum_skip_entry
+
+.Lin4_cksum_skip_loop:
+ ldr r1, [r0, #(M_LEN)]
+ ldr r6, [r0, #(M_DATA)]
+ ldr r0, [r0, #(M_NEXT)]
+.Lin4_cksum_skip_entry:
+ subs r2, r2, r1
+ blt .Lin4_cksum_skip_done
+ cmp r0, #0x00
+ bne .Lin4_cksum_skip_loop
+ b .Lin4_cksum_whoops
+
+.Lin4_cksum_skip_done:
+ mov ip, r0
+ add r0, r2, r6
+ add r0, r0, r1
+ rsb r1, r2, #0x00
+ mov r9, r3
+ mov r10, #0x00
+ b .Lin_cksum_entry4
+
+.Lin4_cksum_whoops:
+ adr r0, .Lin4_cksum_whoops_str
+ bl _C_LABEL(panic)
+.Lin4_cksum_whoops_str:
+ .asciz "in4_cksum: out of mbufs\n"
+ .align 5
+#endif /* INET */
+#endif
+
+
+/*
+ * The main in*_cksum() workhorse...
+ *
+ * Entry parameters:
+ * r0 Pointer to buffer
+ * r1 Buffer length
+ * lr Return address
+ *
+ * Returns:
+ * r2 Accumulated 32-bit sum
+ *
+ * Clobbers:
+ * r0-r7
+ */
+/* LINTSTUB: Ignore */
+ASENTRY_NP(L_cksumdata)
+#ifdef __XSCALE__
+ pld [r0] /* Pre-fetch the start of the buffer */
+#endif
+ mov r2, #0
+
+ /* We first have to word-align the buffer. */
+ ands r7, r0, #0x03
+ beq .Lcksumdata_wordaligned
+ rsb r7, r7, #0x04
+ cmp r1, r7 /* Enough bytes left to make it? */
+ blt .Lcksumdata_endgame
+ cmp r7, #0x02
+ ldrb r4, [r0], #0x01 /* Fetch 1st byte */
+ ldrgeb r5, [r0], #0x01 /* Fetch 2nd byte */
+ movlt r5, #0x00
+ ldrgtb r6, [r0], #0x01 /* Fetch 3rd byte */
+ movle r6, #0x00
+ /* Combine the three bytes depending on endianness and alignment */
+#ifdef __ARMEB__
+ orreq r2, r5, r4, lsl #8
+ orreq r2, r2, r6, lsl #24
+ orrne r2, r4, r5, lsl #8
+ orrne r2, r2, r6, lsl #16
+#else
+ orreq r2, r4, r5, lsl #8
+ orreq r2, r2, r6, lsl #16
+ orrne r2, r5, r4, lsl #8
+ orrne r2, r2, r6, lsl #24
+#endif
+ subs r1, r1, r7 /* Update length */
+ moveq pc, lr /* All done? */
+
+ /* Buffer is now word aligned */
+.Lcksumdata_wordaligned:
+#ifdef __XSCALE__
+ cmp r1, #0x04 /* Less than 4 bytes left? */
+ blt .Lcksumdata_endgame /* Yup */
+
+ /* Now quad-align, if necessary */
+ ands r7, r0, #0x04
+ ldrne r7, [r0], #0x04
+ subne r1, r1, #0x04
+ subs r1, r1, #0x40
+ blt .Lcksumdata_bigloop_end /* Note: C flag clear if branch taken */
+
+ /*
+ * Buffer is now quad aligned. Sum 64 bytes at a time.
+ * Note: First ldrd is hoisted above the loop, together with
+ * setting r6 to zero to avoid stalling for results in the
+ * loop. (r7 is live, from above).
+ */
+ ldrd r4, [r0], #0x08
+ mov r6, #0x00
+.Lcksumdata_bigloop:
+ pld [r0, #0x18]
+ adds r2, r2, r6
+ adcs r2, r2, r7
+ ldrd r6, [r0], #0x08
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ ldrd r4, [r0], #0x08
+ adcs r2, r2, r6
+ adcs r2, r2, r7
+ ldrd r6, [r0], #0x08
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ ldrd r4, [r0], #0x08
+ adcs r2, r2, r6
+ adcs r2, r2, r7
+ pld [r0, #0x18]
+ ldrd r6, [r0], #0x08
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ ldrd r4, [r0], #0x08
+ adcs r2, r2, r6
+ adcs r2, r2, r7
+ ldrd r6, [r0], #0x08
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ adc r2, r2, #0x00
+ subs r1, r1, #0x40
+ ldrged r4, [r0], #0x08
+ bge .Lcksumdata_bigloop
+
+ adds r2, r2, r6 /* r6/r7 still need summing */
+.Lcksumdata_bigloop_end:
+ adcs r2, r2, r7
+ adc r2, r2, #0x00
+
+#else /* !__XSCALE__ */
+
+ subs r1, r1, #0x40
+ blt .Lcksumdata_bigloop_end
+
+.Lcksumdata_bigloop:
+ ldmia r0!, {r3, r4, r5, r6}
+ adds r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ ldmia r0!, {r3, r4, r5, r7}
+ adcs r2, r2, r6
+ adcs r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ ldmia r0!, {r3, r4, r5, r6}
+ adcs r2, r2, r7
+ adcs r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ ldmia r0!, {r3, r4, r5, r7}
+ adcs r2, r2, r6
+ adcs r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ adcs r2, r2, r7
+ adc r2, r2, #0x00
+ subs r1, r1, #0x40
+ bge .Lcksumdata_bigloop
+.Lcksumdata_bigloop_end:
+#endif
+
+ adds r1, r1, #0x40
+ moveq pc, lr
+ cmp r1, #0x20
+
+#ifdef __XSCALE__
+ ldrged r4, [r0], #0x08 /* Avoid stalling pld and result */
+ blt .Lcksumdata_less_than_32
+ pld [r0, #0x18]
+ ldrd r6, [r0], #0x08
+ adds r2, r2, r4
+ adcs r2, r2, r5
+ ldrd r4, [r0], #0x08
+ adcs r2, r2, r6
+ adcs r2, r2, r7
+ ldrd r6, [r0], #0x08
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ adcs r2, r2, r6 /* XXX: Unavoidable result stall */
+ adcs r2, r2, r7
+#else
+ blt .Lcksumdata_less_than_32
+ ldmia r0!, {r3, r4, r5, r6}
+ adds r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ ldmia r0!, {r3, r4, r5, r7}
+ adcs r2, r2, r6
+ adcs r2, r2, r3
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+ adcs r2, r2, r7
+#endif
+ adc r2, r2, #0x00
+ subs r1, r1, #0x20
+ moveq pc, lr
+
+.Lcksumdata_less_than_32:
+ /* There are less than 32 bytes left */
+ and r3, r1, #0x18
+ rsb r4, r3, #0x18
+ sub r1, r1, r3
+ adds r4, r4, r4, lsr #1 /* Side effect: Clear carry flag */
+ addne pc, pc, r4
+
+/*
+ * Note: We use ldm here, even on Xscale, since the combined issue/result
+ * latencies for ldm and ldrd are the same. Using ldm avoids needless #ifdefs.
+ */
+ /* At least 24 bytes remaining... */
+ ldmia r0!, {r4, r5}
+ nop
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+
+ /* At least 16 bytes remaining... */
+ ldmia r0!, {r4, r5}
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+
+ /* At least 8 bytes remaining... */
+ ldmia r0!, {r4, r5}
+ adcs r2, r2, r4
+ adcs r2, r2, r5
+
+ /* Less than 8 bytes remaining... */
+ adc r2, r2, #0x00
+ subs r1, r1, #0x04
+ blt .Lcksumdata_lessthan4
+
+ ldr r4, [r0], #0x04
+ sub r1, r1, #0x04
+ adds r2, r2, r4
+ adc r2, r2, #0x00
+
+ /* Deal with < 4 bytes remaining */
+.Lcksumdata_lessthan4:
+ adds r1, r1, #0x04
+ moveq pc, lr
+
+ /* Deal with 1 to 3 remaining bytes, possibly misaligned */
+.Lcksumdata_endgame:
+ ldrb r3, [r0] /* Fetch first byte */
+ cmp r1, #0x02
+ ldrgeb r4, [r0, #0x01] /* Fetch 2nd and 3rd as necessary */
+ movlt r4, #0x00
+ ldrgtb r5, [r0, #0x02]
+ movle r5, #0x00
+ /* Combine the three bytes depending on endianness and alignment */
+ tst r0, #0x01
+#ifdef __ARMEB__
+ orreq r3, r4, r3, lsl #8
+ orreq r3, r3, r5, lsl #24
+ orrne r3, r3, r4, lsl #8
+ orrne r3, r3, r5, lsl #16
+#else
+ orreq r3, r3, r4, lsl #8
+ orreq r3, r3, r5, lsl #16
+ orrne r3, r4, r3, lsl #8
+ orrne r3, r3, r5, lsl #24
+#endif
+ adds r2, r2, r3
+ adc r2, r2, #0x00
+ mov pc, lr
diff --git a/sys/arch/arm/arm/irq_dispatch.S b/sys/arch/arm/arm/irq_dispatch.S
new file mode 100644
index 00000000000..72c0dcb4879
--- /dev/null
+++ b/sys/arch/arm/arm/irq_dispatch.S
@@ -0,0 +1,155 @@
+/* $OpenBSD: irq_dispatch.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: irq_dispatch.S,v 1.5 2003/10/30 08:57:24 scw Exp $^I*/$
+
+/*
+ * Copyright (c) 2002 Fujitsu Component Limited
+ * Copyright (c) 2002 Genetec Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "assym.h"
+
+#include <machine/asm.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+
+#ifdef FOOTBRIDGE_INTR
+#include <arm/footbridge/footbridge_intr.h>
+#else
+#error ARM_INTR_IMPL not defined
+#endif
+
+#ifndef ARM_IRQ_HANDLER
+#error ARM_IRQ_HANDLER not defined
+#endif
+
+/*
+ * irq_entry:
+ * Main entry point for the IRQ vector. This is a generic version
+ * which can be used by different platforms.
+ */
+ .text
+ .align 0
+.Lcurrent_intr_depth:
+ .word _C_LABEL(current_intr_depth)
+
+AST_ALIGNMENT_FAULT_LOCALS
+
+ASENTRY_NP(irq_entry)
+ sub lr, lr, #0x00000004 /* Adjust the lr */
+
+ PUSHFRAMEINSVC /* Push an interrupt frame */
+ ENABLE_ALIGNMENT_FAULTS
+
+ /*
+ * Increment the interrupt nesting depth and call the interrupt
+ * dispatch routine. We've pushed a frame, so we can safely use
+ * callee-saved regs here. We use the following registers, which
+ * we expect to presist:
+ *
+ * r5 address of `current_intr_depth' variable
+ * r6 old value of `current_intr_depth'
+ */
+ ldr r5, .Lcurrent_intr_depth
+ mov r0, sp /* arg for dispatcher */
+ ldr r6, [r5]
+ add r1, r6, #1
+ str r1, [r5]
+
+ bl ARM_IRQ_HANDLER
+
+ /*
+ * Restore the old interrupt depth value (which should be the
+ * same as decrementing it at this point).
+ */
+ str r6, [r5]
+
+ DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
+ PULLFRAMEFROMSVCANDEXIT
+ movs pc, lr /* Exit */
+
+ .bss
+ .align 0
+
+ .global _C_LABEL(astpending)
+_C_LABEL(astpending):
+ .word 0
+
+ .global _C_LABEL(current_intr_depth)
+_C_LABEL(current_intr_depth):
+ .word 0
+
+ /*
+ * XXX Provide intrnames/intrcnt for legacy code, but
+ * don't actually use them.
+ */
+
+ .global _C_LABEL(intrnames), _C_LABEL(eintrnames)
+ .global _C_LABEL(intrcnt), _C_LABEL(eintrcnt)
+_C_LABEL(intrnames):
+_C_LABEL(eintrnames):
+
+ .global _C_LABEL(intrcnt), _C_LABEL(sintrcnt), _C_LABEL(eintrcnt)
+_C_LABEL(intrcnt):
+_C_LABEL(eintrcnt):
diff --git a/sys/arch/arm/arm/locore.S b/sys/arch/arm/arm/locore.S
new file mode 100644
index 00000000000..7e7cb356301
--- /dev/null
+++ b/sys/arch/arm/arm/locore.S
@@ -0,0 +1,215 @@
+/* $OpenBSD: locore.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $^I*/$
+
+/*
+ * Copyright (C) 1994-1997 Mark Brinicombe
+ * Copyright (C) 1994 Brini
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of Brini may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "assym.h"
+#include <sys/syscall.h>
+#include <sys/errno.h>
+#include <machine/asm.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+
+/* What size should this really be ? It is only used by init_arm() */
+#define INIT_ARM_STACK_SIZE 2048
+
+/*
+ * This is for kvm_mkdb, and should be the address of the beginning
+ * of the kernel text segment (not necessarily the same as kernbase).
+ */
+
+ .text
+ .align 0
+
+ENTRY_NP(kernel_text)
+
+ASENTRY_NP(start)
+ adr r1, .Lstart
+ ldmia r1, {r1, r2, sp} /* Set initial stack and */
+ sub r2, r2, r1 /* get zero init data */
+ mov r3, #0
+
+.L1:
+ str r3, [r1], #0x0004 /* Zero the bss */
+ subs r2, r2, #4
+ bgt .L1
+
+ mov fp, #0x00000000 /* trace back starts here */
+ bl _C_LABEL(initarm) /* Off we go */
+
+ /* init arm will return the new stack pointer. */
+ mov sp, r0
+
+ mov fp, #0x00000000 /* trace back starts here */
+ mov ip, sp
+ stmfd sp!, {fp, ip, lr, pc}
+ sub fp, ip, #4
+
+ bl _C_LABEL(main) /* call main()! */
+
+ adr r0, .Lmainreturned
+ b _C_LABEL(panic)
+ /* NOTEACHED */
+
+.Lstart:
+ .word _edata
+ .word _end
+ .word svcstk + INIT_ARM_STACK_SIZE
+
+.Lmainreturned:
+ .asciz "main() returned"
+ .align 0
+
+ .bss
+svcstk:
+ .space INIT_ARM_STACK_SIZE
+
+ .text
+ .align 0
+
+#ifndef OFW
+ /* OFW based systems will used OF_boot() */
+
+.Lcpufuncs:
+ .word _C_LABEL(cpufuncs)
+
+ENTRY_NP(cpu_reset)
+ mrs r2, cpsr
+ bic r2, r2, #(PSR_MODE)
+ orr r2, r2, #(PSR_SVC32_MODE)
+ orr r2, r2, #(I32_bit | F32_bit)
+ msr cpsr_all, r2
+
+ ldr r4, .Lcpu_reset_address
+ ldr r4, [r4]
+
+ ldr r0, .Lcpufuncs
+ mov lr, pc
+ ldr pc, [r0, #CF_IDCACHE_WBINV_ALL]
+
+ /*
+ * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
+ * necessary.
+ */
+
+ ldr r1, .Lcpu_reset_needs_v4_MMU_disable
+ ldr r1, [r1]
+ cmp r1, #0
+ mov r2, #0
+
+ /*
+ * MMU & IDC off, 32 bit program & data space
+ * Hurl ourselves into the ROM
+ */
+ mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
+ mcr 15, 0, r0, c1, c0, 0
+ mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */
+ mov pc, r4
+
+ /*
+ * _cpu_reset_address contains the address to branch to, to complete
+ * the cpu reset after turning the MMU off
+ * This variable is provided by the hardware specific code
+ */
+.Lcpu_reset_address:
+ .word _C_LABEL(cpu_reset_address)
+
+ /*
+ * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
+ * v4 MMU disable instruction needs executing... it is an illegal instruction
+ * on f.e. ARM6/7 that locks up the computer in an endless illegal
+ * instruction / data-abort / reset loop.
+ */
+.Lcpu_reset_needs_v4_MMU_disable:
+ .word _C_LABEL(cpu_reset_needs_v4_MMU_disable)
+
+#endif /* OFW */
+
+#ifdef IPKDB
+/*
+ * Execute(inst, psr, args, sp)
+ *
+ * Execute INSTruction with PSR and ARGS[0] - ARGS[3] making
+ * available stack at SP for next undefined instruction trap.
+ *
+ * Move the instruction onto the stack and jump to it.
+ */
+ENTRY_NP(Execute)
+ mov ip, sp
+ stmfd sp!, {r2, r4-r7, fp, ip, lr, pc}
+ sub fp, ip, #4
+ mov ip, r3
+ ldr r7, .Lreturn
+ stmfd sp!, {r0, r7}
+ adr r7, #.LExec
+ mov r5, r1
+ mrs r4, cpsr
+ ldmia r2, {r0-r3}
+ mov r6, sp
+ mov sp, ip
+ msr cpsr_all, r5
+ mov pc, r6
+.LExec:
+ mrs r5, cpsr
+/* XXX Cannot switch thus easily back from user mode */
+ msr cpsr_all, r4
+ add sp, r6, #8
+ ldmfd sp!, {r6}
+ stmia r6, {r0-r3}
+ mov r0, r5
+ ldmdb fp, {r4-r7, fp, sp, pc}
+.Lreturn:
+ mov pc, r7
+#endif
+
+/*
+ * setjump + longjmp
+ */
+ENTRY(setjmp)
+ stmia r0, {r4-r14}
+ mov r0, #0x00000000
+ mov pc, lr
+
+ENTRY(longjmp)
+ ldmia r0, {r4-r14}
+ mov r0, #0x00000001
+ mov pc, lr
+
+ .data
+ .global _C_LABEL(esym)
+_C_LABEL(esym): .word _C_LABEL(end)
+
+ENTRY_NP(abort)
+ b _C_LABEL(abort)
+
+
+/* End of locore.S */
diff --git a/sys/arch/arm/arm/mem.c b/sys/arch/arm/arm/mem.c
new file mode 100644
index 00000000000..3e0936d7d3b
--- /dev/null
+++ b/sys/arch/arm/arm/mem.c
@@ -0,0 +1,249 @@
+/* $OpenBSD: mem.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: mem.c,v 1.11 2003/10/16 12:02:58 jdolecek Exp $^I*/$
+
+/*
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1988 University of Utah.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * the Systems Programming Group of the University of Utah Computer
+ * Science Department.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Memory special file
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/buf.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+
+#include <machine/cpu.h>
+#include <arm/conf.h>
+
+#include <uvm/uvm_extern.h>
+
+extern char *memhook; /* poor name! */
+caddr_t zeropage;
+int physlock;
+
+/*ARGSUSED*/
+int
+mmopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ switch (minor(dev)) {
+ default:
+ break;
+ }
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+mmclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+
+ return (0);
+}
+#define DEV_MEM 0
+#define DEV_KMEM 1
+#define DEV_NULL 2
+#define DEV_ZERO 12
+
+/*ARGSUSED*/
+int
+mmrw(dev, uio, flags)
+ dev_t dev;
+ struct uio *uio;
+ int flags;
+{
+ register vaddr_t o, v;
+ register int c;
+ register struct iovec *iov;
+ int error = 0;
+ vm_prot_t prot;
+
+ if (minor(dev) == DEV_MEM) {
+ /* lock against other uses of shared vmmap */
+ while (physlock > 0) {
+ physlock++;
+ error = tsleep((caddr_t)&physlock, PZERO | PCATCH,
+ "mmrw", 0);
+ if (error)
+ return (error);
+ }
+ physlock = 1;
+ }
+ while (uio->uio_resid > 0 && error == 0) {
+ iov = uio->uio_iov;
+ if (iov->iov_len == 0) {
+ uio->uio_iov++;
+ uio->uio_iovcnt--;
+ if (uio->uio_iovcnt < 0)
+ panic("mmrw");
+ continue;
+ }
+ switch (minor(dev)) {
+
+ case DEV_MEM:
+ v = uio->uio_offset;
+ prot = uio->uio_rw == UIO_READ ? VM_PROT_READ :
+ VM_PROT_WRITE;
+ pmap_enter(pmap_kernel(), (vaddr_t)memhook,
+ trunc_page(v), prot, prot|PMAP_WIRED);
+ pmap_update(pmap_kernel());
+ o = uio->uio_offset & PGOFSET;
+ c = min(uio->uio_resid, (int)(PAGE_SIZE - o));
+ error = uiomove((caddr_t)memhook + o, c, uio);
+ pmap_remove(pmap_kernel(), (vaddr_t)memhook,
+ (vaddr_t)memhook + PAGE_SIZE);
+ pmap_update(pmap_kernel());
+ break;
+
+ case DEV_KMEM:
+ v = uio->uio_offset;
+ c = min(iov->iov_len, MAXPHYS);
+ if (!uvm_kernacc((caddr_t)v, c,
+ uio->uio_rw == UIO_READ ? B_READ : B_WRITE))
+ return (EFAULT);
+ error = uiomove((caddr_t)v, c, uio);
+ break;
+
+ case DEV_NULL:
+ if (uio->uio_rw == UIO_WRITE)
+ uio->uio_resid = 0;
+ return (0);
+
+#ifdef COMPAT_16
+ case _DEV_ZERO_oARM:
+#endif
+ case DEV_ZERO:
+ if (uio->uio_rw == UIO_WRITE) {
+ uio->uio_resid = 0;
+ return (0);
+ }
+ if (zeropage == NULL) {
+ zeropage = (caddr_t)
+ malloc(PAGE_SIZE, M_TEMP, M_WAITOK);
+ memset(zeropage, 0, PAGE_SIZE);
+ }
+ c = min(iov->iov_len, PAGE_SIZE);
+ error = uiomove(zeropage, c, uio);
+ break;
+
+ default:
+ return (ENXIO);
+ }
+ }
+ if (minor(dev) == DEV_MEM) {
+/*unlock:*/
+ if (physlock > 1)
+ wakeup((caddr_t)&physlock);
+ physlock = 0;
+ }
+ return (error);
+}
+
+paddr_t
+mmmmap(dev, off, prot)
+ dev_t dev;
+ off_t off;
+ int prot;
+{
+ struct proc *p = curproc; /* XXX */
+
+ /*
+ * /dev/mem is the only one that makes sense through this
+ * interface. For /dev/kmem any physaddr we return here
+ * could be transient and hence incorrect or invalid at
+ * a later time. /dev/null just doesn't make any sense
+ * and /dev/zero is a hack that is handled via the default
+ * pager in mmap().
+ */
+ if (minor(dev) != DEV_MEM)
+ return (-1);
+
+ /* minor device 0 is physical memory */
+
+ if (off >= ctob(physmem) &&
+ suser(p, 0) != 0)
+ return -1;
+ return arm_btop(off);
+}
+/*ARGSUSED*/
+int
+mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+ return (EOPNOTSUPP);
+}
+
diff --git a/sys/arch/arm/arm/pmap.c b/sys/arch/arm/arm/pmap.c
new file mode 100644
index 00000000000..6c1c4fc23b8
--- /dev/null
+++ b/sys/arch/arm/arm/pmap.c
@@ -0,0 +1,5131 @@
+/* $OpenBSD: pmap.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: pmap.c,v 1.147 2004/01/18 13:03:50 scw Exp $^I*/$
+
+/*
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2002-2003 Wasabi Systems, Inc.
+ * Copyright (c) 2001 Richard Earnshaw
+ * Copyright (c) 2001-2002 Christopher Gilbert
+ * All rights reserved.
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *
+ * RiscBSD kernel project
+ *
+ * pmap.c
+ *
+ * Machine dependant vm stuff
+ *
+ * Created : 20/09/94
+ */
+
+/*
+ * Performance improvements, UVM changes, overhauls and part-rewrites
+ * were contributed by Neil A. Carson <neil@causality.com>.
+ */
+
+/*
+ * Overhauled again to speedup the pmap, use MMU Domains so that L1 tables
+ * can be shared, and re-work the KVM layout, by Steve Woodford of Wasabi
+ * Systems, Inc.
+ *
+ * There are still a few things outstanding at this time:
+ *
+ * - There are some unresolved issues for MP systems:
+ *
+ * o The L1 metadata needs a lock, or more specifically, some places
+ * need to acquire an exclusive lock when modifying L1 translation
+ * table entries.
+ *
+ * o When one cpu modifies an L1 entry, and that L1 table is also
+ * being used by another cpu, then the latter will need to be told
+ * that a tlb invalidation may be necessary. (But only if the old
+ * domain number in the L1 entry being over-written is currently
+ * the active domain on that cpu). I guess there are lots more tlb
+ * shootdown issues too...
+ *
+ * o If the vector_page is at 0x00000000 instead of 0xffff0000, then
+ * MP systems will lose big-time because of the MMU domain hack.
+ * The only way this can be solved (apart from moving the vector
+ * page to 0xffff0000) is to reserve the first 1MB of user address
+ * space for kernel use only. This would require re-linking all
+ * applications so that the text section starts above this 1MB
+ * boundary.
+ *
+ * o Tracking which VM space is resident in the cache/tlb has not yet
+ * been implemented for MP systems.
+ *
+ * o Finally, there is a pathological condition where two cpus running
+ * two separate processes (not procs) which happen to share an L1
+ * can get into a fight over one or more L1 entries. This will result
+ * in a significant slow-down if both processes are in tight loops.
+ */
+
+/*
+ * Special compilation symbols
+ * PMAP_DEBUG - Build in pmap_debug_level code
+ */
+
+/* Include header files */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/user.h>
+#include <sys/pool.h>
+#include <sys/cdefs.h>
+
+#include <uvm/uvm.h>
+
+#include <machine/bus.h>
+#include <machine/pmap.h>
+#include <machine/pcb.h>
+#include <machine/param.h>
+#include <arm/katelib.h>
+#include <arm/cpufunc.h>
+
+#ifdef PMAP_DEBUG
+
+/* XXX need to get rid of all refs to this */
+int pmap_debug_level = 0;
+
+/*
+ * for switching to potentially finer grained debugging
+ */
+#define PDB_FOLLOW 0x0001
+#define PDB_INIT 0x0002
+#define PDB_ENTER 0x0004
+#define PDB_REMOVE 0x0008
+#define PDB_CREATE 0x0010
+#define PDB_PTPAGE 0x0020
+#define PDB_GROWKERN 0x0040
+#define PDB_BITS 0x0080
+#define PDB_COLLECT 0x0100
+#define PDB_PROTECT 0x0200
+#define PDB_MAP_L1 0x0400
+#define PDB_BOOTSTRAP 0x1000
+#define PDB_PARANOIA 0x2000
+#define PDB_WIRING 0x4000
+#define PDB_PVDUMP 0x8000
+#define PDB_VAC 0x10000
+#define PDB_KENTER 0x20000
+#define PDB_KREMOVE 0x40000
+
+int debugmap = 1;
+int pmapdebug = 0;
+#define NPDEBUG(_lev_,_stat_) \
+ if (pmapdebug & (_lev_)) \
+ ((_stat_))
+
+#else /* PMAP_DEBUG */
+#define NPDEBUG(_lev_,_stat_) /* Nothing */
+#endif /* PMAP_DEBUG */
+
+/*
+ * pmap_kernel() points here
+ */
+struct pmap kernel_pmap_store;
+
+/*
+ * Which pmap is currently 'live' in the cache
+ *
+ * XXXSCW: Fix for SMP ...
+ */
+union pmap_cache_state *pmap_cache_state;
+
+/*
+ * Pool and cache that pmap structures are allocated from.
+ * We use a cache to avoid clearing the pm_l2[] array (1KB)
+ * in pmap_create().
+ */
+static struct pool pmap_pmap_pool;
+static struct pool_cache pmap_pmap_cache;
+static LIST_HEAD(, pmap) pmap_pmaps;
+
+/*
+ * Pool of PV structures
+ */
+static struct pool pmap_pv_pool;
+void *pmap_bootstrap_pv_page_alloc(struct pool *, int);
+void pmap_bootstrap_pv_page_free(struct pool *, void *);
+struct pool_allocator pmap_bootstrap_pv_allocator = {
+ pmap_bootstrap_pv_page_alloc, pmap_bootstrap_pv_page_free
+};
+
+/*
+ * Pool and cache of l2_dtable structures.
+ * We use a cache to avoid clearing the structures when they're
+ * allocated. (196 bytes)
+ */
+static struct pool pmap_l2dtable_pool;
+static struct pool_cache pmap_l2dtable_cache;
+static vaddr_t pmap_kernel_l2dtable_kva;
+
+/*
+ * Pool and cache of L2 page descriptors.
+ * We use a cache to avoid clearing the descriptor table
+ * when they're allocated. (1KB)
+ */
+static struct pool pmap_l2ptp_pool;
+static struct pool_cache pmap_l2ptp_cache;
+static vaddr_t pmap_kernel_l2ptp_kva;
+static paddr_t pmap_kernel_l2ptp_phys;
+
+/*
+ * pmap copy/zero page, and mem(5) hook point
+ */
+static pt_entry_t *csrc_pte, *cdst_pte;
+static vaddr_t csrcp, cdstp;
+char *memhook;
+extern caddr_t msgbufaddr;
+
+/*
+ * Flag to indicate if pmap_init() has done its thing
+ */
+boolean_t pmap_initialized;
+
+/*
+ * Misc. locking data structures
+ */
+
+#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+static struct lock pmap_main_lock;
+
+#define PMAP_MAP_TO_HEAD_LOCK() \
+ (void) spinlockmgr(&pmap_main_lock, LK_SHARED, NULL)
+#define PMAP_MAP_TO_HEAD_UNLOCK() \
+ (void) spinlockmgr(&pmap_main_lock, LK_RELEASE, NULL)
+#define PMAP_HEAD_TO_MAP_LOCK() \
+ (void) spinlockmgr(&pmap_main_lock, LK_EXCLUSIVE, NULL)
+#define PMAP_HEAD_TO_MAP_UNLOCK() \
+ spinlockmgr(&pmap_main_lock, LK_RELEASE, (void *) 0)
+#else
+#define PMAP_MAP_TO_HEAD_LOCK() /* null */
+#define PMAP_MAP_TO_HEAD_UNLOCK() /* null */
+#define PMAP_HEAD_TO_MAP_LOCK() /* null */
+#define PMAP_HEAD_TO_MAP_UNLOCK() /* null */
+#endif
+
+#define pmap_acquire_pmap_lock(pm) \
+ do { \
+ if ((pm) != pmap_kernel()) \
+ simple_lock(&(pm)->pm_lock); \
+ } while (/*CONSTCOND*/0)
+
+#define pmap_release_pmap_lock(pm) \
+ do { \
+ if ((pm) != pmap_kernel()) \
+ simple_unlock(&(pm)->pm_lock); \
+ } while (/*CONSTCOND*/0)
+
+
+/*
+ * Metadata for L1 translation tables.
+ */
+struct l1_ttable {
+ /* Entry on the L1 Table list */
+ SLIST_ENTRY(l1_ttable) l1_link;
+
+ /* Entry on the L1 Least Recently Used list */
+ TAILQ_ENTRY(l1_ttable) l1_lru;
+
+ /* Track how many domains are allocated from this L1 */
+ volatile u_int l1_domain_use_count;
+
+ /*
+ * A free-list of domain numbers for this L1.
+ * We avoid using ffs() and a bitmap to track domains since ffs()
+ * is slow on ARM.
+ */
+ u_int8_t l1_domain_first;
+ u_int8_t l1_domain_free[PMAP_DOMAINS];
+
+ /* Physical address of this L1 page table */
+ paddr_t l1_physaddr;
+
+ /* KVA of this L1 page table */
+ pd_entry_t *l1_kva;
+};
+
+/*
+ * Convert a virtual address into its L1 table index. That is, the
+ * index used to locate the L2 descriptor table pointer in an L1 table.
+ * This is basically used to index l1->l1_kva[].
+ *
+ * Each L2 descriptor table represents 1MB of VA space.
+ */
+#define L1_IDX(va) (((vaddr_t)(va)) >> L1_S_SHIFT)
+
+/*
+ * L1 Page Tables are tracked using a Least Recently Used list.
+ * - New L1s are allocated from the HEAD.
+ * - Freed L1s are added to the TAIl.
+ * - Recently accessed L1s (where an 'access' is some change to one of
+ * the userland pmaps which owns this L1) are moved to the TAIL.
+ */
+static TAILQ_HEAD(, l1_ttable) l1_lru_list;
+static struct simplelock l1_lru_lock;
+
+/*
+ * A list of all L1 tables
+ */
+static SLIST_HEAD(, l1_ttable) l1_list;
+
+/*
+ * The l2_dtable tracks L2_BUCKET_SIZE worth of L1 slots.
+ *
+ * This is normally 16MB worth L2 page descriptors for any given pmap.
+ * Reference counts are maintained for L2 descriptors so they can be
+ * freed when empty.
+ */
+struct l2_dtable {
+ /* The number of L2 page descriptors allocated to this l2_dtable */
+ u_int l2_occupancy;
+
+ /* List of L2 page descriptors */
+ struct l2_bucket {
+ pt_entry_t *l2b_kva; /* KVA of L2 Descriptor Table */
+ paddr_t l2b_phys; /* Physical address of same */
+ u_short l2b_l1idx; /* This L2 table's L1 index */
+ u_short l2b_occupancy; /* How many active descriptors */
+ } l2_bucket[L2_BUCKET_SIZE];
+};
+
+/*
+ * Given an L1 table index, calculate the corresponding l2_dtable index
+ * and bucket index within the l2_dtable.
+ */
+#define L2_IDX(l1idx) (((l1idx) >> L2_BUCKET_LOG2) & \
+ (L2_SIZE - 1))
+#define L2_BUCKET(l1idx) ((l1idx) & (L2_BUCKET_SIZE - 1))
+
+/*
+ * Given a virtual address, this macro returns the
+ * virtual address required to drop into the next L2 bucket.
+ */
+#define L2_NEXT_BUCKET(va) (((va) & L1_S_FRAME) + L1_S_SIZE)
+
+/*
+ * L2 allocation.
+ */
+#define pmap_alloc_l2_dtable() \
+ pool_cache_get(&pmap_l2dtable_cache, PR_NOWAIT)
+#define pmap_free_l2_dtable(l2) \
+ pool_cache_put(&pmap_l2dtable_cache, (l2))
+/*
+#define POOL_CACHE_PADDR
+*/
+#ifdef POOL_CACHE_PADDR
+#define pmap_alloc_l2_ptp(pap) \
+ ((pt_entry_t *)pool_cache_get_paddr(&pmap_l2ptp_cache,\
+ PR_NOWAIT, (pap)))
+#else
+static __inline pt_entry_t *
+pmap_alloc_l2_ptp(paddr_t *pap)
+{
+ pt_entry_t * pted;
+
+ pted = pool_cache_get(&pmap_l2ptp_cache, PR_NOWAIT);
+ *pap = vtophys((vaddr_t)pted);
+ return pted;
+}
+#endif /* POOL_CACHE_PADDR */
+
+/*
+ * We try to map the page tables write-through, if possible. However, not
+ * all CPUs have a write-through cache mode, so on those we have to sync
+ * the cache when we frob page tables.
+ *
+ * We try to evaluate this at compile time, if possible. However, it's
+ * not always possible to do that, hence this run-time var.
+ */
+int pmap_needs_pte_sync;
+
+/*
+ * Real definition of pv_entry.
+ */
+struct pv_entry {
+ struct pv_entry *pv_next; /* next pv_entry */
+ pmap_t pv_pmap; /* pmap where mapping lies */
+ vaddr_t pv_va; /* virtual address for mapping */
+ u_int pv_flags; /* flags */
+};
+
+/*
+ * Macro to determine if a mapping might be resident in the
+ * instruction cache and/or TLB
+ */
+#define PV_BEEN_EXECD(f) (((f) & (PVF_REF | PVF_EXEC)) == (PVF_REF | PVF_EXEC))
+
+/*
+ * Macro to determine if a mapping might be resident in the
+ * data cache and/or TLB
+ */
+#define PV_BEEN_REFD(f) (((f) & PVF_REF) != 0)
+
+/*
+ * Local prototypes
+ */
+int pmap_set_pt_cache_mode(pd_entry_t *, vaddr_t);
+void pmap_alloc_specials(vaddr_t *, int, vaddr_t *,
+ pt_entry_t **);
+static boolean_t pmap_is_current(pmap_t);
+static boolean_t pmap_is_cached(pmap_t);
+void pmap_enter_pv(struct vm_page *, struct pv_entry *,
+ pmap_t, vaddr_t, u_int);
+static struct pv_entry *pmap_find_pv(struct vm_page *, pmap_t, vaddr_t);
+struct pv_entry *pmap_remove_pv(struct vm_page *, pmap_t, vaddr_t);
+u_int pmap_modify_pv(struct vm_page *, pmap_t, vaddr_t,
+ u_int, u_int);
+
+void pmap_pinit(pmap_t);
+int pmap_pmap_ctor(void *, void *, int);
+
+void pmap_alloc_l1(pmap_t);
+void pmap_free_l1(pmap_t);
+static void pmap_use_l1(pmap_t);
+
+static struct l2_bucket *pmap_get_l2_bucket(pmap_t, vaddr_t);
+struct l2_bucket *pmap_alloc_l2_bucket(pmap_t, vaddr_t);
+void pmap_free_l2_bucket(pmap_t, struct l2_bucket *, u_int);
+int pmap_l2ptp_ctor(void *, void *, int);
+int pmap_l2dtable_ctor(void *, void *, int);
+
+static void pmap_vac_me_harder(struct vm_page *, pmap_t, vaddr_t);
+void pmap_vac_me_kpmap(struct vm_page *, pmap_t, vaddr_t);
+void pmap_vac_me_user(struct vm_page *, pmap_t, vaddr_t);
+
+void pmap_clearbit(struct vm_page *, u_int);
+int pmap_clean_page(struct pv_entry *, boolean_t);
+void pmap_page_remove(struct vm_page *);
+
+void pmap_init_l1(struct l1_ttable *, pd_entry_t *);
+vaddr_t kernel_pt_lookup(paddr_t);
+
+
+/*
+ * External function prototypes
+ */
+extern void bzero_page(vaddr_t);
+extern void bcopy_page(vaddr_t, vaddr_t);
+
+/*
+ * Misc variables
+ */
+vaddr_t virtual_avail;
+vaddr_t virtual_end;
+vaddr_t pmap_curmaxkvaddr;
+
+vaddr_t avail_start;
+vaddr_t avail_end;
+
+extern pv_addr_t systempage;
+
+/* Function to set the debug level of the pmap code */
+
+#ifdef PMAP_DEBUG
+void
+pmap_debug(int level)
+{
+ pmap_debug_level = level;
+ printf("pmap_debug: level=%d\n", pmap_debug_level);
+}
+#endif /* PMAP_DEBUG */
+
+/*
+ * A bunch of routines to conditionally flush the caches/TLB depending
+ * on whether the specified pmap actually needs to be flushed at any
+ * given time.
+ */
+static __inline void
+pmap_tlb_flushID_SE(pmap_t pm, vaddr_t va)
+{
+
+ if (pm->pm_cstate.cs_tlb_id)
+ cpu_tlb_flushID_SE(va);
+}
+
+static __inline void
+pmap_tlb_flushD_SE(pmap_t pm, vaddr_t va)
+{
+
+ if (pm->pm_cstate.cs_tlb_d)
+ cpu_tlb_flushD_SE(va);
+}
+
+static __inline void
+pmap_tlb_flushID(pmap_t pm)
+{
+
+ if (pm->pm_cstate.cs_tlb_id) {
+ cpu_tlb_flushID();
+ pm->pm_cstate.cs_tlb = 0;
+ }
+}
+
+static __inline void
+pmap_tlb_flushD(pmap_t pm)
+{
+
+ if (pm->pm_cstate.cs_tlb_d) {
+ cpu_tlb_flushD();
+ pm->pm_cstate.cs_tlb_d = 0;
+ }
+}
+
+static __inline void
+pmap_idcache_wbinv_range(pmap_t pm, vaddr_t va, vsize_t len)
+{
+
+ if (pm->pm_cstate.cs_cache_id)
+ cpu_idcache_wbinv_range(va, len);
+}
+
+static __inline void
+pmap_dcache_wb_range(pmap_t pm, vaddr_t va, vsize_t len,
+ boolean_t do_inv, boolean_t rd_only)
+{
+
+ if (pm->pm_cstate.cs_cache_d) {
+ if (do_inv) {
+ if (rd_only)
+ cpu_dcache_inv_range(va, len);
+ else
+ cpu_dcache_wbinv_range(va, len);
+ } else
+ if (!rd_only)
+ cpu_dcache_wb_range(va, len);
+ }
+}
+
+static __inline void
+pmap_idcache_wbinv_all(pmap_t pm)
+{
+
+ if (pm->pm_cstate.cs_cache_id) {
+ cpu_idcache_wbinv_all();
+ pm->pm_cstate.cs_cache = 0;
+ }
+}
+
+static __inline void
+pmap_dcache_wbinv_all(pmap_t pm)
+{
+
+ if (pm->pm_cstate.cs_cache_d) {
+ cpu_dcache_wbinv_all();
+ pm->pm_cstate.cs_cache_d = 0;
+ }
+}
+
+static __inline boolean_t
+pmap_is_current(pmap_t pm)
+{
+
+ if (pm == pmap_kernel() ||
+ (curproc && curproc->p_vmspace->vm_map.pmap == pm))
+ return (TRUE);
+
+ return (FALSE);
+}
+
+static __inline boolean_t
+pmap_is_cached(pmap_t pm)
+{
+
+ if (pm == pmap_kernel() || pmap_cache_state == NULL ||
+ pmap_cache_state == &pm->pm_cstate)
+ return (TRUE);
+
+ return (FALSE);
+}
+
+/*
+ * PTE_SYNC_CURRENT:
+ *
+ * Make sure the pte is written out to RAM.
+ * We need to do this for one of two cases:
+ * - We're dealing with the kernel pmap
+ * - There is no pmap active in the cache/tlb.
+ * - The specified pmap is 'active' in the cache/tlb.
+ */
+#ifdef PMAP_INCLUDE_PTE_SYNC
+#define PTE_SYNC_CURRENT(pm, ptep) \
+do { \
+ if (PMAP_NEEDS_PTE_SYNC && \
+ pmap_is_cached(pm)) \
+ PTE_SYNC(ptep); \
+} while (/*CONSTCOND*/0)
+#else
+#define PTE_SYNC_CURRENT(pm, ptep) /* nothing */
+#endif
+
+/*
+ * main pv_entry manipulation functions:
+ * pmap_enter_pv: enter a mapping onto a vm_page list
+ * pmap_remove_pv: remove a mappiing from a vm_page list
+ *
+ * NOTE: pmap_enter_pv expects to lock the pvh itself
+ * pmap_remove_pv expects te caller to lock the pvh before calling
+ */
+
+/*
+ * pmap_enter_pv: enter a mapping onto a vm_page lst
+ *
+ * => caller should hold the proper lock on pmap_main_lock
+ * => caller should have pmap locked
+ * => we will gain the lock on the vm_page and allocate the new pv_entry
+ * => caller should adjust ptp's wire_count before calling
+ * => caller should not adjust pmap's wire_count
+ */
+void
+pmap_enter_pv(struct vm_page *pg, struct pv_entry *pve, pmap_t pm,
+ vaddr_t va, u_int flags)
+{
+
+ NPDEBUG(PDB_PVDUMP,
+ printf("pmap_enter_pv: pm %p, pg %p, flags 0x%x\n", pm, pg, flags));
+
+ pve->pv_pmap = pm;
+ pve->pv_va = va;
+ pve->pv_flags = flags;
+
+ simple_lock(&pg->mdpage.pvh_slock); /* lock vm_page */
+ pve->pv_next = pg->mdpage.pvh_list; /* add to ... */
+ pg->mdpage.pvh_list = pve; /* ... locked list */
+ pg->mdpage.pvh_attrs |= flags & (PVF_REF | PVF_MOD);
+ if (pm == pmap_kernel()) {
+ if (flags & PVF_WRITE)
+ pg->mdpage.krw_mappings++;
+ else
+ pg->mdpage.kro_mappings++;
+ } else
+ if (flags & PVF_WRITE)
+ pg->mdpage.urw_mappings++;
+ else
+ pg->mdpage.uro_mappings++;
+ simple_unlock(&pg->mdpage.pvh_slock); /* unlock, done! */
+
+ if (pve->pv_flags & PVF_WIRED)
+ ++pm->pm_stats.wired_count;
+}
+
+/*
+ *
+ * pmap_find_pv: Find a pv entry
+ *
+ * => caller should hold lock on vm_page
+ */
+static __inline struct pv_entry *
+pmap_find_pv(struct vm_page *pg, pmap_t pm, vaddr_t va)
+{
+ struct pv_entry *pv;
+
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
+ if (pm == pv->pv_pmap && va == pv->pv_va)
+ break;
+ }
+
+ return (pv);
+}
+
+/*
+ * pmap_remove_pv: try to remove a mapping from a pv_list
+ *
+ * => caller should hold proper lock on pmap_main_lock
+ * => pmap should be locked
+ * => caller should hold lock on vm_page [so that attrs can be adjusted]
+ * => caller should adjust ptp's wire_count and free PTP if needed
+ * => caller should NOT adjust pmap's wire_count
+ * => we return the removed pve
+ */
+struct pv_entry *
+pmap_remove_pv(struct vm_page *pg, pmap_t pm, vaddr_t va)
+{
+ struct pv_entry *pve, **prevptr;
+
+ NPDEBUG(PDB_PVDUMP,
+ printf("pmap_remove_pv: pm %p, pg %p, va 0x%08lx\n", pm, pg, va));
+
+ prevptr = &pg->mdpage.pvh_list; /* previous pv_entry pointer */
+ pve = *prevptr;
+
+ while (pve) {
+ if (pve->pv_pmap == pm && pve->pv_va == va) { /* match? */
+ NPDEBUG(PDB_PVDUMP,
+ printf("pmap_remove_pv: pm %p, pg %p, flags 0x%x\n", pm, pg, pve->pv_flags));
+ *prevptr = pve->pv_next; /* remove it! */
+ if (pve->pv_flags & PVF_WIRED)
+ --pm->pm_stats.wired_count;
+ if (pm == pmap_kernel()) {
+ if (pve->pv_flags & PVF_WRITE)
+ pg->mdpage.krw_mappings--;
+ else
+ pg->mdpage.kro_mappings--;
+ } else
+ if (pve->pv_flags & PVF_WRITE)
+ pg->mdpage.urw_mappings--;
+ else
+ pg->mdpage.uro_mappings--;
+ break;
+ }
+ prevptr = &pve->pv_next; /* previous pointer */
+ pve = pve->pv_next; /* advance */
+ }
+
+ return(pve); /* return removed pve */
+}
+
+/*
+ *
+ * pmap_modify_pv: Update pv flags
+ *
+ * => caller should hold lock on vm_page [so that attrs can be adjusted]
+ * => caller should NOT adjust pmap's wire_count
+ * => caller must call pmap_vac_me_harder() if writable status of a page
+ * may have changed.
+ * => we return the old flags
+ *
+ * Modify a physical-virtual mapping in the pv table
+ */
+u_int
+pmap_modify_pv(struct vm_page *pg, pmap_t pm, vaddr_t va,
+ u_int clr_mask, u_int set_mask)
+{
+ struct pv_entry *npv;
+ u_int flags, oflags;
+
+ if ((npv = pmap_find_pv(pg, pm, va)) == NULL)
+ return (0);
+
+ NPDEBUG(PDB_PVDUMP,
+ printf("pmap_modify_pv: pm %p, pg %p, clr 0x%x, set 0x%x, flags 0x%x\n", pm, pg, clr_mask, set_mask, npv->pv_flags));
+
+ /*
+ * There is at least one VA mapping this page.
+ */
+
+ if (clr_mask & (PVF_REF | PVF_MOD))
+ pg->mdpage.pvh_attrs |= set_mask & (PVF_REF | PVF_MOD);
+
+ oflags = npv->pv_flags;
+ npv->pv_flags = flags = (oflags & ~clr_mask) | set_mask;
+
+ if ((flags ^ oflags) & PVF_WIRED) {
+ if (flags & PVF_WIRED)
+ ++pm->pm_stats.wired_count;
+ else
+ --pm->pm_stats.wired_count;
+ }
+
+ if ((flags ^ oflags) & PVF_WRITE) {
+ if (pm == pmap_kernel()) {
+ if (flags & PVF_WRITE) {
+ pg->mdpage.krw_mappings++;
+ pg->mdpage.kro_mappings--;
+ } else {
+ pg->mdpage.kro_mappings++;
+ pg->mdpage.krw_mappings--;
+ }
+ } else
+ if (flags & PVF_WRITE) {
+ pg->mdpage.urw_mappings++;
+ pg->mdpage.uro_mappings--;
+ } else {
+ pg->mdpage.uro_mappings++;
+ pg->mdpage.urw_mappings--;
+ }
+ }
+
+ return (oflags);
+}
+
+void
+pmap_pinit(pmap_t pm)
+{
+
+ if (vector_page < KERNEL_BASE) {
+ /*
+ * Map the vector page.
+ */
+ pmap_enter(pm, vector_page, systempage.pv_pa,
+ VM_PROT_READ, VM_PROT_READ | PMAP_WIRED);
+ pmap_update(pm);
+ }
+}
+
+/*
+ * Allocate an L1 translation table for the specified pmap.
+ * This is called at pmap creation time.
+ */
+void
+pmap_alloc_l1(pmap_t pm)
+{
+ struct l1_ttable *l1;
+ u_int8_t domain;
+
+ /*
+ * Remove the L1 at the head of the LRU list
+ */
+ simple_lock(&l1_lru_lock);
+ l1 = TAILQ_FIRST(&l1_lru_list);
+ KDASSERT(l1 != NULL);
+ TAILQ_REMOVE(&l1_lru_list, l1, l1_lru);
+
+ /*
+ * Pick the first available domain number, and update
+ * the link to the next number.
+ */
+ domain = l1->l1_domain_first;
+ l1->l1_domain_first = l1->l1_domain_free[domain];
+
+ /*
+ * If there are still free domain numbers in this L1,
+ * put it back on the TAIL of the LRU list.
+ */
+ if (++l1->l1_domain_use_count < PMAP_DOMAINS)
+ TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru);
+
+ simple_unlock(&l1_lru_lock);
+
+ /*
+ * Fix up the relevant bits in the pmap structure
+ */
+ pm->pm_l1 = l1;
+ pm->pm_domain = domain;
+}
+
+/*
+ * Free an L1 translation table.
+ * This is called at pmap destruction time.
+ */
+void
+pmap_free_l1(pmap_t pm)
+{
+ struct l1_ttable *l1 = pm->pm_l1;
+
+ simple_lock(&l1_lru_lock);
+
+ /*
+ * If this L1 is currently on the LRU list, remove it.
+ */
+ if (l1->l1_domain_use_count < PMAP_DOMAINS)
+ TAILQ_REMOVE(&l1_lru_list, l1, l1_lru);
+
+ /*
+ * Free up the domain number which was allocated to the pmap
+ */
+ l1->l1_domain_free[pm->pm_domain] = l1->l1_domain_first;
+ l1->l1_domain_first = pm->pm_domain;
+ l1->l1_domain_use_count--;
+
+ /*
+ * The L1 now must have at least 1 free domain, so add
+ * it back to the LRU list. If the use count is zero,
+ * put it at the head of the list, otherwise it goes
+ * to the tail.
+ */
+ if (l1->l1_domain_use_count == 0)
+ TAILQ_INSERT_HEAD(&l1_lru_list, l1, l1_lru);
+ else
+ TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru);
+
+ simple_unlock(&l1_lru_lock);
+}
+
+static __inline void
+pmap_use_l1(pmap_t pm)
+{
+ struct l1_ttable *l1;
+
+ /*
+ * Do nothing if we're in interrupt context.
+ * Access to an L1 by the kernel pmap must not affect
+ * the LRU list.
+ */
+ if (current_intr_depth || pm == pmap_kernel())
+ return;
+
+ l1 = pm->pm_l1;
+
+ /*
+ * If the L1 is not currently on the LRU list, just return
+ */
+ if (l1->l1_domain_use_count == PMAP_DOMAINS)
+ return;
+
+ simple_lock(&l1_lru_lock);
+
+ /*
+ * Check the use count again, now that we've acquired the lock
+ */
+ if (l1->l1_domain_use_count == PMAP_DOMAINS) {
+ simple_unlock(&l1_lru_lock);
+ return;
+ }
+
+ /*
+ * Move the L1 to the back of the LRU list
+ */
+ TAILQ_REMOVE(&l1_lru_list, l1, l1_lru);
+ TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru);
+
+ simple_unlock(&l1_lru_lock);
+}
+
+/*
+ * void pmap_free_l2_ptp(pt_entry_t *, paddr_t *)
+ *
+ * Free an L2 descriptor table.
+ */
+static __inline void
+#ifndef PMAP_INCLUDE_PTE_SYNC
+pmap_free_l2_ptp(pt_entry_t *l2, paddr_t pa)
+#else
+pmap_free_l2_ptp(boolean_t need_sync, pt_entry_t *l2, paddr_t pa)
+#endif
+{
+#ifdef PMAP_INCLUDE_PTE_SYNC
+ /*
+ * Note: With a write-back cache, we may need to sync this
+ * L2 table before re-using it.
+ * This is because it may have belonged to a non-current
+ * pmap, in which case the cache syncs would have been
+ * skipped when the pages were being unmapped. If the
+ * L2 table were then to be immediately re-allocated to
+ * the *current* pmap, it may well contain stale mappings
+ * which have not yet been cleared by a cache write-back
+ * and so would still be visible to the mmu.
+ */
+ if (need_sync)
+ PTE_SYNC_RANGE(l2, L2_TABLE_SIZE_REAL / sizeof(pt_entry_t));
+#endif
+#ifdef POOL_CACHE_PADDR
+ pool_cache_put_paddr(&pmap_l2ptp_cache, (void *)l2, pa);
+#else
+ pool_cache_put(&pmap_l2ptp_cache, (void *)l2);
+#endif
+}
+
+/*
+ * Returns a pointer to the L2 bucket associated with the specified pmap
+ * and VA, or NULL if no L2 bucket exists for the address.
+ */
+static __inline struct l2_bucket *
+pmap_get_l2_bucket(pmap_t pm, vaddr_t va)
+{
+ struct l2_dtable *l2;
+ struct l2_bucket *l2b;
+ u_short l1idx;
+
+ l1idx = L1_IDX(va);
+
+ if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL ||
+ (l2b = &l2->l2_bucket[L2_BUCKET(l1idx)])->l2b_kva == NULL)
+ return (NULL);
+
+ return (l2b);
+}
+
+/*
+ * Returns a pointer to the L2 bucket associated with the specified pmap
+ * and VA.
+ *
+ * If no L2 bucket exists, perform the necessary allocations to put an L2
+ * bucket/page table in place.
+ *
+ * Note that if a new L2 bucket/page was allocated, the caller *must*
+ * increment the bucket occupancy counter appropriately *before*
+ * releasing the pmap's lock to ensure no other thread or cpu deallocates
+ * the bucket/page in the meantime.
+ */
+struct l2_bucket *
+pmap_alloc_l2_bucket(pmap_t pm, vaddr_t va)
+{
+ struct l2_dtable *l2;
+ struct l2_bucket *l2b;
+ u_short l1idx;
+
+ l1idx = L1_IDX(va);
+
+ if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) {
+ /*
+ * No mapping at this address, as there is
+ * no entry in the L1 table.
+ * Need to allocate a new l2_dtable.
+ */
+ if ((l2 = pmap_alloc_l2_dtable()) == NULL)
+ return (NULL);
+
+ /*
+ * Link it into the parent pmap
+ */
+ pm->pm_l2[L2_IDX(l1idx)] = l2;
+ }
+
+ l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+
+ /*
+ * Fetch pointer to the L2 page table associated with the address.
+ */
+ if (l2b->l2b_kva == NULL) {
+ pt_entry_t *ptep;
+
+ /*
+ * No L2 page table has been allocated. Chances are, this
+ * is because we just allocated the l2_dtable, above.
+ */
+ if ((ptep = pmap_alloc_l2_ptp(&l2b->l2b_phys)) == NULL) {
+ /*
+ * Oops, no more L2 page tables available at this
+ * time. We may need to deallocate the l2_dtable
+ * if we allocated a new one above.
+ */
+ if (l2->l2_occupancy == 0) {
+ pm->pm_l2[L2_IDX(l1idx)] = NULL;
+ pmap_free_l2_dtable(l2);
+ }
+ return (NULL);
+ }
+
+ l2->l2_occupancy++;
+ l2b->l2b_kva = ptep;
+ l2b->l2b_l1idx = l1idx;
+ }
+
+ return (l2b);
+}
+
+/*
+ * One or more mappings in the specified L2 descriptor table have just been
+ * invalidated.
+ *
+ * Garbage collect the metadata and descriptor table itself if necessary.
+ *
+ * The pmap lock must be acquired when this is called (not necessary
+ * for the kernel pmap).
+ */
+void
+pmap_free_l2_bucket(pmap_t pm, struct l2_bucket *l2b, u_int count)
+{
+ struct l2_dtable *l2;
+ pd_entry_t *pl1pd, l1pd;
+ pt_entry_t *ptep;
+ u_short l1idx;
+
+ KDASSERT(count <= l2b->l2b_occupancy);
+
+ /*
+ * Update the bucket's reference count according to how many
+ * PTEs the caller has just invalidated.
+ */
+ l2b->l2b_occupancy -= count;
+
+ /*
+ * Note:
+ *
+ * Level 2 page tables allocated to the kernel pmap are never freed
+ * as that would require checking all Level 1 page tables and
+ * removing any references to the Level 2 page table. See also the
+ * comment elsewhere about never freeing bootstrap L2 descriptors.
+ *
+ * We make do with just invalidating the mapping in the L2 table.
+ *
+ * This isn't really a big deal in practice and, in fact, leads
+ * to a performance win over time as we don't need to continually
+ * alloc/free.
+ */
+ if (l2b->l2b_occupancy > 0 || pm == pmap_kernel())
+ return;
+
+ /*
+ * There are no more valid mappings in this level 2 page table.
+ * Go ahead and NULL-out the pointer in the bucket, then
+ * free the page table.
+ */
+ l1idx = l2b->l2b_l1idx;
+ ptep = l2b->l2b_kva;
+ l2b->l2b_kva = NULL;
+
+ pl1pd = &pm->pm_l1->l1_kva[l1idx];
+
+ /*
+ * If the L1 slot matches the pmap's domain
+ * number, then invalidate it.
+ */
+ l1pd = *pl1pd & (L1_TYPE_MASK | L1_C_DOM_MASK);
+ if (l1pd == (L1_C_DOM(pm->pm_domain) | L1_TYPE_C)) {
+ *pl1pd = 0;
+ PTE_SYNC(pl1pd);
+ }
+
+ /*
+ * Release the L2 descriptor table back to the pool cache.
+ */
+#ifndef PMAP_INCLUDE_PTE_SYNC
+ pmap_free_l2_ptp(ptep, l2b->l2b_phys);
+#else
+ pmap_free_l2_ptp(!pmap_is_cached(pm), ptep, l2b->l2b_phys);
+#endif
+
+ /*
+ * Update the reference count in the associated l2_dtable
+ */
+ l2 = pm->pm_l2[L2_IDX(l1idx)];
+ if (--l2->l2_occupancy > 0)
+ return;
+
+ /*
+ * There are no more valid mappings in any of the Level 1
+ * slots managed by this l2_dtable. Go ahead and NULL-out
+ * the pointer in the parent pmap and free the l2_dtable.
+ */
+ pm->pm_l2[L2_IDX(l1idx)] = NULL;
+ pmap_free_l2_dtable(l2);
+}
+
+/*
+ * Pool cache constructors for L2 descriptor tables, metadata and pmap
+ * structures.
+ */
+int
+pmap_l2ptp_ctor(void *arg, void *v, int flags)
+{
+#ifndef PMAP_INCLUDE_PTE_SYNC
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, pte;
+ vaddr_t va = (vaddr_t)v & ~PGOFSET;
+
+ /*
+ * The mappings for these page tables were initially made using
+ * pmap_kenter_pa() by the pool subsystem. Therefore, the cache-
+ * mode will not be right for page table mappings. To avoid
+ * polluting the pmap_kenter_pa() code with a special case for
+ * page tables, we simply fix up the cache-mode here if it's not
+ * correct.
+ */
+ l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+ KDASSERT(l2b != NULL);
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ pte = *ptep;
+
+ if ((pte & L2_S_CACHE_MASK) != pte_l2_s_cache_mode_pt) {
+ /*
+ * Page tables must have the cache-mode set to Write-Thru.
+ */
+ *ptep = (pte & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode_pt;
+ PTE_SYNC(ptep);
+ cpu_tlb_flushD_SE(va);
+ cpu_cpwait();
+ }
+#endif
+
+ memset(v, 0, L2_TABLE_SIZE_REAL);
+ PTE_SYNC_RANGE(v, L2_TABLE_SIZE_REAL / sizeof(pt_entry_t));
+ return (0);
+}
+
+int
+pmap_l2dtable_ctor(void *arg, void *v, int flags)
+{
+
+ memset(v, 0, sizeof(struct l2_dtable));
+ return (0);
+}
+
+int
+pmap_pmap_ctor(void *arg, void *v, int flags)
+{
+
+ memset(v, 0, sizeof(struct pmap));
+ return (0);
+}
+
+/*
+ * Since we have a virtually indexed cache, we may need to inhibit caching if
+ * there is more than one mapping and at least one of them is writable.
+ * Since we purge the cache on every context switch, we only need to check for
+ * other mappings within the same pmap, or kernel_pmap.
+ * This function is also called when a page is unmapped, to possibly reenable
+ * caching on any remaining mappings.
+ *
+ * The code implements the following logic, where:
+ *
+ * KW = # of kernel read/write pages
+ * KR = # of kernel read only pages
+ * UW = # of user read/write pages
+ * UR = # of user read only pages
+ *
+ * KC = kernel mapping is cacheable
+ * UC = user mapping is cacheable
+ *
+ * KW=0,KR=0 KW=0,KR>0 KW=1,KR=0 KW>1,KR>=0
+ * +---------------------------------------------
+ * UW=0,UR=0 | --- KC=1 KC=1 KC=0
+ * UW=0,UR>0 | UC=1 KC=1,UC=1 KC=0,UC=0 KC=0,UC=0
+ * UW=1,UR=0 | UC=1 KC=0,UC=0 KC=0,UC=0 KC=0,UC=0
+ * UW>1,UR>=0 | UC=0 KC=0,UC=0 KC=0,UC=0 KC=0,UC=0
+ */
+
+static const int pmap_vac_flags[4][4] = {
+ {-1, 0, 0, PVF_KNC},
+ {0, 0, PVF_NC, PVF_NC},
+ {0, PVF_NC, PVF_NC, PVF_NC},
+ {PVF_UNC, PVF_NC, PVF_NC, PVF_NC}
+};
+
+static __inline int
+pmap_get_vac_flags(const struct vm_page *pg)
+{
+ int kidx, uidx;
+
+ kidx = 0;
+ if (pg->mdpage.kro_mappings || pg->mdpage.krw_mappings > 1)
+ kidx |= 1;
+ if (pg->mdpage.krw_mappings)
+ kidx |= 2;
+
+ uidx = 0;
+ if (pg->mdpage.uro_mappings || pg->mdpage.urw_mappings > 1)
+ uidx |= 1;
+ if (pg->mdpage.urw_mappings)
+ uidx |= 2;
+
+ return (pmap_vac_flags[uidx][kidx]);
+}
+
+static __inline void
+pmap_vac_me_harder(struct vm_page *pg, pmap_t pm, vaddr_t va)
+{
+ int nattr;
+
+ nattr = pmap_get_vac_flags(pg);
+
+ if (nattr < 0) {
+ pg->mdpage.pvh_attrs &= ~PVF_NC;
+ return;
+ }
+
+ if (nattr == 0 && (pg->mdpage.pvh_attrs & PVF_NC) == 0)
+ return;
+
+ if (pm == pmap_kernel())
+ pmap_vac_me_kpmap(pg, pm, va);
+ else
+ pmap_vac_me_user(pg, pm, va);
+
+ pg->mdpage.pvh_attrs = (pg->mdpage.pvh_attrs & ~PVF_NC) | nattr;
+}
+
+void
+pmap_vac_me_kpmap(struct vm_page *pg, pmap_t pm, vaddr_t va)
+{
+ u_int u_cacheable, u_entries;
+ struct pv_entry *pv;
+ pmap_t last_pmap = pm;
+
+ /*
+ * Pass one, see if there are both kernel and user pmaps for
+ * this page. Calculate whether there are user-writable or
+ * kernel-writable pages.
+ */
+ u_cacheable = 0;
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
+ if (pv->pv_pmap != pm && (pv->pv_flags & PVF_NC) == 0)
+ u_cacheable++;
+ }
+
+ u_entries = pg->mdpage.urw_mappings + pg->mdpage.uro_mappings;
+
+ /*
+ * We know we have just been updating a kernel entry, so if
+ * all user pages are already cacheable, then there is nothing
+ * further to do.
+ */
+ if (pg->mdpage.k_mappings == 0 && u_cacheable == u_entries)
+ return;
+
+ if (u_entries) {
+ /*
+ * Scan over the list again, for each entry, if it
+ * might not be set correctly, call pmap_vac_me_user
+ * to recalculate the settings.
+ */
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
+ /*
+ * We know kernel mappings will get set
+ * correctly in other calls. We also know
+ * that if the pmap is the same as last_pmap
+ * then we've just handled this entry.
+ */
+ if (pv->pv_pmap == pm || pv->pv_pmap == last_pmap)
+ continue;
+
+ /*
+ * If there are kernel entries and this page
+ * is writable but non-cacheable, then we can
+ * skip this entry also.
+ */
+ if (pg->mdpage.k_mappings &&
+ (pv->pv_flags & (PVF_NC | PVF_WRITE)) ==
+ (PVF_NC | PVF_WRITE))
+ continue;
+
+ /*
+ * Similarly if there are no kernel-writable
+ * entries and the page is already
+ * read-only/cacheable.
+ */
+ if (pg->mdpage.krw_mappings == 0 &&
+ (pv->pv_flags & (PVF_NC | PVF_WRITE)) == 0)
+ continue;
+
+ /*
+ * For some of the remaining cases, we know
+ * that we must recalculate, but for others we
+ * can't tell if they are correct or not, so
+ * we recalculate anyway.
+ */
+ pmap_vac_me_user(pg, (last_pmap = pv->pv_pmap), 0);
+ }
+
+ if (pg->mdpage.k_mappings == 0)
+ return;
+ }
+
+ pmap_vac_me_user(pg, pm, va);
+}
+
+void
+pmap_vac_me_user(struct vm_page *pg, pmap_t pm, vaddr_t va)
+{
+ pmap_t kpmap = pmap_kernel();
+ struct pv_entry *pv, *npv;
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, pte;
+ u_int entries = 0;
+ u_int writable = 0;
+ u_int cacheable_entries = 0;
+ u_int kern_cacheable = 0;
+ u_int other_writable = 0;
+
+ /*
+ * Count mappings and writable mappings in this pmap.
+ * Include kernel mappings as part of our own.
+ * Keep a pointer to the first one.
+ */
+ for (pv = npv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
+ /* Count mappings in the same pmap */
+ if (pm == pv->pv_pmap || kpmap == pv->pv_pmap) {
+ if (entries++ == 0)
+ npv = pv;
+
+ /* Cacheable mappings */
+ if ((pv->pv_flags & PVF_NC) == 0) {
+ cacheable_entries++;
+ if (kpmap == pv->pv_pmap)
+ kern_cacheable++;
+ }
+
+ /* Writable mappings */
+ if (pv->pv_flags & PVF_WRITE)
+ ++writable;
+ } else
+ if (pv->pv_flags & PVF_WRITE)
+ other_writable = 1;
+ }
+
+ /*
+ * Enable or disable caching as necessary.
+ * Note: the first entry might be part of the kernel pmap,
+ * so we can't assume this is indicative of the state of the
+ * other (maybe non-kpmap) entries.
+ */
+ if ((entries > 1 && writable) ||
+ (entries > 0 && pm == kpmap && other_writable)) {
+ if (cacheable_entries == 0)
+ return;
+
+ for (pv = npv; pv; pv = pv->pv_next) {
+ if ((pm != pv->pv_pmap && kpmap != pv->pv_pmap) ||
+ (pv->pv_flags & PVF_NC))
+ continue;
+
+ pv->pv_flags |= PVF_NC;
+
+ l2b = pmap_get_l2_bucket(pv->pv_pmap, pv->pv_va);
+ ptep = &l2b->l2b_kva[l2pte_index(pv->pv_va)];
+ pte = *ptep & ~L2_S_CACHE_MASK;
+
+ if ((va != pv->pv_va || pm != pv->pv_pmap) &&
+ l2pte_valid(pte)) {
+ if (PV_BEEN_EXECD(pv->pv_flags)) {
+ pmap_idcache_wbinv_range(pv->pv_pmap,
+ pv->pv_va, PAGE_SIZE);
+ pmap_tlb_flushID_SE(pv->pv_pmap,
+ pv->pv_va);
+ } else
+ if (PV_BEEN_REFD(pv->pv_flags)) {
+ pmap_dcache_wb_range(pv->pv_pmap,
+ pv->pv_va, PAGE_SIZE, TRUE,
+ (pv->pv_flags & PVF_WRITE) == 0);
+ pmap_tlb_flushD_SE(pv->pv_pmap,
+ pv->pv_va);
+ }
+ }
+
+ *ptep = pte;
+ PTE_SYNC_CURRENT(pv->pv_pmap, ptep);
+ }
+ cpu_cpwait();
+ } else
+ if (entries > cacheable_entries) {
+ /*
+ * Turn cacheing back on for some pages. If it is a kernel
+ * page, only do so if there are no other writable pages.
+ */
+ for (pv = npv; pv; pv = pv->pv_next) {
+ if (!(pv->pv_flags & PVF_NC) || (pm != pv->pv_pmap &&
+ (kpmap != pv->pv_pmap || other_writable)))
+ continue;
+
+ pv->pv_flags &= ~PVF_NC;
+
+ l2b = pmap_get_l2_bucket(pv->pv_pmap, pv->pv_va);
+ ptep = &l2b->l2b_kva[l2pte_index(pv->pv_va)];
+ pte = (*ptep & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode;
+
+ if (l2pte_valid(pte)) {
+ if (PV_BEEN_EXECD(pv->pv_flags)) {
+ pmap_tlb_flushID_SE(pv->pv_pmap,
+ pv->pv_va);
+ } else
+ if (PV_BEEN_REFD(pv->pv_flags)) {
+ pmap_tlb_flushD_SE(pv->pv_pmap,
+ pv->pv_va);
+ }
+ }
+
+ *ptep = pte;
+ PTE_SYNC_CURRENT(pv->pv_pmap, ptep);
+ }
+ }
+}
+
+/*
+ * Modify pte bits for all ptes corresponding to the given physical address.
+ * We use `maskbits' rather than `clearbits' because we're always passing
+ * constants and the latter would require an extra inversion at run-time.
+ */
+void
+pmap_clearbit(struct vm_page *pg, u_int maskbits)
+{
+ struct l2_bucket *l2b;
+ struct pv_entry *pv;
+ pt_entry_t *ptep, npte, opte;
+ pmap_t pm;
+ vaddr_t va;
+ u_int oflags;
+
+ NPDEBUG(PDB_BITS,
+ printf("pmap_clearbit: pg %p (0x%08lx) mask 0x%x\n",
+ pg, pg->phys_addr, maskbits));
+
+ PMAP_HEAD_TO_MAP_LOCK();
+ simple_lock(&pg->mdpage.pvh_slock);
+
+ /*
+ * Clear saved attributes (modify, reference)
+ */
+ pg->mdpage.pvh_attrs &= ~(maskbits & (PVF_MOD | PVF_REF));
+
+ if (pg->mdpage.pvh_list == NULL) {
+ simple_unlock(&pg->mdpage.pvh_slock);
+ PMAP_HEAD_TO_MAP_UNLOCK();
+ return;
+ }
+
+ /*
+ * Loop over all current mappings setting/clearing as appropos
+ */
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
+ va = pv->pv_va;
+ pm = pv->pv_pmap;
+ oflags = pv->pv_flags;
+ pv->pv_flags &= ~maskbits;
+
+ pmap_acquire_pmap_lock(pm);
+
+ l2b = pmap_get_l2_bucket(pm, va);
+ KDASSERT(l2b != NULL);
+
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ npte = opte = *ptep;
+
+ NPDEBUG(PDB_BITS,
+ printf(
+ "pmap_clearbit: pv %p, pm %p, va 0x%08lx, flag 0x%x\n",
+ pv, pv->pv_pmap, pv->pv_va, oflags));
+
+ if (maskbits & (PVF_WRITE|PVF_MOD)) {
+ if ((pv->pv_flags & PVF_NC)) {
+ /*
+ * Entry is not cacheable:
+ *
+ * Don't turn caching on again if this is a
+ * modified emulation. This would be
+ * inconsitent with the settings created by
+ * pmap_vac_me_harder(). Otherwise, it's safe
+ * to re-enable cacheing.
+ *
+ * There's no need to call pmap_vac_me_harder()
+ * here: all pages are losing their write
+ * permission.
+ */
+ if (maskbits & PVF_WRITE) {
+ npte |= pte_l2_s_cache_mode;
+ pv->pv_flags &= ~PVF_NC;
+ }
+ } else
+ if (opte & L2_S_PROT_W) {
+ /*
+ * Entry is writable/cacheable: check if pmap
+ * is current if it is flush it, otherwise it
+ * won't be in the cache
+ */
+ if (PV_BEEN_EXECD(oflags))
+ pmap_idcache_wbinv_range(pm, pv->pv_va,
+ PAGE_SIZE);
+ else
+ if (PV_BEEN_REFD(oflags))
+ pmap_dcache_wb_range(pm, pv->pv_va,
+ PAGE_SIZE,
+ (maskbits & PVF_REF) ? TRUE : FALSE,
+ FALSE);
+ }
+
+ /* make the pte read only */
+ npte &= ~L2_S_PROT_W;
+
+ if (maskbits & PVF_WRITE) {
+ /*
+ * Keep alias accounting up to date
+ */
+ if (pv->pv_pmap == pmap_kernel()) {
+ if (oflags & PVF_WRITE) {
+ pg->mdpage.krw_mappings--;
+ pg->mdpage.kro_mappings++;
+ }
+ } else
+ if (oflags & PVF_WRITE) {
+ pg->mdpage.urw_mappings--;
+ pg->mdpage.uro_mappings++;
+ }
+ }
+ }
+
+ if (maskbits & PVF_REF) {
+ if ((pv->pv_flags & PVF_NC) == 0 &&
+ (maskbits & (PVF_WRITE|PVF_MOD)) == 0) {
+ /*
+ * Check npte here; we may have already
+ * done the wbinv above, and the validity
+ * of the PTE is the same for opte and
+ * npte.
+ */
+ if (npte & L2_S_PROT_W) {
+ if (PV_BEEN_EXECD(oflags))
+ pmap_idcache_wbinv_range(pm,
+ pv->pv_va, PAGE_SIZE);
+ else
+ if (PV_BEEN_REFD(oflags))
+ pmap_dcache_wb_range(pm,
+ pv->pv_va, PAGE_SIZE,
+ TRUE, FALSE);
+ } else
+ if ((npte & L2_TYPE_MASK) != L2_TYPE_INV) {
+ /* XXXJRT need idcache_inv_range */
+ if (PV_BEEN_EXECD(oflags))
+ pmap_idcache_wbinv_range(pm,
+ pv->pv_va, PAGE_SIZE);
+ else
+ if (PV_BEEN_REFD(oflags))
+ pmap_dcache_wb_range(pm,
+ pv->pv_va, PAGE_SIZE,
+ TRUE, TRUE);
+ }
+ }
+
+ /*
+ * Make the PTE invalid so that we will take a
+ * page fault the next time the mapping is
+ * referenced.
+ */
+ npte &= ~L2_TYPE_MASK;
+ npte |= L2_TYPE_INV;
+ }
+
+ if (npte != opte) {
+ *ptep = npte;
+ PTE_SYNC(ptep);
+ /* Flush the TLB entry if a current pmap. */
+ if (PV_BEEN_EXECD(oflags))
+ pmap_tlb_flushID_SE(pm, pv->pv_va);
+ else
+ if (PV_BEEN_REFD(oflags))
+ pmap_tlb_flushD_SE(pm, pv->pv_va);
+ }
+
+ pmap_release_pmap_lock(pm);
+
+ NPDEBUG(PDB_BITS,
+ printf("pmap_clearbit: pm %p va 0x%lx opte 0x%08x npte 0x%08x\n",
+ pm, va, opte, npte));
+ }
+
+ simple_unlock(&pg->mdpage.pvh_slock);
+ PMAP_HEAD_TO_MAP_UNLOCK();
+}
+
+/*
+ * pmap_clean_page()
+ *
+ * This is a local function used to work out the best strategy to clean
+ * a single page referenced by its entry in the PV table. It's used by
+ * pmap_copy_page, pmap_zero page and maybe some others later on.
+ *
+ * Its policy is effectively:
+ * o If there are no mappings, we don't bother doing anything with the cache.
+ * o If there is one mapping, we clean just that page.
+ * o If there are multiple mappings, we clean the entire cache.
+ *
+ * So that some functions can be further optimised, it returns 0 if it didn't
+ * clean the entire cache, or 1 if it did.
+ *
+ * XXX One bug in this routine is that if the pv_entry has a single page
+ * mapped at 0x00000000 a whole cache clean will be performed rather than
+ * just the 1 page. Since this should not occur in everyday use and if it does
+ * it will just result in not the most efficient clean for the page.
+ */
+int
+pmap_clean_page(struct pv_entry *pv, boolean_t is_src)
+{
+ pmap_t pm, pm_to_clean = NULL;
+ struct pv_entry *npv;
+ u_int cache_needs_cleaning = 0;
+ u_int flags = 0;
+ vaddr_t page_to_clean = 0;
+
+ if (pv == NULL) {
+ /* nothing mapped in so nothing to flush */
+ return (0);
+ }
+
+ /*
+ * Since we flush the cache each time we change to a different
+ * user vmspace, we only need to flush the page if it is in the
+ * current pmap.
+ */
+ if (curproc)
+ pm = curproc->p_vmspace->vm_map.pmap;
+ else
+ pm = pmap_kernel();
+
+ for (npv = pv; npv; npv = npv->pv_next) {
+ if (npv->pv_pmap == pmap_kernel() || npv->pv_pmap == pm) {
+ flags |= npv->pv_flags;
+ /*
+ * The page is mapped non-cacheable in
+ * this map. No need to flush the cache.
+ */
+ if (npv->pv_flags & PVF_NC) {
+#ifdef DIAGNOSTIC
+ if (cache_needs_cleaning)
+ panic("pmap_clean_page: "
+ "cache inconsistency");
+#endif
+ break;
+ } else if (is_src && (npv->pv_flags & PVF_WRITE) == 0)
+ continue;
+ if (cache_needs_cleaning) {
+ page_to_clean = 0;
+ break;
+ } else {
+ page_to_clean = npv->pv_va;
+ pm_to_clean = npv->pv_pmap;
+ }
+ cache_needs_cleaning = 1;
+ }
+ }
+
+ if (page_to_clean) {
+ if (PV_BEEN_EXECD(flags))
+ pmap_idcache_wbinv_range(pm_to_clean, page_to_clean,
+ PAGE_SIZE);
+ else
+ pmap_dcache_wb_range(pm_to_clean, page_to_clean,
+ PAGE_SIZE, !is_src, (flags & PVF_WRITE) == 0);
+ } else if (cache_needs_cleaning) {
+ if (PV_BEEN_EXECD(flags))
+ pmap_idcache_wbinv_all(pm);
+ else
+ pmap_dcache_wbinv_all(pm);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Routine: pmap_page_remove
+ * Function:
+ * Removes this physical page from
+ * all physical maps in which it resides.
+ * Reflects back modify bits to the pager.
+ */
+void
+pmap_page_remove(struct vm_page *pg)
+{
+ struct l2_bucket *l2b;
+ struct pv_entry *pv, *npv;
+ pmap_t pm, curpm;
+ pt_entry_t *ptep, pte;
+ boolean_t flush;
+ u_int flags;
+
+ NPDEBUG(PDB_FOLLOW,
+ printf("pmap_page_remove: pg %p (0x%08lx)\n", pg, pg->phys_addr));
+
+ PMAP_HEAD_TO_MAP_LOCK();
+ simple_lock(&pg->mdpage.pvh_slock);
+
+ pv = pg->mdpage.pvh_list;
+ if (pv == NULL) {
+ simple_unlock(&pg->mdpage.pvh_slock);
+ PMAP_HEAD_TO_MAP_UNLOCK();
+ return;
+ }
+
+ /*
+ * Clear alias counts
+ */
+ pg->mdpage.k_mappings = 0;
+ pg->mdpage.urw_mappings = pg->mdpage.uro_mappings = 0;
+
+ flush = FALSE;
+ flags = 0;
+ if (curproc)
+ curpm = curproc->p_vmspace->vm_map.pmap;
+ else
+ curpm = pmap_kernel();
+
+ pmap_clean_page(pv, FALSE);
+
+ while (pv) {
+ pm = pv->pv_pmap;
+ if (flush == FALSE && (pm == curpm || pm == pmap_kernel()))
+ flush = TRUE;
+
+ pmap_acquire_pmap_lock(pm);
+
+ l2b = pmap_get_l2_bucket(pm, pv->pv_va);
+ KDASSERT(l2b != NULL);
+
+ ptep = &l2b->l2b_kva[l2pte_index(pv->pv_va)];
+ pte = *ptep;
+
+ /*
+ * Update statistics
+ */
+ --pm->pm_stats.resident_count;
+
+ /* Wired bit */
+ if (pv->pv_flags & PVF_WIRED)
+ --pm->pm_stats.wired_count;
+
+ flags |= pv->pv_flags;
+
+ /*
+ * Invalidate the PTEs.
+ */
+ *ptep = 0;
+ PTE_SYNC_CURRENT(pm, ptep);
+ pmap_free_l2_bucket(pm, l2b, 1);
+
+ npv = pv->pv_next;
+ pool_put(&pmap_pv_pool, pv);
+ pv = npv;
+ pmap_release_pmap_lock(pm);
+ }
+ pg->mdpage.pvh_list = NULL;
+ simple_unlock(&pg->mdpage.pvh_slock);
+ PMAP_HEAD_TO_MAP_UNLOCK();
+
+ if (flush) {
+ if (PV_BEEN_EXECD(flags))
+ pmap_tlb_flushID(curpm);
+ else
+ pmap_tlb_flushD(curpm);
+ }
+ cpu_cpwait();
+}
+
+/*
+ * pmap_t pmap_create(void)
+ *
+ * Create a new pmap structure from scratch.
+ */
+pmap_t
+pmap_create(void)
+{
+ pmap_t pm;
+
+ pm = pool_cache_get(&pmap_pmap_cache, PR_WAITOK);
+
+ simple_lock_init(&pm->pm_lock);
+ pm->pm_obj.pgops = NULL; /* currently not a mappable object */
+ TAILQ_INIT(&pm->pm_obj.memq);
+ pm->pm_obj.uo_npages = 0;
+ pm->pm_obj.uo_refs = 1;
+ pm->pm_stats.wired_count = 0;
+ pm->pm_stats.resident_count = 1;
+ pm->pm_cstate.cs_all = 0;
+ pmap_alloc_l1(pm);
+
+ /*
+ * Note: The pool cache ensures that the pm_l2[] array is already
+ * initialised to zero.
+ */
+
+ pmap_pinit(pm);
+
+ LIST_INSERT_HEAD(&pmap_pmaps, pm, pm_list);
+
+ return (pm);
+}
+
+/*
+ * void pmap_enter(pmap_t pm, vaddr_t va, paddr_t pa, vm_prot_t prot,
+ * int flags)
+ *
+ * Insert the given physical page (p) at
+ * the specified virtual address (v) in the
+ * target physical map with the protection requested.
+ *
+ * NB: This is the only routine which MAY NOT lazy-evaluate
+ * or lose information. That is, this routine must actually
+ * insert this page into the given map NOW.
+ */
+int
+pmap_enter(pmap_t pm, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
+{
+ struct l2_bucket *l2b;
+ struct vm_page *pg, *opg;
+ struct pv_entry *pve;
+ pt_entry_t *ptep, npte, opte;
+ u_int nflags;
+ u_int oflags;
+
+ NPDEBUG(PDB_ENTER, printf("pmap_enter: pm %p va 0x%lx pa 0x%lx prot %x flag %x\n", pm, va, pa, prot, flags));
+
+ KDASSERT((flags & PMAP_WIRED) == 0 || (flags & VM_PROT_ALL) != 0);
+ KDASSERT(((va | pa) & PGOFSET) == 0);
+
+ /*
+ * Get a pointer to the page. Later on in this function, we
+ * test for a managed page by checking pg != NULL.
+ */
+ pg = pmap_initialized ? PHYS_TO_VM_PAGE(pa) : NULL;
+
+ nflags = 0;
+ if (prot & VM_PROT_WRITE)
+ nflags |= PVF_WRITE;
+ if (prot & VM_PROT_EXECUTE)
+ nflags |= PVF_EXEC;
+ if (flags & PMAP_WIRED)
+ nflags |= PVF_WIRED;
+
+ PMAP_MAP_TO_HEAD_LOCK();
+ pmap_acquire_pmap_lock(pm);
+
+ /*
+ * Fetch the L2 bucket which maps this page, allocating one if
+ * necessary for user pmaps.
+ */
+ if (pm == pmap_kernel())
+ l2b = pmap_get_l2_bucket(pm, va);
+ else
+ l2b = pmap_alloc_l2_bucket(pm, va);
+ if (l2b == NULL) {
+ if (flags & PMAP_CANFAIL) {
+ pmap_release_pmap_lock(pm);
+ PMAP_MAP_TO_HEAD_UNLOCK();
+ return (ENOMEM);
+ }
+ panic("pmap_enter: failed to allocate L2 bucket");
+ }
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ opte = *ptep;
+ npte = pa;
+ oflags = 0;
+
+ if (opte) {
+ /*
+ * There is already a mapping at this address.
+ * If the physical address is different, lookup the
+ * vm_page.
+ */
+ if (l2pte_pa(opte) != pa)
+ opg = PHYS_TO_VM_PAGE(l2pte_pa(opte));
+ else
+ opg = pg;
+ } else
+ opg = NULL;
+
+ if (pg) {
+ /*
+ * This is to be a managed mapping.
+ */
+ if ((flags & VM_PROT_ALL) ||
+ (pg->mdpage.pvh_attrs & PVF_REF)) {
+ /*
+ * - The access type indicates that we don't need
+ * to do referenced emulation.
+ * OR
+ * - The physical page has already been referenced
+ * so no need to re-do referenced emulation here.
+ */
+ npte |= L2_S_PROTO;
+
+ nflags |= PVF_REF;
+
+ if ((prot & VM_PROT_WRITE) != 0 &&
+ ((flags & VM_PROT_WRITE) != 0 ||
+ (pg->mdpage.pvh_attrs & PVF_MOD) != 0)) {
+ /*
+ * This is a writable mapping, and the
+ * page's mod state indicates it has
+ * already been modified. Make it
+ * writable from the outset.
+ */
+ npte |= L2_S_PROT_W;
+ nflags |= PVF_MOD;
+ }
+ } else {
+ /*
+ * Need to do page referenced emulation.
+ */
+ npte |= L2_TYPE_INV;
+ }
+
+ npte |= pte_l2_s_cache_mode;
+
+ if (pg == opg) {
+ /*
+ * We're changing the attrs of an existing mapping.
+ */
+ simple_lock(&pg->mdpage.pvh_slock);
+ oflags = pmap_modify_pv(pg, pm, va,
+ PVF_WRITE | PVF_EXEC | PVF_WIRED |
+ PVF_MOD | PVF_REF, nflags);
+ simple_unlock(&pg->mdpage.pvh_slock);
+
+ /*
+ * We may need to flush the cache if we're
+ * doing rw-ro...
+ */
+ if (pm->pm_cstate.cs_cache_d &&
+ (oflags & PVF_NC) == 0 &&
+ (opte & L2_S_PROT_W) != 0 &&
+ (prot & VM_PROT_WRITE) == 0)
+ cpu_dcache_wb_range(va, PAGE_SIZE);
+ } else {
+ /*
+ * New mapping, or changing the backing page
+ * of an existing mapping.
+ */
+ if (opg) {
+ /*
+ * Replacing an existing mapping with a new one.
+ * It is part of our managed memory so we
+ * must remove it from the PV list
+ */
+ simple_lock(&opg->mdpage.pvh_slock);
+ pve = pmap_remove_pv(opg, pm, va);
+ pmap_vac_me_harder(opg, pm, 0);
+ simple_unlock(&opg->mdpage.pvh_slock);
+ oflags = pve->pv_flags;
+
+ /*
+ * If the old mapping was valid (ref/mod
+ * emulation creates 'invalid' mappings
+ * initially) then make sure to frob
+ * the cache.
+ */
+ if ((oflags & PVF_NC) == 0 &&
+ l2pte_valid(opte)) {
+ if (PV_BEEN_EXECD(oflags)) {
+ pmap_idcache_wbinv_range(pm, va,
+ PAGE_SIZE);
+ } else
+ if (PV_BEEN_REFD(oflags)) {
+ pmap_dcache_wb_range(pm, va,
+ PAGE_SIZE, TRUE,
+ (oflags & PVF_WRITE) == 0);
+ }
+ }
+ } else
+ if ((pve = pool_get(&pmap_pv_pool, PR_NOWAIT)) == NULL){
+ if ((flags & PMAP_CANFAIL) == 0)
+ panic("pmap_enter: no pv entries");
+
+ if (pm != pmap_kernel())
+ pmap_free_l2_bucket(pm, l2b, 0);
+ pmap_release_pmap_lock(pm);
+ PMAP_MAP_TO_HEAD_UNLOCK();
+ NPDEBUG(PDB_ENTER,
+ printf("pmap_enter: ENOMEM\n"));
+ return (ENOMEM);
+ }
+
+ pmap_enter_pv(pg, pve, pm, va, nflags);
+ }
+ } else {
+ /*
+ * We're mapping an unmanaged page.
+ * These are always readable, and possibly writable, from
+ * the get go as we don't need to track ref/mod status.
+ */
+ npte |= L2_S_PROTO;
+ if (prot & VM_PROT_WRITE)
+ npte |= L2_S_PROT_W;
+
+ /*
+ * Make sure the vector table is mapped cacheable
+ */
+ if (pm != pmap_kernel() && va == vector_page)
+ npte |= pte_l2_s_cache_mode;
+
+ if (opg) {
+ /*
+ * Looks like there's an existing 'managed' mapping
+ * at this address.
+ */
+ simple_lock(&opg->mdpage.pvh_slock);
+ pve = pmap_remove_pv(opg, pm, va);
+ pmap_vac_me_harder(opg, pm, 0);
+ simple_unlock(&opg->mdpage.pvh_slock);
+ oflags = pve->pv_flags;
+
+ if ((oflags & PVF_NC) == 0 && l2pte_valid(opte)) {
+ if (PV_BEEN_EXECD(oflags))
+ pmap_idcache_wbinv_range(pm, va,
+ PAGE_SIZE);
+ else
+ if (PV_BEEN_REFD(oflags))
+ pmap_dcache_wb_range(pm, va, PAGE_SIZE,
+ TRUE, (oflags & PVF_WRITE) == 0);
+ }
+ pool_put(&pmap_pv_pool, pve);
+ }
+ }
+
+ /*
+ * Make sure userland mappings get the right permissions
+ */
+ if (pm != pmap_kernel() && va != vector_page)
+ npte |= L2_S_PROT_U;
+
+ /*
+ * Keep the stats up to date
+ */
+ if (opte == 0) {
+ l2b->l2b_occupancy++;
+ pm->pm_stats.resident_count++;
+ }
+
+ NPDEBUG(PDB_ENTER,
+ printf("pmap_enter: opte 0x%08x npte 0x%08x\n", opte, npte));
+
+ /*
+ * If this is just a wiring change, the two PTEs will be
+ * identical, so there's no need to update the page table.
+ */
+ if (npte != opte) {
+ boolean_t is_cached = pmap_is_cached(pm);
+
+ *ptep = npte;
+ if (is_cached) {
+ /*
+ * We only need to frob the cache/tlb if this pmap
+ * is current
+ */
+ PTE_SYNC(ptep);
+ if (va != vector_page && l2pte_valid(npte)) {
+ /*
+ * This mapping is likely to be accessed as
+ * soon as we return to userland. Fix up the
+ * L1 entry to avoid taking another
+ * page/domain fault.
+ */
+ pd_entry_t *pl1pd, l1pd;
+
+ pl1pd = &pm->pm_l1->l1_kva[L1_IDX(va)];
+ l1pd = l2b->l2b_phys | L1_C_DOM(pm->pm_domain) |
+ L1_C_PROTO;
+ if (*pl1pd != l1pd) {
+ *pl1pd = l1pd;
+ PTE_SYNC(pl1pd);
+ }
+ }
+ }
+
+ if (PV_BEEN_EXECD(oflags))
+ pmap_tlb_flushID_SE(pm, va);
+ else
+ if (PV_BEEN_REFD(oflags))
+ pmap_tlb_flushD_SE(pm, va);
+
+ NPDEBUG(PDB_ENTER,
+ printf("pmap_enter: is_cached %d cs 0x%08x\n",
+ is_cached, pm->pm_cstate.cs_all));
+
+ if (pg != NULL) {
+ simple_lock(&pg->mdpage.pvh_slock);
+ pmap_vac_me_harder(pg, pm, va);
+ simple_unlock(&pg->mdpage.pvh_slock);
+ }
+ }
+
+ pmap_release_pmap_lock(pm);
+ PMAP_MAP_TO_HEAD_UNLOCK();
+
+ return (0);
+}
+
+/*
+ * pmap_remove()
+ *
+ * pmap_remove is responsible for nuking a number of mappings for a range
+ * of virtual address space in the current pmap. To do this efficiently
+ * is interesting, because in a number of cases a wide virtual address
+ * range may be supplied that contains few actual mappings. So, the
+ * optimisations are:
+ * 1. Skip over hunks of address space for which no L1 or L2 entry exists.
+ * 2. Build up a list of pages we've hit, up to a maximum, so we can
+ * maybe do just a partial cache clean. This path of execution is
+ * complicated by the fact that the cache must be flushed _before_
+ * the PTE is nuked, being a VAC :-)
+ * 3. If we're called after UVM calls pmap_remove_all(), we can defer
+ * all invalidations until pmap_update(), since pmap_remove_all() has
+ * already flushed the cache.
+ * 4. Maybe later fast-case a single page, but I don't think this is
+ * going to make _that_ much difference overall.
+ */
+
+#define PMAP_REMOVE_CLEAN_LIST_SIZE 3
+
+void
+pmap_remove(pmap_t pm, vaddr_t sva, vaddr_t eva)
+{
+ struct l2_bucket *l2b;
+ vaddr_t next_bucket;
+ pt_entry_t *ptep;
+ u_int cleanlist_idx, total, cnt;
+ struct {
+ vaddr_t va;
+ pt_entry_t *pte;
+ } cleanlist[PMAP_REMOVE_CLEAN_LIST_SIZE];
+ u_int mappings, is_exec, is_refd;
+
+ NPDEBUG(PDB_REMOVE, printf("pmap_remove: pmap=%p sva=%08lx eva=%08lx\n",
+ pm, sva, eva));
+
+ /*
+ * we lock in the pmap => pv_head direction
+ */
+ PMAP_MAP_TO_HEAD_LOCK();
+ pmap_acquire_pmap_lock(pm);
+
+ if (pm->pm_remove_all || !pmap_is_cached(pm)) {
+ cleanlist_idx = PMAP_REMOVE_CLEAN_LIST_SIZE + 1;
+ if (pm->pm_cstate.cs_tlb == 0)
+ pm->pm_remove_all = TRUE;
+ } else
+ cleanlist_idx = 0;
+
+ total = 0;
+
+ while (sva < eva) {
+ /*
+ * Do one L2 bucket's worth at a time.
+ */
+ next_bucket = L2_NEXT_BUCKET(sva);
+ if (next_bucket > eva)
+ next_bucket = eva;
+
+ l2b = pmap_get_l2_bucket(pm, sva);
+ if (l2b == NULL) {
+ sva = next_bucket;
+ continue;
+ }
+
+ ptep = &l2b->l2b_kva[l2pte_index(sva)];
+ mappings = 0;
+
+ while (sva < next_bucket) {
+ struct vm_page *pg;
+ pt_entry_t pte;
+ paddr_t pa;
+
+ pte = *ptep;
+
+ if (pte == 0) {
+ /*
+ * Nothing here, move along
+ */
+ sva += PAGE_SIZE;
+ ptep++;
+ continue;
+ }
+
+ pm->pm_stats.resident_count--;
+ pa = l2pte_pa(pte);
+ is_exec = 0;
+ is_refd = 1;
+
+ /*
+ * Update flags. In a number of circumstances,
+ * we could cluster a lot of these and do a
+ * number of sequential pages in one go.
+ */
+ if ((pg = PHYS_TO_VM_PAGE(pa)) != NULL) {
+ struct pv_entry *pve;
+ simple_lock(&pg->mdpage.pvh_slock);
+ pve = pmap_remove_pv(pg, pm, sva);
+ pmap_vac_me_harder(pg, pm, 0);
+ simple_unlock(&pg->mdpage.pvh_slock);
+ if (pve != NULL) {
+ if (pm->pm_remove_all == FALSE) {
+ is_exec =
+ PV_BEEN_EXECD(pve->pv_flags);
+ is_refd =
+ PV_BEEN_REFD(pve->pv_flags);
+ }
+ pool_put(&pmap_pv_pool, pve);
+ }
+ }
+
+ if (!l2pte_valid(pte)) {
+ *ptep = 0;
+ PTE_SYNC_CURRENT(pm, ptep);
+ sva += PAGE_SIZE;
+ ptep++;
+ mappings++;
+ continue;
+ }
+
+ if (cleanlist_idx < PMAP_REMOVE_CLEAN_LIST_SIZE) {
+ /* Add to the clean list. */
+ cleanlist[cleanlist_idx].pte = ptep;
+ cleanlist[cleanlist_idx].va =
+ sva | (is_exec & 1);
+ cleanlist_idx++;
+ } else
+ if (cleanlist_idx == PMAP_REMOVE_CLEAN_LIST_SIZE) {
+ /* Nuke everything if needed. */
+ pmap_idcache_wbinv_all(pm);
+ pmap_tlb_flushID(pm);
+
+ /*
+ * Roll back the previous PTE list,
+ * and zero out the current PTE.
+ */
+ for (cnt = 0;
+ cnt < PMAP_REMOVE_CLEAN_LIST_SIZE; cnt++) {
+ *cleanlist[cnt].pte = 0;
+ }
+ *ptep = 0;
+ PTE_SYNC(ptep);
+ cleanlist_idx++;
+ pm->pm_remove_all = TRUE;
+ } else {
+ *ptep = 0;
+ PTE_SYNC(ptep);
+ if (pm->pm_remove_all == FALSE) {
+ if (is_exec)
+ pmap_tlb_flushID_SE(pm, sva);
+ else
+ if (is_refd)
+ pmap_tlb_flushD_SE(pm, sva);
+ }
+ }
+
+ sva += PAGE_SIZE;
+ ptep++;
+ mappings++;
+ }
+
+ /*
+ * Deal with any left overs
+ */
+ if (cleanlist_idx <= PMAP_REMOVE_CLEAN_LIST_SIZE) {
+ total += cleanlist_idx;
+ for (cnt = 0; cnt < cleanlist_idx; cnt++) {
+ if (pm->pm_cstate.cs_all != 0) {
+ vaddr_t clva = cleanlist[cnt].va & ~1;
+ if (cleanlist[cnt].va & 1) {
+ pmap_idcache_wbinv_range(pm,
+ clva, PAGE_SIZE);
+ pmap_tlb_flushID_SE(pm, clva);
+ } else {
+ pmap_dcache_wb_range(pm,
+ clva, PAGE_SIZE, TRUE,
+ FALSE);
+ pmap_tlb_flushD_SE(pm, clva);
+ }
+ }
+ *cleanlist[cnt].pte = 0;
+ PTE_SYNC_CURRENT(pm, cleanlist[cnt].pte);
+ }
+
+ /*
+ * If it looks like we're removing a whole bunch
+ * of mappings, it's faster to just write-back
+ * the whole cache now and defer TLB flushes until
+ * pmap_update() is called.
+ */
+ if (total <= PMAP_REMOVE_CLEAN_LIST_SIZE)
+ cleanlist_idx = 0;
+ else {
+ cleanlist_idx = PMAP_REMOVE_CLEAN_LIST_SIZE + 1;
+ pmap_idcache_wbinv_all(pm);
+ pm->pm_remove_all = TRUE;
+ }
+ }
+
+ pmap_free_l2_bucket(pm, l2b, mappings);
+ }
+
+ pmap_release_pmap_lock(pm);
+ PMAP_MAP_TO_HEAD_UNLOCK();
+}
+
+/*
+ * pmap_kenter_pa: enter an unmanaged, wired kernel mapping
+ *
+ * We assume there is already sufficient KVM space available
+ * to do this, as we can't allocate L2 descriptor tables/metadata
+ * from here.
+ */
+void
+pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
+{
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, opte;
+
+ NPDEBUG(PDB_KENTER,
+ printf("pmap_kenter_pa: va 0x%08lx, pa 0x%08lx, prot 0x%x\n",
+ va, pa, prot));
+
+ l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+ KDASSERT(l2b != NULL);
+
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ opte = *ptep;
+
+ if (l2pte_valid(opte)) {
+ cpu_dcache_wbinv_range(va, PAGE_SIZE);
+ cpu_tlb_flushD_SE(va);
+ cpu_cpwait();
+ } else
+ if (opte == 0)
+ l2b->l2b_occupancy++;
+
+ *ptep = L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) |
+ pte_l2_s_cache_mode;
+ PTE_SYNC(ptep);
+}
+
+void
+pmap_kremove(vaddr_t va, vsize_t len)
+{
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, *sptep, opte;
+ vaddr_t next_bucket, eva;
+ u_int mappings;
+
+ NPDEBUG(PDB_KREMOVE, printf("pmap_kremove: va 0x%08lx, len 0x%08lx\n",
+ va, len));
+
+ eva = va + len;
+
+ while (va < eva) {
+ next_bucket = L2_NEXT_BUCKET(va);
+ if (next_bucket > eva)
+ next_bucket = eva;
+
+ l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+ KDASSERT(l2b != NULL);
+
+ sptep = ptep = &l2b->l2b_kva[l2pte_index(va)];
+ mappings = 0;
+
+ while (va < next_bucket) {
+ opte = *ptep;
+ if (l2pte_valid(opte)) {
+ cpu_dcache_wbinv_range(va, PAGE_SIZE);
+ cpu_tlb_flushD_SE(va);
+ }
+ if (opte) {
+ *ptep = 0;
+ mappings++;
+ }
+ va += PAGE_SIZE;
+ ptep++;
+ }
+ KDASSERT(mappings <= l2b->l2b_occupancy);
+ l2b->l2b_occupancy -= mappings;
+ PTE_SYNC_RANGE(sptep, (u_int)(ptep - sptep));
+ }
+ cpu_cpwait();
+}
+
+boolean_t
+pmap_extract(pmap_t pm, vaddr_t va, paddr_t *pap)
+{
+ struct l2_dtable *l2;
+ pd_entry_t *pl1pd, l1pd;
+ pt_entry_t *ptep, pte;
+ paddr_t pa;
+ u_int l1idx;
+
+ pmap_acquire_pmap_lock(pm);
+
+ l1idx = L1_IDX(va);
+ pl1pd = &pm->pm_l1->l1_kva[l1idx];
+ l1pd = *pl1pd;
+
+ if (l1pte_section_p(l1pd)) {
+ /*
+ * These should only happen for pmap_kernel()
+ */
+ KDASSERT(pm == pmap_kernel());
+ pmap_release_pmap_lock(pm);
+ pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET);
+ } else {
+ /*
+ * Note that we can't rely on the validity of the L1
+ * descriptor as an indication that a mapping exists.
+ * We have to look it up in the L2 dtable.
+ */
+ l2 = pm->pm_l2[L2_IDX(l1idx)];
+
+ if (l2 == NULL ||
+ (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) {
+ pmap_release_pmap_lock(pm);
+ return (FALSE);
+ }
+
+ ptep = &ptep[l2pte_index(va)];
+ pte = *ptep;
+ pmap_release_pmap_lock(pm);
+
+ if (pte == 0)
+ return (FALSE);
+
+ switch (pte & L2_TYPE_MASK) {
+ case L2_TYPE_L:
+ pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET);
+ break;
+
+ default:
+ pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET);
+ break;
+ }
+ }
+
+ if (pap != NULL)
+ *pap = pa;
+
+ return (TRUE);
+}
+
+void
+pmap_protect(pmap_t pm, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
+{
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, pte;
+ vaddr_t next_bucket;
+ u_int flags;
+ int flush;
+
+ NPDEBUG(PDB_PROTECT,
+ printf("pmap_protect: pm %p sva 0x%lx eva 0x%lx prot 0x%x\n",
+ pm, sva, eva, prot));
+
+ if ((prot & VM_PROT_READ) == 0) {
+ pmap_remove(pm, sva, eva);
+ return;
+ }
+
+ if (prot & VM_PROT_WRITE) {
+ /*
+ * If this is a read->write transition, just ignore it and let
+ * uvm_fault() take care of it later.
+ */
+ return;
+ }
+
+ PMAP_MAP_TO_HEAD_LOCK();
+ pmap_acquire_pmap_lock(pm);
+
+ /*
+ * OK, at this point, we know we're doing write-protect operation.
+ * If the pmap is active, write-back the range.
+ */
+ pmap_dcache_wb_range(pm, sva, eva - sva, FALSE, FALSE);
+
+ flush = ((eva - sva) >= (PAGE_SIZE * 4)) ? 0 : -1;
+ flags = 0;
+
+ while (sva < eva) {
+ next_bucket = L2_NEXT_BUCKET(sva);
+ if (next_bucket > eva)
+ next_bucket = eva;
+
+ l2b = pmap_get_l2_bucket(pm, sva);
+ if (l2b == NULL) {
+ sva = next_bucket;
+ continue;
+ }
+
+ ptep = &l2b->l2b_kva[l2pte_index(sva)];
+
+ while (sva < next_bucket) {
+ if ((pte = *ptep) != 0 && (pte & L2_S_PROT_W) != 0) {
+ struct vm_page *pg;
+ u_int f;
+
+ pg = PHYS_TO_VM_PAGE(l2pte_pa(pte));
+ pte &= ~L2_S_PROT_W;
+ *ptep = pte;
+ PTE_SYNC(ptep);
+
+ if (pg != NULL) {
+ simple_lock(&pg->mdpage.pvh_slock);
+ f = pmap_modify_pv(pg, pm, sva,
+ PVF_WRITE, 0);
+ pmap_vac_me_harder(pg, pm, sva);
+ simple_unlock(&pg->mdpage.pvh_slock);
+ } else
+ f = PVF_REF | PVF_EXEC;
+
+ if (flush >= 0) {
+ flush++;
+ flags |= f;
+ } else
+ if (PV_BEEN_EXECD(f))
+ pmap_tlb_flushID_SE(pm, sva);
+ else
+ if (PV_BEEN_REFD(f))
+ pmap_tlb_flushD_SE(pm, sva);
+ }
+
+ sva += PAGE_SIZE;
+ ptep++;
+ }
+ }
+
+ pmap_release_pmap_lock(pm);
+ PMAP_MAP_TO_HEAD_UNLOCK();
+
+ if (flush) {
+ if (PV_BEEN_EXECD(flags))
+ pmap_tlb_flushID(pm);
+ else
+ if (PV_BEEN_REFD(flags))
+ pmap_tlb_flushD(pm);
+ }
+}
+
+void
+pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
+{
+
+ NPDEBUG(PDB_PROTECT,
+ printf("pmap_page_protect: pg %p (0x%08lx), prot 0x%x\n",
+ pg, pg->phys_addr, prot));
+
+ switch(prot) {
+ case VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE:
+ case VM_PROT_READ|VM_PROT_WRITE:
+ return;
+
+ case VM_PROT_READ:
+ case VM_PROT_READ|VM_PROT_EXECUTE:
+ pmap_clearbit(pg, PVF_WRITE);
+ break;
+
+ default:
+ pmap_page_remove(pg);
+ break;
+ }
+}
+
+/*
+ * pmap_clear_modify:
+ *
+ * Clear the "modified" attribute for a page.
+ */
+boolean_t
+pmap_clear_modify(struct vm_page *pg)
+{
+ boolean_t rv;
+
+ if (pg->mdpage.pvh_attrs & PVF_MOD) {
+ rv = TRUE;
+ pmap_clearbit(pg, PVF_MOD);
+ } else
+ rv = FALSE;
+
+ return (rv);
+}
+
+/*
+ * pmap_clear_reference:
+ *
+ * Clear the "referenced" attribute for a page.
+ */
+boolean_t
+pmap_clear_reference(struct vm_page *pg)
+{
+ boolean_t rv;
+
+ if (pg->mdpage.pvh_attrs & PVF_REF) {
+ rv = TRUE;
+ pmap_clearbit(pg, PVF_REF);
+ } else
+ rv = FALSE;
+
+ return (rv);
+}
+
+/*
+ * pmap_is_modified:
+ *
+ * Test if a page has the "modified" attribute.
+ */
+/* See <arm/pmap.h> */
+
+/*
+ * pmap_is_referenced:
+ *
+ * Test if a page has the "referenced" attribute.
+ */
+/* See <arm/pmap.h> */
+
+int
+pmap_fault_fixup(pmap_t pm, vaddr_t va, vm_prot_t ftype, int user)
+{
+ struct l2_dtable *l2;
+ struct l2_bucket *l2b;
+ pd_entry_t *pl1pd, l1pd;
+ pt_entry_t *ptep, pte;
+ paddr_t pa;
+ u_int l1idx;
+ int rv = 0;
+
+ PMAP_MAP_TO_HEAD_LOCK();
+ pmap_acquire_pmap_lock(pm);
+
+ l1idx = L1_IDX(va);
+
+ /*
+ * If there is no l2_dtable for this address, then the process
+ * has no business accessing it.
+ *
+ * Note: This will catch userland processes trying to access
+ * kernel addresses.
+ */
+ l2 = pm->pm_l2[L2_IDX(l1idx)];
+ if (l2 == NULL)
+ goto out;
+
+ /*
+ * Likewise if there is no L2 descriptor table
+ */
+ l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+ if (l2b->l2b_kva == NULL)
+ goto out;
+
+ /*
+ * Check the PTE itself.
+ */
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ pte = *ptep;
+ if (pte == 0)
+ goto out;
+
+ /*
+ * Catch a userland access to the vector page mapped at 0x0
+ */
+ if (user && (pte & L2_S_PROT_U) == 0)
+ goto out;
+
+ pa = l2pte_pa(pte);
+
+ if ((ftype & VM_PROT_WRITE) && (pte & L2_S_PROT_W) == 0) {
+ /*
+ * This looks like a good candidate for "page modified"
+ * emulation...
+ */
+ struct pv_entry *pv;
+ struct vm_page *pg;
+
+ /* Extract the physical address of the page */
+ if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
+ goto out;
+
+ /* Get the current flags for this page. */
+ simple_lock(&pg->mdpage.pvh_slock);
+
+ pv = pmap_find_pv(pg, pm, va);
+ if (pv == NULL) {
+ simple_unlock(&pg->mdpage.pvh_slock);
+ goto out;
+ }
+
+ /*
+ * Do the flags say this page is writable? If not then it
+ * is a genuine write fault. If yes then the write fault is
+ * our fault as we did not reflect the write access in the
+ * PTE. Now we know a write has occurred we can correct this
+ * and also set the modified bit
+ */
+ if ((pv->pv_flags & PVF_WRITE) == 0) {
+ simple_unlock(&pg->mdpage.pvh_slock);
+ goto out;
+ }
+
+ NPDEBUG(PDB_FOLLOW,
+ printf("pmap_fault_fixup: mod emul. pm %p, va 0x%08lx, pa 0x%08lx\n",
+ pm, va, pg->phys_addr));
+
+ pg->mdpage.pvh_attrs |= PVF_REF | PVF_MOD;
+ pv->pv_flags |= PVF_REF | PVF_MOD;
+ simple_unlock(&pg->mdpage.pvh_slock);
+
+ /*
+ * Re-enable write permissions for the page. No need to call
+ * pmap_vac_me_harder(), since this is just a
+ * modified-emulation fault, and the PVF_WRITE bit isn't
+ * changing. We've already set the cacheable bits based on
+ * the assumption that we can write to this page.
+ */
+ *ptep = (pte & ~L2_TYPE_MASK) | L2_S_PROTO | L2_S_PROT_W;
+ PTE_SYNC(ptep);
+ rv = 1;
+ } else
+ if ((pte & L2_TYPE_MASK) == L2_TYPE_INV) {
+ /*
+ * This looks like a good candidate for "page referenced"
+ * emulation.
+ */
+ struct pv_entry *pv;
+ struct vm_page *pg;
+
+ /* Extract the physical address of the page */
+ if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
+ goto out;
+
+ /* Get the current flags for this page. */
+ simple_lock(&pg->mdpage.pvh_slock);
+
+ pv = pmap_find_pv(pg, pm, va);
+ if (pv == NULL) {
+ simple_unlock(&pg->mdpage.pvh_slock);
+ goto out;
+ }
+
+ pg->mdpage.pvh_attrs |= PVF_REF;
+ pv->pv_flags |= PVF_REF;
+ simple_unlock(&pg->mdpage.pvh_slock);
+
+ NPDEBUG(PDB_FOLLOW,
+ printf("pmap_fault_fixup: ref emul. pm %p, va 0x%08lx, pa 0x%08lx\n",
+ pm, va, pg->phys_addr));
+
+ *ptep = (pte & ~L2_TYPE_MASK) | L2_S_PROTO;
+ PTE_SYNC(ptep);
+ rv = 1;
+ }
+
+ /*
+ * We know there is a valid mapping here, so simply
+ * fix up the L1 if necessary.
+ */
+ pl1pd = &pm->pm_l1->l1_kva[l1idx];
+ l1pd = l2b->l2b_phys | L1_C_DOM(pm->pm_domain) | L1_C_PROTO;
+ if (*pl1pd != l1pd) {
+ *pl1pd = l1pd;
+ PTE_SYNC(pl1pd);
+ rv = 1;
+ }
+
+#ifdef CPU_SA110
+ /*
+ * There are bugs in the rev K SA110. This is a check for one
+ * of them.
+ */
+ if (rv == 0 && curcpu()->ci_arm_cputype == CPU_ID_SA110 &&
+ curcpu()->ci_arm_cpurev < 3) {
+ /* Always current pmap */
+ if (l2pte_valid(pte)) {
+ extern int kernel_debug;
+ if (kernel_debug & 1) {
+ struct proc *p = curproc;
+ printf("prefetch_abort: page is already "
+ "mapped - pte=%p *pte=%08x\n", ptep, pte);
+ printf("prefetch_abort: pc=%08lx proc=%p "
+ "process=%s\n", va, p, p->p_comm);
+ printf("prefetch_abort: far=%08x fs=%x\n",
+ cpu_faultaddress(), cpu_faultstatus());
+ }
+#ifdef DDB
+ if (kernel_debug & 2)
+ Debugger();
+#endif
+ rv = 1;
+ }
+ }
+#endif /* CPU_SA110 */
+
+#ifdef DEBUG
+ /*
+ * If 'rv == 0' at this point, it generally indicates that there is a
+ * stale TLB entry for the faulting address. This happens when two or
+ * more processes are sharing an L1. Since we don't flush the TLB on
+ * a context switch between such processes, we can take domain faults
+ * for mappings which exist at the same VA in both processes. EVEN IF
+ * WE'VE RECENTLY FIXED UP THE CORRESPONDING L1 in pmap_enter(), for
+ * example.
+ *
+ * This is extremely likely to happen if pmap_enter() updated the L1
+ * entry for a recently entered mapping. In this case, the TLB is
+ * flushed for the new mapping, but there may still be TLB entries for
+ * other mappings belonging to other processes in the 1MB range
+ * covered by the L1 entry.
+ *
+ * Since 'rv == 0', we know that the L1 already contains the correct
+ * value, so the fault must be due to a stale TLB entry.
+ *
+ * Since we always need to flush the TLB anyway in the case where we
+ * fixed up the L1, or frobbed the L2 PTE, we effectively deal with
+ * stale TLB entries dynamically.
+ *
+ * However, the above condition can ONLY happen if the current L1 is
+ * being shared. If it happens when the L1 is unshared, it indicates
+ * that other parts of the pmap are not doing their job WRT managing
+ * the TLB.
+ */
+ if (rv == 0 && pm->pm_l1->l1_domain_use_count == 1) {
+ extern int last_fault_code;
+ printf("fixup: pm %p, va 0x%lx, ftype %d - nothing to do!\n",
+ pm, va, ftype);
+ printf("fixup: l2 %p, l2b %p, ptep %p, pl1pd %p\n",
+ l2, l2b, ptep, pl1pd);
+ printf("fixup: pte 0x%x, l1pd 0x%x, last code 0x%x\n",
+ pte, l1pd, last_fault_code);
+#ifdef DDB
+ Debugger();
+#endif
+ }
+#endif
+
+ cpu_tlb_flushID_SE(va);
+ cpu_cpwait();
+
+ rv = 1;
+
+out:
+ pmap_release_pmap_lock(pm);
+ PMAP_MAP_TO_HEAD_UNLOCK();
+
+ return (rv);
+}
+
+/*
+ * pmap_collect: free resources held by a pmap
+ *
+ * => optional function.
+ * => called when a process is swapped out to free memory.
+ */
+void
+pmap_collect(pmap_t pm)
+{
+ /*
+ * Nothing to do.
+ * We don't even need to free-up the process' L1.
+ */
+}
+
+/*
+ * Routine: pmap_procwr
+ *
+ * Function:
+ * Synchronize caches corresponding to [addr, addr+len) in p.
+ *
+ */
+void
+pmap_procwr(struct proc *p, vaddr_t va, int len)
+{
+ /* We only need to do anything if it is the current process. */
+ if (p == curproc)
+ cpu_icache_sync_range(va, len);
+}
+
+/*
+ * Routine: pmap_unwire
+ * Function: Clear the wired attribute for a map/virtual-address pair.
+ *
+ * In/out conditions:
+ * The mapping must already exist in the pmap.
+ */
+void
+pmap_unwire(pmap_t pm, vaddr_t va)
+{
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, pte;
+ struct vm_page *pg;
+ paddr_t pa;
+
+ NPDEBUG(PDB_WIRING, printf("pmap_unwire: pm %p, va 0x%08lx\n", pm, va));
+
+ PMAP_MAP_TO_HEAD_LOCK();
+ pmap_acquire_pmap_lock(pm);
+
+ l2b = pmap_get_l2_bucket(pm, va);
+ KDASSERT(l2b != NULL);
+
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ pte = *ptep;
+
+ /* Extract the physical address of the page */
+ pa = l2pte_pa(pte);
+
+ if ((pg = PHYS_TO_VM_PAGE(pa)) != NULL) {
+ /* Update the wired bit in the pv entry for this page. */
+ simple_lock(&pg->mdpage.pvh_slock);
+ (void) pmap_modify_pv(pg, pm, va, PVF_WIRED, 0);
+ simple_unlock(&pg->mdpage.pvh_slock);
+ }
+
+ pmap_release_pmap_lock(pm);
+ PMAP_MAP_TO_HEAD_UNLOCK();
+}
+
+void
+pmap_activate(struct proc *p)
+{
+ pmap_t pm;
+ struct pcb *pcb;
+ int s;
+
+ pm = p->p_vmspace->vm_map.pmap;
+ pcb = &p->p_addr->u_pcb;
+
+ pmap_set_pcb_pagedir(pm, pcb);
+
+ if (p == curproc) {
+ u_int cur_dacr, cur_ttb;
+
+ __asm __volatile("mrc p15, 0, %0, c2, c0, 0" : "=r"(cur_ttb));
+ __asm __volatile("mrc p15, 0, %0, c3, c0, 0" : "=r"(cur_dacr));
+
+ cur_ttb &= ~(L1_TABLE_SIZE - 1);
+
+ if (cur_ttb == (u_int)pcb->pcb_pagedir &&
+ cur_dacr == pcb->pcb_dacr) {
+ /*
+ * No need to switch address spaces.
+ */
+ return;
+ }
+
+ s = splhigh();
+ pmap_acquire_pmap_lock(pm);
+ disable_interrupts(I32_bit | F32_bit);
+
+ /*
+ * We MUST, I repeat, MUST fix up the L1 entry corresponding
+ * to 'vector_page' in the incoming L1 table before switching
+ * to it otherwise subsequent interrupts/exceptions (including
+ * domain faults!) will jump into hyperspace.
+ */
+ if (pcb->pcb_pl1vec) {
+ *pcb->pcb_pl1vec = pcb->pcb_l1vec;
+ /*
+ * Don't need to PTE_SYNC() at this point since
+ * cpu_setttb() is about to flush both the cache
+ * and the TLB.
+ */
+ }
+
+ cpu_domains(pcb->pcb_dacr);
+ cpu_setttb(pcb->pcb_pagedir);
+
+ enable_interrupts(I32_bit | F32_bit);
+
+ /*
+ * Flag any previous userland pmap as being NOT
+ * resident in the cache/tlb.
+ */
+ if (pmap_cache_state && pmap_cache_state != &pm->pm_cstate)
+ pmap_cache_state->cs_all = 0;
+
+ /*
+ * The new pmap, however, IS resident.
+ */
+ pmap_cache_state = &pm->pm_cstate;
+ pm->pm_cstate.cs_all = PMAP_CACHE_STATE_ALL;
+ pmap_release_pmap_lock(pm);
+ splx(s);
+ }
+}
+
+void
+pmap_deactivate(struct proc *p)
+{
+}
+
+void
+pmap_update(pmap_t pm)
+{
+
+ if (pm->pm_remove_all) {
+ /*
+ * Finish up the pmap_remove_all() optimisation by flushing
+ * the TLB.
+ */
+ pmap_tlb_flushID(pm);
+ pm->pm_remove_all = FALSE;
+ }
+
+ if (pmap_is_current(pm)) {
+ /*
+ * If we're dealing with a current userland pmap, move its L1
+ * to the end of the LRU.
+ */
+ if (pm != pmap_kernel())
+ pmap_use_l1(pm);
+
+ /*
+ * We can assume we're done with frobbing the cache/tlb for
+ * now. Make sure any future pmap ops don't skip cache/tlb
+ * flushes.
+ */
+ pm->pm_cstate.cs_all = PMAP_CACHE_STATE_ALL;
+ }
+
+ /*
+ * make sure TLB/cache operations have completed.
+ */
+ cpu_cpwait();
+}
+
+void
+pmap_remove_all(pmap_t pm)
+{
+
+ /*
+ * The vmspace described by this pmap is about to be torn down.
+ * Until pmap_update() is called, UVM will only make calls
+ * to pmap_remove(). We can make life much simpler by flushing
+ * the cache now, and deferring TLB invalidation to pmap_update().
+ */
+ pmap_idcache_wbinv_all(pm);
+ pm->pm_remove_all = TRUE;
+}
+
+/*
+ * Retire the given physical map from service.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_destroy(pmap_t pm)
+{
+ u_int count;
+
+ if (pm == NULL)
+ return;
+
+ if (pm->pm_remove_all) {
+ pmap_tlb_flushID(pm);
+ pm->pm_remove_all = FALSE;
+ }
+
+ /*
+ * Drop reference count
+ */
+ simple_lock(&pm->pm_lock);
+ count = --pm->pm_obj.uo_refs;
+ simple_unlock(&pm->pm_lock);
+ if (count > 0) {
+ if (pmap_is_current(pm)) {
+ if (pm != pmap_kernel())
+ pmap_use_l1(pm);
+ pm->pm_cstate.cs_all = PMAP_CACHE_STATE_ALL;
+ }
+ return;
+ }
+
+ /*
+ * reference count is zero, free pmap resources and then free pmap.
+ */
+
+ if (vector_page < KERNEL_BASE) {
+ struct pcb *pcb = &proc0.p_addr->u_pcb;
+
+ if (pmap_is_current(pm)) {
+ /*
+ * Frob the L1 entry corresponding to the vector
+ * page so that it contains the kernel pmap's domain
+ * number. This will ensure pmap_remove() does not
+ * pull the current vector page out from under us.
+ */
+ disable_interrupts(I32_bit | F32_bit);
+ *pcb->pcb_pl1vec = pcb->pcb_l1vec;
+ cpu_domains(pcb->pcb_dacr);
+ cpu_setttb(pcb->pcb_pagedir);
+ enable_interrupts(I32_bit | F32_bit);
+ }
+
+ /* Remove the vector page mapping */
+ pmap_remove(pm, vector_page, vector_page + PAGE_SIZE);
+ pmap_update(pm);
+
+ /*
+ * Make sure cpu_switch(), et al, DTRT. This is safe to do
+ * since this process has no remaining mappings of its own.
+ */
+ curpcb->pcb_pl1vec = pcb->pcb_pl1vec;
+ curpcb->pcb_l1vec = pcb->pcb_l1vec;
+ curpcb->pcb_dacr = pcb->pcb_dacr;
+ curpcb->pcb_pagedir = pcb->pcb_pagedir;
+ }
+
+ LIST_REMOVE(pm, pm_list);
+
+ pmap_free_l1(pm);
+
+ /* return the pmap to the pool */
+ pool_cache_put(&pmap_pmap_cache, pm);
+}
+
+
+/*
+ * void pmap_reference(pmap_t pm)
+ *
+ * Add a reference to the specified pmap.
+ */
+void
+pmap_reference(pmap_t pm)
+{
+
+ if (pm == NULL)
+ return;
+
+ pmap_use_l1(pm);
+
+ simple_lock(&pm->pm_lock);
+ pm->pm_obj.uo_refs++;
+ simple_unlock(&pm->pm_lock);
+}
+
+/*
+ * pmap_zero_page()
+ *
+ * Zero a given physical page by mapping it at a page hook point.
+ * In doing the zero page op, the page we zero is mapped cachable, as with
+ * StrongARM accesses to non-cached pages are non-burst making writing
+ * _any_ bulk data very slow.
+ */
+#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0
+void
+pmap_zero_page_generic(struct vm_page *pg)
+{
+ paddr_t phys = VM_PAGE_TO_PHYS(pg);
+#ifdef DEBUG
+ if (pg->mdpage.pvh_list != NULL)
+ panic("pmap_zero_page: page has mappings");
+#endif
+
+ KDASSERT((phys & PGOFSET) == 0);
+
+ /*
+ * Hook in the page, zero it, and purge the cache for that
+ * zeroed page. Invalidate the TLB as needed.
+ */
+ *cdst_pte = L2_S_PROTO | phys |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | pte_l2_s_cache_mode;
+ PTE_SYNC(cdst_pte);
+ cpu_tlb_flushD_SE(cdstp);
+ cpu_cpwait();
+ bzero_page(cdstp);
+ cpu_dcache_wbinv_range(cdstp, PAGE_SIZE);
+}
+#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */
+
+#if ARM_MMU_XSCALE == 1
+void
+pmap_zero_page_xscale(struct vm_page *pg)
+{
+ paddr_t phys = VM_PAGE_TO_PHYS(pg);
+#ifdef DEBUG
+ if (pg->mdpage.pvh_list != NULL)
+ panic("pmap_zero_page: page has mappings");
+#endif
+
+ KDASSERT((phys & PGOFSET) == 0);
+
+ /*
+ * Hook in the page, zero it, and purge the cache for that
+ * zeroed page. Invalidate the TLB as needed.
+ */
+ *cdst_pte = L2_S_PROTO | phys |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) |
+ L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */
+ PTE_SYNC(cdst_pte);
+ cpu_tlb_flushD_SE(cdstp);
+ cpu_cpwait();
+ bzero_page(cdstp);
+#if 0
+ xscale_cache_clean_minidata();
+#else
+ printf("xscale_cache_clean_minidata call\n");
+#endif
+}
+#endif /* ARM_MMU_XSCALE == 1 */
+
+/* pmap_pageidlezero()
+ *
+ * The same as above, except that we assume that the page is not
+ * mapped. This means we never have to flush the cache first. Called
+ * from the idle loop.
+ */
+boolean_t
+pmap_pageidlezero(struct vm_page *pg)
+{
+ unsigned int i;
+ int *ptr;
+ boolean_t rv = TRUE;
+ paddr_t phys = VM_PAGE_TO_PHYS(pg);
+#ifdef DEBUG
+ if (pg->mdpage.pvh_list != NULL)
+ panic("pmap_pageidlezero: page has mappings");
+#endif
+
+ KDASSERT((phys & PGOFSET) == 0);
+
+ /*
+ * Hook in the page, zero it, and purge the cache for that
+ * zeroed page. Invalidate the TLB as needed.
+ */
+ *cdst_pte = L2_S_PROTO | phys |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | pte_l2_s_cache_mode;
+ PTE_SYNC(cdst_pte);
+ cpu_tlb_flushD_SE(cdstp);
+ cpu_cpwait();
+
+ for (i = 0, ptr = (int *)cdstp;
+ i < (PAGE_SIZE / sizeof(int)); i++) {
+ if (whichqs != 0) {
+ /*
+ * A process has become ready. Abort now,
+ * so we don't keep it waiting while we
+ * do slow memory access to finish this
+ * page.
+ */
+ rv = FALSE;
+ break;
+ }
+ *ptr++ = 0;
+ }
+
+ if (rv)
+ /*
+ * if we aborted we'll rezero this page again later so don't
+ * purge it unless we finished it
+ */
+ cpu_dcache_wbinv_range(cdstp, PAGE_SIZE);
+
+ return (rv);
+}
+
+/*
+ * pmap_copy_page()
+ *
+ * Copy one physical page into another, by mapping the pages into
+ * hook points. The same comment regarding cachability as in
+ * pmap_zero_page also applies here.
+ */
+#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0
+void
+pmap_copy_page_generic(struct vm_page *src_pg, struct vm_page *dst_pg)
+{
+ paddr_t src = VM_PAGE_TO_PHYS(src_pg);
+ paddr_t dst = VM_PAGE_TO_PHYS(dst_pg);
+#ifdef DEBUG
+ if (dst_pg->mdpage.pvh_list != NULL)
+ panic("pmap_copy_page: dst page has mappings");
+#endif
+
+ KDASSERT((src & PGOFSET) == 0);
+ KDASSERT((dst & PGOFSET) == 0);
+
+ /*
+ * Clean the source page. Hold the source page's lock for
+ * the duration of the copy so that no other mappings can
+ * be created while we have a potentially aliased mapping.
+ */
+ simple_lock(&src_pg->mdpage.pvh_slock);
+ (void) pmap_clean_page(src_pg->mdpage.pvh_list, TRUE);
+
+ /*
+ * Map the pages into the page hook points, copy them, and purge
+ * the cache for the appropriate page. Invalidate the TLB
+ * as required.
+ */
+ *csrc_pte = L2_S_PROTO | src |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_READ) | pte_l2_s_cache_mode;
+ PTE_SYNC(csrc_pte);
+ *cdst_pte = L2_S_PROTO | dst |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) | pte_l2_s_cache_mode;
+ PTE_SYNC(cdst_pte);
+ cpu_tlb_flushD_SE(csrcp);
+ cpu_tlb_flushD_SE(cdstp);
+ cpu_cpwait();
+ bcopy_page(csrcp, cdstp);
+ cpu_dcache_inv_range(csrcp, PAGE_SIZE);
+ simple_unlock(&src_pg->mdpage.pvh_slock); /* cache is safe again */
+ cpu_dcache_wbinv_range(cdstp, PAGE_SIZE);
+}
+#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */
+
+#if ARM_MMU_XSCALE == 1
+void
+pmap_copy_page_xscale(struct vm_page *src_pg, struct vm_page *dst_pg)
+{
+ paddr_t src = VM_PAGE_TO_PHYS(src_pg);
+ paddr_t dst = VM_PAGE_TO_PHYS(dst_pg);
+#ifdef DEBUG
+ if (dst_pg->mdpage.pvh_list != NULL)
+ panic("pmap_copy_page: dst page has mappings");
+#endif
+
+ KDASSERT((src & PGOFSET) == 0);
+ KDASSERT((dst & PGOFSET) == 0);
+
+ /*
+ * Clean the source page. Hold the source page's lock for
+ * the duration of the copy so that no other mappings can
+ * be created while we have a potentially aliased mapping.
+ */
+ simple_lock(&src_pg->mdpage.pvh_slock);
+ (void) pmap_clean_page(src_pg->mdpage.pvh_list, TRUE);
+
+ /*
+ * Map the pages into the page hook points, copy them, and purge
+ * the cache for the appropriate page. Invalidate the TLB
+ * as required.
+ */
+ *csrc_pte = L2_S_PROTO | src |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_READ) |
+ L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */
+ PTE_SYNC(csrc_pte);
+ *cdst_pte = L2_S_PROTO | dst |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_WRITE) |
+ L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X); /* mini-data */
+ PTE_SYNC(cdst_pte);
+ cpu_tlb_flushD_SE(csrcp);
+ cpu_tlb_flushD_SE(cdstp);
+ cpu_cpwait();
+ bcopy_page(csrcp, cdstp);
+ simple_unlock(&src_pg->mdpage.pvh_slock); /* cache is safe again */
+#if 0
+ xscale_cache_clean_minidata();
+#else
+ printf("xscale_cache_clean_minidata call\n");
+#endif
+}
+#endif /* ARM_MMU_XSCALE == 1 */
+
+/*
+ * void pmap_virtual_space(vaddr_t *start, vaddr_t *end)
+ *
+ * Return the start and end addresses of the kernel's virtual space.
+ * These values are setup in pmap_bootstrap and are updated as pages
+ * are allocated.
+ */
+void
+pmap_virtual_space(vaddr_t *start, vaddr_t *end)
+{
+ *start = virtual_avail;
+ *end = virtual_end;
+}
+
+/*
+ * Helper function for pmap_grow_l2_bucket()
+ */
+static __inline int
+pmap_grow_map(vaddr_t va, pt_entry_t cache_mode, paddr_t *pap)
+{
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep;
+ paddr_t pa;
+
+ if (uvm.page_init_done == FALSE) {
+ if (uvm_page_physget(&pa) == FALSE)
+ return (1);
+ } else {
+ struct vm_page *pg;
+ pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE);
+ if (pg == NULL)
+ return (1);
+ pa = VM_PAGE_TO_PHYS(pg);
+ }
+
+ if (pap)
+ *pap = pa;
+
+ l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+ KDASSERT(l2b != NULL);
+
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ *ptep = L2_S_PROTO | pa | cache_mode |
+ L2_S_PROT(PTE_KERNEL, VM_PROT_READ | VM_PROT_WRITE);
+ PTE_SYNC(ptep);
+ memset((void *)va, 0, PAGE_SIZE);
+ return (0);
+}
+
+/*
+ * This is the same as pmap_alloc_l2_bucket(), except that it is only
+ * used by pmap_growkernel().
+ */
+static __inline struct l2_bucket *
+pmap_grow_l2_bucket(pmap_t pm, vaddr_t va)
+{
+ struct l2_dtable *l2;
+ struct l2_bucket *l2b;
+ u_short l1idx;
+ vaddr_t nva;
+
+ l1idx = L1_IDX(va);
+
+ if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) {
+ /*
+ * No mapping at this address, as there is
+ * no entry in the L1 table.
+ * Need to allocate a new l2_dtable.
+ */
+ nva = pmap_kernel_l2dtable_kva;
+ if ((nva & PGOFSET) == 0) {
+ /*
+ * Need to allocate a backing page
+ */
+ if (pmap_grow_map(nva, pte_l2_s_cache_mode, NULL))
+ return (NULL);
+ }
+
+ l2 = (struct l2_dtable *)nva;
+ nva += sizeof(struct l2_dtable);
+
+ if ((nva & PGOFSET) < (pmap_kernel_l2dtable_kva & PGOFSET)) {
+ /*
+ * The new l2_dtable straddles a page boundary.
+ * Map in another page to cover it.
+ */
+ if (pmap_grow_map(nva, pte_l2_s_cache_mode, NULL))
+ return (NULL);
+ }
+
+ pmap_kernel_l2dtable_kva = nva;
+
+ /*
+ * Link it into the parent pmap
+ */
+ pm->pm_l2[L2_IDX(l1idx)] = l2;
+ }
+
+ l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+
+ /*
+ * Fetch pointer to the L2 page table associated with the address.
+ */
+ if (l2b->l2b_kva == NULL) {
+ pt_entry_t *ptep;
+
+ /*
+ * No L2 page table has been allocated. Chances are, this
+ * is because we just allocated the l2_dtable, above.
+ */
+ nva = pmap_kernel_l2ptp_kva;
+ ptep = (pt_entry_t *)nva;
+ if ((nva & PGOFSET) == 0) {
+ /*
+ * Need to allocate a backing page
+ */
+ if (pmap_grow_map(nva, pte_l2_s_cache_mode_pt,
+ &pmap_kernel_l2ptp_phys))
+ return (NULL);
+ PTE_SYNC_RANGE(ptep, PAGE_SIZE / sizeof(pt_entry_t));
+ }
+
+ l2->l2_occupancy++;
+ l2b->l2b_kva = ptep;
+ l2b->l2b_l1idx = l1idx;
+ l2b->l2b_phys = pmap_kernel_l2ptp_phys;
+
+ pmap_kernel_l2ptp_kva += L2_TABLE_SIZE_REAL;
+ pmap_kernel_l2ptp_phys += L2_TABLE_SIZE_REAL;
+ }
+
+ return (l2b);
+}
+
+vaddr_t
+pmap_growkernel(vaddr_t maxkvaddr)
+{
+ pmap_t kpm = pmap_kernel();
+ struct l1_ttable *l1;
+ struct l2_bucket *l2b;
+ pd_entry_t *pl1pd;
+ int s;
+
+ if (maxkvaddr <= pmap_curmaxkvaddr)
+ goto out; /* we are OK */
+
+ NPDEBUG(PDB_GROWKERN,
+ printf("pmap_growkernel: growing kernel from 0x%lx to 0x%lx\n",
+ pmap_curmaxkvaddr, maxkvaddr));
+
+ KDASSERT(maxkvaddr <= virtual_end);
+
+ /*
+ * whoops! we need to add kernel PTPs
+ */
+
+ s = splhigh(); /* to be safe */
+ simple_lock(&kpm->pm_lock);
+
+ /* Map 1MB at a time */
+ for (; pmap_curmaxkvaddr < maxkvaddr; pmap_curmaxkvaddr += L1_S_SIZE) {
+
+ l2b = pmap_grow_l2_bucket(kpm, pmap_curmaxkvaddr);
+ KDASSERT(l2b != NULL);
+
+ /* Distribute new L1 entry to all other L1s */
+ SLIST_FOREACH(l1, &l1_list, l1_link) {
+ pl1pd = &l1->l1_kva[L1_IDX(pmap_curmaxkvaddr)];
+ *pl1pd = l2b->l2b_phys | L1_C_DOM(PMAP_DOMAIN_KERNEL) |
+ L1_C_PROTO;
+ PTE_SYNC(pl1pd);
+ }
+ }
+
+ /*
+ * flush out the cache, expensive but growkernel will happen so
+ * rarely
+ */
+ cpu_dcache_wbinv_all();
+ cpu_tlb_flushD();
+ cpu_cpwait();
+
+ simple_unlock(&kpm->pm_lock);
+ splx(s);
+
+out:
+ return (pmap_curmaxkvaddr);
+}
+
+/************************ Utility routines ****************************/
+
+/*
+ * vector_page_setprot:
+ *
+ * Manipulate the protection of the vector page.
+ */
+void
+vector_page_setprot(int prot)
+{
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep;
+
+ l2b = pmap_get_l2_bucket(pmap_kernel(), vector_page);
+ KDASSERT(l2b != NULL);
+
+ ptep = &l2b->l2b_kva[l2pte_index(vector_page)];
+
+ *ptep = (*ptep & ~L1_S_PROT_MASK) | L2_S_PROT(PTE_KERNEL, prot);
+ PTE_SYNC(ptep);
+ cpu_tlb_flushD_SE(vector_page);
+ cpu_cpwait();
+}
+
+/*
+ * This is used to stuff certain critical values into the PCB where they
+ * can be accessed quickly from cpu_switch() et al.
+ */
+void
+pmap_set_pcb_pagedir(pmap_t pm, struct pcb *pcb)
+{
+ struct l2_bucket *l2b;
+
+ KDASSERT(pm->pm_l1);
+
+ pcb->pcb_pagedir = pm->pm_l1->l1_physaddr;
+ pcb->pcb_dacr = (DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) |
+ (DOMAIN_CLIENT << (pm->pm_domain * 2));
+ pcb->pcb_cstate = (void *)&pm->pm_cstate;
+
+ if (vector_page < KERNEL_BASE) {
+ pcb->pcb_pl1vec = &pm->pm_l1->l1_kva[L1_IDX(vector_page)];
+ l2b = pmap_get_l2_bucket(pm, vector_page);
+ pcb->pcb_l1vec = l2b->l2b_phys | L1_C_PROTO |
+ L1_C_DOM(pm->pm_domain);
+ } else
+ pcb->pcb_pl1vec = NULL;
+}
+
+/*
+ * Fetch pointers to the PDE/PTE for the given pmap/VA pair.
+ * Returns TRUE if the mapping exists, else FALSE.
+ *
+ * NOTE: This function is only used by a couple of arm-specific modules.
+ * It is not safe to take any pmap locks here, since we could be right
+ * in the middle of debugging the pmap anyway...
+ *
+ * It is possible for this routine to return FALSE even though a valid
+ * mapping does exist. This is because we don't lock, so the metadata
+ * state may be inconsistent.
+ *
+ * NOTE: We can return a NULL *ptp in the case where the L1 pde is
+ * a "section" mapping.
+ */
+boolean_t
+pmap_get_pde_pte(pmap_t pm, vaddr_t va, pd_entry_t **pdp, pt_entry_t **ptp)
+{
+ struct l2_dtable *l2;
+ pd_entry_t *pl1pd, l1pd;
+ pt_entry_t *ptep;
+ u_short l1idx;
+
+ if (pm->pm_l1 == NULL)
+ return (FALSE);
+
+ l1idx = L1_IDX(va);
+ *pdp = pl1pd = &pm->pm_l1->l1_kva[l1idx];
+ l1pd = *pl1pd;
+
+ if (l1pte_section_p(l1pd)) {
+ *ptp = NULL;
+ return (TRUE);
+ }
+
+ if (pm->pm_l2 == NULL)
+ return (FALSE);
+
+ l2 = pm->pm_l2[L2_IDX(l1idx)];
+
+ if (l2 == NULL ||
+ (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) {
+ return (FALSE);
+ }
+
+ *ptp = &ptep[l2pte_index(va)];
+ return (TRUE);
+}
+
+boolean_t
+pmap_get_pde(pmap_t pm, vaddr_t va, pd_entry_t **pdp)
+{
+ u_short l1idx;
+
+ if (pm->pm_l1 == NULL)
+ return (FALSE);
+
+ l1idx = L1_IDX(va);
+ *pdp = &pm->pm_l1->l1_kva[l1idx];
+
+ return (TRUE);
+}
+
+/************************ Bootstrapping routines ****************************/
+
+void
+pmap_init_l1(struct l1_ttable *l1, pd_entry_t *l1pt)
+{
+ int i;
+
+ l1->l1_kva = l1pt;
+ l1->l1_domain_use_count = 0;
+ l1->l1_domain_first = 0;
+
+ for (i = 0; i < PMAP_DOMAINS; i++)
+ l1->l1_domain_free[i] = i + 1;
+
+ /*
+ * Copy the kernel's L1 entries to each new L1.
+ */
+ if (pmap_initialized)
+ memcpy(l1pt, pmap_kernel()->pm_l1->l1_kva, L1_TABLE_SIZE);
+
+ if (pmap_extract(pmap_kernel(), (vaddr_t)l1pt,
+ &l1->l1_physaddr) == FALSE)
+ panic("pmap_init_l1: can't get PA of L1 at %p", l1pt);
+
+ SLIST_INSERT_HEAD(&l1_list, l1, l1_link);
+ TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru);
+}
+
+/*
+ * pmap_bootstrap() is called from the board-specific initarm() routine
+ * once the kernel L1/L2 descriptors tables have been set up.
+ *
+ * This is a somewhat convoluted process since pmap bootstrap is, effectively,
+ * spread over a number of disparate files/functions.
+ *
+ * We are passed the following parameters
+ * - kernel_l1pt
+ * This is a pointer to the base of the kernel's L1 translation table.
+ * - vstart
+ * 1MB-aligned start of managed kernel virtual memory.
+ * - vend
+ * 1MB-aligned end of managed kernel virtual memory.
+ *
+ * We use the first parameter to build the metadata (struct l1_ttable and
+ * struct l2_dtable) necessary to track kernel mappings.
+ */
+#define PMAP_STATIC_L2_SIZE 16
+void
+pmap_bootstrap(pd_entry_t *kernel_l1pt, vaddr_t vstart, vaddr_t vend)
+{
+ static struct l1_ttable static_l1;
+ static struct l2_dtable static_l2[PMAP_STATIC_L2_SIZE];
+ struct l1_ttable *l1 = &static_l1;
+ struct l2_dtable *l2;
+ struct l2_bucket *l2b;
+ pmap_t pm = pmap_kernel();
+ pd_entry_t pde;
+ pt_entry_t *ptep;
+ paddr_t pa;
+ vaddr_t va;
+ vsize_t size;
+ int l1idx, l2idx, l2next = 0;
+
+ /*
+ * Initialise the kernel pmap object
+ */
+ pm->pm_l1 = l1;
+ pm->pm_domain = PMAP_DOMAIN_KERNEL;
+ pm->pm_cstate.cs_all = PMAP_CACHE_STATE_ALL;
+ simple_lock_init(&pm->pm_lock);
+ pm->pm_obj.pgops = NULL;
+ TAILQ_INIT(&pm->pm_obj.memq);
+ pm->pm_obj.uo_npages = 0;
+ pm->pm_obj.uo_refs = 1;
+
+ /*
+ * Scan the L1 translation table created by initarm() and create
+ * the required metadata for all valid mappings found in it.
+ */
+ for (l1idx = 0; l1idx < (L1_TABLE_SIZE / sizeof(pd_entry_t)); l1idx++) {
+ pde = kernel_l1pt[l1idx];
+
+ /*
+ * We're only interested in Coarse mappings.
+ * pmap_extract() can deal with section mappings without
+ * recourse to checking L2 metadata.
+ */
+ if ((pde & L1_TYPE_MASK) != L1_TYPE_C)
+ continue;
+
+ /*
+ * Lookup the KVA of this L2 descriptor table
+ */
+ pa = (paddr_t)(pde & L1_C_ADDR_MASK);
+ ptep = (pt_entry_t *)kernel_pt_lookup(pa);
+ if (ptep == NULL) {
+ panic("pmap_bootstrap: No L2 for va 0x%x, pa 0x%lx",
+ (u_int)l1idx << L1_S_SHIFT, pa);
+ }
+
+ /*
+ * Fetch the associated L2 metadata structure.
+ * Allocate a new one if necessary.
+ */
+ if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) {
+ if (l2next == PMAP_STATIC_L2_SIZE)
+ panic("pmap_bootstrap: out of static L2s");
+ pm->pm_l2[L2_IDX(l1idx)] = l2 = &static_l2[l2next++];
+ }
+
+ /*
+ * One more L1 slot tracked...
+ */
+ l2->l2_occupancy++;
+
+ /*
+ * Fill in the details of the L2 descriptor in the
+ * appropriate bucket.
+ */
+ l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+ l2b->l2b_kva = ptep;
+ l2b->l2b_phys = pa;
+ l2b->l2b_l1idx = l1idx;
+
+ /*
+ * Establish an initial occupancy count for this descriptor
+ */
+ for (l2idx = 0;
+ l2idx < (L2_TABLE_SIZE_REAL / sizeof(pt_entry_t));
+ l2idx++) {
+ if ((ptep[l2idx] & L2_TYPE_MASK) != L2_TYPE_INV) {
+ l2b->l2b_occupancy++;
+ }
+ }
+
+ /*
+ * Make sure the descriptor itself has the correct cache mode.
+ * If not, fix it, but whine about the problem. Port-meisters
+ * should consider this a clue to fix up their initarm()
+ * function. :)
+ */
+ if (pmap_set_pt_cache_mode(kernel_l1pt, (vaddr_t)ptep)) {
+ printf("pmap_bootstrap: WARNING! wrong cache mode for "
+ "L2 pte @ %p\n", ptep);
+ }
+ }
+
+ /*
+ * Ensure the primary (kernel) L1 has the correct cache mode for
+ * a page table. Bitch if it is not correctly set.
+ */
+ for (va = (vaddr_t)kernel_l1pt;
+ va < ((vaddr_t)kernel_l1pt + L1_TABLE_SIZE); va += PAGE_SIZE) {
+ if (pmap_set_pt_cache_mode(kernel_l1pt, va))
+ printf("pmap_bootstrap: WARNING! wrong cache mode for "
+ "primary L1 @ 0x%lx\n", va);
+ }
+
+ cpu_dcache_wbinv_all();
+ cpu_tlb_flushID();
+ cpu_cpwait();
+
+ /*
+ * now we allocate the "special" VAs which are used for tmp mappings
+ * by the pmap (and other modules). we allocate the VAs by advancing
+ * virtual_avail (note that there are no pages mapped at these VAs).
+ *
+ * Managed KVM space start from wherever initarm() tells us.
+ */
+ virtual_avail = vstart;
+ virtual_end = vend;
+
+ pmap_alloc_specials(&virtual_avail, 1, &csrcp, &csrc_pte);
+ pmap_set_pt_cache_mode(kernel_l1pt, (vaddr_t)csrc_pte);
+ pmap_alloc_specials(&virtual_avail, 1, &cdstp, &cdst_pte);
+ pmap_set_pt_cache_mode(kernel_l1pt, (vaddr_t)cdst_pte);
+ pmap_alloc_specials(&virtual_avail, 1, (void *)&memhook, NULL);
+ pmap_alloc_specials(&virtual_avail, round_page(MSGBUFSIZE) / PAGE_SIZE,
+ (void *)&msgbufaddr, NULL);
+
+ /*
+ * Allocate a range of kernel virtual address space to be used
+ * for L2 descriptor tables and metadata allocation in
+ * pmap_growkernel().
+ */
+ size = ((virtual_end - pmap_curmaxkvaddr) + L1_S_OFFSET) / L1_S_SIZE;
+ pmap_alloc_specials(&virtual_avail,
+ round_page(size * L2_TABLE_SIZE_REAL) / PAGE_SIZE,
+ &pmap_kernel_l2ptp_kva, NULL);
+
+ size = (size + (L2_BUCKET_SIZE - 1)) / L2_BUCKET_SIZE;
+ pmap_alloc_specials(&virtual_avail,
+ round_page(size * sizeof(struct l2_dtable)) / PAGE_SIZE,
+ &pmap_kernel_l2dtable_kva, NULL);
+
+ /*
+ * init the static-global locks and global pmap list.
+ */
+#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG)
+ spinlockinit(&pmap_main_lock, "pmaplk", 0);
+#endif
+
+ /*
+ * We can now initialise the first L1's metadata.
+ */
+ SLIST_INIT(&l1_list);
+ TAILQ_INIT(&l1_lru_list);
+ simple_lock_init(&l1_lru_lock);
+ pmap_init_l1(l1, kernel_l1pt);
+
+ /*
+ * Initialize the pmap pool and cache
+ */
+ pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmappl",
+ &pool_allocator_nointr);
+ pool_cache_init(&pmap_pmap_cache, &pmap_pmap_pool,
+ pmap_pmap_ctor, NULL, NULL);
+ LIST_INIT(&pmap_pmaps);
+ LIST_INSERT_HEAD(&pmap_pmaps, pm, pm_list);
+
+ /*
+ * Initialize the pv pool.
+ */
+ pool_init(&pmap_pv_pool, sizeof(struct pv_entry), 0, 0, 0, "pvepl",
+ &pmap_bootstrap_pv_allocator);
+
+ /*
+ * Initialize the L2 dtable pool and cache.
+ */
+ pool_init(&pmap_l2dtable_pool, sizeof(struct l2_dtable), 0, 0, 0,
+ "l2dtblpl", NULL);
+ pool_cache_init(&pmap_l2dtable_cache, &pmap_l2dtable_pool,
+ pmap_l2dtable_ctor, NULL, NULL);
+
+ /*
+ * Initialise the L2 descriptor table pool and cache
+ */
+ pool_init(&pmap_l2ptp_pool, L2_TABLE_SIZE_REAL, 0, L2_TABLE_SIZE_REAL,
+ 0, "l2ptppl", NULL);
+ pool_cache_init(&pmap_l2ptp_cache, &pmap_l2ptp_pool,
+ pmap_l2ptp_ctor, NULL, NULL);
+
+ cpu_dcache_wbinv_all();
+}
+
+int
+pmap_set_pt_cache_mode(pd_entry_t *kl1, vaddr_t va)
+{
+ pd_entry_t *pdep, pde;
+ pt_entry_t *ptep, pte;
+ vaddr_t pa;
+ int rv = 0;
+
+ /*
+ * Make sure the descriptor itself has the correct cache mode
+ */
+ pdep = &kl1[L1_IDX(va)];
+ pde = *pdep;
+
+ if (l1pte_section_p(pde)) {
+ if ((pde & L1_S_CACHE_MASK) != pte_l1_s_cache_mode_pt) {
+ *pdep = (pde & ~L1_S_CACHE_MASK) |
+ pte_l1_s_cache_mode_pt;
+ PTE_SYNC(pdep);
+ cpu_dcache_wbinv_range((vaddr_t)pdep, sizeof(*pdep));
+ rv = 1;
+ }
+ } else {
+ pa = (paddr_t)(pde & L1_C_ADDR_MASK);
+ ptep = (pt_entry_t *)kernel_pt_lookup(pa);
+ if (ptep == NULL)
+ panic("pmap_bootstrap: No L2 for L2 @ va %p\n", ptep);
+
+ ptep = &ptep[l2pte_index(va)];
+ pte = *ptep;
+ if ((pte & L2_S_CACHE_MASK) != pte_l2_s_cache_mode_pt) {
+ *ptep = (pte & ~L2_S_CACHE_MASK) |
+ pte_l2_s_cache_mode_pt;
+ PTE_SYNC(ptep);
+ cpu_dcache_wbinv_range((vaddr_t)ptep, sizeof(*ptep));
+ rv = 1;
+ }
+ }
+
+ return (rv);
+}
+
+void
+pmap_alloc_specials(vaddr_t *availp, int pages, vaddr_t *vap, pt_entry_t **ptep)
+{
+ vaddr_t va = *availp;
+ struct l2_bucket *l2b;
+
+ if (ptep) {
+ l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+ if (l2b == NULL)
+ panic("pmap_alloc_specials: no l2b for 0x%lx", va);
+
+ if (ptep)
+ *ptep = &l2b->l2b_kva[l2pte_index(va)];
+ }
+
+ *vap = va;
+ *availp = va + (PAGE_SIZE * pages);
+}
+
+void
+pmap_init(void)
+{
+ extern int physmem;
+
+ /*
+ * Set the available memory vars - These do not map to real memory
+ * addresses and cannot as the physical memory is fragmented.
+ * They are used by ps for %mem calculations.
+ * One could argue whether this should be the entire memory or just
+ * the memory that is useable in a user process.
+ */
+ avail_start = 0;
+ avail_end = physmem * PAGE_SIZE;
+
+ /*
+ * Now we need to free enough pv_entry structures to allow us to get
+ * the kmem_map/kmem_object allocated and inited (done after this
+ * function is finished). to do this we allocate one bootstrap page out
+ * of kernel_map and use it to provide an initial pool of pv_entry
+ * structures. we never free this page.
+ */
+ pool_setlowat(&pmap_pv_pool,
+ (PAGE_SIZE / sizeof(struct pv_entry)) * 2);
+
+ pmap_initialized = TRUE;
+}
+
+static vaddr_t last_bootstrap_page = 0;
+static void *free_bootstrap_pages = NULL;
+
+void *
+pmap_bootstrap_pv_page_alloc(struct pool *pp, int flags)
+{
+ extern void *pool_page_alloc(struct pool *, int);
+ vaddr_t new_page;
+ void *rv;
+
+ if (pmap_initialized)
+ return (pool_page_alloc(pp, flags));
+
+ if (free_bootstrap_pages) {
+ rv = free_bootstrap_pages;
+ free_bootstrap_pages = *((void **)rv);
+ return (rv);
+ }
+
+ new_page = uvm_km_kmemalloc(kernel_map, NULL, PAGE_SIZE,
+ (flags & PR_WAITOK) ? 0 : UVM_KMF_NOWAIT);
+
+ KASSERT(new_page > last_bootstrap_page);
+ last_bootstrap_page = new_page;
+ return ((void *)new_page);
+}
+
+void
+pmap_bootstrap_pv_page_free(struct pool *pp, void *v)
+{
+ extern void pool_page_free(struct pool *, void *);
+
+ if (pmap_initialized) {
+ pool_page_free(pp, v);
+ return;
+ }
+
+ if ((vaddr_t)v < last_bootstrap_page) {
+ *((void **)v) = free_bootstrap_pages;
+ free_bootstrap_pages = v;
+ return;
+ }
+}
+
+/*
+ * pmap_postinit()
+ *
+ * This routine is called after the vm and kmem subsystems have been
+ * initialised. This allows the pmap code to perform any initialisation
+ * that can only be done one the memory allocation is in place.
+ */
+void
+pmap_postinit(void)
+{
+ extern paddr_t physical_start, physical_end;
+ struct l2_bucket *l2b;
+ struct l1_ttable *l1;
+ struct pglist plist;
+ struct vm_page *m;
+ pd_entry_t *pl1pt;
+ pt_entry_t *ptep, pte;
+ vaddr_t va, eva;
+ u_int loop, needed;
+ int error;
+
+ pool_setlowat(&pmap_l2ptp_pool,
+ (PAGE_SIZE / L2_TABLE_SIZE_REAL) * 4);
+ pool_setlowat(&pmap_l2dtable_pool,
+ (PAGE_SIZE / sizeof(struct l2_dtable)) * 2);
+
+ needed = (maxproc / PMAP_DOMAINS) + ((maxproc % PMAP_DOMAINS) ? 1 : 0);
+ needed -= 1;
+
+ l1 = malloc(sizeof(*l1) * needed, M_VMPMAP, M_WAITOK);
+
+ for (loop = 0; loop < needed; loop++, l1++) {
+ /* Allocate a L1 page table */
+ va = uvm_km_valloc(kernel_map, L1_TABLE_SIZE);
+ if (va == 0)
+ panic("Cannot allocate L1 KVM");
+
+ TAILQ_INIT(&plist);
+
+ error = uvm_pglistalloc(L1_TABLE_SIZE, physical_start,
+ physical_end, L1_TABLE_SIZE, 0, &plist, 1, M_WAITOK);
+ if (error)
+ panic("Cannot allocate L1 physical pages");
+
+ m = TAILQ_FIRST(&plist);
+ eva = va + L1_TABLE_SIZE;
+ pl1pt = (pd_entry_t *)va;
+
+ while (m && va < eva) {
+ paddr_t pa = VM_PAGE_TO_PHYS(m);
+
+
+ pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
+
+ /*
+ * Make sure the L1 descriptor table is mapped
+ * with the cache-mode set to write-through.
+ */
+ l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+ ptep = &l2b->l2b_kva[l2pte_index(va)];
+ pte = *ptep;
+ pte = (pte & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode_pt;
+ *ptep = pte;
+ PTE_SYNC(ptep);
+ cpu_tlb_flushD_SE(va);
+
+ va += PAGE_SIZE;
+ m = m->pageq.tqe_next;
+ }
+
+#ifdef DIAGNOSTIC
+ if (m)
+ panic("pmap_alloc_l1pt: pglist not empty");
+#endif /* DIAGNOSTIC */
+
+ pmap_init_l1(l1, pl1pt);
+ }
+
+#ifdef DEBUG
+ printf("pmap_postinit: Allocated %d static L1 descriptor tables\n",
+ needed);
+#endif
+}
+
+/*
+ * Note that the following routines are used by board-specific initialisation
+ * code to configure the initial kernel page tables.
+ *
+ * If ARM32_NEW_VM_LAYOUT is *not* defined, they operate on the assumption that
+ * L2 page-table pages are 4KB in size and use 4 L1 slots. This mimics the
+ * behaviour of the old pmap, and provides an easy migration path for
+ * initial bring-up of the new pmap on existing ports. Fortunately,
+ * pmap_bootstrap() compensates for this hackery. This is only a stop-gap and
+ * will be deprecated.
+ *
+ * If ARM32_NEW_VM_LAYOUT *is* defined, these functions deal with 1KB L2 page
+ * tables.
+ */
+
+/*
+ * This list exists for the benefit of pmap_map_chunk(). It keeps track
+ * of the kernel L2 tables during bootstrap, so that pmap_map_chunk() can
+ * find them as necessary.
+ *
+ * Note that the data on this list MUST remain valid after initarm() returns,
+ * as pmap_bootstrap() uses it to contruct L2 table metadata.
+ */
+SLIST_HEAD(, pv_addr) kernel_pt_list = SLIST_HEAD_INITIALIZER(kernel_pt_list);
+
+vaddr_t
+kernel_pt_lookup(paddr_t pa)
+{
+ pv_addr_t *pv;
+
+ SLIST_FOREACH(pv, &kernel_pt_list, pv_list) {
+#ifndef ARM32_NEW_VM_LAYOUT
+ if (pv->pv_pa == (pa & ~PGOFSET))
+ return (pv->pv_va | (pa & PGOFSET));
+#else
+ if (pv->pv_pa == pa)
+ return (pv->pv_va);
+#endif
+ }
+ return (0);
+}
+
+/*
+ * pmap_map_section:
+ *
+ * Create a single section mapping.
+ */
+void
+pmap_map_section(vaddr_t l1pt, vaddr_t va, paddr_t pa, int prot, int cache)
+{
+ pd_entry_t *pde = (pd_entry_t *) l1pt;
+ pd_entry_t fl;
+
+ KASSERT(((va | pa) & L1_S_OFFSET) == 0);
+
+ switch (cache) {
+ case PTE_NOCACHE:
+ default:
+ fl = 0;
+ break;
+
+ case PTE_CACHE:
+ fl = pte_l1_s_cache_mode;
+ break;
+
+ case PTE_PAGETABLE:
+ fl = pte_l1_s_cache_mode_pt;
+ break;
+ }
+
+ pde[va >> L1_S_SHIFT] = L1_S_PROTO | pa |
+ L1_S_PROT(PTE_KERNEL, prot) | fl | L1_S_DOM(PMAP_DOMAIN_KERNEL);
+ PTE_SYNC(&pde[va >> L1_S_SHIFT]);
+}
+
+/*
+ * pmap_map_entry:
+ *
+ * Create a single page mapping.
+ */
+void
+pmap_map_entry(vaddr_t l1pt, vaddr_t va, paddr_t pa, int prot, int cache)
+{
+ pd_entry_t *pde = (pd_entry_t *) l1pt;
+ pt_entry_t fl;
+ pt_entry_t *pte;
+
+ KASSERT(((va | pa) & PGOFSET) == 0);
+
+ switch (cache) {
+ case PTE_NOCACHE:
+ default:
+ fl = 0;
+ break;
+
+ case PTE_CACHE:
+ fl = pte_l2_s_cache_mode;
+ break;
+
+ case PTE_PAGETABLE:
+ fl = pte_l2_s_cache_mode_pt;
+ break;
+ }
+
+ if ((pde[va >> L1_S_SHIFT] & L1_TYPE_MASK) != L1_TYPE_C)
+ panic("pmap_map_entry: no L2 table for VA 0x%08lx", va);
+
+#ifndef ARM32_NEW_VM_LAYOUT
+ pte = (pt_entry_t *)
+ kernel_pt_lookup(pde[va >> L1_S_SHIFT] & L2_S_FRAME);
+#else
+ pte = (pt_entry_t *) kernel_pt_lookup(pde[L1_IDX(va)] & L1_C_ADDR_MASK);
+#endif
+ if (pte == NULL)
+ panic("pmap_map_entry: can't find L2 table for VA 0x%08lx", va);
+
+#ifndef ARM32_NEW_VM_LAYOUT
+ pte[(va >> PGSHIFT) & 0x3ff] =
+ L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | fl;
+ PTE_SYNC(&pte[(va >> PGSHIFT) & 0x3ff]);
+#else
+ pte[l2pte_index(va)] =
+ L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | fl;
+ PTE_SYNC(&pte[l2pte_index(va)]);
+#endif
+}
+
+/*
+ * pmap_link_l2pt:
+ *
+ * Link the L2 page table specified by "l2pv" into the L1
+ * page table at the slot for "va".
+ */
+void
+pmap_link_l2pt(vaddr_t l1pt, vaddr_t va, pv_addr_t *l2pv)
+{
+ pd_entry_t *pde = (pd_entry_t *) l1pt, proto;
+ u_int slot = va >> L1_S_SHIFT;
+
+#ifndef ARM32_NEW_VM_LAYOUT
+ KASSERT((va & ((L1_S_SIZE * 4) - 1)) == 0);
+ KASSERT((l2pv->pv_pa & PGOFSET) == 0);
+#endif
+
+ proto = L1_S_DOM(PMAP_DOMAIN_KERNEL) | L1_C_PROTO;
+
+ pde[slot + 0] = proto | (l2pv->pv_pa + 0x000);
+#ifdef ARM32_NEW_VM_LAYOUT
+ PTE_SYNC(&pde[slot]);
+#else
+ pde[slot + 1] = proto | (l2pv->pv_pa + 0x400);
+ pde[slot + 2] = proto | (l2pv->pv_pa + 0x800);
+ pde[slot + 3] = proto | (l2pv->pv_pa + 0xc00);
+ PTE_SYNC_RANGE(&pde[slot + 0], 4);
+#endif
+
+ SLIST_INSERT_HEAD(&kernel_pt_list, l2pv, pv_list);
+}
+
+/*
+ * pmap_map_chunk:
+ *
+ * Map a chunk of memory using the most efficient mappings
+ * possible (section, large page, small page) into the
+ * provided L1 and L2 tables at the specified virtual address.
+ */
+vsize_t
+pmap_map_chunk(vaddr_t l1pt, vaddr_t va, paddr_t pa, vsize_t size,
+ int prot, int cache)
+{
+ pd_entry_t *pde = (pd_entry_t *) l1pt;
+ pt_entry_t *pte, f1, f2s, f2l;
+ vsize_t resid;
+ int i;
+
+ resid = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+
+ if (l1pt == 0)
+ panic("pmap_map_chunk: no L1 table provided");
+
+#ifdef VERBOSE_INIT_ARM
+ printf("pmap_map_chunk: pa=0x%lx va=0x%lx size=0x%lx resid=0x%lx "
+ "prot=0x%x cache=%d\n", pa, va, size, resid, prot, cache);
+#endif
+
+ switch (cache) {
+ case PTE_NOCACHE:
+ default:
+ f1 = 0;
+ f2l = 0;
+ f2s = 0;
+ break;
+
+ case PTE_CACHE:
+ f1 = pte_l1_s_cache_mode;
+ f2l = pte_l2_l_cache_mode;
+ f2s = pte_l2_s_cache_mode;
+ break;
+
+ case PTE_PAGETABLE:
+ f1 = pte_l1_s_cache_mode_pt;
+ f2l = pte_l2_l_cache_mode_pt;
+ f2s = pte_l2_s_cache_mode_pt;
+ break;
+ }
+
+ size = resid;
+
+ while (resid > 0) {
+ /* See if we can use a section mapping. */
+ if (L1_S_MAPPABLE_P(va, pa, resid)) {
+#ifdef VERBOSE_INIT_ARM
+ printf("S");
+#endif
+ pde[va >> L1_S_SHIFT] = L1_S_PROTO | pa |
+ L1_S_PROT(PTE_KERNEL, prot) | f1 |
+ L1_S_DOM(PMAP_DOMAIN_KERNEL);
+ PTE_SYNC(&pde[va >> L1_S_SHIFT]);
+ va += L1_S_SIZE;
+ pa += L1_S_SIZE;
+ resid -= L1_S_SIZE;
+ continue;
+ }
+
+ /*
+ * Ok, we're going to use an L2 table. Make sure
+ * one is actually in the corresponding L1 slot
+ * for the current VA.
+ */
+ if ((pde[va >> L1_S_SHIFT] & L1_TYPE_MASK) != L1_TYPE_C)
+ panic("pmap_map_chunk: no L2 table for VA 0x%08lx", va);
+
+#ifndef ARM32_NEW_VM_LAYOUT
+ pte = (pt_entry_t *)
+ kernel_pt_lookup(pde[va >> L1_S_SHIFT] & L2_S_FRAME);
+#else
+ pte = (pt_entry_t *) kernel_pt_lookup(
+ pde[L1_IDX(va)] & L1_C_ADDR_MASK);
+#endif
+ if (pte == NULL)
+ panic("pmap_map_chunk: can't find L2 table for VA"
+ "0x%08lx", va);
+
+ /* See if we can use a L2 large page mapping. */
+ if (L2_L_MAPPABLE_P(va, pa, resid)) {
+#ifdef VERBOSE_INIT_ARM
+ printf("L");
+#endif
+ for (i = 0; i < 16; i++) {
+#ifndef ARM32_NEW_VM_LAYOUT
+ pte[((va >> PGSHIFT) & 0x3f0) + i] =
+ L2_L_PROTO | pa |
+ L2_L_PROT(PTE_KERNEL, prot) | f2l;
+ PTE_SYNC(&pte[((va >> PGSHIFT) & 0x3f0) + i]);
+#else
+ pte[l2pte_index(va) + i] =
+ L2_L_PROTO | pa |
+ L2_L_PROT(PTE_KERNEL, prot) | f2l;
+ PTE_SYNC(&pte[l2pte_index(va) + i]);
+#endif
+ }
+ va += L2_L_SIZE;
+ pa += L2_L_SIZE;
+ resid -= L2_L_SIZE;
+ continue;
+ }
+
+ /* Use a small page mapping. */
+#ifdef VERBOSE_INIT_ARM
+ printf("P");
+#endif
+#ifndef ARM32_NEW_VM_LAYOUT
+ pte[(va >> PGSHIFT) & 0x3ff] =
+ L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | f2s;
+ PTE_SYNC(&pte[(va >> PGSHIFT) & 0x3ff]);
+#else
+ pte[l2pte_index(va)] =
+ L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, prot) | f2s;
+ PTE_SYNC(&pte[l2pte_index(va)]);
+#endif
+ va += PAGE_SIZE;
+ pa += PAGE_SIZE;
+ resid -= PAGE_SIZE;
+ }
+#ifdef VERBOSE_INIT_ARM
+ printf("\n");
+#endif
+ return (size);
+}
+
+/********************** Static device map routines ***************************/
+
+const struct pmap_devmap *pmap_devmap_table;
+
+/*
+ * Register the devmap table. This is provided in case early console
+ * initialization needs to register mappings created by bootstrap code
+ * before pmap_devmap_bootstrap() is called.
+ */
+void
+pmap_devmap_register(const struct pmap_devmap *table)
+{
+
+ pmap_devmap_table = table;
+}
+
+/*
+ * Map all of the static regions in the devmap table, and remember
+ * the devmap table so other parts of the kernel can look up entries
+ * later.
+ */
+void
+pmap_devmap_bootstrap(vaddr_t l1pt, const struct pmap_devmap *table)
+{
+ int i;
+
+ pmap_devmap_table = table;
+
+ for (i = 0; pmap_devmap_table[i].pd_size != 0; i++) {
+#ifdef VERBOSE_INIT_ARM
+ printf("devmap: %08lx -> %08lx @ %08lx\n",
+ pmap_devmap_table[i].pd_pa,
+ pmap_devmap_table[i].pd_pa +
+ pmap_devmap_table[i].pd_size - 1,
+ pmap_devmap_table[i].pd_va);
+#endif
+ pmap_map_chunk(l1pt, pmap_devmap_table[i].pd_va,
+ pmap_devmap_table[i].pd_pa,
+ pmap_devmap_table[i].pd_size,
+ pmap_devmap_table[i].pd_prot,
+ pmap_devmap_table[i].pd_cache);
+ }
+}
+
+const struct pmap_devmap *
+pmap_devmap_find_pa(paddr_t pa, psize_t size)
+{
+ int i;
+
+ if (pmap_devmap_table == NULL)
+ return (NULL);
+
+ for (i = 0; pmap_devmap_table[i].pd_size != 0; i++) {
+ if (pa >= pmap_devmap_table[i].pd_pa &&
+ pa + size <= pmap_devmap_table[i].pd_pa +
+ pmap_devmap_table[i].pd_size)
+ return (&pmap_devmap_table[i]);
+ }
+
+ return (NULL);
+}
+
+const struct pmap_devmap *
+pmap_devmap_find_va(vaddr_t va, vsize_t size)
+{
+ int i;
+
+ if (pmap_devmap_table == NULL)
+ return (NULL);
+
+ for (i = 0; pmap_devmap_table[i].pd_size != 0; i++) {
+ if (va >= pmap_devmap_table[i].pd_va &&
+ va + size <= pmap_devmap_table[i].pd_va +
+ pmap_devmap_table[i].pd_size)
+ return (&pmap_devmap_table[i]);
+ }
+
+ return (NULL);
+}
+
+/********************** PTE initialization routines **************************/
+
+/*
+ * These routines are called when the CPU type is identified to set up
+ * the PTE prototypes, cache modes, etc.
+ *
+ * The variables are always here, just in case LKMs need to reference
+ * them (though, they shouldn't).
+ */
+
+pt_entry_t pte_l1_s_cache_mode;
+pt_entry_t pte_l1_s_cache_mode_pt;
+pt_entry_t pte_l1_s_cache_mask;
+
+pt_entry_t pte_l2_l_cache_mode;
+pt_entry_t pte_l2_l_cache_mode_pt;
+pt_entry_t pte_l2_l_cache_mask;
+
+pt_entry_t pte_l2_s_cache_mode;
+pt_entry_t pte_l2_s_cache_mode_pt;
+pt_entry_t pte_l2_s_cache_mask;
+
+pt_entry_t pte_l2_s_prot_u;
+pt_entry_t pte_l2_s_prot_w;
+pt_entry_t pte_l2_s_prot_mask;
+
+pt_entry_t pte_l1_s_proto;
+pt_entry_t pte_l1_c_proto;
+pt_entry_t pte_l2_s_proto;
+
+void (*pmap_copy_page_func)(struct vm_page *, struct vm_page *);
+void (*pmap_zero_page_func)(struct vm_page *);
+
+#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0
+void
+pmap_pte_init_generic(void)
+{
+
+ pte_l1_s_cache_mode = L1_S_B|L1_S_C;
+ pte_l1_s_cache_mask = L1_S_CACHE_MASK_generic;
+
+ pte_l2_l_cache_mode = L2_B|L2_C;
+ pte_l2_l_cache_mask = L2_L_CACHE_MASK_generic;
+
+ pte_l2_s_cache_mode = L2_B|L2_C;
+ pte_l2_s_cache_mask = L2_S_CACHE_MASK_generic;
+
+ /*
+ * If we have a write-through cache, set B and C. If
+ * we have a write-back cache, then we assume setting
+ * only C will make those pages write-through.
+ */
+ if (cpufuncs.cf_dcache_wb_range == (void *) cpufunc_nullop) {
+ pte_l1_s_cache_mode_pt = L1_S_B|L1_S_C;
+ pte_l2_l_cache_mode_pt = L2_B|L2_C;
+ pte_l2_s_cache_mode_pt = L2_B|L2_C;
+ } else {
+ pte_l1_s_cache_mode_pt = L1_S_C;
+ pte_l2_l_cache_mode_pt = L2_C;
+ pte_l2_s_cache_mode_pt = L2_C;
+ }
+
+ pte_l2_s_prot_u = L2_S_PROT_U_generic;
+ pte_l2_s_prot_w = L2_S_PROT_W_generic;
+ pte_l2_s_prot_mask = L2_S_PROT_MASK_generic;
+
+ pte_l1_s_proto = L1_S_PROTO_generic;
+ pte_l1_c_proto = L1_C_PROTO_generic;
+ pte_l2_s_proto = L2_S_PROTO_generic;
+
+ pmap_copy_page_func = pmap_copy_page_generic;
+ pmap_zero_page_func = pmap_zero_page_generic;
+}
+
+#if defined(CPU_ARM8)
+void
+pmap_pte_init_arm8(void)
+{
+
+ /*
+ * ARM8 is compatible with generic, but we need to use
+ * the page tables uncached.
+ */
+ pmap_pte_init_generic();
+
+ pte_l1_s_cache_mode_pt = 0;
+ pte_l2_l_cache_mode_pt = 0;
+ pte_l2_s_cache_mode_pt = 0;
+}
+#endif /* CPU_ARM8 */
+
+#if defined(CPU_ARM9)
+void
+pmap_pte_init_arm9(void)
+{
+
+ /*
+ * ARM9 is compatible with generic, but we want to use
+ * write-through caching for now.
+ */
+ pmap_pte_init_generic();
+
+ pte_l1_s_cache_mode = L1_S_C;
+ pte_l2_l_cache_mode = L2_C;
+ pte_l2_s_cache_mode = L2_C;
+
+ pte_l1_s_cache_mode_pt = L1_S_C;
+ pte_l2_l_cache_mode_pt = L2_C;
+ pte_l2_s_cache_mode_pt = L2_C;
+}
+#endif /* CPU_ARM9 */
+#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */
+
+#if defined(CPU_ARM10)
+void
+pmap_pte_init_arm10(void)
+{
+
+ /*
+ * ARM10 is compatible with generic, but we want to use
+ * write-through caching for now.
+ */
+ pmap_pte_init_generic();
+
+ pte_l1_s_cache_mode = L1_S_B | L1_S_C;
+ pte_l2_l_cache_mode = L2_B | L2_C;
+ pte_l2_s_cache_mode = L2_B | L2_C;
+
+ pte_l1_s_cache_mode_pt = L1_S_C;
+ pte_l2_l_cache_mode_pt = L2_C;
+ pte_l2_s_cache_mode_pt = L2_C;
+
+}
+#endif /* CPU_ARM10 */
+
+#if ARM_MMU_SA1 == 1
+void
+pmap_pte_init_sa1(void)
+{
+
+ /*
+ * The StrongARM SA-1 cache does not have a write-through
+ * mode. So, do the generic initialization, then reset
+ * the page table cache mode to B=1,C=1, and note that
+ * the PTEs need to be sync'd.
+ */
+ pmap_pte_init_generic();
+
+ pte_l1_s_cache_mode_pt = L1_S_B|L1_S_C;
+ pte_l2_l_cache_mode_pt = L2_B|L2_C;
+ pte_l2_s_cache_mode_pt = L2_B|L2_C;
+
+ pmap_needs_pte_sync = 1;
+}
+#endif /* ARM_MMU_SA1 == 1*/
+
+#if ARM_MMU_XSCALE == 1
+#if (ARM_NMMUS > 1)
+u_int xscale_use_minidata;
+#endif
+
+void
+pmap_pte_init_xscale(void)
+{
+ uint32_t auxctl;
+ int write_through = 0;
+
+ pte_l1_s_cache_mode = L1_S_B|L1_S_C;
+ pte_l1_s_cache_mask = L1_S_CACHE_MASK_xscale;
+
+ pte_l2_l_cache_mode = L2_B|L2_C;
+ pte_l2_l_cache_mask = L2_L_CACHE_MASK_xscale;
+
+ pte_l2_s_cache_mode = L2_B|L2_C;
+ pte_l2_s_cache_mask = L2_S_CACHE_MASK_xscale;
+
+ pte_l1_s_cache_mode_pt = L1_S_C;
+ pte_l2_l_cache_mode_pt = L2_C;
+ pte_l2_s_cache_mode_pt = L2_C;
+
+#ifdef XSCALE_CACHE_READ_WRITE_ALLOCATE
+ /*
+ * The XScale core has an enhanced mode where writes that
+ * miss the cache cause a cache line to be allocated. This
+ * is significantly faster than the traditional, write-through
+ * behavior of this case.
+ */
+ pte_l1_s_cache_mode |= L1_S_XSCALE_TEX(TEX_XSCALE_X);
+ pte_l2_l_cache_mode |= L2_XSCALE_L_TEX(TEX_XSCALE_X);
+ pte_l2_s_cache_mode |= L2_XSCALE_T_TEX(TEX_XSCALE_X);
+#endif /* XSCALE_CACHE_READ_WRITE_ALLOCATE */
+
+#ifdef XSCALE_CACHE_WRITE_THROUGH
+ /*
+ * Some versions of the XScale core have various bugs in
+ * their cache units, the work-around for which is to run
+ * the cache in write-through mode. Unfortunately, this
+ * has a major (negative) impact on performance. So, we
+ * go ahead and run fast-and-loose, in the hopes that we
+ * don't line up the planets in a way that will trip the
+ * bugs.
+ *
+ * However, we give you the option to be slow-but-correct.
+ */
+ write_through = 1;
+#elif defined(XSCALE_CACHE_WRITE_BACK)
+ /* force write back cache mode */
+ write_through = 0;
+#elif defined(CPU_XSCALE_PXA2X0)
+ /*
+ * Intel PXA2[15]0 processors are known to have a bug in
+ * write-back cache on revision 4 and earlier (stepping
+ * A[01] and B[012]). Fixed for C0 and later.
+ */
+ {
+ uint32_t id, type;
+
+ id = cpufunc_id();
+ type = id & ~(CPU_ID_XSCALE_COREREV_MASK|CPU_ID_REVISION_MASK);
+
+ if (type == CPU_ID_PXA250 || type == CPU_ID_PXA210) {
+ if ((id & CPU_ID_REVISION_MASK) < 5) {
+ /* write through for stepping A0-1 and B0-2 */
+ write_through = 1;
+ }
+ }
+ }
+#endif /* XSCALE_CACHE_WRITE_THROUGH */
+
+ if (write_through) {
+ pte_l1_s_cache_mode = L1_S_C;
+ pte_l2_l_cache_mode = L2_C;
+ pte_l2_s_cache_mode = L2_C;
+ }
+
+#if (ARM_NMMUS > 1)
+ xscale_use_minidata = 1;
+#endif
+
+ pte_l2_s_prot_u = L2_S_PROT_U_xscale;
+ pte_l2_s_prot_w = L2_S_PROT_W_xscale;
+ pte_l2_s_prot_mask = L2_S_PROT_MASK_xscale;
+
+ pte_l1_s_proto = L1_S_PROTO_xscale;
+ pte_l1_c_proto = L1_C_PROTO_xscale;
+ pte_l2_s_proto = L2_S_PROTO_xscale;
+
+ pmap_copy_page_func = pmap_copy_page_xscale;
+ pmap_zero_page_func = pmap_zero_page_xscale;
+
+ /*
+ * Disable ECC protection of page table access, for now.
+ */
+ __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctl));
+ auxctl &= ~XSCALE_AUXCTL_P;
+ __asm __volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (auxctl));
+}
+
+/*
+ * xscale_setup_minidata:
+ *
+ * Set up the mini-data cache clean area. We require the
+ * caller to allocate the right amount of physically and
+ * virtually contiguous space.
+ */
+vaddr_t xscale_minidata_clean_addr;
+vsize_t xscale_minidata_clean_size; /* already initialized */
+
+void
+xscale_setup_minidata(vaddr_t l1pt, vaddr_t va, paddr_t pa)
+{
+ extern vaddr_t xscale_minidata_clean_addr;
+ extern vsize_t xscale_minidata_clean_size; /* already initialized */
+ pd_entry_t *pde = (pd_entry_t *) l1pt;
+ pt_entry_t *pte;
+ vsize_t size;
+ uint32_t auxctl;
+ panic("xscale_setup_minidata: xscale_minidata_clean_size, "
+ "xscale_minidata_clean_addr");
+
+ xscale_minidata_clean_addr = va;
+
+ /* Round it to page size. */
+ size = (xscale_minidata_clean_size + L2_S_OFFSET) & L2_S_FRAME;
+
+ for (; size != 0;
+ va += L2_S_SIZE, pa += L2_S_SIZE, size -= L2_S_SIZE) {
+#ifndef ARM32_NEW_VM_LAYOUT
+ pte = (pt_entry_t *)
+ kernel_pt_lookup(pde[va >> L1_S_SHIFT] & L2_S_FRAME);
+#else
+ pte = (pt_entry_t *) kernel_pt_lookup(
+ pde[L1_IDX(va)] & L1_C_ADDR_MASK);
+#endif
+ if (pte == NULL)
+ panic("xscale_setup_minidata: can't find L2 table for "
+ "VA 0x%08lx", va);
+#ifndef ARM32_NEW_VM_LAYOUT
+ pte[(va >> PGSHIFT) & 0x3ff] =
+#else
+ pte[l2pte_index(va)] =
+#endif
+ L2_S_PROTO | pa | L2_S_PROT(PTE_KERNEL, VM_PROT_READ) |
+ L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X);
+ }
+
+ /*
+ * Configure the mini-data cache for write-back with
+ * read/write-allocate.
+ *
+ * NOTE: In order to reconfigure the mini-data cache, we must
+ * make sure it contains no valid data! In order to do that,
+ * we must issue a global data cache invalidate command!
+ *
+ * WE ASSUME WE ARE RUNNING UN-CACHED WHEN THIS ROUTINE IS CALLED!
+ * THIS IS VERY IMPORTANT!
+ */
+
+ /* Invalidate data and mini-data. */
+ __asm __volatile("mcr p15, 0, %0, c7, c6, 0" : : "r" (0));
+ __asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (auxctl));
+ auxctl = (auxctl & ~XSCALE_AUXCTL_MD_MASK) | XSCALE_AUXCTL_MD_WB_RWA;
+ __asm __volatile("mcr p15, 0, %0, c1, c0, 1" : : "r" (auxctl));
+}
+
+/*
+ * Change the PTEs for the specified kernel mappings such that they
+ * will use the mini data cache instead of the main data cache.
+ */
+void
+pmap_uarea(vaddr_t va)
+{
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, *sptep, pte;
+ vaddr_t next_bucket, eva;
+
+#if (ARM_NMMUS > 1)
+ if (xscale_use_minidata == 0)
+ return;
+#endif
+
+ eva = va + USPACE;
+
+ while (va < eva) {
+ next_bucket = L2_NEXT_BUCKET(va);
+ if (next_bucket > eva)
+ next_bucket = eva;
+
+ l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+ KDASSERT(l2b != NULL);
+
+ sptep = ptep = &l2b->l2b_kva[l2pte_index(va)];
+
+ while (va < next_bucket) {
+ pte = *ptep;
+ if (!l2pte_minidata(pte)) {
+ cpu_dcache_wbinv_range(va, PAGE_SIZE);
+ cpu_tlb_flushD_SE(va);
+ *ptep = pte & ~L2_B;
+ }
+ ptep++;
+ va += PAGE_SIZE;
+ }
+ PTE_SYNC_RANGE(sptep, (u_int)(ptep - sptep));
+ }
+ cpu_cpwait();
+}
+#endif /* ARM_MMU_XSCALE == 1 */
+
+#if defined(DDB)
+/*
+ * A couple of ddb-callable functions for dumping pmaps
+ */
+void pmap_dump_all(void);
+void pmap_dump(pmap_t);
+
+void
+pmap_dump_all(void)
+{
+ pmap_t pm;
+
+ LIST_FOREACH(pm, &pmap_pmaps, pm_list) {
+ if (pm == pmap_kernel())
+ continue;
+ pmap_dump(pm);
+ printf("\n");
+ }
+}
+
+static pt_entry_t ncptes[64];
+void pmap_dump_ncpg(pmap_t);
+
+void
+pmap_dump(pmap_t pm)
+{
+ struct l2_dtable *l2;
+ struct l2_bucket *l2b;
+ pt_entry_t *ptep, pte;
+ vaddr_t l2_va, l2b_va, va;
+ int i, j, k, occ, rows = 0;
+
+ if (pm == pmap_kernel())
+ printf("pmap_kernel (%p): ", pm);
+ else
+ printf("user pmap (%p): ", pm);
+
+ printf("domain %d, l1 at %p\n", pm->pm_domain, pm->pm_l1->l1_kva);
+
+ l2_va = 0;
+ for (i = 0; i < L2_SIZE; i++, l2_va += 0x01000000) {
+ l2 = pm->pm_l2[i];
+
+ if (l2 == NULL || l2->l2_occupancy == 0)
+ continue;
+
+ l2b_va = l2_va;
+ for (j = 0; j < L2_BUCKET_SIZE; j++, l2b_va += 0x00100000) {
+ l2b = &l2->l2_bucket[j];
+
+ if (l2b->l2b_occupancy == 0 || l2b->l2b_kva == NULL)
+ continue;
+
+ ptep = l2b->l2b_kva;
+
+ for (k = 0; k < 256 && ptep[k] == 0; k++)
+ ;
+
+ k &= ~63;
+ occ = l2b->l2b_occupancy;
+ va = l2b_va + (k * 4096);
+ for (; k < 256; k++, va += 0x1000) {
+ char ch = ' ';
+ if ((k % 64) == 0) {
+ if ((rows % 8) == 0) {
+ printf(
+" |0000 |8000 |10000 |18000 |20000 |28000 |30000 |38000\n");
+ }
+ printf("%08lx: ", va);
+ }
+
+ ncptes[k & 63] = 0;
+ pte = ptep[k];
+ if (pte == 0) {
+ ch = '.';
+ } else {
+ occ--;
+ switch (pte & 0x0c) {
+ case 0x00:
+ ch = 'D'; /* No cache No buff */
+ break;
+ case 0x04:
+ ch = 'B'; /* No cache buff */
+ break;
+ case 0x08:
+ if (pte & 0x40)
+ ch = 'm';
+ else
+ ch = 'C'; /* Cache No buff */
+ break;
+ case 0x0c:
+ ch = 'F'; /* Cache Buff */
+ break;
+ }
+
+ if ((pte & L2_S_PROT_U) == L2_S_PROT_U)
+ ch += 0x20;
+
+ if ((pte & 0xc) == 0)
+ ncptes[k & 63] = pte;
+ }
+
+ if ((k % 64) == 63) {
+ rows++;
+ printf("%c\n", ch);
+ pmap_dump_ncpg(pm);
+ if (occ == 0)
+ break;
+ } else
+ printf("%c", ch);
+ }
+ }
+ }
+}
+
+void
+pmap_dump_ncpg(pmap_t pm)
+{
+ struct vm_page *pg;
+ struct pv_entry *pv;
+ int i;
+
+ for (i = 0; i < 63; i++) {
+ if (ncptes[i] == 0)
+ continue;
+
+ pg = PHYS_TO_VM_PAGE(l2pte_pa(ncptes[i]));
+ if (pg == NULL)
+ continue;
+
+ printf(" pa 0x%08lx: krw %d kro %d urw %d uro %d\n",
+ pg->phys_addr,
+ pg->mdpage.krw_mappings, pg->mdpage.kro_mappings,
+ pg->mdpage.urw_mappings, pg->mdpage.uro_mappings);
+
+ for (pv = pg->mdpage.pvh_list; pv; pv = pv->pv_next) {
+ printf(" %c va 0x%08lx, flags 0x%x\n",
+ (pm == pv->pv_pmap) ? '*' : ' ',
+ pv->pv_va, pv->pv_flags);
+ }
+ }
+}
+#endif
diff --git a/sys/arch/arm/arm/process_machdep.c b/sys/arch/arm/arm/process_machdep.c
new file mode 100644
index 00000000000..b1ac0c9a97d
--- /dev/null
+++ b/sys/arch/arm/arm/process_machdep.c
@@ -0,0 +1,225 @@
+/* $OpenBSD: process_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: process_machdep.c,v 1.11 2003/08/07 16:26:52 agc Exp $ */
+
+/*
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From:
+ * Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel
+ */
+
+/*
+ * Copyright (c) 1995 Frank Lancaster. All rights reserved.
+ * Copyright (c) 1995 Tools GmbH. All rights reserved.
+ * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1993 Jan-Simon Pendry
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * From:
+ * Id: procfs_i386.c,v 4.1 1993/12/17 10:47:45 jsp Rel
+ */
+
+/*
+ * This file may seem a bit stylized, but that so that it's easier to port.
+ * Functions to be implemented here are:
+ *
+ * process_read_regs(proc, regs)
+ * Get the current user-visible register set from the process
+ * and copy it into the regs structure (<machine/reg.h>).
+ * The process is stopped at the time read_regs is called.
+ *
+ * process_write_regs(proc, regs)
+ * Update the current register set from the passed in regs
+ * structure. Take care to avoid clobbering special CPU
+ * registers or privileged bits in the PSL.
+ * The process is stopped at the time write_regs is called.
+ *
+ * process_sstep(proc, sstep)
+ * Arrange for the process to trap or not trap depending on sstep
+ * after executing a single instruction.
+ *
+ * process_set_pc(proc)
+ * Set the process's program counter.
+ */
+
+#include <sys/param.h>
+
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <machine/reg.h>
+
+#include <arm/armreg.h>
+
+#ifdef ARMFPE
+#include <arm/fpe-arm/armfpe.h>
+#endif
+
+static __inline struct trapframe *
+process_frame(struct proc *p)
+{
+
+ return p->p_addr->u_pcb.pcb_tf;
+}
+
+int
+process_read_regs(struct proc *p, struct reg *regs)
+{
+ struct trapframe *tf = process_frame(p);
+
+ KASSERT(tf != NULL);
+ bcopy((caddr_t)&tf->tf_r0, (caddr_t)regs->r, sizeof(regs->r));
+ regs->r_sp = tf->tf_usr_sp;
+ regs->r_lr = tf->tf_usr_lr;
+ regs->r_pc = tf->tf_pc;
+ regs->r_cpsr = tf->tf_spsr;
+
+#ifdef DIAGNOSTIC
+ if ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE
+ && tf->tf_spsr & I32_bit)
+ panic("process_read_regs: Interrupts blocked in user process");
+#endif
+
+ return(0);
+}
+
+int
+process_read_fpregs(struct proc *p, struct fpreg *regs)
+{
+#ifdef ARMFPE
+ arm_fpe_getcontext(p, regs);
+ return(0);
+#else /* ARMFPE */
+ /* No hardware FP support */
+ memset(regs, 0, sizeof(struct fpreg));
+ return(0);
+#endif /* ARMFPE */
+}
+
+int
+process_write_regs(struct proc *p, struct reg *regs)
+{
+ struct trapframe *tf = process_frame(p);
+
+ KASSERT(tf != NULL);
+ bcopy((caddr_t)regs->r, (caddr_t)&tf->tf_r0, sizeof(regs->r));
+ tf->tf_usr_sp = regs->r_sp;
+ tf->tf_usr_lr = regs->r_lr;
+#ifdef __PROG32
+ tf->tf_pc = regs->r_pc;
+ tf->tf_spsr &= ~PSR_FLAGS;
+ tf->tf_spsr |= regs->r_cpsr & PSR_FLAGS;
+#ifdef DIAGNOSTIC
+ if ((tf->tf_spsr & PSR_MODE) == PSR_USR32_MODE
+ && tf->tf_spsr & I32_bit)
+ panic("process_write_regs: Interrupts blocked in user process");
+#endif
+#else /* __PROG26 */
+ if ((regs->r_pc & (R15_MODE | R15_IRQ_DISABLE | R15_FIQ_DISABLE)) != 0)
+ return EPERM;
+
+ tf->tf_r15 = regs->r_pc;
+#endif
+
+ return(0);
+}
+
+int
+process_write_fpregs(struct proc *p, struct fpreg *regs)
+{
+#ifdef ARMFPE
+ arm_fpe_setcontext(p, regs);
+ return(0);
+#else /* ARMFPE */
+ /* No hardware FP support */
+ return(0);
+#endif /* ARMFPE */
+}
+
+int
+process_sstep(struct proc *p, int sstep)
+{
+ /* XXX */
+ return 0;
+}
+
+int
+process_set_pc(struct proc *p, caddr_t addr)
+{
+ struct trapframe *tf = process_frame(p);
+
+ KASSERT(tf != NULL);
+#ifdef __PROG32
+ tf->tf_pc = (int)addr;
+#else /* __PROG26 */
+ /* Only set the PC, not the PSR */
+ if (((register_t)addr & R15_PC) != (register_t)addr)
+ return EINVAL;
+ tf->tf_r15 = (tf->tf_r15 & ~R15_PC) | (register_t)addr;
+#endif
+
+ return (0);
+}
diff --git a/sys/arch/arm/arm/procfs_machdep.c b/sys/arch/arm/arm/procfs_machdep.c
new file mode 100644
index 00000000000..ecde04d2802
--- /dev/null
+++ b/sys/arch/arm/arm/procfs_machdep.c
@@ -0,0 +1,23 @@
+/* $OpenBSD: procfs_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: procfs_machdep.c,v 1.2 2003/07/15 00:24:39 lukem Exp $ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <miscfs/procfs/procfs.h>
+
+
+#if 0
+/*
+ * Linux-style /proc/cpuinfo.
+ * Only used when procfs is mounted with -o linux.
+ */
+int
+procfs_getcpuinfstr(char *buf, int *len)
+{
+ *len = 0;
+
+ return 0;
+}
+#endif
diff --git a/sys/arch/arm/arm/setcpsr.S b/sys/arch/arm/arm/setcpsr.S
new file mode 100644
index 00000000000..86129919ef1
--- /dev/null
+++ b/sys/arch/arm/arm/setcpsr.S
@@ -0,0 +1,79 @@
+/* $OpenBSD: setcpsr.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: setcpsr.S,v 1.2 2002/08/15 01:37:02 briggs Exp $^I*/$
+
+/*
+ * Copyright (c) 1994 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * setcpsr.S
+ *
+ * Miscellaneous routines to play with the CPSR register
+ *
+ * Eventually this routine can be inline assembly.
+ *
+ * Created : 12/09/94
+ *
+ * Based of kate/display/setcpsr.s
+ */
+
+#include <machine/asm.h>
+
+/* Sets and clears bits in the CPSR register
+ *
+ * r0 - bic mask
+ * r1 - eor mask
+ */
+
+ENTRY_NP(SetCPSR)
+ mrs r3, cpsr /* Set the CPSR */
+ bic r2, r3, r0
+ eor r2, r2, r1
+ msr cpsr_all, r2
+
+ mov r0, r3 /* Return the old CPSR */
+
+ mov pc, lr
+
+
+/* Gets the CPSR register
+ *
+ * Returns the CPSR in r0
+ */
+
+ENTRY_NP(GetCPSR)
+ mrs r0, cpsr /* Get the CPSR */
+
+ mov pc, lr
+
diff --git a/sys/arch/arm/arm/setstack.S b/sys/arch/arm/arm/setstack.S
new file mode 100644
index 00000000000..0d3925db9bb
--- /dev/null
+++ b/sys/arch/arm/arm/setstack.S
@@ -0,0 +1,93 @@
+/* $OpenBSD: setstack.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: setstack.S,v 1.2 2002/08/15 01:37:02 briggs Exp $^I*/$
+
+/*
+ * Copyright (c) 1994 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * setstack.S
+ *
+ * Miscellaneous routine to play with the stack pointer in different CPU modes
+ *
+ * Eventually this routine can be inline assembly.
+ *
+ * Created : 17/09/94
+ *
+ * Based of kate/display/setstack.s
+ */
+
+#include <machine/cpu.h>
+#include <machine/asm.h>
+
+/* To set the stack pointer for a particular mode we must switch
+ * to that mode update the banked r13 and then switch back.
+ * This routine provides an easy way of doing this for any mode
+ *
+ * r0 = CPU mode
+ * r1 = stackptr
+ */
+
+ENTRY(set_stackptr)
+ mrs r3, cpsr /* Switch to the appropriate mode */
+ bic r2, r3, #(PSR_MODE)
+ orr r2, r2, r0
+ msr cpsr_all, r2
+
+ mov sp, r1 /* Set the stack pointer */
+
+ msr cpsr_all, r3 /* Restore the old mode */
+
+ mov pc, lr /* Exit */
+
+/* To get the stack pointer for a particular mode we must switch
+ * to that mode copy the banked r13 and then switch back.
+ * This routine provides an easy way of doing this for any mode
+ *
+ * r0 = CPU mode
+ */
+
+ENTRY(get_stackptr)
+ mrs r3, cpsr /* Switch to the appropriate mode */
+ bic r2, r3, #(PSR_MODE)
+ orr r2, r2, r0
+ msr cpsr_all, r2
+
+ mov r0, sp /* Set the stack pointer */
+
+ msr cpsr_all, r3 /* Restore the old mode */
+
+ mov pc, lr /* Exit */
+
+/* End of setstack.S */
diff --git a/sys/arch/arm/arm/sig_machdep.c b/sys/arch/arm/arm/sig_machdep.c
new file mode 100644
index 00000000000..cf5756ba210
--- /dev/null
+++ b/sys/arch/arm/arm/sig_machdep.c
@@ -0,0 +1,384 @@
+/* $OpenBSD: sig_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: sig_machdep.c,v 1.22 2003/10/08 00:28:41 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Machine dependant functions for kernel setup
+ *
+ * Created : 17/09/94
+ */
+
+#include <sys/param.h>
+
+#include <sys/mount.h> /* XXX only needed by syscallargs.h */
+#include <sys/proc.h>
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/syscallargs.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+
+#include <arm/armreg.h>
+
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#ifndef acorn26
+#include <arm/cpufunc.h>
+#endif
+
+static __inline struct trapframe *
+process_frame(struct proc *p)
+{
+
+ return p->p_addr->u_pcb.pcb_tf;
+}
+
+void *getframe(struct proc *p, int sig, int *onstack);
+
+
+/*
+ * Send an interrupt to process.
+ *
+ * Stack is set up to allow sigcode stored
+ * in u. to call routine, followed by kcall
+ * to sigreturn routine below. After sigreturn
+ * resets the signal mask, the stack, and the
+ * frame pointer, it returns to the user specified pc.
+ */
+void
+sendsig(sig_t catcher, int sig, int returnmask, u_long code, int type,
+ union sigval val)
+{
+ struct proc *p = curproc;
+ struct trapframe *tf;
+ struct sigframe *fp, frame;
+ struct sigacts *psp = p->p_sigacts;
+ int oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
+ int onstack = 0;
+
+ tf = process_frame(p);
+
+ /* Do we need to jump onto the signal stack? */
+
+ /* Allocate space for the signal handler context. */
+ if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack &&
+ (psp->ps_sigonstack & sigmask(sig))) {
+ onstack = 1;
+ fp = (struct sigframe *)((caddr_t)psp->ps_sigstk.ss_sp +
+ psp->ps_sigstk.ss_size);
+ } else
+ fp = (struct sigframe *)tf->tf_usr_sp;
+ /* make room on the stack */
+ fp--;
+
+ /* make the stack aligned */
+ fp = (void *)STACKALIGN(fp);
+
+ /* Build stack frame for signal trampoline. */
+ frame.sf_signum = sig;
+ frame.sf_sip = NULL;
+ frame.sf_scp = &fp->sf_sc;
+ frame.sf_handler = catcher;
+
+ /* Save register context. */
+ frame.sf_sc.sc_r0 = tf->tf_r0;
+ frame.sf_sc.sc_r1 = tf->tf_r1;
+ frame.sf_sc.sc_r2 = tf->tf_r2;
+ frame.sf_sc.sc_r3 = tf->tf_r3;
+ frame.sf_sc.sc_r4 = tf->tf_r4;
+ frame.sf_sc.sc_r5 = tf->tf_r5;
+ frame.sf_sc.sc_r6 = tf->tf_r6;
+ frame.sf_sc.sc_r7 = tf->tf_r7;
+ frame.sf_sc.sc_r8 = tf->tf_r8;
+ frame.sf_sc.sc_r9 = tf->tf_r9;
+ frame.sf_sc.sc_r10 = tf->tf_r10;
+ frame.sf_sc.sc_r11 = tf->tf_r11;
+ frame.sf_sc.sc_r12 = tf->tf_r12;
+ frame.sf_sc.sc_usr_sp = tf->tf_usr_sp;
+ frame.sf_sc.sc_usr_lr = tf->tf_usr_lr;
+ frame.sf_sc.sc_svc_lr = tf->tf_svc_lr;
+ frame.sf_sc.sc_pc = tf->tf_pc;
+ frame.sf_sc.sc_spsr = tf->tf_spsr;
+
+ /* Save signal stack. */
+ frame.sf_sc.sc_onstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
+
+ /* Save signal mask. */
+ frame.sf_sc.sc_mask = returnmask;
+
+ if (psp->ps_siginfo & sigmask(sig)) {
+ frame.sf_sip = &fp->sf_si;
+ initsiginfo(&frame.sf_si, sig, code, type, val);
+ }
+
+ if (copyout(&frame, fp, sizeof(frame)) != 0) {
+ /*
+ * Process has trashed its stack; give it an illegal
+ * instruction to halt it in its tracks.
+ */
+ sigexit(p, SIGILL);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Build context to run handler in. We invoke the handler
+ * directly, only returning via the trampoline. Note the
+ * trampoline version numbers are coordinated with machine-
+ * dependent code in libc.
+ */
+
+ /*
+ * this was all in the switch below, seemed daft to duplicate it, if
+ * we do a new trampoline version it might change then
+ */
+ tf->tf_r0 = sig;
+ tf->tf_r1 = code;
+ tf->tf_r2 = (int)frame.sf_scp;
+ tf->tf_pc = (int)frame.sf_handler;
+ tf->tf_usr_sp = (int)fp;
+
+ tf->tf_usr_lr = (int)p->p_sigcode;
+ /* XXX This should not be needed. */
+ cpu_icache_sync_all();
+
+ /* Remember that we're now on the signal stack. */
+ if (onstack)
+ psp->ps_sigstk.ss_flags |= SS_ONSTACK;
+}
+
+#if 0
+void *
+getframe(struct proc *p, int sig, int *onstack)
+{
+ struct sigctx *ctx = &p->p_sigctx;
+ struct trapframe *tf = process_frame(l);
+
+ /* Do we need to jump onto the signal stack? */
+ *onstack = (ctx->ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0
+ && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
+ if (*onstack)
+ return (char *)ctx->ps_sigstk.ss_sp + ctx->ps_sigstk.ss_size;
+ return (void *)tf->tf_usr_sp;
+}
+#endif
+
+
+/*
+ * System call to cleanup state after a signal
+ * has been taken. Reset signal mask and
+ * stack state from context left by sendsig (above).
+ * Return to previous pc and psl as specified by
+ * context left by sendsig. Check carefully to
+ * make sure that the user has not modified the
+ * psr to gain improper privileges or to cause
+ * a machine fault.
+ */
+
+int
+sys_sigreturn(struct proc *p, void *v, register_t *retval)
+{
+ struct sys_sigreturn_args /* {
+ syscallarg(struct sigcontext *) sigcntxp;
+ } */ *uap = v;
+ struct sigcontext *scp, context;
+ struct trapframe *tf;
+ struct sigacts *psp = p->p_sigacts;
+
+ /*
+ * we do a rather scary test in userland
+ */
+ if (v == NULL)
+ return (EFAULT);
+
+ /*
+ * The trampoline code hands us the context.
+ * It is unsafe to keep track of it ourselves, in the event that a
+ * program jumps out of a signal handler.
+ */
+ scp = SCARG(uap, sigcntxp);
+ if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
+ return (EFAULT);
+
+ /*
+ * Make sure the processor mode has not been tampered with and
+ * interrupts have not been disabled.
+ */
+#ifdef __PROG32
+ if ((context.sc_spsr & PSR_MODE) != PSR_USR32_MODE ||
+ (context.sc_spsr & (I32_bit | F32_bit)) != 0)
+ return (EINVAL);
+#else /* __PROG26 */
+ if ((context.sc_pc & R15_MODE) != R15_MODE_USR ||
+ (context.sc_pc & (R15_IRQ_DISABLE | R15_FIQ_DISABLE)) != 0)
+ return EINVAL;
+#endif
+
+ /* Restore register context. */
+ tf = process_frame(p);
+ tf->tf_r0 = context.sc_r0;
+ tf->tf_r1 = context.sc_r1;
+ tf->tf_r2 = context.sc_r2;
+ tf->tf_r3 = context.sc_r3;
+ tf->tf_r4 = context.sc_r4;
+ tf->tf_r5 = context.sc_r5;
+ tf->tf_r6 = context.sc_r6;
+ tf->tf_r7 = context.sc_r7;
+ tf->tf_r8 = context.sc_r8;
+ tf->tf_r9 = context.sc_r9;
+ tf->tf_r10 = context.sc_r10;
+ tf->tf_r11 = context.sc_r11;
+ tf->tf_r12 = context.sc_r12;
+ tf->tf_usr_sp = context.sc_usr_sp;
+ tf->tf_usr_lr = context.sc_usr_lr;
+ tf->tf_svc_lr = context.sc_svc_lr;
+ tf->tf_pc = context.sc_pc;
+ tf->tf_spsr = context.sc_spsr;
+
+ /* Restore signal stack. */
+ if (context.sc_onstack & SS_ONSTACK)
+ psp->ps_sigstk.ss_flags |= SS_ONSTACK;
+ else
+ psp->ps_sigstk.ss_flags &= ~SS_ONSTACK;
+
+ /* Restore signal mask. */
+#if 0
+ (void) sigprocmask1(p, SIG_SETMASK, &context.sc_mask, 0);
+#else
+ p->p_sigmask = context.sc_mask & ~sigcantmask;
+#endif
+
+ return (EJUSTRETURN);
+}
+
+#if 0
+void
+cpu_getmcontext(p, mcp, flags)
+ struct proc *p;
+ mcontext_t *mcp;
+ unsigned int *flags;
+{
+ struct trapframe *tf = process_frame(p);
+ __greg_t *gr = mcp->__gregs;
+ __greg_t ras_pc;
+
+ /* Save General Register context. */
+ gr[_REG_R0] = tf->tf_r0;
+ gr[_REG_R1] = tf->tf_r1;
+ gr[_REG_R2] = tf->tf_r2;
+ gr[_REG_R3] = tf->tf_r3;
+ gr[_REG_R4] = tf->tf_r4;
+ gr[_REG_R5] = tf->tf_r5;
+ gr[_REG_R6] = tf->tf_r6;
+ gr[_REG_R7] = tf->tf_r7;
+ gr[_REG_R8] = tf->tf_r8;
+ gr[_REG_R9] = tf->tf_r9;
+ gr[_REG_R10] = tf->tf_r10;
+ gr[_REG_R11] = tf->tf_r11;
+ gr[_REG_R12] = tf->tf_r12;
+ gr[_REG_SP] = tf->tf_usr_sp;
+ gr[_REG_LR] = tf->tf_usr_lr;
+ gr[_REG_PC] = tf->tf_pc;
+ gr[_REG_CPSR] = tf->tf_spsr;
+
+ if ((ras_pc = (__greg_t)ras_lookup(l->l_proc,
+ (caddr_t) gr[_REG_PC])) != -1)
+ gr[_REG_PC] = ras_pc;
+
+ *flags |= _UC_CPU;
+
+#ifdef ARMFPE
+ /* Save Floating Point Register context. */
+ arm_fpe_getcontext(p, (struct fpreg *)(void *)&mcp->fpregs);
+ *flags |= _UC_FPU;
+#endif
+}
+
+int
+cpu_setmcontext(p, mcp, flags)
+ struct proc *p;
+ const mcontext_t *mcp;
+ unsigned int flags;
+{
+ struct trapframe *tf = process_frame(l);
+ __greg_t *gr = mcp->__gregs;
+
+ if ((flags & _UC_CPU) != 0) {
+ /* Restore General Register context. */
+ /* Make sure the processor mode has not been tampered with. */
+#ifdef PROG32
+ if ((gr[_REG_CPSR] & PSR_MODE) != PSR_USR32_MODE ||
+ (gr[_REG_CPSR] & (I32_bit | F32_bit)) != 0)
+ return (EINVAL);
+#else /* PROG26 */
+ if ((gr[_REG_PC] & R15_MODE) != R15_MODE_USR ||
+ (gr[_REG_PC] & (R15_IRQ_DISABLE | R15_FIQ_DISABLE)) != 0)
+ return (EINVAL);
+#endif
+
+ tf->tf_r0 = gr[_REG_R0];
+ tf->tf_r1 = gr[_REG_R1];
+ tf->tf_r2 = gr[_REG_R2];
+ tf->tf_r3 = gr[_REG_R3];
+ tf->tf_r4 = gr[_REG_R4];
+ tf->tf_r5 = gr[_REG_R5];
+ tf->tf_r6 = gr[_REG_R6];
+ tf->tf_r7 = gr[_REG_R7];
+ tf->tf_r8 = gr[_REG_R8];
+ tf->tf_r9 = gr[_REG_R9];
+ tf->tf_r10 = gr[_REG_R10];
+ tf->tf_r11 = gr[_REG_R11];
+ tf->tf_r12 = gr[_REG_R12];
+ tf->tf_usr_sp = gr[_REG_SP];
+ tf->tf_usr_lr = gr[_REG_LR];
+ tf->tf_pc = gr[_REG_PC];
+ tf->tf_spsr = gr[_REG_CPSR];
+ }
+
+#ifdef ARMFPE
+ if ((flags & _UC_FPU) != 0) {
+ /* Restore Floating Point Register context. */
+ arm_fpe_setcontext(p, (struct fpreg *)(void *)&mcp->__fpregs);
+ }
+#endif
+ if (flags & _UC_SETSTACK)
+ l->l_proc->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK;
+ if (flags & _UC_CLRSTACK)
+ l->l_proc->p_sigctx.ps_sigstk.ss_flags &= ~SS_ONSTACK;
+
+ return (0);
+}
+#endif
diff --git a/sys/arch/arm/arm/sigcode.S b/sys/arch/arm/arm/sigcode.S
new file mode 100644
index 00000000000..c46cc6e12d0
--- /dev/null
+++ b/sys/arch/arm/arm/sigcode.S
@@ -0,0 +1,62 @@
+/* $OpenBSD: sigcode.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: sigcode.S,v 1.6 2003/10/05 19:44:58 matt Exp $ */
+
+/*
+ * Copyright (C) 1994-1997 Mark Brinicombe
+ * Copyright (C) 1994 Brini
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of Brini may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+#include "assym.h"
+#include <sys/syscall.h>
+
+/*
+ * Signal trampoline;
+ */
+
+ENTRY_NP(sigcode)
+/*
+ * The kernel arranges for the handler to be invoked directly. This
+ * trampoline is used only to return from the signal.
+ *
+ * The stack pointer points to the saved sigcontext.
+ */
+/* mov r0, sp */
+ add r0, sp, #SIGF_SC
+ swi SYS_sigreturn
+
+/* Well if that failed we better exit quick ! */
+
+ swi SYS_exit
+ b . - 8
+
+ .align 0
+ .global _C_LABEL(esigcode)
+_C_LABEL(esigcode):
diff --git a/sys/arch/arm/arm/softintr.c b/sys/arch/arm/arm/softintr.c
new file mode 100644
index 00000000000..bf6be9b552c
--- /dev/null
+++ b/sys/arch/arm/arm/softintr.c
@@ -0,0 +1,207 @@
+/* $OpenBSD: softintr.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: softintr.c,v 1.2 2003/07/15 00:24:39 lukem Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+
+/* XXX Network interrupts should be converted to new softintrs. */
+#include <net/netisr.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/intr.h>
+
+struct soft_intrq soft_intrq[SI_NQUEUES];
+
+struct soft_intrhand *softnet_intrhand;
+
+void netintr(void);
+
+/*
+ * softintr_init:
+ *
+ * Initialize the software interrupt system.
+ */
+void
+softintr_init(void)
+{
+#if 0
+ static const char *softintr_names[] = SI_QUEUENAMES;
+#endif
+ struct soft_intrq *siq;
+ int i;
+
+ for (i = 0; i < SI_NQUEUES; i++) {
+ siq = &soft_intrq[i];
+ TAILQ_INIT(&siq->siq_list);
+#if 0
+ evcnt_attach_dynamic(&siq->siq_evcnt, EVCNT_TYPE_INTR,
+ NULL, "soft", softintr_names[i]);
+#endif
+ siq->siq_si = i;
+ }
+
+ /* XXX Establish legacy software interrupt handlers. */
+ softnet_intrhand = softintr_establish(IPL_SOFTNET,
+ (void (*)(void *))netintr, NULL);
+
+ assert(softnet_intrhand != NULL);
+}
+
+/*
+ * softintr_dispatch:
+ *
+ * Process pending software interrupts on the specified queue.
+ *
+ * NOTE: We must already be at the correct interrupt priority level.
+ */
+void
+softintr_dispatch(int si)
+{
+ struct soft_intrq *siq = &soft_intrq[si];
+ struct soft_intrhand *sih;
+ int oldirqstate;
+
+ siq->siq_evcnt.ev_count++;
+ for (;;) {
+ oldirqstate = disable_interrupts(I32_bit);
+ sih = TAILQ_FIRST(&siq->siq_list);
+ if (sih == NULL) {
+ restore_interrupts(oldirqstate);
+ break;
+ }
+
+ TAILQ_REMOVE(&siq->siq_list, sih, sih_list);
+ sih->sih_pending = 0;
+
+ uvmexp.softs++;
+
+ restore_interrupts(oldirqstate);
+
+ (*sih->sih_func)(sih->sih_arg);
+ }
+}
+
+/*
+ * softintr_establish: [interface]
+ *
+ * Register a software interrupt handler.
+ */
+void *
+softintr_establish(int ipl, void (*func)(void *), void *arg)
+{
+ struct soft_intrhand *sih;
+ int si;
+
+ switch (ipl) {
+ case IPL_SOFT:
+ si = SI_SOFT;
+ break;
+
+ case IPL_SOFTCLOCK:
+ si = SI_SOFTCLOCK;
+ break;
+
+ case IPL_SOFTNET:
+ si = SI_SOFTNET;
+ break;
+
+ case IPL_TTY:
+ case IPL_SOFTSERIAL:
+ si = SI_SOFTSERIAL;
+ break;
+
+ default:
+ panic("softintr_establish: unknown soft IPL %d", ipl);
+ }
+
+ sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT);
+ if (__predict_true(sih != NULL)) {
+ sih->sih_func = func;
+ sih->sih_arg = arg;
+ sih->sih_siq = &soft_intrq[si];
+ sih->sih_pending = 0;
+ }
+printf("softintr_establish ipl 0x%x si %d\n", ipl, si);
+ return (sih);
+}
+
+/*
+ * softintr_disestablish: [interface]
+ *
+ * Unregister a software interrupt handler.
+ */
+void
+softintr_disestablish(void *arg)
+{
+ struct soft_intrhand *sih = arg;
+ struct soft_intrq *siq = sih->sih_siq;
+ int oldirqstate;
+
+ oldirqstate = disable_interrupts(I32_bit);
+ if (sih->sih_pending) {
+ TAILQ_REMOVE(&siq->siq_list, sih, sih_list);
+ sih->sih_pending = 0;
+ }
+ restore_interrupts(oldirqstate);
+
+ free(sih, M_DEVBUF);
+}
+
+int netisr;
+
+void
+netintr(void)
+{
+ int n, s;
+
+ s = splhigh();
+ n = netisr;
+ netisr = 0;
+ splx(s);
+
+#define DONETISR(bit, fn) \
+ do { \
+ if (n & (1 << (bit))) \
+ fn(); \
+ } while (/*CONSTCOND*/0)
+
+#include <net/netisr_dispatch.h>
+
+#undef DONETISR
+}
diff --git a/sys/arch/arm/arm/stubs.c b/sys/arch/arm/arm/stubs.c
new file mode 100644
index 00000000000..29996d0273a
--- /dev/null
+++ b/sys/arch/arm/arm/stubs.c
@@ -0,0 +1,215 @@
+/* $OpenBSD: stubs.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: stubs.c,v 1.14 2003/07/15 00:24:42 lukem Exp $^I*/$
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Routines that are temporary or do not have a home yet.
+ *
+ * Created : 17/09/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/msgbuf.h>
+#include <uvm/uvm_extern.h>
+#include <machine/cpu.h>
+#include <machine/intr.h>
+#include <machine/bootconfig.h>
+#include <machine/pcb.h>
+#include <arm/machdep.h>
+
+extern dev_t dumpdev;
+
+/*
+ * These variables are needed by /sbin/savecore
+ */
+u_int32_t dumpmag = 0x8fca0101; /* magic number */
+int dumpsize = 0; /* pages */
+long dumplo = 0; /* blocks */
+
+struct pcb dumppcb;
+
+/*
+ * This is called by main to set dumplo and dumpsize.
+ * Dumps always skip the first CLBYTES of disk space
+ * in case there might be a disk label stored there.
+ * If there is extra space, put dump at the end to
+ * reduce the chance that swapping trashes it.
+ */
+
+void dumpconf(void);
+
+void
+dumpconf()
+{
+ const struct bdevsw *bdev;
+ int nblks; /* size of dump area */
+
+ if (dumpdev == NODEV)
+ return;
+ bdev = bdevsw_lookup(dumpdev);
+ if (bdev == NULL)
+ panic("dumpconf: bad dumpdev=0x%x", dumpdev);
+ if (bdev->d_psize == NULL)
+ return;
+ nblks = (*bdev->d_psize)(dumpdev);
+ if (nblks <= ctod(1))
+ return;
+
+ dumpsize = physmem;
+
+ /* Always skip the first CLBYTES, in case there is a label there. */
+ if (dumplo < ctod(1))
+ dumplo = ctod(1);
+
+ /* Put dump at end of partition, and make it fit. */
+ if (dumpsize > dtoc(nblks - dumplo))
+ dumpsize = dtoc(nblks - dumplo);
+ if (dumplo < nblks - ctod(dumpsize))
+ dumplo = nblks - ctod(dumpsize);
+}
+
+/* This should be moved to machdep.c */
+
+extern char *memhook; /* XXX */
+
+/*
+ * Doadump comes here after turning off memory management and
+ * getting on the dump stack, either when called above, or by
+ * the auto-restart code.
+ */
+
+void
+dumpsys()
+{
+ const struct bdevsw *bdev;
+ daddr_t blkno;
+ int psize;
+ int error;
+ int addr;
+ int block;
+ int len;
+ vaddr_t dumpspace;
+
+ /* Save registers. */
+ savectx(&dumppcb);
+ /* flush everything out of caches */
+ cpu_dcache_wbinv_all();
+
+ if (dumpdev == NODEV)
+ return;
+ if (dumpsize == 0) {
+ dumpconf();
+ if (dumpsize == 0)
+ return;
+ }
+ if (dumplo <= 0) {
+ printf("\ndump to dev %u,%u not possible\n", major(dumpdev),
+ minor(dumpdev));
+ return;
+ }
+ printf("\ndumping to dev %u,%u offset %ld\n", major(dumpdev),
+ minor(dumpdev), dumplo);
+
+ blkno = dumplo;
+ dumpspace = (vaddr_t) memhook;
+
+ bdev = bdevsw_lookup(dumpdev);
+ if (bdev == NULL || bdev->d_psize == NULL)
+ return;
+ psize = (*bdev->d_psize)(dumpdev);
+ printf("dump ");
+ if (psize == -1) {
+ printf("area unavailable\n");
+ return;
+ }
+
+ error = 0;
+ len = 0;
+
+ for (block = 0; block < bootconfig.dramblocks && error == 0; ++block) {
+ addr = bootconfig.dram[block].address;
+ for (;addr < (bootconfig.dram[block].address
+ + (bootconfig.dram[block].pages * PAGE_SIZE));
+ addr += PAGE_SIZE) {
+ if ((len % (1024*1024)) == 0)
+ printf("%d ", len / (1024*1024));
+ pmap_kenter_pa(dumpspace, addr, VM_PROT_READ);
+ pmap_update(pmap_kernel());
+
+ error = (*bdev->d_dump)(dumpdev,
+ blkno, (caddr_t) dumpspace, PAGE_SIZE);
+ pmap_kremove(dumpspace, PAGE_SIZE);
+ pmap_update(pmap_kernel());
+ if (error) break;
+ blkno += btodb(PAGE_SIZE);
+ len += PAGE_SIZE;
+ }
+ }
+
+ switch (error) {
+ case ENXIO:
+ printf("device bad\n");
+ break;
+
+ case EFAULT:
+ printf("device not ready\n");
+ break;
+
+ case EINVAL:
+ printf("area improper\n");
+ break;
+
+ case EIO:
+ printf("i/o error\n");
+ break;
+
+ case EINTR:
+ printf("aborted from console\n");
+ break;
+
+ default:
+ printf("succeeded\n");
+ break;
+ }
+ printf("\n\n");
+ delay(1000000);
+}
+
+/* End of stubs.c */
diff --git a/sys/arch/arm/arm/sys_machdep.c b/sys/arch/arm/arm/sys_machdep.c
new file mode 100644
index 00000000000..3b08e677768
--- /dev/null
+++ b/sys/arch/arm/arm/sys_machdep.c
@@ -0,0 +1,119 @@
+/* $OpenBSD: sys_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: sys_machdep.c,v 1.6 2003/07/15 00:24:42 lukem Exp $^I*/$
+
+/*
+ * Copyright (c) 1995-1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * sys_machdep.c
+ *
+ * Machine dependant syscalls
+ *
+ * Created : 10/01/96
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/mount.h>
+#include <uvm/uvm_extern.h>
+#include <sys/sysctl.h>
+#include <sys/syscallargs.h>
+
+#include <machine/sysarch.h>
+
+/* Prototypes */
+static int arm32_sync_icache __P((struct proc *, char *, register_t *));
+static int arm32_drain_writebuf __P((struct proc *, char *, register_t *));
+
+static int
+arm32_sync_icache(p, args, retval)
+ struct proc *p;
+ char *args;
+ register_t *retval;
+{
+ struct arm_sync_icache_args ua;
+ int error;
+
+ if ((error = copyin(args, &ua, sizeof(ua))) != 0)
+ return (error);
+
+ cpu_icache_sync_range(ua.addr, ua.len);
+
+ *retval = 0;
+ return(0);
+}
+
+static int
+arm32_drain_writebuf(p, args, retval)
+ struct proc *p;
+ char *args;
+ register_t *retval;
+{
+ /* No args. */
+
+ cpu_drain_writebuf();
+
+ *retval = 0;
+ return(0);
+}
+
+int
+sys_sysarch(p, v, retval)
+ struct proc *p;
+ void *v;
+ register_t *retval;
+{
+ struct sys_sysarch_args /* {
+ syscallarg(int) op;
+ syscallarg(void *) parms;
+ } */ *uap = v;
+ int error = 0;
+
+ switch(SCARG(uap, op)) {
+ case ARM_SYNC_ICACHE :
+ error = arm32_sync_icache(p, SCARG(uap, parms), retval);
+ break;
+
+ case ARM_DRAIN_WRITEBUF :
+ error = arm32_drain_writebuf(p, SCARG(uap, parms), retval);
+ break;
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+/* End of sys_machdep.c */
diff --git a/sys/arch/arm/arm/syscall.c b/sys/arch/arm/arm/syscall.c
new file mode 100644
index 00000000000..57c3f1a7756
--- /dev/null
+++ b/sys/arch/arm/arm/syscall.c
@@ -0,0 +1,492 @@
+/* $OpenBSD: syscall.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: syscall.c,v 1.24 2003/11/14 19:03:17 scw Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * syscall entry handling
+ *
+ * Created : 09/11/94
+ */
+
+#include <sys/param.h>
+
+#include <sys/device.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/syscall.h>
+#include <sys/systm.h>
+#include <sys/user.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
+#ifdef SYSTRACE
+#include <sys/systrace.h>
+#endif
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <arm/swi.h>
+
+#ifdef acorn26
+#include <machine/machdep.h>
+#endif
+
+#define MAXARGS 8
+
+void syscall_intern(struct proc *);
+void syscall_plain(struct trapframe *, struct proc *, u_int32_t);
+void syscall_fancy(struct trapframe *, struct proc *, u_int32_t);
+
+void
+swi_handler(trapframe_t *frame)
+{
+ struct proc *p = curproc;
+ u_int32_t insn;
+ union sigval sv;
+
+ /*
+ * Enable interrupts if they were enabled before the exception.
+ * Since all syscalls *should* come from user mode it will always
+ * be safe to enable them, but check anyway.
+ */
+#ifdef acorn26
+ if ((frame->tf_r15 & R15_IRQ_DISABLE) == 0)
+ int_on();
+#else
+ if (!(frame->tf_spsr & I32_bit))
+ enable_interrupts(I32_bit);
+#endif
+
+#ifdef acorn26
+ frame->tf_pc += INSN_SIZE;
+#endif
+
+ /*
+ * Make sure the program counter is correctly aligned so we
+ * don't take an alignment fault trying to read the opcode.
+ */
+ if (__predict_false(((frame->tf_pc - INSN_SIZE) & 3) != 0)) {
+ /* Give the user an illegal instruction signal. */
+ sv.sival_ptr = (u_int32_t *)(u_int32_t)(frame->tf_pc-INSN_SIZE);
+ trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
+ userret(p);
+ return;
+ }
+
+ /* XXX fuword? */
+#ifdef __PROG32
+ insn = *(u_int32_t *)(frame->tf_pc - INSN_SIZE);
+#else
+ insn = *(u_int32_t *)((frame->tf_r15 & R15_PC) - INSN_SIZE);
+#endif
+
+ p->p_addr->u_pcb.pcb_tf = frame;
+
+#ifdef CPU_ARM7
+ /*
+ * This code is only needed if we are including support for the ARM7
+ * core. Other CPUs do not need it but it does not hurt.
+ */
+
+ /*
+ * ARM700/ARM710 match sticks and sellotape job ...
+ *
+ * I know this affects GPS/VLSI ARM700/ARM710 + various ARM7500.
+ *
+ * On occasion data aborts are mishandled and end up calling
+ * the swi vector.
+ *
+ * If the instruction that caused the exception is not a SWI
+ * then we hit the bug.
+ */
+ if ((insn & 0x0f000000) != 0x0f000000) {
+ frame->tf_pc -= INSN_SIZE;
+ curcpu()->ci_arm700bugcount.ev_count++;
+ userret(l);
+ return;
+ }
+#endif /* CPU_ARM7 */
+
+ uvmexp.syscalls++;
+
+#if 0
+ (*(void(*)(struct trapframe *, struct proc *, u_int32_t))
+ (p->p_md.md_syscall))(frame, p, insn);
+#else
+ syscall_fancy(frame, p, insn);
+#endif
+}
+
+void
+syscall_intern(struct proc *p)
+{
+#ifdef KTRACE
+ if (p->p_traceflag & (KTRFAC_SYSCALL | KTRFAC_SYSRET)) {
+ p->p_md.md_syscall = syscall_fancy;
+ return;
+ }
+#endif
+#ifdef SYSTRACE
+ if (p->p_flag & P_SYSTRACE) {
+ p->p_md.md_syscall = syscall_fancy;
+ return;
+ }
+#endif
+ p->p_md.md_syscall = syscall_plain;
+}
+
+void
+syscall_plain(struct trapframe *frame, struct proc *p, u_int32_t insn)
+{
+ const struct sysent *callp;
+ int code, error;
+ u_int nap, nargs;
+ register_t *ap, *args, copyargs[MAXARGS], rval[2];
+ union sigval sv;
+
+ switch (insn & SWI_OS_MASK) { /* Which OS is the SWI from? */
+ case SWI_OS_ARM: /* ARM-defined SWIs */
+ code = insn & 0x00ffffff;
+ switch (code) {
+ case SWI_IMB:
+ case SWI_IMBrange:
+ /*
+ * Do nothing as there is no prefetch unit that needs
+ * flushing
+ */
+ break;
+ default:
+ /* Undefined so illegal instruction */
+ sv.sival_ptr = (u_int32_t *)(frame->tf_pc - INSN_SIZE);
+ trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
+ break;
+ }
+
+ userret(p);
+ return;
+ case 0x000000: /* Old unofficial NetBSD range. */
+ case SWI_OS_NETBSD: /* New official NetBSD range. */
+ nap = 4;
+ break;
+ default:
+ /* Undefined so illegal instruction */
+ sv.sival_ptr = (u_int32_t *)(frame->tf_pc - INSN_SIZE);
+ trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
+ userret(p);
+ return;
+ }
+
+ code = insn & 0x000fffff;
+
+ ap = &frame->tf_r0;
+ callp = p->p_emul->e_sysent;
+
+ switch (code) {
+ case SYS_syscall:
+ code = *ap++;
+ nap--;
+ break;
+ case SYS___syscall:
+ code = ap[_QUAD_LOWWORD];
+ ap += 2;
+ nap -= 2;
+ break;
+ }
+
+ if (code < 0 || code >= p->p_emul->e_nsysent) {
+ callp += p->p_emul->e_nosys;
+ } else {
+ callp += code;
+ }
+ nargs = callp->sy_argsize / sizeof(register_t);
+ if (nargs <= nap)
+ args = ap;
+ else {
+ KASSERT(nargs <= MAXARGS);
+ memcpy(copyargs, ap, nap * sizeof(register_t));
+ error = copyin((void *)frame->tf_usr_sp, copyargs + nap,
+ (nargs - nap) * sizeof(register_t));
+ if (error)
+ goto bad;
+ args = copyargs;
+ }
+
+#ifdef SYSCALL_DEBUG
+ scdebug_call(p, code, args);
+#endif
+ rval[0] = 0;
+ rval[1] = 0;
+ error = (*callp->sy_call)(p, args, rval);
+
+ switch (error) {
+ case 0:
+ frame->tf_r0 = rval[0];
+ frame->tf_r1 = rval[1];
+
+#ifdef __PROG32
+ frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
+#else
+ frame->tf_r15 &= ~R15_FLAG_C; /* carry bit */
+#endif
+ break;
+
+ case ERESTART:
+ /*
+ * Reconstruct the pc to point at the swi.
+ */
+ frame->tf_pc -= INSN_SIZE;
+ break;
+
+ case EJUSTRETURN:
+ /* nothing to do */
+ break;
+
+ default:
+ bad:
+ frame->tf_r0 = error;
+#ifdef __PROG32
+ frame->tf_spsr |= PSR_C_bit; /* carry bit */
+#else
+ frame->tf_r15 |= R15_FLAG_C; /* carry bit */
+#endif
+ break;
+ }
+#ifdef SYSCALL_DEBUG
+ scdebug_ret(p, code, error, rval);
+#endif
+
+ userret(p);
+}
+
+void
+syscall_fancy(struct trapframe *frame, struct proc *p, u_int32_t insn)
+{
+ const struct sysent *callp;
+ int code, error, orig_error;
+ u_int nap, nargs;
+ register_t *ap, *args, copyargs[MAXARGS], rval[2];
+ union sigval sv;
+
+ switch (insn & SWI_OS_MASK) { /* Which OS is the SWI from? */
+ case SWI_OS_ARM: /* ARM-defined SWIs */
+ code = insn & 0x00ffffff;
+ switch (code) {
+ case SWI_IMB:
+ case SWI_IMBrange:
+ /*
+ * Do nothing as there is no prefetch unit that needs
+ * flushing
+ */
+ break;
+ default:
+ /* Undefined so illegal instruction */
+ sv.sival_ptr = (u_int32_t *)(frame->tf_pc - INSN_SIZE);
+ trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
+ break;
+ }
+
+ userret(p);
+ return;
+ case 0x000000: /* Old unofficial NetBSD range. */
+ case SWI_OS_NETBSD: /* New official NetBSD range. */
+ nap = 4;
+ break;
+ default:
+ /* Undefined so illegal instruction */
+ sv.sival_ptr = (u_int32_t *)(frame->tf_pc - INSN_SIZE);
+ trapsignal(p, SIGILL, 0, ILL_ILLOPN, sv);
+ userret(p);
+ return;
+ }
+
+ code = insn & 0x000fffff;
+
+ ap = &frame->tf_r0;
+ callp = p->p_emul->e_sysent;
+
+ switch (code) {
+ case SYS_syscall:
+ code = *ap++;
+ nap--;
+ break;
+ case SYS___syscall:
+ code = ap[_QUAD_LOWWORD];
+ ap += 2;
+ nap -= 2;
+ break;
+ }
+
+ if (code < 0 || code >= p->p_emul->e_nsysent) {
+ callp += p->p_emul->e_nosys;
+ } else {
+ callp += code;
+ }
+ nargs = callp->sy_argsize / sizeof(register_t);
+ if (nargs <= nap) {
+ args = ap;
+ error = 0;
+ } else {
+ KASSERT(nargs <= MAXARGS);
+ memcpy(copyargs, ap, nap * sizeof(register_t));
+ error = copyin((void *)frame->tf_usr_sp, copyargs + nap,
+ (nargs - nap) * sizeof(register_t));
+ args = copyargs;
+ }
+ orig_error = error;
+#ifdef SYSCALL_DEBUG
+ scdebug_call(p, code, args);
+#endif
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSCALL))
+ ktrsyscall(p, code, callp->sy_argsize, args);
+#endif
+ if (error)
+ goto bad;
+
+ rval[0] = 0;
+ rval[1] = 0;
+#if NSYSTRACE > 0
+ if (ISSET(p->p_flag, P_SYSTRACE))
+ orig_error = error = systrace_redirect(code, p, args, rval);
+ else
+#endif
+ orig_error = error = (*callp->sy_call)(p, args, rval);
+
+ switch (error) {
+ case 0:
+ frame->tf_r0 = rval[0];
+ frame->tf_r1 = rval[1];
+
+#ifdef __PROG32
+ frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
+#else
+ frame->tf_r15 &= ~R15_FLAG_C; /* carry bit */
+#endif
+ break;
+
+ case ERESTART:
+ /*
+ * Reconstruct the pc to point at the swi.
+ */
+ frame->tf_pc -= INSN_SIZE;
+ break;
+
+ case EJUSTRETURN:
+ /* nothing to do */
+ break;
+
+ default:
+ bad:
+ frame->tf_r0 = error;
+#ifdef __PROG32
+ frame->tf_spsr |= PSR_C_bit; /* carry bit */
+#else
+ frame->tf_r15 |= R15_FLAG_C; /* carry bit */
+#endif
+ break;
+ }
+#ifdef SYSCALL_DEBUG
+ scdebug_ret(p, code, orig_error, rval);
+#endif
+ userret(p);
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET))
+ ktrsysret(p, code, orig_error, rval[0]);
+#endif
+}
+
+void
+child_return(arg)
+ void *arg;
+{
+ struct proc *p = arg;
+ struct trapframe *frame = p->p_addr->u_pcb.pcb_tf;
+
+ frame->tf_r0 = 0;
+#ifdef __PROG32
+ frame->tf_spsr &= ~PSR_C_bit; /* carry bit */
+#else
+ frame->tf_r15 &= ~R15_FLAG_C; /* carry bit */
+#endif
+
+ userret(p);
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_SYSRET)) {
+ ktrsysret(p, SYS_fork, 0, 0);
+ }
+#endif
+}
diff --git a/sys/arch/arm/arm/undefined.c b/sys/arch/arm/arm/undefined.c
new file mode 100644
index 00000000000..7a38f631b2e
--- /dev/null
+++ b/sys/arch/arm/arm/undefined.c
@@ -0,0 +1,329 @@
+/* $OpenBSD: undefined.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 2001 Ben Harris.
+ * Copyright (c) 1995 Mark Brinicombe.
+ * Copyright (c) 1995 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * undefined.c
+ *
+ * Fault handler
+ *
+ * Created : 06/01/95
+ */
+
+#define FAST_FPE
+
+#include <sys/param.h>
+
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/signal.h>
+#include <sys/signalvar.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/syslog.h>
+#include <sys/vmmeter.h>
+#ifdef FAST_FPE
+#include <sys/acct.h>
+#endif
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <arm/undefined.h>
+#include <machine/trap.h>
+
+
+#ifdef acorn26
+#include <machine/machdep.h>
+#endif
+
+static int gdb_trapper(u_int, u_int, struct trapframe *, int);
+
+#ifdef FAST_FPE
+extern int want_resched;
+#endif
+
+LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS];
+
+
+void *
+install_coproc_handler(int coproc, undef_handler_t handler)
+{
+ struct undefined_handler *uh;
+
+ KASSERT(coproc >= 0 && coproc < MAX_COPROCS);
+ KASSERT(handler != NULL); /* Used to be legal. */
+
+ /* XXX: M_TEMP??? */
+ MALLOC(uh, struct undefined_handler *, sizeof(*uh), M_TEMP, M_WAITOK);
+ uh->uh_handler = handler;
+ install_coproc_handler_static(coproc, uh);
+ return uh;
+}
+
+void
+install_coproc_handler_static(int coproc, struct undefined_handler *uh)
+{
+
+ LIST_INSERT_HEAD(&undefined_handlers[coproc], uh, uh_link);
+}
+
+void
+remove_coproc_handler(void *cookie)
+{
+ struct undefined_handler *uh = cookie;
+
+ LIST_REMOVE(uh, uh_link);
+ FREE(uh, M_TEMP);
+}
+
+
+static int
+gdb_trapper(u_int addr, u_int insn, struct trapframe *frame, int code)
+{
+ union sigval sv;
+ struct proc *p;
+ p = (curproc == NULL) ? &proc0 : curproc;
+
+ if (insn == GDB_BREAKPOINT || insn == GDB5_BREAKPOINT) {
+ if (code == FAULT_USER) {
+ sv.sival_int = addr;
+ trapsignal(p, SIGTRAP, 0, TRAP_BRKPT, sv);
+ return 0;
+ }
+#ifdef KGDB
+ return !kgdb_trap(T_BREAKPOINT, frame);
+#endif
+ }
+ return 1;
+}
+
+static struct undefined_handler gdb_uh;
+
+void
+undefined_init()
+{
+ int loop;
+
+ /* Not actually necessary -- the initialiser is just NULL */
+ for (loop = 0; loop < MAX_COPROCS; ++loop)
+ LIST_INIT(&undefined_handlers[loop]);
+
+ /* Install handler for GDB breakpoints */
+ gdb_uh.uh_handler = gdb_trapper;
+ install_coproc_handler_static(0, &gdb_uh);
+}
+
+
+void
+undefinedinstruction(trapframe_t *frame)
+{
+ struct proc *p;
+ u_int fault_pc;
+ int fault_instruction;
+ int fault_code;
+ int coprocessor;
+ struct undefined_handler *uh;
+#ifdef VERBOSE_ARM32
+ int s;
+#endif
+ union sigval sv;
+
+ /* Enable interrupts if they were enabled before the exception. */
+#ifdef acorn26
+ if ((frame->tf_r15 & R15_IRQ_DISABLE) == 0)
+ int_on();
+#else
+ if (!(frame->tf_spsr & I32_bit))
+ enable_interrupts(I32_bit);
+#endif
+
+#ifndef acorn26
+ frame->tf_pc -= INSN_SIZE;
+#endif
+
+#ifdef __PROG26
+ fault_pc = frame->tf_r15 & R15_PC;
+#else
+ fault_pc = frame->tf_pc;
+#endif
+
+ /* Get the current proc structure or proc0 if there is none. */
+ p = (curproc == NULL) ? &proc0 : curproc;
+
+ /*
+ * Make sure the program counter is correctly aligned so we
+ * don't take an alignment fault trying to read the opcode.
+ */
+ if (__predict_false((fault_pc & 3) != 0)) {
+ /* Give the user an illegal instruction signal. */
+ sv.sival_int = (u_int32_t) fault_pc;
+ trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
+ userret(p);
+ return;
+ }
+
+ /*
+ * Should use fuword() here .. but in the interests of squeezing every
+ * bit of speed we will just use ReadWord(). We know the instruction
+ * can be read as was just executed so this will never fail unless the
+ * kernel is screwed up in which case it does not really matter does
+ * it ?
+ */
+
+ fault_instruction = *(u_int32_t *)fault_pc;
+
+ /* Update vmmeter statistics */
+ uvmexp.traps++;
+
+ /* Check for coprocessor instruction */
+
+ /*
+ * According to the datasheets you only need to look at bit 27 of the
+ * instruction to tell the difference between and undefined
+ * instruction and a coprocessor instruction following an undefined
+ * instruction trap.
+ */
+
+ if ((fault_instruction & (1 << 27)) != 0)
+ coprocessor = (fault_instruction >> 8) & 0x0f;
+ else
+ coprocessor = 0;
+
+ /* Get the current proc structure or proc0 if there is none. */
+
+ if ((p = curproc) == 0)
+ p = &proc0;
+
+#ifdef __PROG26
+ if ((frame->tf_r15 & R15_MODE) == R15_MODE_USR) {
+#else
+ if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
+#endif
+ /*
+ * Modify the fault_code to reflect the USR/SVC state at
+ * time of fault.
+ */
+ fault_code = FAULT_USER;
+ p->p_addr->u_pcb.pcb_tf = frame;
+ } else
+ fault_code = 0;
+
+ /* OK this is were we do something about the instruction. */
+ LIST_FOREACH(uh, &undefined_handlers[coprocessor], uh_link)
+ if (uh->uh_handler(fault_pc, fault_instruction, frame,
+ fault_code) == 0)
+ break;
+
+ if (uh == NULL) {
+ /* Fault has not been handled */
+
+#ifdef VERBOSE_ARM32
+ s = spltty();
+
+ if ((fault_instruction & 0x0f000010) == 0x0e000000) {
+ printf("CDP\n");
+ disassemble(fault_pc);
+ } else if ((fault_instruction & 0x0e000000) == 0x0c000000) {
+ printf("LDC/STC\n");
+ disassemble(fault_pc);
+ } else if ((fault_instruction & 0x0f000010) == 0x0e000010) {
+ printf("MRC/MCR\n");
+ disassemble(fault_pc);
+ } else if ((fault_instruction & ~INSN_COND_MASK)
+ != (KERNEL_BREAKPOINT & ~INSN_COND_MASK)) {
+ printf("Undefined instruction\n");
+ disassemble(fault_pc);
+ }
+
+ splx(s);
+#endif
+
+ if ((fault_code & FAULT_USER) == 0) {
+ printf("Undefined instruction in kernel\n");
+#ifdef DDB
+ Debugger();
+#endif
+ }
+
+ sv.sival_int = frame->tf_pc;
+ trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
+ }
+
+ if ((fault_code & FAULT_USER) == 0)
+ return;
+
+#ifdef FAST_FPE
+ /* Optimised exit code */
+ {
+ int sig;
+
+ /* take pending signals */
+
+ while ((sig = (CURSIG(p))) != 0) {
+ postsig(sig);
+ }
+
+ p->p_priority = p->p_usrpri;
+
+ /*
+ * Check for reschedule request, at the moment there is only
+ * 1 ast so this code should always be run
+ */
+
+ if (want_resched) {
+ /*
+ * We are being preempted.
+ */
+ preempt(NULL);
+ while ((sig = (CURSIG(p))) != 0) {
+ postsig(sig);
+ }
+ }
+
+ /* XXX
+ curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
+ */
+ }
+
+#else
+ userret(p);
+#endif
+}
diff --git a/sys/arch/arm/arm/vectors.S b/sys/arch/arm/arm/vectors.S
new file mode 100644
index 00000000000..41d5deb1879
--- /dev/null
+++ b/sys/arch/arm/arm/vectors.S
@@ -0,0 +1,104 @@
+/* $OpenBSD: vectors.S,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: vectors.S,v 1.4 2002/08/17 16:36:32 thorpej Exp $ */
+
+/*
+ * Copyright (C) 1994-1997 Mark Brinicombe
+ * Copyright (C) 1994 Brini
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of Brini may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "assym.h"
+#include <machine/asm.h>
+
+/*
+ * These are the exception vectors copied down to page 0.
+ *
+ * Note that FIQs are special; rather than using a level of
+ * indirection, we actually copy the FIQ code down into the
+ * vector page.
+ */
+
+ .text
+ .align 0
+ .global _C_LABEL(page0), _C_LABEL(page0_data), _C_LABEL(page0_end)
+ .global _C_LABEL(fiqvector)
+
+_C_LABEL(page0):
+ ldr pc, .Lreset_target
+ ldr pc, .Lundefined_target
+ ldr pc, .Lswi_target
+ ldr pc, .Lprefetch_abort_target
+ ldr pc, .Ldata_abort_target
+ ldr pc, .Laddress_exception_target
+ ldr pc, .Lirq_target
+#ifdef __ARM_FIQ_INDIRECT
+ ldr pc, .Lfiq_target
+#else
+.Lfiqvector:
+ .set _C_LABEL(fiqvector), . - _C_LABEL(page0)
+ subs pc, lr, #4
+ .org .Lfiqvector + 0x100
+#endif
+
+_C_LABEL(page0_data):
+.Lreset_target:
+ .word reset_entry
+
+.Lundefined_target:
+ .word undefined_entry
+
+.Lswi_target:
+ .word swi_entry
+
+.Lprefetch_abort_target:
+ .word prefetch_abort_entry
+
+.Ldata_abort_target:
+ .word data_abort_entry
+
+.Laddress_exception_target:
+ .word address_exception_entry
+
+.Lirq_target:
+ .word irq_entry
+
+#ifdef __ARM_FIQ_INDIRECT
+.Lfiq_target:
+ .word _C_LABEL(fiqvector)
+#else
+ .word 0 /* pad it out */
+#endif
+_C_LABEL(page0_end):
+
+#ifdef __ARM_FIQ_INDIRECT
+ .data
+ .align 0
+_C_LABEL(fiqvector):
+ subs pc, lr, #4
+ .org _C_LABEL(fiqvector) + 0x100
+#endif
diff --git a/sys/arch/arm/arm/vm_machdep.c b/sys/arch/arm/arm/vm_machdep.c
new file mode 100644
index 00000000000..5375f465e2a
--- /dev/null
+++ b/sys/arch/arm/arm/vm_machdep.c
@@ -0,0 +1,390 @@
+/* $OpenBSD: vm_machdep.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/*^I$NetBSD: vm_machdep.c,v 1.31 2004/01/04 11:33:29 jdolecek Exp $^I*/$
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * vm_machdep.h
+ *
+ * vm machine specific bits
+ *
+ * Created : 08/10/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/buf.h>
+#if 0
+#include <sys/pmc.h>
+#endif
+#include <sys/user.h>
+#include <sys/exec.h>
+#include <sys/syslog.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+#include <machine/reg.h>
+#include <machine/vmparam.h>
+
+#ifdef ARMFPE
+#include <arm/fpe-arm/armfpe.h>
+#endif
+
+extern pv_addr_t systempage;
+
+int process_read_regs __P((struct proc *p, struct reg *regs));
+int process_read_fpregs __P((struct proc *p, struct fpreg *regs));
+
+void switch_exit __P((struct proc *p, struct proc *p0,
+ void (*)(struct proc *)));
+extern void proc_trampoline __P((void));
+
+/*
+ * Special compilation symbols:
+ *
+ * STACKCHECKS - Fill undefined and supervisor stacks with a known pattern
+ * on forking and check the pattern on exit, reporting
+ * the amount of stack used.
+ */
+
+#if 0
+void
+cpu_proc_fork(p1, p2)
+ struct proc *p1, *p2;
+{
+
+#if defined(PERFCTRS)
+ if (PMC_ENABLED(p1))
+ pmc_md_fork(p1, p2);
+ else {
+ p2->p_md.pmc_enabled = 0;
+ p2->p_md.pmc_state = NULL;
+ }
+#endif
+}
+#endif
+
+/*
+ * Finish a fork operation, with process p2 nearly set up.
+ * Copy and update the pcb and trap frame, making the child ready to run.
+ *
+ * Rig the child's kernel stack so that it will start out in
+ * proc_trampoline() and call child_return() with p2 as an
+ * argument. This causes the newly-created child process to go
+ * directly to user level with an apparent return value of 0 from
+ * fork(), while the parent process returns normally.
+ *
+ * p1 is the process being forked; if p1 == &proc0, we are creating
+ * a kernel thread, and the return path and argument are specified with
+ * `func' and `arg'.
+ *
+ * If an alternate user-level stack is requested (with non-zero values
+ * in both the stack and stacksize args), set up the user stack pointer
+ * accordingly.
+ */
+void
+cpu_fork(p1, p2, stack, stacksize, func, arg)
+ struct proc *p1;
+ struct proc *p2;
+ void *stack;
+ size_t stacksize;
+ void (*func) __P((void *));
+ void *arg;
+{
+ struct pcb *pcb = (struct pcb *)&p2->p_addr->u_pcb;
+ struct trapframe *tf;
+ struct switchframe *sf;
+
+#ifdef PMAP_DEBUG
+ if (pmap_debug_level >= 0)
+ printf("cpu_fork: %p %p %p %p\n", p1, p2, curlwp, &proc0);
+#endif /* PMAP_DEBUG */
+
+#if 0 /* XXX */
+ if (l1 == curlwp) {
+ /* Sync the PCB before we copy it. */
+ savectx(curpcb);
+ }
+#endif
+
+ /* Copy the pcb */
+ *pcb = p1->p_addr->u_pcb;
+
+ /*
+ * Set up the undefined stack for the process.
+ * Note: this stack is not in use if we are forking from p1
+ */
+ pcb->pcb_un.un_32.pcb32_und_sp = (u_int)p2->p_addr +
+ USPACE_UNDEF_STACK_TOP;
+ pcb->pcb_un.un_32.pcb32_sp = (u_int)p2->p_addr + USPACE_SVC_STACK_TOP;
+
+#ifdef STACKCHECKS
+ /* Fill the undefined stack with a known pattern */
+ memset(((u_char *)p2->p_addr) + USPACE_UNDEF_STACK_BOTTOM, 0xdd,
+ (USPACE_UNDEF_STACK_TOP - USPACE_UNDEF_STACK_BOTTOM));
+ /* Fill the kernel stack with a known pattern */
+ memset(((u_char *)p2->p_addr) + USPACE_SVC_STACK_BOTTOM, 0xdd,
+ (USPACE_SVC_STACK_TOP - USPACE_SVC_STACK_BOTTOM));
+#endif /* STACKCHECKS */
+
+#ifdef PMAP_DEBUG
+ if (pmap_debug_level >= 0) {
+ printf("p1->procaddr=%p p1->procaddr->u_pcb=%p pid=%d pmap=%p\n",
+ p1->p_addr, &p1->p_addr->u_pcb, p1->p_lid,
+ p1->p_proc->p_vmspace->vm_map.pmap);
+ printf("p2->procaddr=%p p2->procaddr->u_pcb=%p pid=%d pmap=%p\n",
+ p2->p_addr, &p2->p_addr->u_pcb, p2->p_lid,
+ p2->p_proc->p_vmspace->vm_map.pmap);
+ }
+#endif /* PMAP_DEBUG */
+
+ pmap_activate(p2);
+
+#ifdef ARMFPE
+ /* Initialise a new FP context for p2 and copy the context from p1 */
+ arm_fpe_core_initcontext(FP_CONTEXT(p2));
+ arm_fpe_copycontext(FP_CONTEXT(p1), FP_CONTEXT(p2));
+#endif /* ARMFPE */
+
+ p2->p_addr->u_pcb.pcb_tf = tf =
+ (struct trapframe *)pcb->pcb_un.un_32.pcb32_sp - 1;
+ *tf = *p1->p_addr->u_pcb.pcb_tf;
+
+ /*
+ * If specified, give the child a different stack.
+ */
+ if (stack != NULL)
+ tf->tf_usr_sp = (u_int)stack + stacksize;
+
+ sf = (struct switchframe *)tf - 1;
+ sf->sf_r4 = (u_int)func;
+ sf->sf_r5 = (u_int)arg;
+ sf->sf_pc = (u_int)proc_trampoline;
+ pcb->pcb_un.un_32.pcb32_sp = (u_int)sf;
+}
+
+#if 0
+void
+cpu_setfunc(struct proc *p, void (*func)(void *), void *arg)
+{
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ struct trapframe *tf = pcb->pcb_tf;
+ struct switchframe *sf = (struct switchframe *)tf - 1;
+
+ sf->sf_r4 = (u_int)func;
+ sf->sf_r5 = (u_int)arg;
+ sf->sf_pc = (u_int)proc_trampoline;
+ pcb->pcb_un.un_32.pcb32_sp = (u_int)sf;
+}
+#endif
+
+
+void
+cpu_exit(struct proc *p)
+{
+ pmap_update(p->p_vmspace->vm_map.pmap); /* XXX DSR help stability */
+ switch_exit(p, &proc0, exit2);
+}
+
+void
+cpu_swapin(p)
+ struct proc *p;
+{
+#if 0
+
+ /* Don't do this. See the comment in cpu_swapout(). */
+#ifdef PMAP_DEBUG
+ if (pmap_debug_level >= 0)
+ printf("cpu_swapin(%p, %d, %s, %p)\n", l, l->l_lid,
+ p->p_comm, p->p_vmspace->vm_map.pmap);
+#endif /* PMAP_DEBUG */
+
+ if (vector_page < KERNEL_BASE) {
+ /* Map the vector page */
+ pmap_enter(p->p_vmspace->vm_map.pmap, vector_page,
+ systempage.pv_pa, VM_PROT_READ, VM_PROT_READ|PMAP_WIRED);
+ pmap_update(p->p_vmspace->vm_map.pmap);
+ }
+#endif
+}
+
+
+void
+cpu_swapout(l)
+ struct proc *l;
+{
+#if 0
+ struct proc *p = l->l_proc;
+
+ /*
+ * Don't do this! If the pmap is shared with another process,
+ * it will loose it's page0 entry. That's bad news indeed.
+ */
+#ifdef PMAP_DEBUG
+ if (pmap_debug_level >= 0)
+ printf("cpu_swapout(%p, %d, %s, %p)\n", l, l->l_lid,
+ p->p_comm, &p->p_vmspace->vm_map.pmap);
+#endif /* PMAP_DEBUG */
+
+ if (vector_page < KERNEL_BASE) {
+ /* Free the system page mapping */
+ pmap_remove(p->p_vmspace->vm_map.pmap, vector_page,
+ vector_page + PAGE_SIZE);
+ pmap_update(p->p_vmspace->vm_map.pmap);
+ }
+#endif
+}
+
+
+/*
+ * Move pages from one kernel virtual address to another.
+ * Both addresses are assumed to reside in the Sysmap,
+ * and size must be a multiple of PAGE_SIZE.
+ */
+
+void
+pagemove(from, to, size)
+ caddr_t from, to;
+ size_t size;
+{
+ paddr_t pa;
+ boolean_t rv;
+
+ if (size % PAGE_SIZE)
+ panic("pagemove: size=%08lx", (u_long) size);
+
+ while (size > 0) {
+ rv = pmap_extract(pmap_kernel(), (vaddr_t) from, &pa);
+#ifdef DEBUG
+ if (rv == FALSE)
+ panic("pagemove 2");
+ if (pmap_extract(pmap_kernel(), (vaddr_t) to, NULL) == TRUE)
+ panic("pagemove 3");
+#endif
+ pmap_kremove((vaddr_t) from, PAGE_SIZE);
+ pmap_kenter_pa((vaddr_t) to, pa, VM_PROT_READ|VM_PROT_WRITE);
+ from += PAGE_SIZE;
+ to += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ pmap_update(pmap_kernel());
+}
+
+/*
+ * Map a user I/O request into kernel virtual address space.
+ * Note: the pages are already locked by uvm_vslock(), so we
+ * do not need to pass an access_type to pmap_enter().
+ */
+void
+vmapbuf(bp, len)
+ struct buf *bp;
+ vsize_t len;
+{
+ vaddr_t faddr, taddr, off;
+ paddr_t fpa;
+
+
+#ifdef PMAP_DEBUG
+ if (pmap_debug_level >= 0)
+ printf("vmapbuf: bp=%08x buf=%08x len=%08x\n", (u_int)bp,
+ (u_int)bp->b_data, (u_int)len);
+#endif /* PMAP_DEBUG */
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vmapbuf");
+
+ faddr = trunc_page((vaddr_t)bp->b_saveaddr = bp->b_data);
+ off = (vaddr_t)bp->b_data - faddr;
+ len = round_page(off + len);
+ taddr = uvm_km_valloc_wait(phys_map, len);
+ bp->b_data = (caddr_t)(taddr + off);
+
+ /*
+ * The region is locked, so we expect that pmap_pte() will return
+ * non-NULL.
+ */
+ while (len) {
+ (void) pmap_extract(vm_map_pmap(&bp->b_proc->p_vmspace->vm_map),
+ faddr, &fpa);
+ pmap_enter(pmap_kernel(), taddr, fpa,
+ VM_PROT_READ|VM_PROT_WRITE, VM_PROT_READ|VM_PROT_WRITE|PMAP_WIRED);
+ faddr += PAGE_SIZE;
+ taddr += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ }
+ pmap_update(pmap_kernel());
+}
+
+/*
+ * Unmap a previously-mapped user I/O request.
+ */
+void
+vunmapbuf(bp, len)
+ struct buf *bp;
+ vsize_t len;
+{
+ vaddr_t addr, off;
+
+#ifdef PMAP_DEBUG
+ if (pmap_debug_level >= 0)
+ printf("vunmapbuf: bp=%08x buf=%08x len=%08x\n",
+ (u_int)bp, (u_int)bp->b_data, (u_int)len);
+#endif /* PMAP_DEBUG */
+
+ if ((bp->b_flags & B_PHYS) == 0)
+ panic("vunmapbuf");
+
+ /*
+ * Make sure the cache does not have dirty data for the
+ * pages we had mapped.
+ */
+ addr = trunc_page((vaddr_t)bp->b_data);
+ off = (vaddr_t)bp->b_data - addr;
+ len = round_page(off + len);
+
+ pmap_remove(pmap_kernel(), addr, addr + len);
+ pmap_update(pmap_kernel());
+ uvm_km_free_wakeup(phys_map, addr, len);
+ bp->b_data = bp->b_saveaddr;
+ bp->b_saveaddr = 0;
+}
+
+/* End of vm_machdep.c */
diff --git a/sys/arch/arm/arm/vm_machdep_arm.c b/sys/arch/arm/arm/vm_machdep_arm.c
new file mode 100644
index 00000000000..03de8238bbb
--- /dev/null
+++ b/sys/arch/arm/arm/vm_machdep_arm.c
@@ -0,0 +1,100 @@
+/* $OpenBSD: vm_machdep_arm.c,v 1.1 2004/02/01 05:09:48 drahn Exp $ */
+/* $NetBSD: vm_machdep_arm.c,v 1.7 2003/06/29 22:28:08 fvdl Exp $ */
+
+/*
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+
+#include <sys/core.h>
+#include <sys/exec.h>
+#include <sys/ptrace.h>
+#include <sys/signalvar.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+#include <sys/vnode.h>
+
+#include <machine/reg.h>
+
+
+/*
+ * Dump the machine specific segment at the start of a core dump.
+ */
+
+int
+cpu_coredump(struct proc *p, struct vnode *vp, struct ucred *cred,
+ struct core *chdr)
+{
+ int error;
+ struct {
+ struct reg regs;
+ struct fpreg fpregs;
+ } cpustate;
+ struct coreseg cseg;
+
+ CORE_SETMAGIC(*chdr, COREMAGIC, MID_MACHINE, 0);
+ chdr->c_hdrsize = ALIGN(sizeof(*chdr));
+ chdr->c_seghdrsize = ALIGN(sizeof(cseg));
+ chdr->c_cpusize = sizeof(cpustate);
+
+ /* Save integer registers. */
+ error = process_read_regs(p, &cpustate.regs);
+ if (error)
+ return error;
+ /* Save floating point registers. */
+ error = process_read_fpregs(p, &cpustate.fpregs);
+ if (error)
+ return error;
+
+ CORE_SETMAGIC(cseg, CORESEGMAGIC, MID_MACHINE, CORE_CPU);
+ cseg.c_addr = 0;
+ cseg.c_size = chdr->c_cpusize;
+
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cseg, chdr->c_seghdrsize,
+ (off_t)chdr->c_hdrsize, UIO_SYSSPACE,
+ IO_NODELOCKED|IO_UNIT, cred, NULL, p);
+ if (error)
+ return error;
+
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&cpustate, sizeof(cpustate),
+ (off_t)(chdr->c_hdrsize + chdr->c_seghdrsize), UIO_SYSSPACE,
+ IO_NODELOCKED|IO_UNIT, cred, NULL, p);
+ if (error)
+ return error;
+
+ chdr->c_nseg++;
+
+ return error;
+}
diff --git a/sys/arch/arm/conf/files.arm b/sys/arch/arm/conf/files.arm
new file mode 100644
index 00000000000..f3196ad4742
--- /dev/null
+++ b/sys/arch/arm/conf/files.arm
@@ -0,0 +1,141 @@
+# $OpenBSD: files.arm,v 1.1 2004/02/01 05:09:48 drahn Exp $
+# $NetBSD: files.arm,v 1.76 2003/11/05 12:53:15 scw Exp $
+
+# CPU types. Make sure to update <arm/cpuconf.h> if you change this list.
+#defflag opt_cputypes.h CPU_ARM2 CPU_ARM250 CPU_ARM3
+#defflag opt_cputypes.h CPU_ARM6 CPU_ARM7 CPU_ARM7TDMI CPU_ARM8
+# CPU_ARM9 CPU_ARM10 CPU_SA110 CPU_SA1100
+# CPU_SA1110 CPU_IXP12X0 CPU_XSCALE_80200
+# CPU_XSCALE_80321 CPU_XSCALE_PXA2X0
+# CPU_XSCALE_IXP425
+
+#defparam opt_cpuoptions.h XSCALE_CCLKCFG
+#defflag opt_cpuoptions.h XSCALE_CACHE_WRITE_THROUGH
+#defflag opt_cpuoptions.h XSCALE_CACHE_WRITE_BACK
+#defflag opt_cpuoptions.h XSCALE_NO_COALESCE_WRITES
+#defflag opt_cpuoptions.h XSCALE_CACHE_READ_WRITE_ALLOCATE
+#defflag opt_cpuoptions.h ARM32_DISABLE_ALIGNMENT_FAULTS
+
+# Interrupt implementation header definition.
+#defparam opt_arm_intr_impl.h ARM_INTR_IMPL
+
+# Board-specific bus_space(9) definitions
+#defflag opt_arm_bus_space.h __BUS_SPACE_HAS_STREAM_METHODS
+
+# Floating point emulator
+#defflag ARMFPE
+#file arch/arm/fpe-arm/armfpe_glue.S armfpe
+#file arch/arm/fpe-arm/armfpe_init.c armfpe
+#file arch/arm/fpe-arm/armfpe.S armfpe
+
+# PMAP_DEBUG (heavily abused option)
+#defflag PMAP_DEBUG
+
+# MI console support
+file dev/cons.c
+
+# generic networking files
+file arch/arm/arm/in_cksum_arm.S inet
+file netns/ns_cksum.c ns
+
+# DDB
+file arch/arm/arm/db_disasm.c ddb
+file arch/arm/arm/db_interface.c (ddb|kgdb)
+file arch/arm/arm/db_trace.c ddb
+file arch/arm/arm/db_machdep.c ddb
+file arch/arm/arm/kgdb_machdep.c kgdb
+
+# FIQ support
+file arch/arm/arm/fiq.c
+file arch/arm/arm/fiq_subr.S
+
+# mainbus files
+device mainbus { [base = -1], [dack = -1], [irq = -1] }
+attach mainbus at root
+file arch/arm/mainbus/mainbus.c mainbus
+file arch/arm/mainbus/mainbus_io.c mainbus
+file arch/arm/mainbus/mainbus_io_asm.S mainbus
+
+device cpu { }
+attach cpu at mainbus with cpu_mainbus
+file arch/arm/mainbus/cpu_mainbus.c cpu_mainbus
+
+# files related to debugging
+file arch/arm/arm/disassem.c
+
+# bus_space(9)
+define bus_space_generic
+file arch/arm/arm/bus_space_asm_generic.S bus_space_generic
+file arch/arm/arm/bus_space_notimpl.S
+
+file arch/arm/arm/arm_machdep.c
+file arch/arm/arm/ast.c
+file arch/arm/arm/bcopyinout.S
+file arch/arm/arm/blockio.S
+file arch/arm/arm/bootconfig.c
+file arch/arm/arm/compat_13_machdep.c compat_13
+file arch/arm/arm/copystr.S
+file arch/arm/arm/cpufunc.c
+file arch/arm/arm/cpufunc_asm.S
+file arch/arm/arm/cpufunc_asm_arm3.S cpu_arm3
+file arch/arm/arm/cpufunc_asm_arm67.S cpu_arm6 | cpu_arm7
+file arch/arm/arm/cpufunc_asm_arm7tdmi.S cpu_arm7tdmi
+file arch/arm/arm/cpufunc_asm_arm8.S cpu_arm8
+file arch/arm/arm/cpufunc_asm_arm9.S cpu_arm9
+file arch/arm/arm/cpufunc_asm_arm10.S cpu_arm10
+file arch/arm/arm/cpufunc_asm_armv4.S cpu_arm9 | cpu_arm10 |
+ cpu_sa110 |
+ cpu_sa1100 |
+ cpu_sa1110 |
+ cpu_ixp12x0 |
+ cpu_xscale_80200 |
+ cpu_xscale_80321 |
+ cpu_xscale_ixp425 |
+ cpu_xscale_pxa2x0
+file arch/arm/arm/cpufunc_asm_sa1.S cpu_sa110 | cpu_sa1100 |
+ cpu_sa1110 |
+ cpu_ixp12x0
+file arch/arm/arm/cpufunc_asm_sa11x0.S cpu_sa1100 | cpu_sa1110
+file arch/arm/arm/cpufunc_asm_xscale.S cpu_xscale_80200 |
+ cpu_xscale_80321 |
+ cpu_xscale_ixp425 |
+ cpu_xscale_pxa2x0
+file arch/arm/arm/cpufunc_asm_ixp12x0.S cpu_ixp12x0
+file arch/arm/arm/process_machdep.c
+file arch/arm/arm/procfs_machdep.c procfs
+file arch/arm/arm/sig_machdep.c
+file arch/arm/arm/sigcode.S
+file arch/arm/arm/syscall.c
+file arch/arm/arm/undefined.c
+# vectors.S gets included manually by Makefile.acorn26, since it needs
+# to be at the start of the text segment on those machines.
+file arch/arm/arm/vectors.S
+file arch/arm/arm/vm_machdep_arm.c
+
+# files common to arm implementations
+file arch/arm/arm/arm32_machdep.c
+file arch/arm/arm/bus_dma.c
+file arch/arm/arm/cpu.c
+file arch/arm/arm/cpuswitch.S
+file arch/arm/arm/exception.S
+file arch/arm/arm/fault.c
+file arch/arm/arm/fusu.S
+file arch/arm/arm/mem.c
+file arch/arm/arm/pmap.c
+file arch/arm/arm/setcpsr.S
+file arch/arm/arm/setstack.S
+file arch/arm/arm/stubs.c
+file arch/arm/arm/sys_machdep.c
+file arch/arm/arm/vm_machdep.c
+file arch/arm/arm/atomic.S
+
+# arm library functions
+file arch/arm/arm/bcopy_page.S
+
+# Linux binary compatibility (COMPAT_LINUX)
+#include "compat/ossaudio/files.ossaudio"
+#include "compat/linux/files.linux"
+#include "compat/linux/arch/arm/files.linux_arm"
+#file arch/arm/arm/linux_sigcode.S compat_linux
+#file arch/arm/arm/linux_syscall.c compat_linux
+#file arch/arm/arm/linux_trap.c compat_linux
diff --git a/sys/arch/arm/conf/files.footbridge b/sys/arch/arm/conf/files.footbridge
new file mode 100644
index 00000000000..01671454bf5
--- /dev/null
+++ b/sys/arch/arm/conf/files.footbridge
@@ -0,0 +1,22 @@
+# $OpenBSD: files.footbridge,v 1.1 2004/02/01 05:09:48 drahn Exp $
+# $NetBSD: files.footbridge,v 1.11 2003/01/03 01:06:40 thorpej Exp $
+#
+# Shared footbridge files information
+
+# DC21285 "Footbridge" specific files
+device footbridge {}: pcibus, bus_space_generic, todservice
+attach footbridge at mainbus
+file arch/arm/footbridge/footbridge.c footbridge
+file arch/arm/footbridge/footbridge_machdep.c footbridge
+file arch/arm/footbridge/footbridge_io.c footbridge
+file arch/arm/footbridge/footbridge_pci.c footbridge
+file arch/arm/arm/irq_dispatch.S
+file arch/arm/footbridge/footbridge_irqhandler.c footbridge
+file arch/arm/footbridge/footbridge_clock.c footbridge
+file arch/arm/arm/softintr.c footbridge
+
+# DC21285 "Footbridge" serial port
+device fcom: tty, bus_space_generic
+attach fcom at footbridge
+file arch/arm/footbridge/footbridge_com.c fcom needs-flag
+file arch/arm/footbridge/footbridge_com_io.c fcom
diff --git a/sys/arch/arm/footbridge/dc21285mem.h b/sys/arch/arm/footbridge/dc21285mem.h
new file mode 100644
index 00000000000..29ab4045e87
--- /dev/null
+++ b/sys/arch/arm/footbridge/dc21285mem.h
@@ -0,0 +1,90 @@
+/* $OpenBSD: dc21285mem.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: dc21285mem.h,v 1.2 2001/06/09 10:44:11 chris Exp $ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997,1998 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Physical memory map provided by the DC21285 'Footbridge'
+ */
+
+#define DC21285_SDRAM_BASE 0x00000000
+#define DC21285_SDRAM_SIZE 0x10000000 /* 256 MB */
+
+#define DC21285_SDRAM_A0MR 0x40000000
+#define DC21285_SDRAM_A1MR 0x40004000
+#define DC21285_SDRAM_A2MR 0x40008000
+#define DC21285_SDRAM_A3MR 0x4000C000
+
+#define DC21285_XBUS_XCS0 0x40010000
+#define DC21285_XBUS_XCS1 0x40011000
+#define DC21285_XBUS_XCS2 0x40012000
+#define DC21285_XBUS_NOCS 0x40013000
+
+#define DC21285_ROM_BASE 0x41000000
+#define DC21285_ROM_SIZE 0x01000000 /* 16MB */
+
+#define DC21285_ARMCSR_BASE 0x42000000
+#define DC21285_ARMCSR_SIZE 0x00100000 /* 1MB */
+
+#define DC21285_SA_CACHE_FLUSH_BASE 0x50000000
+#define DC21285_SA_CACHE_FLUSH_SIZE 0x01000000 /* 16MB */
+
+#define DC21285_OUTBOUND_WRITE_FLUSH 0x78000000
+
+#define DC21285_PCI_IACK_SPECIAL 0x79000000
+#define DC21285_PCI_TYPE_1_CONFIG 0x7A000000
+#define DC21285_PCI_TYPE_0_CONFIG 0x7B000000
+#define DC21285_PCI_IO_BASE 0x7C000000
+#define DC21285_PCI_IO_SIZE 0x00010000 /* 64K */
+#define DC21285_PCI_MEM_BASE 0x80000000
+#define DC21285_PCI_MEM_SIZE 0x80000000 /* 2GB */
+
+/*
+ * Standard Virtual memory map used for the DC21285 'Footbridge'
+ */
+#define DC21285_ARMCSR_VBASE 0xFD000000
+#define DC21285_ARMCSR_VSIZE 0x00100000 /* 1MB */
+#define DC21285_CACHE_FLUSH_VBASE 0xFD100000
+#define DC21285_CACHE_FLUSH_VSIZE 0x00100000 /* 1MB */
+#define DC21285_PCI_IO_VBASE 0xFD200000
+#define DC21285_PCI_IO_VSIZE 0x00100000 /* 1MB */
+#define DC21285_PCI_IACK_VBASE 0xFD300000
+#define DC21285_PCI_IACK_VSIZE 0x00100000 /* 1MB */
+#define DC21285_PCI_ISA_MEM_VBASE 0xFD400000
+#define DC21285_PCI_ISA_MEM_VSIZE 0x00100000 /* 1MB */
+#define DC21285_PCI_TYPE_1_CONFIG_VBASE 0xFE000000
+#define DC21285_PCI_TYPE_1_CONFIG_VSIZE 0x01000000 /* 16MB */
+#define DC21285_PCI_TYPE_0_CONFIG_VBASE 0xFF000000
+#define DC21285_PCI_TYPE_0_CONFIG_VSIZE 0x01000000 /* 16MB */
diff --git a/sys/arch/arm/footbridge/dc21285reg.h b/sys/arch/arm/footbridge/dc21285reg.h
new file mode 100644
index 00000000000..e1a690ccc1e
--- /dev/null
+++ b/sys/arch/arm/footbridge/dc21285reg.h
@@ -0,0 +1,393 @@
+/* $OpenBSD: dc21285reg.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: dc21285reg.h,v 1.3 2002/11/03 21:43:30 chris Exp $ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997,1998 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * DC21285 register definitions
+ */
+
+/* PCI registers in CSR space */
+
+#define VENDOR_ID 0x00
+#define DC21285_VENDOR_ID 0x1011
+#define DEVICE_ID 0x02
+#define DC21285_DEVICE_ID 0x1065
+#define REVISION 0x08
+#define CLASS 0x0A
+
+/* Other PCI control / status registers */
+
+#define OUTBOUND_INT_STATUS 0x030
+#define OUTBOUND_INT_MASK 0x034
+#define I2O_INBOUND_FIFO 0x040
+#define I2O_OUTBOUND_FIFO 0x044
+
+/* Mailbox registers */
+
+#define MAILBOX_0 0x050
+#define MAILBOX_1 0x054
+#define MAILBOX_2 0x058
+#define MAILBOX_3 0x05C
+
+#define DOORBELL 0x060
+#define DOORBELL_SETUP 0x064
+#define ROM_WRITE_BYTE_ADDRESS 0x068
+
+/* DMA Channel registers */
+
+#define DMA_CHAN_1_BYTE_COUNT 0x80
+#define DMA_CHAN_1_PCI_ADDR 0x84
+#define DMA_CHAN_1_SDRAM_ADDR 0x88
+#define DMA_CHAN_1_DESCRIPT 0x8C
+#define DMA_CHAN_1_CONTROL 0x90
+#define DMA_CHAN_2_BYTE_COUNT 0xA0
+#define DMA_CHAN_2_PCI_ADDR 0xA4
+#define DMA_CHAN_2_SDRAM_ADDR 0xA8
+#define DMA_CHAN_2_DESCRIPTOR 0xAC
+#define DMA_CHAN_2_CONTROL 0xB0
+
+/* Offsets into DMA descriptor */
+
+#define DMA_BYTE_COUNT 0
+#define DMA_PCI_ADDRESS 4
+#define DMA_SDRAM_ADDRESS 8
+#define DMA_NEXT_DESCRIPTOR 12
+
+/* DMA byte count register bits */
+
+#define DMA_INTERBURST_SHIFT 24
+#define DMA_PCI_TO_SDRAM 0
+#define DMA_SDRAM_TO_PCI (1 << 30)
+#define DMA_END_CHAIN (1 << 31)
+
+/* DMA control bits */
+
+#define DMA_ENABLE (1 << 0)
+#define DMA_TRANSFER_DONE (1 << 2)
+#define DMA_ERROR (1 << 3)
+#define DMA_REGISTOR_DESCRIPTOR (1 << 4)
+#define DMA_PCI_MEM_READ (0 << 5)
+#define DMA_PCI_MEM_READ_LINE (1 << 5)
+#define DMA_PCI_MEM_READ_MULTI1 (2 << 5)
+#define DMA_PCI_MEM_READ_MULTI2 (3 << 5)
+#define DMA_CHAIN_DONE (1 << 7)
+#define DMA_INTERBURST_4 (0 << 8)
+#define DMA_INTERBURST_8 (1 << 8)
+#define DMA_INTERBURST_16 (2 << 8)
+#define DMA_INTERBURST_32 (3 << 8)
+#define DMA_PCI_LENGTH_8 0
+#define DMA_PCI_LENGTH_16 (1 << 15)
+#define DMA_SDRAM_LENGTH_1 (0 << 16)
+#define DMA_SDRAM_LENGTH_2 (1 << 16)
+#define DMA_SDRAM_LENGTH_4 (2 << 16)
+#define DMA_SDRAM_LENGTH_8 (3 << 16)
+#define DMA_SDRAM_LENGTH_16 (4 << 16)
+
+/* CSR Base Address Mask */
+
+#define CSR_BA_MASK 0x0F8
+#define CSR_MASK_128B 0x00000000
+#define CSR_MASK_512KB 0x00040000
+#define CSR_MASK_1MB 0x000C0000
+#define CSR_MASK_2MB 0x001C0000
+#define CSR_MASK_4MB 0x003C0000
+#define CSR_MASK_8MB 0x007C0000
+#define CSR_MASK_16MB 0x00FC0000
+#define CSR_MASK_32MB 0x01FC0000
+#define CSR_MASK_64MB 0x03FC0000
+#define CSR_MASK_128MB 0x07FC0000
+#define CSR_MASK_256MB 0x0FFC0000
+#define CSR_BA_OFFSET 0x0FC
+
+/* SDRAM Base Address Mask */
+
+#define SDRAM_BA_MASK 0x100
+#define SDRAM_MASK_256KB 0x00000000
+#define SDRAM_MASK_512KB 0x00040000
+#define SDRAM_MASK_1MB 0x000C0000
+#define SDRAM_MASK_2MB 0x001C0000
+#define SDRAM_MASK_4MB 0x003C0000
+#define SDRAM_MASK_8MB 0x007C0000
+#define SDRAM_MASK_16MB 0x00FC0000
+#define SDRAM_MASK_32MB 0x01FC0000
+#define SDRAM_MASK_64MB 0x03FC0000
+#define SDRAM_MASK_128MB 0x07FC0000
+#define SDRAM_MASK_256MB 0x0FFC0000
+#define SDRAM_WINDOW_DISABLE (1 << 31)
+#define SDRAM_BA_OFFSET 0x104
+
+/* Expansion ROM Base Address Mask */
+
+#define EXPANSION_ROM_BA_MASK 0x108
+#define ROM_MASK_1MB 0x00000000
+#define ROM_MASK_2MB 0x00100000
+#define ROM_MASK_4MB 0x00300000
+#define ROM_MASK_8MB 0x00700000
+#define ROM_MASK_16MB 0x00F00000
+#define ROM_WINDOW_DISABLE (1 << 31)
+
+/* SDRAM configuration */
+
+#define SDRAM_TIMING 0x10C
+#define SDRAM_ARRAY_SIZE_0 0x0
+#define SDRAM_ARRAY_SIZE_1MB 0x1
+#define SDRAM_ARRAY_SIZE_2MB 0x2
+#define SDRAM_ARRAY_SIZE_4MB 0x3
+#define SDRAM_ARRAY_SIZE_8MB 0x4
+#define SDRAM_ARRAY_SIZE_16MB 0x5
+#define SDRAM_ARRAY_SIZE_32MB 0x6
+#define SDRAM_ARRAY_SIZE_64MB 0x7
+#define SDRAM_2_BANKS 0
+#define SDRAM_4_BANKS (1 << 3)
+#define SDRAM_ADDRESS_MUX_SHIFT 4
+#define SDRAM_ARRAY_BASE_SHIFT 20
+#define SDRAM_ADDRESS_SIZE_0 0x110
+#define SDRAM_ADDRESS_SIZE_1 0x114
+#define SDRAM_ADDRESS_SIZE_2 0x118
+#define SDRAM_ADDRESS_SIZE_3 0x11C
+
+/* I2O registers */
+
+#define I2O_INBOUND_FREE_HEAD 0x120
+#define I2O_INBOUND_POST_TAIL 0x124
+#define I2O_OUTBOUND_POST_HEAD 0x128
+#define I2O_OUTBOUND_FREE_TAIL 0x12c
+#define I2O_INBOUND_FREE_COUNT 0x130
+#define I2O_OUTBOUND_POST_COUNT 0x134
+#define I2O_INBOUND_POST_COUNT 0x138
+
+/* Control register */
+
+#define SA_CONTROL 0x13C
+#define INITIALIZE_COMPLETE (1 << 0)
+#define ASSERT_SERR (1 << 1)
+#define RECEIVED_SERR (1 << 3)
+#define SA_SDRAM_PARITY_ERROR (1 << 4)
+#define PCI_SDRAM_PARITY_ERROR (1 << 5)
+#define DMA_SDRAM_PARITY_ERROR (1 << 6)
+#define DISCARD_TIMER_EXPIRED (1 << 8)
+#define PCI_NOT_RESET (1 << 9)
+#define WATCHDOG_ENABLE (1 << 13)
+#define I2O_SIZE_256 (0 << 10)
+#define I2O_SIZE_512 (1 << 10)
+#define I2O_SIZE_1024 (2 << 10)
+#define I2O_SIZE_2048 (3 << 10)
+#define I2O_SIZE_4096 (4 << 10)
+#define I2O_SIZE_8192 (5 << 10)
+#define I2O_SIZE_16384 (6 << 10)
+#define I2O_SIZE_32768 (7 << 10)
+#define ROM_WIDTH_8 (3 << 14)
+#define ROM_WIDTH_16 (1 << 14)
+#define ROM_WIDTH_32 (2 << 14)
+#define ROM_ACCESS_TIME_SHIFT 16
+#define ROM_BURST_TIME_SHIFT 20
+#define ROM_TRISTATE_TIME_SHIFT 24
+#define XCS_DIRECTION_SHIFT 28
+#define PCI_CENTRAL_FUNCTION (1 << 31)
+
+#define PCI_ADDRESS_EXTENSION 0x140
+#define PREFETCHABLE_MEM_RANGE 0x144
+
+/* XBUS / PCI Arbiter registers */
+
+#define XBUS_CYCLE_ARBITER 0x148
+#define XBUS_CYCLE_0_SHIFT 0
+#define XBUS_CYCLE_1_SHIFT 3
+#define XBUS_CYCLE_2_SHIFT 6
+#define XBUS_CYCLE_3_SHIFT 9
+#define XBUS_CYCLE_STROBE_SHIFT 12
+#define XBUS_PCI_ARBITER (1 << 23)
+#define XBUS_INT_IN_L0_LOW 0
+#define XBUS_INT_IN_L0_HIGH (1 << 24)
+#define XBUS_INT_IN_L1_LOW 0
+#define XBUS_INT_IN_L1_HIGH (1 << 25)
+#define XBUS_INT_IN_L2_LOW 0
+#define XBUS_INT_IN_L2_HIGH (1 << 26)
+#define XBUS_INT_IN_L3_LOW 0
+#define XBUS_INT_IN_L3_HIGH (1 << 27)
+#define XBUS_INT_XCS0_LOW 0
+#define XBUS_INT_XCS0_HIGH (1 << 28)
+#define XBUS_INT_XCS1_LOW 0
+#define XBUS_INT_XCS1_HIGH (1 << 29)
+#define XBUS_INT_XCS2_LOW 0
+#define XBUS_INT_XCS2_HIGH (1 << 30)
+#define XBUS_PCI_INT_REQUEST (1 << 31)
+
+#define XBUS_IO_STROBE_MASK 0x14C
+#define XBUS_IO_STROBE_0_SHIFT 0
+#define XBUS_IO_STROBE_2_SHIFT 8
+#define XBUS_IO_STROBE_3_SHIFT 16
+#define XBUS_IO_STROBE_4_SHIFT 24
+
+#define DOORBELL_PCI_MASK 0x150
+#define DOORBELL_SA_MASK 0x154
+
+/* UART registers */
+
+#define UART_DATA 0x160
+#define UART_RX_STAT 0x164
+#define UART_PARITY_ERROR 0x01
+#define UART_FRAME_ERROR 0x02
+#define UART_OVERRUN_ERROR 0x04
+#define UART_RX_ERROR (UART_PARITY_ERROR | UART_FRAME_ERROR \
+ | UART_OVERRUN_ERROR)
+#define UART_H_UBRLCR 0x168
+#define UART_BREAK 0x01
+#define UART_PARITY_ENABLE 0x02
+#define UART_ODD_PARITY 0x00
+#define UART_EVEN_PARITY 0x04
+#define UART_STOP_BITS_1 0x00
+#define UART_STOP_BITS_2 0x08
+#define UART_ENABLE_FIFO 0x10
+#define UART_DATA_BITS_5 0x00
+#define UART_DATA_BITS_6 0x20
+#define UART_DATA_BITS_7 0x40
+#define UART_DATA_BITS_8 0x60
+#define UART_M_UBRLCR 0x16C
+#define UART_L_UBRLCR 0x170
+#define UART_BRD(fclk, x) (((fclk) / 4 / 16 / x) - 1)
+
+#define UART_CONTROL 0x174
+#define UART_ENABLE 0x01
+#define UART_SIR_ENABLE 0x02
+#define UART_IRDA_ENABLE 0x04
+#define UART_FLAGS 0x178
+#define UART_TX_BUSY 0x08
+#define UART_RX_FULL 0x10
+#define UART_TX_EMPTY 0x20
+
+/* Interrupt numbers for IRQ and FIQ registers */
+
+#define IRQ_RESERVED0 0x00
+#define IRQ_SOFTINT 0x01
+#define IRQ_SERIAL_RX 0x02
+#define IRQ_SERIAL_TX 0x03
+#define IRQ_TIMER_1 0x04
+#define IRQ_TIMER_2 0x05
+#define IRQ_TIMER_3 0x06
+#define IRQ_TIMER_4 0x07
+#define IRQ_IN_L0 0x08
+#define IRQ_IN_L1 0x09
+#define IRQ_IN_L2 0x0A
+#define IRQ_IN_L3 0x0B
+#define IRQ_XCS_L0 0x0C
+#define IRQ_XCS_L1 0x0D
+#define IRQ_XCS_L2 0x0E
+#define IRQ_DOORBELL 0x0F
+#define IRQ_DMA_1 0x10
+#define IRQ_DMA_2 0x11
+#define IRQ_PCI 0x12
+#define IRQ_PMCSR 0x13
+#define IRQ_RESERVED1 0x14
+#define IRQ_RESERVED2 0x15
+#define IRQ_BIST 0x16
+#define IRQ_SERR 0x17
+#define IRQ_SDRAM_PARITY 0x18
+#define IRQ_I2O 0x19
+#define IRQ_RESERVED3 0x1A
+#define IRQ_DISCARD_TIMER 0x1B
+#define IRQ_DATA_PARITY 0x1C
+#define IRQ_MASTER_ABORT 0x1D
+#define IRQ_TARGET_ABORT 0x1E
+#define IRQ_PARITY 0x1F
+
+/* IRQ and FIQ status / enable registers */
+
+#define IRQ_STATUS 0x180
+#define IRQ_RAW_STATUS 0x184
+#define IRQ_ENABLE 0x188
+#define IRQ_ENABLE_SET 0x188
+#define IRQ_ENABLE_CLEAR 0x18c
+#define IRQ_SOFT 0x190
+
+#define FIQ_STATUS 0x280
+#define FIQ_RAW_STATUS 0x284
+#define FIQ_ENABLE 0x288
+#define FIQ_ENABLE_SET 0x288
+#define FIQ_ENABLE_CLEAR 0x28c
+#define FIQ_SOFT 0x290
+
+/* Timer registers */
+
+/* Relative offsets and bases */
+
+#define TIMER_LOAD 0x00
+#define TIMER_VALUE 0x04
+#define TIMER_CONTROL 0x08
+#define TIMER_CLEAR 0x0C
+#define TIMER_1_BASE 0x300
+#define TIMER_2_BASE 0x320
+#define TIMER_3_BASE 0x340
+#define TIMER_4_BASE 0x360
+
+/* Control register bits */
+
+#define TIMER_FCLK 0x00
+#define TIMER_FCLK_16 0x04
+#define TIMER_FCLK_256 0x08
+#define TIMER_EXTERNAL 0x0C
+#define TIMER_MODE_FREERUN 0x00
+#define TIMER_MODE_PERIODIC 0x40
+#define TIMER_ENABLE 0x80
+
+/* Maximum timer value */
+
+#define TIMER_MAX_VAL 0x00FFFFFF
+
+/* Specific registers */
+
+#define TIMER_1_LOAD 0x300
+#define TIMER_1_VALUE 0x304
+#define TIMER_1_CONTROL 0x308
+#define TIMER_1_CLEAR 0x30C
+#define TIMER_2_LOAD 0x320
+#define TIMER_2_VALUE 0x324
+#define TIMER_2_CONTROL 0x328
+#define TIMER_2_CLEAR 0x32C
+#define TIMER_3_LOAD 0x340
+#define TIMER_3_VALUE 0x344
+#define TIMER_3_CONTROL 0x348
+#define TIMER_3_CLEAR 0x34C
+#define TIMER_4_LOAD 0x360
+#define TIMER_4_VALUE 0x364
+#define TIMER_4_CONTROL 0x368
+#define TIMER_4_CLEAR 0x36C
+
+/* Miscellaneous definitions */
+
+#ifndef FCLK
+#define FCLK 50000000
+#endif
diff --git a/sys/arch/arm/footbridge/footbridge.c b/sys/arch/arm/footbridge/footbridge.c
new file mode 100644
index 00000000000..35d2f3889fb
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge.c
@@ -0,0 +1,293 @@
+/* $OpenBSD: footbridge.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge.c,v 1.7 2002/05/16 01:01:33 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997,1998 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#include <dev/pci/pcivar.h>
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/cpuconf.h>
+#include <arm/cpufunc.h>
+
+#include <arm/mainbus/mainbus.h>
+#include <arm/footbridge/footbridgevar.h>
+#include <arm/footbridge/dc21285reg.h>
+#include <arm/footbridge/dc21285mem.h>
+#include <arm/footbridge/footbridge.h>
+
+/*
+ * DC21285 'Footbridge' device
+ *
+ * This probes and attaches the footbridge device
+ * It then configures any children
+ */
+
+/* Declare prototypes */
+
+static int footbridge_match __P((struct device *parent, void *cf,
+ void *aux));
+static void footbridge_attach __P((struct device *parent, struct device *self,
+ void *aux));
+static int footbridge_print __P((void *aux, const char *pnp));
+static int footbridge_intr __P((void *arg));
+
+/* Driver and attach structures */
+struct cfattach footbridge_ca = {
+ sizeof(struct footbridge_softc), footbridge_match, footbridge_attach
+};
+
+struct cfdriver footbridge_cd = {
+ NULL, "footbridge", DV_DULL
+};
+
+/* Various bus space tags */
+extern struct bus_space footbridge_bs_tag;
+extern void footbridge_create_io_bs_tag(bus_space_tag_t t, void *cookie);
+extern void footbridge_create_mem_bs_tag(bus_space_tag_t t, void *cookie);
+struct bus_space footbridge_csr_tag;
+struct bus_space footbridge_pci_io_bs_tag;
+struct bus_space footbridge_pci_mem_bs_tag;
+extern struct arm32_pci_chipset footbridge_pci_chipset;
+extern struct arm32_bus_dma_tag footbridge_pci_bus_dma_tag;
+
+/* Used in footbridge_clock.c */
+struct footbridge_softc *clock_sc;
+
+/* Set to non-zero to enable verbose reporting of footbridge system ints */
+int footbridge_intr_report = 0;
+
+int footbridge_found;
+
+void
+footbridge_pci_bs_tag_init(void)
+{
+ /* Set up the PCI bus tags */
+ footbridge_create_io_bs_tag(&footbridge_pci_io_bs_tag,
+ (void *)DC21285_PCI_IO_VBASE);
+ footbridge_create_mem_bs_tag(&footbridge_pci_mem_bs_tag,
+ (void *)DC21285_PCI_MEM_BASE);
+}
+
+/*
+ * int footbridgeprint(void *aux, const char *name)
+ *
+ * print configuration info for children
+ */
+
+static int
+footbridge_print(aux, pnp)
+ void *aux;
+ const char *pnp;
+{
+ union footbridge_attach_args *fba = aux;
+
+ if (pnp)
+ printf("%s at %s", fba->fba_name, pnp);
+ if (strcmp(fba->fba_name, "pci") == 0)
+ printf(" bus %d", fba->fba_pba.pba_bus);
+ return(UNCONF);
+}
+
+/*
+ * int footbridge_match(struct device *parent, struct cfdata *cf, void *aux)
+ *
+ * Just return ok for this if it is device 0
+ */
+
+static int
+footbridge_match(parent, vcf, aux)
+ struct device *parent;
+ void *vcf;
+ void *aux;
+{
+ struct mainbus_attach_args *ma = aux;
+ struct cfdata *cf = (struct cfdata *)vcf;
+
+ return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0);
+}
+
+
+/*
+ * void footbridge_attach(struct device *parent, struct device *dev, void *aux)
+ *
+ */
+
+static void
+footbridge_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct footbridge_softc *sc = (struct footbridge_softc *)self;
+ union footbridge_attach_args fba;
+ int vendor, device, rev;
+
+ /* There can only be 1 footbridge. */
+ footbridge_found = 1;
+
+ clock_sc = sc;
+
+ sc->sc_iot = &footbridge_bs_tag;
+
+ /* Map the Footbridge */
+ if (bus_space_map(sc->sc_iot, DC21285_ARMCSR_VBASE,
+ DC21285_ARMCSR_VSIZE, 0, &sc->sc_ioh))
+ panic("%s: Cannot map registers", self->dv_xname);
+
+ /* Read the ID to make sure it is what we think it is */
+ vendor = bus_space_read_2(sc->sc_iot, sc->sc_ioh, VENDOR_ID);
+ device = bus_space_read_2(sc->sc_iot, sc->sc_ioh, DEVICE_ID);
+ rev = bus_space_read_1(sc->sc_iot, sc->sc_ioh, REVISION);
+ if (vendor != DC21285_VENDOR_ID && device != DC21285_DEVICE_ID)
+ panic("%s: Unrecognised ID", self->dv_xname);
+
+ printf(": DC21285 rev %d\n", rev);
+
+ /* Disable all interrupts from the footbridge */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IRQ_ENABLE_CLEAR, 0xffffffff);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, FIQ_ENABLE_CLEAR, 0xffffffff);
+
+/* bus_space_write_4(sc->sc_iot, sc->sc_ioh, 0x18, 0x40000000);*/
+
+ /* Install a generic handler to catch a load of system interrupts */
+ sc->sc_serr_ih = footbridge_intr_claim(IRQ_SERR, IPL_HIGH,
+ "serr", footbridge_intr, sc);
+ sc->sc_sdram_par_ih = footbridge_intr_claim(IRQ_SDRAM_PARITY, IPL_HIGH,
+ "sdram parity", footbridge_intr, sc);
+ sc->sc_data_par_ih = footbridge_intr_claim(IRQ_DATA_PARITY, IPL_HIGH,
+ "data parity", footbridge_intr, sc);
+ sc->sc_master_abt_ih = footbridge_intr_claim(IRQ_MASTER_ABORT, IPL_HIGH,
+ "mast abt", footbridge_intr, sc);
+ sc->sc_target_abt_ih = footbridge_intr_claim(IRQ_TARGET_ABORT, IPL_HIGH,
+ "targ abt", footbridge_intr, sc);
+ sc->sc_parity_ih = footbridge_intr_claim(IRQ_PARITY, IPL_HIGH,
+ "parity", footbridge_intr, sc);
+
+ /* Set up the PCI bus tags */
+ footbridge_create_io_bs_tag(&footbridge_pci_io_bs_tag,
+ (void *)DC21285_PCI_IO_VBASE);
+ footbridge_create_mem_bs_tag(&footbridge_pci_mem_bs_tag,
+ (void *)DC21285_PCI_MEM_BASE);
+
+ /* calibrate the delay loop */
+ calibrate_delay();
+ /* Attach the PCI bus */
+ fba.fba_pba.pba_busname = "pci";
+ fba.fba_pba.pba_pc = &footbridge_pci_chipset;
+ fba.fba_pba.pba_iot = &footbridge_pci_io_bs_tag;
+ fba.fba_pba.pba_memt = &footbridge_pci_mem_bs_tag;
+ fba.fba_pba.pba_dmat = &footbridge_pci_bus_dma_tag;
+ /*
+ fba.fba_pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
+ */
+ fba.fba_pba.pba_bus = 0;
+ config_found(self, &fba.fba_pba, footbridge_print);
+
+ /* Attach a time-of-day clock device */
+ fba.fba_tca.ta_name = "todclock";
+ fba.fba_tca.ta_rtc_arg = NULL;
+ fba.fba_tca.ta_rtc_write = NULL;
+ fba.fba_tca.ta_rtc_read = NULL;
+ fba.fba_tca.ta_flags = TODCLOCK_FLAG_FAKE;
+ config_found(self, &fba.fba_tca, footbridge_print);
+
+ /* Attach uart device */
+ fba.fba_fca.fca_name = "fcom";
+ fba.fba_fca.fca_iot = sc->sc_iot;
+ fba.fba_fca.fca_ioh = sc->sc_ioh;
+ fba.fba_fca.fca_rx_irq = IRQ_SERIAL_RX;
+ fba.fba_fca.fca_tx_irq = IRQ_SERIAL_TX;
+ config_found(self, &fba.fba_fca, footbridge_print);
+
+ /* Setup fast SA110 cache clean area */
+#ifdef CPU_SA110
+ if (cputype == CPU_ID_SA110)
+ footbridge_sa110_cc_setup();
+#endif /* CPU_SA110 */
+
+}
+
+/* Generic footbridge interrupt handler */
+
+int
+footbridge_intr(arg)
+ void *arg;
+{
+ struct footbridge_softc *sc = arg;
+ u_int ctrl, intr;
+
+ /*
+ * Read the footbridge control register and check for
+ * SERR and parity errors
+ */
+ ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SA_CONTROL);
+ intr = ctrl & (RECEIVED_SERR | SA_SDRAM_PARITY_ERROR |
+ PCI_SDRAM_PARITY_ERROR | DMA_SDRAM_PARITY_ERROR);
+ if (intr) {
+ /* Report the interrupt if reporting is enabled */
+ if (footbridge_intr_report)
+ printf("footbridge_intr: ctrl=%08x\n", intr);
+ /* Clear the interrupt state */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SA_CONTROL,
+ ctrl | intr);
+ }
+ /*
+ * Read the PCI status register and check for errors
+ */
+ ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PCI_COMMAND_STATUS_REG);
+ intr = ctrl & (PCI_STATUS_PARITY_ERROR | PCI_STATUS_MASTER_TARGET_ABORT
+ | PCI_STATUS_MASTER_ABORT | PCI_STATUS_SPECIAL_ERROR
+ | PCI_STATUS_PARITY_DETECT);
+ if (intr) {
+ /* Report the interrupt if reporting is enabled */
+ if (footbridge_intr_report)
+ printf("footbridge_intr: pcistat=%08x\n", intr);
+ /* Clear the interrupt state */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh,
+ PCI_COMMAND_STATUS_REG, ctrl | intr);
+ }
+ return(0);
+}
+
+/* End of footbridge.c */
diff --git a/sys/arch/arm/footbridge/footbridge.h b/sys/arch/arm/footbridge/footbridge.h
new file mode 100644
index 00000000000..3da3c6af1a4
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge.h
@@ -0,0 +1,17 @@
+/* $OpenBSD: footbridge.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge.h,v 1.2 2002/05/04 10:04:42 chris Exp $ */
+
+#ifndef _FOOTBRIDGE_H_
+#define _FOOTBRIDGE_H_
+
+#include <sys/termios.h>
+#include <arm/bus.h>
+void footbridge_pci_bs_tag_init __P((void));
+void footbridge_sa110_cc_setup __P((void));
+void footbridge_create_io_bs_tag __P((struct bus_space *, void *));
+void footbridge_create_mem_bs_tag __P((struct bus_space *, void *));
+int fcomcnattach __P((u_int, int, tcflag_t));
+int fcomcndetach __P((void));
+void calibrate_delay __P((void));
+
+#endif
diff --git a/sys/arch/arm/footbridge/footbridge_clock.c b/sys/arch/arm/footbridge/footbridge_clock.c
new file mode 100644
index 00000000000..fbe733a4367
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_clock.c
@@ -0,0 +1,482 @@
+/* $OpenBSD: footbridge_clock.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_clock.c,v 1.17 2003/03/23 14:12:25 chris Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+/* Include header files */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/device.h>
+
+#include <machine/intr.h>
+
+#include <arm/cpufunc.h>
+
+#include <arm/footbridge/dc21285reg.h>
+#include <arm/footbridge/footbridgevar.h>
+#include <arm/footbridge/footbridge.h>
+
+extern struct footbridge_softc *clock_sc;
+extern u_int dc21285_fclk;
+
+int clockhandler __P((void *));
+int statclockhandler __P((void *));
+static int load_timer __P((int, int));
+
+/*
+ * Statistics clock variance, in usec. Variance must be a
+ * power of two. Since this gives us an even number, not an odd number,
+ * we discard one case and compensate. That is, a variance of 1024 would
+ * give us offsets in [0..1023]. Instead, we take offsets in [1..1023].
+ * This is symmetric about the point 512, or statvar/2, and thus averages
+ * to that value (assuming uniform random numbers).
+ */
+const int statvar = 1024;
+int statmin; /* minimum stat clock count in ticks */
+int statcountperusec; /* number of ticks per usec at current stathz */
+int statprev; /* last value of we set statclock to */
+
+#if 0
+static int clockmatch __P((struct device *parent, struct cfdata *cf, void *aux));
+static void clockattach __P((struct device *parent, struct device *self, void *aux));
+
+CFATTACH_DECL(footbridge_clock, sizeof(struct clock_softc),
+ clockmatch, clockattach, NULL, NULL);
+
+/*
+ * int clockmatch(struct device *parent, void *match, void *aux)
+ *
+ * Just return ok for this if it is device 0
+ */
+
+static int
+clockmatch(parent, cf, aux)
+ struct device *parent;
+ struct cfdata *cf;
+ void *aux;
+{
+ union footbridge_attach_args *fba = aux;
+
+ if (strcmp(fba->fba_ca.ca_name, "clk") == 0)
+ return(1);
+ return(0);
+}
+
+
+/*
+ * void clockattach(struct device *parent, struct device *dev, void *aux)
+ *
+ */
+
+static void
+clockattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct clock_softc *sc = (struct clock_softc *)self;
+ union footbridge_attach_args *fba = aux;
+
+ sc->sc_iot = fba->fba_ca.ca_iot;
+ sc->sc_ioh = fba->fba_ca.ca_ioh;
+
+ clock_sc = sc;
+
+ /* Cannot do anything until cpu_initclocks() has been called */
+
+ printf("\n");
+}
+#endif
+
+/*
+ * int clockhandler(struct clockframe *frame)
+ *
+ * Function called by timer 1 interrupts.
+ * This just clears the interrupt condition and calls hardclock().
+ */
+
+int
+clockhandler(aframe)
+ void *aframe;
+{
+ struct clockframe *frame = aframe;
+ bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_1_CLEAR, 0);
+ hardclock(frame);
+ {
+ void debugled(u_int32_t);
+ extern int ticks;
+ debugled(ticks);
+ }
+ return(0); /* Pass the interrupt on down the chain */
+}
+
+/*
+ * int statclockhandler(struct clockframe *frame)
+ *
+ * Function called by timer 2 interrupts.
+ * This just clears the interrupt condition and calls statclock().
+ */
+
+int
+statclockhandler(aframe)
+ void *aframe;
+{
+ struct clockframe *frame = aframe;
+ int newint, r;
+ int currentclock ;
+
+ /* start the clock off again */
+ bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_2_CLEAR, 0);
+
+ do {
+ r = random() & (statvar-1);
+ } while (r == 0);
+ newint = statmin + (r * statcountperusec);
+
+ /* fetch the current count */
+ currentclock = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_2_VALUE);
+
+ /*
+ * work out how much time has run, add another usec for time spent
+ * here
+ */
+ r = ((statprev - currentclock) + statcountperusec);
+
+ if (r < newint) {
+ newint -= r;
+ r = 0;
+ }
+ else
+ printf("statclockhandler: Statclock overrun\n");
+
+
+ /*
+ * update the clock to the new counter, this reloads the existing
+ * timer
+ */
+ bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_2_LOAD, newint);
+ statprev = newint;
+ statclock(frame);
+ if (r)
+ /*
+ * We've completely overrun the previous interval,
+ * make sure we report the correct number of ticks.
+ */
+ statclock(frame);
+
+ return(0); /* Pass the interrupt on down the chain */
+}
+
+static int
+load_timer(base, hz)
+ int base;
+ int hz;
+{
+ unsigned int timer_count;
+ int control;
+
+ timer_count = dc21285_fclk / hz;
+ if (timer_count > TIMER_MAX_VAL * 16) {
+ control = TIMER_FCLK_256;
+ timer_count >>= 8;
+ } else if (timer_count > TIMER_MAX_VAL) {
+ control = TIMER_FCLK_16;
+ timer_count >>= 4;
+ } else
+ control = TIMER_FCLK;
+
+ control |= (TIMER_ENABLE | TIMER_MODE_PERIODIC);
+ bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ base + TIMER_LOAD, timer_count);
+ bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ base + TIMER_CONTROL, control);
+ bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ base + TIMER_CLEAR, 0);
+ return(timer_count);
+}
+
+/*
+ * void setstatclockrate(int hz)
+ *
+ * Set the stat clock rate. The stat clock uses timer2
+ */
+
+void
+setstatclockrate(hz)
+ int hz;
+{
+ int statint;
+ int countpersecond;
+ int statvarticks;
+
+ /* statint == num in counter to drop by desired hz */
+ statint = statprev = clock_sc->sc_statclock_count =
+ load_timer(TIMER_2_BASE, hz);
+
+ /* Get the total ticks a second */
+ countpersecond = statint * hz;
+
+ /* now work out how many ticks per usec */
+ statcountperusec = countpersecond / 1000000;
+
+ /* calculate a variance range of statvar */
+ statvarticks = statcountperusec * statvar;
+
+ /* minimum is statint - 50% of variant */
+ statmin = statint - (statvarticks / 2);
+}
+
+/*
+ * void cpu_initclocks(void)
+ *
+ * Initialise the clocks.
+ *
+ * Timer 1 is used for the main system clock (hardclock)
+ * Timer 2 is used for the statistics clock (statclock)
+ */
+
+void
+cpu_initclocks()
+{
+ /* stathz and profhz should be set to something, we have the timer */
+#if 0
+ if (stathz == 0)
+ stathz = hz;
+
+ if (profhz == 0)
+ profhz = stathz * 5;
+#endif
+
+ /* Report the clock frequencies */
+ printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
+
+ /* Setup timer 1 and claim interrupt */
+ clock_sc->sc_clock_count = load_timer(TIMER_1_BASE, hz);
+
+ /*
+ * Use ticks per 256us for accuracy since ticks per us is often
+ * fractional e.g. @ 66MHz
+ */
+ clock_sc->sc_clock_ticks_per_256us =
+ ((((clock_sc->sc_clock_count * hz) / 1000) * 256) / 1000);
+ clock_sc->sc_clockintr = footbridge_intr_claim(IRQ_TIMER_1, IPL_CLOCK,
+ "tmr1 hard clk", clockhandler, 0);
+
+ if (clock_sc->sc_clockintr == NULL)
+ panic("%s: Cannot install timer 1 interrupt handler",
+ clock_sc->sc_dev.dv_xname);
+
+ /* If stathz is non-zero then setup the stat clock */
+ if (stathz) {
+ /* Setup timer 2 and claim interrupt */
+ setstatclockrate(stathz);
+ clock_sc->sc_statclockintr = footbridge_intr_claim(IRQ_TIMER_2, IPL_STATCLOCK,
+ "tmr2 stat clk", statclockhandler, 0);
+ if (clock_sc->sc_statclockintr == NULL)
+ panic("%s: Cannot install timer 2 interrupt handler",
+ clock_sc->sc_dev.dv_xname);
+ }
+}
+
+
+/*
+ * void microtime(struct timeval *tvp)
+ *
+ * Fill in the specified timeval struct with the current time
+ * accurate to the microsecond.
+ */
+
+void
+microtime(tvp)
+ struct timeval *tvp;
+{
+ int s;
+ int tm;
+ int deltatm;
+ static struct timeval oldtv;
+
+ if (clock_sc == NULL || clock_sc->sc_clock_count == 0)
+ return;
+
+ s = splhigh();
+
+ tm = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_1_VALUE);
+
+ deltatm = clock_sc->sc_clock_count - tm;
+
+#ifdef DIAGNOSTIC
+ if (deltatm < 0)
+ panic("opps deltatm < 0 tm=%d deltatm=%d", tm, deltatm);
+#endif
+
+ /* Fill in the timeval struct */
+ *tvp = time;
+ tvp->tv_usec += ((deltatm << 8) / clock_sc->sc_clock_ticks_per_256us);
+
+ /* Make sure the micro seconds don't overflow. */
+ while (tvp->tv_usec >= 1000000) {
+ tvp->tv_usec -= 1000000;
+ ++tvp->tv_sec;
+ }
+
+ /* Make sure the time has advanced. */
+ if (tvp->tv_sec == oldtv.tv_sec &&
+ tvp->tv_usec <= oldtv.tv_usec) {
+ tvp->tv_usec = oldtv.tv_usec + 1;
+ if (tvp->tv_usec >= 1000000) {
+ tvp->tv_usec -= 1000000;
+ ++tvp->tv_sec;
+ }
+ }
+
+ oldtv = *tvp;
+ (void)splx(s);
+}
+
+/*
+ * Use a timer to track microseconds, if the footbridge hasn't been setup we
+ * rely on an estimated loop, however footbridge is attached very early on.
+ */
+
+static int delay_clock_count = 0;
+static int delay_count_per_usec = 0;
+
+void
+calibrate_delay(void)
+{
+ delay_clock_count = load_timer(TIMER_3_BASE, 100);
+ delay_count_per_usec = delay_clock_count/10000;
+#ifdef VERBOSE_DELAY_CALIBRATION
+ printf("delay calibration: delay_cc = %d, delay_c/us=%d\n",
+ delay_clock_count, delay_count_per_usec);
+
+ printf("0..");
+ delay(1000000);
+ printf("1..");
+ delay(1000000);
+ printf("2..");
+ delay(1000000);
+ printf("3..");
+ delay(1000000);
+ printf("4..");
+ delay(1000000);
+ printf("5..");
+ delay(1000000);
+ printf("6..");
+ delay(1000000);
+ printf("7..");
+ delay(1000000);
+ printf("8..");
+ delay(1000000);
+ printf("9..");
+ delay(1000000);
+ printf("10\n");
+#endif
+}
+
+int delaycount = 25000;
+
+void
+delay(n)
+ u_int n;
+{
+ volatile u_int i;
+ uint32_t cur, last, delta, usecs;
+
+ if (n == 0) return;
+
+
+ /*
+ * not calibrated the timer yet, so try to live with this horrible
+ * loop!
+ */
+ if (delay_clock_count == 0)
+ {
+ while (n-- > 0) {
+ for (i = delaycount; --i;);
+ }
+ return;
+ }
+
+ /*
+ * read the current value (do not reset it as delay is reentrant)
+ */
+ last = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_3_VALUE);
+
+ delta = usecs = 0;
+
+ while (n > usecs)
+ {
+ cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_3_VALUE);
+ if (last < cur)
+ /* timer has wrapped */
+ delta += ((delay_clock_count - cur) + last);
+ else
+ delta += (last - cur);
+
+ if (cur == 0)
+ {
+ /*
+ * reset the timer, note that if something blocks us for more
+ * than 1/100s we may delay for too long, but I believe that
+ * is fairly unlikely.
+ */
+ bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
+ TIMER_3_CLEAR, 0);
+ }
+ last = cur;
+
+ if (delta >= delay_count_per_usec)
+ {
+ usecs += delta / delay_count_per_usec;
+ delta %= delay_count_per_usec;
+ }
+ }
+}
+
+/* End of footbridge_clock.c */
diff --git a/sys/arch/arm/footbridge/footbridge_com.c b/sys/arch/arm/footbridge/footbridge_com.c
new file mode 100644
index 00000000000..7c930907148
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_com.c
@@ -0,0 +1,870 @@
+/* $OpenBSD: footbridge_com.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_com.c,v 1.13 2003/03/23 14:12:25 chris Exp $ */
+
+/*-
+ * Copyright (c) 1997 Mark Brinicombe
+ * Copyright (c) 1997 Causality Limited
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * COM driver, using the footbridge UART
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/termios.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <arm/conf.h>
+#include <arm/footbridge/dc21285mem.h>
+#include <arm/footbridge/dc21285reg.h>
+#include <arm/footbridge/footbridgevar.h>
+#include <arm/footbridge/footbridge.h>
+
+#include <dev/cons.h>
+
+#include "fcom.h"
+
+extern u_int dc21285_fclk;
+
+
+#ifdef DDB
+/*
+ * Define the keycode recognised as a request to call the debugger
+ * A value of 0 disables the feature when DDB is built in
+ */
+#define DDB_KEYCODE '@'
+#ifndef DDB_KEYCODE
+#define DDB_KEYCODE 0
+#endif /* DDB_KEYCODE */
+#endif /* DDB */
+
+struct fcom_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ void *sc_ih;
+ struct timeout sc_softintr_ch;
+ int sc_rx_irq;
+ int sc_tx_irq;
+ int sc_hwflags;
+#define HW_FLAG_CONSOLE 0x01
+ int sc_swflags;
+ int sc_l_ubrlcr;
+ int sc_m_ubrlcr;
+ int sc_h_ubrlcr;
+ char *sc_rxbuffer[2];
+ char *sc_rxbuf;
+ int sc_rxpos;
+ int sc_rxcur;
+ struct tty *sc_tty;
+};
+
+#define RX_BUFFER_SIZE 0x100
+
+static int fcom_probe __P((struct device *, void*, void *));
+static void fcom_attach __P((struct device *, struct device *, void *));
+static void fcom_softintr __P((void *));
+
+static int fcom_rxintr __P((void *));
+/*static int fcom_txintr __P((void *));*/
+
+/*struct consdev;*/
+/*void fcomcnprobe __P((struct consdev *));
+void fcomcninit __P((struct consdev *));*/
+int fcomcngetc __P((dev_t));
+void fcomcnputc __P((dev_t, int));
+void fcomcnpollc __P((dev_t, int));
+
+struct cfattach fcom_ca = {
+ sizeof (struct fcom_softc), fcom_probe, fcom_attach
+};
+
+struct cfdriver fcom_cd = {
+ NULL, "fcom", DV_DULL
+};
+#if 0
+CFATTACH_DECL(fcom, sizeof(struct fcom_softc),
+ fcom_probe, fcom_attach, NULL, NULL);
+#endif
+
+extern struct cfdriver fcom_cd;
+
+dev_type_open(fcomopen);
+dev_type_close(fcomclose);
+dev_type_read(fcomread);
+dev_type_write(fcomwrite);
+dev_type_ioctl(fcomioctl);
+dev_type_tty(fcomtty);
+dev_type_poll(fcompoll);
+
+#if 0
+const struct cdevsw fcom_cdevsw = {
+ fcomopen, fcomclose, fcomread, fcomwrite, fcomioctl,
+ nostop, fcomtty, fcompoll, nommap, ttykqfilter, D_TTY
+};
+#endif
+
+void fcominit __P((bus_space_tag_t, bus_space_handle_t, int, int));
+void fcominitcons __P((bus_space_tag_t, bus_space_handle_t));
+
+bus_space_tag_t fcomconstag;
+bus_space_handle_t fcomconsioh;
+extern int comcnmode;
+extern int comcnspeed;
+
+#define COMUNIT(x) (minor(x))
+#ifndef CONUNIT
+#define CONUNIT 0
+#endif
+
+/*
+ * The console is set up at init time, well in advance of the reset of the
+ * system and thus we have a private bus space tag for the console.
+ *
+ * The tag is provided by fcom_io.c and fcom_io_asm.S
+ */
+extern struct bus_space fcomcons_bs_tag;
+
+/*
+ * int fcom_probe(struct device *parent, struct cfdata *cf, void *aux)
+ *
+ * Make sure we are trying to attach a com device and then
+ * probe for one.
+ */
+
+static int
+fcom_probe(parent, cf, aux)
+ struct device *parent;
+ void *cf;
+ void *aux;
+{
+ union footbridge_attach_args *fba = aux;
+
+ if (strcmp(fba->fba_name, "fcom") == 0)
+ return(1);
+ return(0);
+}
+
+/*
+ * void fcom_attach(struct device *parent, struct device *self, void *aux)
+ *
+ * attach the com device
+ */
+
+static void
+fcom_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ union footbridge_attach_args *fba = aux;
+ struct fcom_softc *sc = (struct fcom_softc *)self;
+
+ /* Set up the softc */
+ sc->sc_iot = fba->fba_fca.fca_iot;
+ sc->sc_ioh = fba->fba_fca.fca_ioh;
+ timeout_set(&sc->sc_softintr_ch, fcom_softintr, sc);
+ sc->sc_rx_irq = fba->fba_fca.fca_rx_irq;
+ sc->sc_tx_irq = fba->fba_fca.fca_tx_irq;
+ sc->sc_hwflags = 0;
+ sc->sc_swflags = 0;
+
+ /* If we have a console tag then make a note of it */
+ if (fcomconstag)
+ sc->sc_hwflags |= HW_FLAG_CONSOLE;
+
+ if (sc->sc_hwflags & HW_FLAG_CONSOLE) {
+ int major;
+
+ /* locate the major number */
+ for (major = 0; major < nchrdev; ++major)
+ if (cdevsw[major].d_open == fcomopen)
+ break;
+
+ cn_tab->cn_dev = makedev(major, sc->sc_dev.dv_unit);
+ printf(": console");
+ }
+ printf("\n");
+
+ sc->sc_ih = footbridge_intr_claim(sc->sc_rx_irq, IPL_SERIAL,
+ "serial rx", fcom_rxintr, sc);
+ if (sc->sc_ih == NULL)
+ panic("%s: Cannot install rx interrupt handler",
+ sc->sc_dev.dv_xname);
+}
+
+static void fcomstart __P((struct tty *));
+static int fcomparam __P((struct tty *, struct termios *));
+
+int
+fcomopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct fcom_softc *sc;
+ int unit = minor(dev);
+ struct tty *tp;
+
+ if (unit >= fcom_cd.cd_ndevs)
+ return ENXIO;
+ sc = fcom_cd.cd_devs[unit];
+ if (!sc)
+ return ENXIO;
+ if (!(tp = sc->sc_tty))
+ sc->sc_tty = tp = ttymalloc();
+ if (!sc->sc_rxbuffer[0]) {
+ sc->sc_rxbuffer[0] = malloc(RX_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
+ sc->sc_rxbuffer[1] = malloc(RX_BUFFER_SIZE, M_DEVBUF, M_WAITOK);
+ sc->sc_rxpos = 0;
+ sc->sc_rxcur = 0;
+ sc->sc_rxbuf = sc->sc_rxbuffer[sc->sc_rxcur];
+ if (!sc->sc_rxbuf)
+ panic("%s: Cannot allocate rx buffer memory",
+ sc->sc_dev.dv_xname);
+ }
+ tp->t_oproc = fcomstart;
+ tp->t_param = fcomparam;
+ tp->t_dev = dev;
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ SET(tp->t_state, TS_WOPEN);
+ ttychars(tp);
+ tp->t_cflag = TTYDEF_CFLAG;
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+
+ /*
+ * Initialize the termios status to the defaults. Add in the
+ * sticky bits from TIOCSFLAGS.
+ */
+ tp->t_ispeed = 0;
+ if (ISSET(sc->sc_hwflags, HW_FLAG_CONSOLE))
+ tp->t_ospeed = comcnspeed;
+ else
+ tp->t_ospeed = TTYDEF_SPEED;
+
+ fcomparam(tp, &tp->t_termios);
+ ttsetwater(tp);
+ } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
+ return EBUSY;
+ tp->t_state |= TS_CARR_ON;
+
+ return (*linesw[tp->t_line].l_open)(dev, tp);
+}
+
+int
+fcomclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag, mode;
+ struct proc *p;
+{
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return (0);
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+#ifdef DIAGNOSTIC
+ if (sc->sc_rxbuffer[0] == NULL)
+ panic("fcomclose: rx buffers not allocated");
+#endif /* DIAGNOSTIC */
+ free(sc->sc_rxbuffer[0], M_DEVBUF);
+ free(sc->sc_rxbuffer[1], M_DEVBUF);
+ sc->sc_rxbuffer[0] = NULL;
+ sc->sc_rxbuffer[1] = NULL;
+
+ return 0;
+}
+
+int
+fcomread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (*linesw[tp->t_line].l_read)(tp, uio, flag);
+}
+
+int
+fcomwrite(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (*linesw[tp->t_line].l_write)(tp, uio, flag);
+}
+
+#if 0
+int
+fcompoll(dev, events, p)
+ dev_t dev;
+ int events;
+ struct proc *p;
+{
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (*linesw[tp->t_line].l_poll)(tp, events, p));
+}
+#endif
+
+int
+fcomioctl(dev, cmd, data, flag, p)
+ dev_t dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(dev)];
+ struct tty *tp = sc->sc_tty;
+ int error;
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ switch (cmd) {
+ case TIOCGFLAGS:
+ *(int *)data = sc->sc_swflags;
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p, 0);
+ if (error)
+ return (error);
+ sc->sc_swflags = *(int *)data;
+ break;
+ }
+
+ return 0;
+}
+
+struct tty *
+fcomtty(dev)
+ dev_t dev;
+{
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(dev)];
+
+ return sc->sc_tty;
+}
+
+int
+fcomstop(struct tty *tp, int flag)
+{
+ return 0;
+}
+
+static void
+fcomstart(tp)
+ struct tty *tp;
+{
+ struct clist *cl;
+ int s, len;
+ u_char buf[64];
+ int loop;
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(tp->t_dev)];
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int timo;
+
+ s = spltty();
+ if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) {
+ (void)splx(s);
+ return;
+ }
+ tp->t_state |= TS_BUSY;
+ (void)splx(s);
+
+/* s = splserial();*/
+ /* wait for any pending transmission to finish */
+ timo = 100000;
+ while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
+ ;
+
+ s = splserial();
+ if (bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout_add(&tp->t_rstrt_to, 1);
+ (void)splx(s);
+ return;
+ }
+
+ (void)splx(s);
+
+ cl = &tp->t_outq;
+ len = q_to_b(cl, buf, 64);
+ for (loop = 0; loop < len; ++loop) {
+/* s = splserial();*/
+
+ bus_space_write_4(iot, ioh, UART_DATA, buf[loop]);
+
+ /* wait for this transmission to complete */
+ timo = 100000;
+ while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
+ ;
+/* (void)splx(s);*/
+ }
+ s = spltty();
+ tp->t_state &= ~TS_BUSY;
+ if (cl->c_cc) {
+ tp->t_state |= TS_TIMEOUT;
+ timeout_add(&tp->t_rstrt_to, 1);
+ }
+ if (cl->c_cc <= tp->t_lowat) {
+ if (tp->t_state & TS_ASLEEP) {
+ tp->t_state &= ~TS_ASLEEP;
+ wakeup(cl);
+ }
+ selwakeup(&tp->t_wsel);
+ }
+ (void)splx(s);
+}
+
+static int
+fcomparam(tp, t)
+ struct tty *tp;
+ struct termios *t;
+{
+ struct fcom_softc *sc = fcom_cd.cd_devs[minor(tp->t_dev)];
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int baudrate;
+ int h_ubrlcr;
+ int m_ubrlcr;
+ int l_ubrlcr;
+ int s;
+
+ /* check requested parameters */
+ if (t->c_ospeed < 0)
+ return (EINVAL);
+ if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
+ return (EINVAL);
+
+ switch (t->c_ospeed) {
+ case B1200:
+ case B2400:
+ case B4800:
+ case B9600:
+ case B19200:
+ case B38400:
+ baudrate = UART_BRD(dc21285_fclk, t->c_ospeed);
+ break;
+ default:
+ baudrate = UART_BRD(dc21285_fclk, 9600);
+ break;
+ }
+
+ l_ubrlcr = baudrate & 0xff;
+ m_ubrlcr = (baudrate >> 8) & 0xf;
+ h_ubrlcr = 0;
+
+ switch (ISSET(t->c_cflag, CSIZE)) {
+ case CS5:
+ h_ubrlcr |= UART_DATA_BITS_5;
+ break;
+ case CS6:
+ h_ubrlcr |= UART_DATA_BITS_6;
+ break;
+ case CS7:
+ h_ubrlcr |= UART_DATA_BITS_7;
+ break;
+ case CS8:
+ h_ubrlcr |= UART_DATA_BITS_8;
+ break;
+ }
+
+ if (ISSET(t->c_cflag, PARENB)) {
+ h_ubrlcr |= UART_PARITY_ENABLE;
+ if (ISSET(t->c_cflag, PARODD))
+ h_ubrlcr |= UART_ODD_PARITY;
+ else
+ h_ubrlcr |= UART_EVEN_PARITY;
+ }
+
+ if (ISSET(t->c_cflag, CSTOPB))
+ h_ubrlcr |= UART_STOP_BITS_2;
+
+ bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
+ bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
+ bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
+
+ s = splserial();
+
+ sc->sc_l_ubrlcr = l_ubrlcr;
+ sc->sc_m_ubrlcr = m_ubrlcr;
+ sc->sc_h_ubrlcr = h_ubrlcr;
+
+ /*
+ * For the console, always force CLOCAL and !HUPCL, so that the port
+ * is always active.
+ */
+ if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
+ ISSET(sc->sc_hwflags, HW_FLAG_CONSOLE)) {
+ SET(t->c_cflag, CLOCAL);
+ CLR(t->c_cflag, HUPCL);
+ }
+
+ /* and copy to tty */
+ tp->t_ispeed = 0;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+
+ bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
+ bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
+ bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
+
+ (void)splx(s);
+
+ return (0);
+}
+
+static int softint_scheduled = 0;
+
+static void
+fcom_softintr(arg)
+ void *arg;
+{
+ struct fcom_softc *sc = arg;
+ struct tty *tp = sc->sc_tty;
+ int s;
+ int loop;
+ int len;
+ char *ptr;
+
+ s = spltty();
+ ptr = sc->sc_rxbuf;
+ len = sc->sc_rxpos;
+ sc->sc_rxcur ^= 1;
+ sc->sc_rxbuf = sc->sc_rxbuffer[sc->sc_rxcur];
+ sc->sc_rxpos = 0;
+ (void)splx(s);
+
+ for (loop = 0; loop < len; ++loop)
+ (*linesw[tp->t_line].l_rint)(ptr[loop], tp);
+ softint_scheduled = 0;
+}
+
+#if 0
+static int
+fcom_txintr(arg)
+ void *arg;
+{
+/* struct fcom_softc *sc = arg;*/
+
+ printf("fcom_txintr()\n");
+ return(0);
+}
+#endif
+
+static int
+fcom_rxintr(arg)
+ void *arg;
+{
+ struct fcom_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ struct tty *tp = sc->sc_tty;
+ int status;
+ int byte;
+
+ do {
+ status = bus_space_read_4(iot, ioh, UART_FLAGS);
+ if ((status & UART_RX_FULL))
+ break;
+ byte = bus_space_read_4(iot, ioh, UART_DATA);
+ status = bus_space_read_4(iot, ioh, UART_RX_STAT);
+#if defined(DDB) && DDB_KEYCODE > 0
+ /*
+ * Temporary hack so that I can force the kernel into
+ * the debugger via the serial port
+ */
+ if (byte == DDB_KEYCODE) Debugger();
+#endif
+ if (tp && (tp->t_state & TS_ISOPEN))
+ if (sc->sc_rxpos < RX_BUFFER_SIZE) {
+ sc->sc_rxbuf[sc->sc_rxpos++] = byte;
+ if (!softint_scheduled) {
+ softint_scheduled = 1;
+ timeout_add(&sc->sc_softintr_ch, 1);
+ }
+ }
+ } while (1);
+ return(0);
+}
+
+#if 0
+void
+fcom_iflush(sc)
+ struct fcom_softc *sc;
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ /* flush any pending I/O */
+ while (!ISSET(bus_space_read_4(iot, ioh, UART_FLAGS), UART_RX_FULL))
+ (void) bus_space_read_4(iot, ioh, UART_DATA);
+}
+#endif
+
+/*
+ * Following are all routines needed for COM to act as console
+ */
+
+#if 0
+void
+fcomcnprobe(cp)
+ struct consdev *cp;
+{
+ int major;
+
+ /* Serial console is always present so no probe */
+
+ /* locate the major number */
+ major = cdevsw_lookup_major(&fcom_cdevsw);
+
+ /* initialize required fields */
+ cp->cn_dev = makedev(major, CONUNIT);
+ cp->cn_pri = CN_REMOTE; /* Force a serial port console */
+}
+
+void
+fcomcninit(cp)
+ struct consdev *cp;
+{
+ fcomconstag = &fcomcons_bs_tag;
+
+ if (bus_space_map(fcomconstag, DC21285_ARMCSR_BASE, DC21285_ARMCSR_SIZE, 0, &fcomconsioh))
+ panic("fcomcninit: mapping failed");
+
+ fcominitcons(fcomconstag, fcomconsioh);
+}
+#endif
+
+struct consdev fcomcons = {
+ NULL, NULL, fcomcngetc, fcomcnputc, fcomcnpollc, NULL,
+ NODEV, CN_NORMAL
+};
+
+int
+fcomcnattach(iobase, rate, cflag)
+ u_int iobase;
+ int rate;
+ tcflag_t cflag;
+{
+#if 0
+ static struct consdev fcomcons = {
+ NULL, NULL, fcomcngetc, fcomcnputc, fcomcnpollc, NULL,
+ NULL, NULL, NODEV, CN_NORMAL
+ };
+#endif
+
+ fcomconstag = &fcomcons_bs_tag;
+
+ if (bus_space_map(fcomconstag, iobase, DC21285_ARMCSR_SIZE,
+ 0, &fcomconsioh))
+ panic("fcomcninit: mapping failed");
+
+ fcominit(fcomconstag, fcomconsioh, rate, cflag);
+
+ cn_tab = &fcomcons;
+
+/* comcnspeed = rate;
+ comcnmode = cflag;*/
+ return (0);
+}
+
+int
+fcomcndetach(void)
+{
+ bus_space_unmap(fcomconstag, fcomconsioh, DC21285_ARMCSR_SIZE);
+
+ cn_tab = NULL;
+ return (0);
+}
+
+/*
+ * Initialize UART to known state.
+ */
+void
+fcominit(iot, ioh, rate, mode)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ int rate;
+ int mode;
+{
+ int baudrate;
+ int h_ubrlcr;
+ int m_ubrlcr;
+ int l_ubrlcr;
+
+ switch (rate) {
+ case B1200:
+ case B2400:
+ case B4800:
+ case B9600:
+ case B19200:
+ case B38400:
+ baudrate = UART_BRD(dc21285_fclk, rate);
+ break;
+ default:
+ baudrate = UART_BRD(dc21285_fclk, 9600);
+ break;
+ }
+
+ h_ubrlcr = 0;
+ switch (mode & CSIZE) {
+ case CS5:
+ h_ubrlcr |= UART_DATA_BITS_5;
+ break;
+ case CS6:
+ h_ubrlcr |= UART_DATA_BITS_6;
+ break;
+ case CS7:
+ h_ubrlcr |= UART_DATA_BITS_7;
+ break;
+ case CS8:
+ h_ubrlcr |= UART_DATA_BITS_8;
+ break;
+ }
+
+ if (mode & PARENB)
+ h_ubrlcr |= UART_PARITY_ENABLE;
+ if (mode & PARODD)
+ h_ubrlcr |= UART_ODD_PARITY;
+ else
+ h_ubrlcr |= UART_EVEN_PARITY;
+
+ if (mode & CSTOPB)
+ h_ubrlcr |= UART_STOP_BITS_2;
+
+ m_ubrlcr = (baudrate >> 8) & 0xf;
+ l_ubrlcr = baudrate & 0xff;
+
+ bus_space_write_4(iot, ioh, UART_L_UBRLCR, l_ubrlcr);
+ bus_space_write_4(iot, ioh, UART_M_UBRLCR, m_ubrlcr);
+ bus_space_write_4(iot, ioh, UART_H_UBRLCR, h_ubrlcr);
+}
+#if 0
+/*
+ * Set UART for console use. Do normal init, then enable interrupts.
+ */
+void
+fcominitcons(iot, ioh)
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+{
+ int s = splserial();
+
+ fcominit(iot, ioh, comcnspeed, comcnmode);
+
+ delay(10000);
+
+ (void)splx(s);
+}
+#endif
+
+int
+fcomcngetc(dev)
+ dev_t dev;
+{
+ int s = splserial();
+ bus_space_tag_t iot = fcomconstag;
+ bus_space_handle_t ioh = fcomconsioh;
+ u_char stat, c;
+
+ while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_RX_FULL) != 0)
+ ;
+ c = bus_space_read_4(iot, ioh, UART_DATA);
+ stat = bus_space_read_4(iot, ioh, UART_RX_STAT);
+ (void)splx(s);
+#if defined(DDB) && DDB_KEYCODE > 0
+ /*
+ * Temporary hack so that I can force the kernel into
+ * the debugger via the serial port
+ */
+ if (c == DDB_KEYCODE) Debugger();
+#endif
+
+ return (c);
+}
+
+/*
+ * Console kernel output character routine.
+ */
+void
+fcomcnputc(dev, c)
+ dev_t dev;
+ int c;
+{
+ int s = splserial();
+ bus_space_tag_t iot = fcomconstag;
+ bus_space_handle_t ioh = fcomconsioh;
+ int timo;
+
+ /* wait for any pending transmission to finish */
+ timo = 50000;
+ while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
+ ;
+ bus_space_write_4(iot, ioh, UART_DATA, c);
+
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while ((bus_space_read_4(iot, ioh, UART_FLAGS) & UART_TX_BUSY) && --timo)
+ ;
+ /* Clear interrupt status here */
+ (void)splx(s);
+}
+
+void
+fcomcnpollc(dev, on)
+ dev_t dev;
+ int on;
+{
+}
diff --git a/sys/arch/arm/footbridge/footbridge_com_io.c b/sys/arch/arm/footbridge/footbridge_com_io.c
new file mode 100644
index 00000000000..32f60020210
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_com_io.c
@@ -0,0 +1,211 @@
+/* $OpenBSD: footbridge_com_io.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_com_io.c,v 1.4 2002/09/27 15:35:44 provos Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This file provides the bus space tag for the footbridge serial console
+ */
+
+/*
+ * bus_space I/O functions for mainbus
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+
+/* Proto types for all the bus_space structure functions */
+
+bs_protos(fcomcons);
+bs_protos(generic);
+bs_protos(bs_notimpl);
+
+/* Declare the fcomcons bus space tag */
+
+struct bus_space fcomcons_bs_tag = {
+ /* cookie */
+ NULL,
+
+ /* mapping/unmapping */
+ fcomcons_bs_map,
+ fcomcons_bs_unmap,
+ fcomcons_bs_subregion,
+
+ /* allocation/deallocation */
+ fcomcons_bs_alloc,
+ fcomcons_bs_free,
+
+ /* get kernel virtual address */
+ 0, /* never used */
+
+ /* Mmap bus space for user */
+ bs_notimpl_bs_mmap,
+
+ /* barrier */
+ fcomcons_bs_barrier,
+
+ /* read (single) */
+ bs_notimpl_bs_r_1,
+ bs_notimpl_bs_r_2,
+ generic_bs_r_4,
+ bs_notimpl_bs_r_8,
+
+ /* read multiple */
+ bs_notimpl_bs_rm_1,
+ bs_notimpl_bs_rm_2,
+ bs_notimpl_bs_rm_4,
+ bs_notimpl_bs_rm_8,
+
+ /* read region */
+ bs_notimpl_bs_rr_1,
+ bs_notimpl_bs_rr_2,
+ bs_notimpl_bs_rr_4,
+ bs_notimpl_bs_rr_8,
+
+ /* write (single) */
+ bs_notimpl_bs_w_1,
+ bs_notimpl_bs_w_2,
+ generic_bs_w_4,
+ bs_notimpl_bs_w_8,
+
+ /* write multiple */
+ bs_notimpl_bs_wm_1,
+ bs_notimpl_bs_wm_2,
+ bs_notimpl_bs_wm_4,
+ bs_notimpl_bs_wm_8,
+
+ /* write region */
+ bs_notimpl_bs_wr_1,
+ bs_notimpl_bs_wr_2,
+ bs_notimpl_bs_wr_4,
+ bs_notimpl_bs_wr_8,
+
+ bs_notimpl_bs_sm_1,
+ bs_notimpl_bs_sm_2,
+ bs_notimpl_bs_sm_4,
+ bs_notimpl_bs_sm_8,
+
+ /* set region */
+ bs_notimpl_bs_sr_1,
+ bs_notimpl_bs_sr_2,
+ bs_notimpl_bs_sr_4,
+ bs_notimpl_bs_sr_8,
+
+ /* copy */
+ bs_notimpl_bs_c_1,
+ bs_notimpl_bs_c_2,
+ bs_notimpl_bs_c_4,
+ bs_notimpl_bs_c_8,
+};
+
+/* bus space functions */
+
+int
+fcomcons_bs_map(t, bpa, size, cacheable, bshp)
+ void *t;
+ bus_addr_t bpa;
+ bus_size_t size;
+ int cacheable;
+ bus_space_handle_t *bshp;
+{
+ /*
+ * Temporary implementation as all I/O is already mapped etc.
+ *
+ * Eventually this function will do the mapping check for multiple maps
+ */
+ *bshp = bpa;
+ return(0);
+ }
+
+int
+fcomcons_bs_alloc(t, rstart, rend, size, alignment, boundary, cacheable,
+ bpap, bshp)
+ void *t;
+ bus_addr_t rstart, rend;
+ bus_size_t size, alignment, boundary;
+ int cacheable;
+ bus_addr_t *bpap;
+ bus_space_handle_t *bshp;
+{
+ panic("fcomcons_alloc(): Help!");
+}
+
+
+void
+fcomcons_bs_unmap(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ /*
+ * Temporary implementation
+ */
+}
+
+void
+fcomcons_bs_free(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+
+ panic("fcomcons_free(): Help!");
+ /* fcomcons_unmap() does all that we need to do. */
+/* fcomcons_unmap(t, bsh, size);*/
+}
+
+int
+fcomcons_bs_subregion(t, bsh, offset, size, nbshp)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, size;
+ bus_space_handle_t *nbshp;
+{
+
+ *nbshp = bsh + offset;
+ return (0);
+}
+
+void
+fcomcons_bs_barrier(t, bsh, offset, len, flags)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, len;
+ int flags;
+{
+}
+
+/* End of footbridge_com_io.c */
diff --git a/sys/arch/arm/footbridge/footbridge_intr.h b/sys/arch/arm/footbridge/footbridge_intr.h
new file mode 100644
index 00000000000..2a9888e7e1b
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_intr.h
@@ -0,0 +1,215 @@
+/* $OpenBSD: footbridge_intr.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_intr.h,v 1.4 2003/01/03 00:56:00 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FOOTBRIDGE_INTR_H_
+#define _FOOTBRIDGE_INTR_H_
+
+#include <arm/armreg.h>
+
+/* Define the various Interrupt Priority Levels */
+
+/* Hardware Interrupt Priority Levels are not mutually exclusive. */
+
+#define IPL_NONE 0 /* nothing */
+#define IPL_SOFT 1 /* generic soft interrupts */
+#define IPL_SOFTCLOCK 2 /* clock software interrupts */
+#define IPL_SOFTNET 3 /* network software interrupts */
+#define IPL_BIO 4 /* block I/O */
+#define IPL_NET 5 /* network */
+#define IPL_SOFTSERIAL 6 /* serial software interrupts */
+#define IPL_TTY 7 /* terminal */
+#define IPL_VM 8 /* memory allocation */
+#define IPL_AUDIO 9 /* audio */
+#define IPL_CLOCK 10 /* clock */
+#define IPL_STATCLOCK 11 /* statclock */
+#define IPL_HIGH 12 /* everything */
+#define IPL_SERIAL 13 /* serial */
+
+#define NIPL 14
+
+#define IST_UNUSABLE -1 /* interrupt cannot be used */
+#define IST_NONE 0 /* none (dummy) */
+#define IST_PULSE 1 /* pulsed */
+#define IST_EDGE 2 /* edge-triggered */
+#define IST_LEVEL 3 /* level-triggered */
+
+#define __NEWINTR /* enables new hooks in cpu_fork()/cpu_switch() */
+
+#define ARM_IRQ_HANDLER _C_LABEL(footbridge_intr_dispatch)
+
+#ifndef _LOCORE
+#include <arm/cpufunc.h>
+
+#include <arm/footbridge/dc21285mem.h>
+#include <arm/footbridge/dc21285reg.h>
+
+#define INT_SWMASK \
+ ((1U << IRQ_SOFTINT) | (1U << IRQ_RESERVED0) | \
+ (1U << IRQ_RESERVED1) | (1U << IRQ_RESERVED2))
+#define ICU_INT_HWMASK (0xffffffff & ~(INT_SWMASK | (1U << IRQ_RESERVED3)))
+
+/* only call this with interrupts off */
+static __inline void __attribute__((__unused__))
+ footbridge_set_intrmask(void)
+{
+ extern __volatile uint32_t intr_enabled;
+ /* fetch once so we write the same number to both registers */
+ uint32_t tmp = intr_enabled & ICU_INT_HWMASK;
+
+ ((__volatile uint32_t*)(DC21285_ARMCSR_VBASE))[IRQ_ENABLE_SET>>2] = tmp;
+ ((__volatile uint32_t*)(DC21285_ARMCSR_VBASE))[IRQ_ENABLE_CLEAR>>2] = ~tmp;
+}
+
+static __inline void __attribute__((__unused__))
+footbridge_splx(int newspl)
+{
+ extern __volatile uint32_t intr_enabled;
+ extern __volatile int current_spl_level;
+ extern __volatile int footbridge_ipending;
+ extern void footbridge_do_pending(void);
+ int oldirqstate, hwpend;
+
+ current_spl_level = newspl;
+
+ hwpend = (footbridge_ipending & ICU_INT_HWMASK) & ~newspl;
+ if (hwpend != 0) {
+ oldirqstate = disable_interrupts(I32_bit);
+ intr_enabled |= hwpend;
+ footbridge_set_intrmask();
+ restore_interrupts(oldirqstate);
+ }
+
+ if ((footbridge_ipending & INT_SWMASK) & ~newspl)
+ footbridge_do_pending();
+}
+
+static __inline int __attribute__((__unused__))
+footbridge_splraise(int ipl)
+{
+ extern __volatile int current_spl_level;
+ extern int footbridge_imask[];
+ int old;
+
+ old = current_spl_level;
+ current_spl_level |= footbridge_imask[ipl];
+
+ return (old);
+}
+
+static __inline int __attribute__((__unused__))
+footbridge_spllower(int ipl)
+{
+ extern __volatile int current_spl_level;
+ extern int footbridge_imask[];
+ int old = current_spl_level;
+
+ footbridge_splx(footbridge_imask[ipl]);
+ return(old);
+}
+
+/* should only be defined in footbridge_intr.c */
+#if !defined(ARM_SPL_NOINLINE)
+
+#define splx(newspl) footbridge_splx(newspl)
+#define _spllower(ipl) footbridge_spllower(ipl)
+#define _splraise(ipl) footbridge_splraise(ipl)
+void _setsoftintr(int);
+
+#else
+
+int _splraise(int);
+int _spllower(int);
+void splx(int);
+void _setsoftintr(int);
+
+#endif /* ! ARM_SPL_NOINLINE */
+
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <machine/irqhandler.h>
+
+#define splsoft() _splraise(IPL_SOFT)
+#define splsoftclock() _splraise(IPL_SOFTCLOCK)
+#define splsoftnet() _splraise(IPL_SOFTNET)
+#define splbio() _splraise(IPL_BIO)
+#define splnet() _splraise(IPL_NET)
+#define splsoftserial() _splraise(IPL_SOFTSERIAL)
+#define spltty() _splraise(IPL_TTY)
+#define spllpt() spltty()
+#define splvm() _splraise(IPL_VM)
+#define splimp() _splraise(IPL_VM)
+#define splaudio() _splraise(IPL_AUDIO)
+#define splclock() _splraise(IPL_CLOCK)
+#define splstatclock() _splraise(IPL_STATCLOCK)
+#define splhigh() _splraise(IPL_HIGH)
+#define splserial() _splraise(IPL_SERIAL)
+
+#define spl0() (void)_spllower(IPL_NONE)
+#define spllowersoftclock() (void)_spllower(IPL_SOFTCLOCK)
+
+#define splsched() splhigh()
+#define spllock() splhigh()
+
+/* Use generic software interrupt support. */
+#include <arm/softintr.h>
+
+/* footbridge has 32 interrupt lines */
+#define NIRQ 32
+
+struct intrhand {
+ TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */
+ int (*ih_func)(void *); /* handler */
+ void *ih_arg; /* arg for handler */
+ int ih_ipl; /* IPL_* */
+ int ih_irq; /* IRQ number */
+};
+
+#define IRQNAMESIZE sizeof("footbridge irq 31")
+
+struct intrq {
+ TAILQ_HEAD(, intrhand) iq_list; /* handler list */
+ struct evcnt iq_ev; /* event counter */
+ int iq_mask; /* IRQs to mask while handling */
+ int iq_levels; /* IPL_*'s this IRQ has */
+ int iq_ist; /* share type */
+ char iq_name[IRQNAMESIZE]; /* interrupt name */
+};
+
+#endif /* _LOCORE */
+
+#endif /* _FOOTBRIDGE_INTR_H */
diff --git a/sys/arch/arm/footbridge/footbridge_io.c b/sys/arch/arm/footbridge/footbridge_io.c
new file mode 100644
index 00000000000..5af52cb7591
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_io.c
@@ -0,0 +1,321 @@
+/* $OpenBSD: footbridge_io.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_io.c,v 1.6 2002/04/12 19:12:31 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1997 Causality Limited
+ * Copyright (c) 1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * bus_space I/O functions for footbridge
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+#include <arm/footbridge/footbridge.h>
+#include <arm/footbridge/dc21285mem.h>
+#include <uvm/uvm_extern.h>
+
+/* Proto types for all the bus_space structure functions */
+
+bs_protos(footbridge);
+bs_protos(generic);
+bs_protos(generic_armv4);
+bs_protos(bs_notimpl);
+bs_map_proto(footbridge_mem);
+bs_unmap_proto(footbridge_mem);
+
+/* Declare the footbridge bus space tag */
+
+struct bus_space footbridge_bs_tag = {
+ /* cookie */
+ (void *) 0, /* Base address */
+
+ /* mapping/unmapping */
+ footbridge_bs_map,
+ footbridge_bs_unmap,
+ footbridge_bs_subregion,
+
+ /* allocation/deallocation */
+ footbridge_bs_alloc,
+ footbridge_bs_free,
+
+ /* get kernel virtual address */
+ footbridge_bs_vaddr,
+
+ /* Mmap bus space for user */
+ bs_notimpl_bs_mmap,
+
+ /* barrier */
+ footbridge_bs_barrier,
+
+ /* read (single) */
+ generic_bs_r_1,
+ generic_armv4_bs_r_2,
+ generic_bs_r_4,
+ bs_notimpl_bs_r_8,
+
+ /* read multiple */
+ generic_bs_rm_1,
+ generic_armv4_bs_rm_2,
+ generic_bs_rm_4,
+ bs_notimpl_bs_rm_8,
+
+ /* read region */
+ bs_notimpl_bs_rr_1,
+ generic_armv4_bs_rr_2,
+ generic_bs_rr_4,
+ bs_notimpl_bs_rr_8,
+
+ /* write (single) */
+ generic_bs_w_1,
+ generic_armv4_bs_w_2,
+ generic_bs_w_4,
+ bs_notimpl_bs_w_8,
+
+ /* write multiple */
+ generic_bs_wm_1,
+ generic_armv4_bs_wm_2,
+ generic_bs_wm_4,
+ bs_notimpl_bs_wm_8,
+
+ /* write region */
+ bs_notimpl_bs_wr_1,
+ generic_armv4_bs_wr_2,
+ generic_bs_wr_4,
+ bs_notimpl_bs_wr_8,
+
+ /* set multiple */
+ bs_notimpl_bs_sm_1,
+ bs_notimpl_bs_sm_2,
+ bs_notimpl_bs_sm_4,
+ bs_notimpl_bs_sm_8,
+
+ /* set region */
+ bs_notimpl_bs_sr_1,
+ generic_armv4_bs_sr_2,
+ bs_notimpl_bs_sr_4,
+ bs_notimpl_bs_sr_8,
+
+ /* copy */
+ bs_notimpl_bs_c_1,
+ generic_armv4_bs_c_2,
+ bs_notimpl_bs_c_4,
+ bs_notimpl_bs_c_8,
+};
+
+void footbridge_create_io_bs_tag(t, cookie)
+ struct bus_space *t;
+ void *cookie;
+{
+ *t = footbridge_bs_tag;
+ t->bs_cookie = cookie;
+}
+
+void footbridge_create_mem_bs_tag(t, cookie)
+ struct bus_space *t;
+ void *cookie;
+{
+ *t = footbridge_bs_tag;
+ t->bs_map = footbridge_mem_bs_map;
+ t->bs_unmap = footbridge_mem_bs_unmap;
+ t->bs_cookie = cookie;
+}
+
+/* bus space functions */
+
+int
+footbridge_bs_map(t, bpa, size, cacheable, bshp)
+ void *t;
+ bus_addr_t bpa;
+ bus_size_t size;
+ int cacheable;
+ bus_space_handle_t *bshp;
+{
+ /*
+ * The whole 64K of PCI space is always completely mapped during
+ * boot.
+ *
+ * Eventually this function will do the mapping check overlapping /
+ * multiple mappings.
+ */
+
+ /* The cookie is the base address for the I/O area */
+ *bshp = bpa + (bus_addr_t)t;
+ return(0);
+}
+
+int
+footbridge_mem_bs_map(t, bpa, size, cacheable, bshp)
+ void *t;
+ bus_addr_t bpa;
+ bus_size_t size;
+ int cacheable;
+ bus_space_handle_t *bshp;
+{
+ bus_addr_t startpa, endpa;
+ vaddr_t va;
+
+ /* Round the allocation to page boundries */
+ startpa = trunc_page(bpa);
+ endpa = round_page(bpa + size);
+
+ /*
+ * Check for mappings below 1MB as we have this space already
+ * mapped. In practice it is only the VGA hole that takes
+ * advantage of this.
+ */
+ if (endpa < DC21285_PCI_ISA_MEM_VSIZE) {
+ /* Store the bus space handle */
+ *bshp = DC21285_PCI_ISA_MEM_VBASE + bpa;
+ return 0;
+ }
+
+ /*
+ * Eventually this function will do the mapping check for overlapping /
+ * multiple mappings
+ */
+
+ va = uvm_km_valloc(kernel_map, endpa - startpa);
+ if (va == 0)
+ return ENOMEM;
+
+ /* Store the bus space handle */
+ *bshp = va + (bpa & PGOFSET);
+
+ /* Now map the pages */
+ /* The cookie is the physical base address for the I/O area */
+ while (startpa < endpa) {
+ pmap_enter(pmap_kernel(), va, (bus_addr_t)t + startpa,
+ VM_PROT_READ | VM_PROT_WRITE, 0);
+ va += PAGE_SIZE;
+ startpa += PAGE_SIZE;
+ }
+ pmap_update(pmap_kernel());
+
+/* if (bpa >= DC21285_PCI_MEM_VSIZE && bpa != DC21285_ARMCSR_VBASE)
+ panic("footbridge_bs_map: Address out of range (%08lx)", bpa);
+*/
+ return(0);
+}
+
+int
+footbridge_bs_alloc(t, rstart, rend, size, alignment, boundary, cacheable,
+ bpap, bshp)
+ void *t;
+ bus_addr_t rstart, rend;
+ bus_size_t size, alignment, boundary;
+ int cacheable;
+ bus_addr_t *bpap;
+ bus_space_handle_t *bshp;
+{
+ panic("footbridge_alloc(): Help!");
+}
+
+
+void
+footbridge_bs_unmap(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ /*
+ * Temporary implementation
+ */
+}
+
+void
+footbridge_mem_bs_unmap(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ vaddr_t startva, endva;
+
+ /*
+ * Check for mappings below 1MB as we have this space permenantly
+ * mapped. In practice it is only the VGA hole that takes
+ * advantage of this.
+ */
+ if (bsh >= DC21285_PCI_ISA_MEM_VBASE
+ && bsh < (DC21285_PCI_ISA_MEM_VBASE + DC21285_PCI_ISA_MEM_VSIZE)) {
+ return;
+ }
+
+ startva = trunc_page(bsh);
+ endva = round_page(bsh + size);
+
+ uvm_km_free(kernel_map, startva, endva - startva);
+}
+
+void
+footbridge_bs_free(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+
+ panic("footbridge_free(): Help!");
+ /* footbridge_bs_unmap() does all that we need to do. */
+/* footbridge_bs_unmap(t, bsh, size);*/
+}
+
+int
+footbridge_bs_subregion(t, bsh, offset, size, nbshp)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, size;
+ bus_space_handle_t *nbshp;
+{
+
+ *nbshp = bsh + (offset << ((int)t));
+ return (0);
+}
+
+void *
+footbridge_bs_vaddr(t, bsh)
+ void *t;
+ bus_space_handle_t bsh;
+{
+
+ return ((void *)bsh);
+}
+
+void
+footbridge_bs_barrier(t, bsh, offset, len, flags)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, len;
+ int flags;
+{
+}
diff --git a/sys/arch/arm/footbridge/footbridge_irqhandler.c b/sys/arch/arm/footbridge/footbridge_irqhandler.c
new file mode 100644
index 00000000000..b3c1cf57341
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_irqhandler.c
@@ -0,0 +1,482 @@
+/* $OpenBSD: footbridge_irqhandler.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_irqhandler.c,v 1.9 2003/06/16 20:00:57 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ARM_SPL_NOINLINE
+#define ARM_SPL_NOINLINE
+#endif
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <uvm/uvm_extern.h>
+
+#include <machine/intr.h>
+#include <machine/cpu.h>
+#include <arm/footbridge/dc21285mem.h>
+#include <arm/footbridge/dc21285reg.h>
+
+#include <dev/pci/pcivar.h>
+
+#include "isa.h"
+#if NISA > 0
+#include <dev/isa/isavar.h>
+#endif
+
+/* Interrupt handler queues. */
+static struct intrq footbridge_intrq[NIRQ];
+
+/* Interrupts to mask at each level. */
+int footbridge_imask[NIPL];
+
+/* Software copy of the IRQs we have enabled. */
+__volatile uint32_t intr_enabled;
+
+/* Current interrupt priority level */
+__volatile int current_spl_level;
+
+/* Interrupts pending */
+__volatile int footbridge_ipending;
+
+void footbridge_intr_dispatch(struct clockframe *frame);
+
+const struct evcnt *footbridge_pci_intr_evcnt __P((void *, pci_intr_handle_t));
+
+void footbridge_do_pending(void);
+
+static const uint32_t si_to_irqbit[SI_NQUEUES] =
+ { IRQ_SOFTINT,
+ IRQ_RESERVED0,
+ IRQ_RESERVED1,
+ IRQ_RESERVED2 };
+
+#define SI_TO_IRQBIT(si) (1U << si_to_irqbit[(si)])
+
+/*
+ * Map a software interrupt queue to an interrupt priority level.
+ */
+static const int si_to_ipl[SI_NQUEUES] = {
+ IPL_SOFT, /* SI_SOFT */
+ IPL_SOFTCLOCK, /* SI_SOFTCLOCK */
+ IPL_SOFTNET, /* SI_SOFTNET */
+ IPL_SOFTSERIAL, /* SI_SOFTSERIAL */
+};
+
+const struct evcnt *
+footbridge_pci_intr_evcnt(pcv, ih)
+ void *pcv;
+ pci_intr_handle_t ih;
+{
+ /* XXX check range is valid */
+#if NISA > 0
+ if (ih >= 0x80 && ih <= 0x8f) {
+ return isa_intr_evcnt(NULL, (ih & 0x0f));
+ }
+#endif
+ return &footbridge_intrq[ih].iq_ev;
+}
+
+static __inline void
+footbridge_enable_irq(int irq)
+{
+ intr_enabled |= (1U << irq);
+
+ footbridge_set_intrmask();
+}
+
+static __inline void
+footbridge_disable_irq(int irq)
+{
+ intr_enabled &= ~(1U << irq);
+ footbridge_set_intrmask();
+}
+
+/*
+ * NOTE: This routine must be called with interrupts disabled in the CPSR.
+ */
+static void
+footbridge_intr_calculate_masks(void)
+{
+ struct intrq *iq;
+ struct intrhand *ih;
+ int irq, ipl;
+
+ /* First, figure out which IPLs each IRQ has. */
+ for (irq = 0; irq < NIRQ; irq++) {
+ int levels = 0;
+ iq = &footbridge_intrq[irq];
+ footbridge_disable_irq(irq);
+ for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
+ ih = TAILQ_NEXT(ih, ih_list))
+ levels |= (1U << ih->ih_ipl);
+ iq->iq_levels = levels;
+ }
+
+ /* Next, figure out which IRQs are used by each IPL. */
+ for (ipl = 0; ipl < NIPL; ipl++) {
+ int irqs = 0;
+ for (irq = 0; irq < NIRQ; irq++) {
+ if (footbridge_intrq[irq].iq_levels & (1U << ipl))
+ irqs |= (1U << irq);
+ }
+ footbridge_imask[ipl] = irqs;
+ }
+
+ /* IPL_NONE must open up all interrupts */
+ footbridge_imask[IPL_NONE] = 0;
+
+ /*
+ * Initialize the soft interrupt masks to block themselves.
+ */
+ footbridge_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFT);
+ footbridge_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTCLOCK);
+ footbridge_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTNET);
+ footbridge_imask[IPL_SOFTSERIAL] = SI_TO_IRQBIT(SI_SOFTSERIAL);
+
+ footbridge_imask[IPL_SOFTCLOCK] |= footbridge_imask[IPL_SOFT];
+ footbridge_imask[IPL_SOFTNET] |= footbridge_imask[IPL_SOFTCLOCK];
+
+ /*
+ * Enforce a heirarchy that gives "slow" device (or devices with
+ * limited input buffer space/"real-time" requirements) a better
+ * chance at not dropping data.
+ */
+ footbridge_imask[IPL_BIO] |= footbridge_imask[IPL_SOFTNET];
+ footbridge_imask[IPL_NET] |= footbridge_imask[IPL_BIO];
+ footbridge_imask[IPL_SOFTSERIAL] |= footbridge_imask[IPL_NET];
+
+ footbridge_imask[IPL_TTY] |= footbridge_imask[IPL_SOFTSERIAL];
+
+ /*
+ * splvm() blocks all interrupts that use the kernel memory
+ * allocation facilities.
+ */
+ footbridge_imask[IPL_VM] |= footbridge_imask[IPL_TTY];
+
+ /*
+ * Audio devices are not allowed to perform memory allocation
+ * in their interrupt routines, and they have fairly "real-time"
+ * requirements, so give them a high interrupt priority.
+ */
+ footbridge_imask[IPL_AUDIO] |= footbridge_imask[IPL_VM];
+
+ /*
+ * splclock() must block anything that uses the scheduler.
+ */
+ footbridge_imask[IPL_CLOCK] |= footbridge_imask[IPL_AUDIO];
+
+ /*
+ * footbridge has seperate statclock.
+ */
+ footbridge_imask[IPL_STATCLOCK] |= footbridge_imask[IPL_CLOCK];
+
+ /*
+ * splhigh() must block "everything".
+ */
+ footbridge_imask[IPL_HIGH] |= footbridge_imask[IPL_STATCLOCK];
+
+ /*
+ * XXX We need serial drivers to run at the absolute highest priority
+ * in order to avoid overruns, so serial > high.
+ */
+ footbridge_imask[IPL_SERIAL] |= footbridge_imask[IPL_HIGH];
+
+ /*
+ * Calculate the ipl level to go to when handling this interrupt
+ */
+ for (irq = 0; irq < NIRQ; irq++) {
+ int irqs = (1U << irq);
+ iq = &footbridge_intrq[irq];
+ if (TAILQ_FIRST(&iq->iq_list) != NULL)
+ footbridge_enable_irq(irq);
+ for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
+ ih = TAILQ_NEXT(ih, ih_list))
+ irqs |= footbridge_imask[ih->ih_ipl];
+ iq->iq_mask = irqs;
+ }
+}
+
+int
+_splraise(int ipl)
+{
+ return (footbridge_splraise(ipl));
+}
+
+/* this will always take us to the ipl passed in */
+void
+splx(int new)
+{
+ footbridge_splx(new);
+}
+
+int
+_spllower(int ipl)
+{
+ return (footbridge_spllower(ipl));
+}
+
+__inline void
+footbridge_do_pending(void)
+{
+#if 0
+ static __cpu_simple_lock_t processing = __SIMPLELOCK_UNLOCKED;
+#else
+ static int processing;
+#endif
+ uint32_t new, oldirqstate;
+
+#if 0
+ if (__cpu_simple_lock_try(&processing) == 0)
+ return;
+#else
+ if (processing)
+ return;
+ processing = 1;
+#endif
+
+ new = current_spl_level;
+
+ oldirqstate = disable_interrupts(I32_bit);
+
+#define DO_SOFTINT(si) \
+ if ((footbridge_ipending & ~new) & SI_TO_IRQBIT(si)) { \
+ footbridge_ipending &= ~SI_TO_IRQBIT(si); \
+ current_spl_level |= footbridge_imask[si_to_ipl[(si)]]; \
+ restore_interrupts(oldirqstate); \
+ softintr_dispatch(si); \
+ oldirqstate = disable_interrupts(I32_bit); \
+ current_spl_level = new; \
+ }
+ DO_SOFTINT(SI_SOFTSERIAL);
+ DO_SOFTINT(SI_SOFTNET);
+ DO_SOFTINT(SI_SOFTCLOCK);
+ DO_SOFTINT(SI_SOFT);
+
+#if 0
+ __cpu_simple_unlock(&processing);
+#else
+ processing = 0;
+#endif
+
+ restore_interrupts(oldirqstate);
+}
+
+
+/* called from splhigh, so the matching splx will set the interrupt up.*/
+void
+_setsoftintr(int si)
+{
+ int oldirqstate;
+
+ oldirqstate = disable_interrupts(I32_bit);
+ footbridge_ipending |= SI_TO_IRQBIT(si);
+ restore_interrupts(oldirqstate);
+
+ /* Process unmasked pending soft interrupts. */
+ if ((footbridge_ipending & INT_SWMASK) & ~current_spl_level)
+ footbridge_do_pending();
+}
+
+void
+footbridge_intr_init(void)
+{
+ struct intrq *iq;
+ int i;
+
+ intr_enabled = 0;
+ current_spl_level = 0xffffffff;
+ footbridge_ipending = 0;
+ footbridge_set_intrmask();
+
+ for (i = 0; i < NIRQ; i++) {
+ iq = &footbridge_intrq[i];
+ TAILQ_INIT(&iq->iq_list);
+
+ snprintf(iq->iq_name, sizeof(iq->iq_name), "irq %d", i);
+#if 0
+ evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
+ NULL, "footbridge", iq->iq_name);
+#endif
+ }
+
+ footbridge_intr_calculate_masks();
+
+ /* Enable IRQ's, we don't have any FIQ's*/
+ enable_interrupts(I32_bit);
+}
+
+void *
+footbridge_intr_claim(int irq, int ipl, char *name, int (*func)(void *), void *arg)
+{
+ struct intrq *iq;
+ struct intrhand *ih;
+ u_int oldirqstate;
+
+ if (irq < 0 || irq > NIRQ)
+ panic("footbridge_intr_establish: IRQ %d out of range", irq);
+
+ ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
+ if (ih == NULL)
+ {
+ printf("No memory");
+ return (NULL);
+ }
+
+ ih->ih_func = func;
+ ih->ih_arg = arg;
+ ih->ih_ipl = ipl;
+ ih->ih_irq = irq;
+
+ iq = &footbridge_intrq[irq];
+
+ iq->iq_ist = IST_LEVEL;
+
+ oldirqstate = disable_interrupts(I32_bit);
+
+ TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
+
+ footbridge_intr_calculate_masks();
+
+ /* detach the existing event counter and add the new name */
+#if 0
+ evcnt_detach(&iq->iq_ev);
+ evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
+ NULL, "footbridge", name);
+#endif
+
+ restore_interrupts(oldirqstate);
+
+ return(ih);
+}
+
+void
+footbridge_intr_disestablish(void *cookie)
+{
+ struct intrhand *ih = cookie;
+ struct intrq *iq = &footbridge_intrq[ih->ih_irq];
+ int oldirqstate;
+
+ /* XXX need to free ih ? */
+ oldirqstate = disable_interrupts(I32_bit);
+
+ TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
+
+ footbridge_intr_calculate_masks();
+
+ restore_interrupts(oldirqstate);
+}
+
+static uint32_t footbridge_intstatus(void);
+
+static inline uint32_t footbridge_intstatus()
+{
+ return ((__volatile uint32_t*)(DC21285_ARMCSR_VBASE))[IRQ_STATUS>>2];
+}
+
+/* called with external interrupts disabled */
+void
+footbridge_intr_dispatch(struct clockframe *frame)
+{
+ struct intrq *iq;
+ struct intrhand *ih;
+ int oldirqstate, pcpl, irq, ibit, hwpend;
+
+ pcpl = current_spl_level;
+
+ hwpend = footbridge_intstatus();
+
+ /*
+ * Disable all the interrupts that are pending. We will
+ * reenable them once they are processed and not masked.
+ */
+ intr_enabled &= ~hwpend;
+ footbridge_set_intrmask();
+
+ while (hwpend != 0) {
+ int intr_rc = 0;
+ irq = ffs(hwpend) - 1;
+ ibit = (1U << irq);
+
+ hwpend &= ~ibit;
+
+ if (pcpl & ibit) {
+ /*
+ * IRQ is masked; mark it as pending and check
+ * the next one. Note: the IRQ is already disabled.
+ */
+ footbridge_ipending |= ibit;
+ continue;
+ }
+
+ footbridge_ipending &= ~ibit;
+
+ iq = &footbridge_intrq[irq];
+ iq->iq_ev.ev_count++;
+ uvmexp.intrs++;
+ current_spl_level |= iq->iq_mask;
+ oldirqstate = enable_interrupts(I32_bit);
+ for (ih = TAILQ_FIRST(&iq->iq_list);
+ ((ih != NULL) && (intr_rc != 1));
+ ih = TAILQ_NEXT(ih, ih_list)) {
+ intr_rc = (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
+ }
+ restore_interrupts(oldirqstate);
+
+ current_spl_level = pcpl;
+
+ /* Re-enable this interrupt now that's it's cleared. */
+ intr_enabled |= ibit;
+ footbridge_set_intrmask();
+
+ /* also check for any new interrupts that may have occured,
+ * that we can handle at this spl level */
+ hwpend |= (footbridge_ipending & ICU_INT_HWMASK) & ~pcpl;
+ }
+
+ /* Check for pendings soft intrs. */
+ if ((footbridge_ipending & INT_SWMASK) & ~current_spl_level) {
+ /*
+ * XXX this feels the wrong place to enable irqs, as some
+ * soft ints are higher priority than hardware irqs
+ */
+ oldirqstate = enable_interrupts(I32_bit);
+ footbridge_do_pending();
+ restore_interrupts(oldirqstate);
+ }
+}
diff --git a/sys/arch/arm/footbridge/footbridge_irqhandler.h b/sys/arch/arm/footbridge/footbridge_irqhandler.h
new file mode 100644
index 00000000000..cf0a7d109ca
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_irqhandler.h
@@ -0,0 +1,60 @@
+/* $OpenBSD: footbridge_irqhandler.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_irqhandler.h,v 1.2 2002/11/03 21:43:31 chris Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FOOTBRIDGE_IRQHANDLER_H_
+#define _FOOTBRIDGE_IRQHANDLER_H_
+
+#ifndef _LOCORE
+#include <sys/types.h>
+#endif /* _LOCORE */
+
+#include <machine/intr.h>
+
+void footbridge_intr_init(void);
+void *footbridge_intr_establish(int, int, int (*)(void *), void *);
+void footbridge_intr_disestablish(void *);
+
+#ifdef _KERNEL
+void *footbridge_intr_claim(int irq, int ipl, char *name, int (*func)(void *), void *arg);
+void footbridge_intr_init(void);
+void footbridge_intr_disestablish(void *cookie);
+#endif /* _KERNEL */
+
+#endif /* _FOOTBRIDGE_IRQHANDLER_H_ */
+
+/* End of irqhandler.h */
diff --git a/sys/arch/arm/footbridge/footbridge_machdep.c b/sys/arch/arm/footbridge/footbridge_machdep.c
new file mode 100644
index 00000000000..40a5a1b4798
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_machdep.c
@@ -0,0 +1,66 @@
+/* $OpenBSD: footbridge_machdep.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_machdep.c,v 1.8 2002/05/03 16:45:22 rjs Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <uvm/uvm_extern.h>
+#include <machine/pmap.h>
+#include <arm/footbridge/footbridge.h>
+#include <arm/footbridge/dc21285mem.h>
+
+/*
+ * For optimal cache cleaning we need two 16K banks of
+ * virtual address space that NOTHING else will access
+ * and then we alternate the cache cleaning between the
+ * two banks.
+ * The cache cleaning code requires requires 2 banks aligned
+ * on total size boundry so the banks can be alternated by
+ * eorring the size bit (assumes the bank size is a power of 2)
+ *
+ * On the DC21285 we have a special cache clean area so we will
+ * use it.
+ */
+
+extern unsigned int sa1_cache_clean_addr;
+extern unsigned int sa1_cache_clean_size;
+
+void
+footbridge_sa110_cc_setup(void)
+{
+ sa1_cache_clean_addr = DC21285_CACHE_FLUSH_VBASE;
+ sa1_cache_clean_size = (PAGE_SIZE * 4);
+}
diff --git a/sys/arch/arm/footbridge/footbridge_pci.c b/sys/arch/arm/footbridge/footbridge_pci.c
new file mode 100644
index 00000000000..ed06a2a6686
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridge_pci.c
@@ -0,0 +1,419 @@
+/* $OpenBSD: footbridge_pci.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridge_pci.c,v 1.4 2001/09/05 16:17:35 matt Exp $ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997,1998 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <arm/footbridge/dc21285reg.h>
+#include <arm/footbridge/dc21285mem.h>
+
+#include "isa.h"
+#if NISA > 0
+#include <dev/isa/isavar.h>
+#endif
+
+void footbridge_pci_attach_hook __P((struct device *,
+ struct device *, struct pcibus_attach_args *));
+int footbridge_pci_bus_maxdevs __P((void *, int));
+pcitag_t footbridge_pci_make_tag __P((void *, int, int, int));
+void footbridge_pci_decompose_tag __P((void *, pcitag_t, int *,
+ int *, int *));
+pcireg_t footbridge_pci_conf_read __P((void *, pcitag_t, int));
+void footbridge_pci_conf_write __P((void *, pcitag_t, int,
+ pcireg_t));
+int footbridge_pci_intr_map __P((struct pci_attach_args *,
+ pci_intr_handle_t *));
+const char *footbridge_pci_intr_string __P((void *, pci_intr_handle_t));
+const struct evcnt *footbridge_pci_intr_evcnt __P((void *, pci_intr_handle_t));
+void *footbridge_pci_intr_establish (void *, pci_intr_handle_t,
+ int, int (*)(void *), void *, char *);
+void footbridge_pci_intr_disestablish (void *, void *);
+
+
+struct arm32_pci_chipset footbridge_pci_chipset = {
+ NULL, /* conf_v */
+#ifdef netwinder
+ netwinder_pci_attach_hook,
+#else
+ footbridge_pci_attach_hook,
+#endif
+ footbridge_pci_bus_maxdevs,
+ footbridge_pci_make_tag,
+ footbridge_pci_decompose_tag,
+ footbridge_pci_conf_read,
+ footbridge_pci_conf_write,
+ NULL, /* intr_v */
+ footbridge_pci_intr_map,
+ footbridge_pci_intr_string,
+ footbridge_pci_intr_evcnt,
+ footbridge_pci_intr_establish,
+ footbridge_pci_intr_disestablish
+};
+
+/*
+ * PCI doesn't have any special needs; just use the generic versions
+ * of these functions.
+ */
+struct arm32_bus_dma_tag footbridge_pci_bus_dma_tag = {
+ 0,
+ 0,
+ NULL,
+ _bus_dmamap_create,
+ _bus_dmamap_destroy,
+ _bus_dmamap_load,
+ _bus_dmamap_load_mbuf,
+ _bus_dmamap_load_uio,
+ _bus_dmamap_load_raw,
+ _bus_dmamap_unload,
+ _bus_dmamap_sync,
+ _bus_dmamem_alloc,
+ _bus_dmamem_free,
+ _bus_dmamem_map,
+ _bus_dmamem_unmap,
+ _bus_dmamem_mmap,
+};
+
+/*
+ * Currently we only support 12 devices as we select directly in the
+ * type 0 config cycle
+ * (See conf_{read,write} for more detail
+ */
+#define MAX_PCI_DEVICES 21
+
+/*static int
+pci_intr(void *arg)
+{
+ printf("pci int %x\n", (int)arg);
+ return(0);
+}*/
+
+
+void
+footbridge_pci_attach_hook(parent, self, pba)
+ struct device *parent, *self;
+ struct pcibus_attach_args *pba;
+{
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_attach_hook()\n");
+#endif
+
+/* intr_claim(18, IPL_NONE, "pci int 0", pci_intr, (void *)0x10000);
+ intr_claim(8, IPL_NONE, "pci int 1", pci_intr, (void *)0x10001);
+ intr_claim(9, IPL_NONE, "pci int 2", pci_intr, (void *)0x10002);
+ intr_claim(11, IPL_NONE, "pci int 3", pci_intr, (void *)0x10003);*/
+}
+
+int
+footbridge_pci_bus_maxdevs(pcv, busno)
+ void *pcv;
+ int busno;
+{
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_bus_maxdevs(pcv=%p, busno=%d)\n", pcv, busno);
+#endif
+ return(MAX_PCI_DEVICES);
+}
+
+pcitag_t
+footbridge_pci_make_tag(pcv, bus, device, function)
+ void *pcv;
+ int bus, device, function;
+{
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_make_tag(pcv=%p, bus=%d, device=%d, function=%d)\n",
+ pcv, bus, device, function);
+#endif
+ return ((bus << 16) | (device << 11) | (function << 8));
+}
+
+void
+footbridge_pci_decompose_tag(pcv, tag, busp, devicep, functionp)
+ void *pcv;
+ pcitag_t tag;
+ int *busp, *devicep, *functionp;
+{
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_decompose_tag(pcv=%p, tag=0x%08x, bp=%x, dp=%x, fp=%x)\n",
+ pcv, tag, busp, devicep, functionp);
+#endif
+
+ if (busp != NULL)
+ *busp = (tag >> 16) & 0xff;
+ if (devicep != NULL)
+ *devicep = (tag >> 11) & 0x1f;
+ if (functionp != NULL)
+ *functionp = (tag >> 8) & 0x7;
+}
+
+pcireg_t
+footbridge_pci_conf_read(pcv, tag, reg)
+ void *pcv;
+ pcitag_t tag;
+ int reg;
+{
+ int bus, device, function;
+ u_int address;
+ pcireg_t data;
+
+ footbridge_pci_decompose_tag(pcv, tag, &bus, &device, &function);
+ if (bus == 0)
+ /* Limited to 12 devices or we exceed type 0 config space */
+ address = DC21285_PCI_TYPE_0_CONFIG_VBASE | (3 << 22) | (device << 11);
+ else
+ address = DC21285_PCI_TYPE_1_CONFIG_VBASE | (device << 11) |
+ (bus << 16);
+
+ address |= (function << 8) | reg;
+
+ data = *((unsigned int *)address);
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_conf_read(pcv=%p tag=0x%08x reg=0x%02x)=0x%08x\n",
+ pcv, tag, reg, data);
+#endif
+ return(data);
+}
+
+void
+footbridge_pci_conf_write(pcv, tag, reg, data)
+ void *pcv;
+ pcitag_t tag;
+ int reg;
+ pcireg_t data;
+{
+ int bus, device, function;
+ u_int address;
+
+ footbridge_pci_decompose_tag(pcv, tag, &bus, &device, &function);
+ if (bus == 0)
+ address = DC21285_PCI_TYPE_0_CONFIG_VBASE | (3 << 22) | (device << 11);
+ else
+ address = DC21285_PCI_TYPE_1_CONFIG_VBASE | (device << 11) |
+ (bus << 16);
+
+ address |= (function << 8) | reg;
+
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_conf_write(pcv=%p tag=0x%08x reg=0x%02x, 0x%08x)\n",
+ pcv, tag, reg, data);
+#endif
+
+ *((unsigned int *)address) = data;
+}
+
+int
+footbridge_pci_intr_map(pa, ihp)
+ struct pci_attach_args *pa;
+ pci_intr_handle_t *ihp;
+{
+ int pin = pa->pa_intrpin, line = pa->pa_intrline;
+ int intr = -1;
+
+#ifdef PCI_DEBUG
+ void *pcv = pa->pa_pc;
+ pcitag_t intrtag = pa->pa_intrtag;
+ int bus, device, function;
+
+ footbridge_pci_decompose_tag(pcv, intrtag, &bus, &device, &function);
+ printf("footbride_pci_intr_map: pcv=%p, tag=%08lx pin=%d line=%d dev=%d\n",
+ pcv, intrtag, pin, line, device);
+#endif
+
+ /*
+ * Only the line is used to map the interrupt.
+ * The firmware is expected to setup up the interrupt
+ * line as seen from the CPU
+ * This means the firmware deals with the interrupt rotation
+ * between slots etc.
+ *
+ * Perhaps the firmware should also to the final mapping
+ * to a 21285 interrupt bit so the code below would be
+ * completely MI.
+ */
+
+ switch (line) {
+ case PCI_INTERRUPT_PIN_NONE:
+ case 0xff:
+ /* No IRQ */
+ printf("pci_intr_map: no mapping for pin %c\n", '@' + pin);
+ *ihp = -1;
+ return(1);
+ break;
+#ifdef __cats__
+ /* This is machine dependant and needs to be moved */
+ case PCI_INTERRUPT_PIN_A:
+ intr = IRQ_PCI;
+ break;
+ case PCI_INTERRUPT_PIN_B:
+ intr = IRQ_IN_L0;
+ break;
+ case PCI_INTERRUPT_PIN_C:
+ intr = IRQ_IN_L1;
+ break;
+ case PCI_INTERRUPT_PIN_D:
+ intr = IRQ_IN_L3;
+ break;
+#endif
+ default:
+ /*
+ * Experimental firmware feature ...
+ *
+ * If the interrupt line is in the range 0x80 to 0x8F
+ * then the lower 4 bits indicate the ISA interrupt
+ * bit that should be used.
+ * If the interrupt line is in the range 0x40 to 0x5F
+ * then the lower 5 bits indicate the actual DC21285
+ * interrupt bit that should be used.
+ */
+
+ if (line >= 0x40 && line <= 0x5f)
+ intr = line & 0x1f;
+ else if (line >= 0x80 && line <= 0x8f)
+ intr = line;
+ else {
+ printf("footbridge_pci_intr_map: out of range interrupt"
+ "pin %d line %d (%#x)\n", pin, line, line);
+ *ihp = -1;
+ return(1);
+ }
+ break;
+ }
+
+#ifdef PCI_DEBUG
+ printf("pin %d, line %d mapped to int %d\n", pin, line, intr);
+#endif
+
+ *ihp = intr;
+ return(0);
+}
+
+const char *
+footbridge_pci_intr_string(pcv, ih)
+ void *pcv;
+ pci_intr_handle_t ih;
+{
+ static char irqstr[8]; /* 4 + 2 + NULL + sanity */
+
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_intr_string(pcv=0x%p, ih=0x%lx)\n", pcv, ih);
+#endif
+ if (ih == 0)
+ panic("footbridge_pci_intr_string: bogus handle 0x%lx", ih);
+
+#if NISA > 0
+ if (ih >= 0x80 && ih <= 0x8f) {
+ snprintf(irqstr, sizeof(irqstr), "isairq %ld", (ih & 0x0f));
+ return(irqstr);
+ }
+#endif
+ snprintf(irqstr, sizeof(irqstr), "irq %ld", ih);
+ return(irqstr);
+}
+
+#if 0
+const struct evcnt *
+footbridge_pci_intr_evcnt(pcv, ih)
+ void *pcv;
+ pci_intr_handle_t ih;
+{
+
+ /* XXX for now, no evcnt parent reported */
+ return NULL;
+}
+#endif
+
+void *
+footbridge_pci_intr_establish(pcv, ih, level, func, arg, name)
+ void *pcv;
+ pci_intr_handle_t ih;
+ int level, (*func) __P((void *));
+ void *arg;
+ char *name;
+{
+ void *intr;
+ int length;
+ char *string;
+
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_intr_establish(pcv=%p, ih=0x%lx, level=%d, func=%p, arg=%p)\n",
+ pcv, ih, level, func, arg);
+#endif
+
+ /* Copy the interrupt string to a private buffer */
+ length = strlen(footbridge_pci_intr_string(pcv, ih));
+ string = malloc(length + 1, M_DEVBUF, M_WAITOK);
+ strlcpy(string, footbridge_pci_intr_string(pcv, ih), length);
+#if NISA > 0
+ /*
+ * XXX the IDE driver will attach the interrupts in compat mode and
+ * thus we need to fail this here.
+ * This assumes that the interrupts are 14 and 15 which they are for
+ * IDE compat mode.
+ * Really the firmware should make this clear in the interrupt reg.
+ */
+ if (ih >= 0x80 && ih <= 0x8d) {
+ intr = isa_intr_establish(NULL, (ih & 0x0f), IST_EDGE,
+ level, func, arg, string);
+ } else
+#endif
+ intr = footbridge_intr_claim(ih, level, string, func, arg);
+
+ return(intr);
+}
+
+void
+footbridge_pci_intr_disestablish(pcv, cookie)
+ void *pcv;
+ void *cookie;
+{
+#ifdef PCI_DEBUG
+ printf("footbridge_pci_intr_disestablish(pcv=%p, cookie=0x%x)\n",
+ pcv, cookie);
+#endif
+ /* XXXX Need to free the string */
+
+ footbridge_intr_disestablish(cookie);
+}
diff --git a/sys/arch/arm/footbridge/footbridgevar.h b/sys/arch/arm/footbridge/footbridgevar.h
new file mode 100644
index 00000000000..04cbe1ce74f
--- /dev/null
+++ b/sys/arch/arm/footbridge/footbridgevar.h
@@ -0,0 +1,96 @@
+/* $OpenBSD: footbridgevar.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: footbridgevar.h,v 1.2 2002/02/10 12:26:00 chris Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/bus.h>
+#include <machine/rtc.h>
+#include <dev/pci/pcivar.h>
+#include <arm/footbridge/todclockvar.h>
+
+/*
+ * DC21285 softc structure.
+ *
+ * Contains the device node, bus space tag, handle and address
+ */
+
+struct footbridge_softc {
+ struct device sc_dev; /* device node */
+ bus_space_tag_t sc_iot; /* bus tag */
+ bus_space_handle_t sc_ioh; /* bus handle */
+
+ /* Clock related variables - used in footbridge_clock.c */
+ unsigned int sc_clock_ticks_per_256us;
+ unsigned int sc_clock_count;
+ void *sc_clockintr;
+ unsigned int sc_statclock_count;
+ void *sc_statclockintr;
+
+ /* Miscellaneous interrupts */
+ void * sc_serr_ih;
+ void * sc_sdram_par_ih;
+ void * sc_data_par_ih;
+ void * sc_master_abt_ih;
+ void * sc_target_abt_ih;
+ void * sc_parity_ih;
+};
+
+/*
+ * Attach args for child devices
+ */
+
+union footbridge_attach_args {
+ const char *fba_name; /* first element*/
+ struct {
+ bus_space_tag_t fba_iot; /* Bus tag */
+ bus_space_handle_t fba_ioh; /* Bus handle */
+ } fba_fba;
+ struct pcibus_attach_args fba_pba; /* pci attach args */
+ struct todclock_attach_args fba_tca;
+ struct fcom_attach_args {
+ char *fca_name;
+ bus_space_tag_t fca_iot;
+ bus_space_handle_t fca_ioh;
+ int fca_rx_irq;
+ int fca_tx_irq;
+ } fba_fca;
+/* struct clock_attach_args {
+ char *ca_name;
+ bus_space_tag_t ca_iot;
+ bus_space_handle_t ca_ioh;
+ } fba_ca;*/
+};
+
+/* End of footbridgevar.h */
diff --git a/sys/arch/arm/footbridge/genassym.cf b/sys/arch/arm/footbridge/genassym.cf
new file mode 100644
index 00000000000..864c1448d12
--- /dev/null
+++ b/sys/arch/arm/footbridge/genassym.cf
@@ -0,0 +1,47 @@
+# $OpenBSD: genassym.cf,v 1.1 2004/02/01 05:09:49 drahn Exp $
+# $NetBSD: genassym.cf,v 1.2 2001/12/20 01:20:23 thorpej Exp $
+
+# Copyright (c) 1982, 1990 The Regents of the University of California.
+# All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# William Jolitz.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+include <machine/intr.h>
+
+define IH_FUNC offsetof(struct irqhandler, ih_func)
+define IH_ARG offsetof(struct irqhandler, ih_arg)
+define IH_FLAGS offsetof(struct irqhandler, ih_flags)
+define IH_LEVEL offsetof(struct irqhandler, ih_level)
+define IH_NUM offsetof(struct irqhandler, ih_num)
+define IH_MASKADDR offsetof(struct irqhandler, ih_maskaddr)
+define IH_MASKBITS offsetof(struct irqhandler, ih_maskbits)
+define IH_NEXT offsetof(struct irqhandler, ih_next)
diff --git a/sys/arch/arm/footbridge/isa/ds1687reg.h b/sys/arch/arm/footbridge/isa/ds1687reg.h
new file mode 100644
index 00000000000..5f5e1ff9f1c
--- /dev/null
+++ b/sys/arch/arm/footbridge/isa/ds1687reg.h
@@ -0,0 +1,129 @@
+/* $OpenBSD: ds1687reg.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: ds1687reg.h,v 1.1 2002/02/10 12:26:01 chris Exp $ */
+
+/*
+ * Copyright (c) 1998 Mark Brinicombe.
+ * Copyright (c) 1998 Causality Limited.
+ * All rights reserved.
+ *
+ * Written by Mark Brinicombe, Causality Limited
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAUASLITY LIMITED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define RTC_ADDR 0x72
+#define RTC_ADDR_REG 0x00
+#define RTC_DATA_REG 0x01
+
+#define RTC_SECONDS 0x00
+#define RTC_SECONDS_ALARM 0x01
+#define RTC_MINUTES 0x02
+#define RTC_MINUTES_ALARM 0x03
+#define RTC_HOURS 0x04
+#define RTC_HOURS_ALARM 0x05
+#define RTC_DAYOFWEEK 0x06
+#define RTC_DAYOFMONTH 0x07
+#define RTC_MONTH 0x08
+#define RTC_YEAR 0x09
+
+#define RTC_REG_A 0x0a
+#define RTC_REG_A_UIP 0x80 /* Update In Progress */
+#define RTC_REG_A_DV2 0x40 /* Countdown CHain */
+#define RTC_REG_A_DV1 0x20 /* Oscillator Enable */
+#define RTC_REG_A_DV0 0x10 /* Bank Select */
+#define RTC_REG_A_BANK_MASK RTC_REG_A_DV0
+#define RTC_REG_A_BANK1 RTC_REG_A_DV0
+#define RTC_REG_A_BANK0 0x00
+#define RTC_REG_A_RS_MASK 0x0f /* Rate select mask */
+#define RTC_REG_A_RS_NONE 0x00
+#define RTC_REG_A_RS_256HZ_1 0x01
+#define RTC_REG_A_RS_128HZ_1 0x02
+#define RTC_REG_A_RS_8192HZ 0x03
+#define RTC_REG_A_RS_4096HZ 0x04
+#define RTC_REG_A_RS_2048HZ 0x05
+#define RTC_REG_A_RS_1024HZ 0x06
+#define RTC_REG_A_RS_512HZ 0x07
+#define RTC_REG_A_RS_256HZ 0x08
+#define RTC_REG_A_RS_128HZ 0x09
+#define RTC_REG_A_RS_64HZ 0x0A
+#define RTC_REG_A_RS_32HZ 0x0B
+#define RTC_REG_A_RS_16HZ 0x0C
+#define RTC_REG_A_RS_8HZ 0x0D
+#define RTC_REG_A_RS_4HZ 0x0E
+#define RTC_REG_A_RS_2HZ 0x0F
+
+#define RTC_REG_B 0x0b
+#define RTC_REG_B_SET 0x80 /* Inhibit update */
+#define RTC_REG_B_PIE 0x40 /* Periodic Interrupt Enable */
+#define RTC_REG_B_AIE 0x20 /* Alarm Interrupt Enable */
+#define RTC_REG_B_UIE 0x10 /* Updated Ended Interrupt Enable */
+#define RTC_REG_B_SQWE 0x08 /* Square Wave Enable */
+#define RTC_REG_B_DM 0x04 /* Data Mode */
+#define RTC_REG_B_BINARY RTC_REG_B_DM
+#define RTC_REG_B_BCD 0
+#define RTC_REG_B_24_12 0x02 /* Hour format */
+#define RTC_REG_B_24_HOUR RTC_REG_B_24_12
+#define RTC_REG_B_12_HOUR 0
+#define RTC_REG_B_DSE 0x01 /* Daylight Savings Enable */
+
+#define RTC_REG_C 0x0c
+#define RTC_REG_C_IRQF 0x80 /* Interrupt Request Flag */
+#define RTC_REG_C_PF 0x40 /* Periodic Interrupt Flag */
+#define RTC_REG_C_AF 0x20 /* Alarm Interrupt Flag */
+#define RTC_REG_C_UF 0x10 /* Update Ended Flags */
+
+#define RTC_REG_D 0x0d
+#define RTC_REG_D_VRT 0x80 /* Valid RAM and Time */
+
+#define RTC_PC_RAM_START 0x0e
+#define RTC_PC_RAM_SIZE 50
+
+#define RTC_BANK0_RAM_START 0x40
+#define RTC_BANK0_RAM_SIZE 0x40
+
+#define RTC_MODEL 0x40
+#define RTC_SERIAL_1 0x41
+#define RTC_SERIAL_2 0x42
+#define RTC_SERIAL_3 0x43
+#define RTC_SERIAL_4 0x44
+#define RTC_SERIAL_5 0x45
+#define RTC_SERIAL_6 0x46
+#define RTC_CRC 0x47
+#define RTC_CENTURY 0x48
+#define RTC_DATE_ALARM 0x49
+#define RTC_REG_4A 0x4a
+#define RTC_REG_4A_VRT2 0x80
+#define RTC_REG_4A_INCR 0x40
+#define RTC_REG_4A_PAB 0x08
+#define RTC_REG_4A_RF 0x04
+#define RTC_REG_4B 0x4b
+#define RTC_EXT_RAM_ADDRESS 0x50
+#define RTC_EXT_RAM_DATA 0x53
+#define RTC_EXT_RAM_START 0x00
+#define RTC_EXT_RAM_SIZE 0x80
diff --git a/sys/arch/arm/footbridge/isa/dsrtc.c b/sys/arch/arm/footbridge/isa/dsrtc.c
new file mode 100644
index 00000000000..b909ed406e1
--- /dev/null
+++ b/sys/arch/arm/footbridge/isa/dsrtc.c
@@ -0,0 +1,279 @@
+/* $OpenBSD: dsrtc.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: dsrtc.c,v 1.5 2003/03/23 14:12:26 chris Exp $ */
+
+/*
+ * Copyright (c) 1998 Mark Brinicombe.
+ * Copyright (c) 1998 Causality Limited.
+ * All rights reserved.
+ *
+ * Written by Mark Brinicombe, Causality Limited
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAUASLITY LIMITED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+
+#include <machine/rtc.h>
+
+#include <arm/footbridge/todclockvar.h>
+#include <arm/footbridge/isa/ds1687reg.h>
+
+#include <dev/isa/isavar.h>
+
+#define NRTC_PORTS 2
+
+struct dsrtc_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+void dsrtcattach __P((struct device *parent, struct device *self, void *aux));
+int dsrtcmatch __P((struct device *parent, void *cf, void *aux));
+int ds1687_read __P((struct dsrtc_softc *sc, int addr));
+void ds1687_write __P((struct dsrtc_softc *sc, int addr, int data));
+int ds1687_ram_read __P((struct dsrtc_softc *sc, int addr));
+void ds1687_ram_write __P((struct dsrtc_softc *sc, int addr, int data));
+static void ds1687_bank_select __P((struct dsrtc_softc *, int));
+static int dsrtc_write __P((void *, rtc_t *));
+static int dsrtc_read __P((void *, rtc_t *));
+
+int
+ds1687_read(sc, addr)
+ struct dsrtc_softc *sc;
+ int addr;
+{
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
+ return(bus_space_read_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG));
+}
+
+void
+ds1687_write(sc, addr, data)
+ struct dsrtc_softc *sc;
+ int addr;
+ int data;
+{
+
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_ADDR_REG, addr);
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh, RTC_DATA_REG, data);
+}
+
+static void
+ds1687_bank_select(sc, bank)
+ struct dsrtc_softc *sc;
+ int bank;
+{
+ int data;
+
+ data = ds1687_read(sc, RTC_REG_A);
+ data &= ~RTC_REG_A_BANK_MASK;
+ if (bank)
+ data |= RTC_REG_A_BANK1;
+ ds1687_write(sc, RTC_REG_A, data);
+}
+
+#if 0
+/* Nothing uses these yet */
+int
+ds1687_ram_read(sc, addr)
+ struct dsrtc_softc *sc;
+ int addr;
+{
+ if (addr < RTC_PC_RAM_SIZE)
+ return(ds1687_read(sc, RTC_PC_RAM_START + addr));
+
+ addr -= RTC_PC_RAM_SIZE;
+ if (addr < RTC_BANK0_RAM_SIZE)
+ return(ds1687_read(sc, RTC_BANK0_RAM_START + addr));
+
+ addr -= RTC_BANK0_RAM_SIZE;
+ if (addr < RTC_EXT_RAM_SIZE) {
+ int data;
+
+ ds1687_bank_select(sc, 1);
+ ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
+ data = ds1687_read(sc, RTC_EXT_RAM_DATA);
+ ds1687_bank_select(sc, 0);
+ return(data);
+ }
+ return(-1);
+}
+
+void
+ds1687_ram_write(sc, addr, val)
+ struct dsrtc_softc *sc;
+ int addr;
+ int val;
+{
+ if (addr < RTC_PC_RAM_SIZE)
+ return(ds1687_write(sc, RTC_PC_RAM_START + addr, val));
+
+ addr -= RTC_PC_RAM_SIZE;
+ if (addr < RTC_BANK0_RAM_SIZE)
+ return(ds1687_write(sc, RTC_BANK0_RAM_START + addr, val));
+
+ addr -= RTC_BANK0_RAM_SIZE;
+ if (addr < RTC_EXT_RAM_SIZE) {
+ ds1687_bank_select(sc, 1);
+ ds1687_write(sc, RTC_EXT_RAM_ADDRESS, addr);
+ ds1687_write(sc, RTC_EXT_RAM_DATA, val);
+ ds1687_bank_select(sc, 0);
+ }
+}
+#endif
+
+static int
+dsrtc_write(arg, rtc)
+ void *arg;
+ rtc_t *rtc;
+{
+ struct dsrtc_softc *sc = arg;
+
+ ds1687_write(sc, RTC_SECONDS, rtc->rtc_sec);
+ ds1687_write(sc, RTC_MINUTES, rtc->rtc_min);
+ ds1687_write(sc, RTC_HOURS, rtc->rtc_hour);
+ ds1687_write(sc, RTC_DAYOFMONTH, rtc->rtc_day);
+ ds1687_write(sc, RTC_MONTH, rtc->rtc_mon);
+ ds1687_write(sc, RTC_YEAR, rtc->rtc_year);
+ ds1687_bank_select(sc, 1);
+ ds1687_write(sc, RTC_CENTURY, rtc->rtc_cen);
+ ds1687_bank_select(sc, 0);
+ return(1);
+}
+
+static int
+dsrtc_read(arg, rtc)
+ void *arg;
+ rtc_t *rtc;
+{
+ struct dsrtc_softc *sc = arg;
+
+ rtc->rtc_micro = 0;
+ rtc->rtc_centi = 0;
+ rtc->rtc_sec = ds1687_read(sc, RTC_SECONDS);
+ rtc->rtc_min = ds1687_read(sc, RTC_MINUTES);
+ rtc->rtc_hour = ds1687_read(sc, RTC_HOURS);
+ rtc->rtc_day = ds1687_read(sc, RTC_DAYOFMONTH);
+ rtc->rtc_mon = ds1687_read(sc, RTC_MONTH);
+ rtc->rtc_year = ds1687_read(sc, RTC_YEAR);
+ ds1687_bank_select(sc, 1);
+ rtc->rtc_cen = ds1687_read(sc, RTC_CENTURY);
+ ds1687_bank_select(sc, 0);
+
+ return(1);
+}
+
+/* device and attach structures */
+struct cfattach ds1687rtc_ca = {
+ sizeof(struct dsrtc_softc), dsrtcmatch, dsrtcattach
+};
+
+struct cfdriver ds1687rtc_cd = {
+ NULL, "dsrtc", DV_DULL
+};
+
+/*
+ * dsrtcmatch()
+ *
+ * Validate the IIC address to make sure its an RTC we understand
+ */
+
+int
+dsrtcmatch(parent, cf, aux)
+ struct device *parent;
+ void *cf;
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+
+#ifdef __NetBSD__
+ if (ia->ia_nio < 1 ||
+ ia->ia_iobase == -1)
+ return (0);
+
+ ia->ia_nio = 1;
+ ia->ia_io[0].ir_size = NRTC_PORTS;
+#else
+ ia->ia_iosize = NRTC_PORTS;
+#endif
+
+
+#if 0
+ ia->ia_niomem = 0;
+ ia->ia_nirq = 0;
+ ia->ia_ndrq = 0;
+#endif
+
+ return(1);
+}
+
+/*
+ * dsrtcattach()
+ *
+ * Attach the rtc device
+ */
+
+void
+dsrtcattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct dsrtc_softc *sc = (struct dsrtc_softc *)self;
+ struct isa_attach_args *ia = aux;
+ struct todclock_attach_args ta;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_iobase,
+ ia->ia_iosize, 0, &sc->sc_ioh)) {
+ printf(": cannot map I/O space\n");
+ return;
+ }
+
+ ds1687_write(sc, RTC_REG_A, RTC_REG_A_DV1);
+ ds1687_write(sc, RTC_REG_B, RTC_REG_B_BINARY | RTC_REG_B_24_HOUR);
+
+ if (!(ds1687_read(sc, RTC_REG_D) & RTC_REG_D_VRT))
+ printf(": lithium cell is dead, RTC unreliable");
+ printf("\n");
+
+ ta.ta_name = "todclock";
+ ta.ta_rtc_arg = sc;
+ ta.ta_rtc_write = dsrtc_write;
+ ta.ta_rtc_read = dsrtc_read;
+ ta.ta_flags = 0;
+ config_found(self, &ta, NULL);
+}
+
+/* End of dsrtc.c */
diff --git a/sys/arch/arm/footbridge/isa/icu.h b/sys/arch/arm/footbridge/isa/icu.h
new file mode 100644
index 00000000000..357a0d8e5a0
--- /dev/null
+++ b/sys/arch/arm/footbridge/isa/icu.h
@@ -0,0 +1,71 @@
+/* $OpenBSD: icu.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: icu.h,v 1.1 2002/02/10 12:26:01 chris Exp $ */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)icu.h 5.6 (Berkeley) 5/9/91
+ */
+
+/*
+ * AT/386 Interrupt Control constants
+ * W. Jolitz 8/89
+ */
+
+#ifndef _ARM32_ISA_ICU_H_
+#define _ARM32_ISA_ICU_H_
+
+#ifndef _LOCORE
+
+/*
+ * Interrupt "level" mechanism variables, masks, and macros
+ */
+extern unsigned imen; /* interrupt mask enable */
+
+#define SET_ICUS() { \
+ outb(IO_ICU1 + 1, imen); \
+ outb(IO_ICU2 + 1, imen >> 8); \
+}
+
+#endif /* !_LOCORE */
+
+/*
+ * Interrupt enable bits -- in order of priority
+ */
+#define IRQ_SLAVE 2
+
+/*
+ * Interrupt Control offset into Interrupt descriptor table (IDT)
+ */
+#define ICU_OFFSET 32 /* 0-31 are processor exceptions */
+#define ICU_LEN 16 /* 32-47 are ISA interrupts */
+
+#endif /* !_ARM32_ISA_ICU_H_ */
diff --git a/sys/arch/arm/footbridge/isa/isa_io.c b/sys/arch/arm/footbridge/isa/isa_io.c
new file mode 100644
index 00000000000..fbb1253c91f
--- /dev/null
+++ b/sys/arch/arm/footbridge/isa/isa_io.c
@@ -0,0 +1,321 @@
+/* $OpenBSD: isa_io.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: isa_io.c,v 1.2 2002/09/27 15:35:44 provos Exp $ */
+
+/*
+ * Copyright 1997
+ * Digital Equipment Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and conditions.
+ * Subject to these conditions, you may download, copy, install,
+ * use, modify and distribute this software in source and/or binary
+ * form. No title or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions as
+ * they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or logo of
+ * Digital Equipment Corporation. Neither the "Digital Equipment
+ * Corporation" name nor any trademark or logo of Digital Equipment
+ * Corporation may be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Digital Equipment Corporation.
+ *
+ * 3) This software is provided "AS-IS" and any express or implied
+ * warranties, including but not limited to, any implied warranties
+ * of merchantability, fitness for a particular purpose, or
+ * non-infringement are disclaimed. In no event shall DIGITAL be
+ * liable for any damages whatsoever, and in particular, DIGITAL
+ * shall not be liable for special, indirect, consequential, or
+ * incidental damages or damages for lost profits, loss of
+ * revenue or loss of use, whether such damages arise in contract,
+ * negligence, tort, under statute, in equity, at law or otherwise,
+ * even if advised of the possibility of such damage.
+ */
+
+/*
+ * bus_space I/O functions for isa
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+#include <machine/pio.h>
+#include <machine/isa_machdep.h>
+
+/* Proto types for all the bus_space structure functions */
+
+bs_protos(isa);
+bs_protos(bs_notimpl);
+
+/*
+ * Declare the isa bus space tags
+ * The IO and MEM structs are identical, except for the cookies,
+ * which contain the address space bases.
+ */
+
+/*
+ * NOTE: ASSEMBLY LANGUAGE RELIES ON THE COOKIE -- THE FIRST MEMBER OF
+ * THIS STRUCTURE -- TO BE THE VIRTUAL ADDRESS OF ISA/IO!
+ */
+struct bus_space isa_io_bs_tag = {
+ /* cookie */
+ NULL, /* initialized below */
+
+ /* mapping/unmapping */
+ isa_bs_map,
+ isa_bs_unmap,
+ isa_bs_subregion,
+
+ /* allocation/deallocation */
+ isa_bs_alloc,
+ isa_bs_free,
+
+ /* get kernel virtual address */
+ isa_bs_vaddr,
+
+ /* mmap bus space for userland */
+ bs_notimpl_bs_mmap, /* XXX possible even? XXX */
+
+ /* barrier */
+ isa_bs_barrier,
+
+ /* read (single) */
+ isa_bs_r_1,
+ isa_bs_r_2,
+ isa_bs_r_4,
+ bs_notimpl_bs_r_8,
+
+ /* read multiple */
+ isa_bs_rm_1,
+ isa_bs_rm_2,
+ isa_bs_rm_4,
+ bs_notimpl_bs_rm_8,
+
+ /* read region */
+ isa_bs_rr_1,
+ isa_bs_rr_2,
+ isa_bs_rr_4,
+ bs_notimpl_bs_rr_8,
+
+ /* write (single) */
+ isa_bs_w_1,
+ isa_bs_w_2,
+ isa_bs_w_4,
+ bs_notimpl_bs_w_8,
+
+ /* write multiple */
+ isa_bs_wm_1,
+ isa_bs_wm_2,
+ isa_bs_wm_4,
+ bs_notimpl_bs_wm_8,
+
+ /* write region */
+ isa_bs_wr_1,
+ isa_bs_wr_2,
+ isa_bs_wr_4,
+ bs_notimpl_bs_wr_8,
+
+ /* set multiple */
+ bs_notimpl_bs_sm_1,
+ bs_notimpl_bs_sm_2,
+ bs_notimpl_bs_sm_4,
+ bs_notimpl_bs_sm_8,
+
+ /* set region */
+ bs_notimpl_bs_sr_1,
+ isa_bs_sr_2,
+ bs_notimpl_bs_sr_4,
+ bs_notimpl_bs_sr_8,
+
+ /* copy */
+ bs_notimpl_bs_c_1,
+ bs_notimpl_bs_c_2,
+ bs_notimpl_bs_c_4,
+ bs_notimpl_bs_c_8,
+};
+
+/*
+ * NOTE: ASSEMBLY LANGUAGE RELIES ON THE COOKIE -- THE FIRST MEMBER OF
+ * THIS STRUCTURE -- TO BE THE VIRTUAL ADDRESS OF ISA/MEMORY!
+ */
+struct bus_space isa_mem_bs_tag = {
+ /* cookie */
+ NULL, /* initialized below */
+
+ /* mapping/unmapping */
+ isa_bs_map,
+ isa_bs_unmap,
+ isa_bs_subregion,
+
+ /* allocation/deallocation */
+ isa_bs_alloc,
+ isa_bs_free,
+
+ /* get kernel virtual address */
+ isa_bs_vaddr,
+
+ /* mmap bus space for userland */
+ bs_notimpl_bs_mmap, /* XXX open for now ... XXX */
+
+ /* barrier */
+ isa_bs_barrier,
+
+ /* read (single) */
+ isa_bs_r_1,
+ isa_bs_r_2,
+ isa_bs_r_4,
+ bs_notimpl_bs_r_8,
+
+ /* read multiple */
+ isa_bs_rm_1,
+ isa_bs_rm_2,
+ isa_bs_rm_4,
+ bs_notimpl_bs_rm_8,
+
+ /* read region */
+ isa_bs_rr_1,
+ isa_bs_rr_2,
+ isa_bs_rr_4,
+ bs_notimpl_bs_rr_8,
+
+ /* write (single) */
+ isa_bs_w_1,
+ isa_bs_w_2,
+ isa_bs_w_4,
+ bs_notimpl_bs_w_8,
+
+ /* write multiple */
+ isa_bs_wm_1,
+ isa_bs_wm_2,
+ isa_bs_wm_4,
+ bs_notimpl_bs_wm_8,
+
+ /* write region */
+ isa_bs_wr_1,
+ isa_bs_wr_2,
+ isa_bs_wr_4,
+ bs_notimpl_bs_wr_8,
+
+ /* set multiple */
+ bs_notimpl_bs_sm_1,
+ bs_notimpl_bs_sm_2,
+ bs_notimpl_bs_sm_4,
+ bs_notimpl_bs_sm_8,
+
+ /* set region */
+ bs_notimpl_bs_sr_1,
+ isa_bs_sr_2,
+ bs_notimpl_bs_sr_4,
+ bs_notimpl_bs_sr_8,
+
+ /* copy */
+ bs_notimpl_bs_c_1,
+ bs_notimpl_bs_c_2,
+ bs_notimpl_bs_c_4,
+ bs_notimpl_bs_c_8,
+};
+
+/* bus space functions */
+
+void
+isa_io_init(isa_io_addr, isa_mem_addr)
+ vm_offset_t isa_io_addr;
+ vm_offset_t isa_mem_addr;
+{
+ isa_io_bs_tag.bs_cookie = (void *)isa_io_addr;
+ isa_mem_bs_tag.bs_cookie = (void *)isa_mem_addr;
+}
+
+/*
+ * break the abstraction: sometimes, other parts of the system
+ * (e.g. X servers) need to map ISA space directly. use these
+ * functions sparingly!
+ */
+vm_offset_t
+isa_io_data_vaddr(void)
+{
+ return (vm_offset_t)isa_io_bs_tag.bs_cookie;
+}
+
+vm_offset_t
+isa_mem_data_vaddr(void)
+{
+ return (vm_offset_t)isa_mem_bs_tag.bs_cookie;
+}
+
+int
+isa_bs_map(t, bpa, size, cacheable, bshp)
+ void *t;
+ bus_addr_t bpa;
+ bus_size_t size;
+ int cacheable;
+ bus_space_handle_t *bshp;
+{
+ *bshp = bpa + (bus_addr_t)t;
+ return(0);
+}
+
+void
+isa_bs_unmap(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ /* Nothing to do. */
+}
+
+int
+isa_bs_subregion(t, bsh, offset, size, nbshp)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, size;
+ bus_space_handle_t *nbshp;
+{
+/* printf("isa_subregion(tag=%p, bsh=%lx, off=%lx, sz=%lx)\n",
+ t, bsh, offset, size);*/
+ *nbshp = bsh + offset;
+ return(0);
+}
+
+int
+isa_bs_alloc(t, rstart, rend, size, alignment, boundary, cacheable,
+ bpap, bshp)
+ void *t;
+ bus_addr_t rstart, rend;
+ bus_size_t size, alignment, boundary;
+ int cacheable;
+ bus_addr_t *bpap;
+ bus_space_handle_t *bshp;
+{
+ panic("isa_alloc(): Help!");
+}
+
+void
+isa_bs_free(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ panic("isa_free(): Help!");
+}
+
+void *
+isa_bs_vaddr(t, bsh)
+ void *t;
+ bus_space_handle_t bsh;
+{
+
+ return ((void *)bsh);
+}
+
+void
+isa_bs_barrier(t, bsh, offset, len, flags)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, len;
+ int flags;
+{
+ /* just return */
+}
diff --git a/sys/arch/arm/footbridge/isa/isa_io_asm.S b/sys/arch/arm/footbridge/isa/isa_io_asm.S
new file mode 100644
index 00000000000..6e618e161b6
--- /dev/null
+++ b/sys/arch/arm/footbridge/isa/isa_io_asm.S
@@ -0,0 +1,342 @@
+/* $OpenBSD: isa_io_asm.S,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: isa_io_asm.S,v 1.1 2002/02/10 12:26:01 chris Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Mark Brinicombe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 1997
+ * Digital Equipment Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and conditions.
+ * Subject to these conditions, you may download, copy, install,
+ * use, modify and distribute this software in source and/or binary
+ * form. No title or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions as
+ * they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or logo of
+ * Digital Equipment Corporation. Neither the "Digital Equipment
+ * Corporation" name nor any trademark or logo of Digital Equipment
+ * Corporation may be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Digital Equipment Corporation.
+ *
+ * 3) This software is provided "AS-IS" and any express or implied
+ * warranties, including but not limited to, any implied warranties
+ * of merchantability, fitness for a particular purpose, or
+ * non-infringement are disclaimed. In no event shall DIGITAL be
+ * liable for any damages whatsoever, and in particular, DIGITAL
+ * shall not be liable for special, indirect, consequential, or
+ * incidental damages or damages for lost profits, loss of
+ * revenue or loss of use, whether such damages arise in contract,
+ * negligence, tort, under statute, in equity, at law or otherwise,
+ * even if advised of the possibility of such damage.
+ */
+
+/*
+ * bus_space I/O functions for isa
+ */
+
+#include <machine/asm.h>
+
+#ifdef GPROF
+#define PAUSE nop ; nop ; nop ; nop ; nop
+#else
+#define PAUSE
+#endif
+
+/*
+ * Note these functions use ARM Architecture V4 instructions as
+ * all current systems with ISA will be using processors that support
+ * V4 or later architectures (SHARK & CATS)
+ */
+
+/*
+ * read single
+ */
+
+ENTRY(isa_bs_r_1)
+ ldrb r0, [r1, r2]
+ PAUSE
+ mov pc, lr
+
+ENTRY(isa_bs_r_2)
+ ldrh r0, [r1, r2] /*.word 0xe19100b2*/
+ PAUSE
+ mov pc, lr
+
+ENTRY(isa_bs_r_4)
+ ldr r0, [r1, r2]
+ PAUSE
+ mov pc, lr
+
+/*
+ * read multiple.
+ */
+
+ENTRY(isa_bs_rm_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_rm_1_loop:
+ ldrb r3, [r0]
+ strb r3, [r1], #1
+ subs r2, r2, #1
+ bne Lisa_rm_1_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_rm_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_rm_2_loop:
+ ldrh r3, [r0] /*.word 0xe1d030b0*/
+ strh r3, [r1], #2 /*.word 0xe0c130b2*/
+ subs r2, r2, #1
+ bne Lisa_rm_2_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_rm_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_rm_4_loop:
+ ldr r3, [r0]
+ str r3, [r1], #4
+ subs r2, r2, #1
+ bne Lisa_rm_4_loop
+
+ mov pc, lr
+
+/*
+ * read region.
+ */
+
+ENTRY(isa_bs_rr_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_rr_1_loop:
+ ldrb r3, [r0], #1
+ strb r3, [r1], #1
+ subs r2, r2, #1
+ bne Lisa_rr_1_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_rr_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_rr_2_loop:
+ ldrh r3, [r0], #2
+ strh r3, [r1], #2 /*.word 0xe0c130b2*/
+ subs r2, r2, #1
+ bne Lisa_rr_2_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_rr_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_rr_4_loop:
+ ldr r3, [r0], #4
+ str r3, [r1], #4
+ subs r2, r2, #1
+ bne Lisa_rr_4_loop
+
+ mov pc, lr
+
+/*
+ * write single
+ */
+
+ENTRY(isa_bs_w_1)
+ strb r3, [r1, r2]
+ PAUSE
+ mov pc, lr
+
+ENTRY(isa_bs_w_2)
+ strh r3, [r1, r2] /*.word 0xe18130b2*/
+ PAUSE
+ mov pc, lr
+
+ENTRY(isa_bs_w_4)
+ str r3, [r1, r2]
+ PAUSE
+ mov pc, lr
+
+/*
+ * write multiple
+ */
+
+ENTRY(isa_bs_wm_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_wm_1_loop:
+ ldrb r3, [r1], #1
+ strb r3, [r0]
+ subs r2, r2, #1
+ bne Lisa_wm_1_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_wm_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_wm_2_loop:
+ ldrh r3, [r1], #2 /*.word 0xe0d130b2*/
+ strh r3, [r0] /*.word 0xe1c030b0*/
+ subs r2, r2, #1
+ bne Lisa_wm_2_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_wm_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_wm_4_loop:
+ ldr r3, [r1], #4
+ str r3, [r0]
+ subs r2, r2, #1
+ bne Lisa_wm_4_loop
+
+ mov pc, lr
+
+
+/*
+ * write region.
+ */
+
+ENTRY(isa_bs_wr_1)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_wr_1_loop:
+ ldrb r3, [r1], #1
+ strb r3, [r0], #1
+ subs r2, r2, #1
+ bne Lisa_wr_1_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_wr_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_wr_2_loop:
+ ldrh r3, [r1], #2 /*.word 0xe0d130b2*/
+ strh r3, [r0], #2
+ subs r2, r2, #1
+ bne Lisa_wr_2_loop
+
+ mov pc, lr
+
+ENTRY(isa_bs_wr_4)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_wr_4_loop:
+ ldr r3, [r1], #4
+ str r3, [r0], #4
+ subs r2, r2, #1
+ bne Lisa_wr_4_loop
+
+ mov pc, lr
+
+/*
+ * Set region
+ */
+
+ENTRY(isa_bs_sr_2)
+ add r0, r1, r2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ teq r2, #0
+ moveq pc, lr
+
+Lisa_bs_sr_2_loop:
+ strh r1, [r0], #2 /*.word e0c010b2*/
+ subs r2, r2, #1
+ bne Lisa_bs_sr_2_loop
+
+ mov pc, lr
diff --git a/sys/arch/arm/footbridge/isa/isa_machdep.c b/sys/arch/arm/footbridge/isa/isa_machdep.c
new file mode 100644
index 00000000000..8927d26ddd6
--- /dev/null
+++ b/sys/arch/arm/footbridge/isa/isa_machdep.c
@@ -0,0 +1,609 @@
+/* $OpenBSD: isa_machdep.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: isa_machdep.c,v 1.4 2003/06/16 20:00:57 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1996-1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Mark Brinicombe, Charles M. Hannum and by Jason R. Thorpe of the
+ * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)isa.c 7.2 (Berkeley) 5/13/91
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
+#include <machine/intr.h>
+#include <machine/pio.h>
+#include <machine/bootconfig.h>
+#include <machine/isa_machdep.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+#include <dev/isa/isadmareg.h>
+#include <dev/isa/isadmavar.h>
+#include <arm/footbridge/isa/icu.h>
+#include <arm/footbridge/dc21285reg.h>
+#include <arm/footbridge/dc21285mem.h>
+
+#include <uvm/uvm_extern.h>
+
+#include "isadma.h"
+
+/* prototypes */
+static void isa_icu_init __P((void));
+
+struct arm32_isa_chipset isa_chipset_tag;
+
+void isa_strayintr __P((int));
+void intr_calculatemasks __P((void));
+int fakeintr __P((void *));
+
+int isa_irqdispatch __P((void *arg));
+
+u_int imask[NIPL];
+unsigned imen;
+
+#define AUTO_EOI_1
+#define AUTO_EOI_2
+
+/*
+ * Fill in default interrupt table (in case of spuruious interrupt
+ * during configuration of kernel, setup interrupt control unit
+ */
+static void
+isa_icu_init(void)
+{
+ /* initialize 8259's */
+ outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU1+1, ICU_OFFSET); /* starting at this vector index */
+ outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */
+#ifdef AUTO_EOI_1
+ outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU1+1, 1); /* 8086 mode */
+#endif
+ outb(IO_ICU1+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU1, 0x68); /* special mask mode (if available) */
+ outb(IO_ICU1, 0x0a); /* Read IRR by default. */
+#ifdef REORDER_IRQ
+ outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
+#endif
+
+ outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
+ outb(IO_ICU2+1, ICU_OFFSET+8); /* staring at this vector index */
+ outb(IO_ICU2+1, IRQ_SLAVE);
+#ifdef AUTO_EOI_2
+ outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */
+#else
+ outb(IO_ICU2+1, 1); /* 8086 mode */
+#endif
+ outb(IO_ICU2+1, 0xff); /* leave interrupts masked */
+ outb(IO_ICU2, 0x68); /* special mask mode (if available) */
+ outb(IO_ICU2, 0x0a); /* Read IRR by default. */
+}
+
+/*
+ * Caught a stray interrupt, notify
+ */
+void
+isa_strayintr(irq)
+ int irq;
+{
+ static u_long strays;
+
+ /*
+ * Stray interrupts on irq 7 occur when an interrupt line is raised
+ * and then lowered before the CPU acknowledges it. This generally
+ * means either the device is screwed or something is cli'ing too
+ * long and it's timing out.
+ */
+ if (++strays <= 5)
+ log(LOG_ERR, "stray interrupt %d%s\n", irq,
+ strays >= 5 ? "; stopped logging" : "");
+}
+
+static struct intrq isa_intrq[ICU_LEN];
+
+/*
+ * Recalculate the interrupt masks from scratch.
+ * We could code special registry and deregistry versions of this function that
+ * would be faster, but the code would be nastier, and we don't expect this to
+ * happen very much anyway.
+ */
+void
+intr_calculatemasks()
+{
+ int irq, level;
+ struct intrq *iq;
+ struct intrhand *ih;
+
+ /* First, figure out which levels each IRQ uses. */
+ for (irq = 0; irq < ICU_LEN; irq++) {
+ int levels = 0;
+ iq = &isa_intrq[irq];
+ for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
+ ih = TAILQ_NEXT(ih, ih_list))
+ levels |= (1U << ih->ih_ipl);
+ iq->iq_levels = levels;
+ }
+
+ /* Then figure out which IRQs use each level. */
+ for (level = 0; level < NIPL; level++) {
+ int irqs = 0;
+ for (irq = 0; irq < ICU_LEN; irq++)
+ if (isa_intrq[irq].iq_levels & (1U << level))
+ irqs |= (1U << irq);
+ imask[level] = irqs;
+ }
+
+ /*
+ * IPL_NONE is used for hardware interrupts that are never blocked,
+ * and do not block anything else.
+ */
+ imask[IPL_NONE] = 0;
+
+ imask[IPL_SOFT] |= imask[IPL_NONE];
+ imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT];
+ imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
+
+ /*
+ * Enforce a hierarchy that gives slow devices a better chance at not
+ * dropping data.
+ */
+ imask[IPL_BIO] |= imask[IPL_SOFTCLOCK];
+ imask[IPL_NET] |= imask[IPL_BIO];
+ imask[IPL_SOFTSERIAL] |= imask[IPL_NET];
+ imask[IPL_TTY] |= imask[IPL_NET];
+ /*
+ * There are tty, network and disk drivers that use free() at interrupt
+ * time, so imp > (tty | net | bio).
+ */
+ imask[IPL_VM] |= imask[IPL_TTY];
+ imask[IPL_AUDIO] |= imask[IPL_VM];
+
+ /*
+ * Since run queues may be manipulated by both the statclock and tty,
+ * network, and disk drivers, clock > imp.
+ */
+ imask[IPL_CLOCK] |= imask[IPL_VM];
+ imask[IPL_STATCLOCK] |= imask[IPL_CLOCK];
+
+ /*
+ * IPL_HIGH must block everything that can manipulate a run queue.
+ */
+ imask[IPL_HIGH] |= imask[IPL_STATCLOCK];
+
+ /*
+ * We need serial drivers to run at the absolute highest priority to
+ * avoid overruns, so serial > high.
+ */
+ imask[IPL_SERIAL] |= imask[IPL_HIGH];
+
+ /* And eventually calculate the complete masks. */
+ for (irq = 0; irq < ICU_LEN; irq++) {
+ int irqs = 1 << irq;
+ iq = &isa_intrq[irq];
+ for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL;
+ ih = TAILQ_NEXT(ih, ih_list))
+ irqs |= imask[ih->ih_ipl];
+ iq->iq_mask = irqs;
+ }
+
+ /* Lastly, determine which IRQs are actually in use. */
+ {
+ int irqs = 0;
+ for (irq = 0; irq < ICU_LEN; irq++)
+ if (!TAILQ_EMPTY(&isa_intrq[irq].iq_list))
+ irqs |= (1U << irq);
+ if (irqs >= 0x100) /* any IRQs >= 8 in use */
+ irqs |= 1 << IRQ_SLAVE;
+ imen = ~irqs;
+ SET_ICUS();
+ }
+#if 0
+ printf("type\tmask\tlevel\thand\n");
+ for (irq = 0; irq < ICU_LEN; irq++) {
+ printf("%x\t%04x\t%x\t%p\n", intrtype[irq], intrmask[irq],
+ intrlevel[irq], intrhand[irq]);
+ }
+ for (level = 0; level < IPL_LEVELS; ++level)
+ printf("%d: %08x\n", level, imask[level]);
+#endif
+}
+
+int
+fakeintr(arg)
+ void *arg;
+{
+
+ return 0;
+}
+
+#define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
+
+int
+isa_intr_alloc(ic, mask, type, irq)
+ isa_chipset_tag_t ic;
+ int mask;
+ int type;
+ int *irq;
+{
+ int i, tmp, bestirq, count;
+ struct intrq *iq;
+ struct intrhand *ih;
+
+ if (type == IST_NONE)
+ panic("intr_alloc: bogus type");
+
+ bestirq = -1;
+ count = -1;
+
+ /* some interrupts should never be dynamically allocated */
+ mask &= 0xdef8;
+
+ /*
+ * XXX some interrupts will be used later (6 for fdc, 12 for pms).
+ * the right answer is to do "breadth-first" searching of devices.
+ */
+ mask &= 0xefbf;
+
+ for (i = 0; i < ICU_LEN; i++) {
+ if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
+ continue;
+
+ iq = &isa_intrq[i];
+ switch(iq->iq_ist) {
+ case IST_NONE:
+ /*
+ * if nothing's using the irq, just return it
+ */
+ *irq = i;
+ return (0);
+
+ case IST_EDGE:
+ case IST_LEVEL:
+ if (type != iq->iq_ist)
+ continue;
+ /*
+ * if the irq is shareable, count the number of other
+ * handlers, and if it's smaller than the last irq like
+ * this, remember it
+ *
+ * XXX We should probably also consider the
+ * interrupt level and stick IPL_TTY with other
+ * IPL_TTY, etc.
+ */
+ tmp = 0;
+ TAILQ_FOREACH(ih, &(iq->iq_list), ih_list)
+ tmp++;
+ if ((bestirq == -1) || (count > tmp)) {
+ bestirq = i;
+ count = tmp;
+ }
+ break;
+
+ case IST_PULSE:
+ /* this just isn't shareable */
+ continue;
+ }
+ }
+
+ if (bestirq == -1)
+ return (1);
+
+ *irq = bestirq;
+
+ return (0);
+}
+
+const struct evcnt *
+isa_intr_evcnt(isa_chipset_tag_t ic, int irq)
+{
+ return &isa_intrq[irq].iq_ev;
+}
+
+/*
+ * Set up an interrupt handler to start being called.
+ * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM.
+ */
+void *
+isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg, name)
+ isa_chipset_tag_t ic;
+ int irq;
+ int type;
+ int level;
+ int (*ih_fun) __P((void *));
+ void *ih_arg;
+ char *name;
+{
+ struct intrq *iq;
+ struct intrhand *ih;
+ u_int oldirqstate;
+
+#if 0
+ printf("isa_intr_establish(%d, %d, %d)\n", irq, type, level);
+#endif
+ /* no point in sleeping unless someone can free memory. */
+ ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
+ if (ih == NULL)
+ return (NULL);
+
+ if (!LEGAL_IRQ(irq) || type == IST_NONE)
+ panic("intr_establish: bogus irq or type");
+
+ iq = &isa_intrq[irq];
+
+ switch (iq->iq_ist) {
+ case IST_NONE:
+ iq->iq_ist = type;
+#if 0
+ printf("Setting irq %d to type %d - ", irq, type);
+#endif
+ if (irq < 8) {
+ outb(0x4d0, (inb(0x4d0) & ~(1 << irq))
+ | ((type == IST_LEVEL) ? (1 << irq) : 0));
+/* printf("%02x\n", inb(0x4d0));*/
+ } else {
+ outb(0x4d1, (inb(0x4d1) & ~(1 << irq))
+ | ((type == IST_LEVEL) ? (1 << irq) : 0));
+/* printf("%02x\n", inb(0x4d1));*/
+ }
+ break;
+ case IST_EDGE:
+ case IST_LEVEL:
+ if (iq->iq_ist == type)
+ break;
+ case IST_PULSE:
+ if (type != IST_NONE)
+ panic("intr_establish: can't share %s with %s",
+ isa_intr_typename(iq->iq_ist),
+ isa_intr_typename(type));
+ break;
+ }
+
+ ih->ih_func = ih_fun;
+ ih->ih_arg = ih_arg;
+ ih->ih_ipl = level;
+ ih->ih_irq = irq;
+
+ /* do not stop us */
+ oldirqstate = disable_interrupts(I32_bit);
+
+ TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
+
+ intr_calculatemasks();
+ restore_interrupts(oldirqstate);
+
+ return (ih);
+}
+
+/*
+ * Deregister an interrupt handler.
+ */
+void
+isa_intr_disestablish(ic, arg)
+ isa_chipset_tag_t ic;
+ void *arg;
+{
+ struct intrhand *ih = arg;
+ struct intrq *iq = &isa_intrq[ih->ih_irq];
+ int irq = ih->ih_irq;
+ u_int oldirqstate;
+
+ if (!LEGAL_IRQ(irq))
+ panic("intr_disestablish: bogus irq");
+
+ oldirqstate = disable_interrupts(I32_bit);
+
+ TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
+
+ intr_calculatemasks();
+
+ restore_interrupts(oldirqstate);
+
+ free(ih, M_DEVBUF);
+
+ if (TAILQ_EMPTY(&(iq->iq_list)))
+ iq->iq_ist = IST_NONE;
+}
+
+/*
+ * isa_intr_init()
+ *
+ * Initialise the ISA ICU and attach an ISA interrupt handler to the
+ * ISA interrupt line on the footbridge.
+ */
+void
+isa_intr_init(void)
+{
+ static void *isa_ih;
+ struct intrq *iq;
+ int i;
+
+ /*
+ * should get the parent here, but initialisation order being so
+ * strange I need to check if it's available
+ */
+ for (i = 0; i < ICU_LEN; i++) {
+ iq = &isa_intrq[i];
+ TAILQ_INIT(&iq->iq_list);
+
+ snprintf(iq->iq_name, sizeof(iq->iq_name), "irq %d", i);
+#if 0
+ evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR,
+ NULL, "isa", iq->iq_name);
+#endif
+ }
+
+ isa_icu_init();
+ intr_calculatemasks();
+ /* something to break the build in an informative way */
+#ifndef ISA_FOOTBRIDGE_IRQ
+#warning Before using isa with footbridge you must define ISA_FOOTBRIDGE_IRQ
+#endif
+ isa_ih = footbridge_intr_claim(ISA_FOOTBRIDGE_IRQ, IPL_BIO, "isabus",
+ isa_irqdispatch, NULL);
+
+}
+
+/* Static array of ISA DMA segments. We only have one on CATS */
+#if NISADMA > 0
+struct arm32_dma_range machdep_isa_dma_ranges[1];
+#endif
+
+void
+isa_footbridge_init(iobase, membase)
+ u_int iobase, membase;
+{
+#if NISADMA > 0
+ extern struct arm32_dma_range *footbridge_isa_dma_ranges;
+ extern int footbridge_isa_dma_nranges;
+
+ machdep_isa_dma_ranges[0].dr_sysbase = bootconfig.dram[0].address;
+ machdep_isa_dma_ranges[0].dr_busbase = bootconfig.dram[0].address;
+ machdep_isa_dma_ranges[0].dr_len = (16 * 1024 * 1024);
+
+ footbridge_isa_dma_ranges = machdep_isa_dma_ranges;
+ footbridge_isa_dma_nranges = 1;
+#endif
+
+ isa_io_init(iobase, membase);
+}
+
+void
+isa_attach_hook(parent, self, iba)
+ struct device *parent, *self;
+ struct isabus_attach_args *iba;
+{
+ /*
+ * Since we can only have one ISA bus, we just use a single
+ * statically allocated ISA chipset structure. Pass it up
+ * now.
+ */
+ iba->iba_ic = &isa_chipset_tag;
+#if NISADMA > 0
+ isa_dma_init();
+#endif
+}
+
+int
+isa_irqdispatch(arg)
+ void *arg;
+{
+ struct clockframe *frame = arg;
+ int irq;
+ struct intrq *iq;
+ struct intrhand *ih;
+ u_int iack;
+ int res = 0;
+
+ iack = *((u_int *)(DC21285_PCI_IACK_VBASE));
+ iack &= 0xff;
+ if (iack < 0x20 || iack > 0x2f) {
+ printf("isa_irqdispatch: %x\n", iack);
+ return(0);
+ }
+
+ irq = iack & 0x0f;
+ iq = &isa_intrq[irq];
+ iq->iq_ev.ev_count++;
+ for (ih = TAILQ_FIRST(&iq->iq_list); res != 1 && ih != NULL;
+ ih = TAILQ_NEXT(ih, ih_list)) {
+ res = (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame);
+ }
+ return res;
+}
+
+
+void
+isa_fillw(val, addr, len)
+ u_int val;
+ void *addr;
+ size_t len;
+{
+ if ((u_int)addr >= isa_mem_data_vaddr()
+ && (u_int)addr < isa_mem_data_vaddr() + 0x100000) {
+ bus_size_t offset = ((u_int)addr) & 0xfffff;
+ bus_space_set_region_2(&isa_mem_bs_tag,
+ (bus_space_handle_t)isa_mem_bs_tag.bs_cookie, offset,
+ val, len);
+ } else {
+ u_short *ptr = addr;
+
+ while (len > 0) {
+ *ptr++ = val;
+ --len;
+ }
+ }
+}
diff --git a/sys/arch/arm/footbridge/isa/sysbeep_isa.c b/sys/arch/arm/footbridge/isa/sysbeep_isa.c
new file mode 100644
index 00000000000..71032afebf5
--- /dev/null
+++ b/sys/arch/arm/footbridge/isa/sysbeep_isa.c
@@ -0,0 +1,90 @@
+/* $OpenBSD: sysbeep_isa.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: sysbeep_isa.c,v 1.4 2002/10/02 15:45:10 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Mark Brinicombe of Causality Limited.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <dev/isa/isavar.h>
+
+#include <dev/isa/pcppivar.h>
+
+/* Prototypes */
+int sysbeep_isa_match __P((struct device *parent, void *cf, void *aux));
+void sysbeep_isa_attach __P((struct device *parent, struct device *self, void *aux));
+void sysbeep_isa __P((int pitch, int period));
+
+/* device attach structure */
+struct cfattach sysbeep_isa_ca = {
+ sizeof (struct device), sysbeep_isa_match, sysbeep_isa_attach
+};
+
+struct cfdriver sysbeep_cd = {
+ NULL, "sysbeep_isa", DV_DULL
+};
+
+static int ppi_attached;
+static pcppi_tag_t ppicookie;
+
+int
+sysbeep_isa_match(parent, match, aux)
+ struct device *parent;
+ void *match;
+ void *aux;
+{
+ return (!ppi_attached);
+}
+
+void
+sysbeep_isa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ printf("\n");
+
+ ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie;
+ ppi_attached = 1;
+}
+
+void
+sysbeep(pitch, period)
+ int pitch, period;
+{
+ if (ppi_attached)
+ pcppi_bell(ppicookie, pitch, period, 0);
+}
diff --git a/sys/arch/arm/footbridge/todclock.c b/sys/arch/arm/footbridge/todclock.c
new file mode 100644
index 00000000000..642724d749c
--- /dev/null
+++ b/sys/arch/arm/footbridge/todclock.c
@@ -0,0 +1,348 @@
+/* $OpenBSD: todclock.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: todclock.c,v 1.4 2002/10/02 05:02:30 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994-1997 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * clock.c
+ *
+ * Timer related machine specific code
+ *
+ * Created : 29/09/94
+ */
+
+/* Include header files */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/device.h>
+
+#include <machine/rtc.h>
+#include <arm/footbridge/todclockvar.h>
+
+#include "todclock.h"
+
+#if NTODCLOCK > 1
+#error "Can only had 1 todclock device"
+#endif
+
+static int yeartoday __P((int));
+
+/*
+ * softc structure for the todclock device
+ */
+
+struct todclock_softc {
+ struct device sc_dev; /* device node */
+ void *sc_rtc_arg; /* arg to read/write */
+ int (*sc_rtc_write) __P((void *, rtc_t *)); /* rtc write function */
+ int (*sc_rtc_read) __P((void *, rtc_t *)); /* rtc read function */
+};
+
+/* prototypes for functions */
+
+static void todclockattach (struct device *parent, struct device *self,
+ void *aux);
+static int todclockmatch (struct device *parent, void *cf, void *aux);
+
+/*
+ * We need to remember our softc for functions like inittodr()
+ * and resettodr()
+ * since we only ever have one time-of-day device we can just store
+ * the direct pointer to softc.
+ */
+
+static struct todclock_softc *todclock_sc = NULL;
+
+/* driver and attach structures */
+
+struct cfattach todclock_ca = {
+ sizeof(struct todclock_softc), todclockmatch, todclockattach
+};
+
+struct cfdriver todclock_cd = {
+ NULL, "todclock", DV_DULL
+};
+
+
+/*
+ * int todclockmatch(struct device *parent, struct cfdata *cf, void *aux)
+ *
+ * todclock device probe function.
+ * just validate the attach args
+ */
+
+int
+todclockmatch(parent, cf, aux)
+ struct device *parent;
+ void *cf;
+ void *aux;
+{
+ struct todclock_attach_args *ta = aux;
+
+ if (todclock_sc != NULL)
+ return(0);
+ if (strcmp(ta->ta_name, "todclock") != 0)
+ return(0);
+
+ if (ta->ta_flags & TODCLOCK_FLAG_FAKE)
+ return(1);
+ return(2);
+}
+
+/*
+ * void todclockattach(struct device *parent, struct device *self, void *aux)
+ *
+ * todclock device attach function.
+ * Initialise the softc structure and do a search for children
+ */
+
+void
+todclockattach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ struct todclock_softc *sc = (void *)self;
+ struct todclock_attach_args *ta = aux;
+
+ /* set up our softc */
+ todclock_sc = sc;
+ todclock_sc->sc_rtc_arg = ta->ta_rtc_arg;
+ todclock_sc->sc_rtc_write = ta->ta_rtc_write;
+ todclock_sc->sc_rtc_read = ta->ta_rtc_read;
+
+ printf("\n");
+
+ /*
+ * Initialise the time of day register.
+ * This is normally left to the filing system to do but not all
+ * filing systems call it e.g. cd9660
+ */
+
+ inittodr(0);
+}
+
+static __inline int
+yeartoday(year)
+ int year;
+{
+ return((year % 4) ? 365 : 366);
+}
+
+
+static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+static int timeset = 0;
+
+#define SECPERDAY (24*60*60)
+#define SECPERNYEAR (365*SECPERDAY)
+#define SECPER4YEARS (4*SECPERNYEAR+SECPERDAY)
+#define EPOCHYEAR 1970
+
+/*
+ * Globally visable functions
+ *
+ * These functions are used from other parts of the kernel.
+ * These functions use the functions defined in the tod_sc
+ * to actually read and write the rtc.
+ *
+ * The first todclock to be attached will be used for handling
+ * the time of day.
+ */
+
+/*
+ * Write back the time of day to the rtc
+ */
+
+void
+resettodr()
+{
+ int s;
+ time_t year, mon, day, hour, min, sec;
+ rtc_t rtc;
+
+ /* Have we set the system time in inittodr() */
+ if (!timeset)
+ return;
+
+ /* We need a todclock device and should always have one */
+ if (!todclock_sc)
+ return;
+
+ /* Abort early if there is not actually an RTC write routine */
+ if (todclock_sc->sc_rtc_write == NULL)
+ return;
+
+ sec = time.tv_sec;
+ sec -= tz.tz_minuteswest * 60;
+ if (tz.tz_dsttime)
+ time.tv_sec += 3600;
+ year = (sec / SECPER4YEARS) * 4;
+ sec %= SECPER4YEARS;
+
+ /* year now hold the number of years rounded down 4 */
+
+ while (sec > (yeartoday(EPOCHYEAR+year) * SECPERDAY)) {
+ sec -= yeartoday(EPOCHYEAR+year)*SECPERDAY;
+ year++;
+ }
+
+ /* year is now a correct offset from the EPOCHYEAR */
+
+ year+=EPOCHYEAR;
+ mon=0;
+ if (yeartoday(year) == 366)
+ month[1]=29;
+ else
+ month[1]=28;
+ while (sec >= month[mon]*SECPERDAY) {
+ sec -= month[mon]*SECPERDAY;
+ mon++;
+ }
+
+ day = sec / SECPERDAY;
+ sec %= SECPERDAY;
+ hour = sec / 3600;
+ sec %= 3600;
+ min = sec / 60;
+ sec %= 60;
+ rtc.rtc_cen = year / 100;
+ rtc.rtc_year = year % 100;
+ rtc.rtc_mon = mon+1;
+ rtc.rtc_day = day+1;
+ rtc.rtc_hour = hour;
+ rtc.rtc_min = min;
+ rtc.rtc_sec = sec;
+ rtc.rtc_centi =
+ rtc.rtc_micro = 0;
+
+ printf("resettod: %02d/%02d/%02d%02d %02d:%02d:%02d\n", rtc.rtc_day,
+ rtc.rtc_mon, rtc.rtc_cen, rtc.rtc_year, rtc.rtc_hour,
+ rtc.rtc_min, rtc.rtc_sec);
+
+ s = splclock();
+ todclock_sc->sc_rtc_write(todclock_sc->sc_rtc_arg, &rtc);
+ (void)splx(s);
+}
+
+/*
+ * Initialise the time of day register, based on the time base which is, e.g.
+ * from a filesystem.
+ */
+
+void
+inittodr(base)
+ time_t base;
+{
+ time_t n;
+ int i, days = 0;
+ int s;
+ int year;
+ rtc_t rtc;
+
+ /*
+ * Default to the suggested time but replace that we one from an
+ * RTC is we can.
+ */
+
+ /* We expect a todclock device */
+
+ /* Use the suggested time as a fall back */
+ time.tv_sec = base;
+ time.tv_usec = 0;
+
+ /* Can we read an RTC ? */
+ if (todclock_sc->sc_rtc_read) {
+ s = splclock();
+ if (todclock_sc->sc_rtc_read(todclock_sc->sc_rtc_arg, &rtc) == 0) {
+ (void)splx(s);
+ return;
+ }
+ (void)splx(s);
+ } else
+ return;
+
+ /* Convert the rtc time into seconds */
+
+ n = rtc.rtc_sec + 60 * rtc.rtc_min + 3600 * rtc.rtc_hour;
+ n += (rtc.rtc_day - 1) * 3600 * 24;
+ year = (rtc.rtc_year + rtc.rtc_cen * 100) - 1900;
+
+ if (yeartoday(year) == 366)
+ month[1] = 29;
+ for (i = rtc.rtc_mon - 2; i >= 0; i--)
+ days += month[i];
+ month[1] = 28;
+
+ for (i = 70; i < year; i++)
+ days += yeartoday(i);
+
+ n += days * 3600 * 24;
+
+ n += tz.tz_minuteswest * 60;
+ if (tz.tz_dsttime)
+ time.tv_sec -= 3600;
+
+ time.tv_sec = n;
+ time.tv_usec = 0;
+
+ /* timeset is used to ensure the time is valid before a resettodr() */
+
+ timeset = 1;
+
+ /* If the base was 0 then keep quiet */
+
+ if (base) {
+ printf("inittodr: %02d:%02d:%02d.%02d%02d %02d/%02d/%02d%02d\n",
+ rtc.rtc_hour, rtc.rtc_min, rtc.rtc_sec, rtc.rtc_centi,
+ rtc.rtc_micro, rtc.rtc_day, rtc.rtc_mon, rtc.rtc_cen,
+ rtc.rtc_year);
+
+ if (n > base + 60) {
+ days = (n - base) / SECPERDAY;
+ printf("Clock has gained %d day%c %ld hours %ld minutes %ld secs\n",
+ days, ((days == 1) ? 0 : 's'),
+ (long)((n - base) / 3600) % 24,
+ (long)((n - base) / 60) % 60,
+ (long) (n - base) % 60);
+ }
+ }
+}
+
+/* End of todclock.c */
diff --git a/sys/arch/arm/footbridge/todclockvar.h b/sys/arch/arm/footbridge/todclockvar.h
new file mode 100644
index 00000000000..58d296d0fa6
--- /dev/null
+++ b/sys/arch/arm/footbridge/todclockvar.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: todclockvar.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: todclockvar.h,v 1.1 2002/02/10 12:26:00 chris Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * todclockvar.h
+ *
+ * structures and variables for the todclock device
+ *
+ * Created : 12/02/97
+ */
+
+/*
+ * Attach args for todclock device
+ */
+
+struct todclock_attach_args {
+ const char *ta_name; /* device name */
+ void *ta_rtc_arg; /* arg to read/write */
+ int (*ta_rtc_write) __P((void *, rtc_t *)); /* function to write rtc */
+ int (*ta_rtc_read) __P((void *, rtc_t *)); /* function to read rtc */
+ int ta_flags; /* flags */
+#define TODCLOCK_FLAG_FAKE 0x01 /* tod service is faked */
+};
+
+/* End of todclockvar.h */
diff --git a/sys/arch/arm/include/ansi.h b/sys/arch/arm/include/ansi.h
new file mode 100644
index 00000000000..466a195e1b3
--- /dev/null
+++ b/sys/arch/arm/include/ansi.h
@@ -0,0 +1,109 @@
+/* $OpenBSD: ansi.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: ansi.h,v 1.4 2003/03/02 22:18:17 tshiozak Exp $ */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ansi.h 8.2 (Berkeley) 1/4/94
+ */
+
+#ifndef _ANSI_H_
+#define _ANSI_H_
+
+#if 0
+#include <machine/types.h>
+#endif
+
+/*
+ * Types which are fundamental to the implementation and may appear in
+ * more than one standard header are defined here. Standard headers
+ * then use:
+ * #ifdef _BSD_SIZE_T_
+ * typedef _BSD_SIZE_T_ size_t;
+ * #undef _BSD_SIZE_T_
+ * #endif
+ */
+#ifdef __ELF__
+#define _BSD_CLOCK_T_ unsigned int /* clock() */
+#define _BSD_PTRDIFF_T_ long int /* ptr1 - ptr2 */
+#define _BSD_SIZE_T_ unsigned long int /* sizeof() */
+#define _BSD_SSIZE_T_ long int /* byte count or error */
+#define _BSD_TIME_T_ int /* time() */
+#else
+#define _BSD_CLOCK_T_ unsigned long /* clock() */
+#define _BSD_PTRDIFF_T_ int /* ptr1 - ptr2 */
+#define _BSD_SIZE_T_ unsigned int /* sizeof() */
+#define _BSD_SSIZE_T_ int /* byte count or error */
+#define _BSD_TIME_T_ long /* time() */
+#endif
+#define _BSD_VA_LIST_ __builtin_va_list /* va_list */
+#define _BSD_CLOCKID_T_ int /* clockid_t */
+#define _BSD_TIMER_T_ int /* timer_t */
+#define _BSD_SUSECONDS_T_ int /* suseconds_t */
+#define _BSD_USECONDS_T_ unsigned int /* useconds_t */
+
+/*
+ * NOTE: rune_t is not covered by ANSI nor other standards, and should not
+ * be instantiated outside of lib/libc/locale. use wchar_t.
+ *
+ * Runes (wchar_t) is declared to be an ``int'' instead of the more natural
+ * ``unsigned long'' or ``long''. Two things are happening here. It is not
+ * unsigned so that EOF (-1) can be naturally assigned to it and used. Also,
+ * it looks like 10646 will be a 31 bit standard. This means that if your
+ * ints cannot hold 32 bits, you will be in trouble. The reason an int was
+ * chosen over a long is that the is*() and to*() routines take ints (says
+ * ANSI C), but they use _RUNE_T_ instead of int. By changing it here, you
+ * lose a bit of ANSI conformance, but your programs will still work.
+ *
+ * Note that _WCHAR_T_ and _RUNE_T_ must be of the same type. When wchar_t
+ * and rune_t are typedef'd, _WCHAR_T_ will be undef'd, but _RUNE_T remains
+ * defined for ctype.h.
+ */
+#define _BSD_WCHAR_T_ int /* wchar_t */
+#define _BSD_WINT_T_ int /* wint_t */
+#define _BSD_RUNE_T_ int /* rune_t */
+#define _BSD_WCTRANS_T_ void * /* wctrans_t */
+#define _BSD_WCTYPE_T_ void * /* wctype_t */
+
+/*
+ * mbstate_t is an opaque object to keep conversion state, during multibyte
+ * stream conversions. The content must not be referenced by user programs.
+ */
+typedef union {
+ char __mbstate8[128];
+ long long __mbstateL; /* for alignment */
+} __mbstate_t;
+#define _BSD_MBSTATE_T_ __mbstate_t /* mbstate_t */
+
+/*
+ * We describe off_t here so its declaration can be visible to
+ * stdio without pulling in all of <sys/type.h>, thus appeasing ANSI.
+ */
+#define _BSD_OFF_T_ long long /* file offset */
+
+#endif /* _ANSI_H_ */
diff --git a/sys/arch/arm/include/armreg.h b/sys/arch/arm/include/armreg.h
new file mode 100644
index 00000000000..f5c1ef567e9
--- /dev/null
+++ b/sys/arch/arm/include/armreg.h
@@ -0,0 +1,353 @@
+/* $OpenBSD: armreg.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: armreg.h,v 1.27 2003/09/06 08:43:02 rearnsha Exp $ */
+
+/*
+ * Copyright (c) 1998, 2001 Ben Harris
+ * Copyright (c) 1994-1996 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_ARMREG_H
+#define _ARM_ARMREG_H
+
+/*
+ * ARM Process Status Register
+ *
+ * The picture in the ARM manuals looks like this:
+ * 3 3 2 2 2 2
+ * 1 0 9 8 7 6 8 7 6 5 4 0
+ * +-+-+-+-+-+-------------------------------------+-+-+-+---------+
+ * |N|Z|C|V|Q| reserved |I|F|T|M M M M M|
+ * | | | | | | | | | |4 3 2 1 0|
+ * +-+-+-+-+-+-------------------------------------+-+-+-+---------+
+ */
+
+#define PSR_FLAGS 0xf0000000 /* flags */
+#define PSR_N_bit (1 << 31) /* negative */
+#define PSR_Z_bit (1 << 30) /* zero */
+#define PSR_C_bit (1 << 29) /* carry */
+#define PSR_V_bit (1 << 28) /* overflow */
+
+#define PSR_Q_bit (1 << 27) /* saturation */
+
+#define I32_bit (1 << 7) /* IRQ disable */
+#define F32_bit (1 << 6) /* FIQ disable */
+
+#define PSR_T_bit (1 << 5) /* Thumb state */
+#define PSR_J_bit (1 << 24) /* Java mode */
+
+#define PSR_MODE 0x0000001f /* mode mask */
+#define PSR_USR26_MODE 0x00000000
+#define PSR_FIQ26_MODE 0x00000001
+#define PSR_IRQ26_MODE 0x00000002
+#define PSR_SVC26_MODE 0x00000003
+#define PSR_USR32_MODE 0x00000010
+#define PSR_FIQ32_MODE 0x00000011
+#define PSR_IRQ32_MODE 0x00000012
+#define PSR_SVC32_MODE 0x00000013
+#define PSR_ABT32_MODE 0x00000017
+#define PSR_UND32_MODE 0x0000001b
+#define PSR_SYS32_MODE 0x0000001f
+#define PSR_32_MODE 0x00000010
+
+#define PSR_IN_USR_MODE(psr) (!((psr) & 3)) /* XXX */
+#define PSR_IN_32_MODE(psr) ((psr) & PSR_32_MODE)
+
+/* In 26-bit modes, the PSR is stuffed into R15 along with the PC. */
+
+#define R15_MODE 0x00000003
+#define R15_MODE_USR 0x00000000
+#define R15_MODE_FIQ 0x00000001
+#define R15_MODE_IRQ 0x00000002
+#define R15_MODE_SVC 0x00000003
+
+#define R15_PC 0x03fffffc
+
+#define R15_FIQ_DISABLE 0x04000000
+#define R15_IRQ_DISABLE 0x08000000
+
+#define R15_FLAGS 0xf0000000
+#define R15_FLAG_N 0x80000000
+#define R15_FLAG_Z 0x40000000
+#define R15_FLAG_C 0x20000000
+#define R15_FLAG_V 0x10000000
+
+/*
+ * Co-processor 15: The system control co-processor.
+ */
+
+#define ARM_CP15_CPU_ID 0
+
+/*
+ * The CPU ID register is theoretically structured, but the definitions of
+ * the fields keep changing.
+ */
+
+/* The high-order byte is always the implementor */
+#define CPU_ID_IMPLEMENTOR_MASK 0xff000000
+#define CPU_ID_ARM_LTD 0x41000000 /* 'A' */
+#define CPU_ID_DEC 0x44000000 /* 'D' */
+#define CPU_ID_INTEL 0x69000000 /* 'i' */
+#define CPU_ID_TI 0x54000000 /* 'T' */
+
+/* How to decide what format the CPUID is in. */
+#define CPU_ID_ISOLD(x) (((x) & 0x0000f000) == 0x00000000)
+#define CPU_ID_IS7(x) (((x) & 0x0000f000) == 0x00007000)
+#define CPU_ID_ISNEW(x) (!CPU_ID_ISOLD(x) && !CPU_ID_IS7(x))
+
+/* On ARM3 and ARM6, this byte holds the foundry ID. */
+#define CPU_ID_FOUNDRY_MASK 0x00ff0000
+#define CPU_ID_FOUNDRY_VLSI 0x00560000
+
+/* On ARM7 it holds the architecture and variant (sub-model) */
+#define CPU_ID_7ARCH_MASK 0x00800000
+#define CPU_ID_7ARCH_V3 0x00000000
+#define CPU_ID_7ARCH_V4T 0x00800000
+#define CPU_ID_7VARIANT_MASK 0x007f0000
+
+/* On more recent ARMs, it does the same, but in a different format */
+#define CPU_ID_ARCH_MASK 0x000f0000
+#define CPU_ID_ARCH_V3 0x00000000
+#define CPU_ID_ARCH_V4 0x00010000
+#define CPU_ID_ARCH_V4T 0x00020000
+#define CPU_ID_ARCH_V5 0x00030000
+#define CPU_ID_ARCH_V5T 0x00040000
+#define CPU_ID_ARCH_V5TE 0x00050000
+#define CPU_ID_VARIANT_MASK 0x00f00000
+
+/* Next three nybbles are part number */
+#define CPU_ID_PARTNO_MASK 0x0000fff0
+
+/* Intel XScale has sub fields in part number */
+#define CPU_ID_XSCALE_COREGEN_MASK 0x0000e000 /* core generation */
+#define CPU_ID_XSCALE_COREREV_MASK 0x00001c00 /* core revision */
+#define CPU_ID_XSCALE_PRODUCT_MASK 0x000003f0 /* product number */
+
+/* And finally, the revision number. */
+#define CPU_ID_REVISION_MASK 0x0000000f
+
+/* Individual CPUs are probably best IDed by everything but the revision. */
+#define CPU_ID_CPU_MASK 0xfffffff0
+
+/* Fake CPU IDs for ARMs without CP15 */
+#define CPU_ID_ARM2 0x41560200
+#define CPU_ID_ARM250 0x41560250
+
+/* Pre-ARM7 CPUs -- [15:12] == 0 */
+#define CPU_ID_ARM3 0x41560300
+#define CPU_ID_ARM600 0x41560600
+#define CPU_ID_ARM610 0x41560610
+#define CPU_ID_ARM620 0x41560620
+
+/* ARM7 CPUs -- [15:12] == 7 */
+#define CPU_ID_ARM700 0x41007000 /* XXX This is a guess. */
+#define CPU_ID_ARM710 0x41007100
+#define CPU_ID_ARM7500 0x41027100 /* XXX This is a guess. */
+#define CPU_ID_ARM710A 0x41047100 /* inc ARM7100 */
+#define CPU_ID_ARM7500FE 0x41077100
+#define CPU_ID_ARM710T 0x41807100
+#define CPU_ID_ARM720T 0x41807200
+#define CPU_ID_ARM740T8K 0x41807400 /* XXX no MMU, 8KB cache */
+#define CPU_ID_ARM740T4K 0x41817400 /* XXX no MMU, 4KB cache */
+
+/* Post-ARM7 CPUs */
+#define CPU_ID_ARM810 0x41018100
+#define CPU_ID_ARM920T 0x41129200
+#define CPU_ID_ARM922T 0x41029220
+#define CPU_ID_ARM940T 0x41029400 /* XXX no MMU */
+#define CPU_ID_ARM946ES 0x41049460 /* XXX no MMU */
+#define CPU_ID_ARM966ES 0x41049660 /* XXX no MMU */
+#define CPU_ID_ARM966ESR1 0x41059660 /* XXX no MMU */
+#define CPU_ID_ARM1020E 0x4115a200 /* (AKA arm10 rev 1) */
+#define CPU_ID_ARM1022ES 0x4105a220
+#define CPU_ID_SA110 0x4401a100
+#define CPU_ID_SA1100 0x4401a110
+#define CPU_ID_TI925T 0x54029250
+#define CPU_ID_SA1110 0x6901b110
+#define CPU_ID_IXP1200 0x6901c120
+#define CPU_ID_80200 0x69052000
+#define CPU_ID_PXA250 0x69052100 /* sans core revision */
+#define CPU_ID_PXA210 0x69052120
+#define CPU_ID_PXA250A 0x69052100 /* 1st version Core */
+#define CPU_ID_PXA210A 0x69052120 /* 1st version Core */
+#define CPU_ID_PXA250B 0x69052900 /* 3rd version Core */
+#define CPU_ID_PXA210B 0x69052920 /* 3rd version Core */
+#define CPU_ID_PXA250C 0x69052d00 /* 4th version Core */
+#define CPU_ID_PXA210C 0x69052d20 /* 4th version Core */
+#define CPU_ID_80321_400 0x69052420
+#define CPU_ID_80321_600 0x69052430
+#define CPU_ID_80321_400_B0 0x69052c20
+#define CPU_ID_80321_600_B0 0x69052c30
+#define CPU_ID_IXP425_533 0x690541c0
+#define CPU_ID_IXP425_400 0x690541d0
+#define CPU_ID_IXP425_266 0x690541f0
+
+/* ARM3-specific coprocessor 15 registers */
+#define ARM3_CP15_FLUSH 1
+#define ARM3_CP15_CONTROL 2
+#define ARM3_CP15_CACHEABLE 3
+#define ARM3_CP15_UPDATEABLE 4
+#define ARM3_CP15_DISRUPTIVE 5
+
+/* ARM3 Control register bits */
+#define ARM3_CTL_CACHE_ON 0x00000001
+#define ARM3_CTL_SHARED 0x00000002
+#define ARM3_CTL_MONITOR 0x00000004
+
+/*
+ * Post-ARM3 CP15 registers:
+ *
+ * 1 Control register
+ *
+ * 2 Translation Table Base
+ *
+ * 3 Domain Access Control
+ *
+ * 4 Reserved
+ *
+ * 5 Fault Status
+ *
+ * 6 Fault Address
+ *
+ * 7 Cache/write-buffer Control
+ *
+ * 8 TLB Control
+ *
+ * 9 Cache Lockdown
+ *
+ * 10 TLB Lockdown
+ *
+ * 11 Reserved
+ *
+ * 12 Reserved
+ *
+ * 13 Process ID (for FCSE)
+ *
+ * 14 Reserved
+ *
+ * 15 Implementation Dependent
+ */
+
+/* Some of the definitions below need cleaning up for V3/V4 architectures */
+
+/* CPU control register (CP15 register 1) */
+#define CPU_CONTROL_MMU_ENABLE 0x00000001 /* M: MMU/Protection unit enable */
+#define CPU_CONTROL_AFLT_ENABLE 0x00000002 /* A: Alignment fault enable */
+#define CPU_CONTROL_DC_ENABLE 0x00000004 /* C: IDC/DC enable */
+#define CPU_CONTROL_WBUF_ENABLE 0x00000008 /* W: Write buffer enable */
+#define CPU_CONTROL_32BP_ENABLE 0x00000010 /* P: 32-bit exception handlers */
+#define CPU_CONTROL_32BD_ENABLE 0x00000020 /* D: 32-bit addressing */
+#define CPU_CONTROL_LABT_ENABLE 0x00000040 /* L: Late abort enable */
+#define CPU_CONTROL_BEND_ENABLE 0x00000080 /* B: Big-endian mode */
+#define CPU_CONTROL_SYST_ENABLE 0x00000100 /* S: System protection bit */
+#define CPU_CONTROL_ROM_ENABLE 0x00000200 /* R: ROM protection bit */
+#define CPU_CONTROL_CPCLK 0x00000400 /* F: Implementation defined */
+#define CPU_CONTROL_BPRD_ENABLE 0x00000800 /* Z: Branch prediction enable */
+#define CPU_CONTROL_IC_ENABLE 0x00001000 /* I: IC enable */
+#define CPU_CONTROL_VECRELOC 0x00002000 /* V: Vector relocation */
+#define CPU_CONTROL_ROUNDROBIN 0x00004000 /* RR: Predictable replacement */
+#define CPU_CONTROL_V4COMPAT 0x00008000 /* L4: ARMv4 compat LDR R15 etc */
+
+#define CPU_CONTROL_IDC_ENABLE CPU_CONTROL_DC_ENABLE
+
+/* XScale Auxillary Control Register (CP15 register 1, opcode2 1) */
+#define XSCALE_AUXCTL_K 0x00000001 /* dis. write buffer coalescing */
+#define XSCALE_AUXCTL_P 0x00000002 /* ECC protect page table access */
+#define XSCALE_AUXCTL_MD_WB_RA 0x00000000 /* mini-D$ wb, read-allocate */
+#define XSCALE_AUXCTL_MD_WB_RWA 0x00000010 /* mini-D$ wb, read/write-allocate */
+#define XSCALE_AUXCTL_MD_WT 0x00000020 /* mini-D$ wt, read-allocate */
+#define XSCALE_AUXCTL_MD_MASK 0x00000030
+
+/* Cache type register definitions */
+#define CPU_CT_ISIZE(x) ((x) & 0xfff) /* I$ info */
+#define CPU_CT_DSIZE(x) (((x) >> 12) & 0xfff) /* D$ info */
+#define CPU_CT_S (1U << 24) /* split cache */
+#define CPU_CT_CTYPE(x) (((x) >> 25) & 0xf) /* cache type */
+
+#define CPU_CT_CTYPE_WT 0 /* write-through */
+#define CPU_CT_CTYPE_WB1 1 /* write-back, clean w/ read */
+#define CPU_CT_CTYPE_WB2 2 /* w/b, clean w/ cp15,7 */
+#define CPU_CT_CTYPE_WB6 6 /* w/b, cp15,7, lockdown fmt A */
+#define CPU_CT_CTYPE_WB7 7 /* w/b, cp15,7, lockdown fmt B */
+
+#define CPU_CT_xSIZE_LEN(x) ((x) & 0x3) /* line size */
+#define CPU_CT_xSIZE_M (1U << 2) /* multiplier */
+#define CPU_CT_xSIZE_ASSOC(x) (((x) >> 3) & 0x7) /* associativity */
+#define CPU_CT_xSIZE_SIZE(x) (((x) >> 6) & 0x7) /* size */
+
+/* Fault status register definitions */
+
+#define FAULT_TYPE_MASK 0x0f
+#define FAULT_USER 0x10
+
+#define FAULT_WRTBUF_0 0x00 /* Vector Exception */
+#define FAULT_WRTBUF_1 0x02 /* Terminal Exception */
+#define FAULT_BUSERR_0 0x04 /* External Abort on Linefetch -- Section */
+#define FAULT_BUSERR_1 0x06 /* External Abort on Linefetch -- Page */
+#define FAULT_BUSERR_2 0x08 /* External Abort on Non-linefetch -- Section */
+#define FAULT_BUSERR_3 0x0a /* External Abort on Non-linefetch -- Page */
+#define FAULT_BUSTRNL1 0x0c /* External abort on Translation -- Level 1 */
+#define FAULT_BUSTRNL2 0x0e /* External abort on Translation -- Level 2 */
+#define FAULT_ALIGN_0 0x01 /* Alignment */
+#define FAULT_ALIGN_1 0x03 /* Alignment */
+#define FAULT_TRANS_S 0x05 /* Translation -- Section */
+#define FAULT_TRANS_P 0x07 /* Translation -- Page */
+#define FAULT_DOMAIN_S 0x09 /* Domain -- Section */
+#define FAULT_DOMAIN_P 0x0b /* Domain -- Page */
+#define FAULT_PERM_S 0x0d /* Permission -- Section */
+#define FAULT_PERM_P 0x0f /* Permission -- Page */
+
+#define FAULT_IMPRECISE 0x400 /* Imprecise exception (XSCALE) */
+
+/*
+ * Address of the vector page, low and high versions.
+ */
+#define ARM_VECTORS_LOW 0x00000000U
+#define ARM_VECTORS_HIGH 0xffff0000U
+
+/*
+ * ARM Instructions
+ *
+ * 3 3 2 2 2
+ * 1 0 9 8 7 0
+ * +-------+-------------------------------------------------------+
+ * | cond | instruction dependant |
+ * |c c c c| |
+ * +-------+-------------------------------------------------------+
+ */
+
+#define INSN_SIZE 4 /* Always 4 bytes */
+#define INSN_COND_MASK 0xf0000000 /* Condition mask */
+#define INSN_COND_AL 0xe0000000 /* Always condition */
+
+#endif
diff --git a/sys/arch/arm/include/asm.h b/sys/arch/arm/include/asm.h
new file mode 100644
index 00000000000..c7bd017aa70
--- /dev/null
+++ b/sys/arch/arm/include/asm.h
@@ -0,0 +1,130 @@
+/* $OpenBSD: asm.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: asm.h,v 1.4 2001/07/16 05:43:32 matt Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)asm.h 5.5 (Berkeley) 5/7/91
+ */
+
+#ifndef _ARM32_ASM_H_
+#define _ARM32_ASM_H_
+
+#ifdef __ELF__
+# define _C_LABEL(x) x
+#else
+# ifdef __STDC__
+# define _C_LABEL(x) _ ## x
+# else
+# define _C_LABEL(x) _/**/x
+# endif
+#endif
+#define _ASM_LABEL(x) x
+
+#ifdef __STDC__
+# define __CONCAT(x,y) x ## y
+# define __STRING(x) #x
+#else
+# define __CONCAT(x,y) x/**/y
+# define __STRING(x) "x"
+#endif
+
+#ifndef _ALIGN_TEXT
+# define _ALIGN_TEXT .align 0
+#endif
+
+/*
+ * gas/arm uses @ as a single comment character and thus cannot be used here
+ * Instead it recognised the # instead of an @ symbols in .type directives
+ * We define a couple of macros so that assembly code will not be dependant
+ * on one or the other.
+ */
+#define _ASM_TYPE_FUNCTION #function
+#define _ASM_TYPE_OBJECT #object
+#define _ENTRY(x) \
+ .text; _ALIGN_TEXT; .globl x; .type x,_ASM_TYPE_FUNCTION; x:
+
+#ifdef GPROF
+# ifdef __ELF__
+# define _PROF_PROLOGUE \
+ mov ip, lr; bl __mcount
+# else
+# define _PROF_PROLOGUE \
+ mov ip,lr; bl mcount
+# endif
+#else
+# define _PROF_PROLOGUE
+#endif
+
+#define ENTRY(y) _ENTRY(_C_LABEL(y)); _PROF_PROLOGUE
+#define ENTRY_NP(y) _ENTRY(_C_LABEL(y))
+#define ASENTRY(y) _ENTRY(_ASM_LABEL(y)); _PROF_PROLOGUE
+#define ASENTRY_NP(y) _ENTRY(_ASM_LABEL(y))
+
+#define ASMSTR .asciz
+
+#if defined(__ELF__) && defined(PIC)
+#ifdef __STDC__
+#define PIC_SYM(x,y) x ## ( ## y ## )
+#else
+#define PIC_SYM(x,y) x/**/(/**/y/**/)
+#endif
+#else
+#define PIC_SYM(x,y) x
+#endif
+
+#ifdef __ELF__
+#define RCSID(x) .section ".ident"; .asciz x
+#else
+#define RCSID(x) .text; .asciz x
+#endif
+
+#ifdef __ELF__
+#define WEAK_ALIAS(alias,sym) \
+ .weak alias; \
+ alias = sym
+#endif
+
+#ifdef __STDC__
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg ## ,30,0,0,0 ; \
+ .stabs __STRING(_C_LABEL(sym)) ## ,1,0,0,0
+#elif defined(__ELF__)
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg,30,0,0,0 ; \
+ .stabs __STRING(sym),1,0,0,0
+#else
+#define WARN_REFERENCES(sym,msg) \
+ .stabs msg,30,0,0,0 ; \
+ .stabs __STRING(_/**/sym),1,0,0,0
+#endif /* __STDC__ */
+
+#endif /* !_ARM_ASM_H_ */
diff --git a/sys/arch/arm/include/atomic.h b/sys/arch/arm/include/atomic.h
new file mode 100644
index 00000000000..9ef4c687a9e
--- /dev/null
+++ b/sys/arch/arm/include/atomic.h
@@ -0,0 +1,103 @@
+/* $OpenBSD: atomic.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: atomic.h,v 1.1 2002/10/19 12:22:34 bsh Exp $ */
+
+/*
+ * Copyright (C) 1994-1997 Mark Brinicombe
+ * Copyright (C) 1994 Brini
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of Brini may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_ATOMIC_H_
+#define _ARM_ATOMIC_H_
+
+#ifndef ATOMIC_SET_BIT_NONINLINE_REQUIRED
+
+#if defined(__PROG26) || defined(ATOMIC_SET_BIT_NOINLINE)
+#define ATOMIC_SET_BIT_NONINLINE_REQUIRED
+#endif
+
+#endif /* ATOMIC_SET_BIT_NONINLINE_REQUIRED */
+
+
+#ifndef _LOCORE
+
+#include <sys/types.h>
+#include <arm/armreg.h> /* I32_bit */
+
+#ifdef ATOMIC_SET_BIT_NONINLINE_REQUIRED
+void atomic_set_bit( u_int *, u_int );
+void atomic_clear_bit( u_int *, u_int );
+#endif
+
+#ifdef __PROG32
+#define __with_interrupts_disabled(expr) \
+ do { \
+ u_int cpsr_save, tmp; \
+ \
+ __asm __volatile( \
+ "mrs %0, cpsr;" \
+ "orr %1, %0, %2;" \
+ "msr cpsr_all, %1;" \
+ : "=r" (cpsr_save), "=r" (tmp) \
+ : "I" (I32_bit) \
+ : "cc" ); \
+ (expr); \
+ __asm __volatile( \
+ "msr cpsr_all, %0" \
+ : /* no output */ \
+ : "r" (cpsr_save) \
+ : "cc" ); \
+ } while(0)
+
+static __inline void
+inline_atomic_set_bit( u_int *address, u_int setmask )
+{
+ __with_interrupts_disabled( *address |= setmask );
+}
+
+static __inline void
+inline_atomic_clear_bit( u_int *address, u_int clearmask )
+{
+ __with_interrupts_disabled( *address &= ~clearmask );
+}
+
+#if !defined(ATOMIC_SET_BIT_NOINLINE)
+
+#define atomic_set_bit(a,m) inline_atomic_set_bit(a,m)
+#define atomic_clear_bit(a,m) inline_atomic_clear_bit(a,m)
+
+#endif
+
+#endif /* __PROG32 */
+
+#undef __with_interrupts_disabled
+
+#endif /* _LOCORE */
+#endif /* _ARM_ATOMIC_H_ */
diff --git a/sys/arch/arm/include/blockio.h b/sys/arch/arm/include/blockio.h
new file mode 100644
index 00000000000..ce071c4717b
--- /dev/null
+++ b/sys/arch/arm/include/blockio.h
@@ -0,0 +1,54 @@
+/* $OpenBSD: blockio.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: blockio.h,v 1.2 2001/06/02 10:44:56 bjh21 Exp $ */
+
+/*-
+ * Copyright (c) 2001 Ben Harris
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * blockio.h - low level functions for bulk PIO data transfer
+ */
+
+#ifndef _ARM_BLOCKIO_H_
+#define _ARM_BLOCKIO_H_
+
+/*
+ * All these take three arguments:
+ * I/O address
+ * Memory address
+ * Number of bytes to copy
+ */
+
+void read_multi_1(u_int, void *, u_int);
+void write_multi_1(u_int, const void *, u_int);
+#define read_multi_2 insw16
+#define write_multi_2 outsw16
+
+void insw(u_int, void *, u_int);
+void outsw(u_int, void *, u_int);
+void insw16(u_int, void *, u_int);
+void outsw16(u_int, void *, u_int);
+
+#endif
diff --git a/sys/arch/arm/include/bus.h b/sys/arch/arm/include/bus.h
new file mode 100644
index 00000000000..b1a508e9903
--- /dev/null
+++ b/sys/arch/arm/include/bus.h
@@ -0,0 +1,1071 @@
+/* $NetBSD: bus.h,v 1.12 2003/10/23 15:03:24 scw Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1996 Charles M. Hannum. All rights reserved.
+ * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM32_BUS_H_
+#define _ARM32_BUS_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_arm_bus_space.h"
+#endif
+
+/*
+ * Addresses (in bus space).
+ */
+typedef u_long bus_addr_t;
+typedef u_long bus_size_t;
+
+/*
+ * Access methods for bus space.
+ */
+typedef struct bus_space *bus_space_tag_t;
+typedef u_long bus_space_handle_t;
+
+/*
+ * int bus_space_map __P((bus_space_tag_t t, bus_addr_t addr,
+ * bus_size_t size, int flags, bus_space_handle_t *bshp));
+ *
+ * Map a region of bus space.
+ */
+
+#define BUS_SPACE_MAP_CACHEABLE 0x01
+#define BUS_SPACE_MAP_LINEAR 0x02
+#define BUS_SPACE_MAP_PREFETCHABLE 0x04
+
+struct bus_space {
+ /* cookie */
+ void *bs_cookie;
+
+ /* mapping/unmapping */
+ int (*bs_map) __P((void *, bus_addr_t, bus_size_t,
+ int, bus_space_handle_t *));
+ void (*bs_unmap) __P((void *, bus_space_handle_t,
+ bus_size_t));
+ int (*bs_subregion) __P((void *, bus_space_handle_t,
+ bus_size_t, bus_size_t, bus_space_handle_t *));
+
+ /* allocation/deallocation */
+ int (*bs_alloc) __P((void *, bus_addr_t, bus_addr_t,
+ bus_size_t, bus_size_t, bus_size_t, int,
+ bus_addr_t *, bus_space_handle_t *));
+ void (*bs_free) __P((void *, bus_space_handle_t,
+ bus_size_t));
+
+ /* get kernel virtual address */
+ void * (*bs_vaddr) __P((void *, bus_space_handle_t));
+
+ /* mmap bus space for user */
+ paddr_t (*bs_mmap) __P((void *, bus_addr_t, off_t, int, int));
+
+ /* barrier */
+ void (*bs_barrier) __P((void *, bus_space_handle_t,
+ bus_size_t, bus_size_t, int));
+
+ /* read (single) */
+ u_int8_t (*bs_r_1) __P((void *, bus_space_handle_t,
+ bus_size_t));
+ u_int16_t (*bs_r_2) __P((void *, bus_space_handle_t,
+ bus_size_t));
+ u_int32_t (*bs_r_4) __P((void *, bus_space_handle_t,
+ bus_size_t));
+ u_int64_t (*bs_r_8) __P((void *, bus_space_handle_t,
+ bus_size_t));
+
+ /* read multiple */
+ void (*bs_rm_1) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t *, bus_size_t));
+ void (*bs_rm_2) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t *, bus_size_t));
+ void (*bs_rm_4) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t));
+ void (*bs_rm_8) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t));
+
+ /* read region */
+ void (*bs_rr_1) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t *, bus_size_t));
+ void (*bs_rr_2) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t *, bus_size_t));
+ void (*bs_rr_4) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t));
+ void (*bs_rr_8) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t));
+
+ /* write (single) */
+ void (*bs_w_1) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t));
+ void (*bs_w_2) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t));
+ void (*bs_w_4) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t));
+ void (*bs_w_8) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t));
+
+ /* write multiple */
+ void (*bs_wm_1) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t));
+ void (*bs_wm_2) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t));
+ void (*bs_wm_4) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t));
+ void (*bs_wm_8) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t));
+
+ /* write region */
+ void (*bs_wr_1) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t));
+ void (*bs_wr_2) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t));
+ void (*bs_wr_4) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t));
+ void (*bs_wr_8) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t));
+
+ /* set multiple */
+ void (*bs_sm_1) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t, bus_size_t));
+ void (*bs_sm_2) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t, bus_size_t));
+ void (*bs_sm_4) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t, bus_size_t));
+ void (*bs_sm_8) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t, bus_size_t));
+
+ /* set region */
+ void (*bs_sr_1) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t, bus_size_t));
+ void (*bs_sr_2) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t, bus_size_t));
+ void (*bs_sr_4) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t, bus_size_t));
+ void (*bs_sr_8) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t, bus_size_t));
+
+ /* copy */
+ void (*bs_c_1) __P((void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t));
+ void (*bs_c_2) __P((void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t));
+ void (*bs_c_4) __P((void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t));
+ void (*bs_c_8) __P((void *, bus_space_handle_t, bus_size_t,
+ bus_space_handle_t, bus_size_t, bus_size_t));
+
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+ /* read stream (single) */
+ u_int8_t (*bs_r_1_s) __P((void *, bus_space_handle_t,
+ bus_size_t));
+ u_int16_t (*bs_r_2_s) __P((void *, bus_space_handle_t,
+ bus_size_t));
+ u_int32_t (*bs_r_4_s) __P((void *, bus_space_handle_t,
+ bus_size_t));
+ u_int64_t (*bs_r_8_s) __P((void *, bus_space_handle_t,
+ bus_size_t));
+
+ /* read multiple stream */
+ void (*bs_rm_1_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t *, bus_size_t));
+ void (*bs_rm_2_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t *, bus_size_t));
+ void (*bs_rm_4_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t));
+ void (*bs_rm_8_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t));
+
+ /* read region stream */
+ void (*bs_rr_1_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t *, bus_size_t));
+ void (*bs_rr_2_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t *, bus_size_t));
+ void (*bs_rr_4_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t *, bus_size_t));
+ void (*bs_rr_8_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t *, bus_size_t));
+
+ /* write stream (single) */
+ void (*bs_w_1_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int8_t));
+ void (*bs_w_2_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int16_t));
+ void (*bs_w_4_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int32_t));
+ void (*bs_w_8_s) __P((void *, bus_space_handle_t,
+ bus_size_t, u_int64_t));
+
+ /* write multiple stream */
+ void (*bs_wm_1_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t));
+ void (*bs_wm_2_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t));
+ void (*bs_wm_4_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t));
+ void (*bs_wm_8_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t));
+
+ /* write region stream */
+ void (*bs_wr_1_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int8_t *, bus_size_t));
+ void (*bs_wr_2_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int16_t *, bus_size_t));
+ void (*bs_wr_4_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int32_t *, bus_size_t));
+ void (*bs_wr_8_s) __P((void *, bus_space_handle_t,
+ bus_size_t, const u_int64_t *, bus_size_t));
+#endif /* __BUS_SPACE_HAS_STREAM_METHODS */
+};
+
+
+/*
+ * Utility macros; INTERNAL USE ONLY.
+ */
+#define __bs_c(a,b) __CONCAT(a,b)
+#define __bs_opname(op,size) __bs_c(__bs_c(__bs_c(bs_,op),_),size)
+
+#define __bs_rs(sz, t, h, o) \
+ (*(t)->__bs_opname(r,sz))((t)->bs_cookie, h, o)
+#define __bs_ws(sz, t, h, o, v) \
+ (*(t)->__bs_opname(w,sz))((t)->bs_cookie, h, o, v)
+#define __bs_nonsingle(type, sz, t, h, o, a, c) \
+ (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, a, c)
+#define __bs_set(type, sz, t, h, o, v, c) \
+ (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, v, c)
+#define __bs_copy(sz, t, h1, o1, h2, o2, cnt) \
+ (*(t)->__bs_opname(c,sz))((t)->bs_cookie, h1, o1, h2, o2, cnt)
+
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+#define __bs_opname_s(op,size) __bs_c(__bs_c(__bs_c(__bs_c(bs_,op),_),size),_s)
+#define __bs_rs_s(sz, t, h, o) \
+ (*(t)->__bs_opname_s(r,sz))((t)->bs_cookie, h, o)
+#define __bs_ws_s(sz, t, h, o, v) \
+ (*(t)->__bs_opname_s(w,sz))((t)->bs_cookie, h, o, v)
+#define __bs_nonsingle_s(type, sz, t, h, o, a, c) \
+ (*(t)->__bs_opname_s(type,sz))((t)->bs_cookie, h, o, a, c)
+#define __bs_set_s(type, sz, t, h, o, v, c) \
+ (*(t)->__bs_opname_s(type,sz))((t)->bs_cookie, h, o, v, c)
+#define __bs_copy_s(sz, t, h1, o1, h2, o2, cnt) \
+ (*(t)->__bs_opname_s(c,sz))((t)->bs_cookie, h1, o1, h2, o2, cnt)
+#endif
+
+/*
+ * Mapping and unmapping operations.
+ */
+#define bus_space_map(t, a, s, c, hp) \
+ (*(t)->bs_map)((t)->bs_cookie, (a), (s), (c), (hp))
+#define bus_space_unmap(t, h, s) \
+ (*(t)->bs_unmap)((t)->bs_cookie, (h), (s))
+#define bus_space_subregion(t, h, o, s, hp) \
+ (*(t)->bs_subregion)((t)->bs_cookie, (h), (o), (s), (hp))
+
+
+/*
+ * Allocation and deallocation operations.
+ */
+#define bus_space_alloc(t, rs, re, s, a, b, c, ap, hp) \
+ (*(t)->bs_alloc)((t)->bs_cookie, (rs), (re), (s), (a), (b), \
+ (c), (ap), (hp))
+#define bus_space_free(t, h, s) \
+ (*(t)->bs_free)((t)->bs_cookie, (h), (s))
+
+/*
+ * Get kernel virtual address for ranges mapped BUS_SPACE_MAP_LINEAR.
+ */
+#define bus_space_vaddr(t, h) \
+ (*(t)->bs_vaddr)((t)->bs_cookie, (h))
+
+/*
+ * MMap bus space for a user application.
+ */
+#define bus_space_mmap(t, a, o, p, f) \
+ (*(t)->bs_mmap)((t)->bs_cookie, (a), (o), (p), (f))
+
+/*
+ * Bus barrier operations.
+ */
+#define bus_space_barrier(t, h, o, l, f) \
+ (*(t)->bs_barrier)((t)->bs_cookie, (h), (o), (l), (f))
+
+#define BUS_SPACE_BARRIER_READ 0x01
+#define BUS_SPACE_BARRIER_WRITE 0x02
+
+/*
+ * Bus read (single) operations.
+ */
+#define bus_space_read_1(t, h, o) __bs_rs(1,(t),(h),(o))
+#define bus_space_read_2(t, h, o) __bs_rs(2,(t),(h),(o))
+#define bus_space_read_4(t, h, o) __bs_rs(4,(t),(h),(o))
+#define bus_space_read_8(t, h, o) __bs_rs(8,(t),(h),(o))
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+#define bus_space_read_stream_1(t, h, o) __bs_rs_s(1,(t),(h),(o))
+#define bus_space_read_stream_2(t, h, o) __bs_rs_s(2,(t),(h),(o))
+#define bus_space_read_stream_4(t, h, o) __bs_rs_s(4,(t),(h),(o))
+#define bus_space_read_stream_8(t, h, o) __bs_rs_s(8,(t),(h),(o))
+#endif
+
+
+/*
+ * Bus read multiple operations.
+ */
+#define bus_space_read_multi_1(t, h, o, a, c) \
+ __bs_nonsingle(rm,1,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_2(t, h, o, a, c) \
+ __bs_nonsingle(rm,2,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_4(t, h, o, a, c) \
+ __bs_nonsingle(rm,4,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_8(t, h, o, a, c) \
+ __bs_nonsingle(rm,8,(t),(h),(o),(a),(c))
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+#define bus_space_read_multi_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,1,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,2,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,4,(t),(h),(o),(a),(c))
+#define bus_space_read_multi_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(rm,8,(t),(h),(o),(a),(c))
+#endif
+
+
+/*
+ * Bus read region operations.
+ */
+#define bus_space_read_region_1(t, h, o, a, c) \
+ __bs_nonsingle(rr,1,(t),(h),(o),(a),(c))
+#define bus_space_read_region_2(t, h, o, a, c) \
+ __bs_nonsingle(rr,2,(t),(h),(o),(a),(c))
+#define bus_space_read_region_4(t, h, o, a, c) \
+ __bs_nonsingle(rr,4,(t),(h),(o),(a),(c))
+#define bus_space_read_region_8(t, h, o, a, c) \
+ __bs_nonsingle(rr,8,(t),(h),(o),(a),(c))
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+#define bus_space_read_region_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,1,(t),(h),(o),(a),(c))
+#define bus_space_read_region_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,2,(t),(h),(o),(a),(c))
+#define bus_space_read_region_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,4,(t),(h),(o),(a),(c))
+#define bus_space_read_region_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(rr,8,(t),(h),(o),(a),(c))
+#endif
+
+
+/*
+ * Bus write (single) operations.
+ */
+#define bus_space_write_1(t, h, o, v) __bs_ws(1,(t),(h),(o),(v))
+#define bus_space_write_2(t, h, o, v) __bs_ws(2,(t),(h),(o),(v))
+#define bus_space_write_4(t, h, o, v) __bs_ws(4,(t),(h),(o),(v))
+#define bus_space_write_8(t, h, o, v) __bs_ws(8,(t),(h),(o),(v))
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+#define bus_space_write_stream_1(t, h, o, v) __bs_ws_s(1,(t),(h),(o),(v))
+#define bus_space_write_stream_2(t, h, o, v) __bs_ws_s(2,(t),(h),(o),(v))
+#define bus_space_write_stream_4(t, h, o, v) __bs_ws_s(4,(t),(h),(o),(v))
+#define bus_space_write_stream_8(t, h, o, v) __bs_ws_s(8,(t),(h),(o),(v))
+#endif
+
+
+/*
+ * Bus write multiple operations.
+ */
+#define bus_space_write_multi_1(t, h, o, a, c) \
+ __bs_nonsingle(wm,1,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_2(t, h, o, a, c) \
+ __bs_nonsingle(wm,2,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_4(t, h, o, a, c) \
+ __bs_nonsingle(wm,4,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_8(t, h, o, a, c) \
+ __bs_nonsingle(wm,8,(t),(h),(o),(a),(c))
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+#define bus_space_write_multi_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,1,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,2,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,4,(t),(h),(o),(a),(c))
+#define bus_space_write_multi_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(wm,8,(t),(h),(o),(a),(c))
+#endif
+
+
+/*
+ * Bus write region operations.
+ */
+#define bus_space_write_region_1(t, h, o, a, c) \
+ __bs_nonsingle(wr,1,(t),(h),(o),(a),(c))
+#define bus_space_write_region_2(t, h, o, a, c) \
+ __bs_nonsingle(wr,2,(t),(h),(o),(a),(c))
+#define bus_space_write_region_4(t, h, o, a, c) \
+ __bs_nonsingle(wr,4,(t),(h),(o),(a),(c))
+#define bus_space_write_region_8(t, h, o, a, c) \
+ __bs_nonsingle(wr,8,(t),(h),(o),(a),(c))
+#ifdef __BUS_SPACE_HAS_STREAM_METHODS
+#define bus_space_write_region_stream_1(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,1,(t),(h),(o),(a),(c))
+#define bus_space_write_region_stream_2(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,2,(t),(h),(o),(a),(c))
+#define bus_space_write_region_stream_4(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,4,(t),(h),(o),(a),(c))
+#define bus_space_write_region_stream_8(t, h, o, a, c) \
+ __bs_nonsingle_s(wr,8,(t),(h),(o),(a),(c))
+#endif
+
+
+/*
+ * Set multiple operations.
+ */
+#define bus_space_set_multi_1(t, h, o, v, c) \
+ __bs_set(sm,1,(t),(h),(o),(v),(c))
+#define bus_space_set_multi_2(t, h, o, v, c) \
+ __bs_set(sm,2,(t),(h),(o),(v),(c))
+#define bus_space_set_multi_4(t, h, o, v, c) \
+ __bs_set(sm,4,(t),(h),(o),(v),(c))
+#define bus_space_set_multi_8(t, h, o, v, c) \
+ __bs_set(sm,8,(t),(h),(o),(v),(c))
+
+/*
+ * Set region operations.
+ */
+#define bus_space_set_region_1(t, h, o, v, c) \
+ __bs_set(sr,1,(t),(h),(o),(v),(c))
+#define bus_space_set_region_2(t, h, o, v, c) \
+ __bs_set(sr,2,(t),(h),(o),(v),(c))
+#define bus_space_set_region_4(t, h, o, v, c) \
+ __bs_set(sr,4,(t),(h),(o),(v),(c))
+#define bus_space_set_region_8(t, h, o, v, c) \
+ __bs_set(sr,8,(t),(h),(o),(v),(c))
+
+/*
+ * Copy operations.
+ */
+#define bus_space_copy_region_1(t, h1, o1, h2, o2, c) \
+ __bs_copy(1, t, h1, o1, h2, o2, c)
+#define bus_space_copy_region_2(t, h1, o1, h2, o2, c) \
+ __bs_copy(2, t, h1, o1, h2, o2, c)
+#define bus_space_copy_region_4(t, h1, o1, h2, o2, c) \
+ __bs_copy(4, t, h1, o1, h2, o2, c)
+#define bus_space_copy_region_8(t, h1, o1, h2, o2, c) \
+ __bs_copy(8, t, h1, o1, h2, o2, c)
+
+void
+bus_space_copy_1(bus_space_tag_t bst, bus_space_handle_t h1,
+ bus_space_handle_t h2, bus_size_t o1, bus_size_t o2, bus_size_t c);
+void
+bus_space_copy_2(bus_space_tag_t bst, bus_space_handle_t h1,
+ bus_space_handle_t h2, bus_size_t o1, bus_size_t o2, bus_size_t c);
+void
+bus_space_copy_4(bus_space_tag_t bst, bus_space_handle_t h1,
+ bus_space_handle_t h2, bus_size_t o1, bus_size_t o2, bus_size_t c);
+#define bus_space_copy_8 \
+ !!! bus_space_write_raw_multi_8 not implemented !!!
+
+/*
+ * Macros to provide prototypes for all the functions used in the
+ * bus_space structure
+ */
+
+#define bs_map_proto(f) \
+int __bs_c(f,_bs_map) __P((void *t, bus_addr_t addr, \
+ bus_size_t size, int cacheable, bus_space_handle_t *bshp));
+
+#define bs_unmap_proto(f) \
+void __bs_c(f,_bs_unmap) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t size));
+
+#define bs_subregion_proto(f) \
+int __bs_c(f,_bs_subregion) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, bus_size_t size, \
+ bus_space_handle_t *nbshp));
+
+#define bs_alloc_proto(f) \
+int __bs_c(f,_bs_alloc) __P((void *t, bus_addr_t rstart, \
+ bus_addr_t rend, bus_size_t size, bus_size_t align, \
+ bus_size_t boundary, int cacheable, bus_addr_t *addrp, \
+ bus_space_handle_t *bshp));
+
+#define bs_free_proto(f) \
+void __bs_c(f,_bs_free) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t size));
+
+#define bs_vaddr_proto(f) \
+void * __bs_c(f,_bs_vaddr) __P((void *t, bus_space_handle_t bsh));
+
+#define bs_mmap_proto(f) \
+paddr_t __bs_c(f,_bs_mmap) __P((void *, bus_addr_t, off_t, int, int));
+
+#define bs_barrier_proto(f) \
+void __bs_c(f,_bs_barrier) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, bus_size_t len, int flags));
+
+#define bs_r_1_proto(f) \
+u_int8_t __bs_c(f,_bs_r_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset));
+
+#define bs_r_2_proto(f) \
+u_int16_t __bs_c(f,_bs_r_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset));
+
+#define bs_r_4_proto(f) \
+u_int32_t __bs_c(f,_bs_r_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset));
+
+#define bs_r_8_proto(f) \
+u_int64_t __bs_c(f,_bs_r_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset));
+
+#define bs_w_1_proto(f) \
+void __bs_c(f,_bs_w_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int8_t value));
+
+#define bs_w_2_proto(f) \
+void __bs_c(f,_bs_w_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int16_t value));
+
+#define bs_w_4_proto(f) \
+void __bs_c(f,_bs_w_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int32_t value));
+
+#define bs_w_8_proto(f) \
+void __bs_c(f,_bs_w_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int64_t value));
+
+#define bs_rm_1_proto(f) \
+void __bs_c(f,_bs_rm_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int8_t *addr, bus_size_t count));
+
+#define bs_rm_2_proto(f) \
+void __bs_c(f,_bs_rm_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int16_t *addr, bus_size_t count));
+
+#define bs_rm_4_proto(f) \
+void __bs_c(f,_bs_rm_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int32_t *addr, bus_size_t count));
+
+#define bs_rm_8_proto(f) \
+void __bs_c(f,_bs_rm_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int64_t *addr, bus_size_t count));
+
+#define bs_wm_1_proto(f) \
+void __bs_c(f,_bs_wm_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int8_t *addr, bus_size_t count));
+
+#define bs_wm_2_proto(f) \
+void __bs_c(f,_bs_wm_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int16_t *addr, bus_size_t count));
+
+#define bs_wm_4_proto(f) \
+void __bs_c(f,_bs_wm_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int32_t *addr, bus_size_t count));
+
+#define bs_wm_8_proto(f) \
+void __bs_c(f,_bs_wm_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int64_t *addr, bus_size_t count));
+
+#define bs_rr_1_proto(f) \
+void __bs_c(f, _bs_rr_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int8_t *addr, bus_size_t count));
+
+#define bs_rr_2_proto(f) \
+void __bs_c(f, _bs_rr_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int16_t *addr, bus_size_t count));
+
+#define bs_rr_4_proto(f) \
+void __bs_c(f, _bs_rr_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int32_t *addr, bus_size_t count));
+
+#define bs_rr_8_proto(f) \
+void __bs_c(f, _bs_rr_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int64_t *addr, bus_size_t count));
+
+#define bs_wr_1_proto(f) \
+void __bs_c(f, _bs_wr_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int8_t *addr, bus_size_t count));
+
+#define bs_wr_2_proto(f) \
+void __bs_c(f, _bs_wr_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int16_t *addr, bus_size_t count));
+
+#define bs_wr_4_proto(f) \
+void __bs_c(f, _bs_wr_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int32_t *addr, bus_size_t count));
+
+#define bs_wr_8_proto(f) \
+void __bs_c(f, _bs_wr_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, const u_int64_t *addr, bus_size_t count));
+
+#define bs_sm_1_proto(f) \
+void __bs_c(f,_bs_sm_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int8_t value, bus_size_t count));
+
+#define bs_sm_2_proto(f) \
+void __bs_c(f,_bs_sm_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int16_t value, bus_size_t count));
+
+#define bs_sm_4_proto(f) \
+void __bs_c(f,_bs_sm_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int32_t value, bus_size_t count));
+
+#define bs_sm_8_proto(f) \
+void __bs_c(f,_bs_sm_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int64_t value, bus_size_t count));
+
+#define bs_sr_1_proto(f) \
+void __bs_c(f,_bs_sr_1) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int8_t value, bus_size_t count));
+
+#define bs_sr_2_proto(f) \
+void __bs_c(f,_bs_sr_2) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int16_t value, bus_size_t count));
+
+#define bs_sr_4_proto(f) \
+void __bs_c(f,_bs_sr_4) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int32_t value, bus_size_t count));
+
+#define bs_sr_8_proto(f) \
+void __bs_c(f,_bs_sr_8) __P((void *t, bus_space_handle_t bsh, \
+ bus_size_t offset, u_int64_t value, bus_size_t count));
+
+#define bs_c_1_proto(f) \
+void __bs_c(f,_bs_c_1) __P((void *t, bus_space_handle_t bsh1, \
+ bus_size_t offset1, bus_space_handle_t bsh2, \
+ bus_size_t offset2, bus_size_t count));
+
+#define bs_c_2_proto(f) \
+void __bs_c(f,_bs_c_2) __P((void *t, bus_space_handle_t bsh1, \
+ bus_size_t offset1, bus_space_handle_t bsh2, \
+ bus_size_t offset2, bus_size_t count));
+
+#define bs_c_4_proto(f) \
+void __bs_c(f,_bs_c_4) __P((void *t, bus_space_handle_t bsh1, \
+ bus_size_t offset1, bus_space_handle_t bsh2, \
+ bus_size_t offset2, bus_size_t count));
+
+#define bs_c_8_proto(f) \
+void __bs_c(f,_bs_c_8) __P((void *t, bus_space_handle_t bsh1, \
+ bus_size_t offset1, bus_space_handle_t bsh2, \
+ bus_size_t offset2, bus_size_t count));
+
+#define bs_protos(f) \
+bs_map_proto(f); \
+bs_unmap_proto(f); \
+bs_subregion_proto(f); \
+bs_alloc_proto(f); \
+bs_free_proto(f); \
+bs_vaddr_proto(f); \
+bs_mmap_proto(f); \
+bs_barrier_proto(f); \
+bs_r_1_proto(f); \
+bs_r_2_proto(f); \
+bs_r_4_proto(f); \
+bs_r_8_proto(f); \
+bs_w_1_proto(f); \
+bs_w_2_proto(f); \
+bs_w_4_proto(f); \
+bs_w_8_proto(f); \
+bs_rm_1_proto(f); \
+bs_rm_2_proto(f); \
+bs_rm_4_proto(f); \
+bs_rm_8_proto(f); \
+bs_wm_1_proto(f); \
+bs_wm_2_proto(f); \
+bs_wm_4_proto(f); \
+bs_wm_8_proto(f); \
+bs_rr_1_proto(f); \
+bs_rr_2_proto(f); \
+bs_rr_4_proto(f); \
+bs_rr_8_proto(f); \
+bs_wr_1_proto(f); \
+bs_wr_2_proto(f); \
+bs_wr_4_proto(f); \
+bs_wr_8_proto(f); \
+bs_sm_1_proto(f); \
+bs_sm_2_proto(f); \
+bs_sm_4_proto(f); \
+bs_sm_8_proto(f); \
+bs_sr_1_proto(f); \
+bs_sr_2_proto(f); \
+bs_sr_4_proto(f); \
+bs_sr_8_proto(f); \
+bs_c_1_proto(f); \
+bs_c_2_proto(f); \
+bs_c_4_proto(f); \
+bs_c_8_proto(f);
+
+#define BUS_SPACE_ALIGNED_POINTER(p, t) ALIGNED_POINTER(p, t)
+
+/* Bus Space DMA macros */
+
+/*
+ * Flags used in various bus DMA methods.
+ */
+#define BUS_DMA_WAITOK 0x000 /* safe to sleep (pseudo-flag) */
+#define BUS_DMA_NOWAIT 0x001 /* not safe to sleep */
+#define BUS_DMA_ALLOCNOW 0x002 /* perform resource allocation now */
+#define BUS_DMA_COHERENT 0x004 /* hint: map memory DMA coherent */
+#define BUS_DMA_STREAMING 0x008 /* hint: sequential, unidirectional */
+#define BUS_DMA_BUS1 0x010 /* placeholders for bus functions... */
+#define BUS_DMA_BUS2 0x020
+#define BUS_DMA_BUS3 0x040
+#define BUS_DMA_BUS4 0x080
+#define BUS_DMA_READ 0x100 /* mapping is device -> memory only */
+#define BUS_DMA_WRITE 0x200 /* mapping is memory -> device only */
+#define BUS_DMA_NOCACHE 0x400 /* hint: map non-cached memory */
+
+/*
+ * Private flags stored in the DMA map.
+ */
+#define ARM32_DMAMAP_COHERENT 0x10000 /* no cache flush necessary on sync */
+
+/* Forwards needed by prototypes below. */
+struct mbuf;
+struct uio;
+
+/*
+ * Operations performed by bus_dmamap_sync().
+ */
+#define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */
+#define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */
+#define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */
+#define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */
+
+typedef struct arm32_bus_dma_tag *bus_dma_tag_t;
+typedef struct arm32_bus_dmamap *bus_dmamap_t;
+
+#define BUS_DMA_TAG_VALID(t) ((t) != (bus_dma_tag_t)0)
+
+/*
+ * bus_dma_segment_t
+ *
+ * Describes a single contiguous DMA transaction. Values
+ * are suitable for programming into DMA registers.
+ */
+struct arm32_bus_dma_segment {
+ /*
+ * PUBLIC MEMBERS: these are used by machine-independent code.
+ */
+ bus_addr_t ds_addr; /* DMA address */
+ bus_size_t ds_len; /* length of transfer */
+ /*
+ * PRIVATE MEMBERS: not for use by machine-independent code.
+ */
+ bus_addr_t _ds_vaddr; /* Virtual mapped address
+ * Used by bus_dmamem_sync() */
+};
+typedef struct arm32_bus_dma_segment bus_dma_segment_t;
+
+/*
+ * arm32_dma_range
+ *
+ * This structure describes a valid DMA range.
+ */
+struct arm32_dma_range {
+ bus_addr_t dr_sysbase; /* system base address */
+ bus_addr_t dr_busbase; /* appears here on bus */
+ bus_size_t dr_len; /* length of range */
+};
+
+/*
+ * bus_dma_tag_t
+ *
+ * A machine-dependent opaque type describing the implementation of
+ * DMA for a given bus.
+ */
+
+struct arm32_bus_dma_tag {
+ /*
+ * DMA range for this tag. If the page doesn't fall within
+ * one of these ranges, an error is returned. The caller
+ * may then decide what to do with the transfer. If the
+ * range pointer is NULL, it is ignored.
+ */
+ struct arm32_dma_range *_ranges;
+ int _nranges;
+
+ /*
+ * Opaque cookie for use by back-end.
+ */
+ void *_cookie;
+
+ /*
+ * DMA mapping methods.
+ */
+ int (*_dmamap_create) __P((bus_dma_tag_t, bus_size_t, int,
+ bus_size_t, bus_size_t, int, bus_dmamap_t *));
+ void (*_dmamap_destroy) __P((bus_dma_tag_t, bus_dmamap_t));
+ int (*_dmamap_load) __P((bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int));
+ int (*_dmamap_load_mbuf) __P((bus_dma_tag_t, bus_dmamap_t,
+ struct mbuf *, int));
+ int (*_dmamap_load_uio) __P((bus_dma_tag_t, bus_dmamap_t,
+ struct uio *, int));
+ int (*_dmamap_load_raw) __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int));
+ void (*_dmamap_unload) __P((bus_dma_tag_t, bus_dmamap_t));
+ void (*_dmamap_sync) __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_addr_t, bus_size_t, int));
+
+ /*
+ * DMA memory utility functions.
+ */
+ int (*_dmamem_alloc) __P((bus_dma_tag_t, bus_size_t, bus_size_t,
+ bus_size_t, bus_dma_segment_t *, int, int *, int));
+ void (*_dmamem_free) __P((bus_dma_tag_t,
+ bus_dma_segment_t *, int));
+ int (*_dmamem_map) __P((bus_dma_tag_t, bus_dma_segment_t *,
+ int, size_t, caddr_t *, int));
+ void (*_dmamem_unmap) __P((bus_dma_tag_t, caddr_t, size_t));
+ paddr_t (*_dmamem_mmap) __P((bus_dma_tag_t, bus_dma_segment_t *,
+ int, off_t, int, int));
+};
+
+#define bus_dmamap_create(t, s, n, m, b, f, p) \
+ (*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p))
+#define bus_dmamap_destroy(t, p) \
+ (*(t)->_dmamap_destroy)((t), (p))
+#define bus_dmamap_load(t, m, b, s, p, f) \
+ (*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f))
+#define bus_dmamap_load_mbuf(t, m, b, f) \
+ (*(t)->_dmamap_load_mbuf)((t), (m), (b), (f))
+#define bus_dmamap_load_uio(t, m, u, f) \
+ (*(t)->_dmamap_load_uio)((t), (m), (u), (f))
+#define bus_dmamap_load_raw(t, m, sg, n, s, f) \
+ (*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f))
+#define bus_dmamap_unload(t, p) \
+ (*(t)->_dmamap_unload)((t), (p))
+#define bus_dmamap_sync(t, p, o, l, ops) \
+ (void)((t)->_dmamap_sync ? \
+ (*(t)->_dmamap_sync)((t), (p), (o), (l), (ops)) : (void)0)
+
+#define bus_dmamem_alloc(t, s, a, b, sg, n, r, f) \
+ (*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f))
+#define bus_dmamem_free(t, sg, n) \
+ (*(t)->_dmamem_free)((t), (sg), (n))
+#define bus_dmamem_map(t, sg, n, s, k, f) \
+ (*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f))
+#define bus_dmamem_unmap(t, k, s) \
+ (*(t)->_dmamem_unmap)((t), (k), (s))
+#define bus_dmamem_mmap(t, sg, n, o, p, f) \
+ (*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f))
+
+/*
+ * bus_dmamap_t
+ *
+ * Describes a DMA mapping.
+ */
+struct arm32_bus_dmamap {
+ /*
+ * PRIVATE MEMBERS: not for use by machine-independent code.
+ */
+ bus_size_t _dm_size; /* largest DMA transfer mappable */
+ int _dm_segcnt; /* number of segs this map can map */
+ bus_size_t _dm_maxsegsz; /* largest possible segment */
+ bus_size_t _dm_boundary; /* don't cross this */
+ int _dm_flags; /* misc. flags */
+
+ void *_dm_origbuf; /* pointer to original buffer */
+ int _dm_buftype; /* type of buffer */
+ struct proc *_dm_proc; /* proc that owns the mapping */
+
+ void *_dm_cookie; /* cookie for bus-specific functions */
+
+ /*
+ * PUBLIC MEMBERS: these are used by machine-independent code.
+ */
+ bus_size_t dm_mapsize; /* size of the mapping */
+ int dm_nsegs; /* # valid segments in mapping */
+ bus_dma_segment_t dm_segs[1]; /* segments; variable length */
+};
+
+#ifdef _ARM32_BUS_DMA_PRIVATE
+
+/* _dm_buftype */
+#define ARM32_BUFTYPE_INVALID 0
+#define ARM32_BUFTYPE_LINEAR 1
+#define ARM32_BUFTYPE_MBUF 2
+#define ARM32_BUFTYPE_UIO 3
+#define ARM32_BUFTYPE_RAW 4
+
+int arm32_dma_range_intersect(struct arm32_dma_range *, int,
+ paddr_t pa, psize_t size, paddr_t *pap, psize_t *sizep);
+
+int _bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int, bus_size_t,
+ bus_size_t, int, bus_dmamap_t *));
+void _bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t));
+int _bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int));
+int _bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t,
+ struct mbuf *, int));
+int _bus_dmamap_load_uio __P((bus_dma_tag_t, bus_dmamap_t,
+ struct uio *, int));
+int _bus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int));
+void _bus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t));
+void _bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, bus_addr_t,
+ bus_size_t, int));
+
+int _bus_dmamem_alloc __P((bus_dma_tag_t tag, bus_size_t size,
+ bus_size_t alignment, bus_size_t boundary,
+ bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags));
+void _bus_dmamem_free __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
+ int nsegs));
+int _bus_dmamem_map __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
+ int nsegs, size_t size, caddr_t *kvap, int flags));
+void _bus_dmamem_unmap __P((bus_dma_tag_t tag, caddr_t kva,
+ size_t size));
+paddr_t _bus_dmamem_mmap __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
+ int nsegs, off_t off, int prot, int flags));
+
+int _bus_dmamem_alloc_range __P((bus_dma_tag_t tag, bus_size_t size,
+ bus_size_t alignment, bus_size_t boundary,
+ bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags,
+ vaddr_t low, vaddr_t high));
+#endif /* _ARM32_BUS_DMA_PRIVATE */
+/* These are OpenBSD extensions to the general NetBSD bus interface. */
+#if 0
+void
+bus_space_read_raw_multi_2(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, u_int8_t *dst, bus_size_t size);
+void
+bus_space_read_raw_multi_4(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, u_int8_t *dst, bus_size_t size);
+#define bus_space_read_raw_multi_8 \
+ !!! bus_space_read_raw_multi_8 not implemented !!!
+
+void
+bus_space_write_raw_multi_2(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, const u_int8_t *src, bus_size_t size);
+void
+bus_space_write_raw_multi_4(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, const u_int8_t *src, bus_size_t size);
+#define bus_space_write_raw_multi_8 \
+ !!! bus_space_write_raw_multi_8 not implemented !!!
+
+#else
+/* BLECH XXXDSR */
+static inline void
+bus_space_read_raw_multi_2(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, u_int8_t *dst, bus_size_t size);
+static inline void
+bus_space_read_raw_multi_2(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, u_int8_t *dst, bus_size_t size)
+{
+ u_int16_t *datap = (u_int16_t *)dst;
+ while (size > 0) {
+ *datap =bus_space_read_2(bst, bsh, ba);
+ datap++;
+ size -= 2;
+ }
+}
+static inline void
+bus_space_read_raw_multi_4(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, u_int8_t *dst, bus_size_t size);
+static inline void
+bus_space_read_raw_multi_4(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, u_int8_t *dst, bus_size_t size)
+{
+ u_int32_t *datap = (u_int32_t *)dst;
+ while (size > 0) {
+ *datap =bus_space_read_4(bst, bsh, ba);
+ datap++;
+ size -= 4;
+ }
+}
+
+static inline void
+bus_space_write_raw_multi_2(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, const u_int8_t *src, bus_size_t size);
+static inline void
+bus_space_write_raw_multi_2(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, const u_int8_t *src, bus_size_t size)
+{
+ u_int16_t *datap = (u_int16_t *)src;
+ while (size > 0) {
+ bus_space_write_2(bst, bsh, ba, *datap);
+ datap++;
+ size -= 2;
+ }
+}
+static inline void
+bus_space_write_raw_multi_4(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, const u_int8_t *src, bus_size_t size);
+static inline void
+bus_space_write_raw_multi_4(bus_space_tag_t bst, bus_space_handle_t bsh,
+ bus_addr_t ba, const u_int8_t *src, bus_size_t size)
+{
+ u_int32_t *datap = (u_int32_t *)src;
+ while (size > 0) {
+ bus_space_write_4(bst, bsh, ba, *datap);
+ datap++;
+ size -= 4;
+ }
+}
+#define bus_space_write_raw_multi_8 \
+ !!! bus_space_write_raw_multi_8 not implemented !!!
+
+#endif
+
+#endif /* _ARM32_BUS_H_ */
diff --git a/sys/arch/arm/include/cdefs.h b/sys/arch/arm/include/cdefs.h
new file mode 100644
index 00000000000..ddb29ed5939
--- /dev/null
+++ b/sys/arch/arm/include/cdefs.h
@@ -0,0 +1,13 @@
+/* $OpenBSD: cdefs.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: cdefs.h,v 1.1 2001/01/10 19:02:05 bjh21 Exp $ */
+
+#ifndef _MACHINE_CDEFS_H_
+#define _MACHINE_CDEFS_H_
+
+#define __weak_alias(alias,sym) \
+ __asm__(".weak " __STRING(alias) " ; " __STRING(alias) " = " __STRING(sym))
+#define __warn_references(sym,msg) \
+ __asm__(".section .gnu.warning." __STRING(sym) " ; .ascii \"" msg "\" ; .text")
+
+
+#endif /* !_MACHINE_CDEFS_H_ */
diff --git a/sys/arch/arm/include/conf.h b/sys/arch/arm/include/conf.h
new file mode 100644
index 00000000000..0f7dac4128a
--- /dev/null
+++ b/sys/arch/arm/include/conf.h
@@ -0,0 +1,134 @@
+/* $OpenBSD: conf.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: conf.h,v 1.7 2002/04/19 01:04:39 wiz Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * conf.h
+ *
+ * Prototypes for device driver functions
+ */
+
+#ifndef _ARM_CONF_H
+#define _ARM_CONF_H
+
+
+#include <sys/conf.h>
+
+#define mmread mmrw
+#define mmwrite mmrw
+cdev_decl(mm);
+
+bdev_decl(wd);
+cdev_decl(wd);
+bdev_decl(sw);
+cdev_decl(sw);
+bdev_decl(fd);
+cdev_decl(fd);
+bdev_decl(rd);
+cdev_decl(rd);
+bdev_decl(raid);
+cdev_decl(raid);
+
+/* Character device declarations */
+
+/* open, close, read, write, ioctl, tty, mmap -- XXX should be a tty */
+#define cdev_physcon_init(c,n) cdev__ttym_init(c,n,0)
+
+/* open, close, ioctl */
+#define cdev_beep_init(c,n) cdev__oci_init(c,n)
+
+/* open, close, read, ioctl */
+#define cdev_kbd_init(c,n) cdev__ocri_init(c,n)
+
+/* open, close, ioctl, mmap */
+#define cdev_vidcvid_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_noimpl(read,enodev), \
+ dev_noimpl(write,enodev), dev_init(c,n,ioctl), \
+ dev_noimpl(stop,enodev), 0, seltrue, dev_init(c,n,mmap), 0 }
+
+/* open, close, read, write, ioctl */
+#define cdev_iic_init(c,n) cdev__ocrwi_init(c,n)
+#define cdev_rtc_init(c,n) cdev__ocrwi_init(c,n)
+
+/* open, close, read, ioctl */
+#define cdev_prof_init(c,n) cdev__ocri_init(c,n)
+
+cdev_decl(physcon);
+cdev_decl(vidcconsole);
+cdev_decl(biconsdev);
+cdev_decl(com);
+cdev_decl(lpt);
+cdev_decl(qms);
+cdev_decl(opms);
+cdev_decl(beep);
+cdev_decl(kbd);
+cdev_decl(iic);
+cdev_decl(rtc);
+cdev_decl(fcom);
+cdev_decl(pc);
+cdev_decl(ofcons_);
+cdev_decl(ofd);
+cdev_decl(ofrtc);
+cdev_decl(sacom);
+cdev_decl(scr);
+cdev_decl(prof);
+#define ofromread ofromrw
+#define ofromwrite ofromrw
+cdev_decl(ofrom);
+cdev_decl(joy);
+cdev_decl(usb);
+cdev_decl(uhid);
+cdev_decl(ugen);
+cdev_decl(ulpt);
+cdev_decl(ucom);
+cdev_decl(urio);
+cdev_decl(uscanner);
+cdev_decl(vc_nb_);
+cdev_decl(wsdisplay);
+cdev_decl(wsfont);
+cdev_decl(wskbd);
+cdev_decl(wsmouse);
+cdev_decl(wsmux);
+cdev_decl(scsibus);
+cdev_decl(openfirm);
+cdev_decl(pci);
+cdev_decl(agp);
+cdev_decl(iop);
+cdev_decl(ld);
+cdev_decl(mlx);
+cdev_decl(mly);
+cdev_decl(plcom);
+
+#endif /* _ARM_CONF_H_ */
diff --git a/sys/arch/arm/include/cpu.h b/sys/arch/arm/include/cpu.h
new file mode 100644
index 00000000000..22b999ed8fb
--- /dev/null
+++ b/sys/arch/arm/include/cpu.h
@@ -0,0 +1,302 @@
+/* $OpenBSD: cpu.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: cpu.h,v 1.34 2003/06/23 11:01:08 martin Exp $ */
+
+/*
+ * Copyright (c) 1994-1996 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * cpu.h
+ *
+ * CPU specific symbols
+ *
+ * Created : 18/09/94
+ *
+ * Based on kate/katelib/arm6.h
+ */
+
+#ifndef _ARM_CPU_H_
+#define _ARM_CPU_H_
+
+/*
+ * User-visible definitions
+ */
+
+/* CTL_MACHDEP definitions. */
+#define CPU_DEBUG 1 /* int: misc kernel debug control */
+#define CPU_BOOTED_DEVICE 2 /* string: device we booted from */
+#define CPU_BOOTED_KERNEL 3 /* string: kernel we booted */
+#define CPU_CONSDEV 4 /* struct: dev_t of our console */
+#define CPU_POWERSAVE 5 /* int: use CPU powersave mode */
+#define CPU_MAXID 6 /* number of valid machdep ids */
+
+#define CTL_MACHDEP_NAMES { \
+ { 0, 0 }, \
+ { "debug", CTLTYPE_INT }, \
+ { "booted_device", CTLTYPE_STRING }, \
+ { "booted_kernel", CTLTYPE_STRING }, \
+ { "console_device", CTLTYPE_STRUCT }, \
+ { "powersave", CTLTYPE_INT }, \
+}
+
+#ifdef _KERNEL
+
+/*
+ * Kernel-only definitions
+ */
+
+#include <arm/cpuconf.h>
+
+#include <machine/intr.h>
+#ifndef _LOCORE
+#if 0
+#include <sys/user.h>
+#endif
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#endif /* !_LOCORE */
+
+#include <arm/armreg.h>
+
+#ifndef _LOCORE
+/* 1 == use cpu_sleep(), 0 == don't */
+extern int cpu_do_powersave;
+#endif
+
+#ifdef __PROG32
+#ifdef _LOCORE
+#define IRQdisable \
+ stmfd sp!, {r0} ; \
+ mrs r0, cpsr ; \
+ orr r0, r0, #(I32_bit) ; \
+ msr cpsr_c, r0 ; \
+ ldmfd sp!, {r0}
+
+#define IRQenable \
+ stmfd sp!, {r0} ; \
+ mrs r0, cpsr ; \
+ bic r0, r0, #(I32_bit) ; \
+ msr cpsr_c, r0 ; \
+ ldmfd sp!, {r0}
+
+#else
+#define IRQdisable __set_cpsr_c(I32_bit, I32_bit);
+#define IRQenable __set_cpsr_c(I32_bit, 0);
+#endif /* _LOCORE */
+#endif
+
+#ifndef _LOCORE
+
+/* All the CLKF_* macros take a struct clockframe * as an argument. */
+
+/*
+ * CLKF_USERMODE: Return TRUE/FALSE (1/0) depending on whether the
+ * frame came from USR mode or not.
+ */
+#ifdef __PROG32
+#define CLKF_USERMODE(frame) ((frame->if_spsr & PSR_MODE) == PSR_USR32_MODE)
+#else
+#define CLKF_USERMODE(frame) ((frame->if_r15 & R15_MODE) == R15_MODE_USR)
+#endif
+
+/*
+ * CLKF_BASEPRI: True if we were at spl0 before the interrupt.
+ *
+ * This is hard-wired to 0 on the ARM, since spllowersoftclock() might
+ * not actually be able to unblock the interrupt, which would cause us
+ * to run the softclock interrupts with hardclock blocked.
+ */
+#define CLKF_BASEPRI(frame) 0
+
+/*
+ * CLKF_INTR: True if we took the interrupt from inside another
+ * interrupt handler.
+ */
+extern int current_intr_depth;
+#ifdef __PROG32
+/* Hack to treat FPE time as interrupt time so we can measure it */
+#define CLKF_INTR(frame) \
+ ((current_intr_depth > 1) || \
+ (frame->if_spsr & PSR_MODE) == PSR_UND32_MODE)
+#else
+#define CLKF_INTR(frame) (current_intr_depth > 1)
+#endif
+
+/*
+ * CLKF_PC: Extract the program counter from a clockframe
+ */
+#ifdef __PROG32
+#define CLKF_PC(frame) (frame->if_pc)
+#else
+#define CLKF_PC(frame) (frame->if_r15 & R15_PC)
+#endif
+
+/*
+ * PROC_PC: Find out the program counter for the given process.
+ */
+#ifdef __PROG32
+#define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_pc)
+#else
+#define PROC_PC(p) ((p)->p_addr->u_pcb.pcb_tf->tf_r15 & R15_PC)
+#endif
+
+/* The address of the vector page. */
+extern vaddr_t vector_page;
+#ifdef __PROG32
+void arm32_vector_init(vaddr_t, int);
+
+#define ARM_VEC_RESET (1 << 0)
+#define ARM_VEC_UNDEFINED (1 << 1)
+#define ARM_VEC_SWI (1 << 2)
+#define ARM_VEC_PREFETCH_ABORT (1 << 3)
+#define ARM_VEC_DATA_ABORT (1 << 4)
+#define ARM_VEC_ADDRESS_EXCEPTION (1 << 5)
+#define ARM_VEC_IRQ (1 << 6)
+#define ARM_VEC_FIQ (1 << 7)
+
+#define ARM_NVEC 8
+#define ARM_VEC_ALL 0xffffffff
+#endif
+
+/*
+ * Per-CPU information. For now we assume one CPU.
+ */
+
+#include <sys/device.h>
+/*
+#include <sys/sched.h>
+*/
+struct cpu_info {
+#if 0
+ struct schedstate_percpu ci_schedstate; /* scheduler state */
+#endif
+#if defined(DIAGNOSTIC) || defined(LOCKDEBUG)
+ u_long ci_spin_locks; /* # of spin locks held */
+ u_long ci_simple_locks; /* # of simple locks held */
+#endif
+ struct device *ci_dev; /* Device corresponding to this CPU */
+ u_int32_t ci_arm_cpuid; /* aggregate CPU id */
+ u_int32_t ci_arm_cputype; /* CPU type */
+ u_int32_t ci_arm_cpurev; /* CPU revision */
+ u_int32_t ci_ctrl; /* The CPU control register */
+ struct evcnt ci_arm700bugcount;
+#ifdef MULTIPROCESSOR
+ MP_CPU_INFO_MEMBERS
+#endif
+};
+
+#ifndef MULTIPROCESSOR
+extern struct cpu_info cpu_info_store;
+#define curcpu() (&cpu_info_store)
+#define cpu_number() 0
+#endif
+
+#ifdef __PROG32
+void cpu_proc_fork(struct proc *, struct proc *);
+#else
+#define cpu_proc_fork(p1, p2)
+#endif
+
+/*
+ * Scheduling glue
+ */
+
+extern int astpending;
+#define setsoftast() (astpending = 1)
+
+/*
+ * Notify the current process (p) that it has a signal pending,
+ * process as soon as possible.
+ */
+
+#define signotify(p) setsoftast()
+
+#define cpu_wait(p) /* nothing */
+
+/*
+ * Preempt the current process if in interrupt from user mode,
+ * or after the current trap/syscall if in system mode.
+ */
+extern int want_resched; /* resched() was called */
+#define need_resched(ci) (want_resched = 1, setsoftast())
+
+/*
+ * Give a profiling tick to the current process when the user profiling
+ * buffer pages are invalid. On the i386, request an ast to send us
+ * through trap(), marking the proc as needing a profiling tick.
+ */
+#define need_proftick(p) ((p)->p_flag |= P_OWEUPC, setsoftast())
+
+#ifndef acorn26
+/*
+ * cpu device glue (belongs in cpuvar.h)
+ */
+
+struct device;
+void cpu_attach __P((struct device *));
+int cpu_alloc_idlepcb __P((struct cpu_info *));
+#endif
+
+
+/*
+ * Random cruft
+ */
+
+/* locore.S */
+void atomic_set_bit __P((u_int *address, u_int setmask));
+void atomic_clear_bit __P((u_int *address, u_int clearmask));
+
+/* cpuswitch.S */
+struct pcb;
+void savectx __P((struct pcb *pcb));
+
+/* ast.c */
+void userret __P((register struct proc *p));
+
+/* machdep.h */
+void bootsync __P((void));
+
+/* fault.c */
+int badaddr_read __P((void *, size_t, void *));
+
+/* syscall.c */
+void swi_handler __P((trapframe_t *));
+
+#endif /* !_LOCORE */
+
+#endif /* _KERNEL */
+
+#endif /* !_ARM_CPU_H_ */
+
+/* End of cpu.h */
diff --git a/sys/arch/arm/include/cpuconf.h b/sys/arch/arm/include/cpuconf.h
new file mode 100644
index 00000000000..8ccd375e18e
--- /dev/null
+++ b/sys/arch/arm/include/cpuconf.h
@@ -0,0 +1,177 @@
+/* $OpenBSD: cpuconf.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: cpuconf.h,v 1.7 2003/05/23 00:57:24 ichiro Exp $ */
+
+/*
+ * Copyright (c) 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_CPUCONF_H_
+#define _ARM_CPUCONF_H_
+
+#if defined(_KERNEL_OPT)
+#include "opt_cputypes.h"
+#endif /* _KERNEL_OPT */
+
+/*
+ * IF YOU CHANGE THIS FILE, MAKE SURE TO UPDATE THE DEFINITION OF
+ * "PMAP_NEEDS_PTE_SYNC" IN <arm/arm/pmap.h> FOR THE CPU TYPE
+ * YOU ARE ADDING SUPPORT FOR.
+ */
+
+/*
+ * Step 1: Count the number of CPU types configured into the kernel.
+ */
+#if defined(_KERNEL_OPT)
+#define CPU_NTYPES (defined(CPU_ARM2) + defined(CPU_ARM250) + \
+ defined(CPU_ARM3) + \
+ defined(CPU_ARM6) + defined(CPU_ARM7) + \
+ defined(CPU_ARM7TDMI) + \
+ defined(CPU_ARM8) + defined(CPU_ARM9) + \
+ defined(CPU_ARM10) + \
+ defined(CPU_SA110) + defined(CPU_SA1100) + \
+ defined(CPU_SA1110) + \
+ defined(CPU_IXP12X0) + \
+ defined(CPU_XSCALE_80200) + \
+ defined(CPU_XSCALE_80321) + \
+ defined(CPU_XSCALE_PXA2X0) + \
+ defined(CPU_XSCALE_IXP425))
+#else
+#define CPU_NTYPES 2
+#endif /* _KERNEL_OPT */
+
+/*
+ * Step 2: Determine which ARM architecture versions are configured.
+ */
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_ARM2) || defined(CPU_ARM250) || defined(CPU_ARM3))
+#define ARM_ARCH_2 1
+#else
+#define ARM_ARCH_2 0
+#endif
+
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_ARM6) || defined(CPU_ARM7))
+#define ARM_ARCH_3 1
+#else
+#define ARM_ARCH_3 0
+#endif
+
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_ARM7TDMI) || defined(CPU_ARM8) || defined(CPU_ARM9) || \
+ defined(CPU_ARM10) || defined(CPU_SA110) || defined(CPU_SA1100) || \
+ defined(CPU_SA1110) || defined(CPU_IXP12X0) || defined(CPU_XSCALE_IXP425))
+#define ARM_ARCH_4 1
+#else
+#define ARM_ARCH_4 0
+#endif
+
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0))
+#define ARM_ARCH_5 1
+#else
+#define ARM_ARCH_5 0
+#endif
+
+#define ARM_NARCH (ARM_ARCH_2 + ARM_ARCH_3 + ARM_ARCH_4 + ARM_ARCH_5)
+#if ARM_NARCH == 0
+#error ARM_NARCH is 0
+#endif
+
+/*
+ * Step 3: Define which MMU classes are configured:
+ *
+ * ARM_MMU_MEMC Prehistoric, external memory controller
+ * and MMU for ARMv2 CPUs.
+ *
+ * ARM_MMU_GENERIC Generic ARM MMU, compatible with ARM6.
+ *
+ * ARM_MMU_SA1 StrongARM SA-1 MMU. Compatible with generic
+ * ARM MMU, but has no write-through cache mode.
+ *
+ * ARM_MMU_XSCALE XScale MMU. Compatible with generic ARM
+ * MMU, but also has several extensions which
+ * require different PTE layout to use.
+ */
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_ARM2) || defined(CPU_ARM250) || defined(CPU_ARM3))
+#define ARM_MMU_MEMC 1
+#else
+#define ARM_MMU_MEMC 0
+#endif
+
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7TDMI) || \
+ defined(CPU_ARM8) || defined(CPU_ARM9) || defined(CPU_ARM10))
+#define ARM_MMU_GENERIC 1
+#else
+#define ARM_MMU_GENERIC 0
+#endif
+
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_SA110) || defined(CPU_SA1100) || defined(CPU_SA1110) ||\
+ defined(CPU_IXP12X0))
+#define ARM_MMU_SA1 1
+#else
+#define ARM_MMU_SA1 0
+#endif
+
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425))
+#define ARM_MMU_XSCALE 1
+#else
+#define ARM_MMU_XSCALE 0
+#endif
+
+#define ARM_NMMUS (ARM_MMU_MEMC + ARM_MMU_GENERIC + \
+ ARM_MMU_SA1 + ARM_MMU_XSCALE)
+#if ARM_NMMUS == 0
+#error ARM_NMMUS is 0
+#endif
+
+/*
+ * Step 4: Define features that may be present on a subset of CPUs
+ *
+ * ARM_XSCALE_PMU Performance Monitoring Unit on 80200 and 80321
+ */
+
+#if !defined(_KERNEL_OPT) || \
+ (defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321))
+#define ARM_XSCALE_PMU 1
+#else
+#define ARM_XSCALE_PMU 0
+#endif
+
+#endif /* _ARM_CPUCONF_H_ */
diff --git a/sys/arch/arm/include/cpufunc.h b/sys/arch/arm/include/cpufunc.h
new file mode 100644
index 00000000000..f732dfe03c2
--- /dev/null
+++ b/sys/arch/arm/include/cpufunc.h
@@ -0,0 +1,524 @@
+/* $OpenBSD: cpufunc.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: cpufunc.h,v 1.29 2003/09/06 09:08:35 rearnsha Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Causality Limited.
+ * 4. The name of Causality Limited may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY CAUSALITY LIMITED ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL CAUSALITY LIMITED BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * cpufunc.h
+ *
+ * Prototypes for cpu, mmu and tlb related functions.
+ */
+
+#ifndef _ARM32_CPUFUNC_H_
+#define _ARM32_CPUFUNC_H_
+
+#ifdef _KERNEL
+
+#include <sys/types.h>
+#include <arm/cpuconf.h>
+
+struct cpu_functions {
+
+ /* CPU functions */
+
+ u_int (*cf_id) __P((void));
+ void (*cf_cpwait) __P((void));
+
+ /* MMU functions */
+
+ u_int (*cf_control) __P((u_int bic, u_int eor));
+ void (*cf_domains) __P((u_int domains));
+ void (*cf_setttb) __P((u_int ttb));
+ u_int (*cf_faultstatus) __P((void));
+ u_int (*cf_faultaddress) __P((void));
+
+ /* TLB functions */
+
+ void (*cf_tlb_flushID) __P((void));
+ void (*cf_tlb_flushID_SE) __P((u_int va));
+ void (*cf_tlb_flushI) __P((void));
+ void (*cf_tlb_flushI_SE) __P((u_int va));
+ void (*cf_tlb_flushD) __P((void));
+ void (*cf_tlb_flushD_SE) __P((u_int va));
+
+ /*
+ * Cache operations:
+ *
+ * We define the following primitives:
+ *
+ * icache_sync_all Synchronize I-cache
+ * icache_sync_range Synchronize I-cache range
+ *
+ * dcache_wbinv_all Write-back and Invalidate D-cache
+ * dcache_wbinv_range Write-back and Invalidate D-cache range
+ * dcache_inv_range Invalidate D-cache range
+ * dcache_wb_range Write-back D-cache range
+ *
+ * idcache_wbinv_all Write-back and Invalidate D-cache,
+ * Invalidate I-cache
+ * idcache_wbinv_range Write-back and Invalidate D-cache,
+ * Invalidate I-cache range
+ *
+ * Note that the ARM term for "write-back" is "clean". We use
+ * the term "write-back" since it's a more common way to describe
+ * the operation.
+ *
+ * There are some rules that must be followed:
+ *
+ * I-cache Synch (all or range):
+ * The goal is to synchronize the instruction stream,
+ * so you may beed to write-back dirty D-cache blocks
+ * first. If a range is requested, and you can't
+ * synchronize just a range, you have to hit the whole
+ * thing.
+ *
+ * D-cache Write-Back and Invalidate range:
+ * If you can't WB-Inv a range, you must WB-Inv the
+ * entire D-cache.
+ *
+ * D-cache Invalidate:
+ * If you can't Inv the D-cache, you must Write-Back
+ * and Invalidate. Code that uses this operation
+ * MUST NOT assume that the D-cache will not be written
+ * back to memory.
+ *
+ * D-cache Write-Back:
+ * If you can't Write-back without doing an Inv,
+ * that's fine. Then treat this as a WB-Inv.
+ * Skipping the invalidate is merely an optimization.
+ *
+ * All operations:
+ * Valid virtual addresses must be passed to each
+ * cache operation.
+ */
+ void (*cf_icache_sync_all) __P((void));
+ void (*cf_icache_sync_range) __P((vaddr_t, vsize_t));
+
+ void (*cf_dcache_wbinv_all) __P((void));
+ void (*cf_dcache_wbinv_range) __P((vaddr_t, vsize_t));
+ void (*cf_dcache_inv_range) __P((vaddr_t, vsize_t));
+ void (*cf_dcache_wb_range) __P((vaddr_t, vsize_t));
+
+ void (*cf_idcache_wbinv_all) __P((void));
+ void (*cf_idcache_wbinv_range) __P((vaddr_t, vsize_t));
+
+ /* Other functions */
+
+ void (*cf_flush_prefetchbuf) __P((void));
+ void (*cf_drain_writebuf) __P((void));
+ void (*cf_flush_brnchtgt_C) __P((void));
+ void (*cf_flush_brnchtgt_E) __P((u_int va));
+
+ void (*cf_sleep) __P((int mode));
+
+ /* Soft functions */
+
+ int (*cf_dataabt_fixup) __P((void *arg));
+ int (*cf_prefetchabt_fixup) __P((void *arg));
+
+ void (*cf_context_switch) __P((void));
+
+ void (*cf_setup) __P((char *string));
+};
+
+extern struct cpu_functions cpufuncs;
+extern u_int cputype;
+
+#define cpu_id() cpufuncs.cf_id()
+#define cpu_cpwait() cpufuncs.cf_cpwait()
+
+#define cpu_control(c, e) cpufuncs.cf_control(c, e)
+#define cpu_domains(d) cpufuncs.cf_domains(d)
+#define cpu_setttb(t) cpufuncs.cf_setttb(t)
+#define cpu_faultstatus() cpufuncs.cf_faultstatus()
+#define cpu_faultaddress() cpufuncs.cf_faultaddress()
+
+#define cpu_tlb_flushID() cpufuncs.cf_tlb_flushID()
+#define cpu_tlb_flushID_SE(e) cpufuncs.cf_tlb_flushID_SE(e)
+#define cpu_tlb_flushI() cpufuncs.cf_tlb_flushI()
+#define cpu_tlb_flushI_SE(e) cpufuncs.cf_tlb_flushI_SE(e)
+#define cpu_tlb_flushD() cpufuncs.cf_tlb_flushD()
+#define cpu_tlb_flushD_SE(e) cpufuncs.cf_tlb_flushD_SE(e)
+
+#define cpu_icache_sync_all() cpufuncs.cf_icache_sync_all()
+#define cpu_icache_sync_range(a, s) cpufuncs.cf_icache_sync_range((a), (s))
+
+#define cpu_dcache_wbinv_all() cpufuncs.cf_dcache_wbinv_all()
+#define cpu_dcache_wbinv_range(a, s) cpufuncs.cf_dcache_wbinv_range((a), (s))
+#define cpu_dcache_inv_range(a, s) cpufuncs.cf_dcache_inv_range((a), (s))
+#define cpu_dcache_wb_range(a, s) cpufuncs.cf_dcache_wb_range((a), (s))
+
+#define cpu_idcache_wbinv_all() cpufuncs.cf_idcache_wbinv_all()
+#define cpu_idcache_wbinv_range(a, s) cpufuncs.cf_idcache_wbinv_range((a), (s))
+
+#define cpu_flush_prefetchbuf() cpufuncs.cf_flush_prefetchbuf()
+#define cpu_drain_writebuf() cpufuncs.cf_drain_writebuf()
+#define cpu_flush_brnchtgt_C() cpufuncs.cf_flush_brnchtgt_C()
+#define cpu_flush_brnchtgt_E(e) cpufuncs.cf_flush_brnchtgt_E(e)
+
+#define cpu_sleep(m) cpufuncs.cf_sleep(m)
+
+#define cpu_dataabt_fixup(a) cpufuncs.cf_dataabt_fixup(a)
+#define cpu_prefetchabt_fixup(a) cpufuncs.cf_prefetchabt_fixup(a)
+#define ABORT_FIXUP_OK 0 /* fixup succeeded */
+#define ABORT_FIXUP_FAILED 1 /* fixup failed */
+#define ABORT_FIXUP_RETURN 2 /* abort handler should return */
+
+#define cpu_setup(a) cpufuncs.cf_setup(a)
+
+int set_cpufuncs __P((void));
+#define ARCHITECTURE_NOT_PRESENT 1 /* known but not configured */
+#define ARCHITECTURE_NOT_SUPPORTED 2 /* not known */
+
+void cpufunc_nullop __P((void));
+int cpufunc_null_fixup __P((void *));
+int early_abort_fixup __P((void *));
+int late_abort_fixup __P((void *));
+u_int cpufunc_id __P((void));
+u_int cpufunc_control __P((u_int clear, u_int bic));
+void cpufunc_domains __P((u_int domains));
+u_int cpufunc_faultstatus __P((void));
+u_int cpufunc_faultaddress __P((void));
+
+#ifdef CPU_ARM3
+u_int arm3_control __P((u_int clear, u_int bic));
+void arm3_cache_flush __P((void));
+#endif /* CPU_ARM3 */
+
+#if defined(CPU_ARM6) || defined(CPU_ARM7)
+void arm67_setttb __P((u_int ttb));
+void arm67_tlb_flush __P((void));
+void arm67_tlb_purge __P((u_int va));
+void arm67_cache_flush __P((void));
+void arm67_context_switch __P((void));
+#endif /* CPU_ARM6 || CPU_ARM7 */
+
+#ifdef CPU_ARM6
+void arm6_setup __P((char *string));
+#endif /* CPU_ARM6 */
+
+#ifdef CPU_ARM7
+void arm7_setup __P((char *string));
+#endif /* CPU_ARM7 */
+
+#ifdef CPU_ARM7TDMI
+int arm7_dataabt_fixup __P((void *arg));
+void arm7tdmi_setup __P((char *string));
+void arm7tdmi_setttb __P((u_int ttb));
+void arm7tdmi_tlb_flushID __P((void));
+void arm7tdmi_tlb_flushID_SE __P((u_int va));
+void arm7tdmi_cache_flushID __P((void));
+void arm7tdmi_context_switch __P((void));
+#endif /* CPU_ARM7TDMI */
+
+#ifdef CPU_ARM8
+void arm8_setttb __P((u_int ttb));
+void arm8_tlb_flushID __P((void));
+void arm8_tlb_flushID_SE __P((u_int va));
+void arm8_cache_flushID __P((void));
+void arm8_cache_flushID_E __P((u_int entry));
+void arm8_cache_cleanID __P((void));
+void arm8_cache_cleanID_E __P((u_int entry));
+void arm8_cache_purgeID __P((void));
+void arm8_cache_purgeID_E __P((u_int entry));
+
+void arm8_cache_syncI __P((void));
+void arm8_cache_cleanID_rng __P((vaddr_t start, vsize_t end));
+void arm8_cache_cleanD_rng __P((vaddr_t start, vsize_t end));
+void arm8_cache_purgeID_rng __P((vaddr_t start, vsize_t end));
+void arm8_cache_purgeD_rng __P((vaddr_t start, vsize_t end));
+void arm8_cache_syncI_rng __P((vaddr_t start, vsize_t end));
+
+void arm8_context_switch __P((void));
+
+void arm8_setup __P((char *string));
+
+u_int arm8_clock_config __P((u_int, u_int));
+#endif
+
+#ifdef CPU_SA110
+void sa110_setup __P((char *string));
+void sa110_context_switch __P((void));
+#endif /* CPU_SA110 */
+
+#if defined(CPU_SA1100) || defined(CPU_SA1110)
+void sa11x0_drain_readbuf __P((void));
+
+void sa11x0_context_switch __P((void));
+void sa11x0_cpu_sleep __P((int mode));
+
+void sa11x0_setup __P((char *string));
+#endif
+
+#if defined(CPU_SA110) || defined(CPU_SA1100) || defined(CPU_SA1110)
+void sa1_setttb __P((u_int ttb));
+
+void sa1_tlb_flushID_SE __P((u_int va));
+
+void sa1_cache_flushID __P((void));
+void sa1_cache_flushI __P((void));
+void sa1_cache_flushD __P((void));
+void sa1_cache_flushD_SE __P((u_int entry));
+
+void sa1_cache_cleanID __P((void));
+void sa1_cache_cleanD __P((void));
+void sa1_cache_cleanD_E __P((u_int entry));
+
+void sa1_cache_purgeID __P((void));
+void sa1_cache_purgeID_E __P((u_int entry));
+void sa1_cache_purgeD __P((void));
+void sa1_cache_purgeD_E __P((u_int entry));
+
+void sa1_cache_syncI __P((void));
+void sa1_cache_cleanID_rng __P((vaddr_t start, vsize_t end));
+void sa1_cache_cleanD_rng __P((vaddr_t start, vsize_t end));
+void sa1_cache_purgeID_rng __P((vaddr_t start, vsize_t end));
+void sa1_cache_purgeD_rng __P((vaddr_t start, vsize_t end));
+void sa1_cache_syncI_rng __P((vaddr_t start, vsize_t end));
+
+#endif
+
+#ifdef CPU_ARM9
+void arm9_setttb __P((u_int));
+
+void arm9_tlb_flushID_SE __P((u_int va));
+
+void arm9_cache_flushID __P((void));
+void arm9_cache_flushID_SE __P((u_int));
+void arm9_cache_flushI __P((void));
+void arm9_cache_flushI_SE __P((u_int));
+void arm9_cache_flushD __P((void));
+void arm9_cache_flushD_SE __P((u_int));
+
+void arm9_cache_cleanID __P((void));
+
+void arm9_cache_syncI __P((void));
+void arm9_cache_flushID_rng __P((vaddr_t, vsize_t));
+void arm9_cache_flushD_rng __P((vaddr_t, vsize_t));
+void arm9_cache_syncI_rng __P((vaddr_t, vsize_t));
+
+void arm9_context_switch __P((void));
+
+void arm9_setup __P((char *string));
+#endif
+
+#ifdef CPU_ARM10
+void arm10_setttb __P((u_int));
+
+void arm10_tlb_flushID_SE __P((u_int));
+void arm10_tlb_flushI_SE __P((u_int));
+
+void arm10_icache_sync_all __P((void));
+void arm10_icache_sync_range __P((vaddr_t, vsize_t));
+
+void arm10_dcache_wbinv_all __P((void));
+void arm10_dcache_wbinv_range __P((vaddr_t, vsize_t));
+void arm10_dcache_inv_range __P((vaddr_t, vsize_t));
+void arm10_dcache_wb_range __P((vaddr_t, vsize_t));
+
+void arm10_idcache_wbinv_all __P((void));
+void arm10_idcache_wbinv_range __P((vaddr_t, vsize_t));
+
+void arm10_context_switch __P((void));
+
+void arm10_setup __P((char *string));
+
+extern unsigned arm10_dcache_sets_max;
+extern unsigned arm10_dcache_sets_inc;
+extern unsigned arm10_dcache_index_max;
+extern unsigned arm10_dcache_index_inc;
+#endif
+
+#if defined(CPU_ARM9) || defined(CPU_ARM10) || defined(CPU_SA110) || \
+ defined(CPU_SA1100) || defined(CPU_SA1110) || \
+ defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425)
+
+void armv4_tlb_flushID __P((void));
+void armv4_tlb_flushI __P((void));
+void armv4_tlb_flushD __P((void));
+void armv4_tlb_flushD_SE __P((u_int va));
+
+void armv4_drain_writebuf __P((void));
+#endif
+
+#if defined(CPU_IXP12X0)
+void ixp12x0_drain_readbuf __P((void));
+void ixp12x0_context_switch __P((void));
+void ixp12x0_setup __P((char *string));
+#endif
+
+#if defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) || \
+ defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) || \
+ (ARM_MMU_XSCALE == 1)
+void xscale_cpwait __P((void));
+
+void xscale_cpu_sleep __P((int mode));
+
+u_int xscale_control __P((u_int clear, u_int bic));
+
+void xscale_setttb __P((u_int ttb));
+
+void xscale_tlb_flushID_SE __P((u_int va));
+
+void xscale_cache_flushID __P((void));
+void xscale_cache_flushI __P((void));
+void xscale_cache_flushD __P((void));
+void xscale_cache_flushD_SE __P((u_int entry));
+
+void xscale_cache_cleanID __P((void));
+void xscale_cache_cleanD __P((void));
+void xscale_cache_cleanD_E __P((u_int entry));
+
+void xscale_cache_clean_minidata __P((void));
+
+void xscale_cache_purgeID __P((void));
+void xscale_cache_purgeID_E __P((u_int entry));
+void xscale_cache_purgeD __P((void));
+void xscale_cache_purgeD_E __P((u_int entry));
+
+void xscale_cache_syncI __P((void));
+void xscale_cache_cleanID_rng __P((vaddr_t start, vsize_t end));
+void xscale_cache_cleanD_rng __P((vaddr_t start, vsize_t end));
+void xscale_cache_purgeID_rng __P((vaddr_t start, vsize_t end));
+void xscale_cache_purgeD_rng __P((vaddr_t start, vsize_t end));
+void xscale_cache_syncI_rng __P((vaddr_t start, vsize_t end));
+void xscale_cache_flushD_rng __P((vaddr_t start, vsize_t end));
+
+void xscale_context_switch __P((void));
+
+void xscale_setup __P((char *string));
+#endif /* CPU_XSCALE_80200 || CPU_XSCALE_80321 || CPU_XSCALE_PXA2X0 || CPU_XSCALE_IXP425 */
+
+#define tlb_flush cpu_tlb_flushID
+#define setttb cpu_setttb
+#define drain_writebuf cpu_drain_writebuf
+
+/*
+ * Macros for manipulating CPU interrupts
+ */
+#ifdef __PROG32
+static __inline u_int32_t __set_cpsr_c(u_int bic, u_int eor) __attribute__((__unused__));
+
+static __inline u_int32_t
+__set_cpsr_c(u_int bic, u_int eor)
+{
+ u_int32_t tmp, ret;
+
+ __asm __volatile(
+ "mrs %0, cpsr\n" /* Get the CPSR */
+ "bic %1, %0, %2\n" /* Clear bits */
+ "eor %1, %1, %3\n" /* XOR bits */
+ "msr cpsr_c, %1\n" /* Set the control field of CPSR */
+ : "=&r" (ret), "=&r" (tmp)
+ : "r" (bic), "r" (eor));
+
+ return ret;
+}
+
+#define disable_interrupts(mask) \
+ (__set_cpsr_c((mask) & (I32_bit | F32_bit), \
+ (mask) & (I32_bit | F32_bit)))
+
+#define enable_interrupts(mask) \
+ (__set_cpsr_c((mask) & (I32_bit | F32_bit), 0))
+
+#define restore_interrupts(old_cpsr) \
+ (__set_cpsr_c((I32_bit | F32_bit), (old_cpsr) & (I32_bit | F32_bit)))
+#else /* ! __PROG32 */
+#define disable_interrupts(mask) \
+ (set_r15((mask) & (R15_IRQ_DISABLE | R15_FIQ_DISABLE), \
+ (mask) & (R15_IRQ_DISABLE | R15_FIQ_DISABLE)))
+
+#define enable_interrupts(mask) \
+ (set_r15((mask) & (R15_IRQ_DISABLE | R15_FIQ_DISABLE), 0))
+
+#define restore_interrupts(old_r15) \
+ (set_r15((R15_IRQ_DISABLE | R15_FIQ_DISABLE), \
+ (old_r15) & (R15_IRQ_DISABLE | R15_FIQ_DISABLE)))
+#endif /* __PROG32 */
+
+#ifdef __PROG32
+/* Functions to manipulate the CPSR. */
+u_int SetCPSR(u_int bic, u_int eor);
+u_int GetCPSR(void);
+#else
+/* Functions to manipulate the processor control bits in r15. */
+u_int set_r15(u_int bic, u_int eor);
+u_int get_r15(void);
+#endif /* __PROG32 */
+
+/*
+ * Functions to manipulate cpu r13
+ * (in arm/arm/setstack.S)
+ */
+
+void set_stackptr __P((u_int mode, u_int address));
+u_int get_stackptr __P((u_int mode));
+
+/*
+ * Miscellany
+ */
+
+int get_pc_str_offset __P((void));
+
+/*
+ * CPU functions from locore.S
+ */
+
+void cpu_reset __P((void)) __attribute__((__noreturn__));
+
+/*
+ * Cache info variables.
+ */
+
+/* PRIMARY CACHE VARIABLES */
+extern int arm_picache_size;
+extern int arm_picache_line_size;
+extern int arm_picache_ways;
+
+extern int arm_pdcache_size; /* and unified */
+extern int arm_pdcache_line_size;
+extern int arm_pdcache_ways;
+
+extern int arm_pcache_type;
+extern int arm_pcache_unified;
+
+extern int arm_dcache_align;
+extern int arm_dcache_align_mask;
+
+#endif /* _KERNEL */
+#endif /* _ARM32_CPUFUNC_H_ */
+
+/* End of cpufunc.h */
diff --git a/sys/arch/arm/include/db_machdep.h b/sys/arch/arm/include/db_machdep.h
new file mode 100644
index 00000000000..073bd60d296
--- /dev/null
+++ b/sys/arch/arm/include/db_machdep.h
@@ -0,0 +1,117 @@
+/* $OpenBSD: db_machdep.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: db_machdep.h,v 1.5 2001/11/22 18:00:00 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1996 Scott K Stevens
+ *
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _ARM_DB_MACHDEP_H_
+#define _ARM_DB_MACHDEP_H_
+
+/*
+ * Machine-dependent defines for new kernel debugger.
+ */
+
+#include <uvm/uvm_extern.h>
+#include <arm/armreg.h>
+#include <machine/frame.h>
+#include <machine/trap.h>
+
+/* end of mangling */
+
+typedef vaddr_t db_addr_t; /* address - unsigned */
+typedef long db_expr_t; /* expression - signed */
+
+typedef trapframe_t db_regs_t;
+
+extern db_regs_t ddb_regs; /* register state */
+#define DDB_REGS (&ddb_regs)
+
+#ifdef __PROG26
+#define PC_REGS(regs) ((db_addr_t)(regs)->tf_r15 & R15_PC)
+#define PC_ADVANCE(regs) ((regs)->tf_r15 += 4)
+#else
+#define PC_REGS(regs) ((db_addr_t)(regs)->tf_pc)
+#endif
+
+#define BKPT_INST (KERNEL_BREAKPOINT) /* breakpoint instruction */
+#define BKPT_SIZE (INSN_SIZE) /* size of breakpoint inst */
+#define BKPT_SET(inst) (BKPT_INST)
+
+/*#define FIXUP_PC_AFTER_BREAK(regs) ((regs)->tf_pc -= BKPT_SIZE)*/
+
+#define T_BREAKPOINT (1)
+
+#define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BREAKPOINT)
+#define IS_WATCHPOINT_TRAP(type, code) (0)
+
+#define inst_trap_return(ins) (0)
+/* ldmxx reg, {..., pc}
+ 01800000 stack mode
+ 000f0000 register
+ 0000ffff register list */
+/* mov pc, reg
+ 0000000f register */
+#define inst_return(ins) (((ins) & 0x0e108000) == 0x08108000 || \
+ ((ins) & 0x0ff0fff0) == 0x01a0f000)
+/* bl ...
+ 00ffffff offset>>2 */
+#define inst_call(ins) (((ins) & 0x0f000000) == 0x0b000000)
+/* b ...
+ 00ffffff offset>>2 */
+/* ldr pc, [pc, reg, lsl #2]
+ 0000000f register */
+#define inst_branch(ins) (((ins) & 0x0f000000) == 0x0a000000 || \
+ ((ins) & 0x0fdffff0) == 0x079ff100)
+#define inst_load(ins) (0)
+#define inst_store(ins) (0)
+#define inst_unconditional_flow_transfer(ins) \
+ ((((ins) & INSN_COND_MASK) == INSN_COND_AL) && \
+ (inst_branch(ins) || inst_call(ins) || inst_return(ins)))
+
+#define getreg_val (0)
+#define next_instr_address(pc, bd) ((bd) ? (pc) : ((pc) + INSN_SIZE))
+
+#define DB_MACHINE_COMMANDS
+
+#define SOFTWARE_SSTEP
+
+db_addr_t db_branch_taken(u_int inst, db_addr_t pc, db_regs_t *regs);
+int kdb_trap __P((int, db_regs_t *));
+void db_machine_init __P((void));
+
+#define branch_taken(ins, pc, fun, regs) \
+ db_branch_taken((ins), (pc), (regs))
+
+#define DB_ELF_SYMBOLS
+#define DB_ELFSIZE 32
+#define DB_NO_AOUT
+
+void db_show_panic_cmd __P((db_expr_t, int, db_expr_t, char *));
+void db_show_frame_cmd __P((db_expr_t, int, db_expr_t, char *));
+
+#endif /* _ARM_DB_MACHDEP_H_ */
diff --git a/sys/arch/arm/include/disklabel.h b/sys/arch/arm/include/disklabel.h
new file mode 100644
index 00000000000..28db2c8195b
--- /dev/null
+++ b/sys/arch/arm/include/disklabel.h
@@ -0,0 +1,151 @@
+/* $OpenBSD: disklabel.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $OpenBSD: disklabel.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: disklabel.h,v 1.2 2001/11/25 19:02:03 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * disklabel.h
+ *
+ * machine specific disk label info
+ *
+ * Created : 04/10/94
+ */
+
+#ifndef _ARM_DISKLABEL_H_
+#define _ARM_DISKLABEL_H_
+
+#define LABELSECTOR 1 /* sector containing label */
+#define LABELOFFSET 0 /* offset of label in sector */
+#define MAXPARTITIONS 16 /* number of partitions */
+#define RAW_PART 2 /* raw partition: XX?c */
+
+#include <sys/dkbad.h>
+#if 0
+#include <arm/disklabel_acorn.h>
+#include <sys/disklabel_mbr.h>
+#endif
+
+/* MBR partition table */
+#define DOSBBSECTOR 0 /* MBR sector number */
+#define DOSPARTOFF 446 /* Offset of MBR partition table */
+#define NDOSPART 4 /* # of partitions in MBR */
+#define DOSMAGICOFF 510 /* Offset of magic number */
+#define DOSMAGIC 0xaa55 /* Actual magic number */
+#define MBRMAGIC DOSMAGIC
+#define DOSMBR_SIGNATURE MBRMAGIC
+#define DOSMBR_SIGNATURE_OFF DOSMAGICOFF
+#define DOSACTIVE 0x80
+
+
+struct dos_partition {
+ u_int8_t dp_flag; /* bootstrap flags */
+ u_int8_t dp_shd; /* starting head */
+ u_int8_t dp_ssect; /* starting sector */
+ u_int8_t dp_scyl; /* starting cylinder */
+ u_int8_t dp_typ; /* partition type (see below) */
+ u_int8_t dp_ehd; /* end head */
+ u_int8_t dp_esect; /* end sector */
+ u_int8_t dp_ecyl; /* end cylinder */
+ u_int32_t dp_start; /* absolute starting sector number */
+ u_int32_t dp_size; /* partition size in sectors */
+};
+
+/* Known DOS partition types. */
+#define DOSPTYP_UNUSED 0x00 /* Unused partition */
+#define DOSPTYP_FAT12 0x01 /* 12-bit FAT */
+#define DOSPTYP_FAT16S 0x04 /* 16-bit FAT, less than 32M */
+#define DOSPTYP_EXTEND 0x05 /* Extended; contains sub-partitions */
+#define DOSPTYP_FAT16B 0x06 /* 16-bit FAT, more than 32M */
+#define DOSPTYP_FAT32 0x0b /* 32-bit FAT */
+#define DOSPTYP_FAT32L 0x0c /* 32-bit FAT, LBA-mapped */
+#define DOSPTYP_FAT16C 0x0e /* 16-bit FAT, CHS-mapped */
+#define DOSPTYP_EXTENDL 0x0f /* Extended, LBA-mapped; contains sub-partitions */
+#define DOSPTYP_ONTRACK 0x54
+#define DOSPTYP_LINUX 0x83 /* That other thing */
+#define DOSPTYP_FREEBSD 0xa5 /* FreeBSD partition type */
+#define DOSPTYP_OPENBSD 0xa6 /* OpenBSD partition type */
+#define DOSPTYP_NETBSD 0xa9 /* NetBSD partition type */
+
+#include <sys/dkbad.h>
+
+/* Isolate the relevant bits to get sector and cylinder. */
+#define DPSECT(s) ((s) & 0x3f)
+#define DPCYL(c, s) ((c) + (((s) & 0xc0) << 2))
+
+
+#ifdef __ARMEL__
+#define get_le(x) (*((u_int32_t *)x))
+#else
+static __inline u_int32_t get_le(void *p);
+static __inline u_int32_t
+#ifdef __cplusplus
+get_le(void *p)
+#else
+get_le(p)
+ void *p;
+#endif
+{
+ u_int8_t *_p = (u_int8_t *)p;
+ int x;
+ x = _p[0];
+ x |= _p[1] << 8;
+ x |= _p[2] << 16;
+ x |= _p[3] << 24;
+ return x;
+}
+#endif
+
+
+#define NMBRPART 4
+struct cpu_disklabel {
+ struct dos_partition dosparts[NMBRPART];
+ struct dkbad bad;
+};
+
+#ifdef _KERNEL
+struct buf;
+struct disklabel;
+/* for readdisklabel. rv != 0 -> matches, msg == NULL -> success */
+int mbr_label_read __P((dev_t, void (*)(struct buf *), struct disklabel *,
+ struct cpu_disklabel *, char **, int *, int *));
+
+/* for writedisklabel. rv == 0 -> dosen't match, rv > 0 -> success */
+int mbr_label_locate __P((dev_t, void (*)(struct buf *),
+ struct disklabel *, struct cpu_disklabel *, int *, int *));
+#endif /* _KERNEL */
+
+#endif /* _ARM_DISKLABEL_H_ */
diff --git a/sys/arch/arm/include/elf_abi.h b/sys/arch/arm/include/elf_abi.h
new file mode 100644
index 00000000000..3115568b7c3
--- /dev/null
+++ b/sys/arch/arm/include/elf_abi.h
@@ -0,0 +1,7 @@
+/* $OpenBSD: elf_abi.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+#ifndef _ARM_ELF_ABI_H
+#define _ARM_ELF_ABI_H
+
+#define DT_PROCNUM 0
+
+#endif /* _ARM_ELF_ABI_H */
diff --git a/sys/arch/arm/include/endian.h b/sys/arch/arm/include/endian.h
new file mode 100644
index 00000000000..b9e046a3d37
--- /dev/null
+++ b/sys/arch/arm/include/endian.h
@@ -0,0 +1,8 @@
+/* $OpenBSD: endian.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+
+#ifdef __ARMEB__
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#include <sys/endian.h>
diff --git a/sys/arch/arm/include/fiq.h b/sys/arch/arm/include/fiq.h
new file mode 100644
index 00000000000..e246323b57f
--- /dev/null
+++ b/sys/arch/arm/include/fiq.h
@@ -0,0 +1,69 @@
+/* $OpenBSD: fiq.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: fiq.h,v 1.1 2001/12/20 01:20:23 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_FIQ_H_
+#define _ARM_FIQ_H_
+
+#include <sys/queue.h>
+
+struct fiqregs {
+ u_int fr_r8; /* FIQ mode r8 */
+ u_int fr_r9; /* FIQ mode r9 */
+ u_int fr_r10; /* FIQ mode r10 */
+ u_int fr_r11; /* FIQ mode r11 */
+ u_int fr_r12; /* FIQ mode r12 */
+ u_int fr_r13; /* FIQ mode r13 */
+};
+
+struct fiqhandler {
+ TAILQ_ENTRY(fiqhandler) fh_list;/* link in the FIQ handler stack */
+ void *fh_func; /* FIQ handler routine */
+ size_t fh_size; /* size of FIQ handler */
+ int fh_flags; /* flags; see below */
+ struct fiqregs *fh_regs; /* pointer to regs structure */
+};
+
+#define FH_CANPUSH 0x01 /* can push this handler out of the way */
+
+int fiq_claim(struct fiqhandler *);
+void fiq_release(struct fiqhandler *);
+
+void fiq_getregs(struct fiqregs *);
+void fiq_setregs(struct fiqregs *);
+
+#endif /* _ARM_FIQ_H_ */
diff --git a/sys/arch/arm/include/float.h b/sys/arch/arm/include/float.h
new file mode 100644
index 00000000000..1466dd4e7d7
--- /dev/null
+++ b/sys/arch/arm/include/float.h
@@ -0,0 +1,90 @@
+/* $OpenBSD: float.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: float.h,v 1.1 2001/01/10 19:02:06 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)float.h 8.1 (Berkeley) 6/11/93
+ */
+
+#ifndef _ARM32_FLOAT_H_
+#define _ARM32_FLOAT_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int __flt_rounds __P((void));
+__END_DECLS
+
+#define FLT_RADIX 2 /* b */
+#define FLT_ROUNDS __flt_rounds()
+
+#define FLT_MANT_DIG 24 /* p */
+#define FLT_EPSILON 1.19209290E-7F /* b**(1-p) */
+#define FLT_DIG 6 /* floor((p-1)*log10(b))+(b == 10) */
+#define FLT_MIN_EXP (-125) /* emin */
+#define FLT_MIN 1.17549435E-38F /* b**(emin-1) */
+#define FLT_MIN_10_EXP (-37) /* ceil(log10(b**(emin-1))) */
+#define FLT_MAX_EXP 128 /* emax */
+#define FLT_MAX 3.40282347E+38F /* (1-b**(-p))*b**emax */
+#define FLT_MAX_10_EXP 38 /* floor(log10((1-b**(-p))*b**emax)) */
+
+#define DBL_MANT_DIG 53
+#define DBL_EPSILON 2.2204460492503131E-16
+#define DBL_DIG 15
+#define DBL_MIN_EXP (-1021)
+#define DBL_MIN 2.2250738585072014E-308
+#define DBL_MIN_10_EXP (-307)
+#define DBL_MAX_EXP 1024
+#define DBL_MAX 1.7976931348623157E+308
+#define DBL_MAX_10_EXP 308
+
+#define LDBL_MANT_DIG DBL_MANT_DIG
+#define LDBL_EPSILON DBL_EPSILON
+#define LDBL_DIG DBL_DIG
+#define LDBL_MIN_EXP DBL_MIN_EXP
+#define LDBL_MIN DBL_MIN
+#define LDBL_MIN_10_EXP DBL_MIN_10_EXP
+#define LDBL_MAX_EXP DBL_MAX_EXP
+#define LDBL_MAX DBL_MAX
+#define LDBL_MAX_10_EXP DBL_MAX_10_EXP
+
+#endif /* _ARM32_FLOAT_H_ */
diff --git a/sys/arch/arm/include/fp.h b/sys/arch/arm/include/fp.h
new file mode 100644
index 00000000000..5d9096e0fa5
--- /dev/null
+++ b/sys/arch/arm/include/fp.h
@@ -0,0 +1,87 @@
+/* $OpenBSD: fp.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: fp.h,v 1.1 2001/01/10 19:02:06 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe.
+ * Copyright (c) 1995 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * fp.h
+ *
+ * FP info
+ *
+ * Created : 10/10/95
+ */
+
+#ifndef __ARM32_FP_H
+#define __ARM32_FP_H
+
+/*
+ * An extended precision floating point number
+ */
+
+typedef struct fp_extended_precision {
+ u_int32_t fp_exponent;
+ u_int32_t fp_mantissa_hi;
+ u_int32_t fp_mantissa_lo;
+} fp_extended_precision_t;
+
+typedef struct fp_extended_precision fp_reg_t;
+
+/*
+ * Information about the FPE-SP state that is stored in the pcb
+ *
+ * This needs to move and be hidden from userland.
+ */
+
+struct fpe_sp_state {
+ unsigned int fp_flags;
+ unsigned int fp_sr;
+ unsigned int fp_cr;
+ fp_reg_t fp_registers[16];
+};
+
+/*
+ * Type for a saved FP context, if we want to translate the context to a
+ * user-readable form
+ */
+
+typedef struct {
+ u_int32_t fpsr;
+ fp_extended_precision_t regs[8];
+} fp_state_t;
+
+#endif
+
+/* End of fp.h */
diff --git a/sys/arch/arm/include/frame.h b/sys/arch/arm/include/frame.h
new file mode 100644
index 00000000000..2db8310770d
--- /dev/null
+++ b/sys/arch/arm/include/frame.h
@@ -0,0 +1,412 @@
+/* $OpenBSD: frame.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: frame.h,v 1.9 2003/12/01 08:48:33 scw Exp $ */
+
+/*
+ * Copyright (c) 1994-1997 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * frame.h
+ *
+ * Stack frames structures
+ *
+ * Created : 30/09/94
+ */
+
+#ifndef _ARM_FRAME_H_
+#define _ARM_FRAME_H_
+
+#ifndef _LOCORE
+
+#include <sys/signal.h>
+
+/*
+ * Trap frame. Pushed onto the kernel stack on a trap (synchronous exception).
+ */
+
+typedef struct trapframe {
+ register_t tf_spsr; /* Zero on arm26 */
+ register_t tf_r0;
+ register_t tf_r1;
+ register_t tf_r2;
+ register_t tf_r3;
+ register_t tf_r4;
+ register_t tf_r5;
+ register_t tf_r6;
+ register_t tf_r7;
+ register_t tf_r8;
+ register_t tf_r9;
+ register_t tf_r10;
+ register_t tf_r11;
+ register_t tf_r12;
+ register_t tf_usr_sp;
+ register_t tf_usr_lr;
+ register_t tf_svc_sp; /* Not used on arm26 */
+ register_t tf_svc_lr; /* Not used on arm26 */
+ register_t tf_pc;
+} trapframe_t;
+
+/* Register numbers */
+#define tf_r13 tf_usr_sp
+#define tf_r14 tf_usr_lr
+#define tf_r15 tf_pc
+
+/*
+ * Signal frame. Pushed onto user stack before calling sigcode.
+ */
+
+struct sigframe {
+ int sf_signum;
+ siginfo_t *sf_sip;
+ struct sigcontext *sf_scp;
+ sig_t sf_handler;
+ struct sigcontext sf_sc;
+ siginfo_t sf_si;
+};
+
+/* the pointers are use in the trampoline code to locate the ucontext */
+#if 0
+struct sigframe_siginfo {
+ siginfo_t sf_si; /* actual saved siginfo */
+ ucontext_t sf_uc; /* actual saved ucontext */
+};
+#endif
+
+#if 0
+#ifdef _KERNEL
+void sendsig_sigcontext(const ksiginfo_t *, const sigset_t *);
+#endif
+#endif
+
+#endif /* _LOCORE */
+
+#ifndef _LOCORE
+
+/*
+ * System stack frames.
+ */
+
+typedef struct irqframe {
+ unsigned int if_spsr;
+ unsigned int if_r0;
+ unsigned int if_r1;
+ unsigned int if_r2;
+ unsigned int if_r3;
+ unsigned int if_r4;
+ unsigned int if_r5;
+ unsigned int if_r6;
+ unsigned int if_r7;
+ unsigned int if_r8;
+ unsigned int if_r9;
+ unsigned int if_r10;
+ unsigned int if_r11;
+ unsigned int if_r12;
+ unsigned int if_usr_sp;
+ unsigned int if_usr_lr;
+ unsigned int if_svc_sp;
+ unsigned int if_svc_lr;
+ unsigned int if_pc;
+} irqframe_t;
+
+#define clockframe irqframe
+
+/*
+ * Switch frame
+ */
+
+struct switchframe {
+ u_int sf_r4;
+ u_int sf_r5;
+ u_int sf_r6;
+ u_int sf_r7;
+ u_int sf_pc;
+};
+
+/*
+ * Stack frame. Used during stack traces (db_trace.c)
+ */
+struct frame {
+ u_int fr_fp;
+ u_int fr_sp;
+ u_int fr_lr;
+ u_int fr_pc;
+};
+
+#ifdef _KERNEL
+void validate_trapframe __P((trapframe_t *, int));
+#endif /* _KERNEL */
+
+#else /* _LOCORE */
+
+/*
+ * AST_ALIGNMENT_FAULT_LOCALS and ENABLE_ALIGNMENT_FAULTS
+ * These are used in order to support dynamic enabling/disabling of
+ * alignment faults when executing old a.out ARM binaries.
+ */
+#if defined(COMPAT_15) && defined(EXEC_AOUT)
+#ifndef MULTIPROCESSOR
+
+/*
+ * Local variables needed by the AST/Alignment Fault macroes
+ */
+#define AST_ALIGNMENT_FAULT_LOCALS \
+.Laflt_astpending: ;\
+ .word _C_LABEL(astpending) ;\
+.Laflt_cpufuncs: ;\
+ .word _C_LABEL(cpufuncs) ;\
+.Laflt_curpcb: ;\
+ .word _C_LABEL(curpcb) ;\
+.Laflt_cpu_info_store: ;\
+ .word _C_LABEL(cpu_info_store)
+
+#define GET_CURPCB_ENTER \
+ ldr r1, .Laflt_curpcb ;\
+ ldr r1, [r1]
+
+#define GET_CPUINFO_ENTER \
+ ldr r0, .Laflt_cpu_info_store
+
+#define GET_CURPCB_EXIT \
+ ldr r1, .Laflt_curpcb ;\
+ ldr r2, .Laflt_cpu_info_store ;\
+ ldr r1, [r1]
+
+#else /* !MULTIPROCESSOR */
+
+#define AST_ALIGNMENT_FAULT_LOCALS \
+.Laflt_astpending: ;\
+ .word _C_LABEL(astpending) ;\
+.Laflt_cpufuncs: ;\
+ .word _C_LABEL(cpufuncs) ;\
+.Laflt_cpu_info: ;\
+ .word _C_LABEL(cpu_info)
+
+#define GET_CURPCB_ENTER \
+ ldr r4, .Laflt_cpu_info ;\
+ bl _C_LABEL(cpu_number) ;\
+ ldr r0, [r4, r0, lsl #2] ;\
+ ldr r1, [r0, #CI_CURPCB]
+
+#define GET_CPUINFO_ENTER /* nothing to do */
+
+#define GET_CURPCB_EXIT \
+ ldr r7, .Laflt_cpu_info ;\
+ bl _C_LABEL(cpu_number) ;\
+ ldr r2, [r7, r0, lsl #2] ;\
+ ldr r1, [r2, #CI_CURPCB]
+#endif /* MULTIPROCESSOR */
+
+/*
+ * This macro must be invoked following PUSHFRAMEINSVC or PUSHFRAME at
+ * the top of interrupt/exception handlers.
+ *
+ * When invoked, r0 *must* contain the value of SPSR on the current
+ * trap/interrupt frame. This is always the case if ENABLE_ALIGNMENT_FAULTS
+ * is invoked immediately after PUSHFRAMEINSVC or PUSHFRAME.
+ */
+#define ENABLE_ALIGNMENT_FAULTS \
+ and r0, r0, #(PSR_MODE) /* Test for USR32 mode */ ;\
+ teq r0, #(PSR_USR32_MODE) ;\
+ bne 1f /* Not USR mode skip AFLT */ ;\
+ GET_CURPCB_ENTER /* r1 = curpcb */ ;\
+ cmp r1, #0x00 /* curpcb NULL? */ ;\
+ ldrne r1, [r1, #PCB_FLAGS] /* Fetch curpcb->pcb_flags */ ;\
+ tstne r1, #PCB_NOALIGNFLT ;\
+ beq 1f /* AFLTs already enabled */ ;\
+ GET_CPUINFO_ENTER /* r0 = cpuinfo */ ;\
+ ldr r2, .Laflt_cpufuncs ;\
+ ldr r1, [r0, #CI_CTRL] /* Fetch control register */ ;\
+ mov r0, #-1 ;\
+ mov lr, pc ;\
+ ldr pc, [r2, #CF_CONTROL] /* Enable alignment faults */ ;\
+1:
+
+/*
+ * This macro must be invoked just before PULLFRAMEFROMSVCANDEXIT or
+ * PULLFRAME at the end of interrupt/exception handlers.
+ */
+#define DO_AST_AND_RESTORE_ALIGNMENT_FAULTS \
+ ldr r0, [sp] /* Get the SPSR from stack */ ;\
+ mrs r4, cpsr /* save CPSR */ ;\
+ and r0, r0, #(PSR_MODE) /* Returning to USR mode? */ ;\
+ teq r0, #(PSR_USR32_MODE) ;\
+ ldreq r5, .Laflt_astpending ;\
+ bne 3f /* Nope, get out now */ ;\
+ bic r4, r4, #(I32_bit) ;\
+1: orr r0, r4, #(I32_bit) /* Disable IRQs */ ;\
+ msr cpsr_c, r0 ;\
+ ldr r1, [r5] /* Pending AST? */ ;\
+ teq r1, #0x00000000 ;\
+ bne 2f /* Yup. Go deal with it */ ;\
+ GET_CURPCB_EXIT /* r1 = curpcb, r2 = cpuinfo */ ;\
+ cmp r1, #0x00 /* curpcb NULL? */ ;\
+ ldrne r1, [r1, #PCB_FLAGS] /* Fetch curpcb->pcb_flags */ ;\
+ tstne r1, #PCB_NOALIGNFLT ;\
+ beq 3f /* Keep AFLTs enabled */ ;\
+ ldr r1, [r2, #CI_CTRL] /* Fetch control register */ ;\
+ ldr r2, .Laflt_cpufuncs ;\
+ mov r0, #-1 ;\
+ bic r1, r1, #CPU_CONTROL_AFLT_ENABLE /* Disable AFLTs */ ;\
+ adr lr, 3f ;\
+ ldr pc, [r2, #CF_CONTROL] /* Set new CTRL reg value */ ;\
+2: mov r1, #0x00000000 ;\
+ str r1, [r5] /* Clear astpending */ ;\
+ msr cpsr_c, r4 /* Restore interrupts */ ;\
+ mov r0, sp ;\
+ adr lr, 1b ;\
+ b _C_LABEL(ast) /* ast(frame) */ ;\
+3:
+
+#else /* !(COMPAT_15 && EXEC_AOUT) */
+
+#define AST_ALIGNMENT_FAULT_LOCALS ;\
+.Laflt_astpending: ;\
+ .word _C_LABEL(astpending)
+
+#define ENABLE_ALIGNMENT_FAULTS /* nothing */
+
+#define DO_AST_AND_RESTORE_ALIGNMENT_FAULTS \
+ ldr r0, [sp] /* Get the SPSR from stack */ ;\
+ mrs r4, cpsr /* save CPSR */ ;\
+ and r0, r0, #(PSR_MODE) /* Returning to USR mode? */ ;\
+ teq r0, #(PSR_USR32_MODE) ;\
+ ldreq r5, .Laflt_astpending ;\
+ bne 2f /* Nope, get out now */ ;\
+ bic r4, r4, #(I32_bit) ;\
+1: orr r0, r4, #(I32_bit) /* Disable IRQs */ ;\
+ msr cpsr_c, r0 ;\
+ ldr r1, [r5] /* Pending AST? */ ;\
+ teq r1, #0x00000000 ;\
+ beq 2f /* Nope. Just bail */ ;\
+ mov r1, #0x00000000 ;\
+ str r1, [r5] /* Clear astpending */ ;\
+ msr cpsr_c, r4 /* Restore interrupts */ ;\
+ mov r0, sp ;\
+ adr lr, 1b ;\
+ b _C_LABEL(ast) /* ast(frame) */ ;\
+2:
+#endif /* COMPAT_15 && EXEC_AOUT */
+
+/*
+ * ASM macros for pushing and pulling trapframes from the stack
+ *
+ * These macros are used to handle the irqframe and trapframe structures
+ * defined above.
+ */
+
+/*
+ * PUSHFRAME - macro to push a trap frame on the stack in the current mode
+ * Since the current mode is used, the SVC lr field is not defined.
+ *
+ * NOTE: r13 and r14 are stored separately as a work around for the
+ * SA110 rev 2 STM^ bug
+ */
+
+#define PUSHFRAME \
+ str lr, [sp, #-4]!; /* Push the return address */ \
+ sub sp, sp, #(4*17); /* Adjust the stack pointer */ \
+ stmia sp, {r0-r12}; /* Push the user mode registers */ \
+ add r0, sp, #(4*13); /* Adjust the stack pointer */ \
+ stmia r0, {r13-r14}^; /* Push the user mode registers */ \
+ mov r0, r0; /* NOP for previous instruction */ \
+ mrs r0, spsr_all; /* Put the SPSR on the stack */ \
+ str r0, [sp, #-4]!
+
+/*
+ * PULLFRAME - macro to pull a trap frame from the stack in the current mode
+ * Since the current mode is used, the SVC lr field is ignored.
+ */
+
+#define PULLFRAME \
+ ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
+ msr spsr_all, r0; \
+ ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \
+ mov r0, r0; /* NOP for previous instruction */ \
+ add sp, sp, #(4*17); /* Adjust the stack pointer */ \
+ ldr lr, [sp], #0x0004 /* Pull the return address */
+
+/*
+ * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode
+ * This should only be used if the processor is not currently in SVC32
+ * mode. The processor mode is switched to SVC mode and the trap frame is
+ * stored. The SVC lr field is used to store the previous value of
+ * lr in SVC mode.
+ *
+ * NOTE: r13 and r14 are stored separately as a work around for the
+ * SA110 rev 2 STM^ bug
+ */
+
+#define PUSHFRAMEINSVC \
+ stmdb sp, {r0-r3}; /* Save 4 registers */ \
+ mov r0, lr; /* Save xxx32 r14 */ \
+ mov r1, sp; /* Save xxx32 sp */ \
+ mrs r3, spsr; /* Save xxx32 spsr */ \
+ mrs r2, cpsr; /* Get the CPSR */ \
+ bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \
+ orr r2, r2, #(PSR_SVC32_MODE); \
+ msr cpsr_c, r2; /* Punch into SVC mode */ \
+ mov r2, sp; /* Save SVC sp */ \
+ str r0, [sp, #-4]!; /* Push return address */ \
+ str lr, [sp, #-4]!; /* Push SVC lr */ \
+ str r2, [sp, #-4]!; /* Push SVC sp */ \
+ msr spsr_all, r3; /* Restore correct spsr */ \
+ ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \
+ sub sp, sp, #(4*15); /* Adjust the stack pointer */ \
+ stmia sp, {r0-r12}; /* Push the user mode registers */ \
+ add r0, sp, #(4*13); /* Adjust the stack pointer */ \
+ stmia r0, {r13-r14}^; /* Push the user mode registers */ \
+ mov r0, r0; /* NOP for previous instruction */ \
+ mrs r0, spsr_all; /* Put the SPSR on the stack */ \
+ str r0, [sp, #-4]!
+
+/*
+ * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack
+ * in SVC32 mode and restore the saved processor mode and PC.
+ * This should be used when the SVC lr register needs to be restored on
+ * exit.
+ */
+
+#define PULLFRAMEFROMSVCANDEXIT \
+ ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
+ msr spsr_all, r0; /* restore SPSR */ \
+ ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \
+ mov r0, r0; /* NOP for previous instruction */ \
+ add sp, sp, #(4*15); /* Adjust the stack pointer */ \
+ ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */
+
+#endif /* _LOCORE */
+
+#endif /* _ARM_FRAME_H_ */
+
+/* End of frame.h */
diff --git a/sys/arch/arm/include/ieee.h b/sys/arch/arm/include/ieee.h
new file mode 100644
index 00000000000..5f9b89ecc0e
--- /dev/null
+++ b/sys/arch/arm/include/ieee.h
@@ -0,0 +1,191 @@
+/* $OpenBSD: ieee.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: ieee.h,v 1.2 2001/02/21 17:43:50 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Lawrence Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ieee.h 8.1 (Berkeley) 6/11/93
+ */
+
+/*
+ * ieee.h defines the machine-dependent layout of the machine's IEEE
+ * floating point.
+ */
+
+/*
+ * Define the number of bits in each fraction and exponent.
+ *
+ * k k+1
+ * Note that 1.0 x 2 == 0.1 x 2 and that denorms are represented
+ *
+ * (-exp_bias+1)
+ * as fractions that look like 0.fffff x 2 . This means that
+ *
+ * -126
+ * the number 0.10000 x 2 , for instance, is the same as the normalized
+ *
+ * -127 -128
+ * float 1.0 x 2 . Thus, to represent 2 , we need one leading zero
+ *
+ * -129
+ * in the fraction; to represent 2 , we need two, and so on. This
+ *
+ * (-exp_bias-fracbits+1)
+ * implies that the smallest denormalized number is 2
+ *
+ * for whichever format we are talking about: for single precision, for
+ *
+ * -126 -149
+ * instance, we get .00000000000000000000001 x 2 , or 1.0 x 2 , and
+ *
+ * -149 == -127 - 23 + 1.
+ */
+
+/*
+ * The ARM has two sets of FP data formats. The FPA supports 32-bit, 64-bit
+ * and 96-bit IEEE formats, with the words in big-endian order. VFP supports
+ * 32-bin and 64-bit IEEE formats with the words in the CPU's native byte
+ * order.
+ *
+ * The FPA also has two packed decimal formats, but we ignore them here.
+ */
+
+#define SNG_EXPBITS 8
+#define SNG_FRACBITS 23
+
+#define DBL_EXPBITS 11
+#define DBL_FRACBITS 52
+
+#ifndef __VFP_FP__
+#define E80_EXPBITS 15
+#define E80_FRACBITS 64
+
+#define EXT_EXPBITS 15
+#define EXT_FRACBITS 112
+#endif
+
+struct ieee_single {
+ u_int sng_frac:23;
+ u_int sng_exponent:8;
+ u_int sng_sign:1;
+};
+
+#ifdef __VFP_FP__
+struct ieee_double {
+#ifdef __ARMEB__
+ u_int dbl_sign:1;
+ u_int dbl_exp:11;
+ u_int dbl_frach:20;
+ u_int dbl_fracl;
+#else /* !__ARMEB__ */
+ u_int dbl_fracl;
+ u_int dbl_frach:20;
+ u_int dbl_exp:11;
+ u_int dbl_sign:1;
+#endif /* !__ARMEB__ */
+};
+#else /* !__VFP_FP__ */
+struct ieee_double {
+ u_int dbl_frach:20;
+ u_int dbl_exp:11;
+ u_int dbl_sign:1;
+ u_int dbl_fracl;
+};
+
+union ieee_double_u {
+ double dblu_d;
+ struct ieee_double dblu_dbl;
+};
+
+
+struct ieee_e80 {
+ u_int e80_exp:15;
+ u_int e80_zero:16;
+ u_int e80_sign:1;
+ u_int e80_frach:31;
+ u_int e80_j:1;
+ u_int e80_fracl;
+};
+
+struct ieee_ext {
+ u_int ext_frach:16;
+ u_int ext_exp:15;
+ u_int ext_sign:1;
+ u_int ext_frachm;
+ u_int ext_fraclm;
+ u_int ext_fracl;
+};
+#endif /* !__VFP_FP__ */
+
+/*
+ * Floats whose exponent is in [1..INFNAN) (of whatever type) are
+ * `normal'. Floats whose exponent is INFNAN are either Inf or NaN.
+ * Floats whose exponent is zero are either zero (iff all fraction
+ * bits are zero) or subnormal values.
+ *
+ * A NaN is a `signalling NaN' if its QUIETNAN bit is clear in its
+ * high fraction; if the bit is set, it is a `quiet NaN'.
+ */
+#define SNG_EXP_INFNAN 255
+#define DBL_EXP_INFNAN 2047
+#ifndef __VFP_FP__
+#define E80_EXP_INFNAN 32767
+#define EXT_EXP_INFNAN 32767
+#endif /* !__VFP_FP__ */
+
+#if 0
+#define SNG_QUIETNAN (1 << 22)
+#define DBL_QUIETNAN (1 << 19)
+#ifndef __VFP_FP__
+#define E80_QUIETNAN (1 << 15)
+#define EXT_QUIETNAN (1 << 15)
+#endif /* !__VFP_FP__ */
+#endif
+
+/*
+ * Exponent biases.
+ */
+#define SNG_EXP_BIAS 127
+#define DBL_EXP_BIAS 1023
+#ifndef __VFP_FP__
+#define E80_EXP_BIAS 16383
+#define EXT_EXP_BIAS 16383
+#endif /* !__VFP_FP__ */
diff --git a/sys/arch/arm/include/ieeefp.h b/sys/arch/arm/include/ieeefp.h
new file mode 100644
index 00000000000..6aaf2b950e1
--- /dev/null
+++ b/sys/arch/arm/include/ieeefp.h
@@ -0,0 +1,41 @@
+/* $OpenBSD: ieeefp.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: ieeefp.h,v 1.1 2001/01/10 19:02:06 bjh21 Exp $ */
+
+/*
+ * Based on ieeefp.h written by J.T. Conklin, Apr 28, 1995
+ * Public domain.
+ */
+
+#ifndef _ARM32_IEEEFP_H_
+#define _ARM32_IEEEFP_H_
+
+/* FP exception codes */
+
+#define FP_EXCEPT_INV 0
+#define FP_EXCEPT_DZ 1
+#define FP_EXCEPT_OFL 2
+#define FP_EXCEPT_UFL 3
+#define FP_EXCEPT_IMP 4
+
+/* Exception type (used by fpsetmask() et al.) */
+
+typedef int fp_except;
+
+/* Bit defines for fp_except */
+
+#define FP_X_INV (1 << FP_EXCEPT_INV) /* invalid operation exception */
+#define FP_X_DZ (1 << FP_EXCEPT_DZ) /* divide-by-zero exception */
+#define FP_X_OFL (1 << FP_EXCEPT_OFL) /* overflow exception */
+#define FP_X_UFL (1 << FP_EXCEPT_UFL) /* underflow exception */
+#define FP_X_IMP (1 << FP_EXCEPT_IMP) /* imprecise (loss of precision; "inexact") */
+
+/* Rounding modes */
+
+typedef enum {
+ FP_RN=0, /* round to nearest representable number */
+ FP_RP=1, /* round toward positive infinity */
+ FP_RM=2, /* round toward negative infinity */
+ FP_RZ=3 /* round to zero (truncate) */
+} fp_rnd;
+
+#endif /* _ARM32_IEEEFP_H_ */
diff --git a/sys/arch/arm/include/internal_types.h b/sys/arch/arm/include/internal_types.h
new file mode 100644
index 00000000000..96546cfacb9
--- /dev/null
+++ b/sys/arch/arm/include/internal_types.h
@@ -0,0 +1,6 @@
+/* $OpenBSD: internal_types.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* Public domain */
+#ifndef _ARM_INTERNAL_TYPES_H_
+#define _ARM_INTERNAL_TYPES_H_
+
+#endif
diff --git a/sys/arch/arm/include/isa_machdep.h b/sys/arch/arm/include/isa_machdep.h
new file mode 100644
index 00000000000..97e2c1171c8
--- /dev/null
+++ b/sys/arch/arm/include/isa_machdep.h
@@ -0,0 +1,193 @@
+/* $OpenBSD: isa_machdep.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: isa_machdep.h,v 1.3 2002/01/07 22:58:07 chris Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM32_ISA_MACHDEP_H_
+#define _ARM32_ISA_MACHDEP_H_
+
+#include <machine/bus.h>
+#include <dev/isa/isadmavar.h>
+
+#define __NO_ISA_INTR_CHECK
+/*
+ * Types provided to machine-independent ISA code.
+ */
+struct arm32_isa_chipset {
+ /*
+ struct isa_dma_state ic_dmastate;
+ */
+};
+
+typedef struct arm32_isa_chipset *isa_chipset_tag_t;
+
+struct device; /* XXX */
+struct isabus_attach_args; /* XXX */
+
+/*
+ * Functions provided to machine-independent ISA code.
+ */
+void isa_attach_hook(struct device *, struct device *,
+ struct isabus_attach_args *);
+const struct evcnt *isa_intr_evcnt(isa_chipset_tag_t ic, int irq);
+void *isa_intr_establish(isa_chipset_tag_t ic, int irq, int type,
+ int level, int (*ih_fun)(void *), void *ih_arg, char *name);
+void isa_intr_disestablish(isa_chipset_tag_t ic, void *handler);
+
+#if 0
+#define isa_dmainit(ic, bst, dmat, d) \
+ _isa_dmainit(&(ic)->ic_dmastate, (bst), (dmat), (d))
+#define isa_dmacascade(ic, c) \
+ _isa_dmacascade(&(ic)->ic_dmastate, (c))
+#define isa_dmamaxsize(ic, c) \
+ _isa_dmamaxsize(&(ic)->ic_dmastate, (c))
+#define isa_dmamap_create(ic, c, s, f) \
+ _isa_dmamap_create(&(ic)->ic_dmastate, (c), (s), (f))
+#define isa_dmamap_destroy(ic, c) \
+ _isa_dmamap_destroy(&(ic)->ic_dmastate, (c))
+#define isa_dmastart(ic, c, a, n, p, f, bf) \
+ _isa_dmastart(&(ic)->ic_dmastate, (c), (a), (n), (p), (f), (bf))
+#define isa_dmaabort(ic, c) \
+ _isa_dmaabort(&(ic)->ic_dmastate, (c))
+#define isa_dmacount(ic, c) \
+ _isa_dmacount(&(ic)->ic_dmastate, (c))
+#define isa_dmafinished(ic, c) \
+ _isa_dmafinished(&(ic)->ic_dmastate, (c))
+#define isa_dmadone(ic, c) \
+ _isa_dmadone(&(ic)->ic_dmastate, (c))
+#define isa_dmafreeze(ic) \
+ _isa_dmafreeze(&(ic)->ic_dmastate)
+#define isa_dmathaw(ic) \
+ _isa_dmathaw(&(ic)->ic_dmastate)
+#define isa_dmamem_alloc(ic, c, s, ap, f) \
+ _isa_dmamem_alloc(&(ic)->ic_dmastate, (c), (s), (ap), (f))
+#define isa_dmamem_free(ic, c, a, s) \
+ _isa_dmamem_free(&(ic)->ic_dmastate, (c), (a), (s))
+#define isa_dmamem_map(ic, c, a, s, kp, f) \
+ _isa_dmamem_map(&(ic)->ic_dmastate, (c), (a), (s), (kp), (f))
+#define isa_dmamem_unmap(ic, c, k, s) \
+ _isa_dmamem_unmap(&(ic)->ic_dmastate, (c), (k), (s))
+#define isa_dmamem_mmap(ic, c, a, s, o, p, f) \
+ _isa_dmamem_mmap(&(ic)->ic_dmastate, (c), (a), (s), (o), (p), (f))
+#define isa_drq_alloc(ic, c) \
+ _isa_drq_alloc(&(ic)->ic_dmastate, c)
+#define isa_drq_free(ic, c) \
+ _isa_drq_free(&(ic)->ic_dmastate, c)
+#define isa_drq_isfree(ic, c) \
+ _isa_drq_isfree(&(ic)->ic_dmastate, (c))
+#define isa_malloc(ic, c, s, p, f) \
+ _isa_malloc(&(ic)->ic_dmastate, (c), (s), (p), (f))
+#define isa_free(a, p) \
+ _isa_free((a), (p))
+#define isa_mappage(m, o, p) \
+ _isa_mappage((m), (o), (p))
+#endif
+
+/*
+ * ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED
+ * BY PORTABLE CODE.
+ */
+
+extern struct arm32_bus_dma_tag isa_bus_dma_tag;
+
+/*
+ * Cookie used by ISA DMA. A pointer to one of these is stashed in
+ * the DMA map.
+ */
+struct arm32_isa_dma_cookie {
+ int id_flags; /* flags; see below */
+
+ /*
+ * Information about the original buffer used during
+ * DMA map syncs. Note that origbuflen is only used
+ * for ID_BUFTYPE_LINEAR.
+ */
+ void *id_origbuf; /* pointer to orig buffer if
+ bouncing */
+ bus_size_t id_origbuflen; /* ...and size */
+ int id_buftype; /* type of buffer */
+
+ void *id_bouncebuf; /* pointer to the bounce buffer */
+ bus_size_t id_bouncebuflen; /* ...and size */
+ int id_nbouncesegs; /* number of valid bounce segs */
+ bus_dma_segment_t id_bouncesegs[0]; /* array of bounce buffer
+ physical memory segments */
+};
+
+/* id_flags */
+#define ID_MIGHT_NEED_BOUNCE 0x01 /* map could need bounce buffers */
+#define ID_HAS_BOUNCE 0x02 /* map currently has bounce buffers */
+#define ID_IS_BOUNCING 0x04 /* map is bouncing current xfer */
+
+/* id_buftype */
+#define ID_BUFTYPE_INVALID 0
+#define ID_BUFTYPE_LINEAR 1
+#define ID_BUFTYPE_MBUF 2
+#define ID_BUFTYPE_UIO 3
+#define ID_BUFTYPE_RAW 4
+
+/* bus space tags */
+extern struct bus_space isa_io_bs_tag;
+extern struct bus_space isa_mem_bs_tag;
+
+/* ISA chipset */
+extern struct arm32_isa_chipset isa_chipset_tag;
+
+/* for pccons.c */
+#define MONO_BASE 0x3B4
+#define MONO_BUF 0x000B0000
+#define CGA_BASE 0x3D4
+#define CGA_BUF 0x000B8000
+#define VGA_BUF 0xA0000
+#define VGA_BUF_LEN (0xBFFFF - 0xA0000)
+
+void isa_init(vaddr_t, vaddr_t);
+void isa_io_init(vaddr_t, vaddr_t);
+void isa_dma_init(void);
+vaddr_t isa_io_data_vaddr(void);
+vaddr_t isa_mem_data_vaddr(void);
+int isa_intr_alloc(isa_chipset_tag_t ic, int mask, int type, int *irq);
+void isa_intr_init(void);
+
+/*
+ * Miscellanous functions.
+ */
+void sysbeep(int, int); /* beep with the system speaker */
+void isa_fillw(u_int val, void *addr, size_t len);
+
+#endif /* _ARM32_ISA_MACHDEP_H_ XXX */
diff --git a/sys/arch/arm/include/katelib.h b/sys/arch/arm/include/katelib.h
new file mode 100644
index 00000000000..b17905d0ce7
--- /dev/null
+++ b/sys/arch/arm/include/katelib.h
@@ -0,0 +1,99 @@
+/* $OpenBSD: katelib.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: katelib.h,v 1.3 2001/11/23 19:21:48 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994-1996 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * katelib.h
+ *
+ * Prototypes for machine specific functions. Most of these
+ * could be inlined.
+ *
+ * This should not really be a separate header file. Eventually I will merge
+ * this into other header files once I have decided where the declarations
+ * should go.
+ *
+ * Created : 18/09/94
+ *
+ * Based on kate/katelib/prototypes.h
+ */
+
+/*
+ * USE OF THIS FILE IS DEPRECATED
+ */
+
+#include <sys/types.h>
+#include <arm/cpufunc.h>
+
+#ifdef _KERNEL
+
+/* Assembly modules */
+
+/* In blockio.S */
+#include <arm/blockio.h>
+
+/* Macros for reading and writing words, shorts, bytes */
+
+#define WriteWord(a, b) \
+*((volatile unsigned int *)(a)) = (b)
+
+#define ReadWord(a) \
+(*((volatile unsigned int *)(a)))
+
+#define WriteShort(a, b) \
+*((volatile unsigned int *)(a)) = ((b) | ((b) << 16))
+
+#define ReadShort(a) \
+((*((volatile unsigned int *)(a))) & 0xffff)
+
+#define WriteByte(a, b) \
+*((volatile unsigned char *)(a)) = (b)
+
+#define ReadByte(a) \
+(*((volatile unsigned char *)(a)))
+
+/* Define in/out macros */
+
+#define inb(port) ReadByte((port))
+#define outb(port, byte) WriteByte((port), (byte))
+#define inw(port) ReadShort((port))
+#define outw(port, word) WriteShort((port), (word))
+#define inl(port) ReadWord((port))
+#define outl(port, lword) WriteWord((port), (lword))
+
+#endif
+
+/* End of katelib.h */
diff --git a/sys/arch/arm/include/limits.h b/sys/arch/arm/include/limits.h
new file mode 100644
index 00000000000..44c99876b4f
--- /dev/null
+++ b/sys/arch/arm/include/limits.h
@@ -0,0 +1,54 @@
+/* $OpenBSD: limits.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: limits.h,v 1.4 2003/04/28 23:16:18 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)limits.h 7.2 (Berkeley) 6/28/90
+ */
+
+#ifndef _ARM32_LIMITS_H_
+#define _ARM32_LIMITS_H_
+
+#define MB_LEN_MAX 1 /* no multibyte characters */
+
+#if !defined(_ANSI_SOURCE)
+#define SIZE_MAX UINT_MAX /* max value for a size_t */
+#define SSIZE_MAX INT_MAX /* max value for a ssize_t */
+
+#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
+#define SIZE_T_MAX UINT_MAX /* max value for a size_t */
+
+#define UQUAD_MAX 0xffffffffffffffffULL /* max unsigned quad */
+#define QUAD_MAX 0x7fffffffffffffffLL /* max signed quad */
+#define QUAD_MIN (-0x7fffffffffffffffLL-1) /* min signed quad */
+
+#endif /* !_POSIX_SOURCE && !_XOPEN_SOURCE */
+#endif /* !_ANSI_SOURCE */
+
+#endif /* _ARM32_LIMITS_H_ */
diff --git a/sys/arch/arm/include/lock.h b/sys/arch/arm/include/lock.h
new file mode 100644
index 00000000000..f949eb8d3b9
--- /dev/null
+++ b/sys/arch/arm/include/lock.h
@@ -0,0 +1,90 @@
+/* $OpenBSD: lock.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: lock.h,v 1.3 2002/10/07 23:19:49 bjh21 Exp $ */
+
+/*-
+ * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Machine-dependent spin lock operations.
+ *
+ * NOTE: The SWP insn used here is available only on ARM architecture
+ * version 3 and later (as well as 2a). What we are going to do is
+ * expect that the kernel will trap and emulate the insn. That will
+ * be slow, but give us the atomicity that we need.
+ */
+
+#ifndef _ARM_LOCK_H_
+#define _ARM_LOCK_H_
+
+static __inline int
+__swp(int __val, __volatile int *__ptr)
+{
+
+ __asm __volatile("swp %0, %1, [%2]"
+ : "=r" (__val) : "r" (__val), "r" (__ptr) : "memory");
+ return __val;
+}
+
+static __inline void __attribute__((__unused__))
+__cpu_simple_lock_init(__cpu_simple_lock_t *alp)
+{
+
+ *alp = __SIMPLELOCK_UNLOCKED;
+}
+
+static __inline void __attribute__((__unused__))
+__cpu_simple_lock(__cpu_simple_lock_t *alp)
+{
+
+ while (__swp(__SIMPLELOCK_LOCKED, alp) != __SIMPLELOCK_UNLOCKED)
+ continue;
+}
+
+static __inline int __attribute__((__unused__))
+__cpu_simple_lock_try(__cpu_simple_lock_t *alp)
+{
+
+ return (__swp(__SIMPLELOCK_LOCKED, alp) == __SIMPLELOCK_UNLOCKED);
+}
+
+static __inline void __attribute__((__unused__))
+__cpu_simple_unlock(__cpu_simple_lock_t *alp)
+{
+
+ *alp = __SIMPLELOCK_UNLOCKED;
+}
+
+#endif /* _ARM_LOCK_H_ */
diff --git a/sys/arch/arm/include/machdep.h b/sys/arch/arm/include/machdep.h
new file mode 100644
index 00000000000..4abb8321219
--- /dev/null
+++ b/sys/arch/arm/include/machdep.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: machdep.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: machdep.h,v 1.7 2002/02/21 02:52:21 thorpej Exp $ */
+
+#ifndef _ARM32_BOOT_MACHDEP_H_
+#define _ARM32_BOOT_MACHDEP_H_
+
+/* misc prototypes used by the many arm machdeps */
+void halt __P((void));
+void parse_mi_bootargs __P((char *));
+void data_abort_handler __P((trapframe_t *));
+void prefetch_abort_handler __P((trapframe_t *));
+void undefinedinstruction_bounce __P((trapframe_t *));
+void dumpsys __P((void));
+
+/*
+ * note that we use void * as all the platforms have different ideas on what
+ * the structure is
+ */
+u_int initarm __P((void *));
+
+/* from arm/arm/intr.c */
+void dosoftints __P((void));
+void set_spl_masks __P((void));
+#ifdef DIAGNOSTIC
+void dump_spl_masks __P((void));
+#endif
+#endif
diff --git a/sys/arch/arm/include/math.h b/sys/arch/arm/include/math.h
new file mode 100644
index 00000000000..a5818196591
--- /dev/null
+++ b/sys/arch/arm/include/math.h
@@ -0,0 +1,4 @@
+/* $OpenBSD: math.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: math.h,v 1.2 2002/02/19 13:08:14 simonb Exp $ */
+
+#define __HAVE_NANF
diff --git a/sys/arch/arm/include/param.h b/sys/arch/arm/include/param.h
new file mode 100644
index 00000000000..72926990653
--- /dev/null
+++ b/sys/arch/arm/include/param.h
@@ -0,0 +1,241 @@
+/* $OpenBSD: param.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: param.h,v 1.9 2002/03/24 03:37:23 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the RiscBSD team.
+ * 4. The name "RiscBSD" nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_ARM_PARAM_H_
+#define _ARM_ARM_PARAM_H_
+
+
+/*
+ * Machine dependent constants for ARM6+ processors
+ */
+/* These are defined in the Port File before it includes
+ * this file. */
+
+#define PAGE_SHIFT 12 /* LOG2(NBPG) */
+#define PGSHIFT 12 /* LOG2(NBPG) */
+#define PAGE_SIZE (1 << PAGE_SHIFT) /* bytes/page */
+#define NBPG (1 << PAGE_SHIFT) /* bytes/page */
+#define PAGE_MASK (PAGE_SIZE - 1)
+#define PGOFSET (PAGE_SIZE - 1)
+#define NPTEPG (PAGE_SIZE/(sizeof (pt_entry_t)))
+
+#define SSIZE 1 /* initial stack size/NBPG */
+#define SINCR 1 /* increment of stack/NBPG */
+#define UPAGES 2 /* pages of u-area */
+#define USPACE (UPAGES * PAGE_SIZE) /* total size of u-area */
+
+#ifndef MSGBUFSIZE
+#define MSGBUFSIZE PAGE_SIZE /* default message buffer size */
+#endif
+
+#ifndef NMBCLUSTERS
+#ifdef GATEWAY
+#define NMBCLUSTERS 2048 /* map size, max cluster allocation */
+#else
+#define NMBCLUSTERS 1024 /* map size, max cluster allocation */
+#endif
+#endif
+
+/*
+ * Minimum and maximum sizes of the kernel malloc arena in PAGE_SIZE-sized
+ * logical pages.
+ */
+#define NKMEMPAGES_MIN_DEFAULT ((6 * 1024 * 1024) >> PAGE_SHIFT)
+#define NKMEMPAGES_MAX_DEFAULT ((7 * 1024 * 1024) >> PAGE_SHIFT)
+
+/* Constants used to divide the USPACE area */
+
+/*
+ * The USPACE area contains :
+ * 1. the user structure for the process
+ * 2. the fp context for FP emulation
+ * 3. the kernel (svc) stack
+ * 4. the undefined instruction stack
+ *
+ * The layout of the area looks like this
+ *
+ * | user area | FP context | undefined stack | kernel stack |
+ *
+ * The size of the user area is known.
+ * The size of the FP context is variable depending of the FP emulator
+ * in use and whether there is hardware FP support. However we can put
+ * an upper limit on it.
+ * The undefined stack needs to be at least 512 bytes. This is a requirement
+ * if the FP emulators
+ * The kernel stack should be at least 4K is size.
+ *
+ * The stack top addresses are used to set the stack pointers. The stack bottom
+ * addresses at the addresses monitored by the diagnostic code for stack overflows
+ *
+ */
+
+#define FPCONTEXTSIZE (0x100)
+#define USPACE_SVC_STACK_TOP (USPACE)
+#define USPACE_SVC_STACK_BOTTOM (USPACE_SVC_STACK_TOP - 0x1000)
+#define USPACE_UNDEF_STACK_TOP (USPACE_SVC_STACK_BOTTOM - 0x10)
+#define USPACE_UNDEF_STACK_BOTTOM (sizeof(struct user) + FPCONTEXTSIZE + 10)
+
+#define arm_btop(x) ((x) >> PAGE_SHIFT)
+#define arm_ptob(x) ((x) << PAGE_SHIFT)
+#define arm_trunc_page(x) ((unsigned)(x) & ~PAGE_MASK)
+
+#ifdef _KERNEL
+#ifndef _LOCORE
+void delay __P((unsigned));
+#define DELAY(x) delay(x)
+#endif
+#endif
+
+/*
+ * Machine dependent constants for all ARM processors
+ */
+
+/*
+ * For KERNEL code:
+ * MACHINE must be defined by the individual port. This is so that
+ * uname returns the correct thing, etc.
+ *
+ * MACHINE_ARCH may be defined by individual ports as a temporary
+ * measure while we're finishing the conversion to ELF.
+ *
+ * For non-KERNEL code:
+ * If ELF, MACHINE and MACHINE_ARCH are forced to "arm/armeb".
+ */
+
+#if defined(_KERNEL)
+#ifndef MACHINE_ARCH /* XXX For now */
+#ifndef __ARMEB__
+#define _MACHINE_ARCH arm
+#define MACHINE_ARCH "arm"
+#else
+#define _MACHINE_ARCH armeb
+#define MACHINE_ARCH "armeb"
+#endif /* __ARMEB__ */
+#endif /* MACHINE_ARCH */
+#elif defined(__ELF__)
+#undef _MACHINE
+#undef MACHINE
+#undef _MACHINE_ARCH
+#undef MACHINE_ARCH
+#define _MACHINE arm
+#define MACHINE "arm"
+#ifndef __ARMEB__
+#define _MACHINE_ARCH arm
+#define MACHINE_ARCH "arm"
+#else
+#define _MACHINE_ARCH armeb
+#define MACHINE_ARCH "armeb"
+#endif /* __ARMEB__ */
+#endif /* __ELF__ */
+
+#define MID_MACHINE MID_ARM6
+
+/*
+ * Round p (pointer or byte index) up to a correctly-aligned value
+ * for all data types (int, long, ...). The result is u_int and
+ * must be cast to any desired pointer type.
+ *
+ * ALIGNED_POINTER is a boolean macro that checks whether an address
+ * is valid to fetch data elements of type t from on this architecture.
+ * This does not reflect the optimal alignment, just the possibility
+ * (within reasonable limits).
+ *
+ */
+#define ALIGNBYTES (sizeof(int) - 1)
+#define ALIGN(p) (((u_int)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+#define ALIGNED_POINTER(p,t) ((((u_long)(p)) & (sizeof(t)-1)) == 0)
+/* ARM-specific macro to align a stack pointer (downwards). */
+#define STACKALIGNBYTES (8 - 1)
+#define STACKALIGN(p) ((u_int)(p) &~ STACKALIGNBYTES)
+
+#define DEV_BSHIFT 9 /* log2(DEV_BSIZE) */
+#define DEV_BSIZE (1 << DEV_BSHIFT)
+#define BLKDEV_IOSIZE 2048
+
+#ifndef MAXPHYS
+#define MAXPHYS 65536 /* max I/O transfer size */
+#endif
+
+/* pages ("clicks") to disk blocks */
+#define ctod(x) ((x) << (PAGE_SHIFT - DEV_BSHIFT))
+#define dtoc(x) ((x) >> (PAGE_SHIFT - DEV_BSHIFT))
+/*#define dtob(x) ((x) << DEV_BSHIFT)*/
+
+#define ctob(x) ((x) << PAGE_SHIFT)
+
+/* bytes to pages */
+#define btoc(x) (((x) + PAGE_MASK) >> PAGE_SHIFT)
+
+#define btodb(bytes) /* calculates (bytes / DEV_BSIZE) */ \
+ ((bytes) >> DEV_BSHIFT)
+#define dbtob(db) /* calculates (db * DEV_BSIZE) */ \
+ ((db) << DEV_BSHIFT)
+
+/*
+ * Map a ``block device block'' to a file system block.
+ * This should be device dependent, and should use the bsize
+ * field from the disk label.
+ * For now though just use DEV_BSIZE.
+ */
+#define bdbtofsb(bn) ((bn) / (BLKDEV_IOSIZE / DEV_BSIZE))
+
+/*
+ * Constants related to network buffer management.
+ * MCLBYTES must be no larger than NBPG (the software page size), and,
+ * on machines that exchange pages of input or output buffers with mbuf
+ * clusters (MAPPED_MBUFS), MCLBYTES must also be an integral multiple
+ * of the hardware page size.
+ */
+#define MSIZE 256 /* size of an mbuf */
+
+#ifndef MCLSHIFT
+#define MCLSHIFT 11 /* convert bytes to m_buf clusters */
+ /* 2K cluster can hold Ether frame */
+#endif /* MCLSHIFT */
+
+#define MCLBYTES (1 << MCLSHIFT) /* size of a m_buf cluster */
+
+#define ovbcopy bcopy
+
+#ifdef _KERNEL
+#ifdef _LOCORE
+#include <machine/psl.h>
+#else
+#include <sys/param.h>
+#include <machine/cpu.h>
+#endif
+#endif
+
+#endif /* _ARM_ARM_PARAM_H_ */
diff --git a/sys/arch/arm/include/pcb.h b/sys/arch/arm/include/pcb.h
new file mode 100644
index 00000000000..d52c0893513
--- /dev/null
+++ b/sys/arch/arm/include/pcb.h
@@ -0,0 +1,115 @@
+/* $OpenBSD: pcb.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: pcb.h,v 1.10 2003/10/13 21:46:39 scw Exp $ */
+
+/*
+ * Copyright (c) 2001 Matt Thomas <matt@3am-software.com>.
+ * Copyright (c) 1994 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the RiscBSD team.
+ * 4. The name "RiscBSD" nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_PCB_H_
+#define _ARM_PCB_H_
+
+#include <machine/frame.h>
+#include <machine/fp.h>
+
+#include <arm/pte.h>
+
+struct trapframe;
+
+struct pcb_arm32 {
+ paddr_t pcb32_pagedir; /* PT hooks */
+ pd_entry_t *pcb32_pl1vec; /* PTR to vector_base L1 entry*/
+ pd_entry_t pcb32_l1vec; /* Value to stuff on ctx sw */
+ u_int pcb32_dacr; /* Domain Access Control Reg */
+ void *pcb32_cstate; /* &pmap->pm_cstate */
+ /*
+ * WARNING!
+ * cpuswitch.S relies on pcb32_r8 being quad-aligned in struct pcb
+ * (due to the use of "strd" when compiled for XSCALE)
+ */
+ u_int pcb32_r8; /* used */
+ u_int pcb32_r9; /* used */
+ u_int pcb32_r10; /* used */
+ u_int pcb32_r11; /* used */
+ u_int pcb32_r12; /* used */
+ u_int pcb32_sp; /* used */
+ u_int pcb32_lr;
+ u_int pcb32_pc;
+ u_int pcb32_und_sp;
+};
+#define pcb_pagedir pcb_un.un_32.pcb32_pagedir
+#define pcb_pl1vec pcb_un.un_32.pcb32_pl1vec
+#define pcb_l1vec pcb_un.un_32.pcb32_l1vec
+#define pcb_dacr pcb_un.un_32.pcb32_dacr
+#define pcb_cstate pcb_un.un_32.pcb32_cstate
+
+struct pcb_arm26 {
+ struct switchframe *pcb26_sf;
+};
+#define pcb_sf pcb_un.un_26.pcb26_sf
+
+/*
+ * WARNING!
+ * See warning for struct pcb_arm32, above, before changing struct pcb!
+ */
+struct pcb {
+ u_int pcb_flags;
+#define PCB_OWNFPU 0x00000001
+#define PCB_NOALIGNFLT 0x00000002 /* For COMPAT_15/EXEC_AOUT */
+ struct trapframe *pcb_tf;
+ caddr_t pcb_onfault; /* On fault handler */
+ union {
+ struct pcb_arm32 un_32;
+ struct pcb_arm26 un_26;
+ } pcb_un;
+ struct fpe_sp_state pcb_fpstate; /* Floating Point state */
+};
+#define pcb_ff pcb_fpstate /* for arm26 */
+
+/*
+ * No additional data for core dumps.
+ */
+struct md_coredump {
+ int md_empty;
+};
+
+#ifdef _KERNEL
+#ifdef _KERNEL_OPT
+#include "opt_multiprocessor.h"
+#endif
+#ifdef MULTIPROCESSOR
+#define curpcb (curcpu()->ci_curpcb)
+#else
+extern struct pcb *curpcb;
+#endif
+#endif /* _KERNEL */
+
+#endif /* _ARM_PCB_H_ */
diff --git a/sys/arch/arm/include/pci_machdep.h b/sys/arch/arm/include/pci_machdep.h
new file mode 100644
index 00000000000..2d67a3d9120
--- /dev/null
+++ b/sys/arch/arm/include/pci_machdep.h
@@ -0,0 +1,103 @@
+/* $OpenBSD: pci_machdep.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: pci_machdep.h,v 1.2 2002/05/15 19:23:52 thorpej Exp $ */
+
+/*
+ * Modified for arm32 by Mark Brinicombe
+ *
+ * from: sys/arch/alpha/pci/pci_machdep.h
+ *
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Machine-specific definitions for PCI autoconfiguration.
+ */
+
+/*
+ * Types provided to machine-independent PCI code
+ */
+typedef struct arm32_pci_chipset *pci_chipset_tag_t;
+typedef u_long pcitag_t;
+typedef u_long pci_intr_handle_t;
+
+/*
+ * Forward declarations.
+ */
+struct pci_attach_args;
+
+/*
+ * arm32-specific PCI structure and type definitions.
+ * NOT TO BE USED DIRECTLY BY MACHINE INDEPENDENT CODE.
+ */
+struct arm32_pci_chipset {
+ void *pc_conf_v;
+ void (*pc_attach_hook)(struct device *,
+ struct device *, struct pcibus_attach_args *);
+ int (*pc_bus_maxdevs)(void *, int);
+ pcitag_t (*pc_make_tag)(void *, int, int, int);
+ void (*pc_decompose_tag)(void *, pcitag_t, int *,
+ int *, int *);
+ pcireg_t (*pc_conf_read)(void *, pcitag_t, int);
+ void (*pc_conf_write)(void *, pcitag_t, int, pcireg_t);
+
+ void *pc_intr_v;
+ int (*pc_intr_map)(struct pci_attach_args *,
+ pci_intr_handle_t *);
+ const char *(*pc_intr_string)(void *, pci_intr_handle_t);
+ const struct evcnt *(*pc_intr_evcnt)(void *, pci_intr_handle_t);
+ void *(*pc_intr_establish)(void *, pci_intr_handle_t,
+ int, int (*)(void *), void *, char *);
+ void (*pc_intr_disestablish)(void *, void *);
+};
+
+/*
+ * Functions provided to machine-independent PCI code.
+ */
+#define pci_attach_hook(p, s, pba) \
+ (*(pba)->pba_pc->pc_attach_hook)((p), (s), (pba))
+#define pci_bus_maxdevs(c, b) \
+ (*(c)->pc_bus_maxdevs)((c)->pc_conf_v, (b))
+#define pci_make_tag(c, b, d, f) \
+ (*(c)->pc_make_tag)((c)->pc_conf_v, (b), (d), (f))
+#define pci_decompose_tag(c, t, bp, dp, fp) \
+ (*(c)->pc_decompose_tag)((c)->pc_conf_v, (t), (bp), (dp), (fp))
+#define pci_conf_read(c, t, r) \
+ (*(c)->pc_conf_read)((c)->pc_conf_v, (t), (r))
+#define pci_conf_write(c, t, r, v) \
+ (*(c)->pc_conf_write)((c)->pc_conf_v, (t), (r), (v))
+#define pci_intr_map(pa, ihp) \
+ (*(pa)->pa_pc->pc_intr_map)((pa), (ihp))
+#define pci_intr_string(c, ih) \
+ (*(c)->pc_intr_string)((c)->pc_intr_v, (ih))
+#define pci_intr_evcnt(c, ih) \
+ (*(c)->pc_intr_evcnt)((c)->pc_intr_v, (ih))
+#define pci_intr_establish(c, ih, l, h, a, n) \
+ (*(c)->pc_intr_establish)((c)->pc_intr_v, (ih), (l), (h), (a), (n))
+#define pci_intr_disestablish(c, iv) \
+ (*(c)->pc_intr_disestablish)((c)->pc_intr_v, (iv))
+
+#define pci_enumerate_bus(sc, m, p) \
+ pci_enumerate_bus_generic((sc), (m), (p))
diff --git a/sys/arch/arm/include/pio.h b/sys/arch/arm/include/pio.h
new file mode 100644
index 00000000000..280c3c2d4c5
--- /dev/null
+++ b/sys/arch/arm/include/pio.h
@@ -0,0 +1,47 @@
+/* $OpenBSD: pio.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: pio.h,v 1.1 2001/02/23 21:23:48 reinoud Exp $ */
+
+/*
+ * Copyright 1997
+ * Digital Equipment Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and conditions.
+ * Subject to these conditions, you may download, copy, install,
+ * use, modify and distribute this software in source and/or binary
+ * form. No title or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions as
+ * they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or logo of
+ * Digital Equipment Corporation. Neither the "Digital Equipment
+ * Corporation" name nor any trademark or logo of Digital Equipment
+ * Corporation may be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Digital Equipment Corporation.
+ *
+ * 3) This software is provided "AS-IS" and any express or implied
+ * warranties, including but not limited to, any implied warranties
+ * of merchantability, fitness for a particular purpose, or
+ * non-infringement are disclaimed. In no event shall DIGITAL be
+ * liable for any damages whatsoever, and in particular, DIGITAL
+ * shall not be liable for special, indirect, consequential, or
+ * incidental damages or damages for lost profits, loss of
+ * revenue or loss of use, whether such damages arise in contract,
+ * negligence, tort, under statute, in equity, at law or otherwise,
+ * even if advised of the possibility of such damage.
+ */
+
+#ifndef _ARM32_PIO_H_
+#define _ARM32_PIO_H_
+
+#include <machine/bus.h>
+
+extern struct bus_space isa_io_bs_tag;
+
+#define inb(port) bus_space_read_1( &isa_io_bs_tag, (bus_space_handle_t)isa_io_bs_tag.bs_cookie, (port))
+#define outb(port, byte) bus_space_write_1(&isa_io_bs_tag, (bus_space_handle_t)isa_io_bs_tag.bs_cookie, (port), (byte))
+
+#endif /* _ARM32_PIO_H_ */
diff --git a/sys/arch/arm/include/pmap.h b/sys/arch/arm/include/pmap.h
new file mode 100644
index 00000000000..0261d72c332
--- /dev/null
+++ b/sys/arch/arm/include/pmap.h
@@ -0,0 +1,595 @@
+/* $OpenBSD: pmap.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: pmap.h,v 1.76 2003/09/06 09:10:46 rearnsha Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe & Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM32_PMAP_H_
+#define _ARM32_PMAP_H_
+
+#ifdef _KERNEL
+
+#include <arm/cpuconf.h>
+#include <arm/pte.h>
+#ifndef _LOCORE
+#include <arm/cpufunc.h>
+#include <uvm/uvm_object.h>
+#endif
+
+/*
+ * a pmap describes a processes' 4GB virtual address space. this
+ * virtual address space can be broken up into 4096 1MB regions which
+ * are described by L1 PTEs in the L1 table.
+ *
+ * There is a line drawn at KERNEL_BASE. Everything below that line
+ * changes when the VM context is switched. Everything above that line
+ * is the same no matter which VM context is running. This is achieved
+ * by making the L1 PTEs for those slots above KERNEL_BASE reference
+ * kernel L2 tables.
+ *
+ * The basic layout of the virtual address space thus looks like this:
+ *
+ * 0xffffffff
+ * .
+ * .
+ * .
+ * KERNEL_BASE
+ * --------------------
+ * .
+ * .
+ * .
+ * 0x00000000
+ */
+
+/*
+ * The number of L2 descriptor tables which can be tracked by an l2_dtable.
+ * A bucket size of 16 provides for 16MB of contiguous virtual address
+ * space per l2_dtable. Most processes will, therefore, require only two or
+ * three of these to map their whole working set.
+ */
+#define L2_BUCKET_LOG2 4
+#define L2_BUCKET_SIZE (1 << L2_BUCKET_LOG2)
+
+/*
+ * Given the above "L2-descriptors-per-l2_dtable" constant, the number
+ * of l2_dtable structures required to track all possible page descriptors
+ * mappable by an L1 translation table is given by the following constants:
+ */
+#define L2_LOG2 ((32 - L1_S_SHIFT) - L2_BUCKET_LOG2)
+#define L2_SIZE (1 << L2_LOG2)
+
+#ifndef _LOCORE
+
+struct l1_ttable;
+struct l2_dtable;
+
+/*
+ * Track cache/tlb occupancy using the following structure
+ */
+union pmap_cache_state {
+ struct {
+ union {
+ u_int8_t csu_cache_b[2];
+ u_int16_t csu_cache;
+ } cs_cache_u;
+
+ union {
+ u_int8_t csu_tlb_b[2];
+ u_int16_t csu_tlb;
+ } cs_tlb_u;
+ } cs_s;
+ u_int32_t cs_all;
+};
+#define cs_cache_id cs_s.cs_cache_u.csu_cache_b[0]
+#define cs_cache_d cs_s.cs_cache_u.csu_cache_b[1]
+#define cs_cache cs_s.cs_cache_u.csu_cache
+#define cs_tlb_id cs_s.cs_tlb_u.csu_tlb_b[0]
+#define cs_tlb_d cs_s.cs_tlb_u.csu_tlb_b[1]
+#define cs_tlb cs_s.cs_tlb_u.csu_tlb
+
+/*
+ * Assigned to cs_all to force cacheops to work for a particular pmap
+ */
+#define PMAP_CACHE_STATE_ALL 0xffffffffu
+
+/*
+ * This structure is used by machine-dependent code to describe
+ * static mappings of devices, created at bootstrap time.
+ */
+struct pmap_devmap {
+ vaddr_t pd_va; /* virtual address */
+ paddr_t pd_pa; /* physical address */
+ psize_t pd_size; /* size of region */
+ vm_prot_t pd_prot; /* protection code */
+ int pd_cache; /* cache attributes */
+};
+
+/*
+ * The pmap structure itself
+ */
+struct pmap {
+ u_int8_t pm_domain;
+ boolean_t pm_remove_all;
+ struct l1_ttable *pm_l1;
+ union pmap_cache_state pm_cstate;
+ struct uvm_object pm_obj;
+#define pm_lock pm_obj.vmobjlock
+ struct l2_dtable *pm_l2[L2_SIZE];
+ struct pmap_statistics pm_stats;
+ LIST_ENTRY(pmap) pm_list;
+};
+
+typedef struct pmap *pmap_t;
+
+/*
+ * Physical / virtual address structure. In a number of places (particularly
+ * during bootstrapping) we need to keep track of the physical and virtual
+ * addresses of various pages
+ */
+typedef struct pv_addr {
+ SLIST_ENTRY(pv_addr) pv_list;
+ paddr_t pv_pa;
+ vaddr_t pv_va;
+} pv_addr_t;
+
+/*
+ * Determine various modes for PTEs (user vs. kernel, cacheable
+ * vs. non-cacheable).
+ */
+#define PTE_KERNEL 0
+#define PTE_USER 1
+#define PTE_NOCACHE 0
+#define PTE_CACHE 1
+#define PTE_PAGETABLE 2
+
+/*
+ * Flags that indicate attributes of pages or mappings of pages.
+ *
+ * The PVF_MOD and PVF_REF flags are stored in the mdpage for each
+ * page. PVF_WIRED, PVF_WRITE, and PVF_NC are kept in individual
+ * pv_entry's for each page. They live in the same "namespace" so
+ * that we can clear multiple attributes at a time.
+ *
+ * Note the "non-cacheable" flag generally means the page has
+ * multiple mappings in a given address space.
+ */
+#define PVF_MOD 0x01 /* page is modified */
+#define PVF_REF 0x02 /* page is referenced */
+#define PVF_WIRED 0x04 /* mapping is wired */
+#define PVF_WRITE 0x08 /* mapping is writable */
+#define PVF_EXEC 0x10 /* mapping is executable */
+#define PVF_UNC 0x20 /* mapping is 'user' non-cacheable */
+#define PVF_KNC 0x40 /* mapping is 'kernel' non-cacheable */
+#define PVF_NC (PVF_UNC|PVF_KNC)
+
+/*
+ * Commonly referenced structures
+ */
+extern struct pmap kernel_pmap_store;
+extern int pmap_debug_level; /* Only exists if PMAP_DEBUG */
+
+/*
+ * Macros that we need to export
+ */
+#define pmap_kernel() (&kernel_pmap_store)
+#define pmap_resident_count(pmap) ((pmap)->pm_stats.resident_count)
+#define pmap_wired_count(pmap) ((pmap)->pm_stats.wired_count)
+
+#define pmap_is_modified(pg) \
+ (((pg)->mdpage.pvh_attrs & PVF_MOD) != 0)
+#define pmap_is_referenced(pg) \
+ (((pg)->mdpage.pvh_attrs & PVF_REF) != 0)
+
+#define pmap_copy(dp, sp, da, l, sa) /* nothing */
+
+#define pmap_phys_address(ppn) (arm_ptob((ppn)))
+
+/*
+ * Functions that we need to export
+ */
+void pmap_procwr(struct proc *, vaddr_t, int);
+void pmap_remove_all(pmap_t);
+boolean_t pmap_extract(pmap_t, vaddr_t, paddr_t *);
+
+#define PMAP_NEED_PROCWR
+#define PMAP_GROWKERNEL /* turn on pmap_growkernel interface */
+
+/* Functions we use internally. */
+void pmap_bootstrap(pd_entry_t *, vaddr_t, vaddr_t);
+
+int pmap_fault_fixup(pmap_t, vaddr_t, vm_prot_t, int);
+boolean_t pmap_get_pde_pte(pmap_t, vaddr_t, pd_entry_t **, pt_entry_t **);
+boolean_t pmap_get_pde(pmap_t, vaddr_t, pd_entry_t **);
+void pmap_set_pcb_pagedir(pmap_t, struct pcb *);
+
+void pmap_debug(int);
+void pmap_postinit(void);
+
+void vector_page_setprot(int);
+
+const struct pmap_devmap *pmap_devmap_find_pa(paddr_t, psize_t);
+const struct pmap_devmap *pmap_devmap_find_va(vaddr_t, vsize_t);
+
+/* Bootstrapping routines. */
+void pmap_map_section(vaddr_t, vaddr_t, paddr_t, int, int);
+void pmap_map_entry(vaddr_t, vaddr_t, paddr_t, int, int);
+vsize_t pmap_map_chunk(vaddr_t, vaddr_t, paddr_t, vsize_t, int, int);
+void pmap_link_l2pt(vaddr_t, vaddr_t, pv_addr_t *);
+void pmap_devmap_bootstrap(vaddr_t, const struct pmap_devmap *);
+void pmap_devmap_register(const struct pmap_devmap *);
+
+/*
+ * Special page zero routine for use by the idle loop (no cache cleans).
+ */
+boolean_t pmap_pageidlezero(struct vm_page *);
+#define PMAP_PAGEIDLEZERO(pg) pmap_pageidlezero((pg))
+
+/*
+ * The current top of kernel VM
+ */
+extern vaddr_t pmap_curmaxkvaddr;
+
+/*
+ * Useful macros and constants
+ */
+
+/* Virtual address to page table entry */
+static __inline pt_entry_t *
+vtopte(vaddr_t va)
+{
+ pd_entry_t *pdep;
+ pt_entry_t *ptep;
+
+ if (pmap_get_pde_pte(pmap_kernel(), va, &pdep, &ptep) == FALSE)
+ return (NULL);
+ return (ptep);
+}
+
+/*
+ * Virtual address to physical address
+ */
+static __inline paddr_t
+vtophys(vaddr_t va)
+{
+ paddr_t pa;
+
+ if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
+ return (0); /* XXXSCW: Panic? */
+
+ return (pa);
+}
+
+/*
+ * The new pmap ensures that page-tables are always mapping Write-Thru.
+ * Thus, on some platforms we can run fast and loose and avoid syncing PTEs
+ * on every change.
+ *
+ * Unfortunately, not all CPUs have a write-through cache mode. So we
+ * define PMAP_NEEDS_PTE_SYNC for C code to conditionally do PTE syncs,
+ * and if there is the chance for PTE syncs to be needed, we define
+ * PMAP_INCLUDE_PTE_SYNC so e.g. assembly code can include (and run)
+ * the code.
+ */
+extern int pmap_needs_pte_sync;
+#if defined(_KERNEL_OPT)
+/*
+ * StrongARM SA-1 caches do not have a write-through mode. So, on these,
+ * we need to do PTE syncs. If only SA-1 is configured, then evaluate
+ * this at compile time.
+ */
+#if (ARM_MMU_SA1 == 1) && (ARM_NMMUS == 1)
+#define PMAP_NEEDS_PTE_SYNC 1
+#define PMAP_INCLUDE_PTE_SYNC
+#elif (ARM_MMU_SA1 == 0)
+#define PMAP_NEEDS_PTE_SYNC 0
+#endif
+#endif /* _KERNEL_OPT */
+
+/*
+ * Provide a fallback in case we were not able to determine it at
+ * compile-time.
+ */
+#ifndef PMAP_NEEDS_PTE_SYNC
+#define PMAP_NEEDS_PTE_SYNC pmap_needs_pte_sync
+#define PMAP_INCLUDE_PTE_SYNC
+#endif
+
+#define PTE_SYNC(pte) \
+do { \
+ if (PMAP_NEEDS_PTE_SYNC) \
+ cpu_dcache_wb_range((vaddr_t)(pte), sizeof(pt_entry_t));\
+} while (/*CONSTCOND*/0)
+
+#define PTE_SYNC_RANGE(pte, cnt) \
+do { \
+ if (PMAP_NEEDS_PTE_SYNC) { \
+ cpu_dcache_wb_range((vaddr_t)(pte), \
+ (cnt) << 2); /* * sizeof(pt_entry_t) */ \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define l1pte_valid(pde) ((pde) != 0)
+#define l1pte_section_p(pde) (((pde) & L1_TYPE_MASK) == L1_TYPE_S)
+#define l1pte_page_p(pde) (((pde) & L1_TYPE_MASK) == L1_TYPE_C)
+#define l1pte_fpage_p(pde) (((pde) & L1_TYPE_MASK) == L1_TYPE_F)
+
+#define l2pte_index(v) (((v) & L2_ADDR_BITS) >> L2_S_SHIFT)
+#define l2pte_valid(pte) ((pte) != 0)
+#define l2pte_pa(pte) ((pte) & L2_S_FRAME)
+#define l2pte_minidata(pte) (((pte) & \
+ (L2_B | L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X)))\
+ == (L2_C | L2_XSCALE_T_TEX(TEX_XSCALE_X)))
+
+/* L1 and L2 page table macros */
+#define pmap_pde_v(pde) l1pte_valid(*(pde))
+#define pmap_pde_section(pde) l1pte_section_p(*(pde))
+#define pmap_pde_page(pde) l1pte_page_p(*(pde))
+#define pmap_pde_fpage(pde) l1pte_fpage_p(*(pde))
+
+#define pmap_pte_v(pte) l2pte_valid(*(pte))
+#define pmap_pte_pa(pte) l2pte_pa(*(pte))
+
+/* Size of the kernel part of the L1 page table */
+#define KERNEL_PD_SIZE \
+ (L1_TABLE_SIZE - (KERNEL_BASE >> L1_S_SHIFT) * sizeof(pd_entry_t))
+
+/************************* ARM MMU configuration *****************************/
+
+#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0
+void pmap_copy_page_generic(struct vm_page *, struct vm_page *);
+void pmap_zero_page_generic(struct vm_page *);
+
+void pmap_pte_init_generic(void);
+#if defined(CPU_ARM8)
+void pmap_pte_init_arm8(void);
+#endif
+#if defined(CPU_ARM9)
+void pmap_pte_init_arm9(void);
+#endif /* CPU_ARM9 */
+#if defined(CPU_ARM10)
+void pmap_pte_init_arm10(void);
+#endif /* CPU_ARM10 */
+#endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */
+
+#if ARM_MMU_SA1 == 1
+void pmap_pte_init_sa1(void);
+#endif /* ARM_MMU_SA1 == 1 */
+
+#if ARM_MMU_XSCALE == 1
+void pmap_copy_page_xscale(struct vm_page *, struct vm_page *);
+void pmap_zero_page_xscale(struct vm_page *);
+
+void pmap_pte_init_xscale(void);
+
+void xscale_setup_minidata(vaddr_t, vaddr_t, paddr_t);
+
+#define PMAP_UAREA(va) pmap_uarea(va)
+void pmap_uarea(vaddr_t);
+#endif /* ARM_MMU_XSCALE == 1 */
+
+extern pt_entry_t pte_l1_s_cache_mode;
+extern pt_entry_t pte_l1_s_cache_mask;
+
+extern pt_entry_t pte_l2_l_cache_mode;
+extern pt_entry_t pte_l2_l_cache_mask;
+
+extern pt_entry_t pte_l2_s_cache_mode;
+extern pt_entry_t pte_l2_s_cache_mask;
+
+extern pt_entry_t pte_l1_s_cache_mode_pt;
+extern pt_entry_t pte_l2_l_cache_mode_pt;
+extern pt_entry_t pte_l2_s_cache_mode_pt;
+
+extern pt_entry_t pte_l2_s_prot_u;
+extern pt_entry_t pte_l2_s_prot_w;
+extern pt_entry_t pte_l2_s_prot_mask;
+
+extern pt_entry_t pte_l1_s_proto;
+extern pt_entry_t pte_l1_c_proto;
+extern pt_entry_t pte_l2_s_proto;
+
+extern void (*pmap_copy_page_func)(struct vm_page *, struct vm_page *);
+extern void (*pmap_zero_page_func)(struct vm_page *);
+
+#endif /* !_LOCORE */
+
+/*****************************************************************************/
+
+/*
+ * tell MI code that the cache is virtually-indexed *and* virtually-tagged.
+ */
+#define PMAP_CACHE_VIVT
+
+/*
+ * Definitions for MMU domains
+ */
+#define PMAP_DOMAINS 15 /* 15 'user' domains (0-14) */
+#define PMAP_DOMAIN_KERNEL 15 /* The kernel uses domain #15 */
+
+/*
+ * These macros define the various bit masks in the PTE.
+ *
+ * We use these macros since we use different bits on different processor
+ * models.
+ */
+#define L1_S_PROT_U (L1_S_AP(AP_U))
+#define L1_S_PROT_W (L1_S_AP(AP_W))
+#define L1_S_PROT_MASK (L1_S_PROT_U|L1_S_PROT_W)
+
+#define L1_S_CACHE_MASK_generic (L1_S_B|L1_S_C)
+#define L1_S_CACHE_MASK_xscale (L1_S_B|L1_S_C|L1_S_XSCALE_TEX(TEX_XSCALE_X))
+
+#define L2_L_PROT_U (L2_AP(AP_U))
+#define L2_L_PROT_W (L2_AP(AP_W))
+#define L2_L_PROT_MASK (L2_L_PROT_U|L2_L_PROT_W)
+
+#define L2_L_CACHE_MASK_generic (L2_B|L2_C)
+#define L2_L_CACHE_MASK_xscale (L2_B|L2_C|L2_XSCALE_L_TEX(TEX_XSCALE_X))
+
+#define L2_S_PROT_U_generic (L2_AP(AP_U))
+#define L2_S_PROT_W_generic (L2_AP(AP_W))
+#define L2_S_PROT_MASK_generic (L2_S_PROT_U|L2_S_PROT_W)
+
+#define L2_S_PROT_U_xscale (L2_AP0(AP_U))
+#define L2_S_PROT_W_xscale (L2_AP0(AP_W))
+#define L2_S_PROT_MASK_xscale (L2_S_PROT_U|L2_S_PROT_W)
+
+#define L2_S_CACHE_MASK_generic (L2_B|L2_C)
+#define L2_S_CACHE_MASK_xscale (L2_B|L2_C|L2_XSCALE_T_TEX(TEX_XSCALE_X))
+
+#define L1_S_PROTO_generic (L1_TYPE_S | L1_S_IMP)
+#define L1_S_PROTO_xscale (L1_TYPE_S)
+
+#define L1_C_PROTO_generic (L1_TYPE_C | L1_C_IMP2)
+#define L1_C_PROTO_xscale (L1_TYPE_C)
+
+#define L2_L_PROTO (L2_TYPE_L)
+
+#define L2_S_PROTO_generic (L2_TYPE_S)
+#define L2_S_PROTO_xscale (L2_TYPE_XSCALE_XS)
+
+/*
+ * User-visible names for the ones that vary with MMU class.
+ */
+
+#if ARM_NMMUS > 1
+/* More than one MMU class configured; use variables. */
+#define L2_S_PROT_U pte_l2_s_prot_u
+#define L2_S_PROT_W pte_l2_s_prot_w
+#define L2_S_PROT_MASK pte_l2_s_prot_mask
+
+#define L1_S_CACHE_MASK pte_l1_s_cache_mask
+#define L2_L_CACHE_MASK pte_l2_l_cache_mask
+#define L2_S_CACHE_MASK pte_l2_s_cache_mask
+
+#define L1_S_PROTO pte_l1_s_proto
+#define L1_C_PROTO pte_l1_c_proto
+#define L2_S_PROTO pte_l2_s_proto
+
+#define pmap_copy_page(s, d) (*pmap_copy_page_func)((s), (d))
+#define pmap_zero_page(d) (*pmap_zero_page_func)((d))
+#elif (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0
+#define L2_S_PROT_U L2_S_PROT_U_generic
+#define L2_S_PROT_W L2_S_PROT_W_generic
+#define L2_S_PROT_MASK L2_S_PROT_MASK_generic
+
+#define L1_S_CACHE_MASK L1_S_CACHE_MASK_generic
+#define L2_L_CACHE_MASK L2_L_CACHE_MASK_generic
+#define L2_S_CACHE_MASK L2_S_CACHE_MASK_generic
+
+#define L1_S_PROTO L1_S_PROTO_generic
+#define L1_C_PROTO L1_C_PROTO_generic
+#define L2_S_PROTO L2_S_PROTO_generic
+
+#define pmap_copy_page(s, d) pmap_copy_page_generic((s), (d))
+#define pmap_zero_page(d) pmap_zero_page_generic((d))
+#elif ARM_MMU_XSCALE == 1
+#define L2_S_PROT_U L2_S_PROT_U_xscale
+#define L2_S_PROT_W L2_S_PROT_W_xscale
+#define L2_S_PROT_MASK L2_S_PROT_MASK_xscale
+
+#define L1_S_CACHE_MASK L1_S_CACHE_MASK_xscale
+#define L2_L_CACHE_MASK L2_L_CACHE_MASK_xscale
+#define L2_S_CACHE_MASK L2_S_CACHE_MASK_xscale
+
+#define L1_S_PROTO L1_S_PROTO_xscale
+#define L1_C_PROTO L1_C_PROTO_xscale
+#define L2_S_PROTO L2_S_PROTO_xscale
+
+#define pmap_copy_page(s, d) pmap_copy_page_xscale((s), (d))
+#define pmap_zero_page(d) pmap_zero_page_xscale((d))
+#endif /* ARM_NMMUS > 1 */
+
+/*
+ * These macros return various bits based on kernel/user and protection.
+ * Note that the compiler will usually fold these at compile time.
+ */
+#define L1_S_PROT(ku, pr) ((((ku) == PTE_USER) ? L1_S_PROT_U : 0) | \
+ (((pr) & VM_PROT_WRITE) ? L1_S_PROT_W : 0))
+
+#define L2_L_PROT(ku, pr) ((((ku) == PTE_USER) ? L2_L_PROT_U : 0) | \
+ (((pr) & VM_PROT_WRITE) ? L2_L_PROT_W : 0))
+
+#define L2_S_PROT(ku, pr) ((((ku) == PTE_USER) ? L2_S_PROT_U : 0) | \
+ (((pr) & VM_PROT_WRITE) ? L2_S_PROT_W : 0))
+
+/*
+ * Macros to test if a mapping is mappable with an L1 Section mapping
+ * or an L2 Large Page mapping.
+ */
+#define L1_S_MAPPABLE_P(va, pa, size) \
+ ((((va) | (pa)) & L1_S_OFFSET) == 0 && (size) >= L1_S_SIZE)
+
+#define L2_L_MAPPABLE_P(va, pa, size) \
+ ((((va) | (pa)) & L2_L_OFFSET) == 0 && (size) >= L2_L_SIZE)
+
+/*
+ * Hooks for the pool allocator.
+ */
+#define POOL_VTOPHYS(va) vtophys((vaddr_t) (va))
+
+#endif /* _KERNEL */
+
+#endif /* _ARM32_PMAP_H_ */
diff --git a/sys/arch/arm/include/proc.h b/sys/arch/arm/include/proc.h
new file mode 100644
index 00000000000..077559e4d8d
--- /dev/null
+++ b/sys/arch/arm/include/proc.h
@@ -0,0 +1,51 @@
+/* $OpenBSD: proc.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: proc.h,v 1.5 2003/03/01 04:36:39 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1994 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the RiscBSD team.
+ * 4. The name "RiscBSD" nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM32_PROC_H_
+#define _ARM32_PROC_H_
+
+/*
+ * Machine-dependent part of the proc structure for arm.
+ */
+
+struct trapframe;
+
+struct mdproc {
+ void (*md_syscall)(struct trapframe *, struct proc *, u_int32_t);
+ int pmc_enabled; /* bitfield of enabled counters */
+ void *pmc_state; /* port-specific pmc state */
+};
+
+#endif /* _ARM32_PROC_H_ */
diff --git a/sys/arch/arm/include/profile.h b/sys/arch/arm/include/profile.h
new file mode 100644
index 00000000000..a15f022bff5
--- /dev/null
+++ b/sys/arch/arm/include/profile.h
@@ -0,0 +1,107 @@
+/* $OpenBSD: profile.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: profile.h,v 1.5 2002/03/24 15:49:40 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 2001 Ben Harris
+ * Copyright (c) 1995-1996 Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _MCOUNT_DECL void _mcount
+
+/*
+ * Cannot implement mcount in C as GCC will trash the ip register when it
+ * pushes a trapframe. Pity we cannot insert assembly before the function
+ * prologue.
+ */
+
+#ifdef __ELF__
+#define MCOUNT_ASM_NAME "__mcount"
+#ifdef PIC
+#define PLTSYM "(PLT)"
+#endif
+#else
+#define MCOUNT_ASM_NAME "mcount"
+#endif
+
+#ifndef PLTSYM
+#define PLTSYM
+#endif
+
+#define MCOUNT \
+ __asm__(".text"); \
+ __asm__(".align 0"); \
+ __asm__(".type " MCOUNT_ASM_NAME ",%function"); \
+ __asm__(".global " MCOUNT_ASM_NAME); \
+ __asm__(MCOUNT_ASM_NAME ":"); \
+ /* \
+ * Preserve registers that are trashed during mcount \
+ */ \
+ __asm__("stmfd sp!, {r0-r3, ip, lr}"); \
+ /* Check what mode we're in. EQ => 32, NE => 26 */ \
+ __asm__("teq r0, r0"); \
+ __asm__("teq pc, r15"); \
+ /* \
+ * find the return address for mcount, \
+ * and the return address for mcount's caller. \
+ * \
+ * frompcindex = pc pushed by call into self. \
+ */ \
+ __asm__("moveq r0, ip"); \
+ __asm__("bicne r0, ip, #0xfc000003"); \
+ /* \
+ * selfpc = pc pushed by mcount call \
+ */ \
+ __asm__("moveq r1, lr"); \
+ __asm__("bicne r1, lr, #0xfc000003"); \
+ /* \
+ * Call the real mcount code \
+ */ \
+ __asm__("bl " __STRING(_mcount) PLTSYM); \
+ /* \
+ * Restore registers that were trashed during mcount \
+ */ \
+ __asm__("ldmfd sp!, {r0-r3, lr, pc}");
+
+#ifdef _KERNEL
+#ifdef __PROG26
+extern int int_off_save(void);
+extern void int_restore(int);
+#define MCOUNT_ENTER (s = int_off_save())
+#define MCOUNT_EXIT int_restore(s)
+#else
+#include <arm/cpufunc.h>
+/*
+ * splhigh() and splx() are heavyweight, and call mcount(). Therefore
+ * we disabled interrupts (IRQ, but not FIQ) directly on the CPU.
+ *
+ * We're lucky that the CPSR and 's' both happen to be 'int's.
+ */
+#define MCOUNT_ENTER s = __set_cpsr_c(0x0080, 0x0080); /* kill IRQ */
+#define MCOUNT_EXIT __set_cpsr_c(0xffffffff, s); /* restore old value */
+#endif /* !acorn26 */
+#endif /* _KERNEL */
diff --git a/sys/arch/arm/include/pte.h b/sys/arch/arm/include/pte.h
new file mode 100644
index 00000000000..f263fffc6cd
--- /dev/null
+++ b/sys/arch/arm/include/pte.h
@@ -0,0 +1,246 @@
+/* $OpenBSD: pte.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: pte.h,v 1.6 2003/04/18 11:08:28 scw Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_PTE_H_
+#define _ARM_PTE_H_
+
+/*
+ * The ARM MMU architecture was introduced with ARM v3 (previous ARM
+ * architecture versions used an optional off-CPU memory controller
+ * to perform address translation).
+ *
+ * The ARM MMU consists of a TLB and translation table walking logic.
+ * There is typically one TLB per memory interface (or, put another
+ * way, one TLB per software-visible cache).
+ *
+ * The ARM MMU is capable of mapping memory in the following chunks:
+ *
+ * 1M Sections (L1 table)
+ *
+ * 64K Large Pages (L2 table)
+ *
+ * 4K Small Pages (L2 table)
+ *
+ * 1K Tiny Pages (L2 table)
+ *
+ * There are two types of L2 tables: Coarse Tables and Fine Tables.
+ * Coarse Tables can map Large and Small Pages. Fine Tables can
+ * map Tiny Pages.
+ *
+ * Coarse Tables can define 4 Subpages within Large and Small pages.
+ * Subpages define different permissions for each Subpage within
+ * a Page.
+ *
+ * Coarse Tables are 1K in length. Fine tables are 4K in length.
+ *
+ * The Translation Table Base register holds the pointer to the
+ * L1 Table. The L1 Table is a 16K contiguous chunk of memory
+ * aligned to a 16K boundary. Each entry in the L1 Table maps
+ * 1M of virtual address space, either via a Section mapping or
+ * via an L2 Table.
+ *
+ * In addition, the Fast Context Switching Extension (FCSE) is available
+ * on some ARM v4 and ARM v5 processors. FCSE is a way of eliminating
+ * TLB/cache flushes on context switch by use of a smaller address space
+ * and a "process ID" that modifies the virtual address before being
+ * presented to the translation logic.
+ */
+
+#ifndef _LOCORE
+typedef uint32_t pd_entry_t; /* L1 table entry */
+typedef uint32_t pt_entry_t; /* L2 table entry */
+#endif /* _LOCORE */
+
+#define L1_S_SIZE 0x00100000 /* 1M */
+#define L1_S_OFFSET (L1_S_SIZE - 1)
+#define L1_S_FRAME (~L1_S_OFFSET)
+#define L1_S_SHIFT 20
+
+#define L2_L_SIZE 0x00010000 /* 64K */
+#define L2_L_OFFSET (L2_L_SIZE - 1)
+#define L2_L_FRAME (~L2_L_OFFSET)
+#define L2_L_SHIFT 16
+
+#define L2_S_SIZE 0x00001000 /* 4K */
+#define L2_S_OFFSET (L2_S_SIZE - 1)
+#define L2_S_FRAME (~L2_S_OFFSET)
+#define L2_S_SHIFT 12
+
+#define L2_T_SIZE 0x00000400 /* 1K */
+#define L2_T_OFFSET (L2_T_SIZE - 1)
+#define L2_T_FRAME (~L2_T_OFFSET)
+#define L2_T_SHIFT 10
+
+/*
+ * The NetBSD VM implementation only works on whole pages (4K),
+ * whereas the ARM MMU's Coarse tables are sized in terms of 1K
+ * (16K L1 table, 1K L2 table).
+ *
+ * So, we allocate L2 tables 4 at a time, thus yielding a 4K L2
+ * table.
+ */
+#define L1_ADDR_BITS 0xfff00000 /* L1 PTE address bits */
+#define L2_ADDR_BITS 0x000ff000 /* L2 PTE address bits */
+
+#define L1_TABLE_SIZE 0x4000 /* 16K */
+#define L2_TABLE_SIZE 0x1000 /* 4K */
+/*
+ * The new pmap deals with the 1KB coarse L2 tables by
+ * allocating them from a pool. Until every port has been converted,
+ * keep the old L2_TABLE_SIZE define lying around. Converted ports
+ * should use L2_TABLE_SIZE_REAL until then.
+ */
+#define L2_TABLE_SIZE_REAL 0x400 /* 1K */
+
+/*
+ * ARM L1 Descriptors
+ */
+
+#define L1_TYPE_INV 0x00 /* Invalid (fault) */
+#define L1_TYPE_C 0x01 /* Coarse L2 */
+#define L1_TYPE_S 0x02 /* Section */
+#define L1_TYPE_F 0x03 /* Fine L2 */
+#define L1_TYPE_MASK 0x03 /* mask of type bits */
+
+/* L1 Section Descriptor */
+#define L1_S_B 0x00000004 /* bufferable Section */
+#define L1_S_C 0x00000008 /* cacheable Section */
+#define L1_S_IMP 0x00000010 /* implementation defined */
+#define L1_S_DOM(x) ((x) << 5) /* domain */
+#define L1_S_DOM_MASK L1_S_DOM(0xf)
+#define L1_S_AP(x) ((x) << 10) /* access permissions */
+#define L1_S_ADDR_MASK 0xfff00000 /* phys address of section */
+
+#define L1_S_XSCALE_P 0x00000200 /* ECC enable for this section */
+#define L1_S_XSCALE_TEX(x) ((x) << 12) /* Type Extension */
+
+/* L1 Coarse Descriptor */
+#define L1_C_IMP0 0x00000004 /* implementation defined */
+#define L1_C_IMP1 0x00000008 /* implementation defined */
+#define L1_C_IMP2 0x00000010 /* implementation defined */
+#define L1_C_DOM(x) ((x) << 5) /* domain */
+#define L1_C_DOM_MASK L1_C_DOM(0xf)
+#define L1_C_ADDR_MASK 0xfffffc00 /* phys address of L2 Table */
+
+#define L1_C_XSCALE_P 0x00000200 /* ECC enable for this section */
+
+/* L1 Fine Descriptor */
+#define L1_F_IMP0 0x00000004 /* implementation defined */
+#define L1_F_IMP1 0x00000008 /* implementation defined */
+#define L1_F_IMP2 0x00000010 /* implementation defined */
+#define L1_F_DOM(x) ((x) << 5) /* domain */
+#define L1_F_DOM_MASK L1_F_DOM(0xf)
+#define L1_F_ADDR_MASK 0xfffff000 /* phys address of L2 Table */
+
+#define L1_F_XSCALE_P 0x00000200 /* ECC enable for this section */
+
+/*
+ * ARM L2 Descriptors
+ */
+
+#define L2_TYPE_INV 0x00 /* Invalid (fault) */
+#define L2_TYPE_L 0x01 /* Large Page */
+#define L2_TYPE_S 0x02 /* Small Page */
+#define L2_TYPE_T 0x03 /* Tiny Page */
+#define L2_TYPE_MASK 0x03 /* mask of type bits */
+
+ /*
+ * This L2 Descriptor type is available on XScale processors
+ * when using a Coarse L1 Descriptor. The Extended Small
+ * Descriptor has the same format as the XScale Tiny Descriptor,
+ * but describes a 4K page, rather than a 1K page.
+ */
+#define L2_TYPE_XSCALE_XS 0x03 /* XScale Extended Small Page */
+
+#define L2_B 0x00000004 /* Bufferable page */
+#define L2_C 0x00000008 /* Cacheable page */
+#define L2_AP0(x) ((x) << 4) /* access permissions (sp 0) */
+#define L2_AP1(x) ((x) << 6) /* access permissions (sp 1) */
+#define L2_AP2(x) ((x) << 8) /* access permissions (sp 2) */
+#define L2_AP3(x) ((x) << 10) /* access permissions (sp 3) */
+#define L2_AP(x) (L2_AP0(x) | L2_AP1(x) | L2_AP2(x) | L2_AP3(x))
+
+#define L2_XSCALE_L_TEX(x) ((x) << 12) /* Type Extension */
+#define L2_XSCALE_T_TEX(x) ((x) << 6) /* Type Extension */
+
+/*
+ * Access Permissions for L1 and L2 Descriptors.
+ */
+#define AP_W 0x01 /* writable */
+#define AP_U 0x02 /* user */
+
+/*
+ * Short-hand for common AP_* constants.
+ *
+ * Note: These values assume the S (System) bit is set and
+ * the R (ROM) bit is clear in CP15 register 1.
+ */
+#define AP_KR 0x00 /* kernel read */
+#define AP_KRW 0x01 /* kernel read/write */
+#define AP_KRWUR 0x02 /* kernel read/write usr read */
+#define AP_KRWURW 0x03 /* kernel read/write usr read/write */
+
+/*
+ * Domain Types for the Domain Access Control Register.
+ */
+#define DOMAIN_FAULT 0x00 /* no access */
+#define DOMAIN_CLIENT 0x01 /* client */
+#define DOMAIN_RESERVED 0x02 /* reserved */
+#define DOMAIN_MANAGER 0x03 /* manager */
+
+/*
+ * Type Extension bits for XScale processors.
+ *
+ * Behavior of C and B when X == 0:
+ *
+ * C B Cacheable Bufferable Write Policy Line Allocate Policy
+ * 0 0 N N - -
+ * 0 1 N Y - -
+ * 1 0 Y Y Write-through Read Allocate
+ * 1 1 Y Y Write-back Read Allocate
+ *
+ * Behavior of C and B when X == 1:
+ * C B Cacheable Bufferable Write Policy Line Allocate Policy
+ * 0 0 - - - - DO NOT USE
+ * 0 1 N Y - -
+ * 1 0 Mini-Data - - -
+ * 1 1 Y Y Write-back R/W Allocate
+ */
+#define TEX_XSCALE_X 0x01 /* X modifies C and B */
+
+#endif /* _ARM_PTE_H_ */
diff --git a/sys/arch/arm/include/ptrace.h b/sys/arch/arm/include/ptrace.h
new file mode 100644
index 00000000000..d0a556e41bc
--- /dev/null
+++ b/sys/arch/arm/include/ptrace.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: ptrace.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: ptrace.h,v 1.2 2001/10/19 00:18:20 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1995 Frank Lancaster
+ * Copyright (c) 1995 Tools GmbH
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * arm-dependent ptrace definitions
+ */
+#ifndef _KERNEL
+#define PT_STEP (PT_FIRSTMACH + 0) /* Not implemented */
+#endif
+#define PT_GETREGS (PT_FIRSTMACH + 1)
+#define PT_SETREGS (PT_FIRSTMACH + 2)
+#define PT_GETFPREGS (PT_FIRSTMACH + 3)
+#define PT_SETFPREGS (PT_FIRSTMACH + 4)
diff --git a/sys/arch/arm/include/reg.h b/sys/arch/arm/include/reg.h
new file mode 100644
index 00000000000..28c1b43b26e
--- /dev/null
+++ b/sys/arch/arm/include/reg.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: reg.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: reg.h,v 1.1 2001/02/11 14:51:55 bjh21 Exp $ */
+
+/*
+ * Copyright (C) 1994, 1995 Frank Lancaster
+ * Copyright (C) 1994, 1995 TooLs GmbH.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @(#)reg.h 5.5 (Berkeley) 1/18/91
+ */
+
+#ifndef _ARM32_REG_H_
+#define _ARM32_REG_H_
+
+#include <machine/fp.h>
+
+struct reg {
+ unsigned int r[13];
+ unsigned int r_sp;
+ unsigned int r_lr;
+ unsigned int r_pc;
+ unsigned int r_cpsr;
+};
+
+struct fpreg {
+ unsigned int fpr_fpsr;
+ fp_reg_t fpr[8];
+};
+
+#endif /* !_ARM32_REG_H_ */
diff --git a/sys/arch/arm/include/reloc.h b/sys/arch/arm/include/reloc.h
new file mode 100644
index 00000000000..f53ab524f26
--- /dev/null
+++ b/sys/arch/arm/include/reloc.h
@@ -0,0 +1,53 @@
+/* Processor specific relocation types */
+
+#define R_ARM_NONE 0
+#define R_ARM_PC24 1
+#define R_ARM_ABS32 2
+#define R_ARM_REL32 3
+#define R_ARM_PC13 4
+#define R_ARM_ABS16 5
+#define R_ARM_ABS12 6
+#define R_ARM_THM_ABS5 7
+#define R_ARM_ABS8 8
+#define R_ARM_SBREL32 9
+#define R_ARM_THM_PC22 10
+#define R_ARM_THM_PC8 11
+#define R_ARM_AMP_VCALL9 12
+#define R_ARM_SWI24 13
+#define R_ARM_THM_SWI8 14
+#define R_ARM_XPC25 15
+#define R_ARM_THM_XPC22 16
+
+/* 17-31 are reserved for ARM Linux. */
+#define R_ARM_COPY 20
+#define R_ARM_GLOB_DAT 21
+#define R_ARM_JUMP_SLOT 22
+#define R_ARM_RELATIVE 23
+#define R_ARM_GOTOFF 24
+#define R_ARM_GOTPC 25
+#define R_ARM_GOT32 26
+#define R_ARM_PLT32 27
+
+#define R_ARM_ALU_PCREL_7_0 32
+#define R_ARM_ALU_PCREL_15_8 33
+#define R_ARM_ALU_PCREL_23_15 34
+#define R_ARM_ALU_SBREL_11_0 35
+#define R_ARM_ALU_SBREL_19_12 36
+#define R_ARM_ALU_SBREL_27_20 37
+
+/* 96-111 are reserved to G++. */
+#define R_ARM_GNU_VTENTRY 100
+#define R_ARM_GNU_VTINHERIT 101
+#define R_ARM_THM_PC11 102
+#define R_ARM_THM_PC9 103
+
+/* 112-127 are reserved for private experiments. */
+
+#define R_ARM_RXPC25 249
+#define R_ARM_RSBREL32 250
+#define R_ARM_THM_RPC22 251
+#define R_ARM_RREL32 252
+#define R_ARM_RABS32 253
+#define R_ARM_RPC24 254
+#define R_ARM_RBASE 255
+
diff --git a/sys/arch/arm/include/rtc.h b/sys/arch/arm/include/rtc.h
new file mode 100644
index 00000000000..6c6a1666d52
--- /dev/null
+++ b/sys/arch/arm/include/rtc.h
@@ -0,0 +1,84 @@
+/* $OpenBSD: rtc.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: rtc.h,v 1.1 2001/02/23 21:23:50 reinoud Exp $ */
+
+/*
+ * Copyright (c) 1994 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * rtc.h
+ *
+ * Header file for RTC / CMOS stuff
+ *
+ * Created : 13/10/94
+ * Updated : 15/07/2000
+ *
+ * Based of kate/display/iiccontrol.c
+ */
+
+/*
+ * IIC addresses for RTC chip
+ * Two PCF8583 chips are supported on the IIC bus
+ */
+
+#define IIC_PCF8583_MASK 0xfc
+#define IIC_PCF8583_ADDR 0xa0
+
+#define RTC_Write (IIC_PCF8583_ADDR | IIC_WRITE)
+#define RTC_Read (IIC_PCF8583_ADDR | IIC_READ)
+
+typedef struct {
+ u_char rtc_micro;
+ u_char rtc_centi;
+ u_char rtc_sec;
+ u_char rtc_min;
+ u_char rtc_hour;
+ u_char rtc_day;
+ u_char rtc_mon;
+ u_char rtc_year;
+ u_char rtc_cen;
+} rtc_t;
+
+#define RTC_ADDR_CHECKSUM 0x3f
+#define RTC_ADDR_BOOTOPTS 0x90
+#define RTC_ADDR_REBOOTCNT 0x91
+#define RTC_ADDR_YEAR 0xc0
+#define RTC_ADDR_CENT 0xc1
+
+#ifdef _KERNEL
+int cmos_read __P((int));
+int cmos_write __P((int, int));
+#endif /* _KERNEL */
+
+/* End of rtc.h */
diff --git a/sys/arch/arm/include/setjmp.h b/sys/arch/arm/include/setjmp.h
new file mode 100644
index 00000000000..f20cab2e929
--- /dev/null
+++ b/sys/arch/arm/include/setjmp.h
@@ -0,0 +1,87 @@
+/* $OpenBSD: setjmp.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: setjmp.h,v 1.2 2001/08/25 14:45:59 bjh21 Exp $ */
+
+/*
+ * machine/setjmp.h: machine dependent setjmp-related information.
+ */
+
+#ifdef __ELF__
+#define _JBLEN 64 /* size, in longs, of a jmp_buf */
+#else
+#define _JBLEN 29 /* size, in longs, of a jmp_buf */
+#endif
+
+/*
+ * NOTE: The internal structure of a jmp_buf is *PRIVATE*
+ * This information is provided as there is software
+ * that fiddles with this with obtain the stack pointer
+ * (yes really ! and its commercial !).
+ *
+ * Description of the setjmp buffer
+ *
+ * word 0 magic number (dependant on creator)
+ * 1 - 3 f4 fp register 4
+ * 4 - 6 f5 fp register 5
+ * 7 - 9 f6 fp register 6
+ * 10 - 12 f7 fp register 7
+ * 13 fpsr fp status register
+ * 14 r4 register 4
+ * 15 r5 register 5
+ * 16 r6 register 6
+ * 17 r7 register 7
+ * 18 r8 register 8
+ * 19 r9 register 9
+ * 20 r10 register 10 (sl)
+ * 21 r11 register 11 (fp)
+ * 22 r12 register 12 (ip)
+ * 23 r13 register 13 (sp)
+ * 24 r14 register 14 (lr)
+ * 25 signal mask (dependant on magic)
+ * 26 (con't)
+ * 27 (con't)
+ * 28 (con't)
+ *
+ * The magic number number identifies the jmp_buf and
+ * how the buffer was created as well as providing
+ * a sanity check
+ *
+ * A side note I should mention - Please do not tamper
+ * with the floating point fields. While they are
+ * always saved and restored at the moment this cannot
+ * be garenteed especially if the compiler happens
+ * to be generating soft-float code so no fp
+ * registers will be used.
+ *
+ * Whilst this can be seen an encouraging people to
+ * use the setjmp buffer in this way I think that it
+ * is for the best then if changes occur compiles will
+ * break rather than just having new builds falling over
+ * mysteriously.
+ */
+
+#define _JB_MAGIC__SETJMP 0x4278f500
+#define _JB_MAGIC_SETJMP 0x4278f501
+
+/* Valid for all jmp_buf's */
+
+#define _JB_MAGIC 0
+#define _JB_REG_F4 1
+#define _JB_REG_F5 4
+#define _JB_REG_F6 7
+#define _JB_REG_F7 10
+#define _JB_REG_FPSR 13
+#define _JB_REG_R4 14
+#define _JB_REG_R5 15
+#define _JB_REG_R6 16
+#define _JB_REG_R7 17
+#define _JB_REG_R8 18
+#define _JB_REG_R9 19
+#define _JB_REG_R10 20
+#define _JB_REG_R11 21
+#define _JB_REG_R12 22
+#define _JB_REG_R13 23
+#define _JB_REG_R14 24
+
+/* Only valid with the _JB_MAGIC_SETJMP magic */
+
+#define _JB_SIGMASK 25
diff --git a/sys/arch/arm/include/signal.h b/sys/arch/arm/include/signal.h
new file mode 100644
index 00000000000..d0d5122166d
--- /dev/null
+++ b/sys/arch/arm/include/signal.h
@@ -0,0 +1,134 @@
+/* $OpenBSD: signal.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: signal.h,v 1.5 2003/10/18 17:57:21 briggs Exp $ */
+
+/*
+ * Copyright (c) 1994-1996 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * signal.h
+ *
+ * Architecture dependant signal types and structures
+ *
+ * Created : 30/09/94
+ */
+
+#ifndef _ARM32_SIGNAL_H_
+#define _ARM32_SIGNAL_H_
+
+#ifndef _LOCORE
+typedef int sig_atomic_t;
+#endif
+
+#define __HAVE_SIGINFO
+
+
+#ifndef _LOCORE
+/*
+ * Information pushed on stack when a signal is delivered.
+ * This is used by the kernel to restore state following
+ * execution of the signal handler. It is also made available
+ * to the handler to allow it to restore state properly if
+ * a non-standard exit is performed.
+ */
+
+struct sigcontext {
+ int sc_onstack; /* sigstack state to restore */
+ int sc_mask; /* signal mask to restore (old style) */
+
+ unsigned int sc_spsr;
+ unsigned int sc_r0;
+ unsigned int sc_r1;
+ unsigned int sc_r2;
+ unsigned int sc_r3;
+ unsigned int sc_r4;
+ unsigned int sc_r5;
+ unsigned int sc_r6;
+ unsigned int sc_r7;
+ unsigned int sc_r8;
+ unsigned int sc_r9;
+ unsigned int sc_r10;
+ unsigned int sc_r11;
+ unsigned int sc_r12;
+ unsigned int sc_usr_sp;
+ unsigned int sc_usr_lr;
+ unsigned int sc_svc_lr;
+ unsigned int sc_pc;
+
+#if 0
+ sigset_t sc_mask; /* signal mask to restore (new style) */
+#endif
+};
+
+#endif /* !_LOCORE */
+
+/* Signals codes */
+
+/*
+ * SIGFPE codes
+ *
+ * see ieeefp.h for definition of FP exception codes
+ */
+
+#define SIG_CODE_FPE_CODE_MASK 0x00000f00 /* Mask for exception code */
+#define SIG_CODE_FPE_CODE_SHIFT 8 /* Shift for exception code */
+#define SIG_CODE_FPE_TYPE_MASK 0x000000ff /* Mask for specific code */
+
+/*
+ * SIGILL codes
+ *
+ * the signal code is the instruction that raised the signal
+ */
+
+/*
+ * SIGBUS and SIGSEGV codes
+ *
+ * The signal code is combination of the fault address and the fault code.
+ *
+ * The fault code is the coproc #15 fault status code
+ *
+ * The exception to this is a SIGBUS or SIGSEGV from a prefetch abort.
+ * In this case the fault status code is not valid so the TYPE_MASK
+ * should be treated as undefined (in practice it is the bottom 4 bits
+ * of the fault address).
+ */
+
+#define SIG_CODE_BUS_ADDR_MASK 0xfffffff0
+#define SIG_CODE_BUS_TYPE_MASK 0x0000000f
+#define SIG_CODE_SEGV_ADDR_MASK SIG_CODE_BUS_ADDR_MASK
+#define SIG_CODE_SEGV_TYPE_MASK SIG_CODE_BUS_TYPE_MASK
+
+#endif /* !_ARM_SIGNAL_H_ */
+
+/* End of signal.h */
diff --git a/sys/arch/arm/include/softintr.h b/sys/arch/arm/include/softintr.h
new file mode 100644
index 00000000000..fdd618dc841
--- /dev/null
+++ b/sys/arch/arm/include/softintr.h
@@ -0,0 +1,106 @@
+/* $OpenBSD: softintr.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: softintr.h,v 1.1 2002/01/29 22:54:14 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_SOFTINTR_H_
+#define _ARM_SOFTINTR_H_
+
+#ifdef _KERNEL
+
+/*
+ * Generic software interrupt support for all ARM platforms.
+ *
+ * To use this code, include <arm/softintr.h> from your platform's
+ * <machine/intr.h>.
+ */
+
+#define SI_SOFT 0 /* for IPL_SOFT */
+#define SI_SOFTCLOCK 1 /* for IPL_SOFTCLOCK */
+#define SI_SOFTNET 2 /* for IPL_SOFTNET */
+#define SI_SOFTSERIAL 3 /* for IPL_SOFTSERIAL */
+
+#define SI_NQUEUES 4
+
+#define SI_QUEUENAMES { \
+ "generic", \
+ "clock", \
+ "net", \
+ "serial", \
+}
+
+struct soft_intrhand {
+ TAILQ_ENTRY(soft_intrhand) sih_list;
+ void (*sih_func)(void *);
+ void *sih_arg;
+ struct soft_intrq *sih_siq;
+ int sih_pending;
+};
+
+struct soft_intrq {
+ TAILQ_HEAD(, soft_intrhand) siq_list;
+ struct evcnt siq_evcnt;
+ int siq_si;
+};
+
+void *softintr_establish(int, void (*)(void *), void *);
+void softintr_disestablish(void *);
+void softintr_init(void);
+void softintr_dispatch(int);
+
+#define softintr_schedule(arg) \
+do { \
+ struct soft_intrhand *__sih = (arg); \
+ struct soft_intrq *__siq = __sih->sih_siq; \
+ int __s; \
+ \
+ __s = splhigh(); \
+ if (__sih->sih_pending == 0) { \
+ TAILQ_INSERT_TAIL(&__siq->siq_list, __sih, sih_list); \
+ __sih->sih_pending = 1; \
+ _setsoftintr(__siq->siq_si); \
+ } \
+ splx(__s); \
+} while (/*CONSTCOND*/0)
+
+/* XXX For legacy software interrupts. */
+extern struct soft_intrhand *softnet_intrhand;
+
+#define setsoftnet() softintr_schedule(softnet_intrhand)
+
+#endif /* _KERNEL */
+
+#endif /* _ARM_SOFTINTR_H_ */
diff --git a/sys/arch/arm/include/spinlock.h b/sys/arch/arm/include/spinlock.h
new file mode 100644
index 00000000000..5b68222836d
--- /dev/null
+++ b/sys/arch/arm/include/spinlock.h
@@ -0,0 +1,10 @@
+/* $OpenBSD: spinlock.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+
+#ifndef _ARM_SPINLOCK_H_
+#define _ARM_SPINLOCK_H_
+
+#define _SPINLOCK_UNLOCKED (0)
+#define _SPINLOCK_LOCKED (1)
+typedef int _spinlock_lock_t;
+
+#endif
diff --git a/sys/arch/arm/include/swi.h b/sys/arch/arm/include/swi.h
new file mode 100644
index 00000000000..19a0145ab92
--- /dev/null
+++ b/sys/arch/arm/include/swi.h
@@ -0,0 +1,23 @@
+/* $OpenBSD: swi.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: swi.h,v 1.1 2002/01/13 15:03:06 bjh21 Exp $ */
+
+/*
+ * This file is in the Public Domain.
+ * Ben Harris, 2002.
+ */
+
+#ifndef _ARM_SWI_H_
+#define _ARM_SWI_H_
+
+#define SWI_OS_MASK 0xf00000
+#define SWI_OS_RISCOS 0x000000
+#define SWI_OS_RISCIX 0x800000
+#define SWI_OS_LINUX 0x900000
+#define SWI_OS_NETBSD 0xa00000
+#define SWI_OS_ARM 0xf00000
+
+#define SWI_IMB 0xf00000
+#define SWI_IMBrange 0xf00001
+
+#endif
+
diff --git a/sys/arch/arm/include/sysarch.h b/sys/arch/arm/include/sysarch.h
new file mode 100644
index 00000000000..b379abbecd3
--- /dev/null
+++ b/sys/arch/arm/include/sysarch.h
@@ -0,0 +1,61 @@
+/* $OpenBSD: sysarch.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: sysarch.h,v 1.4 2002/03/30 06:23:39 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1996-1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _ARM_SYSARCH_H_
+#define _ARM_SYSARCH_H_
+
+#include <sys/cdefs.h>
+
+/*
+ * Architecture specific syscalls (arm)
+ */
+
+#define ARM_SYNC_ICACHE 0
+#define ARM_DRAIN_WRITEBUF 1
+
+struct arm_sync_icache_args {
+ u_int32_t addr; /* Virtual start address */
+ size_t len; /* Region size */
+};
+
+#ifndef _KERNEL
+__BEGIN_DECLS
+int arm_sync_icache __P((u_int addr, int len));
+int arm_drain_writebuf __P((void));
+int sysarch __P((int, void *));
+__END_DECLS
+#endif
+
+#endif /* !_ARM_SYSARCH_H_ */
diff --git a/sys/arch/arm/include/trap.h b/sys/arch/arm/include/trap.h
new file mode 100644
index 00000000000..d6346a42ef4
--- /dev/null
+++ b/sys/arch/arm/include/trap.h
@@ -0,0 +1,71 @@
+/* $OpenBSD: trap.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: trap.h,v 1.4 2003/04/28 01:54:50 briggs Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * trap.h
+ *
+ * Various trap definitions
+ */
+
+/*
+ * Instructions used for breakpoints.
+ *
+ * These are undefined instructions.
+ * Technically the userspace breakpoint could be a SWI but we want to
+ * keep this the same as IPKDB which needs an undefined instruction as
+ * a break point.
+ *
+ * Ideally ARM would define several standard instruction sequences for
+ * use as breakpoints.
+ *
+ * The BKPT instruction isn't much use to us, since its behaviour is
+ * unpredictable on ARMv3 and lower.
+ *
+ * The ARM ARM says that for maximum compatibility, we should use undefined
+ * instructions that look like 0x.7f...f. .
+ */
+
+#define GDB_BREAKPOINT 0xe6000011 /* Used by GDB 4.x */
+#define IPKDB_BREAKPOINT 0xe6000010 /* Used by IPKDB */
+#define GDB5_BREAKPOINT 0xe7ffdefe /* Used by GDB 5.0 */
+#define KERNEL_BREAKPOINT 0xe7ffffff /* Used by DDB */
+
+#define KBPT_ASM ".word 0xe7ffdefe"
+
+#define USER_BREAKPOINT GDB_BREAKPOINT
+
+#define T_FAULT 1
+
+/* End of trap.h */
diff --git a/sys/arch/arm/include/types.h b/sys/arch/arm/include/types.h
new file mode 100644
index 00000000000..d14f21478f0
--- /dev/null
+++ b/sys/arch/arm/include/types.h
@@ -0,0 +1,119 @@
+/* $OpenBSD: types.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: types.h,v 1.4 2002/02/28 03:17:25 simonb Exp $ */
+
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)types.h 7.5 (Berkeley) 3/9/91
+ */
+
+#ifndef _ARM_TYPES_H_
+#define _ARM_TYPES_H_
+
+/* OpenBSD only supports arm32 */
+#ifdef _KERNEL
+#define __PROG32 /* indicate 32-bit mode */
+#endif
+
+#include <sys/cdefs.h>
+
+#if defined(_KERNEL)
+typedef struct label_t { /* Used by setjmp & longjmp */
+ int val[11];
+} label_t;
+#endif
+
+/* NB: This should probably be if defined(_KERNEL) */
+#if !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)
+typedef unsigned long vm_offset_t;
+typedef unsigned long vm_size_t;
+
+typedef vm_offset_t paddr_t;
+typedef vm_size_t psize_t;
+typedef vm_offset_t vaddr_t;
+typedef vm_size_t vsize_t;
+#endif
+
+#define __HAVE_MINIMAL_EMUL
+
+/*
+ * Basic integral types. Omit the typedef if
+ * not possible for a machine/compiler combination.
+ */
+#define __BIT_TYPES_DEFINED__
+typedef __signed char int8_t;
+typedef unsigned char u_int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short u_int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int u_int32_t;
+typedef unsigned int uint32_t;
+/* LONGLONG */
+typedef long long int64_t;
+/* LONGLONG */
+typedef unsigned long long u_int64_t;
+/* LONGLONG */
+typedef unsigned long long uint64_t;
+
+typedef int32_t register_t;
+
+/*
+ * 7.18.1 Integer types
+ */
+
+/* 7.18.1.1 Exact-width integer types */
+
+typedef __signed char __int8_t;
+typedef unsigned char __uint8_t;
+typedef short int __int16_t;
+typedef unsigned short int __uint16_t;
+typedef int __int32_t;
+typedef unsigned int __uint32_t;
+#ifdef __COMPILER_INT64__
+typedef __COMPILER_INT64__ __int64_t;
+typedef __COMPILER_UINT64__ __uint64_t;
+#else
+/* LONGLONG */
+typedef long long int __int64_t;
+/* LONGLONG */
+typedef unsigned long long int __uint64_t;
+#endif
+
+
+/* 7.18.1.4 Integer types capable of holding object pointers */
+
+typedef long int __intptr_t;
+typedef unsigned long int __uintptr_t;
+
+#endif /* _ARM_TYPES_H_ */
diff --git a/sys/arch/arm/include/undefined.h b/sys/arch/arm/include/undefined.h
new file mode 100644
index 00000000000..dfb22764ed7
--- /dev/null
+++ b/sys/arch/arm/include/undefined.h
@@ -0,0 +1,89 @@
+/* $OpenBSD: undefined.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: undefined.h,v 1.4 2001/12/20 01:20:23 thorpej Exp $ */
+
+/*
+ * Copyright (c) 1995-1996 Mark Brinicombe.
+ * Copyright (c) 1995 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * undefined.h
+ *
+ * Undefined instruction types, symbols and prototypes
+ *
+ * Created : 08/02/95
+ */
+
+
+#ifndef _ARM_UNDEFINED_H_
+#define _ARM_UNDEFINED_H_
+#ifdef _KERNEL
+
+#include <sys/queue.h>
+
+typedef int (*undef_handler_t) __P((unsigned int, unsigned int, trapframe_t *, int));
+
+#define FP_COPROC 1
+#define FP_COPROC2 2
+#define MAX_COPROCS 16
+
+/* Prototypes for undefined.c */
+
+void *install_coproc_handler __P((int, undef_handler_t));
+void remove_coproc_handler __P((void *));
+void undefined_init __P((void));
+
+/*
+ * XXX Stuff below here is for use before malloc() is available. Most code
+ * shouldn't use it.
+ */
+
+struct undefined_handler {
+ LIST_ENTRY(undefined_handler) uh_link;
+ undef_handler_t uh_handler;
+};
+
+/*
+ * Handlers installed using install_coproc_handler_static shouldn't be
+ * removed.
+ */
+void install_coproc_handler_static __P((int, struct undefined_handler *));
+
+/* Calls up to undefined.c from trap handlers */
+void undefinedinstruction(struct trapframe *);
+
+#endif
+
+/* End of undefined.h */
+
+#endif /* _ARM_UNDEFINED_H_ */
diff --git a/sys/arch/arm/include/vmparam.h b/sys/arch/arm/include/vmparam.h
new file mode 100644
index 00000000000..3a6aebc4b26
--- /dev/null
+++ b/sys/arch/arm/include/vmparam.h
@@ -0,0 +1,152 @@
+/* $OpenBSD: vmparam.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: vmparam.h,v 1.18 2003/05/21 18:04:44 thorpej Exp $ */
+
+/*
+ * Copyright (c) 2001, 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ARM_ARM_VMPARAM_H_
+#define _ARM_ARM_VMPARAM_H_
+
+#ifdef _KERNEL
+
+/*
+ * Virtual Memory parameters common to all arm32 platforms.
+ */
+
+#include <sys/lock.h> /* struct simplelock */
+#include <arm/pte.h> /* pt_entry_t */
+#endif /* _KERNEL */
+
+#define USRTEXT VM_MIN_ADDRESS
+#define USRSTACK VM_MAXUSER_ADDRESS
+#define KERNBASE VM_MAXUSER_ADDRESS
+
+/*
+ * The time for a process to be blocked before being very swappable.
+ * This is a number of seconds which the system takes as being a non-trivial
+ * amount of real time. You probably shouldn't change this;
+ * it is used in subtle ways (fractions and multiples of it are, that is, like
+ * half of a ``long time'', almost a long time, etc.)
+ * It is related to human patience and other factors which don't really
+ * change over time.
+ */
+#define MAXSLP 20
+
+/*
+ * Note that MAXTSIZ can't be larger than 32M, otherwise the compiler
+ * would have to be changed to not generate "bl" instructions.
+ */
+#define MAXTSIZ (16*1024*1024) /* max text size */
+#ifndef DFLDSIZ
+#define DFLDSIZ (128*1024*1024) /* initial data size limit */
+#endif
+#ifndef MAXDSIZ
+#define MAXDSIZ (512*1024*1024) /* max data size */
+#endif
+#ifndef DFLSSIZ
+#define DFLSSIZ (2*1024*1024) /* initial stack size limit */
+#endif
+#ifndef MAXSSIZ
+#define MAXSSIZ (8*1024*1024) /* max stack size */
+#endif
+
+/*
+ * Size of SysV shared memory map
+ */
+#ifndef SHMMAXPGS
+#define SHMMAXPGS 1024
+#endif
+
+/*
+ * While the ARM architecture defines Section mappings, large pages,
+ * and small pages, the standard page size is (and will always be) 4K.
+ */
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1 << PAGE_SHIFT) /* bytes/page */
+#define PAGE_MASK (PAGE_SIZE - 1)
+
+/*
+ * Mach derived constants
+ */
+#define VM_MIN_ADDRESS ((vaddr_t) 0x00001000)
+#define VM_MAXUSER_ADDRESS ((vaddr_t) ARM_KERNEL_BASE)
+#define VM_MAX_ADDRESS VM_MAXUSER_ADDRESS
+
+#define VM_MIN_KERNEL_ADDRESS ((vaddr_t) ARM_KERNEL_BASE)
+#define VM_MAX_KERNEL_ADDRESS ((vaddr_t) 0xffffffff)
+
+#ifdef _KERNEL
+
+/* XXX max. amount of KVM to be used by buffers. */
+#ifndef VM_MAX_KERNEL_BUF
+extern vaddr_t virtual_avail;
+extern vaddr_t virtual_end;
+
+#define VM_MAX_KERNEL_BUF \
+ ((virtual_end - virtual_avail) * 4 / 10)
+#endif
+
+/*
+ * pmap-specific data store in the vm_page structure.
+ */
+#define __HAVE_VM_PAGE_MD
+struct vm_page_md {
+ struct pv_entry *pvh_list; /* pv_entry list */
+ struct simplelock pvh_slock; /* lock on this head */
+ int pvh_attrs; /* page attributes */
+ u_int uro_mappings;
+ u_int urw_mappings;
+ union {
+ u_short s_mappings[2]; /* Assume kernel count <= 65535 */
+ u_int i_mappings;
+ } k_u;
+#define kro_mappings k_u.s_mappings[0]
+#define krw_mappings k_u.s_mappings[1]
+#define k_mappings k_u.i_mappings
+};
+
+#define VM_MDPAGE_INIT(pg) \
+do { \
+ (pg)->mdpage.pvh_list = NULL; \
+ simple_lock_init(&(pg)->mdpage.pvh_slock); \
+ (pg)->mdpage.pvh_attrs = 0; \
+ (pg)->mdpage.uro_mappings = 0; \
+ (pg)->mdpage.urw_mappings = 0; \
+ (pg)->mdpage.k_mappings = 0; \
+} while (/*CONSTCOND*/0)
+
+#endif /* _KERNEL */
+
+#endif /* _ARM_ARM_VMPARAM_H_ */
diff --git a/sys/arch/arm/mainbus/cpu_mainbus.c b/sys/arch/arm/mainbus/cpu_mainbus.c
new file mode 100644
index 00000000000..63de2094b39
--- /dev/null
+++ b/sys/arch/arm/mainbus/cpu_mainbus.c
@@ -0,0 +1,102 @@
+/* $OpenBSD: cpu_mainbus.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: cpu_mainbus.c,v 1.3 2002/01/05 22:41:48 chris Exp $ */
+
+/*
+ * Copyright (c) 1995 Mark Brinicombe.
+ * Copyright (c) 1995 Brini.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * cpu.c
+ *
+ * Probing and configuration for the master cpu
+ *
+ * Created : 10/10/95
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/proc.h>
+#if 0
+#include <uvm/uvm_extern.h>
+#include <machine/io.h>
+#include <machine/conf.h>
+#endif
+#include <machine/cpu.h>
+#if 0
+#include <arm/cpus.h>
+#include <arm/undefined.h>
+#endif
+#include <arm/mainbus/mainbus.h>
+
+/*
+ * Prototypes
+ */
+static int cpu_mainbus_match (struct device *, void *, void *);
+static void cpu_mainbus_attach (struct device *, struct device *, void *);
+
+/*
+ * int cpumatch(struct device *parent, struct cfdata *cf, void *aux)
+ */
+
+static int
+cpu_mainbus_match(struct device *parent, void *vcf, void *aux)
+{
+ struct mainbus_attach_args *ma = aux;
+ struct cfdata *cf = (struct cfdata *)vcf;
+
+ return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0);
+}
+
+/*
+ * void cpusattach(struct device *parent, struct device *dev, void *aux)
+ *
+ * Attach the main cpu
+ */
+
+static void
+cpu_mainbus_attach(parent, self, aux)
+ struct device *parent;
+ struct device *self;
+ void *aux;
+{
+ cpu_attach(self);
+}
+
+struct cfattach cpu_mainbus_ca = {
+ sizeof(struct device), cpu_mainbus_match, cpu_mainbus_attach
+};
+
+struct cfdriver cpu_cd = {
+ NULL, "cpu", DV_DULL
+};
diff --git a/sys/arch/arm/mainbus/mainbus.c b/sys/arch/arm/mainbus/mainbus.c
new file mode 100644
index 00000000000..a472197631d
--- /dev/null
+++ b/sys/arch/arm/mainbus/mainbus.c
@@ -0,0 +1,129 @@
+/* $OpenBSD: mainbus.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: mainbus.c,v 1.3 2001/06/13 17:52:43 nathanw Exp $ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * mainbus.c
+ *
+ * mainbus configuration
+ *
+ * Created : 15/12/94
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+
+#if defined(arm32) /* XXX */
+#include <machine/io.h>
+#endif
+#include <machine/bus.h>
+#include <arm/mainbus/mainbus.h>
+/*
+#include "locators.h"
+*/
+
+/*
+ * mainbus is a root device so we a bus space tag to pass to children
+ *
+ * The tag is provided by mainbus_io.c and mainbus_io_asm.S
+ */
+
+extern struct bus_space mainbus_bs_tag;
+
+/* Prototypes for functions provided */
+
+int mainbusmatch __P((struct device *, void *, void *));
+void mainbusattach __P((struct device *, struct device *, void *));
+int mainbusprint __P((void *aux, const char *mainbus));
+int mainbussearch __P((struct device *, struct cfdata *, void *));
+
+/* attach and device structures for the device */
+
+struct cfattach mainbus_ca = {
+ sizeof(struct device), mainbusmatch, mainbusattach
+};
+
+struct cfdriver mainbus_cd = {
+ NULL, "mainbus", DV_DULL
+};
+
+/*
+ * int mainbusmatch(struct device *parent, struct cfdata *cf, void *aux)
+ *
+ * Always match for unit 0
+ */
+
+int
+mainbusmatch(struct device *parent, void *cf, void *aux)
+{
+ return (1);
+}
+
+/*
+ * void mainbusattach(struct device *parent, struct device *self, void *aux)
+ *
+ * probe and attach all children
+ */
+
+void
+mainbusattach(struct device *parent, struct device *self, void *aux)
+{
+ struct mainbus_attach_args ma;
+ printf("\n");
+
+ ma.ma_iot = &mainbus_bs_tag;
+ ma.ma_name = "cpu";
+ config_found(self, &ma, mainbusprint); /* XXX */
+ ma.ma_iot = &mainbus_bs_tag;
+ ma.ma_name = "footbridge";
+ config_found(self, &ma, mainbusprint); /* XXX */
+}
+
+/*
+ * int mainbusprint(void *aux, const char *mainbus)
+ *
+ * print routine used during config of children
+ */
+
+int
+mainbusprint(void *aux, const char *mainbus)
+{
+/* XXXX print flags */
+ return (QUIET);
+}
diff --git a/sys/arch/arm/mainbus/mainbus.h b/sys/arch/arm/mainbus/mainbus.h
new file mode 100644
index 00000000000..11fa23ecba8
--- /dev/null
+++ b/sys/arch/arm/mainbus/mainbus.h
@@ -0,0 +1,61 @@
+/* $OpenBSD: mainbus.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: mainbus.h,v 1.1 2001/02/24 19:38:02 reinoud Exp $ */
+
+/*
+ * Copyright (c) 1994,1995 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * mainbus.h
+ *
+ * mainbus configuration
+ *
+ * Created : 15/12/94
+ */
+
+#include <machine/bus.h>
+
+/*
+ * mainbus driver attach arguments
+ */
+
+struct mainbus_attach_args {
+ u_int ma_iobase; /* base i/o address */
+ int ma_iosize; /* span of ports used */
+ int ma_irq; /* interrupt request */
+ int ma_drq; /* DMA request */
+ void *ma_aux; /* driver specific */
+ bus_space_tag_t ma_iot; /* bus space tag */
+ char *ma_name;
+};
+
+/* End of mainbus.h */
diff --git a/sys/arch/arm/mainbus/mainbus_io.c b/sys/arch/arm/mainbus/mainbus_io.c
new file mode 100644
index 00000000000..4a6235b7804
--- /dev/null
+++ b/sys/arch/arm/mainbus/mainbus_io.c
@@ -0,0 +1,248 @@
+/* $OpenBSD: mainbus_io.c,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: mainbus_io.c,v 1.14 2003/12/06 22:05:33 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * bus_space I/O functions for mainbus
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+
+#include <uvm/uvm.h>
+
+#include <machine/bus.h>
+#include <machine/pmap.h>
+
+/* Proto types for all the bus_space structure functions */
+
+bs_protos(mainbus);
+bs_protos(bs_notimpl);
+
+/* Declare the mainbus bus space tag */
+
+struct bus_space mainbus_bs_tag = {
+ /* cookie */
+ NULL,
+
+ /* mapping/unmapping */
+ mainbus_bs_map,
+ mainbus_bs_unmap,
+ mainbus_bs_subregion,
+
+ /* allocation/deallocation */
+ mainbus_bs_alloc,
+ mainbus_bs_free,
+
+ /* get kernel virtual address */
+ 0, /* there is no linear mapping */
+
+ /* Mmap bus space for user */
+ mainbus_bs_mmap,
+
+ /* barrier */
+ mainbus_bs_barrier,
+
+ /* read (single) */
+ mainbus_bs_r_1,
+ mainbus_bs_r_2,
+ mainbus_bs_r_4,
+ bs_notimpl_bs_r_8,
+
+ /* read multiple */
+ bs_notimpl_bs_rm_1,
+ mainbus_bs_rm_2,
+ bs_notimpl_bs_rm_4,
+ bs_notimpl_bs_rm_8,
+
+ /* read region */
+ bs_notimpl_bs_rr_1,
+ bs_notimpl_bs_rr_2,
+ bs_notimpl_bs_rr_4,
+ bs_notimpl_bs_rr_8,
+
+ /* write (single) */
+ mainbus_bs_w_1,
+ mainbus_bs_w_2,
+ mainbus_bs_w_4,
+ bs_notimpl_bs_w_8,
+
+ /* write multiple */
+ mainbus_bs_wm_1,
+ mainbus_bs_wm_2,
+ bs_notimpl_bs_wm_4,
+ bs_notimpl_bs_wm_8,
+
+ /* write region */
+ bs_notimpl_bs_wr_1,
+ bs_notimpl_bs_wr_2,
+ bs_notimpl_bs_wr_4,
+ bs_notimpl_bs_wr_8,
+
+ bs_notimpl_bs_sm_1,
+ bs_notimpl_bs_sm_2,
+ bs_notimpl_bs_sm_4,
+ bs_notimpl_bs_sm_8,
+
+ /* set region */
+ bs_notimpl_bs_sr_1,
+ bs_notimpl_bs_sr_2,
+ bs_notimpl_bs_sr_4,
+ bs_notimpl_bs_sr_8,
+
+ /* copy */
+ bs_notimpl_bs_c_1,
+ bs_notimpl_bs_c_2,
+ bs_notimpl_bs_c_4,
+ bs_notimpl_bs_c_8,
+};
+
+/* bus space functions */
+
+int
+mainbus_bs_map(t, bpa, size, flags, bshp)
+ void *t;
+ bus_addr_t bpa;
+ bus_size_t size;
+ int flags;
+ bus_space_handle_t *bshp;
+{
+ u_long startpa, endpa, pa;
+ vaddr_t va;
+ pt_entry_t *pte;
+
+ if ((u_long)bpa > (u_long)KERNEL_BASE) {
+ /* XXX This is a temporary hack to aid transition. */
+ *bshp = bpa;
+ return(0);
+ }
+
+ startpa = trunc_page(bpa);
+ endpa = round_page(bpa + size);
+
+ /* XXX use extent manager to check duplicate mapping */
+
+ va = uvm_km_valloc(kernel_map, endpa - startpa);
+ if (! va)
+ return(ENOMEM);
+
+ *bshp = (bus_space_handle_t)(va + (bpa - startpa));
+
+ for(pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
+ pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
+ if ((flags & BUS_SPACE_MAP_CACHEABLE) == 0) {
+ pte = vtopte(va);
+ *pte &= ~L2_S_CACHE_MASK;
+ PTE_SYNC(pte);
+ }
+ }
+ pmap_update(pmap_kernel());
+
+ return(0);
+}
+
+int
+mainbus_bs_alloc(t, rstart, rend, size, alignment, boundary, cacheable,
+ bpap, bshp)
+ void *t;
+ bus_addr_t rstart, rend;
+ bus_size_t size, alignment, boundary;
+ int cacheable;
+ bus_addr_t *bpap;
+ bus_space_handle_t *bshp;
+{
+ panic("mainbus_bs_alloc(): Help!");
+}
+
+
+void
+mainbus_bs_unmap(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+ /*
+ * Temporary implementation
+ */
+}
+
+void
+mainbus_bs_free(t, bsh, size)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t size;
+{
+
+ panic("mainbus_bs_free(): Help!");
+ /* mainbus_bs_unmap() does all that we need to do. */
+/* mainbus_bs_unmap(t, bsh, size);*/
+}
+
+int
+mainbus_bs_subregion(t, bsh, offset, size, nbshp)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, size;
+ bus_space_handle_t *nbshp;
+{
+
+ *nbshp = bsh + (offset << 2);
+ return (0);
+}
+
+paddr_t
+mainbus_bs_mmap(t, paddr, offset, prot, flags)
+ void *t;
+ bus_addr_t paddr;
+ off_t offset;
+ int prot;
+ int flags;
+{
+ /*
+ * mmap from address `paddr+offset' for one page
+ */
+ return (arm_btop((paddr + offset)));
+}
+
+void
+mainbus_bs_barrier(t, bsh, offset, len, flags)
+ void *t;
+ bus_space_handle_t bsh;
+ bus_size_t offset, len;
+ int flags;
+{
+}
+
+/* End of mainbus_io.c */
diff --git a/sys/arch/arm/mainbus/mainbus_io_asm.S b/sys/arch/arm/mainbus/mainbus_io_asm.S
new file mode 100644
index 00000000000..af052ad3513
--- /dev/null
+++ b/sys/arch/arm/mainbus/mainbus_io_asm.S
@@ -0,0 +1,113 @@
+/* $OpenBSD: mainbus_io_asm.S,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $NetBSD: mainbus_io_asm.S,v 1.1 2001/02/24 19:38:02 reinoud Exp $ */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+/*
+ * bus_space I/O functions for mainbus
+ */
+
+
+/*
+ * read single
+ */
+
+ENTRY(mainbus_bs_r_1)
+ ldrb r0, [r1, r2, lsl #2]
+ mov pc, lr
+
+ENTRY(mainbus_bs_r_2)
+ ldr r0, [r1, r2, lsl #2]
+ bic r0, r0, #0xff000000
+ bic r0, r0, #0x00ff0000
+ mov pc, lr
+
+ENTRY(mainbus_bs_r_4)
+ ldr r0, [r1, r2, lsl #2]
+ mov pc, lr
+
+/*
+ * write single
+ */
+
+ENTRY(mainbus_bs_w_1)
+ strb r3, [r1, r2, lsl #2]
+ mov pc, lr
+
+ENTRY(mainbus_bs_w_2)
+ mov r3, r3, lsl #16
+ orr r3, r3, r3, lsr #16
+ str r3, [r1, r2, lsl #2]
+ mov pc, lr
+
+ENTRY(mainbus_bs_w_4)
+ str r3, [r1, r2, lsl #2]
+ mov pc, lr
+
+/*
+ * read multiple
+ */
+
+ENTRY(mainbus_bs_rm_2)
+ add r0, r1, r2, lsl #2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ b _C_LABEL(insw16)
+
+/*
+ * write multiple
+ */
+
+ENTRY(mainbus_bs_wm_1)
+ add r0, r1, r2, lsl #2
+ ldr r2, [sp, #0]
+
+ /* Make sure that we have a positive length */
+ cmp r2, #0x00000000
+ movle pc, lr
+
+mainbus_wm_1_loop:
+ ldrb r1, [r3], #0x0001
+ str r1, [r0]
+ subs r2, r2, #0x00000001
+ bgt mainbus_wm_1_loop
+
+ mov pc, lr
+
+ENTRY(mainbus_bs_wm_2)
+ add r0, r1, r2, lsl #2
+ mov r1, r3
+ ldr r2, [sp, #0]
+ b _C_LABEL(outsw16)