[U-Boot] [PATCH] efi_loader: Fix serial console size detection

Matthias Brugger mbrugger at suse.com
Wed Feb 27 09:55:00 UTC 2019



On 26/02/2019 17:58, Heinrich Schuchardt wrote:
> On 2/26/19 12:46 PM, matthias.bgg at kernel.org wrote:
>> From: Matthias Brugger <mbrugger at suse.com>
>>
>> Function term_read_reply tries to read from the serial console until
>> the end_char was read. This can hang forever if we are, for some reason,
>> not be able to read the full response (e.g. serial buffer too small,
>> frame error). This patch moves the timeout detection into
>> term_read_reply to assure we will make progress.
>>
>> Fixes: 6bb591f704 ("efi_loader: query serial console size reliably")
>> Signed-off-by: Matthias Brugger <mbrugger at suse.com>
> 
> Thanks Matthias for the patch.
> 
> The general direction is right. Yet I would prefer if you could move the
> waiting loop as described below.
> 
>> ---
>>  lib/efi_loader/efi_console.c | 63 +++++++++++++++++++++---------------
>>  1 file changed, 37 insertions(+), 26 deletions(-)
>>
>> diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
>> index 66c33a551d..817220455f 100644
>> --- a/lib/efi_loader/efi_console.c
>> +++ b/lib/efi_loader/efi_console.c
>> @@ -62,6 +62,16 @@ static struct simple_text_output_mode efi_con_mode = {
>>  	.cursor_visible = 1,
>>  };
>>  
>> +static int term_get_char(char *c)
>> +{
>> +	if (tstc()) {
>> +		*c = getc();
>> +		return 0;
>> +	}
>> +
>> +	return 1;
> 
> The function signals an error if the character to read is not yet in the
> UART buffer. I think it would be preferable to put the waiting time (100
> ms is sufficient at 110 baud and above) into this function instead. This
> has the following advantages:
> 
> - We would need only one waiting loop.
> - We could reuse the function in function efi_cin_read_key() where we
>   have another chance to hang waiting for a character.
> 

Ok, I'll do that in v2.

>> +}
>> +
>>  /*
>>   * Receive and parse a reply from the terminal.
>>   *
>> @@ -74,32 +84,42 @@ static int term_read_reply(int *n, int num, char end_char)
>>  {
>>  	char c;
>>  	int i = 0;
>> +	u64 timeout;
>>  
>> -	c = getc();
>> -	if (c != cESC)
>> +	/* Allow up to one second for the response */
>> +	timeout = timer_get_us() + 1000000;
> 
> Even at 110 baud a waiting time of 100 ms is sufficient.
> 

So we don't have to wait up to one second for the first character to arrive as
we did in query_console_serial() before this patch?

>> +	while (!tstc())
>> +		if (timer_get_us() > timeout)
>> +			return -1;
> 
> This loop could be moved to term_get_char().
> 
>> +
>> +	if (term_get_char(&c) || c != cESC)
>>  		return -1;
>> -	c = getc();
>> -	if (c != '[')
>> +
>> +	if (term_get_char(&c) || c != '[')
> 
> We should allow time for this character to arrive.
> 
>>  		return -1;
>>  
>>  	n[0] = 0;
>>  	while (1) {
>> -		c = getc();
>> -		if (c == ';') {
>> -			i++;
>> -			if (i >= num)> +		if (!term_get_char(&c)) {
> 
> On loop entry there is no wait before this term_get_char().

I don't understand, if the character is not yet present, we will loop in the
while until it arrives or we hit the timeout.

Regards,
Matthias

> 
> Best regards
> 
> Heinrich
> 
>> +			if (c == ';') {
>> +				i++;
>> +				if (i >= num)
>> +					return -1;
>> +				n[i] = 0;
>> +				continue;
>> +			} else if (c == end_char) {
>> +				break;
>> +			} else if (c > '9' || c < '0') {
>>  				return -1;
>> -			n[i] = 0;
>> -			continue;
>> -		} else if (c == end_char) {
>> -			break;
>> -		} else if (c > '9' || c < '0') {
>> -			return -1;
>> +			}
>> +
>> +			/* Read one more decimal position */
>> +			n[i] *= 10;
>> +			n[i] += c - '0';
>>  		}
>>  
>> -		/* Read one more decimal position */
>> -		n[i] *= 10;
>> -		n[i] += c - '0';
>> +		if (timer_get_us() > timeout)
>> +			return -1;
>>  	}
>>  	if (i != num - 1)
>>  		return -1;
>> @@ -196,7 +216,6 @@ static int query_console_serial(int *rows, int *cols)
>>  {
>>  	int ret = 0;
>>  	int n[2];
>> -	u64 timeout;
>>  
>>  	/* Empty input buffer */
>>  	while (tstc())
>> @@ -216,14 +235,6 @@ static int query_console_serial(int *rows, int *cols)
>>  	       ESC "[999;999H"	/* Move to bottom right corner */
>>  	       ESC "[6n");	/* Query cursor position */
>>  
>> -	/* Allow up to one second for a response */
>> -	timeout = timer_get_us() + 1000000;
>> -	while (!tstc())
>> -		if (timer_get_us() > timeout) {
>> -			ret = -1;
>> -			goto out;
>> -		}
>> -
>>  	/* Read {rows,cols} */
>>  	if (term_read_reply(n, 2, 'R')) {
>>  		ret = 1;
>>
> 


More information about the U-Boot mailing list