“But That’s Impossible in Pascal”

or

Systems Programming in a High-Level Language

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

slide # 1

Topics :

•

Special Requirements of Systems Programming • The System Control Blocks

• A Trivial Example Program

• A Pascal ACP

• Conclusions

slide # 2

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

slide # 4

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 kernel 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

slide # 5

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

slide # 6

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

slide # 7

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

slide # 8

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

slide # 9

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

slide # 10

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

slide # 11

Topics :

• Special Requirements of Systems Programming •

The System Control Blocks

• A Trivial Example Program

• A Pascal ACP

• Conclusions

slide # 12

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

slide # 13

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

slide # 14

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, addressed by index

slide # 16

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

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

slide # 17

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

slide # 19

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

slide # 20

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 operation 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 ;

slide # 22

type

privmask = packed array [0..63] of boolean ; word = 0..65535 ; byte = 0..255 ; pcb ptr = ˆ pcb ; phd ptr = ˆ phd ; jib ptr = ˆ jib ;

slide # 23

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 ;

slide # 24

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 ;

slide # 26

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 ;

slide # 27

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 ;

slide # 29

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

slide # 30

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

slide # 32

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

slide # 33

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 ;

slide # 35

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 ;

slide # 36

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 is 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;

slide # 38

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, nonpaged ucb,interrupt routine address);

end; end ;

slide # 40

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

slide # 42

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

slide # 43

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