diff mbox series

[kvm-unit-tests,2/3] lib: s390x: sclp: Add compat handling for HMC ASCII consoles

Message ID 20231010073855.26319-3-frankja@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series s390x: Improve console handling | expand

Commit Message

Janosch Frank Oct. 10, 2023, 7:38 a.m. UTC
Without the \r the output of the HMC ASCII console takes a lot of
additional effort to read in comparison to the line mode console.

Additionally we add a console clear for the HMC ASCII console so that
old messages from a previously running operating system are not
polluting the console.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
---
 lib/s390x/sclp-console.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

Comments

Nico Boehr Oct. 10, 2023, 8:35 a.m. UTC | #1
Quoting Janosch Frank (2023-10-10 09:38:54)
[...]
> diff --git a/lib/s390x/sclp-console.c b/lib/s390x/sclp-console.c
> index 19c74e46..313be1e4 100644
> --- a/lib/s390x/sclp-console.c
> +++ b/lib/s390x/sclp-console.c
[...]
> +static bool lpar_ascii_compat;

This only toggles adding \r. So why not name it accordingly?
Something like:
  ascii_line_end_dos
or
  ascii_add_cr_line_end

>  static char lm_buff[120];
>  static unsigned char lm_buff_off;
>  static struct spinlock lm_buff_lock;
> @@ -97,14 +100,27 @@ static void sclp_print_ascii(const char *str)
>  {
>         int len = strlen(str);
>         WriteEventData *sccb = (void *)_sccb;
> +       char *str_dest = (char *)&sccb->msg;
> +       int i = 0;
>  
>         sclp_mark_busy();
>         memset(sccb, 0, sizeof(*sccb));
> +
> +       for (; i < len; i++) {
> +               *str_dest = str[i];
> +               str_dest++;
> +               /* Add a \r to the \n for HMC ASCII console */
> +               if (str[i] == '\n' && lpar_ascii_compat) {
> +                       *str_dest = '\r';
> +                       str_dest++;
> +               }
> +       }

Please don't hide the check inside the loop.
Do:
if (lpar_ascii_compat)
  // your loop
else
  memcpy()

Also, please add protection against overflowing sccb->msg (max 4088 bytes
if I looked it up right).

> +       len = (uintptr_t)str_dest - (uintptr_t)&sccb->msg;

And when you do the above, it should be easy to get rid of pointer
subtraction.

[...]
>  void sclp_console_setup(void)
>  {
> +       lpar_ascii_compat = detect_host_early() == HOST_IS_LPAR;
> +
>         /* We send ASCII and line mode. */
>         sclp_write_event_mask(0, SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG);
> +       /* Hard terminal reset to clear screen for HMC ASCII console */
> +       if (lpar_ascii_compat)
> +               sclp_print_ascii("\ec");

I have in the past cursed programs which clear the screen, but I can see
the advantage here. How do others feel about this?
Janosch Frank Oct. 10, 2023, 8:57 a.m. UTC | #2
On 10/10/23 10:35, Nico Boehr wrote:
> Quoting Janosch Frank (2023-10-10 09:38:54)
> [...]
>> diff --git a/lib/s390x/sclp-console.c b/lib/s390x/sclp-console.c
>> index 19c74e46..313be1e4 100644
>> --- a/lib/s390x/sclp-console.c
>> +++ b/lib/s390x/sclp-console.c
> [...]
>> +static bool lpar_ascii_compat;
> 
> This only toggles adding \r. So why not name it accordingly?

Because it also toggles clearing the screen

> Something like:
>    ascii_line_end_dos
> or
>    ascii_add_cr_line_end
> 
>>   static char lm_buff[120];
>>   static unsigned char lm_buff_off;
>>   static struct spinlock lm_buff_lock;
>> @@ -97,14 +100,27 @@ static void sclp_print_ascii(const char *str)
>>   {
>>          int len = strlen(str);
>>          WriteEventData *sccb = (void *)_sccb;
>> +       char *str_dest = (char *)&sccb->msg;
>> +       int i = 0;
>>   
>>          sclp_mark_busy();
>>          memset(sccb, 0, sizeof(*sccb));
>> +
>> +       for (; i < len; i++) {
>> +               *str_dest = str[i];
>> +               str_dest++;
>> +               /* Add a \r to the \n for HMC ASCII console */
>> +               if (str[i] == '\n' && lpar_ascii_compat) {
>> +                       *str_dest = '\r';
>> +                       str_dest++;
>> +               }
>> +       }
> 
> Please don't hide the check inside the loop.
> Do:
> if (lpar_ascii_compat)
>    // your loop
> else
>    memcpy()


I'd rather have a loop than to nest it inside an if.

> 
> Also, please add protection against overflowing sccb->msg (max 4088 bytes
> if I looked it up right).

I considered this but we already have a 2k length check before that and 
I'd like to see someone print ~2k in a single call.

The question is if we want the complexity for something that we'll very 
likely never hit.

> 
>> +       len = (uintptr_t)str_dest - (uintptr_t)&sccb->msg;
> 
> And when you do the above, it should be easy to get rid of pointer
> subtraction.
> 
> [...]
>>   void sclp_console_setup(void)
>>   {
>> +       lpar_ascii_compat = detect_host_early() == HOST_IS_LPAR;
>> +
>>          /* We send ASCII and line mode. */
>>          sclp_write_event_mask(0, SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG);
>> +       /* Hard terminal reset to clear screen for HMC ASCII console */
>> +       if (lpar_ascii_compat)
>> +               sclp_print_ascii("\ec");
> 
> I have in the past cursed programs which clear the screen, but I can see
> the advantage here. How do others feel about this?
Nico Boehr Oct. 10, 2023, 12:35 p.m. UTC | #3
Quoting Janosch Frank (2023-10-10 10:57:24)
> On 10/10/23 10:35, Nico Boehr wrote:
> > Quoting Janosch Frank (2023-10-10 09:38:54)
> > [...]
> >> diff --git a/lib/s390x/sclp-console.c b/lib/s390x/sclp-console.c
> >> index 19c74e46..313be1e4 100644
> >> --- a/lib/s390x/sclp-console.c
> >> +++ b/lib/s390x/sclp-console.c
> > [...]
> >> +static bool lpar_ascii_compat;
> > 
> > This only toggles adding \r. So why not name it accordingly?
> 
> Because it also toggles clearing the screen

OK

[...]
> >> @@ -97,14 +100,27 @@ static void sclp_print_ascii(const char *str)
> >>   {
> >>          int len = strlen(str);
> >>          WriteEventData *sccb = (void *)_sccb;
> >> +       char *str_dest = (char *)&sccb->msg;
> >> +       int i = 0;
> >>   
> >>          sclp_mark_busy();
> >>          memset(sccb, 0, sizeof(*sccb));
> >> +
> >> +       for (; i < len; i++) {
> >> +               *str_dest = str[i];
> >> +               str_dest++;
> >> +               /* Add a \r to the \n for HMC ASCII console */
> >> +               if (str[i] == '\n' && lpar_ascii_compat) {
> >> +                       *str_dest = '\r';
> >> +                       str_dest++;
> >> +               }
> >> +       }
> > 
> > Please don't hide the check inside the loop.
> > Do:
> > if (lpar_ascii_compat)
> >    // your loop
> > else
> >    memcpy()
> 
> 
> I'd rather have a loop than to nest it inside an if.

I disagree, but it's not worth discussing too much over this.

> > Also, please add protection against overflowing sccb->msg (max 4088 bytes
> > if I looked it up right).
> 
> I considered this but we already have a 2k length check before that

...which is not sufficient...

> and I'd like to see someone print ~2k in a single call.
> 
> The question is if we want the complexity for something that we'll very 
> likely never hit.

IMO we want it since it can lead to random memory corruption which can be
very hard to debug.

And I don't think it's complex since in the simplest case you could just go
with a strnlen() here. Better just truncate the string than to corrupt
random memory.
diff mbox series

Patch

diff --git a/lib/s390x/sclp-console.c b/lib/s390x/sclp-console.c
index 19c74e46..313be1e4 100644
--- a/lib/s390x/sclp-console.c
+++ b/lib/s390x/sclp-console.c
@@ -11,6 +11,7 @@ 
 #include <asm/arch_def.h>
 #include <asm/io.h>
 #include <asm/spinlock.h>
+#include "hardware.h"
 #include "sclp.h"
 
 /*
@@ -85,6 +86,8 @@  static uint8_t _ascebc[256] = {
      0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
 };
 
+static bool lpar_ascii_compat;
+
 static char lm_buff[120];
 static unsigned char lm_buff_off;
 static struct spinlock lm_buff_lock;
@@ -97,14 +100,27 @@  static void sclp_print_ascii(const char *str)
 {
 	int len = strlen(str);
 	WriteEventData *sccb = (void *)_sccb;
+	char *str_dest = (char *)&sccb->msg;
+	int i = 0;
 
 	sclp_mark_busy();
 	memset(sccb, 0, sizeof(*sccb));
+
+	for (; i < len; i++) {
+		*str_dest = str[i];
+		str_dest++;
+		/* Add a \r to the \n for HMC ASCII console */
+		if (str[i] == '\n' && lpar_ascii_compat) {
+			*str_dest = '\r';
+			str_dest++;
+		}
+	}
+
+	len = (uintptr_t)str_dest - (uintptr_t)&sccb->msg;
 	sccb->h.length = offsetof(WriteEventData, msg) + len;
 	sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
 	sccb->ebh.length = sizeof(EventBufferHeader) + len;
 	sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
-	memcpy(&sccb->msg, str, len);
 
 	sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
 }
@@ -218,8 +234,13 @@  static void sclp_console_disable_read(void)
 
 void sclp_console_setup(void)
 {
+	lpar_ascii_compat = detect_host_early() == HOST_IS_LPAR;
+
 	/* We send ASCII and line mode. */
 	sclp_write_event_mask(0, SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG);
+	/* Hard terminal reset to clear screen for HMC ASCII console */
+	if (lpar_ascii_compat)
+		sclp_print_ascii("\ec");
 }
 
 void sclp_print(const char *str)