 98f6d1a668
			
		
	
	
	98f6d1a668
	
	
	
		
			
			When printing multi-line text using sclp_print, line endings are not correctly handled. The routine is expecting an EBCDIC new line character as line terminator while the input text is encoded in ASCII format. Fix this problem by modifying sclp_print to scan for ASCII new line characters. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
		
			
				
	
	
		
			359 lines
		
	
	
	
		
			8.1 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			359 lines
		
	
	
	
		
			8.1 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  * Mini SCLP driver.
 | |
|  *
 | |
|  * Copyright IBM Corp. 2004, 2009
 | |
|  *
 | |
|  *   Author(s):	Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>,
 | |
|  *		Heiko Carstens <heiko.carstens@de.ibm.com>,
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/linkage.h>
 | |
| 
 | |
| LC_EXT_NEW_PSW		= 0x58			# addr of ext int handler
 | |
| LC_EXT_NEW_PSW_64	= 0x1b0			# addr of ext int handler 64 bit
 | |
| LC_EXT_INT_PARAM	= 0x80			# addr of ext int parameter
 | |
| LC_EXT_INT_CODE		= 0x86			# addr of ext int code
 | |
| LC_AR_MODE_ID		= 0xa3
 | |
| 
 | |
| #
 | |
| # Subroutine which waits synchronously until either an external interruption
 | |
| # or a timeout occurs.
 | |
| #
 | |
| # Parameters:
 | |
| #   R2	= 0 for no timeout, non-zero for timeout in (approximated) seconds
 | |
| #
 | |
| # Returns:
 | |
| #   R2	= 0 on interrupt, 2 on timeout
 | |
| #   R3	= external interruption parameter if R2=0
 | |
| #
 | |
| 
 | |
| _sclp_wait_int:
 | |
| 	stm	%r6,%r15,24(%r15)		# save registers
 | |
| 	basr	%r13,0				# get base register
 | |
| .LbaseS1:
 | |
| 	ahi	%r15,-96			# create stack frame
 | |
| 	la	%r8,LC_EXT_NEW_PSW		# register int handler
 | |
| 	la	%r9,.LextpswS1-.LbaseS1(%r13)
 | |
| #ifdef CONFIG_64BIT
 | |
| 	tm	LC_AR_MODE_ID,1
 | |
| 	jno	.Lesa1
 | |
| 	la	%r8,LC_EXT_NEW_PSW_64		# register int handler 64 bit
 | |
| 	la	%r9,.LextpswS1_64-.LbaseS1(%r13)
 | |
| .Lesa1:
 | |
| #endif
 | |
| 	mvc	.LoldpswS1-.LbaseS1(16,%r13),0(%r8)
 | |
| 	mvc	0(16,%r8),0(%r9)
 | |
| #ifdef CONFIG_64BIT
 | |
| 	epsw	%r6,%r7				# set current addressing mode
 | |
| 	nill	%r6,0x1				# in new psw (31 or 64 bit mode)
 | |
| 	nilh	%r7,0x8000
 | |
| 	stm	%r6,%r7,0(%r8)
 | |
| #endif
 | |
| 	lhi	%r6,0x0200			# cr mask for ext int (cr0.54)
 | |
| 	ltr	%r2,%r2
 | |
| 	jz	.LsetctS1
 | |
| 	ahi	%r6,0x0800			# cr mask for clock int (cr0.52)
 | |
| 	stck	.LtimeS1-.LbaseS1(%r13)		# initiate timeout
 | |
| 	al	%r2,.LtimeS1-.LbaseS1(%r13)
 | |
| 	st	%r2,.LtimeS1-.LbaseS1(%r13)
 | |
| 	sckc	.LtimeS1-.LbaseS1(%r13)
 | |
| 
 | |
| .LsetctS1:
 | |
| 	stctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# enable required interrupts
 | |
| 	l	%r0,.LctlS1-.LbaseS1(%r13)
 | |
| 	lhi	%r1,~(0x200 | 0x800)		# clear old values
 | |
| 	nr	%r1,%r0
 | |
| 	or	%r1,%r6				# set new value
 | |
| 	st	%r1,.LctlS1-.LbaseS1(%r13)
 | |
| 	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)
 | |
| 	st	%r0,.LctlS1-.LbaseS1(%r13)
 | |
| 	lhi	%r2,2				# return code for timeout
 | |
| .LloopS1:
 | |
| 	lpsw	.LwaitpswS1-.LbaseS1(%r13)	# wait until interrupt
 | |
| .LwaitS1:
 | |
| 	lh	%r7,LC_EXT_INT_CODE
 | |
