“But That’s Impossible in Pascal”

or

Systems Programming in a High-Level Language

E. W. (Wayne) Sewell E-Systems, Garland Division Dallas, Texas Topics :

•

Special Requirements of Systems Programming • The System Control Blocks

• A Trivial Example Program

• A Pascal ACP

• Conclusions Special Requirements of Systems Programming (all require kernel mode) :

• Accessing the nonpaged pool

• Locking the I/O database

• MUTEXes

• Raised IPL

• Access to VMS routines in system space Problems encountered when trying to use kernel mode with high-level languages :

• There are severe restraints placed on code running in kernel

• Access violations are catastrophic for the entire VAX, not just the process—to avoid them the PROBE instruction is used

• Most calls to system routines are via the JSB instruction with parameters in specific registers

• Compiler output cannot be controlled So why not do it in MACRO and be done with it?

• It is tedious to write entire programs in MACRO • Some classes of system programs only need ker-

nel mode at distinct points — the rest of the processing can be done in user mode

• During development, trivial logic errors can crash the entire system So what’s the best way?

• Main program in high-level language with MACRO subroutines (in change-mode-to-kernel dispatcher) for specific operations

• Subroutines are modular, easily debugged, can be reused

• Percentage of time spent in kernel is minimized; during development, exception conditions crash only the process What is a change-mode-to-kernel dispatcher?

• Special type of subroutine library

• Each routine can be specified to run at a particular access mode

• When control is transferred back to calling program, returns to user mode

• Also known as user-written system services Systems programs which are likely candidates for high-level languages:

• Ancillary Control Processes (ACPs)

• Programs which need to run in kernel only briefly, during distinct phases such as input or output, and most processing can be done in user mode Systems programs which are poor candidates for high-level languages:

• Device drivers and other code loaded into system space

• Programs which cannot be implemented as a standard VMS process

• Programs which must run in kernel most of the time Advantages of systems programming in Pascal:

• Programming is easier

• Code running in privileged modes is minimized (fewer system crashes).

• All other advantages of high-level languages over MACRO Disadvantages of systems programming in Pascal:

• Code does not track changes to VMS data structures automatically

• Cannot be used for device drivers or other code with limited process context

• Overhead of change-mode-to-kernel dispatcher Topics :

• Special Requirements of Systems Programming •

The System Control Blocks

• A Trivial Example Program

• A Pascal ACP

• Conclusions System Control Blocks:

• Defined in Pascal with standard record mechanism (must be packed records)

• Referenced with standard Pascal pointer variables

• Two types of System Control Blocks—structured and unstructured Structured System Control Blocks:

• Definition of first 11 bytes is the same for all block types

• First two longwords are forward and backward pointers, used to place block into a queue

• Word following queue pointers (offset 8) contains actual length of block

• Byte following length (offset 10) contains a binary code uniquely identifying block type The record layout for the structured xyz block is defined in Pascal code as:

xyz ptr = ˆ xyz ;

xyz = packed record xyz qfl : xyz ptr ; xyz qbl : xyz ptr ; xyz size : word ; xyz type : byte ; xyz other : byte ; . . . end ; Unstructured System Control Blocks:

• Have no header because they are never queued • Referenced by other means

• Length of block fixed or stored outside of block • Examples:

– I/O buffers—address and length are in IRP – Process Header (PHD)—length fixed, ad-

dressed by index The system control block definitions are extracted from the system macro library via:

$ library/macro/extract=$xyzdef/out=tempfile.dat —

sys$library:lib Before editing:

$equ pcb$w size 8 $equ pcb$b type 10 $equ pcb$b pri 11 $equ pcb$l pid 96

After editing:

pcb$w size : word; pcb$b type : byte; pcb$b pri : byte; pcb$l pid : integer; Topics :

• Special Requirements of Systems Programming • The System Control Blocks •

A Trivial Example Program

• A Pascal ACP

• Conclusions SCANPCB—A Trivial Example Program

• Dumps system control blocks to pas$output

