home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magazyn Exec 3
/
CD_Magazyn_EXEC_nr_3.iso
/
Recent
/
misc
/
emu
/
evax11.lha
/
evax
/
kernel.asm
< prev
next >
Wrap
Assembly Source File
|
2000-01-28
|
55KB
|
1,320 lines
;
; MicroKernel OS for VAX.
;
; This is used to support development and testing of VAX programs.
; It is not a full OS but provides minimal support for basic functions
; like writing output to the console
;
;
; SERVICES SUPPORTED
;
; The microkernel supports a small (but growing!) list of basic VMS
; services. These include some kernel-mode operations such as
; console I/O, some user-mode operations like str*() runtime library
; support, and some "shim" operations that are supported by the
; emulator in lieu of a runtime library, such as the malloc() and
; related routines.
;
;
; HOW TO ADD A USER-MODE ROUTINE
;
; User mode routines don't require special manipulation of the
; processor or use of privileged memory, instructions, etc. There
; is a section below for LIB$ and DECC$ support routines. Simply
; write the entry point as a normal assembler routine.
;
; If you need the runtime to be available to a native VAX/VMS image
; that you plan to run, add an entry in the _second_ section that
; contains .SHIM declarations. These declarations create bindings
; that the image activator uses to link calls to sharable images to
; your code instead. Routines that are written as native VAX code
; (such as DECC$STRCPY, for example) have a shim dispatch code of
; zero.
;
;
; HOW TO ADD A SHIM ROUTINE
;
; A SHIM routine is one that is not written in native VAX code at
; all. Instead, a stub (shim) is created by the pseudo-assembler
; that generates an appropriate XFC instruction. This instruction
; causes the emulator to read the native VAX argument list and
; dispatch to a runtime support routine written in the emulator
; itself. An example of this is DECC$MALLOC(), which is implemented
; by the routine decc_malloc() located in the file librtl_memory.c
;
; You must write the shim routine itself (see any of the librtl*.c
; files for how to read the argument list, access string descriptors
; easily, etc.). Add a prototype for the runtime in shim.h, and
; an entry in the shim dispatch table in "shim.c". Note that there
; is a table entry for each routine, plus a second call that at runtime
; fills in the function pointer value. You must code both parts.
;
; Finally, go to the _first_ section containing .SHIM declarations
; below and add an entry for your routine. The second parameter
; must be the index into the shim table that contains your routine.
;
;
; HOW TO ADD A NEW KERNEL-mode SERVICE
;
; Services have two parts, the user mode part and the kernel mode
; part. The user mode part should validate that the arguments are
; valid for user mode (to prevent calling with Kernel addresses,
; for example) and otherwise check the arguments for correctness.
; Note that for some services (lib$format_dec, for example) the
; entire service runs in user mode and requires no system service.
;
; When it's time to run the portion(s) of the service that must
; run in kernel mode, write the routine as a function. You must
; assume that the user mode part will put it's arguments in
; registers for the call. By convention, R5 is used for the
; argument or the pointer to the arguments as appropriate.
;
; The function should return any information it needs to via
; the argument list by address, and a return code in R0.
;
; Place the address of the kernel handler in the EXE$TABLE
; below. The position in the table must match the kernel mode
; selector that invokes it.
;
; Indicate that we are building the microkernel. This enables a number
; of pseudo directives, etc. and tells the console it can use commands
; like RUN that depend on the microkernel.
.microkernel
; Build the P1 system service vector to support VMS images
.p1vector
;
; We must have the system return codes defined for us
.if defined( "SS$_NORMAL") = 0 .include "ssdef.asm"
; Note that this can only be built if we are in kernel mode. The
; system initializes in kernel mode at IPL 31 to prevent interrupts,
; etc. from occuring. We assume this state for the system to work
; correctly.
.region system
exe$base: .byte 0
;--------------------------------------------------------------------
; CONSOLE TRANSMIT INTERRUPT HANDLER
;--------------------------------------------------------------------
.align 8
exe$tx: movl #1, @#exe$tx_ready
rei
;--------------------------------------------------------------------
; CONSOLE RECIEVE INTERRUPT HANDLER
;--------------------------------------------------------------------
.align 8
exe$rx: pushl r0
pushl r1
mfpr #VAX$PR_RXDB, -(sp)
calls #1, @#EXE$RX_GET
movl (sp)+, r1
movl (sp)+, r0
rei
;--------------------------------------------------------------------
; CHMK EXCEPTION HANDLER
;--------------------------------------------------------------------
.align 8
; Turn the exception into a call. This lets us use registers
; much more easily. The #2 makes the stack a two-element arg
; list. When done with the call, we must discard the #1 and
; the PSL, leaving just the PC for the REI.
exe$chmk: movl r0, @#exe$chmk_r0
movl r1, @#exe$chmk_r1
pushl ap ; Save the AP at time of call
pushl #2
callg sp, @#exe$dispatch
movl @#exe$chmk_r1, r1
moval b^0x0C(sp), sp
rei
;--------------------------------------------------------------------
; ACCVIO EXCEPTION HANDLER
;--------------------------------------------------------------------
.align 8
; Turn the exception into a call. Add the signal value, and
; account for the fault addr, mode, PC, and PSL arguments.
exe$accvio: pushl #SS$_ACCVIO
pushl #5
callg sp, @#exe$signal
moval b^10(sp), sp
moval @#exe$halt, (sp)
rei
;--------------------------------------------------------------------
; RESERVED OPCODE EXCEPTION HANDLER
;--------------------------------------------------------------------
.align 8
; Turn the exception into a call. Add the signal value, and
; account for the PC, and PSL arguments.
exe$resop: pushl #SS$_ROPRAND
pushl #3
callg sp, @#exe$signal
moval b^0C(sp), sp
moval @#exe$halt, (sp)
rei
;--------------------------------------------------------------------
; PRIVILEGED INSTRUCTION EXCEPTION HANDLER
;--------------------------------------------------------------------
.align 8
; Turn the exception into a call. Add the signal value, and
; account for the PC, and PSL arguments.
exe$priv: pushl #SS$_NOPRIV
pushl #3
callg sp, @#exe$signal
moval b^0C(sp), sp
moval @#exe$halt, (sp)
rei
;--------------------------------------------------------------------
; SOFTWARE INTERRUPT 2 (AST HANDLER)
;--------------------------------------------------------------------
.align 8
exe$deliver_ast:nop
_next: remque @#exe$ast_list, r0
bvs _done
pushl r0
pushl r1
pushl r0
calls #1, @#exe$handle_ast
blbc r0, _err
movl (sp)+, r1
movl (sp)+, r0
brb _next
; Handle errors in ast services if needed, and then pop R1 and R0
; before getting out.
_err: movl -(sp), r1
movl -(sp), r0
_done: rei
;--------------------------------------------------------------------
; RESERVED ADDRESSING MODE EXCEPTION HANDLER
;--------------------------------------------------------------------
.align 8
; Turn the exception into a call. Add the signal value, and
; account for the PC, and PSL arguments.
exe$resaddr: pushl #SS$_RADRMOD
pushl #3
callg sp, @#exe$signal
moval b^0C(sp), sp
moval @#exe$halt, (sp)
rei
;--------------------------------------------------------------------
; EXCEPTIONS LAND HERE AFTER FINISHING HANDLER
;--------------------------------------------------------------------
exe$halt: xfc #xfc$halt_silent ; no fault halt
halt ; if you push it, it blows
;--------------------------------------------------------------------
; INTERVAL TIMER HANDLER
;--------------------------------------------------------------------
.align 8
exe$interval: incl @#exe$int_count
mtpr #0FF, #VAX$PR_ICCS
rei
;--------------------------------------------------------------------
; GENERAL SIGNAL HANDLER
;--------------------------------------------------------------------
; This is called when a hardware or software exception occurs.
; At the time of the call, a varying number of arguments are
; on the stack. The last two are always the PC and PSL where
; the fault occurred. The first is always the exception. Any
; in between make up the signal vector.
.entry exe$signal, ^m<r2,r3, r4>
pushal @#_sigmsg
calls #1, @#lib$put_output
movl (ap), r2
movl #1,r4
_sigloop: tstl r2
blss _done
movl #8, @#exe$sig_buff_len
pushl (ap)+
pushl r4
incl r4
pushal _sigfmt
calls #3,decc$printf
decl r2
brb _sigloop
_done: ret
_sigmsg: .ascid "The microkernel has trapped an error. Signal vector:"
_sigfmt: .asciz " %ld %08lX\n"
;--------------------------------------------------------------------
; CHMK SELECTOR DISPATCHER
;--------------------------------------------------------------------
; Here's the real dispatcher. It validates the kernel selector
; value, and if it's okay, generates a call to an address stored
; in the exe$table array. The first argument is the real AP for
; the call, and the second argument is the dispatcher code.
.entry exe$dispatch, ^m<r2,r3>
movl b^8(ap), r2
movl b^4(ap), ap
tstl r2
bgeq _10
movl #SS$_INVARG, r0
brb exe$exit
_10: cmpl r2, @#exe$table_len
blss _20
movl #SS$_INVARG, r0
brb exe$exit
_20: moval @#exe$table, r3
movl (r3)[r2], r0
callg ap, (r0)
exe$exit: ret
;--------------------------------------------------------------------
; CHMK 0 WRITE BYTE TO CONSOLE
;--------------------------------------------------------------------
.set EXE$PUT_CONSOLE 0
.entry exe$$put_console
; First, see if the device is ready or not. This is set
; by the ready interrupt service routine when a byte is
; successsfully written.
_wait: tstl @#exe$tx_ready
beql _wait
; Mark the device as busy, and write a byte to it.
clrl @#exe$tx_ready
mtpr r5, #VAX$PR_TXDB
movl #SS$_NORMAL, r0
ret
;--------------------------------------------------------------------
; CHMK 1 READ BYTE FROM CONSOLE
;--------------------------------------------------------------------
.set EXE$GET_CONSOLE 2
.entry exe$$get_console
mfpr #VAX$PR_RXDB, r0
ret
;--------------------------------------------------------------------
; CHMK 3 READ BUFFER FROM FILE
;--------------------------------------------------------------------
; AP points to a legitimate argument block.
;
; 4(AP) file id (ignored for now, assume console)
; 8(AP) address of buffer to write
; 12(AP) length of buffer to write
;
.set EXE$GET_FILE 3
.entry exe$$get_file, ^m<r2>
moval b^0f0(sp),sp ; Make automatic storage
movl b^08(ap),b^0FC(fp) ; addr part of descriptor
movl b^0c(ap),b^0F8(fp) ; len part of descriptor
clrl B^0f4(fp) ; space to write length
pushal b^0f4(fp) ; addr of length
pushl #0 ; no prompt
pushal b^0f8(fp) ; addr of descriptor
calls #3, @#LIB$GET_INPUT
movl b^0f4(fp), r0 ; Get length
movl b^08(ap), r2 ; Get buffer addr
clrb (r2)[r0] ; Null terminate it
ret ; And return length in R0
;--------------------------------------------------------------------
; CHMK 4 WRITE BUFFER TO FILE
;--------------------------------------------------------------------
; AP points to a legitimate argument block.
;
; 4(AP) file id (ignored for now, assume console)
; 8(AP) address of buffer to write
; 12(AP) length of buffer to write
;
.set EXE$PUT_FILE 4
.entry exe$$put_file
pushl b^08(ap) ; addr part of descriptor
pushl b^0c(AP) ; len part of descriptor
pushl sp ; Make addr of descriptor on stack
calls #1, @#lib$put_one
ret
;--------------------------------------------------------------------
; CHMK SELECTOR FUNCTION DISPATCH TABLE
;--------------------------------------------------------------------
; This is the dispatch table. There must be a entry point
; address in each slot that is in the table.
exe$table: .long exe$$put_console ; CHMK 0
.long exe$halt ; CHMK 1 - Halt emulation
.long exe$$get_console ; CHMK 2
.long decc$read ; CHMK 3 - direct to SHIM
.long decc$write ; CHMK 4 - direct to SHIM
.long decc$open ; CHMK 5 - direct to SHIM
.long decc$close ; CHMK 6 - direct to SHIM
; Store the length in longwords of the table
exe$table_len: .long ( . - exe$table ) / 4
;--------------------------------------------------------------------
; AST HANDLER
;--------------------------------------------------------------------
; This is called by the AST interrupt handler to process an
; item that had been queued up for AST delivery. The single
; parameter is the AST control block. The first two longwords
; are undefined (part of the AST queue block). The remaining
; data after the linkages are where the AST data resides.
.entry exe$handle_ast
ret
;--------------------------------------------------------------------
; CONSOLE READ A BYTE
;--------------------------------------------------------------------
; This is called by the CONREAD interrupt handler to process a
; single byte of data, passed as the parameter to this routine.
; We file this away in the console read buffer.
.entry exe$rx_get
cmpl #100,@#exe$rxlen
beql _done
incl @#exe$rxlen
movl @#exe$rxptr, r0
movb b^4(ap),(r0)+
movl r0,@#exe$rxptr
_done: ret
;--------------------------------------------------------------------
; KERNEL INITIALIZATION
;--------------------------------------------------------------------
; This is called by the vax.init file after the kernel is built.
; This completes the runtime initialization of the system. Put
; things here that you want to have built by the VAX as opposed
; to the assembler. You must GO this code, not CALL it because
; the console CALL code will screw up the registers on the RET
; instruction.
exe$initialize: tstl @#exe$init_done ; If we've already done
bneq exe$init_exit ; this, just return
; Set the bit in the TXCS register that says to interrupt
; us when the data is successfully written. This will cause
; the EXE$TX interrupt handler to be hit again, which resets
; our internal ready flag at exe$tx_ready.
mtpr #40,#VAX$PR_TXCS
; Similarly, let's indicate that we accept interrupts for the
; console input.
mtpr #40,#VAX$PR_RXCS
; We want an interval timer interrupt every 500 instructions
; or so. Currently the ICR is based on instructions, not real
; time (this is a must-fix for later).
mcoml #^d500, r0
mtpr r0, #VAX$PR_NICR
; Now that NICR is set up, turn on interrupts, and reload the
; ICR from the NICR.
mtpr #0ff,#VAX$PR_ICCS
; Mark the flag that says we're done
movl #1, @#exe$init_done
; We've got to get out of kernel mode. To do this at runtime,
; we fake out a REI instruction. Push the desired PSL and PC
; on the stack and do an REI. This will take us to the exit
; point, in user mode with IPL of zero (so interrupts will
; start happening).
pushl #03000000 ; desired PSL
pushal @#exe$init_exit ; desired PC
rei ; do it
; This is the exit point from the initialization routine.
exe$init_exit: pushl #0a
pushl #0d
pushal @#exe$init_msg
calls #3, @#LIB$PUT_OUTPUT
halt
; Let's protect the dispatcher so that you can't even read/see it
; unless you are in kernel mode. This keeps prying eyes out of
; the system. But, we can't do it yet because doing so would prevent
; forward references to fix up in the assembler. So, save where we
; are and use it later.
.set exe$end .
; Because of that, we need to be sure to start on a new boundary.
.align 0200
.set exe$ubase .
;--------------------------------------------------------------------
; USER MODE FRONT-END TO SYSTEM SERVICES
;--------------------------------------------------------------------
;
; Write a list of items, passed as parameters via standard calling
; conventions. Each item is passed to lib$put_output() as a single
; item for output.
;
.entry lib$put_output, ^m<r3,r4>
movl (ap), r3 ; Count of arguments
tstl r3 ; Are there any?
beql _exit ; No, we're done
addl3 #4, ap, r4 ; Yes, find first one
_loop: pushl (r4)+ ; push the parameter
calls #1, @#lib$put_one ; call output
sobgtr r3, _loop ; loop if more
pushl #0a ; else end with LF
calls #1, @#lib$put_one
pushl #0d ; and CR
calls #1, @#lib$put_one
movl #1, r0 ; now done
ret
_exit: movl #1, r0
ret
; LIB$PUT_ONE( struct dsc$descriptor_s * msg );
.entry lib$put_one, ^m<r2,r3,r4,r5,r6>
movl b^4(ap), r5 ; Get descriptor address
cmpl r5, #0ff ; see if it's one char.
blequ _byte ; if so, print it
clrl r6 ; Empty counter register
movw (r5), r6 ; Get count word from desc
beql _exit ; If zero, then no work
movl b^4(r5), r2 ; Else get address
clrl r4 ; Clear data register
_loop: movb (r2)+, r5 ; Get byte, advance ptr
chmk #EXE$PUT_CONSOLE ; Output single byte
blbc r0, _errexit ; If bad RC, done
sobgtr r6, _loop ; Decrement counter, rpt
brb _exit
_byte: chmk #EXE$PUT_CONSOLE ; Output single byte in R5
blbc r0, _errexit ; If bad RC, done
_exit: movl #SS$_NORMAL, r0 ; Signal success
_errexit: ret ; And flee
; rc = LIB$GET_INPUT( DESCRIPTOR * buff [, DESCRIPTOR * prompt [, short * len ]]);
.entry lib$get_input, ^m<r2,r3,r4>
movl b^4(ap), r2 ; Address of descriptor
movl b^8(ap), r3 ; Address of prompt
tstl r3
beql _get ; If no prompt, skip it
pushl r3
calls #1, lib$put_one ; Else put out prompt
_get: cvtwl (r2),r4 ; Get length
pushl r4 ; push length of buffer
pushl b^4(r2) ; push address of buffer
calls #2,exe$input ; Get input from user
movl b^0c(ap), r3 ; Get address of length
tstl r3
beql _done
cvtlw r0, (r3) ; Write length to caller
_done: movl #SS$_NORMAL, r0
ret
; len = LIB$FORMAT_DEC( long value, char * buffer, long *size );
.entry lib$format_dec, ^m<r2,r3,r4,r5,r6,r7,r8, r9>
;
; We're going to allocate some stack space. So move the SP down to
; prepare room for it.
subl2 #4,sp
movl b^0C(ap), r9 ; Get length pointer
movl b^4(ap), r2 ; Get the value to format
tstl r2 ; Is it zero?
beql _zero ; If so, special case
;
; Allocate some "automatic storage" on the stack by marking where we
; are (since we want the end of the buffer anyway) and move the SP
; down in case we need it for something else.
;
movl sp,r6 ; Point to end of space
subl2 r9, sp ; and move end of stack down
; by size of user's buffer
clrl r7 ; init the counter
_loop: divl3 #^d10, r2, r3 ; Shift off digit
mull3 r3, #^d10, r4 ; And back again
subl3 r4, r2, r5 ; Difference is digit
addl2 #30, r5 ; Make ASCII
movb r5, -(r6) ; copy to buffer, decrement
incl r7 ; and increment counter
cmpl r7, (r9) ; too big?
bgtr _oflow ; yes, bail out
tstl r4 ; Is there more?
beql _exit ; No, done
movl r3, r2 ; Yes, set it up
brb _loop ; And loop again
_oflow: movl #SS$_BUFFEROVF, r0 ; Return overflow
ret
_zero: movl sp, r6 ; Get address of stack buffer
movb #30, (r6) ; Write "0" to buffer
movl #1, r7 ; return length of 1
_exit: movl b^8(ap), r8 ; Get address of buffer
movc3 r7, (r6), (r8) ; Copy to user's buffer
movl b^0c(ap),r8
movl r7, (r8) ; and return the length
movl #SS$_NORMAL, r0 ; signal success
ret ; Go home.
; len = LIB$FORMAT_HEX( long value, char * buffer, long *size );
.entry lib$format_hex, ^m<r2,r3,r4,r5,r6,r7,r8, r9>
;
; We're going to allocate some stack space. So move the SP down to
; prepare room for it.
subl2 #4,sp
moval @#lib$hex_table, r8 ; get address of table
movl b^0C(ap), r9 ; Get length pointer
movl b^4(ap), r2 ; Get the value to format
tstl r2 ; Is it zero?
beql _zero ; If so, special case
;
; Allocate some "automatic storage" on the stack by marking where we
; are (since we want the end of the buffer anyway) and move the SP
; down in case we need it for something else.
;
movl sp,r6 ; Point to end of space
subl2 (r9), sp ; and move end of stack down
; by size of user's buffer
clrl r7 ; init the counter
_loop: divl3 #^d16, r2, r3 ; Shift off digit
mull3 r3, #^d16, r4 ; And back again
subl3 r4, r2, r5 ; Difference is digit
movb (r8)[r5],-(r6) ; Look up in table to make HEX,
; copy to buffer, decrement
incl r7 ; and increment counter
cmpl r7, (r9) ; too big?
bgtr _oflow ; yes, bail out
tstl r4 ; Is there more?
beql _exit ; No, done
movl r3, r2 ; Yes, set it up
brb _loop ; And loop again
_oflow: movl #SS$_BUFFEROVF, r0 ; Return overflow
ret
_zero: movl sp, r6 ; Get address of stack buffer
movb #30, (r6) ; Write "0" to buffer
movl #1, r7 ; return length of 1
_exit: movl b^8(ap), r8 ; Get address of buffer
movc3 r7, (r6), (r8) ; Copy to user's buffer
movl b^0c(ap),r8
movl r7, (r8) ; and return the length
movl #SS$_NORMAL, r0 ; signal success
ret ; Go home.
;--------------------------------------------------------------------
; DECC$SHR runtime support
;--------------------------------------------------------------------
; *** Note that the MAIN entry initialization is via JSB not CALL
decc$main: nop ; Currently, no work done.
rsb
.entry decc$exit
nop
ret
.entry cma$tis_errno_get_addr, ^m<>
moval @#vaxc$errno, r0
ret
.entry decc$calloc, ^m<r2,r3>
mull3 b^4(ap),b^8(ap), r3 ; How much storage?
pushl r3
calls #1, @#decc$malloc ; Get the storage
tstl r0 ; If no memory, done
beql _done
movl r0,r2
_zero: clrb (r2)+ ; Clear byte
sobgtr r3, _zero ; for as many bytes as needed
_done: ret ; Done
.entry decc$strcat, ^m<r2>
pushl b^4(ap) ; Find length of dst
calls #1, @#decc$strlen
addl3 b^4(ap), r0, r2 ; Add to addr of dst
pushl b^8(ap) ; push src
pushl r2 ; and dst
calls #2, @#decc$strcpy ; and copy there
addl2 r2,r0 ; return total length
ret
.entry decc$strcpy, ^m<r2,r3>
movl b^4(ap), r2
movl b^8(ap), r3
clrl r0
_loop: movb (r3),(r2)
tstb (r2)
beql _done
incl r0
incl r2
incl r3
brb _loop
_done: ret
.entry decc$strlen, ^m<r2>
movl b^4(ap), r2
clrl r0
_loop: tstb (r2)
beql _done
incl r0
incl r2
brb _loop
_done: ret
; Table to support inline "ctype" operations like isupper, etc. This will be
; used at runtime if the ctypea flag indicates the table is available.
decc$$gl___ctypea:
.long 1 ; CTYPE table is available. If set to zero,
; then the storage for the table can be
; reclaimed for some other purpose.
decc$$ga___ctypet:
long ctype_table ; Address of the type table found here
; Actual table starts here
ctype_table: .long ^X00000020 ; 00
.long ^X00000020 ; 01
.long ^X00000020 ; 02
.long ^X00000020 ; 03
.long ^X00000020 ; 04
.long ^X00000020 ; 05
.long ^X00000020 ; 06
.long ^X00000020 ; 07
.long ^X00000020 ; 08
.long ^X00000428 ; 09
.long ^X00000028 ; 0A
.long ^X00000028 ; 0B
.long ^X00000028 ; 0C
.long ^X00000028 ; 0D
.long ^X00000020 ; 0E
.long ^X00000020 ; 0F
.long ^X00000020 ; 10
.long ^X00000020 ; 11
.long ^X00000020 ; 12
.long ^X00000020 ; 13
.long ^X00000020 ; 14
.long ^X00000020 ; 15
.long ^X00000020 ; 16
.long ^X00000020 ; 17
.long ^X00000020 ; 18
.long ^X00000020 ; 19
.long ^X00000020 ; 1A
.long ^X00000020 ; 1B
.long ^X00000020 ; 1C
.long ^X00000020 ; 1D
.long ^X00000020 ; 1E
.long ^X00000020 ; 1F
.long ^X00000488 ; 20
.long ^X00000290 ; 21
.long ^X00000290 ; 22
.long ^X00000290 ; 23
.long ^X00000290 ; 24
.long ^X00000290 ; 25
.long ^X00000290 ; 26
.long ^X00000290 ; 27
.long ^X00000290 ; 28
.long ^X00000290 ; 29
.long ^X00000290 ; 2A
.long ^X00000290 ; 2B
.long ^X00000290 ; 2C
.long ^X00000290 ; 2D
.long ^X00000290 ; 2E
.long ^X00000290 ; 2F
.long ^X000002C4 ; 30
.long ^X000002C4 ; 31
.long ^X000002C4 ; 32
.long ^X000002C4 ; 33
.long ^X000002C4 ; 34
.long ^X000002C4 ; 35
.long ^X000002C4 ; 36
.long ^X000002C4 ; 37
.long ^X000002C4 ; 38
.long ^X000002C4 ; 39
.long ^X00000290 ; 3A
.long ^X00000290 ; 3B
.long ^X00000290 ; 3C
.long ^X00000290 ; 3D
.long ^X00000290 ; 3E
.long ^X00000290 ; 3F
.long ^X00000290 ; 40
.long ^X000003C1 ; 41
.long ^X000003C1 ; 42
.long ^X000003C1 ; 43
.long ^X000003C1 ; 44
.long ^X000003C1 ; 45
.long ^X000003C1 ; 46
.long ^X00000381 ; 47
.long ^X00000381 ; 48
.long ^X00000381 ; 49
.long ^X00000381 ; 4A
.long ^X00000381 ; 4B
.long ^X00000381 ; 4C
.long ^X00000381 ; 4D
.long ^X00000381 ; 4E
.long ^X00000381 ; 4F
.long ^X00000381 ; 50
.long ^X00000381 ; 51
.long ^X00000381 ; 52
.long ^X00000381 ; 53
.long ^X00000381 ; 54
.long ^X00000381 ; 55
.long ^X00000381 ; 56
.long ^X00000381 ; 57
.long ^X00000381 ; 58
.long ^X00000381 ; 59
.long ^X00000381 ; 5A
.long ^X00000290 ; 5B
.long ^X00000290 ; 5C
.long ^X00000290 ; 5D
.long ^X00000290 ; 5E
.long ^X00000290 ; 5F
.long ^X00000290 ; 60
.long ^X000003C2 ; 61
.long ^X000003C2 ; 62
.long ^X000003C2 ; 63
.long ^X000003C2 ; 64
.long ^X000003C2 ; 65
.long ^X000003C2 ; 66
.long ^X00000382 ; 67
.long ^X00000382 ; 68
.long ^X00000382 ; 69
.long ^X00000382 ; 6A
.long ^X00000382 ; 6B
.long ^X00000382 ; 6C
.long ^X00000382 ; 6D
.long ^X00000382 ; 6E
.long ^X00000382 ; 6F
.long ^X00000382 ; 70
.long ^X00000382 ; 71
.long ^X00000382 ; 72
.long ^X00000382 ; 73
.long ^X00000382 ; 74
.long ^X00000382 ; 75
.long ^X00000382 ; 76
.long ^X00000382 ; 77
.long ^X00000382 ; 78
.long ^X00000382 ; 79
.long ^X00000382 ; 7A
.long ^X00000290 ; 7B
.long ^X00000290 ; 7C
.long ^X00000290 ; 7D
.long ^X00000290 ; 7E
.long ^X00000020 ; 7F
.long ^X00000000 ; 80
.long ^X00000000 ; 81
.long ^X00000000 ; 82
.long ^X00000000 ; 83
.long ^X00000020 ; 84
.long ^X00000020 ; 85
.long ^X00000020 ; 86
.long ^X00000020 ; 87
.long ^X00000020 ; 88
.long ^X00000020 ; 89
.long ^X00000020 ; 8A
.long ^X00000020 ; 8B
.long ^X00000020 ; 8C
.long ^X00000020 ; 8D
.long ^X00000020 ; 8E
.long ^X00000020 ; 8F
.long ^X00000020 ; 90
.long ^X00000020 ; 91
.long ^X00000020 ; 92
.long ^X00000020 ; 93
.long ^X00000020 ; 94
.long ^X00000020 ; 95
.long ^X00000020 ; 96
.long ^X00000020 ; 97
.long ^X00000000 ; 98
.long ^X00000000 ; 99
.long ^X00000000 ; 9A
.long ^X00000020 ; 9B
.long ^X00000020 ; 9C
.long ^X00000020 ; 9D
.long ^X00000020 ; 9E
.long ^X00000020 ; 9F
.long ^X00000000 ; A0
.long ^X00000290 ; A1
.long ^X00000290 ; A2
.long ^X00000290 ; A3
.long ^X00000000 ; A4
.long ^X00000290 ; A5
.long ^X00000000 ; A6
.long ^X00000290 ; A7
.long ^X00000290 ; A8
.long ^X00000290 ; A9
.long ^X00000290 ; AA
.long ^X00000290 ; AB
.long ^X00000000 ; AC
.long ^X00000000 ; AD
.long ^X00000000 ; AE
.long ^X00000000 ; AF
.long ^X00000290 ; B0
.long ^X00000290 ; B1
.long ^X00000290 ; B2
.long ^X00000290 ; B3
.long ^X00000000 ; B4
.long ^X00000290 ; B5
.long ^X00000290 ; B6
.long ^X00000290 ; B7
.long ^X00000000 ; B8
.long ^X00000290 ; B9
.long ^X00000290 ; BA
.long ^X00000290 ; BB
.long ^X00000290 ; BC
.long ^X00000290 ; BD
.long ^X00000000 ; BE
.long ^X00000290 ; BF
.long ^X00000290 ; C0
.long ^X00000290 ; C1
.long ^X00000290 ; C2
.long ^X00000290 ; C3
.long ^X00000290 ; C4
.long ^X00000290 ; C5
.long ^X00000290 ; C6
.long ^X00000290 ; C7
.long ^X00000290 ; C8
.long ^X00000290 ; C9
.long ^X00000290 ; CA
.long ^X00000290 ; CB
.long ^X00000290 ; CC
.long ^X00000290 ; CD
.long ^X00000290 ; CE
.long ^X00000290 ; CF
.long ^X00000000 ; D0
.long ^X00000290 ; D1
.long ^X00000290 ; D2
.long ^X00000290 ; D3
.long ^X00000290 ; D4
.long ^X00000290 ; D5
.long ^X00000290 ; D6
.long ^X00000290 ; D7
.long ^X00000290 ; D8
.long ^X00000290 ; D9
.long ^X00000290 ; DA
.long ^X00000290 ; DB
.long ^X00000290 ; DC
.long ^X00000290 ; DD
.long ^X00000000 ; DE
.long ^X00000290 ; DF
.long ^X00000290 ; E0
.long ^X00000290 ; E1
.long ^X00000290 ; E2
.long ^X00000290 ; E3
.long ^X00000290 ; E4
.long ^X00000290 ; E5
.long ^X00000290 ; E6
.long ^X00000290 ; E7
.long ^X00000290 ; E8
.long ^X00000290 ; E9
.long ^X00000290 ; EA
.long ^X00000290 ; EB
.long ^X00000290 ; EC
.long ^X00000290 ; ED
.long ^X00000290 ; EE
.long ^X00000290 ; EF
.long ^X00000000 ; F0
.long ^X00000290 ; F1
.long ^X00000290 ; F2
.long ^X00000290 ; F3
.long ^X00000290 ; F4
.long ^X00000290 ; F5
.long ^X00000290 ; F6
.long ^X00000290 ; F7
.long ^X00000290 ; F8
.long ^X00000290 ; F9
.long ^X00000290 ; FA
.long ^X00000290 ; FB
.long ^X00000290 ; FC
.long ^X00000290 ; FD
.long ^X00000000 ; FE
.long ^X00000000 ; FF
;--------------------------------------------------------------------
; SOFTWARE SHIM DEFINITIONS FOR XFC EXITS
;
; The first parameter is the local entry point name, that can be
; called by assembler code, etc.
;
; The second parameter defines the function code in the XFC handler
; as defined in "shim.c"
;
; The third parameter is the name of the sharable image that this
; routine is a shim for. This is used by the RUN command's image
; activator to map runtime libraries to families of shims.
;
; The fourth parameter is the offset in the sharable image of the
; real sharable image that supports this routine. This is used by
; the image activator to bind a specific sharable image .ADDRESS
; or G^ references to this shim entry.
;
;--------------------------------------------------------------------
.align 8
; ------------ ----- -------- ------
; Entry Name ID RTL Offset
; ------------ ----- -------- ------
.shim lib$adawi, ^d1, LIBRTL, 0778
.shim str$upcase, ^d2, LIBRTL, 0A70
.shim exe$input, ^d3, EVAX, 0004
.shim decc$open, ^d4, DECC$SHR, 04E8
.shim decc$close, ^d5, DECC$SHR, 0490
.shim decc$read, ^d6, DECC$SHR, 04F0
.shim decc$write, ^d7, DECC$SHR, 0508
.shim decc$printf, ^d8, DECC$SHR, 0380
.shim decc$sprintf, ^d9, DECC$SHR, 03E0
.shim decc$strcmp, ^d10, DECC$SHR, 06C0
.shim decc$strncmp, ^d11, DECC$SHR, 06F8
.shim decc$strncpy, ^d12, DECC$SHR, 0700
.shim decc$atoi, ^d13, DECC$SHR, 0568
.shim decc$gets, ^d14, DECC$SHR, 0370
.shim decc$malloc, ^d15, DECC$SHR, 0548
.shim decc$free, ^d16, DECC$SHR, 0538
.shim decc$isalnum, ^d17, DECC$SHR, 0018
.shim decc$isalpha, ^d18, DECC$SHR, 0020
.shim decc$iscntrl, ^d19, DECC$SHR, 0030
.shim decc$isdigit, ^d20, DECC$SHR, 0038
.shim decc$isgraph, ^d21, DECC$SHR, 0040
.shim decc$islower, ^d22, DECC$SHR, 0048
.shim decc$isprint, ^d23, DECC$SHR, 0050
.shim decc$ispunct, ^d24, DECC$SHR, 0058
.shim decc$isspace, ^d25, DECC$SHR, 0060
.shim decc$isupper, ^d26, DECC$SHR, 0068
.shim decc$isxdigit, ^d27, DECC$SHR, 0070
.shim decc$isascii, ^d28, DECC$SHR, 0028
.shim lib$get_vm, ^d29, LIBRTL, 0550
.shim lib$free_vm, ^d30, LIBRTL, 0548
.shim lib$delete_vm_zone, ^d31, LIBRTL, 0A48
.shim decc$time, ^d32, DECC$SHR, 0768
; ------------ ----- -------- ------
; Entry Name ID RTL Offset
; ------------ ----- -------- ------
.set exe$uend .
;--------------------------------------------------------------------
; WRITABLE STORAGE AREA FOR KERNEL
;--------------------------------------------------------------------
; This is the kernel writable data area. It has different page
; attributes so it must be aligned on a new page boundary.
.align 0200
.set exe$wbase .
exe$tx_ready: .long 1 ; Is TXCS available?
exe$rx_ready: .long 0 ; Is RXCS available?
exe$init_done: .long 0 ; Is kernel initialized?
exe$int_count: .long 0 ; Interval timer count
exe$ast_list: .long exe$ast_list ; Head of AST queue
.long exe$ast_list
; Register Save Areas
exe$chmk_r0: .long 0
exe$chmk_r1: .long 0
; Region handlers
exe$p0_rgn: .long 0
exe$p1_rgn: .long 0
exe$s0_rgn: .long 0
; Console input stuff
exe$rxdata: .blkb 100
exe$rxptr: .long exe$rxdata
exe$rxlen: .long 0
vaxc$errno: .long 0
; Message descriptors
exe$init_msgb: .ascii "Kernel initialized..."
.byte 0a,0d
exe$init_msg: .long . - exe$init_msgb
.long exe$init_msgb
exe$sig_buff: .blkb 10
exe$sig_desc:
exe$sig_buff_len:.long 8
.long exe$sig_buff
; Storage used by LIBRTL replacements
lib$hex_table:
.ascii "0123456789ABCDEF"
decc$gl_opterr: .long 0 ; These are static owned storage
decc$gl_optind: .long 0 ; that support the getopt()
decc$gl_optopt: .long 0 ; runtime routine. They are
decc$ga_optarg: .long optarg_buff ; usually .ADDRESS fixups in images
optarg_buff: .long 0 ; actual buffer pointer goes here
decc$ga_stdin: .long 0 ; The stdin handle goes here
decc$ga_stdout: .long 0 ; the stdout handle goes here
decc$ga_stderr: .long 0 ; the stderr handle goes here
.set exe$wend .
.align 200
.set exe$fbase .
;
; I've been playing around with a forth interpreter written back in 1984
; for a VAX. It might be interesting to include it in the microkernel
; for handling logic at the virtual VAX level. If the interpreter source
; is present, assemble it as well.
; .if file_exists("forth.asm") .include "forth.asm"
nop
.set exe$fend .
;--------------------------------------------------------------------
; SOFTWARE SHIM DEFINITIONS FOR NATIVE KERNEL ROUTINES
;
; NOTE that this is placed after the writable storage area, because
; some of the shim values point to storage locations there, rather
; than just routine entry points in the readonly part of the kernel.
;
; They have to be here, because .SHIM cannot tolerate a forward
; reference in the symbol name.
;
; The first parameter is the local entry point name, that can be
; called by assembler code, etc.
;
; The second parameter of 0 means the routine is implemented in the
; microkernel and doesn't need a native runtime XFC stub.
;
; The third parameter is the name of the sharable image that this
; routine is a shim for. This is used by the RUN command's image
; activator to map runtime libraries to families of shims.
;
; The fourth parameter is the offset in the sharable image of the
; real sharable image that supports this routine. This is used by
; the image activator to bind a specific sharable image .ADDRESS
; or G^ references to this shim entry.
;
;--------------------------------------------------------------------
.shim lib$put_output, 0, LIBRTL, 0478
.shim decc$main, 0, DECC$SHR, 0000
.shim decc$exit, 0, DECC$SHR, 0528
.shim decc$strlen, 0, DECC$SHR, 06E8
.shim decc$strcpy, 0, DECC$SHR, 06D0
.shim decc$strcat, 0, DECC$SHR, 06B0
.shim cma$tis_errno_get_addr, 0, CMA$TIS_SHR, 0038
.shim decc$calloc, 0, DECC$SHR, 0520
.shim decc$$ga___ctypet, 0, DECC$SHR, 309C
.shim decc$$gl___ctypea, 0, DECC$SHR, 3098
.shim decc$gl_optopt, 0, DECC$SHR, 306C
.shim decc$gl_optind, 0, DECC$SHR, 3068
.shim decc$gl_opterr, 0, DECC$SHR, 3064
.shim decc$ga_optarg, 0, DECC$SHR, 3070
.shim decc$ga_stdin, 0, DECC$SHR, 2018
.shim decc$ga_stdout, 0, DECC$SHR, 201C
.shim decc$ga_stderr, 0, DECC$SHR, 2020
;--------------------------------------------------------------------
; RESET STATE FOR CONSOLE ASSEMBLER
;--------------------------------------------------------------------
; This section takes care of miscellanous housekeeping.
; Define the exception handlers in the SCB and make the
; entire kernel area protected from being written on.
;
; Note that for many of these, we define "console$handler"
; as the handler. This equates to -1, and causes the emulator
; to report on the exception using non-VAX native code, and
; halts the emulation. Later, this handler will also be
; able to chase user-mode stack frames looking for exception
; handlers.
.scb exc$chmk, exe$chmk
.scb exc$priv, console$handler ; exe$priv
.scb exc$accvio, console$handler ; exe$accvio
.scb exc$resop, console$handler ; exe$resop
.scb exc$resaddr, console$handler ; exe$resaddr
.scb exc$interval, exe$interval
.scb exc$software2, exe$deliver_ast
.scb exc$conwrite, exe$tx
.scb exc$conread, exe$rx
; Set page protections on the segments of the kernel. This MUST
; be done after all symbol fixups are generated, because the
; microassembler is forced to abide by page table protections.
.console set page exe$ubase to exe$uend prot=pte$k_ur
.console set page exe$base to exe$end prot=pte$k_ur
.console set page exe$wbase to exe$wend prot=pte$k_kwur
.console set page exe$fbase to exe$fend prot=pte$k_all
; All done, let's set the console back so user assembly can
; occur normally
.region p0