diff mbox

[U-Boot,V4] console: Implement pre-console buffer

Message ID 1314795505-14321-1-git-send-email-graeme.russ@gmail.com
State Accepted
Headers show

Commit Message

Graeme Russ Aug. 31, 2011, 12:58 p.m. UTC
Allow redirection of console output prior to console initialisation to a
temporary buffer.

To enable this functionality, the board configuration file must define:
 - CONFIG_PRE_CONSOLE_BUFFER - Enable pre-console buffer
 - CONFIG_PRE_CON_BUF_ADDR - Base address of pre-console buffer
 - CONFIG_PRE_CON_BUF_SZ - Size of pre-console buffer (in bytes)

The pre-console buffer will buffer the last CONFIG_PRE_CON_BUF_SZ bytes
Any earlier characters are silently dropped.

Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
---
Changes since V3
 - Fixed  blank subject caused by gap between the Cc: list and Date:

Changes since V2
 - Cast buffer size to unsigned long to help compilers produce tighter
   code
 - Use inline stub functions to reduce #ifdef clutter
 - Add documentation to README

Changes Since V1
 - Implemented circular buffer
 - Trivial code styl corrections

 README                                    |   14 +++++++++
 arch/arm/include/asm/global_data.h        |    3 ++
 arch/avr32/include/asm/global_data.h      |    3 ++
 arch/blackfin/include/asm/global_data.h   |    3 ++
 arch/m68k/include/asm/global_data.h       |    3 ++
 arch/microblaze/include/asm/global_data.h |    3 ++
 arch/mips/include/asm/global_data.h       |    3 ++
 arch/nios2/include/asm/global_data.h      |    3 ++
 arch/powerpc/include/asm/global_data.h    |    3 ++
 arch/sh/include/asm/global_data.h         |    3 ++
 arch/sparc/include/asm/global_data.h      |    3 ++
 arch/x86/include/asm/global_data.h        |    3 ++
 common/console.c                          |   43 +++++++++++++++++++++++++++-
 13 files changed, 88 insertions(+), 2 deletions(-)

--
1.7.5.2.317.g391b14

Comments

Mike Frysinger Aug. 31, 2011, 3:09 p.m. UTC | #1
On Wednesday, August 31, 2011 08:58:25 Graeme Russ wrote:
> Allow redirection of console output prior to console initialisation to a
> temporary buffer.

looks good to me.  doesnt apply, but that's because this needs your other gd 
rework patch.

Acked-by: Mike Frysinger <vapier@gentoo.org>
-mike
Simon Glass Aug. 31, 2011, 4:58 p.m. UTC | #2
Hi Graeme,

On Wed, Aug 31, 2011 at 5:58 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
> Allow redirection of console output prior to console initialisation to a
> temporary buffer.
>
> To enable this functionality, the board configuration file must define:
>  - CONFIG_PRE_CONSOLE_BUFFER - Enable pre-console buffer
>  - CONFIG_PRE_CON_BUF_ADDR - Base address of pre-console buffer
>  - CONFIG_PRE_CON_BUF_SZ - Size of pre-console buffer (in bytes)
>
> The pre-console buffer will buffer the last CONFIG_PRE_CON_BUF_SZ bytes
> Any earlier characters are silently dropped.
>
> Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
> ---
> Changes since V3
>  - Fixed  blank subject caused by gap between the Cc: list and Date:
>
> Changes since V2
>  - Cast buffer size to unsigned long to help compilers produce tighter
>   code
>  - Use inline stub functions to reduce #ifdef clutter
>  - Add documentation to README
>
> Changes Since V1
>  - Implemented circular buffer
>  - Trivial code styl corrections
>
>  README                                    |   14 +++++++++
>  arch/arm/include/asm/global_data.h        |    3 ++
>  arch/avr32/include/asm/global_data.h      |    3 ++
>  arch/blackfin/include/asm/global_data.h   |    3 ++
>  arch/m68k/include/asm/global_data.h       |    3 ++
>  arch/microblaze/include/asm/global_data.h |    3 ++
>  arch/mips/include/asm/global_data.h       |    3 ++
>  arch/nios2/include/asm/global_data.h      |    3 ++
>  arch/powerpc/include/asm/global_data.h    |    3 ++
>  arch/sh/include/asm/global_data.h         |    3 ++
>  arch/sparc/include/asm/global_data.h      |    3 ++
>  arch/x86/include/asm/global_data.h        |    3 ++
>  common/console.c                          |   43 +++++++++++++++++++++++++++-
>  13 files changed, 88 insertions(+), 2 deletions(-)
>
> diff --git a/README b/README
> index 0886987..170e67b 100644
> --- a/README
> +++ b/README
> @@ -619,6 +619,20 @@ The following options need to be configured:
>                must be defined, to setup the maximum idle timeout for
>                the SMC.
>
> +- Pre-Console Buffer:
> +                Prior to the console being initialised (i.e. serial UART
> +                initialised etc) all console output is silently discarded.
> +                Defining CONFIG_PRE_CONSOLE_BUFFER will cause U-Boot to
> +                buffer any console messages prior to the console being
> +                initialised to a buffer of size CONFIG_PRE_CON_BUF_SZ
> +                bytes located at CONFIG_PRE_CON_BUF_ADDR. The buffer is
> +                a cicular buffer, so if more than CONFIG_PRE_CON_BUF_SZ

nit: circular. Just a suggestion if you like: you could also offer
guidance for the location of the buffer, something like:

You can place the buffer at the top of memory by adding something like
this in your board config file:

#define CONFIG_PRE_CON_BUF_ADDR		(CONFIG_SYS_INIT_RAM_ADDR + \
					CONFIG_SYS_INIT_RAM_SIZE - \
					CONFIG_PRE_CON_BUF_SZ)
#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_PRE_CON_BUF_ADDR - \
						GENERATED_GBL_DATA_SIZE)

> +                bytes are output before the console is  initialised, the
> +                earlier bytes are discarded.
> +

Anyway:

Acked-by: Simon Glass <sjg@chromium.org>

Regards,
Simon
Wolfgang Denk Aug. 31, 2011, 7:18 p.m. UTC | #3
Dear Simon Glass,

In message <CAPnjgZ1bMkN3xoNCqtg1CLMa=0rgpHsuyHyZg5yOkR3Hk+v+Bw@mail.gmail.com> you wrote:
> 
> nit: circular. Just a suggestion if you like: you could also offer
> guidance for the location of the buffer, something like:
>
> You can place the buffer at the top of memory by adding something like
> this in your board config file:
>
> #define CONFIG_PRE_CON_BUF_ADDR		(CONFIG_SYS_INIT_RAM_ADDR + \
> 					CONFIG_SYS_INIT_RAM_SIZE - \
> 					CONFIG_PRE_CON_BUF_SZ)
> #define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_PRE_CON_BUF_ADDR - \
> 						GENERATED_GBL_DATA_SIZE)

