mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 09:19:51 +00:00
s390/sclp: convert early sclp console code to C
The 31-bit assembler code for the early sclp console is error prone as git commit fde24b54d976cc123506695c17db01438a11b673 "s390/sclp: clear upper register halves in _sclp_print_early" has shown. Convert the assembler code to C. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
1d2334cb7d
commit
22362a0e23
7 changed files with 186 additions and 356 deletions
|
@ -33,6 +33,8 @@ mflags-$(CONFIG_MARCH_Z196) := -march=z196
|
|||
mflags-$(CONFIG_MARCH_ZEC12) := -march=zEC12
|
||||
mflags-$(CONFIG_MARCH_Z13) := -march=z13
|
||||
|
||||
export CC_FLAGS_MARCH := $(mflags-y)
|
||||
|
||||
aflags-y += $(mflags-y)
|
||||
cflags-y += $(mflags-y)
|
||||
|
||||
|
|
|
@ -232,6 +232,17 @@ static inline void __load_psw_mask (unsigned long mask)
|
|||
: "=&d" (addr), "=Q" (psw) : "Q" (psw) : "memory", "cc");
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract current PSW mask
|
||||
*/
|
||||
static inline unsigned long __extract_psw(void)
|
||||
{
|
||||
unsigned int reg1, reg2;
|
||||
|
||||
asm volatile("epsw %0,%1" : "=d" (reg1), "=a" (reg2));
|
||||
return (((unsigned long) reg1) << 32) | ((unsigned long) reg2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rewind PSW instruction address by specified number of bytes.
|
||||
*/
|
||||
|
|
|
@ -79,6 +79,6 @@ int sclp_pci_configure(u32 fid);
|
|||
int sclp_pci_deconfigure(u32 fid);
|
||||
int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
|
||||
void sclp_early_detect(void);
|
||||
long _sclp_print_early(const char *);
|
||||
int _sclp_print_early(const char *);
|
||||
|
||||
#endif /* _ASM_S390_SCLP_H */
|
||||
|
|
|
@ -28,6 +28,17 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
|
|||
|
||||
CFLAGS_sysinfo.o += -w
|
||||
|
||||
#
|
||||
# Use -march=z900 for sclp.c to be able to print an error message if
|
||||
# the kernel is started on a machine which is too old
|
||||
#
|
||||
CFLAGS_REMOVE_sclp.o = $(CC_FLAGS_FTRACE)
|
||||
ifneq ($(CC_FLAGS_MARCH),-march=z900)
|
||||
CFLAGS_REMOVE_sclp.o += $(CC_FLAGS_MARCH)
|
||||
CFLAGS_sclp.o += -march=z900
|
||||
endif
|
||||
GCOV_PROFILE_sclp.o := n
|
||||
|
||||
obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o
|
||||
obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
|
||||
obj-y += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o
|
||||
|
|
|
@ -370,6 +370,7 @@ ENTRY(startup_kdump)
|
|||
xc 0x200(256),0x200 # partially clear lowcore
|
||||
xc 0x300(256),0x300
|
||||
xc 0xe00(256),0xe00
|
||||
lctlg %c0,%c15,0x200(%r0) # initialize control registers
|
||||
stck __LC_LAST_UPDATE_CLOCK
|
||||
spt 6f-.LPG0(%r13)
|
||||
mvc __LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13)
|
||||
|
|
|
@ -1,355 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
#include <asm/irq.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)
|
||||
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:
|
||||
mvc .LoldpswS1-.LbaseS1(16,%r13),0(%r8)
|
||||
mvc 0(16,%r8),0(%r9)
|
||||
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)
|
||||
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,EXT_IRQ_CLK_COMP # timeout?
|
||||
je .LtimeoutS1
|
||||
chi %r7,EXT_IRQ_SERVICE_SIG # 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
|
||||
.LextpswS1_64:
|
||||
.quad 0, .LwaitS1 # PSW to handle ext int, 64 bit
|
||||
.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
|
||||
tm LC_AR_MODE_ID,1
|
||||
jno .Lesa2
|
||||
ahi %r15,-80
|
||||
stmh %r6,%r15,96(%r15) # store upper register halves
|
||||
basr %r13,0
|
||||
lmh %r0,%r15,.Lzeroes-.(%r13) # clear upper register halves
|
||||
.Lesa2:
|
||||
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:
|
||||
tm LC_AR_MODE_ID,1
|
||||
jno .Lesa3
|
||||
lgfr %r2,%r2 # sign extend return value
|
||||
lmh %r6,%r15,96(%r15) # restore upper register halves
|
||||
ahi %r15,80
|
||||
.Lesa3:
|
||||
lm %r6,%r15,120(%r15) # restore registers
|
||||
br %r14
|
||||
.Lzeroes:
|
||||
.fill 64,4,0
|
||||
|
||||
.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
|
160
arch/s390/kernel/sclp.c
Normal file
160
arch/s390/kernel/sclp.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright IBM Corp. 2015
|
||||
* Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/lowcore.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sclp.h>
|
||||
|
||||
static char _sclp_work_area[4096] __aligned(PAGE_SIZE);
|
||||
|
||||
static void _sclp_wait_int(void)
|
||||
{
|
||||
unsigned long cr0, cr0_new, psw_mask, addr;
|
||||
psw_t psw_ext_save, psw_wait;
|
||||
|
||||
__ctl_store(cr0, 0, 0);
|
||||
cr0_new = cr0 | 0x200;
|
||||
__ctl_load(cr0_new, 0, 0);
|
||||
|
||||
psw_ext_save = S390_lowcore.external_new_psw;
|
||||
psw_mask = __extract_psw() & (PSW_MASK_EA | PSW_MASK_BA);
|
||||
S390_lowcore.external_new_psw.mask = psw_mask;
|
||||
psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
|
||||
S390_lowcore.ext_int_code = 0;
|
||||
|
||||
do {
|
||||
asm volatile(
|
||||
" larl %[addr],0f\n"
|
||||
" stg %[addr],%[psw_wait_addr]\n"
|
||||
" stg %[addr],%[psw_ext_addr]\n"
|
||||
" lpswe %[psw_wait]\n"
|
||||
"0:\n"
|
||||
: [addr] "=&d" (addr),
|
||||
[psw_wait_addr] "=Q" (psw_wait.addr),
|
||||
[psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr)
|
||||
: [psw_wait] "Q" (psw_wait)
|
||||
: "cc", "memory");
|
||||
} while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG);
|
||||
|
||||
__ctl_load(cr0, 0, 0);
|
||||
S390_lowcore.external_new_psw = psw_ext_save;
|
||||
}
|
||||
|
||||
static int _sclp_servc(unsigned int cmd, char *sccb)
|
||||
{
|
||||
unsigned int cc;
|
||||
|
||||
do {
|
||||
asm volatile(
|
||||
" .insn rre,0xb2200000,%1,%2\n"
|
||||
" ipm %0\n"
|
||||
: "=d" (cc) : "d" (cmd), "a" (sccb)
|
||||
: "cc", "memory");
|
||||
cc >>= 28;
|
||||
if (cc == 3)
|
||||
return -EINVAL;
|
||||
_sclp_wait_int();
|
||||
} while (cc != 0);
|
||||
return (*(unsigned short *)(sccb + 6) == 0x20) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
static int _sclp_setup(int disable)
|
||||
{
|
||||
static unsigned char init_sccb[] = {
|
||||
0x00, 0x1c,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04,
|
||||
0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
unsigned int *masks;
|
||||
int rc;
|
||||
|
||||
memcpy(_sclp_work_area, init_sccb, 28);
|
||||
masks = (unsigned int *)(_sclp_work_area + 12);
|
||||
if (disable)
|
||||
memset(masks, 0, 16);
|
||||
/* SCLP write mask */
|
||||
rc = _sclp_servc(0x00780005, _sclp_work_area);
|
||||
if (rc)
|
||||
return rc;
|
||||
if ((masks[0] & masks[3]) != masks[0] ||
|
||||
(masks[1] & masks[2]) != masks[1])
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _sclp_print(const char *str)
|
||||
{
|
||||
static unsigned char write_head[] = {
|
||||
/* sccb header */
|
||||
0x00, 0x52, /* 0 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
|
||||
/* evbuf */
|
||||
0x00, 0x4a, /* 8 */
|
||||
0x02, 0x00, 0x00, 0x00, /* 10 */
|
||||
/* mdb */
|
||||
0x00, 0x44, /* 14 */
|
||||
0x00, 0x01, /* 16 */
|
||||
0xd4, 0xc4, 0xc2, 0x40, /* 18 */
|
||||
0x00, 0x00, 0x00, 0x01, /* 22 */
|
||||
/* go */
|
||||
0x00, 0x38, /* 26 */
|
||||
0x00, 0x01, /* 28 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 30 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */
|
||||
0x00, 0x00, 0x00, 0x00, /* 50 */
|
||||
0x00, 0x00, /* 54 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */
|
||||
0x00, 0x00, /* 80 */
|
||||
};
|
||||
static unsigned char write_mto[] = {
|
||||
/* mto */
|
||||
0x00, 0x0a, /* 0 */
|
||||
0x00, 0x04, /* 2 */
|
||||
0x10, 0x00, /* 4 */
|
||||
0x00, 0x00, 0x00, 0x00 /* 6 */
|
||||
};
|
||||
unsigned char *ptr, ch;
|
||||
unsigned int count;
|
||||
|
||||
memcpy(_sclp_work_area, write_head, sizeof(write_head));
|
||||
ptr = _sclp_work_area + sizeof(write_head);
|
||||
do {
|
||||
memcpy(ptr, write_mto, sizeof(write_mto));
|
||||
for (count = sizeof(write_mto); (ch = *str++) != 0; count++) {
|
||||
if (ch == 0x0a)
|
||||
break;
|
||||
ptr[count] = _ascebc[ch];
|
||||
}
|
||||
/* Update length fields in mto, mdb, evbuf and sccb */
|
||||
*(unsigned short *) ptr = count;
|
||||
*(unsigned short *)(_sclp_work_area + 14) += count;
|
||||
*(unsigned short *)(_sclp_work_area + 8) += count;
|
||||
*(unsigned short *)(_sclp_work_area + 0) += count;
|
||||
ptr += count;
|
||||
} while (ch != 0);
|
||||
|
||||
/* SCLP write data */
|
||||
return _sclp_servc(0x00760005, _sclp_work_area);
|
||||
}
|
||||
|
||||
int _sclp_print_early(const char *str)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = _sclp_setup(0);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = _sclp_print(str);
|
||||
if (rc)
|
||||
return rc;
|
||||
return _sclp_setup(1);
|
||||
}
|
Loading…
Reference in a new issue