;----------------------------------------------------------------------
;
;   LOCKR - This file, in combination with LOCK, is a demonstration
;	of a Resident System Extension (RSX) under CP/M 3. The RSX
; 	returns an empty string for calls to the "Read Line" BDOS
;	call until the correct password is entered. This effectively
;	disables command line input. When the correct password is
;	entered, the RSX sets theremove flag true so the CCP
;	disables/removes the RSX.
;
;	This file is the RSX itself.
;
;   Mike Douglas, 06/11/19
;
;   Assemble with RMAC
;	A>RMAC LOCK
;	A>RMAC LOCKR
;
;   Link to a .COM file and to a page relocatable file ([OP] option)
;	A>LINK LOCK
;	A>LINK LOCKR [OP]
;
;   Rename LOCKR.PRL to LOCKR.RSX
;	A>REN LOCKR.RSX=LOCKR.PRL
;
;   Create the executable file by combining the startup .COM and
;   and the .RSX files
;	A>GENCOM LOCK LOCKR
;
;----------------------------------------------------------------------

WBOOT	equ	0		;warm boot jump vector
BDOS	equ	5		;BDOS entry jump vector
WRTLINE	equ	9		;BDOS write a line to the console
RDLINE	equ	10		;BDOS read a line from the console

CR	equ	13		;ASCII carriage return
LF	equ	10		;ASCII line feed

	cseg
;-----------------------------------------------------------------------
; RSX Prefix
;-----------------------------------------------------------------------
rsxSer	db	0,0,0,0,0,0	;CCP puts the CP/M serial number here
rsxStrt	jmp	funcTst		;entry point of RSX
rsxNext	db	JMP,0,0		;filled in with next RSX in chain
rsxPrev	db	0,0		;filled in with previous RSX in chain
rsxFlag	db	0		;remove flag (0FFh=remove)
rsxBank	db	0		;load for banked and unbanked systems
rsxName	db	'LOCKRSX '	;8 character name
rxlLoad	db	0		;0FFh if this is the CCP loader
	db	0,0		;reserved

;-----------------------------------------------------------------------
; funcTst - entry to the RSX. If this is not a BDOS read line
;    request, then pass the request to the next RSX in line.
;    Otherwise, call the BDOS to perform a read line and see
;    what the user typed. If it matches the password in strPass,
;    then remove the RSX and warm start. Otherwise, return a
;    empty string to the caller.
;-----------------------------------------------------------------------
funcTst	mov	a,c		;is this a read line request?
	cpi	RDLINE
	jnz	rsxNext		;no, pass control to next RSX

	lxi	h,0		;save stack pointer
	dad	sp
	shld	stkSave

	lxi	sp,lclStk	;switch to local stack
	push	d		;save DE->input buffer
	call	rsxNext		;issue RDLINE request

	pop	d		;DE->input buffer
	call	cmpPass		;compare to password
	jz	unlock		;match, unlock the computer

; Not the password, return empty string to the caller

	inx	d		;DE->length of data input
	xra	a		;set to zero
	stax	d

	lhld	stkSave		;restore original stack pointer
	sphl
	ret			;and exit

; Correct password entered, display "Console Enabled" message and
;    set the rsxFlag true so that the CCP disables/removes this
;    RSX when we exit by forcing a warm boot.

unlock	lxi	d,mEnable	;DE = address of "enabled" message
	mvi	c,WRTLINE	;C = BDOS write line command
	call	rsxNext		;display the message

	mvi	a,0FFh		;set RSX remove flag to remove us
	sta	rsxFlag
	jmp	WBOOT		;exit with warm boot to remove RSX

;-----------------------------------------------------------------------
; cmpPass - compare string in BDOS "read line" format pointed to
;     by DE to strPass. Returns Z true if equal, false if not.
;     Preserves DE.
;-----------------------------------------------------------------------
cmpPass	push	d		;save DE

	lxi	h,strPass	;HL->password string
	inx	d		;DE->length read

	mov	b,m		;B=length of password string
	inr	b		;include length byte

cmpLoop	ldax	d		;A=byte from user
	cmp	m		;same as password?
	jnz	cmpExit		;no

	inx	d		;bump pointers
	inx	h
	dcr	b		;decrement byte count
	jnz	cmpLoop

cmpExit	pop	d		;restore DE
	ret			;return with status 

;-----------------------------------------------------------------------
; Data Area
;-----------------------------------------------------------------------

strPass	db	8		;length of password string
	db	'RSX DEMO'	;password

mEnable	db	CR,LF,LF
	db	'Console Enabled'
	db	CR,LF,'$'

	ds	32		;16 word stack
LCLSTK	equ	$		;local stack

stkSave	ds	2		;save user's stack pointer

	end		