• Uses EXAMPSUBS, example change-mode-to-kernel dispatcher to access nonpaged pool

• Uses standard Pascal write lines to dump contents of Process Control Block (PCB), Process Header (PHD), and Job Information Block (JIB) for current process to terminal There are three routines contained in the example change-mode-to-kernel dispatcher:

• GET MY PCB, which simply returns the address of the process control block (PCB) of the current process

• COPY SYSTEM CONTROL BLOCK, copies one of the

system controls blocks from the nonpaged-pool to process memory space or vice versa using the lengths contained within the control blocks themselves—used for structured blocks

• COPY NONPAGED BUFF, which performs the same

kind  of  a  copy  op-

eration as COPY SYSTEM CONTROL BLOCK, except

that the lengths are explicitly specified—used for unstructured blocks const

prv$v cmkrnl = 0 ; prv$v cmexec = 1 ; prv$v sysnam = 2 ; . . . prv$v security = 38 ; type

privmask = packed array [0..63] of boolean ; word = 0..65535 ; byte = 0..255 ; pcb ptr = ˆ pcb ; phd ptr = ˆ phd ; jib ptr = ˆ jib ; var nonpaged pcb pointer, local pcb pointer : pcb ptr ; nonpaged jib pointer, local jib pointer : jib ptr ; nonpaged phd pointer, local phd pointer : phd ptr ; privnames : array [prv$v cmkrnl..prv$v security]

of varying [30] of char ; function copy nonpaged buff (%immed fl , tl : integer ;

%immed f , t : integer) : integer ; extern ;

function copy system control block (%immed f , t : integer)

: integer ; extern ;

function get my pcb (var p : pcb ptr) : integer ; extern ; procedure init priv names ;

begin privnames[prv$v cmkrnl ] := ’cmkrnl’ ; privnames[prv$v cmexec ] := ’cmexec’ ; . . . privnames[prv$v security ] := ’security’ ; end ; return code := get my pcb (nonpaged pcb pointer) ; new(local pcb pointer) ; local pcb pointerˆ .pcb$w size := size(pcb) ; return code := copy system control block

(nonpaged pcb pointer ::

integer,

local pcb pointer :: integer)

; writeln (’pcb at ’ , hex (nonpaged pcb pointer)) ; writeln ; print pcb ; writeln ; nonpaged jib pointer := local pcb pointerˆ .pcb$l jib ; procedure print pcb ; begin with local pcb pointerˆ do begin

writeln (’pcb$l sqfl = ’ , hex (pcb$l sqfl)) ; writeln (’pcb$b type = ’ , pcb$b type) ; . . . writeln (’pcb$q priv = ’) ; print privs (pcb$q priv) ; writeln ; writeln ; end ;

end ; procedure print privs (privmask : privmask) ;

var

n : integer ;

begin for n := prv$v cmkrnl to prv$v security do

if privmask[n] then

writeln (privnames[n]) ;

end ; The following code returns the address of the Process Control Block of the current process:

pcbaddr = 4

$ent get my pcb
movl r4,@pcbaddr(ap)
movl #ss$ normal,r0
55$: ret

Note: the address of the current PCB is preloaded into register 4 by the dispatcher; it can also be found via @#sch$gl curpcb The following code copies a system control block from the process virtual address space to system space or vice versa. The lengths of the blocks are contained within them.

$ent copy system control block
movl 4(ap),r2
movl 8(ap),r3
movc5 pcb$w size(r2),(r2),#0,pcb$w size(r3),(r3)
movl #ss$ normal,r0
55$: ret

Topics : • Special Requirements of Systems Programming • The System Control Blocks

• A Trivial Example Program •

A Pascal ACP

• Conclusions What is an ACP ?

• Extension of a device driver

• Has full process context with regular P0 memory space

• Can hibernate, wait for event flags, issue system services and perform lower-level I/O

• Driver passes QIOs it cannot handle to ACP via linked-list (queue) in nonpaged pool The functions performed by the ACP include:

