; Retro UNIX 386 v1 Kernel (v0.2) - SYS9.INC
; Last Modification: 15/09/2015
; ----------------------------------------------------------------------------
; Derived from 'Retro UNIX 8086 v1' source code by Erdogan Tan
; (v0.1 - Beginning: 11/07/2012)
;
; Derived from UNIX Operating System (v1.0 for PDP-11) 
; (Original) Source Code by Ken Thompson (1971-1972)
; <Bell Laboratories (17/3/1972)>
; <Preliminary Release of UNIX Implementation Document>
;
; Retro UNIX 8086 v1 - U9.ASM (01/09/2014) //// UNIX v1 -> u9.s
;
; ****************************************************************************

getch:
	; 30/06/2015
	; 18/02/2015 - Retro UNIX 386 v1 - feature only!
	sub	al, al ; 0
getch_q: ; 06/08/2015
	mov 	ah, [ptty] ; active (current) video page
        jmp     short getc_n

getc: 
	; 15/09/2015
	; 01/07/2015
	; 30/06/2015
	; 18/02/2015 (Retro UNIX 386 v1 - Beginning)
	; 13/05/2013 - 04/07/2014 (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 modification !
	; 
	; 'getc' gets (next) character 
	;	 from requested TTY (keyboard) buffer 
	; INPUTS ->
	;     [u.ttyn] = tty number (0 to 7) (8 is COM1, 9 is COM2)	
	;     AL=0 -> Get (next) character from requested TTY buffer
	;	(Keyboard buffer will point to 
	;			next character at next call)
	;     AL=1 -> Test a key is available in requested TTY buffer
	;	(Keyboard buffer will point to 
	;			current character at next call)
	; OUTPUTS ->
	;     (If AL input is 1) ZF=1 -> 'empty buffer' (no chars)
	;     			 ZF=0 -> AX has (current) character
	;      AL = ascii code
	;      AH = scan code	(AH = line status for COM1 or COM2)	 			
	; 		        (cf=1 -> error code/flags in AH)
	; Original UNIX V1 'getc': 
	;		get a character off character list
	;
	; ((Modified registers: eAX, eBX, eCX, eDX, eSI, eDI))	
	;
	; 30/06/20045 (32 bit modifications)
	; 16/07/2013
	; mov 	[getctty], ah
	;

	mov	ah, [u.ttyn] 	; 28/07/2013
getc_n:
	; 30/06/2015
	or	ah, ah
	jz	short getc0 
	shl	ah, 1
	movzx	ebx, ah
	add	ebx, ttychr
	jmp	short getc1
getc0:
	mov	ebx, ttychr
getc1:
	mov	cx, [ebx] 	; ascii & scan code
				; (by kb_int)	
	or	cx, cx
	jnz	short getc2
	and 	al, al
	jz	short getc_s
	xor	ax, ax
	retn
getc2:	
	and	al, al
	mov	ax, cx
	mov	cx, 0
	jnz	short getc3
getc_sn:
	mov	[ebx], cx ; 0, reset
	cmp	ax, cx  ; zf = 0
getc3:
	retn
getc_s:
	; 15/09/2015
	; 01/07/2015
	; 30/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 16/07/2013 - 14/02/2014 (Retro UNIX 8086 v1)
	;
	; tty  of the current process is not 
	; current tty (ptty); so, current process only 
	; can use keyboard input when its tty becomes 
	; current tty (ptty).
	; 'sleep' is for preventing an endless lock
	; during this tty input request.
	; (Because, the user is not looking at the video page
	; of the process to undersand there is a keyboard
	; input request.)
	;
	;((Modified registers: eAX, eBX, eCX, eDX, eSI, eDI))
	;
	; 05/10/2013
	; ah = byte ptr [u.ttyn] ; (tty number)
	;
	; 10/10/2013
gcw0:
	mov	cl, 10 ; ch = 0
gcw1:	
	call	idle
	mov	ax, [ebx] 	; ascii & scan code
				; (by kb_int)
	or	ax, ax
;	jnz	short gcw3
	jnz	short gcw2 ; 15/09/2015
	; 30/06/2015
	dec	cl
	jnz	short gcw1
	;
	mov	ah, [u.ttyn] 	; 20/10/2013
;	; 10/12/2013
;	cmp 	ah, [ptty]
;	jne	short gcw2
;	; 14/02/2014
;	cmp	byte [u.uno], 1
;	jna	short gcw0		
;gcw2:
	call	sleep
	;
	; 20/09/2013
	mov	ah, [u.ttyn]
	xor 	al, al
	jmp	short getc_n
;gcw3:
gcw2: 	; 15/09/2015
	; 10/10/2013
	xor	cl, cl
	jmp	short getc_sn

sndc:   ; <Send character>
	;
	; 30/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 14/05/2013 - 28/07/2014 (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 feature only !
	;
	; 30/06/2014
	sub	ah, 8 ; ; 0 = tty8 or 1 = tty9
	push	ax ; al = character (to be sent)
	movzx	edx, ah ; serial port index (0 or 1)
	push	edx
sndc0:
	; 28/07/2014
	;mov	ah, 3 	; Get serial port status
	;int	14h
	;test	ah, 20h	; Transmitter holding register empty ?
	;jnz	short sndc1
	;
	; 30/06/2014
	mov	al, [esp]
	call	sp_status ; get serial port status
	; AL = Line status, AH = Modem status
	;
	test	al, 20h	; Transmitter holding register empty ?
	jnz	short sndc1
	;
	mov	ebx, [esp]
	add	ebx, tsleep
	;
	mov	ah, [u.ttyn]
	mov	[ebx], ah ; 27/07/2014
	;
	call	sleep
	jmp	short sndc0
sndc1:
	pop	edx ; 30/06/2015
	pop	ax ; al = character (to be sent)
	; 13/07/2014
	push	dx
	or	dl, dl
	mov	dx, 2F8h   ;data port (COM2)
	jnz	short sndc2
	add	dh, 1	   ;3F8h, data port (COM1)
sndc2:
	out	dx, al	   ;send on serial port
	;pop	dx
	; 30/06/2015
	pop	ax ; al = 0 (tty8) or 1 (tty9)
	; 27/07/2014
	call	idle
	; 
	;mov	ah, 3 	; Get serial port status
	;int	14h
	;cmp	ah, 80h ; time out error
	;
	call	sp_status ; get serial port status
	; AL = Line status, AH = Modem status
	cmp	al, 80h	; time out error 
	cmc	; cf = 0 (OK), cf = 1 (error!)
	retn

putc:	
	; 13/08/2015
	; 30/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 15/05/2013 - 27/07/2014 (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 modification !
	; 
	; 'putc' puts a character 
	;	 onto requested (tty) video page or
	;	 serial port
	; INPUTS ->
	;     AL = ascii code of the character
	;     AH = video page (tty) number (0 to 7)
	;			  (8 is COM1, 9 is COM2)	
	; OUTPUTS ->
	;    (If AL input is 1) ZF=1 -> 'empty buffer' (no chars)
	;      			ZF=0 -> AX has (current) character
	;     cf=0 and AH = 0 -> no error
	;     cf=1 and AH > 0 -> error (only for COM1 and COM2)		 			
	; 
	; Original UNIX V1 'putc': 
	;     put a character at the end of character list
	;
	; ((Modified registers: eAX, eBX, eCX, eDX, eSI, eDI))
	;
	cmp	ah, 7
	ja	short sndc
	; 30/06/2015
	movzx	ebx, ah
	; 13/08/2015
	mov	ah, 07h ; black background, light gray character color
	jmp	write_tty ; 'video.inc'

get_cpos:
	; 29/06/2015 (Retro UNIX 386 v1)
	; 04/12/2013 (Retro UNIX 8086 v1 - 'sysgtty')
	;
	; INPUT -> bl = video page number
	; RETURN -> dx = cursor position

	push	ebx
	and	ebx, 0Fh ; 07h ; tty0 to tty7
	shl	bl, 1
	add	ebx, cursor_posn
	mov	dx, [ebx]
	pop	ebx
	retn

read_ac_current:
	; 29/06/2015 (Retro UNIX 386 v1)
	; 04/12/2013 (Retro UNIX 8086 v1 - 'sysgtty')
	;
	; INPUT -> bl = video page number
	; RETURN -> ax = character (al) and attribute (ah)

	call 	find_position ; 'video.inc'
	; dx = status port
	; esi = cursor location/address
	add	esi, 0B8000h	; 30/08/2014 (Retro UNIX 386 v1)
	mov 	ax, [esi]	; get the character and attribute
	retn

syssleep:
	; 29/06/2015 - (Retro UNIX 386 v1)
	; 11/06/2014 - (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 feature only
	; (INPUT -> none)
	;
	movzx	ebx, byte [u.uno] ; process number
	mov	ah, [ebx+p.ttyc-1] ; current/console tty
	call	sleep
	jmp	sysret

vp_clr:
	; Reset/Clear Video Page
	;
	; 30/06/2015 - (Retro UNIX 386 v1)
	; 21/05/2013 - 30/10/2013(Retro UNIX 8086 v1) (U0.ASM)
	;
	; Retro UNIX 8086 v1 feature only !
	;
	; INPUTS -> 
	;   BL = video page number	 
	;
	; OUTPUT ->
	;   none
	; ((Modified registers: eAX, BH, eCX, eDX, eSI, eDI))
	;
	; 04/12/2013
	sub	al, al
	; al = 0 (clear video page)
	; bl = video page
	mov	ah, 07h
	; ah = 7 (attribute/color)
	xor 	cx, cx ; 0, left upper column (cl) & row (cl)
	mov	dx, 184Fh ; right lower column & row (dl=24, dh=79)
	call	scroll_up
	; bl = video page
	xor	dx, dx ; 0 (cursor position) 
	jmp 	set_cpos

sysmsg:
	; 01/07/2015 - (Retro UNIX 386 v1 feature only!)
	; Print user-application message on user's console tty
	;
	; Input -> EBX = Message address
	;	   ECX = Message length (max. 255)
	;	   DL = Color (IBM PC Rombios color attributes)
	;
	cmp	ecx, MAX_MSG_LEN ; 255
	ja	sysret ; nothing to do with big message size
	or	cl, cl
	jz	sysret
	and	dl, dl
	jnz	short sysmsg0
	mov	dl, 07h ; default color
		; (black background, light gray character) 
sysmsg0:
	mov	[u.base], ebx
	mov	[ccolor], dl ; color attributes
	mov	ebp, esp
	xor	ebx, ebx ; 0
	mov	[u.nread], ebx ; 0
	;
	cmp	[u.kcall], bl ; 0
	ja	short sysmsgk ; Temporary (01/07/2015)
	;
	mov	[u.count], ecx
	inc	ecx ; + 00h ; ASCIZZ
	sub	esp, ecx
	mov	edi, esp
	mov	esi, esp
	mov	[u.pcount], bx ; reset page (phy. addr.) counter
	mov	bl, [u.uno] ; process number
	mov	ah, [ebx+p.ttyc-1] ; user's (process's) console tty
	mov	[u.ttyn], ah
sysmsg1:
	call	cpass
	jz	short sysmsg4
	stosb
	and	al, al
	jnz	short sysmsg1
sysmsg2:
	cmp	ah, 7 ; tty number
	ja	short sysmsg5 ; serial port
	call	print_cmsg
sysmsg3:
	mov	esp, ebp	
	jmp	sysret
sysmsg4:
	mov	byte [edi], 0
	jmp	short sysmsg2
sysmsg5:
	mov	al, [esi]
	call	sndc
	jc	short sysmsg3
	cmp	byte [esi], 0  ; 0 is stop character
	jna	short sysmsg3
	inc 	esi
	mov	ah, [u.ttyn]
	jmp	short sysmsg5

sysmsgk: ; Temporary (01/07/2015)
	; The message has been sent by Kernel (ASCIIZ string)
	; (ECX -character count- will not be considered)
	mov	esi, [u.base]
	mov	ah, [ptty] ; present/current screen (video page)
	mov	[u.ttyn], ah
	mov	byte [u.kcall], 0
	jmp	short sysmsg2
	

print_cmsg: 
	; 01/07/2015 (retro UNIX 386 v1 feature only !)
	;
	; print message (on user's console tty) 
	;	with requested color
	;
	; INPUTS:
	;	esi = message address
	;	[u.ttyn] = tty number (0 to 7)
	;	[ccolor] = color attributes (IBM PC BIOS colors)
	;
	lodsb
pcmsg1:
	push 	esi
        movzx   ebx, byte [u.ttyn]
	mov	ah, [ccolor]
	call 	write_tty
	pop	esi
	lodsb
	and 	al, al  ; 0
	jnz 	short pcmsg1
	retn

sysgeterr:
	; 21/09/2015 - (Retro UNIX 386 v1 feature only!)
	; Get last error number or page fault count
	; (for debugging)
	;
	; Input -> EBX = return type
	;	   0 = last error code (which is in 'u.error')	
	;	   FFFFFFFFh = page fault count for running process
	;	   FFFFFFFEh = total page fault count
	;	   1 .. FFFFFFFDh = undefined 
	;
	; Output -> EAX = last error number or page fault count
	;	   (depending on EBX input)
	; 	
	and 	ebx, ebx
	jnz	short glerr_2
glerr_0:
	mov	eax, [u.error]
glerr_1:
	mov	[u.r0], eax
 	retn
glerr_2:
	inc	ebx ; FFFFFFFFh -> 0, FFFFFFFEh -> FFFFFFFFh
	jz	short glerr_2 ; page fault count for process
	inc	ebx ; FFFFFFFFh -> 0	
	jnz	short glerr_0
	mov	eax, [PF_Count] ; total page fault count
        jmp     short glerr_1
glerr_3:
	mov 	eax, [u.pfcount]
	jmp	short glerr_1

sysconnect:
	; 23/10/2015 - (Retro UNIX 386 v1 feature only!)
	; * connects COM1 or COM2 serial ports
	;   to the operating system as a terminal 
	;   or as input/output device
	; * changes connection modes as requested
	;   (disconnects/deactives previous mode)
	; INPUT:
	;	EBX (BL) = SERIAL PORT (0= COM1, 1= COM2)
	;	ECX (CL) = CONNECTION MODE
	; 	EDX (DL) = METHOD (0 for default method)
	;
 	; OUPUT:
	;	none (connection mode is changed as requested)
	;
	; Note: Only super user or owner of the tty can change
	;	communication mode.
	; Modes:
	;	0 - command mode (commands by remote device)
	;	1 - terminal mode (asciiz character strings)
	;	2 - keyboard mode (ascii+scan codes)
	;	3 - mouse mode (input)
	;	4 - device control mode (output)
	;
	cmp	ebx, 1
	ja	badsys
	cmp	ecx, 4
	ja	badsys 
	;
	cmp	byte [u.uid], 0 ; root ?
	jna	short conn_1
	;
	mov	al, [ebx+com1own]
	cmp	al, [u.uno]
	ja	short conn_error	
conn_1:
	cmp	
	mov	[ebx


conn_err:
	mov 	dword [u.error], ERR_NOT_OWNER
	jmp	error 