+ pmap_put_mapwindow(map);
+
+ (void) ml_set_interrupts_enabled(istate);
+
+ __mfence();
+}
+
+
+/*
+ * the copy engine has the following characteristics
+ * - copyio handles copies to/from user or kernel space
+ * - copypv deals with physical or virtual addresses
+ *
+ * implementation details as follows
+ * - a cache of up to NCOPY_WINDOWS is maintained per thread for
+ * access of user virutal space
+ * - the window size is determined by the amount of virtual space
+ * that can be mapped by a single page table
+ * - the mapping is done by copying the page table pointer from
+ * the user's directory entry corresponding to the window's
+ * address in user space to the directory entry corresponding
+ * to the window slot in the kernel's address space
+ * - the set of mappings is preserved across context switches,
+ * so the copy can run with pre-emption enabled
+ * - there is a gdt entry set up to anchor the kernel window on
+ * each processor
+ * - the copies are done using the selector corresponding to the
+ * gdt entry
+ * - the addresses corresponding to the user virtual address are
+ * relative to the beginning of the window being used to map
+ * that region... thus the thread can be pre-empted and switched
+ * to a different processor while in the midst of a copy
+ * - the window caches must be invalidated if the pmap changes out
+ * from under the thread... this can happen during vfork/exec...
+ * inval_copy_windows is the invalidation routine to be used
+ * - the copyio engine has 4 different states associated with it
+ * that allows for lazy tlb flushes and the ability to avoid
+ * a flush all together if we've just come from user space
+ * the 4 states are as follows...
+ *
+ * WINDOWS_OPENED - set by copyio to indicate to the context
+ * switch code that it is necessary to do a tlbflush after
+ * switching the windows since we're in the middle of a copy
+ *
+ * WINDOWS_CLOSED - set by copyio to indicate that it's done
+ * using the windows, so that the context switch code need
+ * not do the tlbflush... instead it will set the state to...
+ *
+ * WINDOWS_DIRTY - set by the context switch code to indicate
+ * to the copy engine that it is responsible for doing a
+ * tlbflush before using the windows again... it's also
+ * set by the inval_copy_windows routine to indicate the
+ * same responsibility.
+ *
+ * WINDOWS_CLEAN - set by the return to user path to indicate
+ * that a tlbflush has happened and that there is no need
+ * for copyio to do another when it is entered next...
+ *
+ * - a window for mapping single physical pages is provided for copypv
+ * - this window is maintained across context switches and has the
+ * same characteristics as the user space windows w/r to pre-emption
+ */
+
+extern int copyout_user(const char *, vm_offset_t, vm_size_t);
+extern int copyout_kern(const char *, vm_offset_t, vm_size_t);
+extern int copyin_user(const vm_offset_t, char *, vm_size_t);
+extern int copyin_kern(const vm_offset_t, char *, vm_size_t);
+extern int copyoutphys_user(const char *, vm_offset_t, vm_size_t);
+extern int copyoutphys_kern(const char *, vm_offset_t, vm_size_t);
+extern int copyinphys_user(const vm_offset_t, char *, vm_size_t);
+extern int copyinphys_kern(const vm_offset_t, char *, vm_size_t);
+extern int copyinstr_user(const vm_offset_t, char *, vm_size_t, vm_size_t *);
+extern int copyinstr_kern(const vm_offset_t, char *, vm_size_t, vm_size_t *);
+
+static int copyio(int, user_addr_t, char *, vm_size_t, vm_size_t *, int);
+static int copyio_phys(addr64_t, addr64_t, vm_size_t, int);
+
+
+#define COPYIN 0
+#define COPYOUT 1
+#define COPYINSTR 2
+#define COPYINPHYS 3
+#define COPYOUTPHYS 4
+
+
+void inval_copy_windows(thread_t thread)
+{
+ int i;