.Title KMDRIVER - Kernel memory access driver .Ident /V01.000/ .Enable SUP .Subtitle Introduction ;+ ; ; ----- KMDRIVER: Kernel memory access driver ; ; ; Facility: ; ; VMS executive, I/O subsystem ; ; Abstract: ; ; This module implements a kernel virtual memory access driver similar ; to /dev/kmem on many Unix systems. While not particularly useful on ; a VMS system, it does serve to illustrate how one might write such a ; driver, and how one might port it to Alpha VMS. ; ; Environment: ; ; VMS native mode, OpenVMS V5.0/V1.0 or later, resident, kernel mode, ; IPL$_ASTDEL and above, SMP ready. ; ; ; Version: V01.000 ; Date: 25-May-1993 ; ; Copyright © 1993 TGV, Incorporated. ; ; Gerard K. Newman 25-May-1993 ; TGV, Incorporated ; 603 Mission Street ; Santa Cruz, CA 95060 ; 408.427.4366 ; ; ; Internet: GKN@TGV.COM ; BITNET: GKN@SDSC.BITNET ; SPAN: SDSC::GKN (27.1) ; uucp: ucsd!gkn ; ; ; Modifications: ; ; ;- .Page .Subtitle Local definitions .Library "ALPHA$LIBRARY:LIB.MLB" ;Get special macros from here EVAX = 1 ;Doesn't appear to be as necessary for V1.5. .NoCross ;Save a tree $CRBDEF ;Controller request block definitions $DCDEF ;Device class & type definitions $DDBDEF ;Device data block definitions $DDTDEF ;Driver dispatch table offsets $DEVDEF ;Device independent status bits $DPTDEF ;Driver prologue table offsets $DYNDEF ;Dynamic data structure types $IODEF ;I/O function codes $IPLDEF ;Interrupt priority levels $IRPDEF ;I/O request packet definitions $ORBDEF ;Object rights block definitions $PCBDEF ;Process control block offsets $PHDDEF ;Process header offsets $PRDEF ;Internal processor registers $PRVDEF ;Privilege bits $PSLDEF ;Processor status longword format. $SSDEF ;System service codes $UCBDEF ;UCB offsets $VECDEF ;Interrupt transfer vector offsets .Cross ;Turn CREF back on ; Local definitions ; UCB offsets which follow the standard UCB. $DEFINI UCB ;Start of the UCB offsets . = UCB$K_LENGTH ;Start after the standard UCB $DEF UCB$L_KM_READS .Blkl ;Reads $DEF UCB$L_KM_WRITES .Blkl ;Writes $DEF UCB$L_KM_PWRFS .Blkl ;Power failures $DEF UCB$K_KM_LENG ;Length of our UCB $DEFEND UCB ;End of the UCB offsets .Page .Subtitle Standard device driver tables Driver_Data ;To the data psect ; Driver prologue table. DPTAB - ;Driver prologue table End = KM_END,- ;End of the driver Adapter = NULL,- ;No adapter (no hardware) SMP = YES,- ;We can deal with SMP Unload = KM_UNLOAD,- ;Unload routine Name = KMDRIVER,- ;Driver name Step = 1,- ;Step 1 Alpha driver. UCBSize = UCB$K_KM_LENG ;UCB size ; Initialization table. DPT_Store INIT ;Initialization table ; Unit control block (UCB). DPT_Store UCB,UCB$B_FLCK,B,SPL$C_IOLOCK8 ;Fork IPL spin lock index DPT_Store UCB,UCB$B_DIPL,B,IPL$_SYNCH ;Device IPL DPT_Store UCB,UCB$L_DEVCHAR,L,<- ;Device characteristics: DEV$M_AVL!- ; Available DEV$M_SHR!- ; Shareable DEV$M_IDV!- ; Capable of input DEV$M_ODV> ; Capable of output DPT_Store UCB,UCB$L_DEVCHAR2,L,<- ;More device characteristics: DEV$M_NNM> ; Prefix the name with "node$" DPT_Store UCB,UCB$B_DEVCLASS,B,DC$_MISC ;It's pretty miscellanous DPT_Store UCB,UCB$B_DEVTYPE,B,DT$_NULL ;For lack of anything better DPT_Store UCB,UCB$W_DEVBUFSIZ,W,65535 ;Buffer size ; Reinitialization table. DPT_Store REINIT ;Reinitialization table ; Device data block (DDB). DPT_Store DDB,DDB$L_DDT,D,KM$DDT ;Driver dispatch table address DPT_Store END ;End of the initialization tables. ; Driver dispatch table. DDTAB - ;Driver dispatch table DevNam = KM,- ;Device name Start = 0,- ;No Start I/O (all done in FDT routines) FuncTB = KM_FUNCTAB,- ;Function decision table address Cancel = 0,- ;No cancel I/O RegDmp = 0,- ;Register dump (no registers!) DiagBf = 0,- ;No diagnostic bufer ErlgBf = 0,- ;No error logging buffer CtrlInit= KM_CTRL_INIT,-;Controller initialization UnitInit= KM_UNIT_INIT ;Unit initialization ; Function decision table. KM_FUNCTAB: ;Function decision table. ; Legal functions. FuncTab ,<- ;Legal functions: READVBLK,- ; Read virtual READLBLK,- ; Read logical READPBLK,- ; Read physical WRITEVBLK,- ; Write virtual WRITELBLK,- ; Write logical WRITEPBLK> ; Write physical ; Buffered functions. FuncTab ,<> ;Buffered functions: ; (none) ; Direct functions and FDT mapping. FuncTab KM_READ,<- ;Read functions: READVBLK,- ; Read virtual READLBLK,- ; Read logical READPBLK> ; Read physical FuncTab KM_WRITE,<- ;Write functions: WRITEVBLK,- ; Write virtual WRITELBLK,- ; Write logical WRITEPBLK> ; Write physical .Page .Subtitle KM_UNLOAD - Driver unload routine Driver_Code ;To the code psect ;+ ; ; ----- KM_UNLOAD: Driver unload routine ; ; ; This routine is called in response to the SYSGEN UNLOAD command. ; ; Environment: ; ; IPL$_POWER, process context. ; ; Inputs: ; ; None. ; ; Outputs: ; ; None. ; ;- KM_UNLOAD: ;Driver unload routine .JSB_Entry Output=R0 MOVL #SS$_NORMAL,R0 ;Allow driver to be unloaded. RSB ; ... .Page .Subtitle KM_CTRL_INIT - Controller initialization ;+ ; ; ----- KM_CTRL_INIT: Controller initialization ; ; ; This routine is called to perform controller specific initialization ; during the SYSGEN LOAD or RELOAD commands and during power failure ; recovery. Since there isn't a controller this routine doesn't do ; a whole lot. ; ; Environment: ; ; IPL$_POWER, system context. ; ; Inputs: ; ; None. ; ; Outputs: ; ; Not much. ; ;- KM_CTRL_INIT: ;Controller initialization .JSB_Entry Input=R5,- Output=R0 ;%%% JSB G^INI$BRK ;%%% Whistle up XDELTA MOVL #SS$_NORMAL,R0 ;Success. RSB ;Done .Page .Subtitle KM_UNIT_INIT - Unit initialization ;+ ; ; ----- KM_UNIT_INIT: Unit initialization ; ; ; This routine is called during the SYSGEN LOAD command (but not RELOAD) and ; during power failure recovery. Since we're just an example device driver ; we count power failures here. ; ; Environment: ; ; IPL$_POWER, system context. ; ; Inputs: ; ; R5 - UCB address ; ; Outputs: ; ; Unit set online. ; ;- KM_UNIT_INIT: ;Unit initialization .JSB_Entry Input=R5,- Output=R0 BBCC #UCB$V_POWER,UCB$L_STS(R5),10$ ;Powerfail recovery? INCL UCB$L_KM_PWRFS(R5) ;Yes, another power failure 10$: BISL #UCB$M_ONLINE,UCB$L_STS(R5) ;We're on the air MOVL #SS$_NORMAL,R0 ;Success. RSB ;Done. .Page .Subtitle KM_READ - Handle read requests ;+ ; ; ----- KM_READ: Handle read requests ; ; ; This routine is called to handle read requests. We access ; check the users' buffer, and the proposed system space ; buffer, and if the check passes we copy the data from system ; space back to user space. ; ; Environment: ; ; IPL$_ASTDEL, process context, CMKRNL privilege required. ; ; Inputs: ; ; R5 - UCB address ; R4 - PCB address ; R3 - IRP address ; ; QIO P1 - User buffer address ; QIO P2 - User buffer size ; QIO P3 - System space address to copy from ; ; Outputs: ; ; Data returned if no ACCVIO. ; ;- KM_READ: ;Handle read requests .JSB_Entry Input=,- Output=,- Scratch=R2 ; Enforce the need for CMKRNL. MOVL #SS$_NOCMKRNL,R0 ;Presume failure IFPRIV CMKRNL,10$ ;Branch if we have CMKRNL JSB G^EXE$ABORTIO ;Lose now. RSB ;Done ; Ok - we have CMKRNL. Address check the output buffer. 10$: MOVQ IRP$L_QIO_P1(R3),R0 ;Fetch buffer address and size MOVZWL R1,R1 ;Only 16 bits of size. JSB G^EXE$READCHK ;Make sure we can write in it (no return means no access) ; Now check to make sure that the specificed system space address is Ok. MOVL IRP$L_QIO_P3(R3),R2 ;Fetch system space address to sniff. IFNORD R1,(R2),20$,- ;Lose if it can't be read PRVMOD=#PSL$C_KERNEL ;Force previous mode to kernel. ; Ok - transfer the data. PUSHL R5 ;Keep UCB PUSHL R4 ; PCB PUSHL R3 ; IRP PUSHL R1 ; and length safe MOVC3 R1,(R2),(R0) ;Copy the data POPR #^m ;Restore registers and stash length ASHL #16,R0,R0 ;Shove length over 16 bits. MOVW #SS$_NORMAL,R0 ;Success. JSB G^EXE$FINISHIO ;Done. RSB ; ... ; Here when the system space can't be read. 20$: MOVQ #SS$_ACCVIO,R0 ;Access violation JSB G^EXE$ABORTIO ;Abort the I/O request. RSB ;Done .Page .Subtitle KM_WRITE - Handle write requests ;+ ; ; ----- KM_WRITE: Handle write requests ; ; ; This routine is called to handle write requests. We access ; check the users' buffer, and the proposed system space ; buffer, and if the check passes we copy the data from user ; space to system space. ; ; Environment: ; ; IPL$_ASTDEL, process context, CMKRNL privilege required. ; ; Inputs: ; ; R5 - UCB address ; R4 - PCB address ; R3 - IRP address ; ; QIO P1 - User buffer address ; QIO P2 - User buffer size ; QIO P3 - System space address to copy to. ; ; Outputs: ; ; Data copied if no ACCVIO. ; ;- KM_WRITE: ;Handle write requests .JSB_Entry Input=,- Output=,- Scratch=R2 ; Enforce the need for CMKRNL. MOVL #SS$_NOCMKRNL,R0 ;Presume failure IFPRIV CMKRNL,10$ ;Branch if we have CMKRNL JSB G^EXE$ABORTIO ;Lose now. RSB ;Done ; Ok - we have CMKRNL. Address check the input buffer. 10$: MOVQ IRP$L_QIO_P1(R3),R0 ;Fetch buffer address and size MOVZWL R1,R1 ;Only 16 bits of size. JSB G^EXE$WRITECHK ;Make sure we can read from it (no return means no access) ; Now check to make sure that the specificed system space address is Ok. MOVL IRP$L_QIO_P3(R3),R2 ;Fetch system space address to sniff. IFNOWRT R1,(R2),20$,- ;Lose if it can't be written. PRVMOD=#PSL$C_KERNEL ;Force previous mode to kernel. ; Ok - transfer the data. PUSHL R5 ;Keep UCB PUSHL R4 ; PCB PUSHL R3 ; IRP PUSHL R1 ; and length safe MOVC3 R1,(R0),(R2) ;Copy the data POPR #^m ;Restore registers and stash length ASHL #16,R0,R0 ;Shove length over 16 bits. MOVW #SS$_NORMAL,R0 ;Success. JSB G^EXE$FINISHIO ;Done. RSB ; ... ; Here when the system space can't be written. 20$: MOVQ #SS$_ACCVIO,R0 ;Access violation JSB G^EXE$ABORTIO ;Abort the I/O request. RSB ;Done .Page .Subtitle End of the driver KM_END: ;Mark the end of the driver for SYSGEN .End