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
);
16 static bool have_vt220
, have_linemode
;
18 static void _sclp_wait_int(void)
20 unsigned long cr0
, cr0_new
, psw_mask
, addr
;
21 psw_t psw_ext_save
, psw_wait
;
23 __ctl_store(cr0
, 0, 0);
24 cr0_new
= cr0
| 0x200;
25 __ctl_load(cr0_new
, 0, 0);
27 psw_ext_save
= S390_lowcore
.external_new_psw
;
28 psw_mask
= __extract_psw();
29 S390_lowcore
.external_new_psw
.mask
= psw_mask
;
30 psw_wait
.mask
= psw_mask
| PSW_MASK_EXT
| PSW_MASK_WAIT
;
31 S390_lowcore
.ext_int_code
= 0;
36 " stg %[addr],%[psw_wait_addr]\n"
37 " stg %[addr],%[psw_ext_addr]\n"
38 " lpswe %[psw_wait]\n"
40 : [addr
] "=&d" (addr
),
41 [psw_wait_addr
] "=Q" (psw_wait
.addr
),
42 [psw_ext_addr
] "=Q" (S390_lowcore
.external_new_psw
.addr
)
43 : [psw_wait
] "Q" (psw_wait
)
45 } while (S390_lowcore
.ext_int_code
!= EXT_IRQ_SERVICE_SIG
);
47 __ctl_load(cr0
, 0, 0);
48 S390_lowcore
.external_new_psw
= psw_ext_save
;
51 static int _sclp_servc(unsigned int cmd
, char *sccb
)
57 " .insn rre,0xb2200000,%1,%2\n"
59 : "=d" (cc
) : "d" (cmd
), "a" (sccb
)
66 return (*(unsigned short *)(sccb
+ 6) == 0x20) ? 0 : -EIO
;
69 static int _sclp_setup(int disable
)
71 static unsigned char init_sccb
[] = {
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81 memcpy(_sclp_work_area
, init_sccb
, 28);
82 masks
= (unsigned int *)(_sclp_work_area
+ 12);
86 rc
= _sclp_servc(0x00780005, _sclp_work_area
);
89 have_vt220
= masks
[2] & EVTYP_VT220MSG_MASK
;
90 have_linemode
= masks
[2] & EVTYP_MSG_MASK
;
94 /* Output multi-line text using SCLP Message interface. */
95 static void _sclp_print_lm(const char *str
)
97 static unsigned char write_head
[] = {
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
103 0x02, 0x00, 0x00, 0x00, /* 10 */
107 0xd4, 0xc4, 0xc2, 0x40, /* 18 */
108 0x00, 0x00, 0x00, 0x01, /* 22 */
112 0x00, 0x00, 0x00, 0x00, /* 30 */
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */
115 0x00, 0x00, 0x00, 0x00, /* 50 */
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */
122 static unsigned char write_mto
[] = {
127 0x00, 0x00, 0x00, 0x00 /* 6 */
129 unsigned char *ptr
, ch
;
132 memcpy(_sclp_work_area
, write_head
, sizeof(write_head
));
133 ptr
= _sclp_work_area
+ sizeof(write_head
);
135 memcpy(ptr
, write_mto
, sizeof(write_mto
));
136 for (count
= sizeof(write_mto
); (ch
= *str
++) != 0; count
++) {
139 ptr
[count
] = _ascebc
[ch
];
141 /* Update length fields in mto, mdb, evbuf and sccb */
142 *(unsigned short *) ptr
= count
;
143 *(unsigned short *)(_sclp_work_area
+ 14) += count
;
144 *(unsigned short *)(_sclp_work_area
+ 8) += count
;
145 *(unsigned short *)(_sclp_work_area
+ 0) += count
;
149 /* SCLP write data */
150 _sclp_servc(0x00760005, _sclp_work_area
);
153 /* Output multi-line text (plus a newline) using SCLP VT220
156 static void _sclp_print_vt220(const char *str
)
158 static unsigned char const write_head
[] = {
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x1a, 0x00, 0x00, 0x00,
166 size_t len
= strlen(str
);
168 if (sizeof(write_head
) + len
>= sizeof(_sclp_work_area
))
169 len
= sizeof(_sclp_work_area
) - sizeof(write_head
) - 1;
171 memcpy(_sclp_work_area
, write_head
, sizeof(write_head
));
172 memcpy(_sclp_work_area
+ sizeof(write_head
), str
, len
);
173 _sclp_work_area
[sizeof(write_head
) + len
] = '\n';
175 /* Update length fields in evbuf and sccb headers */
176 *(unsigned short *)(_sclp_work_area
+ 8) += len
+ 1;
177 *(unsigned short *)(_sclp_work_area
+ 0) += len
+ 1;
179 /* SCLP write data */
180 (void)_sclp_servc(0x00760005, _sclp_work_area
);
183 /* Output one or more lines of text on the SCLP console (VT220 and /
184 * or line-mode). All lines get terminated; no need for a trailing LF.
186 void _sclp_print_early(const char *str
)
188 if (_sclp_setup(0) != 0)
193 _sclp_print_vt220(str
);