That would only make sense if these were generic options that are used
across all boards and architectures. 

Best regards,

Wolfgang Denk
Simon Glass Aug. 31, 2011, 8:05 p.m. UTC | #4
Hi Wolfgang,

On Wed, Aug 31, 2011 at 12:18 PM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Simon Glass,
>
> In message <CAPnjgZ1bMkN3xoNCqtg1CLMa=0rgpHsuyHyZg5yOkR3Hk+v+Bw@mail.gmail.com> you wrote:
>>
>> nit: circular. Just a suggestion if you like: you could also offer
>> guidance for the location of the buffer, something like:
>>
>> You can place the buffer at the top of memory by adding something like
>> this in your board config file:
>>
>> #define CONFIG_PRE_CON_BUF_ADDR               (CONFIG_SYS_INIT_RAM_ADDR + \
>>                                       CONFIG_SYS_INIT_RAM_SIZE - \
>>                                       CONFIG_PRE_CON_BUF_SZ)
>> #define CONFIG_SYS_INIT_SP_ADDR               (CONFIG_PRE_CON_BUF_ADDR - \
>>                                               GENERATED_GBL_DATA_SIZE)
>
> That would only make sense if these were generic options that are used
> across all boards and architectures.

Yes ok - its' already decided not to put this code in arch/xxx/board.c
so let's leave this out then.

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
> If it went on at this rate, in several billion  years  he'd  be  rich
> beyond his wildest dreams!            - Terry Pratchett, _Soul Music_
>
Mike Frysinger Aug. 31, 2011, 8:22 p.m. UTC | #5
On Wednesday, August 31, 2011 16:05:38 Simon Glass wrote:
> On Wed, Aug 31, 2011 at 12:18 PM, Wolfgang Denk wrote:
> > Simon Glass wrote:
> >> nit: circular. Just a suggestion if you like: you could also offer
> >> guidance for the location of the buffer, something like:
> >> 
> >> You can place the buffer at the top of memory by adding something like
> >> this in your board config file:
> >> 
> >> #define CONFIG_PRE_CON_BUF_ADDR               (CONFIG_SYS_INIT_RAM_ADDR
> >> + \ CONFIG_SYS_INIT_RAM_SIZE - \ CONFIG_PRE_CON_BUF_SZ)
> >> #define CONFIG_SYS_INIT_SP_ADDR               (CONFIG_PRE_CON_BUF_ADDR -
> >> \ GENERATED_GBL_DATA_SIZE)
> > 
> > That would only make sense if these were generic options that are used
> > across all boards and architectures.
> 
> Yes ok - its' already decided not to put this code in arch/xxx/board.c
> so let's leave this out then.

fwiw, i'll probably do that in Blackfin's default arch config.h so that boards 
get a sane default that'll work across all Blackfin cpus
-mike
Simon Glass Aug. 31, 2011, 8:26 p.m. UTC | #6
On Wed, Aug 31, 2011 at 1:22 PM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Wednesday, August 31, 2011 16:05:38 Simon Glass wrote:
>> On Wed, Aug 31, 2011 at 12:18 PM, Wolfgang Denk wrote:
>> > Simon Glass wrote:
>> >> nit: circular. Just a suggestion if you like: you could also offer
>> >> guidance for the location of the buffer, something like:
>> >>
>> >> You can place the buffer at the top of memory by adding something like
>> >> this in your board config file:
>> >>
>> >> #define CONFIG_PRE_CON_BUF_ADDR               (CONFIG_SYS_INIT_RAM_ADDR
>> >> + \ CONFIG_SYS_INIT_RAM_SIZE - \ CONFIG_PRE_CON_BUF_SZ)
>> >> #define CONFIG_SYS_INIT_SP_ADDR               (CONFIG_PRE_CON_BUF_ADDR -
>> >> \ GENERATED_GBL_DATA_SIZE)
>> >
>> > That would only make sense if these were generic options that are used
>> > across all boards and architectures.
>>
>> Yes ok - its' already decided not to put this code in arch/xxx/board.c
>> so let's leave this out then.
>
> fwiw, i'll probably do that in Blackfin's default arch config.h so that boards
> get a sane default that'll work across all Blackfin cpus

SGTM - this sort of address arithmetic in every board header file is a bit ick.

> -mike
>
Graeme Russ Aug. 31, 2011, 9:15 p.m. UTC | #7
Hi Mike,

On 01/09/11 01:09, Mike Frysinger wrote:
> On Wednesday, August 31, 2011 08:58:25 Graeme Russ wrote:
>> Allow redirection of console output prior to console initialisation to a
>> temporary buffer.
> 
> looks good to me.  doesnt apply, but that's because this needs your other gd 
> rework patch.
> 
> Acked-by: Mike Frysinger <vapier@gentoo.org>
> -mike

It should apply - This patch does not depend on my 'flagify' patch set

Regards,

Graeme
Mike Frysinger Aug. 31, 2011, 9:33 p.m. UTC | #8
On Wednesday, August 31, 2011 17:15:25 Graeme Russ wrote:
> On 01/09/11 01:09, Mike Frysinger wrote:
> > On Wednesday, August 31, 2011 08:58:25 Graeme Russ wrote:
> >> Allow redirection of console output prior to console initialisation to a
> >> temporary buffer.
> > 
> > looks good to me.  doesnt apply, but that's because this needs your other
> > gd rework patch.
> > 
> > Acked-by: Mike Frysinger <vapier@gentoo.org>
> > -mike
> 
> It should apply - This patch does not depend on my 'flagify' patch set

err, yeah, i skipped 1/2 since the subject lost "2/2" but gained "v4" :)

no biggie
-mike
Graeme Russ Aug. 31, 2011, 9:59 p.m. UTC | #9
Hi Mike

On Thursday, September 1, 2011, Mike Frysinger <vapier@gentoo.org> wrote:
> On Wednesday, August 31, 2011 17:15:25 Graeme Russ wrote:
>> On 01/09/11 01:09, Mike Frysinger wrote:
>> > On Wednesday, August 31, 2011 08:58:25 Graeme Russ wrote:
>> >> Allow redirection of console output prior to console initialisation to
a
>> >> temporary buffer.
>> >
>> > looks good to me.  doesnt apply, but that's because this needs your
other
>> > gd rework patch.
>> >
>> > Acked-by: Mike Frysinger <vapier@gentoo.org>
>> > -mike
>>
>> It should apply - This patch does not depend on my 'flagify' patch set
>
> err, yeah, i skipped 1/2 since the subject lost "2/2" but gained "v4" :)
>
> no biggie

So it applies?

Regards