| 	chi	%r7,0x1004			# timeout?
 | |
| 	je	.LtimeoutS1
 | |
| 	chi	%r7,0x2401			# service int?
 | |
| 	jne	.LloopS1
 | |
| 	sr	%r2,%r2
 | |
| 	l	%r3,LC_EXT_INT_PARAM
 | |
| .LtimeoutS1:
 | |
| 	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# restore interrupt setting
 | |
| 	# restore old handler
 | |
| 	mvc	0(16,%r8),.LoldpswS1-.LbaseS1(%r13)
 | |
| 	lm	%r6,%r15,120(%r15)		# restore registers
 | |
| 	br	%r14				# return to caller
 | |
| 
 | |
| 	.align	8
 | |
| .LoldpswS1:
 | |
| 	.long	0, 0, 0, 0			# old ext int PSW
 | |
| .LextpswS1:
 | |
| 	.long	0x00080000, 0x80000000+.LwaitS1	# PSW to handle ext int
 | |
| #ifdef CONFIG_64BIT
 | |
| .LextpswS1_64:
 | |
| 	.quad	0, .LwaitS1			# PSW to handle ext int, 64 bit
 | |
| #endif
 | |
| .LwaitpswS1:
 | |
| 	.long	0x010a0000, 0x00000000+.LloopS1	# PSW to wait for ext int
 | |
| .LtimeS1:
 | |
| 	.quad	0				# current time
 | |
| .LctlS1:
 | |
| 	.long	0				# CT0 contents
 | |
| 
 | |
| #
 | |
| # Subroutine to synchronously issue a service call.
 | |
| #
 | |
| # Parameters:
 | |
| #   R2	= command word
 | |
| #   R3	= sccb address
 | |
| #
 | |
| # Returns:
 | |
| #   R2	= 0 on success, 1 on failure
 | |
| #   R3	= sccb response code if R2 = 0
 | |
| #
 | |
| 
 | |
| _sclp_servc:
 | |
| 	stm	%r6,%r15,24(%r15)		# save registers
 | |
| 	ahi	%r15,-96			# create stack frame
 | |
| 	lr	%r6,%r2				# save command word
 | |
| 	lr	%r7,%r3				# save sccb address
 | |
| .LretryS2:
 | |
| 	lhi	%r2,1				# error return code
 | |
| 	.insn	rre,0xb2200000,%r6,%r7		# servc
 | |
| 	brc	1,.LendS2			# exit if not operational
 | |
| 	brc	8,.LnotbusyS2			# go on if not busy
 | |
| 	sr	%r2,%r2				# wait until no longer busy
 | |
| 	bras	%r14,_sclp_wait_int
 | |
| 	j	.LretryS2			# retry
 | |
| .LnotbusyS2:
 | |
| 	sr	%r2,%r2				# wait until result
 | |
| 	bras	%r14,_sclp_wait_int
 | |
| 	sr	%r2,%r2
 | |
| 	lh	%r3,6(%r7)
 | |
| .LendS2:
 | |
| 	lm	%r6,%r15,120(%r15)		# restore registers
 | |
| 	br	%r14
 | |
| 
 | |
| #
 | |
| # Subroutine to set up the SCLP interface.
 | |
| #
 | |
| # Parameters:
 | |
| #   R2	= 0 to activate, non-zero to deactivate
 | |
| #
 | |
| # Returns:
 | |
| #   R2	= 0 on success, non-zero on failure
 | |
| #
 | |
| 
 | |
| _sclp_setup:
 | |
| 	stm	%r6,%r15,24(%r15)		# save registers
 | |
| 	ahi	%r15,-96			# create stack frame
 | |
| 	basr	%r13,0				# get base register
 | |
| .LbaseS3:
 | |
| 	l	%r6,.LsccbS0-.LbaseS3(%r13)	# prepare init mask sccb
 | |
| 	mvc	0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13)
 | |
| 	ltr	%r2,%r2				# initialization?
 | |
| 	jz	.LdoinitS3			# go ahead
 | |
| 	# clear masks
 | |
| 	xc	.LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6)
 | |
| .LdoinitS3:
 | |
| 	l	%r2,.LwritemaskS3-.LbaseS3(%r13)# get command word
 | |
| 	lr	%r3,%r6				# get sccb address
 | |
| 	bras	%r14,_sclp_servc		# issue service call
 | |
| 	ltr	%r2,%r2				# servc successful?
 | |
| 	jnz	.LerrorS3
 | |
| 	chi	%r3,0x20			# write mask successful?
 | |