• Creating and initializing the ACP Control Block (AQB) and Volume Control Block (VCB) in the non-paged pool.

• Creating and initializing the Unit Control Block (UCB) for each virtual terminal.

• Reading the I/O Request Packets (IRPs) and converting them to Remote Data Packets (RDPs) for transmission over the link.

• Posting the I/O complete when the return RDPs come back from the link In addition to the two block-copy routines listed above for the example program, the following additional routines are contained in the change-mode-to-kernel dispatcher for the ACP:

function allocate acp queue block( var a : aqb ptr) : integer ; extern ;

function allocate volume control block( var v : vcb ptr)

: integer ; extern ;

function get irp from queue( %immed a : aqb ptr; var i : irp ptr); : integer ; extern ; More ACP dispatcher routines:

function add aqb to system( %immed a : aqb ptr; %immed v : vcb ptr; %immed u : ucb ptr) : integer ; extern ;

function post io completion( %immed i : irp ptr; %immed u : ucb ptr; %immed rtn : integer) : integer ; extern ; Still more ACP dispatcher routines:

function create new ucb(%immed tu : ucb ptr ; var nu : ucb ptr) : integer ; extern ;

function kill ucb(var nu : ucb ptr)

: integer ; extern ; This the the main processing loop of the ACP; during each iteration, it either gets another IRP from the ACP queue or another RDP returning from the link.

repeat io performed := false; if link data present

then process link data; if odd(get irp from queue

(nonpaged aqb ptr, nonpaged irp ptr)) then process request packet;

if not io performed then

hibernate until new input;

until dead; This section of code saves the essence of the IRP in the local address space and transmits the RDP across the link:

procedure process request packet; begin io performed := true; return code :=copy system control block

(nonpaged irp ptr :: integer; local irp ptr :: integer);

with local irp ptrˆ do begin from ptr := irp svapte; to ptr := irp buff ptr; return code := copy nonpaged buff

(irp boff,irp boff,from ptr,to ptr); put irp on local queue(irp seqnum); send rdp across link; end;

end ; This routine is executed when the RDP returns from the link and the original QIO is posted complete.

procedure process io completion;

begin locate saved irp; with local irp ptrˆ do begin

from ptr := inbuff; to ptr := irp svapte ; return code :=

copy nonpaged buff(inbuff length ,

inbuff length , from ptr, to ptr); return code :=

post io completion(nonpaged irp ptr,

non-

paged ucb,interrupt routine address);

end; end ; This section of code allocates and initializes an ACP Queue Block (AQB).

return code :=allocate acp queue block(nonpaged aqb ptr);

new(local aqb ptr); with local aqb ptrˆ do

begin

aqb size := aqb$c length; aqb type := dyn$c aqb; aqb mntcnt := 0; aqb acptype := aqb$k rem; aqb acppid := my pid; end;

return code :=copy system control block(local aqb ptr :: integer;

nonpaged aqb ptr :: integer); The following code allocates an AQB in the nonpaged pool, via the allocate nonpaged procedure:

$ent allocate acp queue block,0
pushl 4(ap)
pushl #aqb$c length
calls #2,allocate nonpaged
blbc r0,10$
movl @4(ap),r1
movw #aqb$c length,aqb$w size(r1)
10$: ret

The following code returns the address of the next IRP in the ACP queue, if one is present; if the queue is empty, a warning-level return code is issued.

$ent  get irp from queue
movl  4(ap),r5
beql  59$
remque @(r5),@8(ap)
bvc  10$
59$: movl  #queue is empty,r0

ret

10$: movl  #ss$ normal,r0

ret Topics :

• Special Requirements of Systems Programming • The System Control Blocks

• A Trivial Example Program

• A Pascal ACP

• Conclusions

Conclusions:

• Some classes of systems programs can be implemented in a high-level language

• Systems programs can be made more readable • Development time can be shortened

• System crashes can be reduced during development

• Kernel mode routines (in a change-mode-to-kernel dispatcher) developed for one system program can be used again for another