diff mbox

[U-Boot,2/5] Add board_panic_no_console() to deal with early critical errors

Message ID 1332188824-5447-2-git-send-email-sjg@chromium.org
State New, archived
Headers show

Commit Message

Simon Glass March 19, 2012, 8:27 p.m. UTC
This patch adds support for console output in the event of a panic() before
the console is inited. The main purpose of this is to deal with a very early
panic() which would otherwise cause a silent hang.

A new board_pre_console_panic() function is added to the board API. If
provided by the board it will be called in the event of a panic before the
console is ready. This function should turn on all available UARTs and
output the string (plus a newline) if it possibly can.

Signed-off-by: Simon Glass <sjg@chromium.org>
---
 README           |   34 ++++++++++++++++++++++++++++++++++
 include/common.h |    8 ++++++++
 lib/vsprintf.c   |   25 +++++++++++++++++++++++--
 3 files changed, 65 insertions(+), 2 deletions(-)

Comments

Graeme Russ March 20, 2012, 10:26 p.m. UTC | #1
Hi Simon,

On Tue, Mar 20, 2012 at 7:27 AM, Simon Glass <sjg@chromium.org> wrote:
> This patch adds support for console output in the event of a panic() before
> the console is inited. The main purpose of this is to deal with a very early
> panic() which would otherwise cause a silent hang.
>
> A new board_pre_console_panic() function is added to the board API. If
> provided by the board it will be called in the event of a panic before the
> console is ready. This function should turn on all available UARTs and
> output the string (plus a newline) if it possibly can.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---

