diff --git a/README b/README index b8ed1f13db..398d70d67c 100644 --- a/README +++ b/README @@ -1530,6 +1530,17 @@ CBFS (Coreboot Filesystem) support allows for a "silent" boot where a splash screen is loaded very quickly after power-on. + CONFIG_SPLASHIMAGE_GUARD + + If this option is set, then U-Boot will prevent the environment + variable "splashimage" from being set to a problematic address + (see README.displaying-bmps and README.arm-unaligned-accesses). + This option is useful for targets where, due to alignment + restrictions, an improperly aligned BMP image will cause a data + abort. If you think you will not have problems with unaligned + accesses (for example because your toolchain prevents them) + there is no need to set this option. + CONFIG_SPLASH_SCREEN_ALIGN If this option is set the splash image can be freely positioned diff --git a/common/lcd.c b/common/lcd.c index ba6975be2f..590bbb9301 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include #if defined(CONFIG_POST) @@ -1099,6 +1101,30 @@ static void *lcd_logo(void) #endif /* CONFIG_LCD_LOGO && !CONFIG_LCD_INFO_BELOW_LOGO */ } +#ifdef CONFIG_SPLASHIMAGE_GUARD +static int on_splashimage(const char *name, const char *value, enum env_op op, + int flags) +{ + ulong addr; + int aligned; + + if (op == env_op_delete) + return 0; + + addr = simple_strtoul(value, NULL, 16); + /* See README.displaying-bmps */ + aligned = (addr % 4 == 2); + if (!aligned) { + printf("Invalid splashimage value. Value must be 16 bit aligned, but not 32 bit aligned\n"); + return -1; + } + + return 0; +} + +U_BOOT_ENV_CALLBACK(splashimage, on_splashimage); +#endif + void lcd_position_cursor(unsigned col, unsigned row) { console_col = min(col, CONSOLE_COLS - 1); diff --git a/doc/README.displaying-bmps b/doc/README.displaying-bmps new file mode 100644 index 0000000000..331154166d --- /dev/null +++ b/doc/README.displaying-bmps @@ -0,0 +1,27 @@ +If you are experiencing hangups/data-aborts when trying to display a BMP image, +the following might be relevant to your situation... + +Some architectures cannot handle unaligned memory accesses, and an attempt to +perform one will lead to a data abort. On such architectures it is necessary to +make sure all data is properly aligned, and in many situations simply choosing +a 32 bit aligned address is enough to ensure proper alignment. This is not +always the case when dealing with data that has an internal layout such as a +BMP image: + +BMP images have a header that starts with 2 byte-size fields followed by mostly +32 bit fields. The packed struct that represents this header can be seen below: + +typedef struct bmp_header { + /* Header */ + char signature[2]; + __u32 file_size; + __u32 reserved; + __u32 data_offset; + ... etc +} __attribute__ ((packed)) bmp_header_t; + +When placed in an aligned address such as 0x80a00000, char signature offsets +the __u32 fields into unaligned addresses (in our example 0x80a00002, +0x80a00006, and so on...). When these fields are accessed by U-Boot, a 32 bit +access is generated at a non-32-bit-aligned address, causing a data abort. +The proper alignment for BMP images is therefore: 32-bit-aligned-address + 2. diff --git a/include/env_callback.h b/include/env_callback.h index c583120c1c..62428d1e0c 100644 --- a/include/env_callback.h +++ b/include/env_callback.h @@ -41,6 +41,12 @@ #define SILENT_CALLBACK #endif +#ifdef CONFIG_SPLASHIMAGE_GUARD +#define SPLASHIMAGE_CALLBACK "splashimage:splashimage," +#else +#define SPLASHIMAGE_CALLBACK +#endif + /* * This list of callback bindings is static, but may be overridden by defining * a new association in the ".callbacks" environment variable. @@ -51,6 +57,7 @@ "bootfile:bootfile," \ "loadaddr:loadaddr," \ SILENT_CALLBACK \ + SPLASHIMAGE_CALLBACK \ "stdin:console,stdout:console,stderr:console," \ CONFIG_ENV_CALLBACK_LIST_STATIC