+/* mem.c 2.2 1/14/80 */
+
+/*
+ * Memory special file
+ * minor device 0 is physical memory
+ * minor device 1 is kernel memory
+ * minor device 2 is EOF/RATHOLE
+ * minor device 3 is unibus memory (addressed by shorts)
+ */
+
+#include "../h/param.h"
+#include "../h/dir.h"
+#include "../h/user.h"
+#include "../h/conf.h"
+#include "../h/buf.h"
+#include "../h/systm.h"
+#include "../h/pte.h"
+#include "../h/mtpr.h"
+#include "../h/vm.h"
+#include "../h/cmap.h"
+
+mmread(dev)
+{
+ register int o;
+ register unsigned c, v;
+
+ switch (minor(dev)) {
+
+ case 0:
+ while (u.u_count != 0 && u.u_error == 0) {
+ if (fubyte(u.u_base) == -1)
+ goto fault;
+ v = btop(u.u_offset);
+ if (v >= physmem)
+ goto fault;
+ *(int *)mmap = v | (PG_V | PG_KR);
+ mtpr(TBIS, vmmap);
+ o = (int)u.u_offset & PGOFSET;
+ c = min((unsigned)(NBPG - o), u.u_count);
+ if (copyout((caddr_t)&vmmap[o], u.u_base, c))
+ goto fault;
+ u.u_count -= c;
+ u.u_base += c;
+ u.u_offset += c;
+ }
+ return;
+
+ case 1:
+ if (u.u_uid != 0) {
+ if ((caddr_t)u.u_offset < (caddr_t)&umbabeg &&
+ (caddr_t)u.u_offset + u.u_count >= (caddr_t)&umbabeg)
+ goto fault;
+ if ((caddr_t)u.u_offset >= (caddr_t)&umbabeg &&
+ (caddr_t)u.u_offset < (caddr_t)&umbaend)
+ goto fault;
+ }
+ if (!kernacc((caddr_t)u.u_offset, u.u_count, B_READ))
+ goto fault;
+ if (copyout((caddr_t)u.u_offset, u.u_base, u.u_count))
+ goto fault;
+ c = u.u_count;
+ u.u_count = 0;
+ u.u_base += c;
+ u.u_offset += c;
+ return;
+
+ case 2:
+ return;
+
+ case 3:
+ if (!kernacc((caddr_t)u.u_offset, u.u_count, B_READ))
+ goto fault;
+ if (!useracc(u.u_base, u.u_count, B_WRITE))
+ goto fault;
+ UNIcpy((caddr_t)u.u_offset, u.u_base, u.u_count, B_READ);
+ c = u.u_count;
+ u.u_count = 0;
+ u.u_base += c;
+ u.u_offset += c;
+ return;
+ }
+fault:
+ u.u_error = EFAULT;
+ return;
+}
+
+mmwrite(dev)
+{
+ register int o;
+ register unsigned c, v;
+
+ switch (minor(dev)) {
+
+ case 0:
+ while (u.u_count != 0 && u.u_error == 0) {
+ if (fubyte(u.u_base) == -1)
+ goto fault;
+ v = btop(u.u_offset);
+ if (v >= physmem)
+ goto fault;
+ *(int *)mmap = v | (PG_V | PG_KW);
+ mtpr(TBIS, vmmap);
+ o = (int)u.u_offset & PGOFSET;
+ c = min((unsigned)(NBPG - o), u.u_count);
+ if (copyin(u.u_base, (caddr_t)&vmmap[o], c))
+ goto fault;
+ u.u_count -= c;
+ u.u_base += c;
+ u.u_offset += c;
+ }
+ return;
+
+ case 1:
+ if (!kernacc((caddr_t)u.u_offset, u.u_count, B_WRITE))
+ goto fault;
+ if (copyin(u.u_base, (caddr_t)u.u_offset, u.u_count))
+ goto fault;
+ u.u_base += u.u_count;
+ u.u_offset += u.u_count;
+ u.u_count = 0;
+ return;
+
+ case 2:
+ u.u_offset += u.u_count;
+ u.u_count = 0;
+ return;
+
+ case 3:
+ if (!kernacc((caddr_t)u.u_offset, u.u_count, B_WRITE))
+ goto fault;
+ if (!useracc(u.u_base, u.u_count, B_READ))
+ goto fault;
+ UNIcpy((caddr_t)u.u_offset, u.u_base, u.u_count, B_WRITE);
+ u.u_base += u.u_count;
+ u.u_offset += u.u_count;
+ u.u_count = 0;
+ return;
+ }
+fault:
+ u.u_error = EFAULT;
+ return;
+}
+
+/*
+ * UNIBUS Address Space <--> User Space transfer
+ */
+UNIcpy(uniadd, usradd, bknt, direct)
+ caddr_t uniadd, usradd;
+ unsigned bknt;
+{
+ register short *from, *to;
+ register int i;
+
+ if (direct == B_READ) {
+ from = (short *) uniadd;
+ to = (short *) usradd;
+ } else {
+ from = (short *) usradd;
+ to = (short *) uniadd;
+ }
+ for (i = (bknt>>1); i > 0; i--)
+ *to++ = *from++;
+}