| 	jne	.LerrorS3
 | |
| 	# check masks
 | |
| 	la	%r2,.LinitmaskS3-.LinitsccbS3(%r6)
 | |
| 	l	%r1,0(%r2)			# receive mask ok?
 | |
| 	n	%r1,12(%r2)
 | |
| 	cl	%r1,0(%r2)
 | |
| 	jne	.LerrorS3
 | |
| 	l	%r1,4(%r2)			# send mask ok?
 | |
| 	n	%r1,8(%r2)
 | |
| 	cl	%r1,4(%r2)
 | |
| 	sr	%r2,%r2
 | |
| 	je	.LendS3
 | |
| .LerrorS3:
 | |
| 	lhi	%r2,1				# error return code
 | |
| .LendS3:
 | |
| 	lm	%r6,%r15,120(%r15)		# restore registers
 | |
| 	br	%r14
 | |
| .LwritemaskS3:
 | |
| 	.long	0x00780005			# SCLP command for write mask
 | |
| .LinitsccbS3:
 | |
| 	.word	.LinitendS3-.LinitsccbS3
 | |
| 	.byte	0,0,0,0
 | |
| 	.word	0
 | |
| 	.word	0
 | |
| 	.word	4
 | |
| .LinitmaskS3:
 | |
| 	.long	0x80000000
 | |
| 	.long	0x40000000
 | |
| 	.long	0
 | |
| 	.long	0
 | |
| .LinitendS3:
 | |
| 
 | |
| #
 | |
| # Subroutine which prints a given text to the SCLP console.
 | |
| #
 | |
| # Parameters:
 | |
| #   R2	= address of nil-terminated ASCII text
 | |
| #
 | |
| # Returns:
 | |
| #   R2	= 0 on success, 1 on failure
 | |
| #
 | |
| 
 | |
| _sclp_print:
 | |
| 	stm	%r6,%r15,24(%r15)		# save registers
 | |
| 	ahi	%r15,-96			# create stack frame
 | |
| 	basr	%r13,0				# get base register
 | |
| .LbaseS4:
 | |
| 	l	%r8,.LsccbS0-.LbaseS4(%r13)	# prepare write data sccb
 | |
| 	mvc	0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13)
 | |
| 	la	%r7,.LmtoS4-.LwritesccbS4(%r8)	# current mto addr
 | |
| 	sr	%r0,%r0
 | |
| 	l	%r10,.Lascebc-.LbaseS4(%r13)	# address of translation table
 | |
| .LinitmtoS4:
 | |
| 	# initialize mto
 | |
| 	mvc	0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13)
 | |
| 	lhi	%r6,.LmtoendS4-.LmtoS4		# current mto length
 | |
| .LloopS4:
 | |
| 	ic	%r0,0(%r2)			# get character
 | |
| 	ahi	%r2,1
 | |
| 	ltr	%r0,%r0				# end of string?
 | |
| 	jz	.LfinalizemtoS4
 | |
| 	chi	%r0,0x0a			# end of line (NL)?
 | |
| 	jz	.LfinalizemtoS4
 | |
| 	stc	%r0,0(%r6,%r7)			# copy to mto
 | |
| 	la	%r11,0(%r6,%r7)
 | |
| 	tr	0(1,%r11),0(%r10)		# translate to EBCDIC
 | |
| 	ahi	%r6,1
 | |
| 	j	.LloopS4
 | |
| .LfinalizemtoS4:
 | |
| 	sth	%r6,0(%r7)			# update mto length
 | |
| 	lh	%r9,.LmdbS4-.LwritesccbS4(%r8)	# update mdb length
 | |
| 	ar	%r9,%r6
 | |
| 	sth	%r9,.LmdbS4-.LwritesccbS4(%r8)
 | |
| 	lh	%r9,.LevbufS4-.LwritesccbS4(%r8)# update evbuf length
 | |
| 	ar	%r9,%r6
 | |
| 	sth	%r9,.LevbufS4-.LwritesccbS4(%r8)
 | |
| 	lh	%r9,0(%r8)			# update sccb length
 | |
| 	ar	%r9,%r6
 | |
| 	sth	%r9,0(%r8)
 | |
| 	ar	%r7,%r6				# update current mto address
 | |
| 	ltr	%r0,%r0				# more characters?
 | |
| 	jnz	.LinitmtoS4
 | |
| 	l	%r2,.LwritedataS4-.LbaseS4(%r13)# write data
 | |
| 	lr	%r3,%r8
 | |
| 	bras	%r14,_sclp_servc
 | |
| 	ltr	%r2,%r2				# servc successful?
 | |
