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#,-`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#,-`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#,-`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`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#,-`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#,-`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