Graeme
Mike Frysinger Aug. 31, 2011, 10:44 p.m. UTC | #10
On Wednesday, August 31, 2011 17:59:19 Graeme Russ wrote:
> So it applies?

yep.  and even compiles without warnings.
-mike
Graeme Russ Aug. 31, 2011, 10:51 p.m. UTC | #11
Hi Mike,

On Thu, Sep 1, 2011 at 8:44 AM, Mike Frysinger <vapier@gentoo.org> wrote:
> On Wednesday, August 31, 2011 17:59:19 Graeme Russ wrote:
>> So it applies?
>
> yep.  and even compiles without warnings.

Ah, but does it work ;)

Regards,

Graeme
Vadim Bendebury Sept. 26, 2011, 10:50 p.m. UTC | #12
On Wed, Aug 31, 2011 at 5:58 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
> Allow redirection of console output prior to console initialisation to a
> temporary buffer.
>
> To enable this functionality, the board configuration file must define:
>  - CONFIG_PRE_CONSOLE_BUFFER - Enable pre-console buffer
>  - CONFIG_PRE_CON_BUF_ADDR - Base address of pre-console buffer
>  - CONFIG_PRE_CON_BUF_SZ - Size of pre-console buffer (in bytes)
>
> The pre-console buffer will buffer the last CONFIG_PRE_CON_BUF_SZ bytes
> Any earlier characters are silently dropped.
>
> Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
> ---
> Changes since V3
>  - Fixed  blank subject caused by gap between the Cc: list and Date:
>
> Changes since V2
>  - Cast buffer size to unsigned long to help compilers produce tighter
>   code
>  - Use inline stub functions to reduce #ifdef clutter
>  - Add documentation to README
>
> Changes Since V1
>  - Implemented circular buffer
>  - Trivial code styl corrections
>
>  README                                    |   14 +++++++++
>  arch/arm/include/asm/global_data.h        |    3 ++
>  arch/avr32/include/asm/global_data.h      |    3 ++
>  arch/blackfin/include/asm/global_data.h   |    3 ++
>  arch/m68k/include/asm/global_data.h       |    3 ++
>  arch/microblaze/include/asm/global_data.h |    3 ++
>  arch/mips/include/asm/global_data.h       |    3 ++
>  arch/nios2/include/asm/global_data.h      |    3 ++
>  arch/powerpc/include/asm/global_data.h    |    3 ++
>  arch/sh/include/asm/global_data.h         |    3 ++
>  arch/sparc/include/asm/global_data.h      |    3 ++
>  arch/x86/include/asm/global_data.h        |    3 ++

I know I am late to the party here, but all of a sudden I need to
implement something similar, albeit slightly different:

- the memory could be allocated by the "cold bootprom" which starts u-boot;
- all console output needs to be saved, not just until the moment when
the console hardware is initialized.

I could work on top of this patch and send another one once this one
has been accepted. May I suggest an improvement though:

is it really necessary to store the index in the global data
structure. This requires editing all these .h files adding another
unsighty  conditionally compiled field. Why not to store the index as
the first word in the buffer allocated for this temp storage?

cheers,
/vb



