From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 22-NOV-1990 17:07:22.65
To:	MRGATE::"ARISIA::EVERHART"
CC:	
Subj:	The RIGHT version of RAMDRIVER, part 3 of 5

Received:  by crdgw1.ge.com (5.57/GE 1.78)
	 id AA04404; Thu, 22 Nov 90 16:42:29 EST
Received: From UCBVAX.BERKELEY.EDU by CRVAX.SRI.COM with TCP; Thu, 22 NOV 90 07:34:39 PST
Received: by ucbvax.Berkeley.EDU (5.63/1.42)
	id AA06238; Thu, 22 Nov 90 07:20:01 -0800
Received: from USENET by ucbvax.Berkeley.EDU with netnews
	for info-vax@kl.sri.com (info-vax@kl.sri.com)
	(contact usenet@ucbvax.Berkeley.EDU if you have questions)
Date: 21 Nov 90 00:37:51 GMT
From: gkn@ucsd.edu  (Gerard K. Newman)
Organization: San Diego Supercomputer Center
Subject: The RIGHT version of RAMDRIVER, part 3 of 5
Message-Id: <23374@ucsd.Edu>
Sender: info-vax-request@kl.sri.com
To: info-vax@kl.sri.com


-+-+-+-+-+-+-+-+ START OF PART 3 -+-+-+-+-+-+-+-+
X`009MOVW`009#SS$_NORMAL,R0`009`009`009 ;Success
X`009CLRL`009R1`009`009`009`009 ;No further status
X`009BITW`009#<IRP$M_PAGIO!IRP$M_SWAPIO>,-`009 ;Special case
X`009`009IRP$W_STS(R3)`009`009`009 ; paging/swapping I/O completion
X`009BNEQ`00940$`009`009`009`009 ;`009...
X`009FORKLOCK LOCK=UCB$B_FLCK(R5),-`009`009 ;Grab the
X`009`009SAVIPL=-(SP),-`009`009`009 ; fork lock
X`009`009PRESERVE=YES`009`009`009 ;  to modify
X`009MOVL`009R3,UCB$L_IRP(R5)`009`009 ;   the UCB
X
X30$:`009JSB`009G`094IOC$REQCOM`009`009 ;Post the request complete (& look fo
Vr more work)
X`009FORKUNLOCK LOCK=UCB$B_FLCK(R5),- ;Release the
X`009`009NEWIPL=(SP)+,-`009`009 ; fork lock
X`009`009PRESERVE=YES,-`009`009 ;`009...
X`009`009CONDITION=RESTORE`009 ;`009...
X`009RSB`009`009`009`009 ;Done
X
X; Here for paging I/O completion -- we already own the fork lock, and
X; IOC$INSIOQC expects to release it ...
X
X40$:`009BSBW`009RAMD_FREE_SPTES`009`009;Release the system page table entrie
Vs used to map the buffer
X`009MOVL`009R3,UCB$L_IRP(R5)`009;Stash the IRP address
X`009JMP`009G`094IOC$REQCOM`009`009;Post this request complete (& look for mo
Vre work)
X
X`009.Page
X`009.Subtitle`009RAMD_READ`009- Process a read IRP
X
X;+
X;
X; ----- RAMD_READ:  Process a read IRP
X;
X;
X; This routine is called to process a read IRP, which involves a transfer
X; from the "disk" to the user's buffer.
X;
X; Environment:
X;
X;`009IPL$_ASTDEL, process context.
X;
X; Inputs:
X;
X;`009R4`009- PCB address
X;`009R3`009- IRP address
X;`009R2`009- User buffer address
X;`009R1`009- Disk buffer address
X;
X; Outputs:
X;
X;`009Data read into the user's buffer.
X;
X;-
X
XRAMD_READ:`009`009`009`009 ;Process a read IRP
X
X`009BSBW`009RAMD_LOCK_READ`009`009 ;Lock the MUTEX for read access
X`009MOVC3`009IRP$L_BCNT(R3),(R1),(R2) ;Read the data
X`009RSB`009`009`009`009 ;Done
X
X`009.Page
X`009.Subtitle`009RAMD_WRITE`009- Process a write IRP
X
X;+
X;
X; ----- RAMD_WRITE:  Process a write IRP
X;
X;
X; This routine is called to process a write IRP, which involves a transfer
X; from the user's buffer to the "disk".  Erase requests also come here.
X;
X; Environment:
X;
X;`009IPL$_ASTDEL, process context.
X;
X; Inputs:
X;
X;`009R4`009- PCB address
X;`009R3`009- IRP address
X;`009R2`009- User buffer address
X;`009R1`009- Disk buffer address
X;
X; Outputs:
X;
X;`009Data written from the user's buffer
X;
X;-
X
XRAMD_WRITE:`009`009`009`009`009;Process a write IRP
X
X`009BSBW`009RAMD_LOCK_WRITE`009`009`009;Lock the MUTEX for write access
X`009BBS`009#IO$V_ERASE,IRP$W_FUNC(R3),10$`009;Erase?
X`009MOVC3`009IRP$L_BCNT(R3),(R2),(R1)`009;Nope.
X`009RSB`009`009`009`009`009;Done
X
X10$:`009MOVC5`009#0,(SP),#0,IRP$L_BCNT(R3),(R1)`009;Erase the data
X`009RSB`009`009`009`009`009;Done
X
X`009.Page
X`009.Subtitle`009RAMD_LOCK_READ`009- Lock our MUTEX for read  access
X`009.Subtitle`009RAMD_LOCK_WRITE`009- Lock our MUTEX for write access
X;+
X;
X; ----- RAMD_LOCK_READ:   Lock our MUTEX for read  access
X; ----- RAMD_LOCK_WRITE:  Lock our MUTEX for write access
X;
X;
X; These routines will  lock our MUTEX for either read or write access,
X; and are sensitive to whether or not we can receive ASTs.  If we can,
X; the standard SCH$LOCK`123R,W`125  routines are called.  Failure to acquire
X; the lock in this case will suspend the process in MWAIT.
X;
X; If we can't receive ASTs (paging I/O) then we call SCH$LOCK`123R,W`125EXEC
X; routines to  lock  the MUTEX  without process  context.  Failure  to
X; acquire the lock in this  case complicates things quite a bit.  What
X; we'd really like to  do is to drop IPL back  down to IPL$_ASTDEL and
X; stick the process  in MWAIT,  but I'm  not convinced  I can  do that
X; safely.  The problem is the length of the call stack that eventually
X; got us  here -- we came  thru  EXE$INSIOQC  prior to  the start  I/O
X; routine, and  hit EXE$BUILDPKTR at some  point before that, and from
X; there the  path gets a bit fuzzy.  So, what we do instead is to look
X; at the kind of I/O request we're processing.  If it's a read request
X; (the usual case) we simply drive  on as if we had acquired the lock.
X; If it's a write  request then we  complete the  I/O request  with an
X; error.  The idea here is that the only way to get a page fault write
X; on a ram disk is to either have  a paging file open on is (dumb), or
X; for someone to  have a global  section with  backing store set  to a
X; file on the  ram disk (dumb).  In either  case I just can't convince
X; myself that the extra work to make this work "right" is worth it.
X;
X; Pie-in-the-sky-department:
X;
X; It would be nice to come up with an interlock which had granularity
X; of, say, 1 block, rather than the entire disk.
X;
X; Inputs:
X;
X;`009R4`009- PCB address
X;`009R3`009- IRP address
X;`009R2`009- User buffer address
X;`009R1`009- Disk buffer address
X;`009R0`009- MUTEX address
X;
X; Outputs:
X;
X;`009MUTEX locked if possible.
X;
X;-
X
XRAMD_LOCK_READ:`009`009`009`009;Lock our MUTEX for read  access
X
X`009BITW`009#<IRP$M_PAGIO!IRP$M_SWAPIO>,-`009;Paging or
X`009`009IRP$W_STS(R3)`009`009`009; swapping I/O?
X`009BNEQ`00910$`009`009`009`009;If NEQ yes, special case
X`009JMP`009G`094SCH$LOCKR`009`009`009;Lock the MUTEX and return
X
X; Here for a page fault read.
X
X10$:`009JSB`009G`094SCH$LOCKREXEC`009`009;Attempt to lock the MUTEX
X`009BLBS`009R0,20$`009`009`009;Win
X`009INCW`009UCB$W_ERRCNT(R5)`009;Count up these errors
X`009BBSS`009#IRP$V_MBXIO,-`009`009;Flag the fact
X`009`009IRP$W_STS(R3),20$`009; that we don't have to unlock
X
X20$:`009RSB`009`009`009`009;Done
X
XRAMD_LOCK_WRITE:`009`009`009;Lock our MUTEX for write access
X
X`009BITW`009#<IRP$M_PAGIO!IRP$M_SWAPIO>,-`009;Paging or
X`009`009IRP$W_STS(R3)`009`009`009; swapping I/O (dumb and double dumb)
X`009BNEQ`00910$`009`009`009`009;If NEQ yes, special case
X`009JMP`009G`094SCH$LOCKW`009`009`009;Nope, lock the MUTEX and return
X
X; Here for a page fault write (dumb).
X
X10$:`009JSB`009G`094SCH$LOCKWEXEC`009`009;Attempt to lock the MUTEX
X`009BLBC`009R0,20$`009`009`009;Lose
X`009RSB`009`009`009`009;Win
X
X; Lossage.  Defeat the I/O request.
X
X20$:`009CMPL`009(SP)+,(SP)+`009`009;Clean the stack
X`009POPR`009#`094m<R3,R4,R5>`009`009;Restore the registers
X`009BSBW`009RAMD_FREE_SPTES`009`009;Release the system page table entries
X`009MOVL`009IRP$L_WCBSAVE(R3),-`009;Restore the
X`009`009IRP$L_WIND(R3)`009`009; window pointer
X`009MOVL`009R3,UCB$L_IRP(R5)`009;Stash the IRP address
X`009INCW`009UCB$W_ERRCNT(R5)`009;Count up these errors.
X`009MOVQ`009#SS$_CTRLERR,R0`009`009;Indicate error
X`009JMP`009G`094IOC$REQCOM`009`009;Punt this request.
X
X`009.Page
X`009.Subtitle`009RAMD_UNLOCK`009- Unlock our MUTEX
X
X;+
X;
X; ----- RAMD_UNLOCK:  Unlock our MUTEX
X;
X;
X; This routine  is called to unlock  our MUTEX.  We are sensitive to our
X; ability to receive ASTs.   If we can,  then we simply call SCH$UNLOCK.
X; If we  can't  (paging I/O), we call  SCH$UNLOCKEXEC  instead.  We also
X; use IRP$V_MBXIO  for paging I/O  unlocks to  indicate that  we ignored
X; the error return from SCH$LOCKREXEC and therefore don't need to unlock
X; the MUTEX.
X;
X; Inputs:
X;
X;`009R5`009- UCB address
X;`009R4`009- PCB address
X;`009R3`009- IRP address
X;
X; Outputs:
X;
X;`009MUTEX unlocked if it was locked.
X;
X;-
X
XRAMD_UNLOCK:`009`009`009`009;Unlock our MUTEX
X
X`009MOVAB`009UCB$L_RAMD_MUTEX(R5),R0`009`009;Address our MUTEX
X`009BITW`009#<IRP$M_PAGIO!IRP$M_SWAPIO>,-`009;Paging or
X`009`009IRP$W_STS(R3)`009`009`009; swapping I/O?
X`009BNEQ`00910$`009`009`009`009;Yep.
X`009JMP`009G`094SCH$UNLOCK`009`009`009;Nope.
X
X; Here for paging I/O -- check the MBXIO bit to see if we ignored
X; the error from SCH$LOCKREXEC.
X
X10$:`009BBSC`009#IRP$V_MBXIO,IRP$W_STS(R3),20$`009;Did we ignore an error fr
Vom SCH$LOCKREXEC?
X`009JMP`009G`094SCH$UNLOCKEXEC`009`009;Nope, unlock and return
X
X20$:`009RSB`009`009`009`009;Nothing to unlock
X
X`009.Page
X`009.Subtitle`009SVAPTE_TO_VA`009- Convert a SVAPTE to a usable virtual addr
Vess
X
X;+
X;
X; ----- SVAPTE_TO_VA:  Convert a SVAPTE to a usable virtual address
X;
X;
X; This routine will take the  SVAPTE from an IRP and convert it to a usable
X; virtual address.  The virtual address can be P0, P1, or S0 space.
X;
X; A  special case is made for paging I/O:  We use system space addresses to
X; deal  with paging I/O.  RAMD_STARTIO has  allocated and mapped a range of
X; SPTs  on top of  the user's  buffer.  We do this for two reasons.  First,
X; user  PTEs involved  in page  read operations  don't have PTE$M_VALID set
X; until after the I/O request completes.  To use the user virtual addresses
X; specified by  these PTEs we  would have to set PTE$M_VALID and also allow
X; KW access  to the pages temporarily.  The  second reason is that we would
X; have to run  at IPL$_SYNCH to  prevent the swapper from moving the user's
X; process header while we were mucking about with the PTEs in it.  By using
X; system virtual addresses  we only have to run at IPL$_SYNCH for two brief
X; periods - one to synchronize access to the SPTE bitmap in the UCB and the
X; other to synchornize access to the SPT.
X;
X; Note bene:
X;
X; This  routine  assumes  that the  system page table (SPT)  is at a higher
X; virtual address  than  all of the  page tables for  processes (PHDs), and
X; that  the P1  page table is at  a higher virtual  address in the PHD than
X; the P0 page table.  We must  briefly execute at IPL$_SYNCH to prevent the
X; PHD from being outswapped.
X;
X; Environment:
X;
X;`009IPL$_ASTDEL, process context.
X;
X; Inputs:
X;
X;`009R4`009- PCB address
X;`009R3`009- IRP address
X;
X; Outputs:
X;
X;`009R2`009- Virtual address
X;
X;-
X
XSVAPTE_TO_VA:`009`009`009`009`009;Convert a SVAPTE to a usable virtual addre
Vss
X
X`009MOVL`009IRP$L_PAGE_VA(R3),R2`009`009;Presume paging I/O
X`009BITW`009#<IRP$M_PAGIO!IRP$M_SWAPIO>,-`009;Check our
X`009`009IRP$W_STS(R3)`009`009`009; presumption
X`009BNEQ`00910$`009`009`009`009;Branch if we're right.
X`009MOVL`009IRP$L_SVAPTE(R3),R2`009`009;Grab the SVAPTE
X`009LOCK`009LOCKNAME=MMG,-`009`009`009;Keep the PHD
X`009`009SAVIPL=-(SP),-`009`009`009; from moving and
X`009`009PRESERVE=YES`009`009`009;  the SPT from changing
X
X; S0 space address?
X
X`009CMPL`009R2,G`094MMG$GL_SPTBASE`009;S0 address?
X`009BGEQU`00930$`009`009`009;If GEQU yes, use a different page table
X
X; Nope -- it's a process virtual address.  Check to see if it's P0 or P1 spa
Vce.
X
X`009MOVL`009PCB$L_PHD(R4),R1`009 ;Grab our process header
X`009MULL3`009#4,PHD$L_P0LRASTL(R1),R0 ;Get the length of the P0 page table i
Vn bytes
X`009ADDL`009PHD$L_P0BR(R1),R0`009 ;Compute the ending address of the P0 page
V table +1
X`009CMPL`009R2,R0`009`009`009 ;Is this a P0 page?
X`009BGEQU`00920$`009`009`009 ;If GEQU no, it's a P1 page
X`009SUBL`009PHD$L_P0BR(R1),R2`009 ;Else compute the byte offset into the P0
V page table
X`009MULL`009#128,R2`009`009`009 ;Convert same into a VA (128*4 = 512)
X`009UNLOCK`009LOCKNAME=MMG,-`009`009 ;Release the
X`009`009NEWIPL=(SP)+,-`009`009 ; MMG lock
X`009`009PRESERVE=YES`009`009 ;`009...
X
X10$:`009RSB`009`009`009`009 ;Done
X
X; Here when we have a P1 space address.
X
X20$:`009SUBL`009PHD$L_P1BR(R1),R2`009;Compute the byte offset into the P1 pa
Vge table
X`009MULL`009#128,R2`009`009`009;Convert same into a virtual page number (128
V*4 = 512)
X`009BISL`009#VA$M_P1,R2`009`009;Bias it into a P1 virtual address
X`009UNLOCK`009LOCKNAME=MMG,-`009`009;Release the
X`009`009NEWIPL=(SP)+,-`009`009; MMG lock
X`009`009PRESERVE=YES`009`009;`009...
X`009RSB`009`009`009`009;Done
X
X; Here when we have a system virtual address (eh?)
X
X30$:`009SUBL`009G`094MMG$GL_SPTBASE,R2`009;Get the byte offset into the SPT
X`009MULL`009#128,R2`009`009`009;Convert same to a virtual page number (128*4
V = 512)
X`009BISL`009#VA$M_SYSTEM,R2`009`009;Convert same into a S0 address
X`009UNLOCK`009LOCKNAME=MMG,-`009`009;Release the
X`009`009NEWIPL=(SP)+,-`009`009; MMG lock
X`009`009PRESERVE=YES`009`009;`009...
X`009RSB`009`009`009`009;Done
X
X`009.Page
X`009.Subtitle`009RAMD_SMAP`009- Map pages into system virtual address space
X
X;+
X;
X; ----- RAMD_SMAP:  Map pages into system virtual address space
X;
X;
X; This routine is called to map user pages into system space.  These pages a
Vre
X; part of a page fault read and hence the valid bit in the PTEs is not set.
V We
X; could just set the valid bit, but then we would also have to change the pa
Vge
X; protection to allow kernel  write to the desired pages,  and it becomes mo
Vre
X; complicated.  In addition, to properly synchronize with the swapper we wou
Vld
X; have to own the MMG interlock  (to keep the PHD from moving) and thus run
V at
X; IPL$_SYNCH,  negating any  performance advantage we might  otherwise  get
V by
X; doing all of these gyrations.
X;
X; Environment:
X;
X;`009IPL$_SYNCH, fork context.
X;
X; Inputs:
X;
X;`009R5`009- UCB address
X;`009R3`009- IRP address
X;
X; Outputs:
X;
X;`009System address space allocated and mapped on top of the user's buffer.
X;
X;-
X
XRAMD_SMAP:`009`009`009`009;Map pages into system virtual address space
X
X`009MOVZWL`009IRP$L_BCNT(R3),R2`009;Fetch the byte count
X`009MOVZWL`009IRP$W_BOFF(R3),R0`009;Fetch the byte offset
X`009MOVAB`009511(R2)`091R0`093,R2`009`009;Combine offset and count & round u
Vp
X`009ASHL`009#-VA$S_BYTE,R2,R2`009;Convert to a page count
X`009JSB`009G`094LDR$ALLOC_PT`009`009;Allocate some page table entries
X`009BLBC`009R0,20$`009`009`009;Lossage!
X
X; We've allocated some page table entries;  map them to the specified physic
Val
X; pages.  We unconditionally map the pages as KW since the only way we can g
Vet
X; here is for page reads (well, page writes, too, but KW won't hurt).
X
X`009MOVL`009R1,IRP$L_SPTE(R3)`009;Save the starting SPTE address
X`009MOVL`009R2,IRP$L_NSPTES(R3)`009;Save the number of system page table ent
Vries
X`009SUBL3`009G`094MMG$GL_SPTBASE,R1,R0`009;Get the byte offset into the SPT
X`009MULL`009#128,R0`009`009`009;Convert same to a virtual page # (128*4 = 51
V2)
X`009BISL3`009#VA$M_SYSTEM,R0,-`009;Convert same into a
X`009`009IRP$L_PAGE_VA(R3)`009; system virtual address
X`009MOVL`009IRP$L_SVAPTE(R3),R0`009;Fetch the address of the first user PTE
X`009PUSHL`009R3`009`009`009;Keep the IRP address safe
X
X; Note that we don't invalidate the translation buffer here;  I'm
X; presuming that the last user of this system virtual address did
X; so.
X
+-+-+-+-+-+-+-+-  END  OF PART 3 +-+-+-+-+-+-+-+-
-- 
gkn	Gerard K. Newman		gkn@sds.sdsc.edu	619.534.5076
	San Diego Supercomputer Center	gkn@sdsc.bitnet		619.534.5152 FAX
	PO Box 85608			sdsc::gkn (27.1/span)
	San Diego, CA  92186-9784	ucsd!gkn