>  void panic(const char *fmt, ...)
>  {
> +       char str[CONFIG_SYS_PBSIZE];
>        va_list args;
> +
>        va_start(args, fmt);
> -       vprintf(fmt, args);
> -       putc('\n');
> +       vsnprintf(str, sizeof(str), fmt, args);
>        va_end(args);
> +
> +       if (gd->have_console) {
> +               puts(str);
> +               putc('\n');
> +       } else {
> +               board_pre_console_panic(str);
> +       }
> +

Would there be benefit in including an option to dump the pre-console
buffer (if one is enabled) - I think it's contents could be rather useful
in debugging what went wrong...

And something is nagging at me that the API is just 'not right'. I don't
know exactly why, but I really don't like how this is plumbed

panic() calls putc() which, if we do not have a console (and we won't in
the case of the early panic case we are dealing with), will be put into
the pre console buffer (if enabled)

So having panic() call a board specific function to dump the pre console
buffer after the  vprintf() / putc() would achieve the same result (but
you need pre console buffer enabled)

So, if CONFIG_PRE_CONSOLE_BUFFER is defined, we could simply add a call to
dump_pre_console_buffer() at the end of panic(). But we already have a
function to do that - print_pre_console_buffer(). If we added an argument
to print_pre_console_buffer() which is a pointer to a 'putc()' type
function (NULL meaning the standard putc()) and that function lived in the
board files then life would be good. We could also add a call to a setup
function so we are not setting up the UARTS every putc (not that
performance is a priority at this stage, but some boards might quibble
about hitting certain registers continuously)

But what to do if pre console buffer is not defined? The panic message
needs to be sent directly to the 'panic UARTS'...

OK, so what about in panic():
 - If gd->have_console is not set:
    o call the board specific setup_panic_uarts()
    o call print_pre_console_buffer() passing panic_putc()
    o call panic_putc() for all characters in str[]
 - If gd->have_console is set:
    o call putc() for all characters in str[]

setup_panic_uarts() and panic_putc() are overriden in the board files

Regards,

Graeme
Simon Glass March 20, 2012, 11:22 p.m. UTC | #2
Hi Graeme,

On Tue, Mar 20, 2012 at 3:26 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
> Hi Simon,
>
> On Tue, Mar 20, 2012 at 7:27 AM, Simon Glass <sjg@chromium.org> wrote:
>> This patch adds support for console output in the event of a panic() before
>> the console is inited. The main purpose of this is to deal with a very early
>> panic() which would otherwise cause a silent hang.
>>
>> A new board_pre_console_panic() function is added to the board API. If
>> provided by the board it will be called in the event of a panic before the
>> console is ready. This function should turn on all available UARTs and
>> output the string (plus a newline) if it possibly can.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> ---
>
>>  void panic(const char *fmt, ...)
>>  {
>> +       char str[CONFIG_SYS_PBSIZE];
>>        va_list args;
>> +
>>        va_start(args, fmt);
>> -       vprintf(fmt, args);
>> -       putc('\n');
>> +       vsnprintf(str, sizeof(str), fmt, args);
>>        va_end(args);
>> +
>> +       if (gd->have_console) {
>> +               puts(str);
>> +               putc('\n');
>> +       } else {
>> +               board_pre_console_panic(str);
>> +       }
>> +
>
> Would there be benefit in including an option to dump the pre-console
> buffer (if one is enabled) - I think it's contents could be rather useful
> in debugging what went wrong...
>
> And something is nagging at me that the API is just 'not right'. I don't
> know exactly why, but I really don't like how this is plumbed
>
> panic() calls putc() which, if we do not have a console (and we won't in
> the case of the early panic case we are dealing with), will be put into
> the pre console buffer (if enabled)
>
> So having panic() call a board specific function to dump the pre console
> buffer after the  vprintf() / putc() would achieve the same result (but
> you need pre console buffer enabled)
>
> So, if CONFIG_PRE_CONSOLE_BUFFER is defined, we could simply add a call to
> dump_pre_console_buffer() at the end of panic(). But we already have a
> function to do that - print_pre_console_buffer(). If we added an argument
> to print_pre_console_buffer() which is a pointer to a 'putc()' type
> function (NULL meaning the standard putc()) and that function lived in the
> board files then life would be good. We could also add a call to a setup
> function so we are not setting up the UARTS every putc (not that
> performance is a priority at this stage, but some boards might quibble
> about hitting certain registers continuously)
>
> But what to do if pre console buffer is not defined? The panic message
> needs to be sent directly to the 'panic UARTS'...
>
> OK, so what about in panic():
>  - If gd->have_console is not set:
>    o call the board specific setup_panic_uarts()
>    o call print_pre_console_buffer() passing panic_putc()
>    o call panic_putc() for all characters in str[]
>  - If gd->have_console is set:
>    o call putc() for all characters in str[]
>
> setup_panic_uarts() and panic_putc() are overriden in the board files

I think this is where we got to last time.

The act of calling this pre-console panic function is destructive - it
may hang the board and output data to UARTs.

I think I understand the scheme you propose. But setup_panic_uarts()
puts the board into a funny state (e.g. may set up or change clocks
and pinmux). You then need a board_pre_console_putc() to actually
output the characters - you don't mention that. That was the patch
that I reverted :-( Yes I understand that you can separate out the
UART init from the part that outputs the characters, but does that
really help?

To put it another way, I think we need to stick with the idea that
this is a panic, not a normal situation. That means that return from
the board panic output function may be difficult or impossible, and so
a putc() arrangement is not a good idea.

For example, I have another board on which there are two possible
oscillator clock settings - and we don't know which to use, and the
arch clock code has not yet been called! In that case I want the
board_pre_console_panic() function to output the string using both
options, so that one will produce a message for the user (the other
will likely produce just a few characters of garbage because the baud
rate is wrong). If we output only a single character then the garbage
and good characters will be interspersed.

So, can we get away from the idea that this is a reliable and stable
way of outputting characters before the console is ready? If you want
the pre-console output, I'm sure we can provide a way of accessing it
which the board pre-console panic function can use.

Regards,
Simon

>
> Regards,
>
> Graeme
Graeme Russ March 20, 2012, 11:43 p.m. UTC | #3
Hi Simon,

On Wed, Mar 21, 2012 at 10:22 AM, Simon Glass <sjg@chromium.org> wrote:
> Hi Graeme,
>
> On Tue, Mar 20, 2012 at 3:26 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
>> Hi Simon,
>>

>>
>> OK, so what about in panic():
>>  - If gd->have_console is not set:
>>    o call the board specific setup_panic_uarts()
>>    o call print_pre_console_buffer() passing panic_putc()
>>    o call panic_putc() for all characters in str[]
>>  - If gd->have_console is set:
>>    o call putc() for all characters in str[]
>>
>> setup_panic_uarts() and panic_putc() are overriden in the board files
>
> I think this is where we got to last time.
>
> The act of calling this pre-console panic function is destructive - it
> may hang the board and output data to UARTs.
>
> I think I understand the scheme you propose. But setup_panic_uarts()
> puts the board into a funny state (e.g. may set up or change clocks
> and pinmux). You then need a board_pre_console_putc() to actually
> output the characters - you don't mention that. That was the patch

That's panic_putc()

> that I reverted :-( Yes I understand that you can separate out the
> UART init from the part that outputs the characters, but does that
> really help?
>
> To put it another way, I think we need to stick with the idea that
> this is a panic, not a normal situation. That means that return from

Agreed

> the board panic output function may be difficult or impossible, and so
> a putc() arrangement is not a good idea.
>
> For example, I have another board on which there are two possible
> oscillator clock settings - and we don't know which to use, and the
> arch clock code has not yet been called! In that case I want the
> board_pre_console_panic() function to output the string using both
> options, so that one will produce a message for the user (the other
> will likely produce just a few characters of garbage because the baud
> rate is wrong). If we output only a single character then the garbage
> and good characters will be interspersed.

Ouch!

> So, can we get away from the idea that this is a reliable and stable
> way of outputting characters before the console is ready? If you want
> the pre-console output, I'm sure we can provide a way of accessing it
> which the board pre-console panic function can use.

OK, add a function to 'normalise' the pre console buffer by moving the
characters so the string starts at the beginning of the buffer and then
add an extra format tot he start of the panic string :) - But now the
panic buffer needs to be bigger :(

OK, maybe leave it up to the board code to dump the pre-console buffer...

I dunno - It all seems a bit 'wrong' somehow

Regards,

Graeme
Simon Glass March 21, 2012, 12:06 a.m. UTC | #4
Hi Graeme,

On Tue, Mar 20, 2012 at 4:43 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
> Hi Simon,
>
> On Wed, Mar 21, 2012 at 10:22 AM, Simon Glass <sjg@chromium.org> wrote:
>> Hi Graeme,
>>
>> On Tue, Mar 20, 2012 at 3:26 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
>>> Hi Simon,
>>>
>
>>>
>>> OK, so what about in panic():
>>>  - If gd->have_console is not set:
>>>    o call the board specific setup_panic_uarts()
>>>    o call print_pre_console_buffer() passing panic_putc()
>>>    o call panic_putc() for all characters in str[]
>>>  - If gd->have_console is set:
>>>    o call putc() for all characters in str[]
>>>
>>> setup_panic_uarts() and panic_putc() are overriden in the board files
>>
>> I think this is where we got to last time.
>>
>> The act of calling this pre-console panic function is destructive - it
>> may hang the board and output data to UARTs.
>>
>> I think I understand the scheme you propose. But setup_panic_uarts()
>> puts the board into a funny state (e.g. may set up or change clocks
>> and pinmux). You then need a board_pre_console_putc() to actually
>> output the characters - you don't mention that. That was the patch
>
> That's panic_putc()
>
>> that I reverted :-( Yes I understand that you can separate out the
>> UART init from the part that outputs the characters, but does that
>> really help?
>>
>> To put it another way, I think we need to stick with the idea that
>> this is a panic, not a normal situation. That means that return from
>
> Agreed
>
>> the board panic output function may be difficult or impossible, and so
>> a putc() arrangement is not a good idea.
>>
>> For example, I have another board on which there are two possible
>> oscillator clock settings - and we don't know which to use, and the
>> arch clock code has not yet been called! In that case I want the
>> board_pre_console_panic() function to output the string using both
>> options, so that one will produce a message for the user (the other
>> will likely produce just a few characters of garbage because the baud
>> rate is wrong). If we output only a single character then the garbage
>> and good characters will be interspersed.
>
> Ouch!

Indeed.

>
>> So, can we get away from the idea that this is a reliable and stable
>> way of outputting characters before the console is ready? If you want
>> the pre-console output, I'm sure we can provide a way of accessing it
>> which the board pre-console panic function can use.
>
> OK, add a function to 'normalise' the pre console buffer by moving the
> characters so the string starts at the beginning of the buffer and then
> add an extra format tot he start of the panic string :) - But now the
> panic buffer needs to be bigger :(
>
> OK, maybe leave it up to the board code to dump the pre-console buffer...

Yes I think it is simpler for now, until we have a better framework.
Both the kernel and U-Boot need early access to information that
either might not arrive, or will only arrive later. This business and
the current hacks in the zImage wrapper are examples of problems that
need solving properly IMO. I am looking at these problems for the
U-Boot SPL case, so at some point this will get nicer in U-Boot. Not
sure about the kernel yet, but hope to avoid zImage for our next
iteration partly because of this nastiness.

>
> I dunno - It all seems a bit 'wrong' somehow

I think you are looking for a unified panic architecture with a
board-specific putc(). That was my previous patch and I just don't
think it works. This new one does solve the problem, avoids Wolfgangs
concerns about dangerous UART output, and is pretty simple to
implement. I believe there is a better way, but we are in the very
early days with device tree, life goes on, and this does work...

Regards,
Simon

>
> Regards,
>
> Graeme
Stephen Warren March 21, 2012, 12:34 a.m. UTC | #5
On 03/20/2012 05:22 PM, Simon Glass wrote:
> On Tue, Mar 20, 2012 at 3:26 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
...
>> OK, so what about in panic():
>>  - If gd->have_console is not set:
>>    o call the board specific setup_panic_uarts()
>>    o call print_pre_console_buffer() passing panic_putc()
>>    o call panic_putc() for all characters in str[]
>>  - If gd->have_console is set:
>>    o call putc() for all characters in str[]
>>
>> setup_panic_uarts() and panic_putc() are overriden in the board files
> 
> I think this is where we got to last time.
> 
> The act of calling this pre-console panic function is destructive - it
> may hang the board and output data to UARTs.

Why would it hang? Well, I assume you're talking about hanging before
actually emitting the panic text, rather than looping afterwards as a
deliberate choice. I'd consider an accidental hang that prevented the
message being seen as a bug.
Simon Glass March 21, 2012, 12:36 a.m. UTC | #6
Hi Stephen,

On Tue, Mar 20, 2012 at 5:34 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 03/20/2012 05:22 PM, Simon Glass wrote:
>> On Tue, Mar 20, 2012 at 3:26 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
> ...
>>> OK, so what about in panic():
>>>  - If gd->have_console is not set:
>>>    o call the board specific setup_panic_uarts()
>>>    o call print_pre_console_buffer() passing panic_putc()
>>>    o call panic_putc() for all characters in str[]
>>>  - If gd->have_console is set:
>>>    o call putc() for all characters in str[]
>>>
>>> setup_panic_uarts() and panic_putc() are overriden in the board files
>>
>> I think this is where we got to last time.
>>
>> The act of calling this pre-console panic function is destructive - it
>> may hang the board and output data to UARTs.
>
> Why would it hang? Well, I assume you're talking about hanging before
> actually emitting the panic text, rather than looping afterwards as a
> deliberate choice. I'd consider an accidental hang that prevented the
> message being seen as a bug.

No I would hope it would output the data first. I was merely pointing
out that the board function may decide to hang rather than return
(although I feel it is safe to return since it is being called from
panic() anyway).

Regards,
Simon
Wolfgang Denk March 21, 2012, 9:02 a.m. UTC | #7
Dear Simon Glass,

In message <1332188824-5447-2-git-send-email-sjg@chromium.org> you wrote:
> This patch adds support for console output in the event of a panic() before
> the console is inited. The main purpose of this is to deal with a very early
> panic() which would otherwise cause a silent hang.
> 
> A new board_pre_console_panic() function is added to the board API. If
> provided by the board it will be called in the event of a panic before the
> console is ready. This function should turn on all available UARTs and
> output the string (plus a newline) if it possibly can.

In addition to the more constructive comments made already by Grame, I
object against this patch because I dislike the whole concept.

> +- Pre-console panic():
> +		Prior to the console being initialised, console output is
> +		normally silently discarded. This can be annoying if a
> +		panic() happens in this time. One reason for this might be

True.  This is the reason why it has always been an important design
rule for U-Boot to initialize the console port as soon as possible.

> +		that you have CONFIG_OF_CONTROL defined but have not
> +		provided a valid device tree for U-Boot. In general U-Boot's
> +		console code cannot resolve this problem, since the console
> +		has not been set up, and it may not be known which UART is
> +		the console anyway (for example if this information is in
> +		the device tree).

Please make up your mind:  either you CAN initialize the console, then
you can use it to output messages in a regular way, or you CANNOT
initialize it, in which case you cannot print anything.  There is no
third option.

> +		The solution is to define a function called
> +		board_pre_console_panic() for your board, which alerts the
> +		user however it can. Hopefuly this will involve displaying
> +		a message on available UARTs, or perhaps at least flashing

If you have "available UARTs", you could use this as console, right?

In the previous discussion you explained the situation differently -
you were talking about _any_ UARTs that might be present on the
hardware, without caring about twhat these might actually be used for.

I explained that such an approach is highly dangerous.  I do not want
you toi set a precedent for such stle and code.

> +		an LED. The function should be very careful to only output
> +		to UARTs that are known to be unused for peripheral
> +		interfaces, and change GPIOs that will have no ill effect
> +		on the board. That said, it is fine to do something
> +		destructive that will prevent the board from continuing to
> +		boot, since it isn't going to...

Sorry, but this is bogus. Either you know the console port, or you
don't.  If there is a free UART, it might be attached to custome
hardware you have no idea about.  Ditto for GPIOs.  Please do not
meddle with device state in arbitrary ways.  If there are LED ports on
that board that are intended to signalize status information then it
makes sense to use these - but do not use any other ports that might
be present on the hardware.

> +		The function will need to output serial data directly,
> +		since the console code is not functional yet. Note that if

This is broken design.  If you can initialize the UART as console,
then doi so and use it in the regular way.

> +		the panic happens early enough, then it is possible that
> +		board_init_f() (or even arch_cpu_init() on ARM) has not
> +		been called yet. You should init all clocks, GPIOs, etc.
> +		that are needed to get the string out. Baud rates will need
> +		to default to something sensible.

Again, this is broken design.  We cannot try to catch errors sooner
and sooner and soner, and if needed initialization steps have not been
executed yet, provide additional code for emergency initialization.
We have regular console code, and now we have pre_console_*() stuff,
and soon we will have pre_pre_pre_pre_pre_pre_pre_pre_console_*()
stuff ? NAK.

Just stick to the design principles, and make sure there is as few
stuff that could possibly go wrong before console initialization as
possible.  Than all this crap (excuse me, but I don;t find a better
word) will not be needed.


I also dislike the modifications to the common code.


I think you are trying to solve an unsolvable problem.  If you cannot
accept that the board gets stuck without printing anything on the
debug console port because there are situations when you don't know
which port this is, then you simply should _define_ and _document_ a
single port as debug console port.  Then initialize and use this in
the regular way.  If later information (like from a loaded device
tree) means the console gets switched to anothe rport, that's OK.
That's what Linux will do as well if you assign another console port
there.


Best regards,

Wolfgang Denk
Simon Glass March 21, 2012, 4:17 p.m. UTC | #8
Hi Wolfgang,

On Wed, Mar 21, 2012 at 2:02 AM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Simon Glass,
>
> In message <1332188824-5447-2-git-send-email-sjg@chromium.org> you wrote:
>> This patch adds support for console output in the event of a panic() before
>> the console is inited. The main purpose of this is to deal with a very early
>> panic() which would otherwise cause a silent hang.
>>
>> A new board_pre_console_panic() function is added to the board API. If
>> provided by the board it will be called in the event of a panic before the
>> console is ready. This function should turn on all available UARTs and
>> output the string (plus a newline) if it possibly can.
>
> In addition to the more constructive comments made already by Grame, I
> object against this patch because I dislike the whole concept.

Well I don't disagree :-)

>
>> +- Pre-console panic():
>> +             Prior to the console being initialised, console output is
>> +             normally silently discarded. This can be annoying if a
>> +             panic() happens in this time. One reason for this might be
>
> True.  This is the reason why it has always been an important design
> rule for U-Boot to initialize the console port as soon as possible.
>
>> +             that you have CONFIG_OF_CONTROL defined but have not
>> +             provided a valid device tree for U-Boot. In general U-Boot's
>> +             console code cannot resolve this problem, since the console
>> +             has not been set up, and it may not be known which UART is
>> +             the console anyway (for example if this information is in
>> +             the device tree).
>
> Please make up your mind:  either you CAN initialize the console, then
> you can use it to output messages in a regular way, or you CANNOT
> initialize it, in which case you cannot print anything.  There is no
> third option.

Well that is very clear - we cannot. We hit panic() before
console_ready() is called.

>
>> +             The solution is to define a function called
>> +             board_pre_console_panic() for your board, which alerts the
>> +             user however it can. Hopefuly this will involve displaying
>> +             a message on available UARTs, or perhaps at least flashing
>
> If you have "available UARTs", you could use this as console, right?

Yes, if we knew which it was.

>
> In the previous discussion you explained the situation differently -
> you were talking about _any_ UARTs that might be present on the
> hardware, without caring about twhat these might actually be used for.

Yes, basically the only difference with this series is that the board
file can control what UARTs are used.

>
> I explained that such an approach is highly dangerous.  I do not want
> you toi set a precedent for such stle and code.

OK

>
>> +             an LED. The function should be very careful to only output
>> +             to UARTs that are known to be unused for peripheral
>> +             interfaces, and change GPIOs that will have no ill effect
>> +             on the board. That said, it is fine to do something
>> +             destructive that will prevent the board from continuing to
>> +             boot, since it isn't going to...
>
> Sorry, but this is bogus. Either you know the console port, or you
> don't.  If there is a free UART, it might be attached to custome
> hardware you have no idea about.  Ditto for GPIOs.  Please do not
> meddle with device state in arbitrary ways.  If there are LED ports on
> that board that are intended to signalize status information then it
> makes sense to use these - but do not use any other ports that might
> be present on the hardware.

Yes that is true. The board file should know what is safe, but when we
share board files among different hardware variants, we have exactly
this problem.

>
>> +             The function will need to output serial data directly,
>> +             since the console code is not functional yet. Note that if
>
> This is broken design.  If you can initialize the UART as console,
> then doi so and use it in the regular way.
>
>> +             the panic happens early enough, then it is possible that
>> +             board_init_f() (or even arch_cpu_init() on ARM) has not
>> +             been called yet. You should init all clocks, GPIOs, etc.
>> +             that are needed to get the string out. Baud rates will need
>> +             to default to something sensible.
>
> Again, this is broken design.  We cannot try to catch errors sooner
> and sooner and soner, and if needed initialization steps have not been
> executed yet, provide additional code for emergency initialization.
> We have regular console code, and now we have pre_console_*() stuff,
> and soon we will have pre_pre_pre_pre_pre_pre_pre_pre_console_*()
> stuff ? NAK.
>
> Just stick to the design principles, and make sure there is as few
> stuff that could possibly go wrong before console initialization as
> possible.  Than all this crap (excuse me, but I don;t find a better
> word) will not be needed.

Fair enough, and agreed. Thanks for looking at this and providing this info.

We know we won't get to console init in this case - there is a panic()
that happens first. So the existing pre-console putc() becomes our
route to displaying a message. The problem with that is only that the
board init hasn't happened yet, so either the pre-console putc() must
init the UARTs or we need a separate init function.

>
>
> I also dislike the modifications to the common code.
>
>
> I think you are trying to solve an unsolvable problem.  If you cannot
> accept that the board gets stuck without printing anything on the
> debug console port because there are situations when you don't know
> which port this is, then you simply should _define_ and _document_ a
> single port as debug console port.  Then initialize and use this in
> the regular way.  If later information (like from a loaded device
> tree) means the console gets switched to anothe rport, that's OK.
> That's what Linux will do as well if you assign another console port
> there.

Yes we are certainly trying to solve an unsolvable problem. There are
some things that will result in a bricked board and we can't solve all
of them. I would be very happy to just accept that. We have the
pre-console stuff which boards can use to do their best, and that
should be good enough for those that care enough. I actually prefer a
pre-console panic to a pre-console putc(), for reasons I went into at
length, but no matter, it's not that important.

So the existing pre-console putc() can be used, if we can sort out how
to make UART init work. Graeme suggested an approach here - I will see
if I can make that work.

Regards,
Simon

>
>
> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
> Gods don't like people not doing much work. People  who  aren't  busy
> all the time might start to _think_.  - Terry Pratchett, _Small Gods_
Wolfgang Denk March 21, 2012, 10:48 p.m. UTC | #9
Dear Simon,

In message <CAPnjgZ1TBN+Ro8f0nDubAYRi54UAV0LxjrdFz-AW5qBgue1+Fw@mail.gmail.com> you wrote:
> 
> > Please make up your mind:  either you CAN initialize the console, then
> > you can use it to output messages in a regular way, or you CANNOT
> > initialize it, in which case you cannot print anything.  There is no
> > third option.
>
> Well that is very clear - we cannot. We hit panic() before
> console_ready() is called.

OK - but this means that no output to a serial console port can be
done, no matter what you try.

> > If you have "available UARTs", you could use this as console, right?
>
> Yes, if we knew which it was.

This is a design issue.  If there are several similar boards that
shall be handled with the same binary, then you must agree on some
common sub-set of features, like on UART port that is available on all
of these, and use this as (early) console port.

> We know we won't get to console init in this case - there is a panic()
> that happens first. So the existing pre-console putc() becomes our
> route to displaying a message. The problem with that is only that the

No.  When you cannot initialize the console, you cannot output
anything to the console. Period.

If there is a way to do some initialization and output charatcers,
than make this your regular console init code, and use it always,
without any special warts.

> board init hasn't happened yet, so either the pre-console putc() must
> init the UARTs or we need a separate init function.

This makes no sense to me.

> So the existing pre-console putc() can be used, if we can sort out how
> to make UART init work. Graeme suggested an approach here - I will see
> if I can make that work.

I don't think I will accept any "pre-console putc()".  This is such a
dirty hack.  Either you can initialize and use putc, then use the
normal console mechanism for it, or you cannot. And "cannot" means
"cannot" here.

Best regards,

Wolfgang Denk
Wolfgang Denk March 21, 2012, 11:04 p.m. UTC | #10
Dear Simon,

In message <20120321224801.2C000202A4D@gemini.denx.de> I wrote:
> 
> > So the existing pre-console putc() can be used, if we can sort out how
> > to make UART init work. Graeme suggested an approach here - I will see
> > if I can make that work.
> 
> I don't think I will accept any "pre-console putc()".  This is such a
> dirty hack.  Either you can initialize and use putc, then use the
> normal console mechanism for it, or you cannot. And "cannot" means
> "cannot" here.

Sorry, this was not what I meant.  My fingers were faster than my
brain.  The existing code around CONFIG_PRE_CONSOLE_BUFFER (i. e.
storage in a temporary buffer until console bcomes available) is of
course OK with me.

What I meant was: I do not want to have any "pre console UART output"
code.

Best regards,

Wolfgang Denk
diff mbox

Patch

diff --git a/README b/README
index 84757a5..38ce52a 100644
--- a/README
+++ b/README
@@ -638,6 +638,40 @@  The following options need to be configured:
 		'Sane' compilers will generate smaller code if
 		CONFIG_PRE_CON_BUF_SZ is a power of 2
 
+- Pre-console panic():
+		Prior to the console being initialised, console output is
+		normally silently discarded. This can be annoying if a
+		panic() happens in this time. One reason for this might be
+		that you have CONFIG_OF_CONTROL defined but have not
+		provided a valid device tree for U-Boot. In general U-Boot's
+		console code cannot resolve this problem, since the console
+		has not been set up, and it may not be known which UART is
+		the console anyway (for example if this information is in
+		the device tree).
+
+		The solution is to define a function called
+		board_pre_console_panic() for your board, which alerts the
+		user however it can. Hopefuly this will involve displaying
+		a message on available UARTs, or perhaps at least flashing
+		an LED. The function should be very careful to only output
+		to UARTs that are known to be unused for peripheral
+		interfaces, and change GPIOs that will have no ill effect
+		on the board. That said, it is fine to do something
+		destructive that will prevent the board from continuing to
+		boot, since it isn't going to...
+
+		The function will need to output serial data directly,
+		since the console code is not functional yet. Note that if
+		the panic happens early enough, then it is possible that
+		board_init_f() (or even arch_cpu_init() on ARM) has not
+		been called yet. You should init all clocks, GPIOs, etc.
+		that are needed to get the string out. Baud rates will need
+		to default to something sensible.
+
+		If your function returns, then the normal panic processing
+		will occur (it will either hang or reset depending on
+		CONFIG_PANIC_HANG).
+
 - Safe printf() functions
 		Define CONFIG_SYS_VSNPRINTF to compile in safe versions of
 		the printf() functions. These are defined in
diff --git a/include/common.h b/include/common.h
index b588410..9db3a6a 100644
--- a/include/common.h
+++ b/include/common.h
@@ -285,6 +285,14 @@  extern ulong monitor_flash_len;
 int mac_read_from_eeprom(void);
 extern u8 _binary_dt_dtb_start[];	/* embedded device tree blob */
 
+/*
+ * Called during a panic() when no console is available. The board should do
+ * its best to get a message to the user any way it can. This function should
+ * return if it can, in which case the system will either hang or reset.
+ * See panic().
+ */
+void board_pre_console_panic(const char *str);
+
 /* common/flash.c */
 void flash_perror (int);
 
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index e38a4b7..a478ff5ab 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -33,6 +33,9 @@  const char hex_asc[] = "0123456789abcdef";
 #define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
 #define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]
 
+DECLARE_GLOBAL_DATA_PTR;
+
+
 static inline char *pack_hex_byte(char *buf, u8 byte)
 {
 	*buf++ = hex_asc_hi(byte);
@@ -777,13 +780,31 @@  int sprintf(char * buf, const char *fmt, ...)
 	return i;
 }
 
+/* Provide a default function for when no console is available */
+static void __board_pre_console_panic(const char *msg)
+{
+	/* Just return since we can't access the console */
+}
+
+void board_pre_console_panic(const char *msg) __attribute__((weak,
+					alias("__board_pre_console_panic")));
+
 void panic(const char *fmt, ...)
 {
+	char str[CONFIG_SYS_PBSIZE];
 	va_list	args;
+
 	va_start(args, fmt);
-	vprintf(fmt, args);
-	putc('\n');
+	vsnprintf(str, sizeof(str), fmt, args);
 	va_end(args);
+
+	if (gd->have_console) {
+		puts(str);
+		putc('\n');
+	} else {
+		board_pre_console_panic(str);
+	}
+
 #if defined (CONFIG_PANIC_HANG)
 	hang();
 #else