>  common/console.c                          |   43 +++++++++++++++++++++++++++-
>  13 files changed, 88 insertions(+), 2 deletions(-)
>
> diff --git a/README b/README
> index 0886987..170e67b 100644
> --- a/README
> +++ b/README
> @@ -619,6 +619,20 @@ The following options need to be configured:
>                must be defined, to setup the maximum idle timeout for
>                the SMC.
>
> +- Pre-Console Buffer:
> +                Prior to the console being initialised (i.e. serial UART
> +                initialised etc) all console output is silently discarded.
> +                Defining CONFIG_PRE_CONSOLE_BUFFER will cause U-Boot to
> +                buffer any console messages prior to the console being
> +                initialised to a buffer of size CONFIG_PRE_CON_BUF_SZ
> +                bytes located at CONFIG_PRE_CON_BUF_ADDR. The buffer is
> +                a cicular buffer, so if more than CONFIG_PRE_CON_BUF_SZ
> +                bytes are output before the console is  initialised, the
> +                earlier bytes are discarded.
> +
> +                'Sane' compilers will generate smaller code if
> +                CONFIG_PRE_CON_BUF_SZ is a power of 2
> +
>  - Boot Delay:  CONFIG_BOOTDELAY - in seconds
>                Delay before automatically booting the default image;
>                set to -1 to disable autoboot.
> diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
> index 4fc51fd..b85b7fe 100644
> --- a/arch/arm/include/asm/global_data.h
> +++ b/arch/arm/include/asm/global_data.h
> @@ -38,6 +38,9 @@ typedef       struct  global_data {
>        unsigned long   flags;
>        unsigned long   baudrate;
>        unsigned long   have_console;   /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        unsigned long   env_addr;       /* Address  of Environment struct */
>        unsigned long   env_valid;      /* Checksum of Environment valid? */
>        unsigned long   fb_base;        /* base address of frame buffer */
> diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h
> index 4ef8fc5..5c654bd 100644
> --- a/arch/avr32/include/asm/global_data.h
> +++ b/arch/avr32/include/asm/global_data.h
> @@ -38,6 +38,9 @@ typedef       struct  global_data {
>        unsigned long   baudrate;
>        unsigned long   stack_end;      /* highest stack address */
>        unsigned long   have_console;   /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        unsigned long   reloc_off;      /* Relocation Offset */
>        unsigned long   env_addr;       /* Address of env struct */
>        unsigned long   env_valid;      /* Checksum of env valid? */
> diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h
> index eba5e93..f7aa711 100644
> --- a/arch/blackfin/include/asm/global_data.h
> +++ b/arch/blackfin/include/asm/global_data.h
> @@ -45,6 +45,9 @@ typedef struct global_data {
>        unsigned long board_type;
>        unsigned long baudrate;
>        unsigned long have_console;     /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        phys_size_t ram_size;           /* RAM size */
>        unsigned long env_addr; /* Address  of Environment struct */
>        unsigned long env_valid;        /* Checksum of Environment valid? */
> diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h
> index fc486fd..0ba2b43 100644
> --- a/arch/m68k/include/asm/global_data.h
> +++ b/arch/m68k/include/asm/global_data.h
> @@ -57,6 +57,9 @@ typedef       struct  global_data {
>        unsigned long   env_addr;       /* Address  of Environment struct       */
>        unsigned long   env_valid;      /* Checksum of Environment valid?       */
>        unsigned long   have_console;   /* serial_init() was called             */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>  #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
>        unsigned long   fb_base;        /* Base addr of framebuffer memory */
>  #endif
> diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h
> index 557ad27..6e8537c 100644
> --- a/arch/microblaze/include/asm/global_data.h
> +++ b/arch/microblaze/include/asm/global_data.h
> @@ -39,6 +39,9 @@ typedef       struct  global_data {
>        unsigned long   flags;
>        unsigned long   baudrate;
>        unsigned long   have_console;   /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        unsigned long   env_addr;       /* Address  of Environment struct */
>        unsigned long   env_valid;      /* Checksum of Environment valid? */
>        unsigned long   fb_base;        /* base address of frame buffer */
> diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
> index 271a290..b193517 100644
> --- a/arch/mips/include/asm/global_data.h
> +++ b/arch/mips/include/asm/global_data.h
> @@ -41,6 +41,9 @@ typedef       struct  global_data {
>        unsigned long   flags;
>        unsigned long   baudrate;
>        unsigned long   have_console;   /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        phys_size_t     ram_size;       /* RAM size */
>        unsigned long   reloc_off;      /* Relocation Offset */
>        unsigned long   env_addr;       /* Address  of Environment struct */
> diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h
> index 2c4a719..d9f0664 100644
> --- a/arch/nios2/include/asm/global_data.h
> +++ b/arch/nios2/include/asm/global_data.h
> @@ -29,6 +29,9 @@ typedef       struct  global_data {
>        unsigned long   baudrate;
>        unsigned long   cpu_clk;        /* CPU clock in Hz!             */
>        unsigned long   have_console;   /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        phys_size_t     ram_size;       /* RAM size */
>        unsigned long   env_addr;       /* Address  of Environment struct */
>        unsigned long   env_valid;      /* Checksum of Environment valid */
> diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
> index a33ca2f..7fcaf38 100644
> --- a/arch/powerpc/include/asm/global_data.h
> +++ b/arch/powerpc/include/asm/global_data.h
> @@ -138,6 +138,9 @@ typedef     struct  global_data {
>        unsigned long   env_addr;       /* Address  of Environment struct       */
>        unsigned long   env_valid;      /* Checksum of Environment valid?       */
>        unsigned long   have_console;   /* serial_init() was called             */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>  #if defined(CONFIG_SYS_ALLOC_DPRAM) || defined(CONFIG_CPM2)
>        unsigned int    dp_alloc_base;
>        unsigned int    dp_alloc_top;
> diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h
> index 0c09ba9..1b782fc 100644
> --- a/arch/sh/include/asm/global_data.h
> +++ b/arch/sh/include/asm/global_data.h
> @@ -34,6 +34,9 @@ typedef       struct global_data
>        unsigned long   baudrate;
>        unsigned long   cpu_clk;        /* CPU clock in Hz! */
>        unsigned long   have_console;   /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        phys_size_t     ram_size;       /* RAM size */
>        unsigned long   env_addr;       /* Address  of Environment struct */
>        unsigned long   env_valid;      /* Checksum of Environment valid */
> diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h
> index 9b14674..a1e4b44 100644
> --- a/arch/sparc/include/asm/global_data.h
> +++ b/arch/sparc/include/asm/global_data.h
> @@ -53,6 +53,9 @@ typedef struct global_data {
>        unsigned long env_valid;        /* Checksum of Environment valid?       */
>        unsigned long have_console;     /* serial_init() was called */
>
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>  #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
>        unsigned long fb_base;  /* Base address of framebuffer memory   */
>  #endif
> diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
> index f977dbe..6cf7955 100644
> --- a/arch/x86/include/asm/global_data.h
> +++ b/arch/x86/include/asm/global_data.h
> @@ -40,6 +40,9 @@ typedef       struct global_data {
>        unsigned long   flags;
>        unsigned long   baudrate;
>        unsigned long   have_console;   /* serial_init() was called */
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +       unsigned long   precon_buf_idx; /* Pre-Console buffer index */
> +#endif
>        unsigned long   reloc_off;      /* Relocation Offset */
>        unsigned long   load_off;       /* Load Offset */
>        unsigned long   env_addr;       /* Address  of Environment struct */
> diff --git a/common/console.c b/common/console.c
> index b23d933..570196e 100644
> --- a/common/console.c
> +++ b/common/console.c
> @@ -329,6 +329,39 @@ int tstc(void)
>        return serial_tstc();
>  }
>
> +#ifdef CONFIG_PRE_CONSOLE_BUFFER
> +#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_PRE_CON_BUF_SZ)
> +
> +void pre_console_putc(const char c)
> +{
> +       char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR;
> +
> +       buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;
> +}
> +
> +void pre_console_puts(const char *s)
> +{
> +       while (*s)
> +               pre_console_putc(*s++);
> +}
> +
> +void print_pre_console_buffer(void)
> +{
> +       unsigned long i = 0;
> +       char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR;
> +
> +       if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ)
> +               i = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ;
> +
> +       while (i < gd->precon_buf_idx)
> +               putc(buffer[CIRC_BUF_IDX(i++)]);
> +}
> +#else
> +static inline void pre_console_putc(const char c) {}
> +static inline void pre_console_puts(const char *s) {}
> +static inline void print_pre_console_buffer(void) {}
> +#endif
> +
>  void putc(const char c)
>  {
>  #ifdef CONFIG_SILENT_CONSOLE
> @@ -342,7 +375,7 @@ void putc(const char c)
>  #endif
>
>        if (!gd->have_console)
> -               return;
> +               return pre_console_putc(c);
>
>        if (gd->flags & GD_FLG_DEVINIT) {
>                /* Send to the standard output */
> @@ -366,7 +399,7 @@ void puts(const char *s)
>  #endif
>
>        if (!gd->have_console)
> -               return;
> +               return pre_console_puts(s);
>
>        if (gd->flags & GD_FLG_DEVINIT) {
>                /* Send to the standard output */
> @@ -383,8 +416,10 @@ int printf(const char *fmt, ...)
>        uint i;
>        char printbuffer[CONFIG_SYS_PBSIZE];
>
> +#ifndef CONFIG_PRE_CONSOLE_BUFFER
>        if (!gd->have_console)
>                return 0;
> +#endif
>
>        va_start(args, fmt);
>
> @@ -404,8 +439,10 @@ int vprintf(const char *fmt, va_list args)
>        uint i;
>        char printbuffer[CONFIG_SYS_PBSIZE];
>
> +#ifndef CONFIG_PRE_CONSOLE_BUFFER
>        if (!gd->have_console)
>                return 0;
> +#endif
>
>        /* For this to work, printbuffer must be larger than
>         * anything we ever want to print.
> @@ -547,6 +584,8 @@ int console_init_f(void)
>                gd->flags |= GD_FLG_SILENT;
>  #endif
>
> +       print_pre_console_buffer();
> +
>        return 0;
>  }
>
> --
> 1.7.5.2.317.g391b14
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
>
Graeme Russ Sept. 27, 2011, 11:22 a.m. UTC | #13
Hi Vadim,

On 27/09/11 08:50, Vadim Bendebury wrote:
> On Wed, Aug 31, 2011 at 5:58 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
>> Allow redirection of console output prior to console initialisation to a
>> temporary buffer.
>>
>> To enable this functionality, the board configuration file must define:
>>  - CONFIG_PRE_CONSOLE_BUFFER - Enable pre-console buffer
>>  - CONFIG_PRE_CON_BUF_ADDR - Base address of pre-console buffer
>>  - CONFIG_PRE_CON_BUF_SZ - Size of pre-console buffer (in bytes)
>>
>> The pre-console buffer will buffer the last CONFIG_PRE_CON_BUF_SZ bytes
>> Any earlier characters are silently dropped.
>>
>> Signed-off-by: Graeme Russ <graeme.russ@gmail.com>

[snip]

> 
> I know I am late to the party here, but all of a sudden I need to
> implement something similar, albeit slightly different:

better late than never :)

> - the memory could be allocated by the "cold bootprom" which starts u-boot;

Typically, the pre-console buffer would exist in the CPU cache (or similar
non-(S)DRAM location)

> - all console output needs to be saved, not just until the moment when
> the console hardware is initialized.

That could be a _huge_ amount of info and highly variable. Remember, the
available space for a pre-console buffer could be tiny. If this is needed,
then maybe look at forking stdio instead (one branch to console, one branch
to you console buffer)

> I could work on top of this patch and send another one once this one
> has been accepted. May I suggest an improvement though:
> 
> is it really necessary to store the index in the global data
> structure. This requires editing all these .h files adding another
> unsighty  conditionally compiled field. Why not to store the index as
> the first word in the buffer allocated for this temp storage?

I like this - but instead:

struct pre_con_buff {
	int idx;
	char *buffer[CONFIG_PRE_CON_BUF_SZ];
}

struct pre_con_buff *pre_con_buffer;

pre_con_buffer = (struct pre_con_buff *)CONFIG_PRE_CON_BUF_ADDR;

Regards,

Graeme
Vadim Bendebury Sept. 27, 2011, 2:55 p.m. UTC | #14
On Tue, Sep 27, 2011 at 4:22 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
> Hi Vadim,
>
> On 27/09/11 08:50, Vadim Bendebury wrote:
>> On Wed, Aug 31, 2011 at 5:58 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
>>> Allow redirection of console output prior to console initialisation to a
>>> temporary buffer.
>>>
>>> To enable this functionality, the board configuration file must define:
>>>  - CONFIG_PRE_CONSOLE_BUFFER - Enable pre-console buffer
>>>  - CONFIG_PRE_CON_BUF_ADDR - Base address of pre-console buffer
>>>  - CONFIG_PRE_CON_BUF_SZ - Size of pre-console buffer (in bytes)
>>>
>>> The pre-console buffer will buffer the last CONFIG_PRE_CON_BUF_SZ bytes
>>> Any earlier characters are silently dropped.
>>>
>>> Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
>
> [snip]
>
>>
>> I know I am late to the party here, but all of a sudden I need to
>> implement something similar, albeit slightly different:
>
> better late than never :)
>
>> - the memory could be allocated by the "cold bootprom" which starts u-boot;
>
> Typically, the pre-console buffer would exist in the CPU cache (or similar
> non-(S)DRAM location)
>
hi Graeme,

Actually, there are many cases when u-boot starts running with memory
fully initialized - ARM platforms is one case and coreboot/u-boot
combination on x86 is another, but in general, yes, this buffer could
be mapped to the internal CPU memory nailed to a fixed address.

>> - all console output needs to be saved, not just until the moment when
>> the console hardware is initialized.
>
> That could be a _huge_ amount of info and highly variable. Remember, the
> available space for a pre-console buffer could be tiny. If this is needed,
> then maybe look at forking stdio instead (one branch to console, one branch
> to you console buffer)
>

Sure, if the room in the preallocated buffer is not enough, only the
most recent data fitting in the space would be kept.

I don't quite understand what you mean by "forking stdio". I was
thinking about introducing a separate driver for this memory stored
console output, but sjg@ explained that while running from ROM u-boot
supports only one console interface, so there is no way to have
console stream sent to more than one driver before relocation.

>> I could work on top of this patch and send another one once this one
>> has been accepted. May I suggest an improvement though:
>>
>> is it really necessary to store the index in the global data
>> structure. This requires editing all these .h files adding another
>> unsighty  conditionally compiled field. Why not to store the index as
>> the first word in the buffer allocated for this temp storage?
>
> I like this - but instead:
>
> struct pre_con_buff {
>        int idx;
>        char *buffer[CONFIG_PRE_CON_BUF_SZ];
> }
>
> struct pre_con_buff *pre_con_buffer;
>
> pre_con_buffer = (struct pre_con_buff *)CONFIG_PRE_CON_BUF_ADDR;
>

yes, this is exactly what I meant,

cheers,
/vb

> Regards,
>
> Graeme
>
Graeme Russ Sept. 29, 2011, 11:15 p.m. UTC | #15
Hi Vadim,

On Wed, Sep 28, 2011 at 12:55 AM, Vadim Bendebury <vbendeb@chromium.org> wrote:
> On Tue, Sep 27, 2011 at 4:22 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
>> Hi Vadim,
>>
>> On 27/09/11 08:50, Vadim Bendebury wrote:
>>> On Wed, Aug 31, 2011 at 5:58 AM, Graeme Russ <graeme.russ@gmail.com> wrote:

[snip]

>> Typically, the pre-console buffer would exist in the CPU cache (or similar
>> non-(S)DRAM location)
>>
> hi Graeme,
>
> Actually, there are many cases when u-boot starts running with memory
> fully initialized - ARM platforms is one case and coreboot/u-boot
> combination on x86 is another, but in general, yes, this buffer could
> be mapped to the internal CPU memory nailed to a fixed address.

And we have to satisfy the 'absolute majority', not the 'many' or the
'simply majority'. And I'm not sure it's always true that ARM platforms
have fully initialised SDRAM when U-Boot starts

>>> - all console output needs to be saved, not just until the moment when
>>> the console hardware is initialized.
>>
>> That could be a _huge_ amount of info and highly variable. Remember, the
>> available space for a pre-console buffer could be tiny. If this is needed,
>> then maybe look at forking stdio instead (one branch to console, one branch
>> to you console buffer)
>>
>
> Sure, if the room in the preallocated buffer is not enough, only the
> most recent data fitting in the space would be kept.
>
> I don't quite understand what you mean by "forking stdio". I was

Search for CONFIG_CONSOLE_MUX - There appears to be support for sending
stdout to multiple output devices:

static void console_putc(int file, const char c)
{
	int i;
	struct stdio_dev *dev;

	for (i = 0; i < cd_count[file]; i++) {
		dev = console_devices[file][i];
		if (dev->putc != NULL)
		dev->putc(c);
	}
}


I don't know have to register additional devices though

> thinking about introducing a separate driver for this memory stored
> console output, but sjg@ explained that while running from ROM u-boot
> supports only one console interface, so there is no way to have
> console stream sent to more than one driver before relocation.

Yes, while running from ROM your options are very limited, but if you have
a console buffer big enough to get you into RAM you can do lot more

>>> I could work on top of this patch and send another one once this one
>>> has been accepted. May I suggest an improvement though:
>>>
>>> is it really necessary to store the index in the global data
>>> structure. This requires editing all these .h files adding another
>>> unsighty  conditionally compiled field. Why not to store the index as
>>> the first word in the buffer allocated for this temp storage?
>>
>> I like this - but instead:
>>
>> struct pre_con_buff {
>>        int idx;
>>        char *buffer[CONFIG_PRE_CON_BUF_SZ];
>> }
>>
>> struct pre_con_buff *pre_con_buffer;
>>
>> pre_con_buffer = (struct pre_con_buff *)CONFIG_PRE_CON_BUF_ADDR;
>>
>
> yes, this is exactly what I meant,
>

Thinking more about this, I think I prefer the current patch for two
reasons:

 1) gd is guaranteed to be cleared - The memory holding the buffer is not
    so you would need to initialise it somehow - That could mean splitting
    the init for each arch
 2) pre_con_buffer is larger than CONFIG_PRE_CON_BUF_SZ. This will need to
    be taken into consideration if the buffer is being crammed into a very
    tightly crafted memory map - Forgetting to take this into account is
    going to cause lots of pain. Now you could do:

	struct pre_con_buff {
		u16 idx;
		char *buffer[CONFIG_PRE_CON_BUF_SZ - 2];
	}

    but the buffer size should really be a power two (so the compiler
    optimises the divides into shifts) - So now we have to define
    CONFIG_PRE_CON_BUF_SZ as say 258. It's starting to get messy


Regards,

Graeme
Vadim Bendebury Sept. 29, 2011, 11:39 p.m. UTC | #16
On Thu, Sep 29, 2011 at 4:15 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
> Hi Vadim,
>
> On Wed, Sep 28, 2011 at 12:55 AM, Vadim Bendebury <vbendeb@chromium.org> wrote:
>> On Tue, Sep 27, 2011 at 4:22 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
>>> Hi Vadim,
>>>
>>> On 27/09/11 08:50, Vadim Bendebury wrote:
>>>> On Wed, Aug 31, 2011 at 5:58 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
>
> [snip]
>
>>> Typically, the pre-console buffer would exist in the CPU cache (or similar
>>> non-(S)DRAM location)
>>>
>> hi Graeme,
>>
>> Actually, there are many cases when u-boot starts running with memory
>> fully initialized - ARM platforms is one case and coreboot/u-boot
>> combination on x86 is another, but in general, yes, this buffer could
>> be mapped to the internal CPU memory nailed to a fixed address.
>
> And we have to satisfy the 'absolute majority', not the 'many' or the
> 'simply majority'. And I'm not sure it's always true that ARM platforms
> have fully initialised SDRAM when U-Boot starts
>
>>>> - all console output needs to be saved, not just until the moment when
>>>> the console hardware is initialized.
>>>
>>> That could be a _huge_ amount of info and highly variable. Remember, the
>>> available space for a pre-console buffer could be tiny. If this is needed,
>>> then maybe look at forking stdio instead (one branch to console, one branch
>>> to you console buffer)
>>>
>>
>> Sure, if the room in the preallocated buffer is not enough, only the
>> most recent data fitting in the space would be kept.
>>
>> I don't quite understand what you mean by "forking stdio". I was
>
> Search for CONFIG_CONSOLE_MUX - There appears to be support for sending
> stdout to multiple output devices:
>
> static void console_putc(int file, const char c)
> {
>        int i;
>        struct stdio_dev *dev;
>
>        for (i = 0; i < cd_count[file]; i++) {
>                dev = console_devices[file][i];
>                if (dev->putc != NULL)
>                dev->putc(c);
>        }
> }
>
>
> I don't know have to register additional devices though
>

hi Graeme,

sure, I understand how the console mux works, i was not sure you were
referring to it.


>> thinking about introducing a separate driver for this memory stored
>> console output, but sjg@ explained that while running from ROM u-boot
>> supports only one console interface, so there is no way to have
>> console stream sent to more than one driver before relocation.
>
> Yes, while running from ROM your options are very limited, but if you have
> a console buffer big enough to get you into RAM you can do lot more
>
>>>> I could work on top of this patch and send another one once this one
>>>> has been accepted. May I suggest an improvement though:
>>>>
>>>> is it really necessary to store the index in the global data
>>>> structure. This requires editing all these .h files adding another
>>>> unsighty  conditionally compiled field. Why not to store the index as
>>>> the first word in the buffer allocated for this temp storage?
>>>
>>> I like this - but instead:
>>>
>>> struct pre_con_buff {
>>>        int idx;
>>>        char *buffer[CONFIG_PRE_CON_BUF_SZ];
>>> }
>>>
>>> struct pre_con_buff *pre_con_buffer;
>>>
>>> pre_con_buffer = (struct pre_con_buff *)CONFIG_PRE_CON_BUF_ADDR;
>>>
>>
>> yes, this is exactly what I meant,
>>
>
> Thinking more about this, I think I prefer the current patch for two
> reasons:
>
>  1) gd is guaranteed to be cleared - The memory holding the buffer is not
>    so you would need to initialise it somehow - That could mean splitting
>    the init for each arch

doesn't each console type have an init routine? this would be a place
to initialize the header.

>  2) pre_con_buffer is larger than CONFIG_PRE_CON_BUF_SZ. This will need to
>    be taken into consideration if the buffer is being crammed into a very
>    tightly crafted memory map - Forgetting to take this into account is
>    going to cause lots of pain. Now you could do:
>
>        struct pre_con_buff {
>                u16 idx;
>                char *buffer[CONFIG_PRE_CON_BUF_SZ - 2];
>        }
>

I actually have just implemented this for coreboot.  It has its own
idiosyncrasies of course, the console buffer needs to be kept in three
different places and the contents copied three times on the way up.

I used this structure for the log buffer:

struct pre_con_buff {
         u16 size;
         u16 idx;
         char buffer[0]
};

Then, the initialization code  would just get the memory area address
and size, overlay this structure on top of it and set the size field
to

<area size> - sizeof(struct pre_con_buff)

yes, this results in a non power of two buffer size, but IMO the
convenience of keeping everything in one place and  (and not changing
multiple .h files) is worth the lost performance of not being able to
utilize power of two arithmetic optimization (which I think is
negligible in any case).

cheers,
/vb


>    but the buffer size should really be a power two (so the compiler
>    optimises the divides into shifts) - So now we have to define
>    CONFIG_PRE_CON_BUF_SZ as say 258. It's starting to get messy
>
>
> Regards,
>
> Graeme
>
Graeme Russ Sept. 29, 2011, 11:47 p.m. UTC | #17
Hi Vladim

On Fri, Sep 30, 2011 at 9:39 AM, Vadim Bendebury <vbendeb@chromium.org> wrote:
> On Thu, Sep 29, 2011 at 4:15 PM, Graeme Russ <graeme.russ@gmail.com> wrote:
>> Hi Vadim,
>>
>> On Wed, Sep 28, 2011 at 12:55 AM, Vadim Bendebury <vbendeb@chromium.org> wrote:
>>> On Tue, Sep 27, 2011 at 4:22 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
>>>> Hi Vadim,
>>>>
>>>> On 27/09/11 08:50, Vadim Bendebury wrote:
>>>>> On Wed, Aug 31, 2011 at 5:58 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
>>

[snip]

>>
>>  1) gd is guaranteed to be cleared - The memory holding the buffer is not
>>    so you would need to initialise it somehow - That could mean splitting
>>    the init for each arch
>
> doesn't each console type have an init routine? this would be a place
> to initialize the header.

The point is that with pre-console buffer, we have a storage location for
console output even before any console init routine is run - console is
available as soon as gd is cleared (which is _very_ early indeed)

>>  2) pre_con_buffer is larger than CONFIG_PRE_CON_BUF_SZ. This will need to
>>    be taken into consideration if the buffer is being crammed into a very
>>    tightly crafted memory map - Forgetting to take this into account is
>>    going to cause lots of pain. Now you could do:
>>
>>        struct pre_con_buff {
>>                u16 idx;
>>                char *buffer[CONFIG_PRE_CON_BUF_SZ - 2];
>>        }
>>
>
> I actually have just implemented this for coreboot.  It has its own
> idiosyncrasies of course, the console buffer needs to be kept in three
> different places and the contents copied three times on the way up.

Ouch!

> I used this structure for the log buffer:
>
> struct pre_con_buff {
>          u16 size;
>         u16 idx;
>         char buffer[0]
> };
>
> Then, the initialization code  would just get the memory area address
> and size, overlay this structure on top of it and set the size field
> to
>
> <area size> - sizeof(struct pre_con_buff)

For U-Boot, that sounds like a lot of stuffing around to save two bytes
in gd

> yes, this results in a non power of two buffer size, but IMO the
> convenience of keeping everything in one place and  (and not changing
> multiple .h files) is worth the lost performance of not being able to
> utilize power of two arithmetic optimization (which I think is
> negligible in any case).

In an embedded bootloader, every clock counts :) - You desktop junkies are
too used to long boot times ;)

>>    but the buffer size should really be a power two (so the compiler
>>    optimises the divides into shifts) - So now we have to define
>>    CONFIG_PRE_CON_BUF_SZ as say 258. It's starting to get messy

And messier (at least in the context of U-Boot - YMMV)

Regards,

Graeme
diff mbox

Patch

diff --git a/README b/README
index 0886987..170e67b 100644
--- a/README
+++ b/README
@@ -619,6 +619,20 @@  The following options need to be configured:
 		must be defined, to setup the maximum idle timeout for
 		the SMC.

+- Pre-Console Buffer:
+                Prior to the console being initialised (i.e. serial UART
+                initialised etc) all console output is silently discarded.
+                Defining CONFIG_PRE_CONSOLE_BUFFER will cause U-Boot to
+                buffer any console messages prior to the console being
+                initialised to a buffer of size CONFIG_PRE_CON_BUF_SZ
+                bytes located at CONFIG_PRE_CON_BUF_ADDR. The buffer is
+                a cicular buffer, so if more than CONFIG_PRE_CON_BUF_SZ
+                bytes are output before the console is  initialised, the
+                earlier bytes are discarded.
+
+                'Sane' compilers will generate smaller code if
+                CONFIG_PRE_CON_BUF_SZ is a power of 2
+
 - Boot Delay:	CONFIG_BOOTDELAY - in seconds
 		Delay before automatically booting the default image;
 		set to -1 to disable autoboot.
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 4fc51fd..b85b7fe 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -38,6 +38,9 @@  typedef	struct	global_data {
 	unsigned long	flags;
 	unsigned long	baudrate;
 	unsigned long	have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	unsigned long	env_addr;	/* Address  of Environment struct */
 	unsigned long	env_valid;	/* Checksum of Environment valid? */
 	unsigned long	fb_base;	/* base address of frame buffer */
diff --git a/arch/avr32/include/asm/global_data.h b/arch/avr32/include/asm/global_data.h
index 4ef8fc5..5c654bd 100644
--- a/arch/avr32/include/asm/global_data.h
+++ b/arch/avr32/include/asm/global_data.h
@@ -38,6 +38,9 @@  typedef	struct	global_data {
 	unsigned long	baudrate;
 	unsigned long	stack_end;	/* highest stack address */
 	unsigned long	have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	unsigned long	reloc_off;	/* Relocation Offset */
 	unsigned long	env_addr;	/* Address of env struct */
 	unsigned long	env_valid;	/* Checksum of env valid? */
diff --git a/arch/blackfin/include/asm/global_data.h b/arch/blackfin/include/asm/global_data.h
index eba5e93..f7aa711 100644
--- a/arch/blackfin/include/asm/global_data.h
+++ b/arch/blackfin/include/asm/global_data.h
@@ -45,6 +45,9 @@  typedef struct global_data {
 	unsigned long board_type;
 	unsigned long baudrate;
 	unsigned long have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	phys_size_t ram_size;		/* RAM size */
 	unsigned long env_addr;	/* Address  of Environment struct */
 	unsigned long env_valid;	/* Checksum of Environment valid? */
diff --git a/arch/m68k/include/asm/global_data.h b/arch/m68k/include/asm/global_data.h
index fc486fd..0ba2b43 100644
--- a/arch/m68k/include/asm/global_data.h
+++ b/arch/m68k/include/asm/global_data.h
@@ -57,6 +57,9 @@  typedef	struct	global_data {
 	unsigned long	env_addr;	/* Address  of Environment struct	*/
 	unsigned long	env_valid;	/* Checksum of Environment valid?	*/
 	unsigned long	have_console;	/* serial_init() was called		*/
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
 	unsigned long	fb_base;	/* Base addr of framebuffer memory */
 #endif
diff --git a/arch/microblaze/include/asm/global_data.h b/arch/microblaze/include/asm/global_data.h
index 557ad27..6e8537c 100644
--- a/arch/microblaze/include/asm/global_data.h
+++ b/arch/microblaze/include/asm/global_data.h
@@ -39,6 +39,9 @@  typedef	struct	global_data {
 	unsigned long	flags;
 	unsigned long	baudrate;
 	unsigned long	have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	unsigned long	env_addr;	/* Address  of Environment struct */
 	unsigned long	env_valid;	/* Checksum of Environment valid? */
 	unsigned long	fb_base;	/* base address of frame buffer */
diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
index 271a290..b193517 100644
--- a/arch/mips/include/asm/global_data.h
+++ b/arch/mips/include/asm/global_data.h
@@ -41,6 +41,9 @@  typedef	struct	global_data {
 	unsigned long	flags;
 	unsigned long	baudrate;
 	unsigned long	have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	phys_size_t	ram_size;	/* RAM size */
 	unsigned long	reloc_off;	/* Relocation Offset */
 	unsigned long	env_addr;	/* Address  of Environment struct */
diff --git a/arch/nios2/include/asm/global_data.h b/arch/nios2/include/asm/global_data.h
index 2c4a719..d9f0664 100644
--- a/arch/nios2/include/asm/global_data.h
+++ b/arch/nios2/include/asm/global_data.h
@@ -29,6 +29,9 @@  typedef	struct	global_data {
 	unsigned long	baudrate;
 	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
 	unsigned long	have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	phys_size_t	ram_size;	/* RAM size */
 	unsigned long	env_addr;	/* Address  of Environment struct */
 	unsigned long	env_valid;	/* Checksum of Environment valid */
diff --git a/arch/powerpc/include/asm/global_data.h b/arch/powerpc/include/asm/global_data.h
index a33ca2f..7fcaf38 100644
--- a/arch/powerpc/include/asm/global_data.h
+++ b/arch/powerpc/include/asm/global_data.h
@@ -138,6 +138,9 @@  typedef	struct	global_data {
 	unsigned long	env_addr;	/* Address  of Environment struct	*/
 	unsigned long	env_valid;	/* Checksum of Environment valid?	*/
 	unsigned long	have_console;	/* serial_init() was called		*/
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 #if defined(CONFIG_SYS_ALLOC_DPRAM) || defined(CONFIG_CPM2)
 	unsigned int	dp_alloc_base;
 	unsigned int	dp_alloc_top;
diff --git a/arch/sh/include/asm/global_data.h b/arch/sh/include/asm/global_data.h
index 0c09ba9..1b782fc 100644
--- a/arch/sh/include/asm/global_data.h
+++ b/arch/sh/include/asm/global_data.h
@@ -34,6 +34,9 @@  typedef	struct global_data
 	unsigned long	baudrate;
 	unsigned long	cpu_clk;	/* CPU clock in Hz! */
 	unsigned long	have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	phys_size_t	ram_size;	/* RAM size */
 	unsigned long	env_addr;	/* Address  of Environment struct */
 	unsigned long	env_valid;	/* Checksum of Environment valid */
diff --git a/arch/sparc/include/asm/global_data.h b/arch/sparc/include/asm/global_data.h
index 9b14674..a1e4b44 100644
--- a/arch/sparc/include/asm/global_data.h
+++ b/arch/sparc/include/asm/global_data.h
@@ -53,6 +53,9 @@  typedef struct global_data {
 	unsigned long env_valid;	/* Checksum of Environment valid?       */
 	unsigned long have_console;	/* serial_init() was called */

+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 #if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
 	unsigned long fb_base;	/* Base address of framebuffer memory   */
 #endif
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h
index f977dbe..6cf7955 100644
--- a/arch/x86/include/asm/global_data.h
+++ b/arch/x86/include/asm/global_data.h
@@ -40,6 +40,9 @@  typedef	struct global_data {
 	unsigned long	flags;
 	unsigned long	baudrate;
 	unsigned long	have_console;	/* serial_init() was called */
+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+	unsigned long	precon_buf_idx;	/* Pre-Console buffer index */
+#endif
 	unsigned long	reloc_off;	/* Relocation Offset */
 	unsigned long	load_off;	/* Load Offset */
 	unsigned long	env_addr;	/* Address  of Environment struct */
diff --git a/common/console.c b/common/console.c
index b23d933..570196e 100644
--- a/common/console.c
+++ b/common/console.c
@@ -329,6 +329,39 @@  int tstc(void)
 	return serial_tstc();
 }

+#ifdef CONFIG_PRE_CONSOLE_BUFFER
+#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_PRE_CON_BUF_SZ)
+
+void pre_console_putc(const char c)
+{
+	char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR;
+
+	buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;
+}
+
+void pre_console_puts(const char *s)
+{
+	while (*s)
+		pre_console_putc(*s++);
+}
+
+void print_pre_console_buffer(void)
+{
+	unsigned long i = 0;
+	char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR;
+
+	if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ)
+		i = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ;
+
+	while (i < gd->precon_buf_idx)
+		putc(buffer[CIRC_BUF_IDX(i++)]);
+}
+#else
+static inline void pre_console_putc(const char c) {}
+static inline void pre_console_puts(const char *s) {}
+static inline void print_pre_console_buffer(void) {}
+#endif
+
 void putc(const char c)
 {
 #ifdef CONFIG_SILENT_CONSOLE
@@ -342,7 +375,7 @@  void putc(const char c)
 #endif

 	if (!gd->have_console)
-		return;
+		return pre_console_putc(c);

 	if (gd->flags & GD_FLG_DEVINIT) {
 		/* Send to the standard output */
@@ -366,7 +399,7 @@  void puts(const char *s)
 #endif

 	if (!gd->have_console)
-		return;
+		return pre_console_puts(s);

 	if (gd->flags & GD_FLG_DEVINIT) {
 		/* Send to the standard output */
@@ -383,8 +416,10 @@  int printf(const char *fmt, ...)
 	uint i;
 	char printbuffer[CONFIG_SYS_PBSIZE];

+#ifndef CONFIG_PRE_CONSOLE_BUFFER
 	if (!gd->have_console)
 		return 0;
+#endif

 	va_start(args, fmt);

@@ -404,8 +439,10 @@  int vprintf(const char *fmt, va_list args)
 	uint i;
 	char printbuffer[CONFIG_SYS_PBSIZE];

+#ifndef CONFIG_PRE_CONSOLE_BUFFER
 	if (!gd->have_console)
 		return 0;
+#endif

 	/* For this to work, printbuffer must be larger than
 	 * anything we ever want to print.
@@ -547,6 +584,8 @@  int console_init_f(void)
 		gd->flags |= GD_FLG_SILENT;
 #endif

+	print_pre_console_buffer();
+
 	return 0;
 }