| 	jnz	.LendS4
 | |
| 	chi	%r3,0x20			# write data successful?
 | |
| 	je	.LendS4
 | |
| 	lhi	%r2,1				# error return code
 | |
| .LendS4:
 | |
| 	lm	%r6,%r15,120(%r15)		# restore registers
 | |
| 	br	%r14
 | |
| 
 | |
| #
 | |
| # Function which prints a given text to the SCLP console.
 | |
| #
 | |
| # Parameters:
 | |
| #   R2	= address of nil-terminated ASCII text
 | |
| #
 | |
| # Returns:
 | |
| #   R2	= 0 on success, 1 on failure
 | |
| #
 | |
| 
 | |
| ENTRY(_sclp_print_early)
 | |
| 	stm	%r6,%r15,24(%r15)		# save registers
 | |
| 	ahi	%r15,-96			# create stack frame
 | |
| #ifdef CONFIG_64BIT
 | |
| 	tm	LC_AR_MODE_ID,1
 | |
| 	jno	.Lesa2
 | |
| 	ahi	%r15,-80
 | |
| 	stmh	%r6,%r15,96(%r15)		# store upper register halves
 | |
| .Lesa2:
 | |
| #endif
 | |
| 	lr	%r10,%r2			# save string pointer
 | |
| 	lhi	%r2,0
 | |
| 	bras	%r14,_sclp_setup		# enable console
 | |
| 	ltr	%r2,%r2
 | |
| 	jnz	.LendS5
 | |
| 	lr	%r2,%r10
 | |
| 	bras	%r14,_sclp_print		# print string
 | |
| 	ltr	%r2,%r2
 | |
| 	jnz	.LendS5
 | |
| 	lhi	%r2,1
 | |
| 	bras	%r14,_sclp_setup		# disable console
 | |
| .LendS5:
 | |
| #ifdef CONFIG_64BIT
 | |
| 	tm	LC_AR_MODE_ID,1
 | |
| 	jno	.Lesa3
 | |
| 	lmh	%r6,%r15,96(%r15)		# store upper register halves
 | |
| 	ahi	%r15,80
 | |
| .Lesa3:
 | |
| #endif
 | |
| 	lm	%r6,%r15,120(%r15)		# restore registers
 | |
| 	br	%r14
 | |
| 
 | |
| .LwritedataS4:
 | |
| 	.long	0x00760005			# SCLP command for write data
 | |
| .LwritesccbS4:
 | |
| 	# sccb
 | |
| 	.word	.LmtoS4-.LwritesccbS4
 | |
| 	.byte	0
 | |
| 	.byte	0,0,0
 | |
| 	.word	0
 | |
| 
 | |
| 	# evbuf
 | |
| .LevbufS4:
 | |
| 	.word	.LmtoS4-.LevbufS4
 | |
| 	.byte	0x02
 | |
| 	.byte	0
 | |
| 	.word	0
 | |
| 
 | |
| .LmdbS4:
 | |
| 	# mdb
 | |
| 	.word	.LmtoS4-.LmdbS4
 | |
| 	.word	1
 | |
| 	.long	0xd4c4c240
 | |
| 	.long	1
 | |
| 
 | |
| 	# go
 | |
| .LgoS4:
 | |
| 	.word	.LmtoS4-.LgoS4
 | |
| 	.word	1
 | |
| 	.long	0
 | |
| 	.byte	0,0,0,0,0,0,0,0
 | |
| 	.byte	0,0,0
 | |
| 	.byte	0
 | |
| 	.byte	0,0,0,0,0,0,0
 | |
| 	.byte	0
 | |
| 	.word	0
 | |
| 	.byte	0,0,0,0,0,0,0,0,0,0
 | |
| 	.byte	0,0,0,0,0,0,0,0
 | |
| 	.byte	0,0,0,0,0,0,0,0
 | |
| 
 | |
| .LmtoS4:
 | |
| 	.word	.LmtoendS4-.LmtoS4
 | |
| 	.word	4
 | |
| 	.word	0x1000
 | |
| 	.byte	0
 | |
| 	.byte	0,0,0
 | |
| .LmtoendS4:
 | |
| 
 | |
| 	# Global constants
 | |
| .LsccbS0:
 | |
| 	.long	_sclp_work_area
 | |
| .Lascebc:
 | |
| 	.long	_ascebc
 | |
| 
 | |
| .section .data,"aw",@progbits
 | |
| 	.balign 4096
 | |
| _sclp_work_area:
 | |
| 	.fill	4096
 | |
| .previous
 |