2 * Copyright IBM Corp. 2015
3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
5 #include <linux/kernel.h>
6 #include <asm/ebcdic.h>
8 #include <asm/lowcore.h>
9 #include <asm/processor.h>
12 #define EVTYP_VT220MSG_MASK 0x00000040
13 #define EVTYP_MSG_MASK 0x40000000
15 static char _sclp_work_area
[4096] __aligned(PAGE_SIZE
) __section(data
);
16 static bool have_vt220
__section(data
);
17 static bool have_linemode
__section(data
);
19 static void _sclp_wait_int(void)
21 unsigned long cr0
, cr0_new
, psw_mask
, addr
;
22 psw_t psw_ext_save
, psw_wait
;
24 __ctl_store(cr0
, 0, 0);
25 cr0_new
= cr0
| 0x200;
26 __ctl_load(cr0_new
, 0, 0);
28 psw_ext_save
= S390_lowcore
.external_new_psw
;
29 psw_mask
= __extract_psw();
30 S390_lowcore
.external_new_psw
.mask
= psw_mask
;
31 psw_wait
.mask
= psw_mask
| PSW_MASK_EXT
| PSW_MASK_WAIT
;
32 S390_lowcore
.ext_int_code
= 0;
37 " stg %[addr],%[psw_wait_addr]\n"
38 " stg %[addr],%[psw_ext_addr]\n"
39 " lpswe %[psw_wait]\n"
41 : [addr
] "=&d" (addr
),
42 [psw_wait_addr
] "=Q" (psw_wait
.addr
),
43 [psw_ext_addr
] "=Q" (S390_lowcore
.external_new_psw
.addr
)
44 : [psw_wait
] "Q" (psw_wait
)
46 } while (S390_lowcore
.ext_int_code
!= EXT_IRQ_SERVICE_SIG
);
48 __ctl_load(cr0
, 0, 0);
49 S390_lowcore
.external_new_psw
= psw_ext_save
;
52 static int _sclp_servc(unsigned int cmd
, char *sccb
)
58 " .insn rre,0xb2200000,%1,%2\n"
60 : "=d" (cc
) : "d" (cmd
), "a" (sccb
)
67 return (*(unsigned short *)(sccb
+ 6) == 0x20) ? 0 : -EIO
;
70 static int _sclp_setup(int disable
)
72 static unsigned char init_sccb
[] = {
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
82 memcpy(_sclp_work_area
, init_sccb
, 28);
83 masks
= (unsigned int *)(_sclp_work_area
+ 12);
87 rc
= _sclp_servc(0x00780005, _sclp_work_area
);
90 have_vt220
= masks
[2] & EVTYP_VT220MSG_MASK
;
91 have_linemode
= masks
[2] & EVTYP_MSG_MASK
;
95 /* Output multi-line text using SCLP Message interface. */
96 static void _sclp_print_lm(const char *str
)
98 static unsigned char write_head
[] = {
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
104 0x02, 0x00, 0x00, 0x00, /* 10 */
108 0xd4, 0xc4, 0xc2, 0x40, /* 18 */
109 0x00, 0x00, 0x00, 0x01, /* 22 */
113 0x00, 0x00, 0x00, 0x00, /* 30 */
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */
116 0x00, 0x00, 0x00, 0x00, /* 50 */
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */
123 static unsigned char write_mto
[] = {
128 0x00, 0x00, 0x00, 0x00 /* 6 */
130 unsigned char *ptr
, ch
;
133 memcpy(_sclp_work_area
, write_head
, sizeof(write_head
));
134 ptr
= _sclp_work_area
+ sizeof(write_head
);
136 memcpy(ptr
, write_mto
, sizeof(write_mto
));
137 for (count
= sizeof(write_mto
); (ch
= *str
++) != 0; count
++) {
140 ptr
[count
] = _ascebc
[ch
];
142 /* Update length fields in mto, mdb, evbuf and sccb */
143 *(unsigned short *) ptr
= count
;
144 *(unsigned short *)(_sclp_work_area
+ 14) += count
;
145 *(unsigned short *)(_sclp_work_area
+ 8) += count
;
146 *(unsigned short *)(_sclp_work_area
+ 0) += count
;
150 /* SCLP write data */
151 _sclp_servc(0x00760005, _sclp_work_area
);
154 /* Output multi-line text (plus a newline) using SCLP VT220
157 static void _sclp_print_vt220(const char *str
)
159 static unsigned char const write_head
[] = {
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x1a, 0x00, 0x00, 0x00,
167 size_t len
= strlen(str
);
169 if (sizeof(write_head
) + len
>= sizeof(_sclp_work_area
))
170 len
= sizeof(_sclp_work_area
) - sizeof(write_head
) - 1;
172 memcpy(_sclp_work_area
, write_head
, sizeof(write_head
));
173 memcpy(_sclp_work_area
+ sizeof(write_head
), str
, len
);
174 _sclp_work_area
[sizeof(write_head
) + len
] = '\n';
176 /* Update length fields in evbuf and sccb headers */
177 *(unsigned short *)(_sclp_work_area
+ 8) += len
+ 1;
178 *(unsigned short *)(_sclp_work_area
+ 0) += len
+ 1;
180 /* SCLP write data */
181 (void)_sclp_servc(0x00760005, _sclp_work_area
);
184 /* Output one or more lines of text on the SCLP console (VT220 and /
185 * or line-mode). All lines get terminated; no need for a trailing LF.
187 void _sclp_print_early(const char *str
)
189 if (_sclp_setup(0) != 0)
194 _sclp_print_vt220(str
);