diff options
author | Scott Wood <scottwood@freescale.com> | 2012-12-14 16:03:55 -0600 |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2012-12-14 16:03:55 -0600 |
commit | 88c5c68ffa277bf01b3254cf5a059e2cbe07be97 (patch) | |
tree | f56b444a1c85d94d6a386df090def099632489fe | |
parent | 0b38fffbe413fc0725c750d046ca62c23fca196e (diff) | |
parent | 6e9005bd96ff0f0548a787ffafee10664a57a8e1 (diff) |
Merge remote-tracking branch 'origin/master'
99 files changed, 5070 insertions, 847 deletions
@@ -815,6 +815,8 @@ The following options need to be configured: CONFIG_CMD_EDITENV edit env variable CONFIG_CMD_EEPROM * EEPROM read/write support CONFIG_CMD_ELF * bootelf, bootvx + CONFIG_CMD_ENV_CALLBACK * display details about env callbacks + CONFIG_CMD_ENV_FLAGS * display details about env flags CONFIG_CMD_EXPORTENV * export the environment CONFIG_CMD_EXT2 * ext2 command support CONFIG_CMD_EXT4 * ext4 command support @@ -824,8 +826,10 @@ The following options need to be configured: CONFIG_CMD_FDOS * Dos diskette Support CONFIG_CMD_FLASH flinfo, erase, protect CONFIG_CMD_FPGA FPGA device initialization support + CONFIG_CMD_GETTIME * Get time since boot CONFIG_CMD_GO * the 'go' command (exec code) CONFIG_CMD_GREPENV * search environment + CONFIG_CMD_HASH * calculate hash / digest CONFIG_CMD_HWFLOW * RTS/CTS hw flow control CONFIG_CMD_I2C * I2C serial bus support CONFIG_CMD_IDE * IDE harddisk support @@ -860,6 +864,7 @@ The following options need to be configured: CONFIG_CMD_PING * send ICMP ECHO_REQUEST to network host CONFIG_CMD_PORTIO * Port I/O + CONFIG_CMD_READ * Read raw data from partition CONFIG_CMD_REGINFO * Register dump CONFIG_CMD_RUN run command in env variable CONFIG_CMD_SAVES * save S record dump @@ -1485,6 +1490,11 @@ CBFS (Coreboot Filesystem) support Support drawing of RLE8-compressed bitmaps on the LCD. + CONFIG_I2C_EDID + + Enables an 'i2c edid' command which can read EDID + information over I2C from an attached LCD display. + - Splash Screen Support: CONFIG_SPLASH_SCREEN @@ -2179,6 +2189,11 @@ CBFS (Coreboot Filesystem) support serial# is unaffected by this, i. e. it remains read-only.] + The same can be accomplished in a more flexible way + for any variable by configuring the type of access + to allow for those variables in the ".flags" variable + or define CONFIG_ENV_FLAGS_LIST_STATIC. + - Protected RAM: CONFIG_PRAM @@ -2409,6 +2424,23 @@ CBFS (Coreboot Filesystem) support A better solution is to properly configure the firewall, but sometimes that is not allowed. +- Hashing support: + CONFIG_CMD_HASH + + This enables a generic 'hash' command which can produce + hashes / digests from a few algorithms (e.g. SHA1, SHA256). + + CONFIG_HASH_VERIFY + + Enable the hash verify command (hash -v). This adds to code + size a little. + + CONFIG_SHA1 - support SHA1 hashing + CONFIG_SHA256 - support SHA256 hashing + + Note: There is also a sha1sum command, which should perhaps + be deprecated in favour of 'hash sha1'. + - Show boot progress: CONFIG_SHOW_BOOT_PROGRESS @@ -3087,6 +3119,49 @@ Configuration Settings: cases. This setting can be used to tune behaviour; see lib/hashtable.c for details. +- CONFIG_ENV_FLAGS_LIST_DEFAULT +- CONFIG_ENV_FLAGS_LIST_STATIC + Enable validation of the values given to enviroment variables when + calling env set. Variables can be restricted to only decimal, + hexadecimal, or boolean. If CONFIG_CMD_NET is also defined, + the variables can also be restricted to IP address or MAC address. + + The format of the list is: + type_attribute = [s|d|x|b|i|m] + access_atribute = [a|r|o|c] + attributes = type_attribute[access_atribute] + entry = variable_name[:attributes] + list = entry[,list] + + The type attributes are: + s - String (default) + d - Decimal + x - Hexadecimal + b - Boolean ([1yYtT|0nNfF]) + i - IP address + m - MAC address + + The access attributes are: + a - Any (default) + r - Read-only + o - Write-once + c - Change-default + + - CONFIG_ENV_FLAGS_LIST_DEFAULT + Define this to a list (string) to define the ".flags" + envirnoment variable in the default or embedded environment. + + - CONFIG_ENV_FLAGS_LIST_STATIC + Define this to a list (string) to define validation that + should be done if an entry is not found in the ".flags" + environment variable. To override a setting in the static + list, simply add an entry for the same variable name to the + ".flags" variable. + +- CONFIG_ENV_ACCESS_IGNORE_FORCE + If defined, don't allow the -f switch to env set override variable + access flags. + The following definitions that deal with the placement and management of environment data (variable area); in general, we support the following configurations: @@ -4188,6 +4263,36 @@ Please note that changes to some configuration parameters may take only effect after the next boot (yes, that's just like Windoze :-). +Callback functions for environment variables: +--------------------------------------------- + +For some environment variables, the behavior of u-boot needs to change +when their values are changed. This functionailty allows functions to +be associated with arbitrary variables. On creation, overwrite, or +deletion, the callback will provide the opportunity for some side +effect to happen or for the change to be rejected. + +The callbacks are named and associated with a function using the +U_BOOT_ENV_CALLBACK macro in your board or driver code. + +These callbacks are associated with variables in one of two ways. The +static list can be added to by defining CONFIG_ENV_CALLBACK_LIST_STATIC +in the board configuration to a string that defines a list of +associations. The list must be in the following format: + + entry = variable_name[:callback_name] + list = entry[,list] + +If the callback name is not specified, then the callback is deleted. +Spaces are also allowed anywhere in the list. + +Callbacks can also be associated by defining the ".callbacks" variable +with the same list format above. Any association in ".callbacks" will +override any association in the static list. You can define +CONFIG_ENV_CALLBACK_LIST_DEFAULT to a list (string) to define the +".callbacks" envirnoment variable in the default or embedded environment. + + Command Line Parsing: ===================== diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c index bfea6abeb0..4ff19c37ef 100644 --- a/arch/arm/cpu/arm926ejs/mxs/clock.c +++ b/arch/arm/cpu/arm926ejs/mxs/clock.c @@ -333,6 +333,8 @@ uint32_t mxc_get_clock(enum mxc_clock clk) return mx28_get_sspclk(MXC_SSPCLK2); case MXC_SSP3_CLK: return mx28_get_sspclk(MXC_SSPCLK3); + case MXC_XTAL_CLK: + return XTAL_FREQ_KHZ * 1000; } return 0; diff --git a/arch/arm/cpu/armv7/exynos/clock.c b/arch/arm/cpu/armv7/exynos/clock.c index 4f3b451be9..21e45d2e82 100644 --- a/arch/arm/cpu/armv7/exynos/clock.c +++ b/arch/arm/cpu/armv7/exynos/clock.c @@ -732,6 +732,21 @@ static unsigned long exynos5_get_i2c_clk(void) return aclk_66; } +static unsigned long exynos4_get_i2c_clk(void) +{ + struct exynos4_clock *clk = + (struct exynos4_clock *)samsung_get_base_clock(); + unsigned long sclk, aclk_100; + unsigned int ratio; + + sclk = get_pll_clk(APLL); + + ratio = (readl(&clk->div_top)) >> 4; + ratio &= 0xf; + aclk_100 = sclk / (ratio + 1); + return aclk_100; +} + unsigned long get_pll_clk(int pllreg) { if (cpu_is_exynos5()) @@ -752,6 +767,8 @@ unsigned long get_i2c_clk(void) { if (cpu_is_exynos5()) { return exynos5_get_i2c_clk(); + } else if (cpu_is_exynos4()) { + return exynos4_get_i2c_clk(); } else { debug("I2C clock is not set for this CPU\n"); return 0; diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c index 7776add9db..44ce0726e9 100644 --- a/arch/arm/cpu/armv7/exynos/pinmux.c +++ b/arch/arm/cpu/armv7/exynos/pinmux.c @@ -265,10 +265,74 @@ static int exynos5_pinmux_config(int peripheral, int flags) return 0; } +static void exynos4_i2c_config(int peripheral, int flags) +{ + struct exynos4_gpio_part1 *gpio1 = + (struct exynos4_gpio_part1 *) samsung_get_base_gpio_part1(); + + switch (peripheral) { + case PERIPH_ID_I2C0: + s5p_gpio_cfg_pin(&gpio1->d1, 0, GPIO_FUNC(0x2)); + s5p_gpio_cfg_pin(&gpio1->d1, 1, GPIO_FUNC(0x2)); + break; + case PERIPH_ID_I2C1: + s5p_gpio_cfg_pin(&gpio1->d1, 2, GPIO_FUNC(0x2)); + s5p_gpio_cfg_pin(&gpio1->d1, 3, GPIO_FUNC(0x2)); + break; + case PERIPH_ID_I2C2: + s5p_gpio_cfg_pin(&gpio1->a0, 6, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a0, 7, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C3: + s5p_gpio_cfg_pin(&gpio1->a1, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->a1, 3, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C4: + s5p_gpio_cfg_pin(&gpio1->b, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->b, 3, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C5: + s5p_gpio_cfg_pin(&gpio1->b, 6, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->b, 7, GPIO_FUNC(0x3)); + break; + case PERIPH_ID_I2C6: + s5p_gpio_cfg_pin(&gpio1->c1, 3, GPIO_FUNC(0x4)); + s5p_gpio_cfg_pin(&gpio1->c1, 4, GPIO_FUNC(0x4)); + break; + case PERIPH_ID_I2C7: + s5p_gpio_cfg_pin(&gpio1->d0, 2, GPIO_FUNC(0x3)); + s5p_gpio_cfg_pin(&gpio1->d0, 3, GPIO_FUNC(0x3)); + break; + } +} + +static int exynos4_pinmux_config(int peripheral, int flags) +{ + switch (peripheral) { + case PERIPH_ID_I2C0: + case PERIPH_ID_I2C1: + case PERIPH_ID_I2C2: + case PERIPH_ID_I2C3: + case PERIPH_ID_I2C4: + case PERIPH_ID_I2C5: + case PERIPH_ID_I2C6: + case PERIPH_ID_I2C7: + exynos4_i2c_config(peripheral, flags); + break; + default: + debug("%s: invalid peripheral %d", __func__, peripheral); + return -1; + } + + return 0; +} + int exynos_pinmux_config(int peripheral, int flags) { if (cpu_is_exynos5()) return exynos5_pinmux_config(peripheral, flags); + else if (cpu_is_exynos4()) + return exynos4_pinmux_config(peripheral, flags); else { debug("pinmux functionality not supported\n"); return -1; diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 2cd4ae1526..3073ca1a81 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -28,6 +28,8 @@ #define EXYNOS4_ADDR_BASE 0x10000000 /* EXYNOS4 */ +#define EXYNOS4_I2C_SPACING 0x10000 + #define EXYNOS4_GPIO_PART3_BASE 0x03860000 #define EXYNOS4_PRO_ID 0x10000000 #define EXYNOS4_SYSREG_BASE 0x10010000 diff --git a/arch/arm/include/asm/arch-mxs/clock.h b/arch/arm/include/asm/arch-mxs/clock.h index 1700fe3915..3d39ef235d 100644 --- a/arch/arm/include/asm/arch-mxs/clock.h +++ b/arch/arm/include/asm/arch-mxs/clock.h @@ -35,6 +35,7 @@ enum mxc_clock { MXC_SSP1_CLK, MXC_SSP2_CLK, MXC_SSP3_CLK, + MXC_XTAL_CLK, }; enum mxs_ioclock { diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c index 22a4d9cc0e..e0cb6353a3 100644 --- a/arch/arm/lib/board.c +++ b/arch/arm/lib/board.c @@ -540,15 +540,13 @@ void board_init_r(gd_t *id, ulong dest_addr) flash_size = flash_init(); if (flash_size > 0) { # ifdef CONFIG_SYS_FLASH_CHECKSUM - char *s = getenv("flashchecksum"); - print_size(flash_size, ""); /* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ - if (s && (*s == 'y')) { + if (getenv_yesno("flashchecksum") == 1) { printf(" CRC: %08X", crc32(0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)); diff --git a/arch/m68k/include/asm/string.h b/arch/m68k/include/asm/string.h index e0773a8828..ecf5e56e10 100644 --- a/arch/m68k/include/asm/string.h +++ b/arch/m68k/include/asm/string.h @@ -16,7 +16,7 @@ #endif extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t); extern char * strcpy(char *,const char *); extern char * strncpy(char *,const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index 02d73fda61..794b8679fe 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -462,8 +462,7 @@ void board_init_r (gd_t *id, ulong dest_addr) * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ - s = getenv ("flashchecksum"); - if (s && (*s == 'y')) { + if (getenv_yesno("flashchecksum") == 1) { printf (" CRC: %08X", crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, diff --git a/arch/microblaze/lib/board.c b/arch/microblaze/lib/board.c index efd63cd341..a7c2f76233 100644 --- a/arch/microblaze/lib/board.c +++ b/arch/microblaze/lib/board.c @@ -74,7 +74,6 @@ void board_init_f(ulong not_used) gd = (gd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET); bd = (bd_t *) (CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_GBL_DATA_OFFSET \ - GENERATED_BD_INFO_SIZE); - __maybe_unused char *s; #if defined(CONFIG_CMD_FLASH) ulong flash_size = 0; #endif @@ -143,8 +142,7 @@ void board_init_f(ulong not_used) * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ - s = getenv ("flashchecksum"); - if (s && (*s == 'y')) { + if (getenv_yesno("flashchecksum") == 1) { printf (" CRC: %08X", crc32(0, (const u8 *)bd->bi_flashstart, flash_size) diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c index 7ddd77832c..d79e1837d9 100644 --- a/arch/mips/lib/board.c +++ b/arch/mips/lib/board.c @@ -24,6 +24,7 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <serial.h> #include <stdio_dev.h> #include <version.h> #include <net.h> @@ -46,7 +47,7 @@ static char *failed = "*** failed ***\n"; * mips_io_port_base is the begin of the address space to which x86 style * I/O ports are mapped. */ -unsigned long mips_io_port_base = -1; +const unsigned long mips_io_port_base = -1; int __board_early_init_f(void) { @@ -262,6 +263,8 @@ void board_init_r(gd_t *id, ulong dest_addr) monitor_flash_len = (ulong)&uboot_end_data - dest_addr; + serial_initialize(); + #if defined(CONFIG_NEEDS_MANUAL_RELOC) /* * We have to relocate the command table manually diff --git a/arch/powerpc/cpu/mpc85xx/mp.c b/arch/powerpc/cpu/mpc85xx/mp.c index e1197ac9e5..43d4836303 100644 --- a/arch/powerpc/cpu/mpc85xx/mp.c +++ b/arch/powerpc/cpu/mpc85xx/mp.c @@ -46,10 +46,8 @@ u32 get_my_id() */ int hold_cores_in_reset(int verbose) { - const char *s = getenv("mp_holdoff"); - /* Default to no, overriden by 'y', 'yes', 'Y', 'Yes', or '1' */ - if (s && (*s == 'y' || *s == 'Y' || *s == '1')) { + if (getenv_yesno("mp_holdoff") == 1) { if (verbose) { puts("Secondary cores are being held in reset.\n"); puts("See 'mp_holdoff' environment variable\n"); diff --git a/arch/powerpc/include/asm/string.h b/arch/powerpc/include/asm/string.h index d912a6b5fe..036805ede2 100644 --- a/arch/powerpc/include/asm/string.h +++ b/arch/powerpc/include/asm/string.h @@ -14,7 +14,7 @@ #define __HAVE_ARCH_MEMCHR extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t); extern char * strcpy(char *,const char *); extern char * strncpy(char *,const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); diff --git a/arch/powerpc/lib/board.c b/arch/powerpc/lib/board.c index 1b051e11c4..6a7bf4b6c2 100644 --- a/arch/powerpc/lib/board.c +++ b/arch/powerpc/lib/board.c @@ -739,16 +739,13 @@ void board_init_r(gd_t *id, ulong dest_addr) flash_size = 0; } else if ((flash_size = flash_init()) > 0) { #ifdef CONFIG_SYS_FLASH_CHECKSUM - char *s; - print_size(flash_size, ""); /* * Compute and print flash CRC if flashchecksum is set to 'y' * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ - s = getenv("flashchecksum"); - if (s && (*s == 'y')) { + if (getenv_yesno("flashchecksum") == 1) { printf(" CRC: %08X", crc32(0, (const unsigned char *) @@ -841,9 +838,7 @@ void board_init_r(gd_t *id, ulong dest_addr) * "i2cfast" into account */ { - char *s = getenv("i2cfast"); - - if (s && ((*s == 'y') || (*s == 'Y'))) { + if (getenv_yesno("i2cfast") == 1) { bd->bi_iic_fast[0] = 1; bd->bi_iic_fast[1] = 1; } diff --git a/arch/sparc/include/asm/string.h b/arch/sparc/include/asm/string.h index c6bbc203d5..af6faea234 100644 --- a/arch/sparc/include/asm/string.h +++ b/arch/sparc/include/asm/string.h @@ -40,7 +40,7 @@ */ extern int strcasecmp(const char *, const char *); -extern int strncasecmp(const char *, const char *, int); +extern int strncasecmp(const char *, const char *, __kernel_size_t); extern char *strcpy(char *, const char *); extern char *strncpy(char *, const char *, __kernel_size_t); extern __kernel_size_t strlen(const char *); diff --git a/arch/sparc/lib/board.c b/arch/sparc/lib/board.c index 32d025a342..1b5e995b15 100644 --- a/arch/sparc/lib/board.c +++ b/arch/sparc/lib/board.c @@ -284,8 +284,7 @@ void board_init_f(ulong bootflag) * * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX */ - s = getenv("flashchecksum"); - if (s && (*s == 'y')) { + if (getenv_yesno("flashchecksum") == 1) { printf(" CRC: %08lX", crc32(0, (const unsigned char *)CONFIG_SYS_FLASH_BASE, flash_size) diff --git a/board/Marvell/db64360/db64360.c b/board/Marvell/db64360/db64360.c index 6cae68601d..38769e03c5 100644 --- a/board/Marvell/db64360/db64360.c +++ b/board/Marvell/db64360/db64360.c @@ -834,15 +834,11 @@ int mem_test_walk (void) /*********************************************************************/ int testdram (void) { - char *s; int rundata, runaddress, runwalk; - s = getenv ("testdramdata"); - rundata = (s && (*s == 'y')) ? 1 : 0; - s = getenv ("testdramaddress"); - runaddress = (s && (*s == 'y')) ? 1 : 0; - s = getenv ("testdramwalk"); - runwalk = (s && (*s == 'y')) ? 1 : 0; + rundata = getenv_yesno("testdramdata") == 1; + runaddress = getenv_yesno("testdramaddress") == 1; + runwalk = getenv_yesno("testdramwalk") == 1; /* rundata = 1; */ /* runaddress = 0; */ diff --git a/board/Marvell/db64460/db64460.c b/board/Marvell/db64460/db64460.c index d4f58b3216..ddb7ed5551 100644 --- a/board/Marvell/db64460/db64460.c +++ b/board/Marvell/db64460/db64460.c @@ -834,15 +834,11 @@ int mem_test_walk (void) /*********************************************************************/ int testdram (void) { - char *s; int rundata, runaddress, runwalk; - s = getenv ("testdramdata"); - rundata = (s && (*s == 'y')) ? 1 : 0; - s = getenv ("testdramaddress"); - runaddress = (s && (*s == 'y')) ? 1 : 0; - s = getenv ("testdramwalk"); - runwalk = (s && (*s == 'y')) ? 1 : 0; + rundata = getenv_yesno("testdramdata") == 1; + runaddress = getenv_yesno("testdramaddress") == 1; + runwalk = getenv_yesno("testdramwalk") == 1; /* rundata = 1; */ /* runaddress = 0; */ diff --git a/board/esd/cpci750/cpci750.c b/board/esd/cpci750/cpci750.c index 98051fb3fb..d7deae4a54 100644 --- a/board/esd/cpci750/cpci750.c +++ b/board/esd/cpci750/cpci750.c @@ -953,22 +953,18 @@ int mem_test_walk (void) /*********************************************************************/ int testdram (void) { - char *s; int rundata = 0; int runaddress = 0; int runwalk = 0; #ifdef CONFIG_SYS_DRAM_TEST_DATA - s = getenv ("testdramdata"); - rundata = (s && (*s == 'y')) ? 1 : 0; + rundata = getenv_yesno("testdramdata") == 1; #endif #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS - s = getenv ("testdramaddress"); - runaddress = (s && (*s == 'y')) ? 1 : 0; + runaddress = getenv_yesno("testdramaddress") == 1; #endif #ifdef CONFIG_SYS_DRAM_TEST_WALK - s = getenv ("testdramwalk"); - runwalk = (s && (*s == 'y')) ? 1 : 0; + runwalk = getenv_yesno("testdramwalk") == 1; #endif if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) { diff --git a/board/esd/pmc440/cmd_pmc440.c b/board/esd/pmc440/cmd_pmc440.c index f1ffb7b540..e9a78a303c 100644 --- a/board/esd/pmc440/cmd_pmc440.c +++ b/board/esd/pmc440/cmd_pmc440.c @@ -391,7 +391,7 @@ int do_painit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) nextbase -= ((CONFIG_ENV_SIZE + 4096 - 1) & ~(4096 - 1)); envp = (env_t *)nextbase; res = (char *)envp->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/board/gw8260/gw8260.c b/board/gw8260/gw8260.c index 77a1e1d3ac..64c54d5e84 100644 --- a/board/gw8260/gw8260.c +++ b/board/gw8260/gw8260.c @@ -544,15 +544,11 @@ int mem_test_walk (void) /*********************************************************************/ int testdram (void) { - char *s; int rundata, runaddress, runwalk; - s = getenv ("testdramdata"); - rundata = (s && (*s == 'y')) ? 1 : 0; - s = getenv ("testdramaddress"); - runaddress = (s && (*s == 'y')) ? 1 : 0; - s = getenv ("testdramwalk"); - runwalk = (s && (*s == 'y')) ? 1 : 0; + rundata = getenv_yesno("testdramdata") == 1; + runaddress = getenv_yesno("testdramaddress") == 1; + runwalk = getenv_yesno("testdramwalk") == 1; if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) { printf ("Testing RAM ... "); diff --git a/board/prodrive/p3mx/p3mx.c b/board/prodrive/p3mx/p3mx.c index 389affcde0..c3fd19169c 100644 --- a/board/prodrive/p3mx/p3mx.c +++ b/board/prodrive/p3mx/p3mx.c @@ -768,22 +768,18 @@ int mem_test_walk (void) /*********************************************************************/ int testdram (void) { - char *s; int rundata = 0; int runaddress = 0; int runwalk = 0; #ifdef CONFIG_SYS_DRAM_TEST_DATA - s = getenv ("testdramdata"); - rundata = (s && (*s == 'y')) ? 1 : 0; + rundata = getenv_yesno("testdramdata") == 1; #endif #ifdef CONFIG_SYS_DRAM_TEST_ADDRESS - s = getenv ("testdramaddress"); - runaddress = (s && (*s == 'y')) ? 1 : 0; + runaddress = getenv_yesno("testdramaddress") == 1; #endif #ifdef CONFIG_SYS_DRAM_TEST_WALK - s = getenv ("testdramwalk"); - runwalk = (s && (*s == 'y')) ? 1 : 0; + runwalk = getenv_yesno("testdramwalk") == 1; #endif if ((rundata == 1) || (runaddress == 1) || (runwalk == 1)) diff --git a/common/Makefile b/common/Makefile index c29a7d82e3..c77439556e 100644 --- a/common/Makefile +++ b/common/Makefile @@ -30,6 +30,7 @@ ifndef CONFIG_SPL_BUILD COBJS-y += main.o COBJS-y += command.o COBJS-y += exports.o +COBJS-y += hash.o COBJS-$(CONFIG_SYS_HUSH_PARSER) += hush.o COBJS-y += s_record.o COBJS-y += xyzModem.o @@ -43,7 +44,10 @@ COBJS-y += cmd_nvedit.o COBJS-y += cmd_version.o # environment +COBJS-y += env_attr.o +COBJS-y += env_callback.o COBJS-y += env_common.o +COBJS-y += env_flags.o COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o @@ -100,8 +104,10 @@ ifdef CONFIG_FPGA COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o endif COBJS-$(CONFIG_CMD_FS_GENERIC) += cmd_fs.o +COBJS-$(CONFIG_CMD_GETTIME) += cmd_gettime.o COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o +COBJS-$(CONFIG_CMD_HASH) += cmd_hash.o COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o COBJS-$(CONFIG_CMD_INI) += cmd_ini.o @@ -117,6 +123,7 @@ COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o +COBJS-$(CONFIG_CMD_IO) += cmd_io.o COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o COBJS-$(CONFIG_MII) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += miiphyutil.o @@ -141,6 +148,7 @@ endif COBJS-y += cmd_pcmcia.o COBJS-$(CONFIG_CMD_PORTIO) += cmd_portio.o COBJS-$(CONFIG_CMD_PXE) += cmd_pxe.o +COBJS-$(CONFIG_CMD_READ) += cmd_read.o COBJS-$(CONFIG_CMD_REGINFO) += cmd_reginfo.o COBJS-$(CONFIG_CMD_REISER) += cmd_reiser.o COBJS-$(CONFIG_CMD_SATA) += cmd_sata.o @@ -184,6 +192,7 @@ COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o COBJS-y += flash.o COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o +COBJS-$(CONFIG_I2C_EDID) += edid.o COBJS-$(CONFIG_KALLSYMS) += kallsyms.o COBJS-$(CONFIG_LCD) += lcd.o COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o @@ -192,6 +201,7 @@ COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o COBJS-$(CONFIG_UPDATE_TFTP) += update.o COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o +COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o endif ifdef CONFIG_SPL_BUILD @@ -200,7 +210,10 @@ COBJS-y += env_common.o COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o +COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o endif diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 4dbe952bb0..f7595c0311 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -537,7 +537,7 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, } break; #endif -#if defined(CONFIG_OF_LIBFDT) +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) case BOOTM_STATE_FDT: { boot_fdt_add_mem_rsv_regions(&images.lmb, diff --git a/common/cmd_gettime.c b/common/cmd_gettime.c new file mode 100644 index 0000000000..d7d36a9871 --- /dev/null +++ b/common/cmd_gettime.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * + * Copyright (c) 2009, Code Aurora Forum. All rights reserved. + * + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Get Timer overflows after 2^32 / CONFIG_SYS_HZ (32Khz) = 131072 sec + */ +#include <common.h> +#include <command.h> + +static int do_gettime(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + unsigned long int val = get_timer(0); + +#ifdef CONFIG_SYS_HZ + printf("Timer val: %lu\n", val); + printf("Seconds : %lu\n", val / CONFIG_SYS_HZ); + printf("Remainder : %lu\n", val % CONFIG_SYS_HZ); + printf("sys_hz = %lu\n", (unsigned long int)CONFIG_SYS_HZ); +#else + printf("CONFIG_SYS_HZ not defined"); + printf("Timer Val %lu", val); +#endif + + return 0; +} + +U_BOOT_CMD( + gettime, 1, 1, do_gettime, + "get timer val elapsed,\n", + "get time elapsed from uboot start\n" +); diff --git a/common/cmd_gpt.c b/common/cmd_gpt.c new file mode 100644 index 0000000000..da7705da69 --- /dev/null +++ b/common/cmd_gpt.c @@ -0,0 +1,333 @@ +/* + * cmd_gpt.c -- GPT (GUID Partition Table) handling command + * + * Copyright (C) 2012 Samsung Electronics + * author: Lukasz Majewski <l.majewski@samsung.com> + * author: Piotr Wilczek <p.wilczek@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <command.h> +#include <mmc.h> +#include <part_efi.h> +#include <exports.h> +#include <linux/ctype.h> + +#ifndef CONFIG_PARTITION_UUIDS +#error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled +#endif + +/** + * extract_env(): Expand env name from string format '&{env_name}' + * and return pointer to the env (if the env is set) + * + * @param str - pointer to string + * @param env - pointer to pointer to extracted env + * + * @return - zero on successful expand and env is set + */ +static char extract_env(const char *str, char **env) +{ + char *e, *s; + + if (!str || strlen(str) < 4) + return -1; + + if ((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')) { + s = strdup(str); + if (s == NULL) + return -1; + memset(s + strlen(s) - 1, '\0', 1); + memmove(s, s + 2, strlen(s) - 1); + e = getenv(s); + free(s); + if (e == NULL) { + printf("Environmental '%s' not set\n", str); + return -1; /* env not set */ + } + *env = e; + return 0; + } + + return -1; +} + +/** + * extract_val(): Extract value from a key=value pair list (comma separated). + * Only value for the given key is returend. + * Function allocates memory for the value, remember to free! + * + * @param str - pointer to string with key=values pairs + * @param key - pointer to the key to search for + * + * @return - pointer to allocated string with the value + */ +static char *extract_val(const char *str, const char *key) +{ + char *v, *k; + char *s, *strcopy; + char *new = NULL; + + strcopy = strdup(str); + if (strcopy == NULL) + return NULL; + + s = strcopy; + while (s) { + v = strsep(&s, ","); + if (!v) + break; + k = strsep(&v, "="); + if (!k) + break; + if (strcmp(k, key) == 0) { + new = strdup(v); + break; + } + } + + free(strcopy); + + return new; +} + +/** + * set_gpt_info(): Fill partition information from string + * function allocates memory, remember to free! + * + * @param dev_desc - pointer block device descriptor + * @param str_part - pointer to string with partition information + * @param str_disk_guid - pointer to pointer to allocated string with disk guid + * @param partitions - pointer to pointer to allocated partitions array + * @param parts_count - number of partitions + * + * @return - zero on success, otherwise error + * + */ +static int set_gpt_info(block_dev_desc_t *dev_desc, + const char *str_part, + char **str_disk_guid, + disk_partition_t **partitions, + u8 *parts_count) +{ + char *tok, *str, *s; + int i; + char *val, *p; + int p_count; + disk_partition_t *parts; + int errno = 0; + + debug("%s: MMC lba num: 0x%x %d\n", __func__, + (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); + + if (str_part == NULL) + return -1; + + str = strdup(str_part); + + /* extract disk guid */ + s = str; + tok = strsep(&s, ";"); + val = extract_val(tok, "uuid_disk"); + if (!val) { + free(str); + return -2; + } + if (extract_env(val, &p)) + p = val; + *str_disk_guid = strdup(p); + free(val); + + if (strlen(s) == 0) + return -3; + + i = strlen(s) - 1; + if (s[i] == ';') + s[i] = '\0'; + + /* calculate expected number of partitions */ + p_count = 1; + p = s; + while (*p) { + if (*p++ == ';') + p_count++; + } + + /* allocate memory for partitions */ + parts = calloc(sizeof(disk_partition_t), p_count); + + /* retrive partions data from string */ + for (i = 0; i < p_count; i++) { + tok = strsep(&s, ";"); + + if (tok == NULL) + break; + + /* uuid */ + val = extract_val(tok, "uuid"); + if (!val) { /* 'uuid' is mandatory */ + errno = -4; + goto err; + } + if (extract_env(val, &p)) + p = val; + if (strlen(p) >= sizeof(parts[i].uuid)) { + printf("Wrong uuid format for partition %d\n", i); + errno = -4; + goto err; + } + strcpy((char *)parts[i].uuid, p); + free(val); + + /* name */ + val = extract_val(tok, "name"); + if (!val) { /* name is mandatory */ + errno = -4; + goto err; + } + if (extract_env(val, &p)) + p = val; + if (strlen(p) >= sizeof(parts[i].name)) { + errno = -4; + goto err; + } + strcpy((char *)parts[i].name, p); + free(val); + + /* size */ + val = extract_val(tok, "size"); + if (!val) { /* 'size' is mandatory */ + errno = -4; + goto err; + } + if (extract_env(val, &p)) + p = val; + parts[i].size = ustrtoul(p, &p, 0); + parts[i].size /= dev_desc->blksz; + free(val); + + /* start address */ + val = extract_val(tok, "start"); + if (val) { /* start address is optional */ + if (extract_env(val, &p)) + p = val; + parts[i].start = ustrtoul(p, &p, 0); + parts[i].start /= dev_desc->blksz; + free(val); + } + } + + *parts_count = p_count; + *partitions = parts; + free(str); + + return 0; +err: + free(str); + free(*str_disk_guid); + free(parts); + + return errno; +} + +static int gpt_mmc_default(int dev, const char *str_part) +{ + int ret; + char *str_disk_guid; + u8 part_count = 0; + disk_partition_t *partitions = NULL; + + struct mmc *mmc = find_mmc_device(dev); + + if (mmc == NULL) { + printf("%s: mmc dev %d NOT available\n", __func__, dev); + return CMD_RET_FAILURE; + } + + if (!str_part) + return -1; + + /* fill partitions */ + ret = set_gpt_info(&mmc->block_dev, str_part, + &str_disk_guid, &partitions, &part_count); + if (ret) { + if (ret == -1) + printf("No partition list provided\n"); + if (ret == -2) + printf("Missing disk guid\n"); + if ((ret == -3) || (ret == -4)) + printf("Partition list incomplete\n"); + return -1; + } + + /* save partitions layout to disk */ + gpt_restore(&mmc->block_dev, str_disk_guid, partitions, part_count); + free(str_disk_guid); + free(partitions); + + return 0; +} + +/** + * do_gpt(): Perform GPT operations + * + * @param cmdtp - command name + * @param flag + * @param argc + * @param argv + * + * @return zero on success; otherwise error + */ +static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + int ret = CMD_RET_SUCCESS; + int dev = 0; + char *pstr; + + if (argc < 5) + return CMD_RET_USAGE; + + /* command: 'write' */ + if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { + /* device: 'mmc' */ + if (strcmp(argv[2], "mmc") == 0) { + /* check if 'dev' is a number */ + for (pstr = argv[3]; *pstr != '\0'; pstr++) + if (!isdigit(*pstr)) { + printf("'%s' is not a number\n", + argv[3]); + return CMD_RET_USAGE; + } + dev = (int)simple_strtoul(argv[3], NULL, 10); + /* write to mmc */ + if (gpt_mmc_default(dev, argv[4])) + return CMD_RET_FAILURE; + } + } else { + return CMD_RET_USAGE; + } + return ret; +} + +U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, + "GUID Partition Table", + "<command> <interface> <dev> <partions_list>\n" + " - GUID partition table restoration\n" + " Restore GPT information on a device connected\n" + " to interface\n" +); diff --git a/common/cmd_hash.c b/common/cmd_hash.c new file mode 100644 index 0000000000..689c608572 --- /dev/null +++ b/common/cmd_hash.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2011 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <hash.h> + +static int do_hash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +#ifdef CONFIG_HASH_VERIFY + int verify = 0; + + if (!strcmp(argv[1], "-v")) { + verify = 1; + argc--; + argv++; + } +#endif + /* Move forward to 'algorithm' parameter */ + argc--; + argv++; + return hash_command(*argv, verify, cmdtp, flag, argc - 1, argv + 1); +} + +#ifdef CONFIG_HASH_VERIFY +U_BOOT_CMD( + hash, 6, 1, do_hash, + "compute hash message digest", + "algorithm address count [[*]sum_dest]\n" + " - compute message digest [save to env var / *address]\n" + "hash -v algorithm address count [*]sum\n" + " - verify hash of memory area with env var / *address" +); +#else +U_BOOT_CMD( + hash, 5, 1, do_hash, + "compute message digest", + "algorithm address count [[*]sum_dest]\n" + " - compute message digest [save to env var / *address]" +); +#endif diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c index 4438db594c..4380794474 100644 --- a/common/cmd_i2c.c +++ b/common/cmd_i2c.c @@ -78,10 +78,12 @@ #include <common.h> #include <command.h> +#include <edid.h> #include <environment.h> #include <i2c.h> #include <malloc.h> #include <asm/byteorder.h> +#include <linux/compiler.h> /* Display values from last command. * Memory modify remembered values are different from display memory. @@ -132,35 +134,65 @@ DECLARE_GLOBAL_DATA_PTR; #define DISP_LINE_LEN 16 -/* implement possible board specific board init */ -static void __def_i2c_init_board(void) +/** + * i2c_init_board() - Board-specific I2C bus init + * + * This function is the default no-op implementation of I2C bus + * initialization. This function can be overriden by board-specific + * implementation if needed. + */ +__weak +void i2c_init_board(void) { return; } -void i2c_init_board(void) - __attribute__((weak, alias("__def_i2c_init_board"))); /* TODO: Implement architecture-specific get/set functions */ -static unsigned int __def_i2c_get_bus_speed(void) + +/** + * i2c_get_bus_speed() - Return I2C bus speed + * + * This function is the default implementation of function for retrieveing + * the current I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns I2C bus speed in Hz. + */ +__weak +unsigned int i2c_get_bus_speed(void) { return CONFIG_SYS_I2C_SPEED; } -unsigned int i2c_get_bus_speed(void) - __attribute__((weak, alias("__def_i2c_get_bus_speed"))); -static int __def_i2c_set_bus_speed(unsigned int speed) +/** + * i2c_set_bus_speed() - Configure I2C bus speed + * @speed: Newly set speed of the I2C bus in Hz + * + * This function is the default implementation of function for setting + * the I2C bus speed in Hz. + * + * A driver implementing runtime switching of I2C bus speed must override + * this function to report the speed correctly. Simple or legacy drivers + * can use this fallback. + * + * Returns zero on success, negative value on error. + */ +__weak +int i2c_set_bus_speed(unsigned int speed) { if (speed != CONFIG_SYS_I2C_SPEED) return -1; return 0; } -int i2c_set_bus_speed(unsigned int) - __attribute__((weak, alias("__def_i2c_set_bus_speed"))); -/* - * get_alen: small parser helper function to get address length - * returns the address length +/** + * get_alen() - Small parser helper function to get address length + * + * Returns the address length. */ static uint get_alen(char *arg) { @@ -178,11 +210,19 @@ static uint get_alen(char *arg) return alen; } -/* +/** + * do_i2c_read() - Handle the "i2c read" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: * i2c read {i2c_chip} {devaddr}{.0, .1, .2} {len} {memaddr} */ - static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { u_char chip; @@ -271,7 +311,16 @@ static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[ return 0; } -/* +/** + * do_i2c_md() - Handle the "i2c md" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: * i2c md {i2c_chip} {addr}{.0, .1, .2} {len} */ @@ -363,8 +412,15 @@ static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] return 0; } - -/* Write (fill) memory +/** + * do_i2c_mw() - Handle the "i2c mw" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. * * Syntax: * i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}] @@ -421,10 +477,20 @@ static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] #endif } - return (0); + return 0; } -/* Calculate a CRC on memory +/** + * do_i2c_crc() - Handle the "i2c crc32" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Calculate a CRC on memory + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. * * Syntax: * i2c crc32 {i2c_chip} {addr}{.0, .1, .2} {count} @@ -481,13 +547,22 @@ static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] return 0; } -/* Modify memory. +/** + * mod_i2c_mem() - Handle the "i2c mm" and "i2c nm" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Modify memory. + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. * * Syntax: * i2c mm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2} * i2c nm{.b, .w, .l} {i2c_chip} {addr}{.0, .1, .2} */ - static int mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[]) { @@ -603,7 +678,16 @@ mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const arg return 0; } -/* +/** + * do_i2c_probe() - Handle the "i2c probe" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: * i2c probe {addr} * @@ -657,7 +741,16 @@ static int do_i2c_probe (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv return (0 == found); } -/* +/** + * do_i2c_loop() - Handle the "i2c loop" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + * * Syntax: * i2c loop {i2c_chip} {addr}{.0, .1, .2} [{length}] [{delay}] * {length} - Number of bytes to read @@ -718,6 +811,8 @@ static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] /* * The SDRAM command is separately configured because many * (most?) embedded boards don't use SDRAM DIMMs. + * + * FIXME: Document and probably move elsewhere! */ #if defined(CONFIG_CMD_SDRAM) static void print_ddr2_tcyc (u_char const b) @@ -1246,7 +1341,48 @@ static int do_sdram (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) } #endif +/* + * Syntax: + * i2c edid {i2c_chip} + */ +#if defined(CONFIG_I2C_EDID) +int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + u_char chip; + struct edid1_info edid; + + if (argc < 2) { + cmd_usage(cmdtp); + return 1; + } + + chip = simple_strtoul(argv[1], NULL, 16); + if (i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid)) != 0) { + puts("Error reading EDID content.\n"); + return 1; + } + + if (edid_check_info(&edid)) { + puts("Content isn't valid EDID.\n"); + return 1; + } + + edid_print_info(&edid); + return 0; + +} +#endif /* CONFIG_I2C_EDID */ + #if defined(CONFIG_I2C_MUX) +/** + * do_i2c_add_bus() - Handle the "i2c bus" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero always. + */ static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int ret=0; @@ -1276,6 +1412,16 @@ static int do_i2c_add_bus(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar #endif /* CONFIG_I2C_MUX */ #if defined(CONFIG_I2C_MULTI_BUS) +/** + * do_i2c_bus_num() - Handle the "i2c dev" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int bus_idx, ret=0; @@ -1294,6 +1440,16 @@ static int do_i2c_bus_num(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar } #endif /* CONFIG_I2C_MULTI_BUS */ +/** + * do_i2c_bus_speed() - Handle the "i2c speed" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int speed, ret=0; @@ -1311,16 +1467,45 @@ static int do_i2c_bus_speed(cmd_tbl_t * cmdtp, int flag, int argc, char * const return ret; } +/** + * do_i2c_mm() - Handle the "i2c mm" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ static int do_i2c_mm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { return mod_i2c_mem (cmdtp, 1, flag, argc, argv); } +/** + * do_i2c_nm() - Handle the "i2c nm" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ static int do_i2c_nm(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { return mod_i2c_mem (cmdtp, 0, flag, argc, argv); } +/** + * do_i2c_reset() - Handle the "i2c reset" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero always. + */ static int do_i2c_reset(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); @@ -1335,6 +1520,9 @@ static cmd_tbl_t cmd_i2c_sub[] = { #if defined(CONFIG_I2C_MULTI_BUS) U_BOOT_CMD_MKENT(dev, 1, 1, do_i2c_bus_num, "", ""), #endif /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) + U_BOOT_CMD_MKENT(edid, 1, 1, do_edid, "", ""), +#endif /* CONFIG_I2C_EDID */ U_BOOT_CMD_MKENT(loop, 3, 1, do_i2c_loop, "", ""), U_BOOT_CMD_MKENT(md, 3, 1, do_i2c_md, "", ""), U_BOOT_CMD_MKENT(mm, 2, 1, do_i2c_mm, "", ""), @@ -1356,6 +1544,16 @@ void i2c_reloc(void) { } #endif +/** + * do_i2c() - Handle the "i2c" command-line command + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Returns zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { cmd_tbl_t *c; @@ -1385,6 +1583,9 @@ static char i2c_help_text[] = #if defined(CONFIG_I2C_MULTI_BUS) "i2c dev [dev] - show or set current I2C bus\n" #endif /* CONFIG_I2C_MULTI_BUS */ +#if defined(CONFIG_I2C_EDID) + "i2c edid chip - print EDID configuration information\n" +#endif /* CONFIG_I2C_EDID */ "i2c loop chip address[.0, .1, .2] [# of objects] - looping read of device\n" "i2c md chip address[.0, .1, .2] [# of objects] - read from I2C device\n" "i2c mm chip address[.0, .1, .2] - write to I2C device (auto-incrementing)\n" diff --git a/common/cmd_io.c b/common/cmd_io.c new file mode 100644 index 0000000000..6450cb576b --- /dev/null +++ b/common/cmd_io.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * IO space access commands. + */ + +#include <common.h> +#include <command.h> +#include <asm/io.h> + +/* + * IO Display + * + * Syntax: + * iod{.b, .w, .l} {addr} + */ +int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + ulong addr; + int size; + + if (argc != 2) + return CMD_RET_USAGE; + + size = cmd_get_data_size(argv[0], 4); + if (size < 0) + return 1; + + addr = simple_strtoul(argv[1], NULL, 16); + + printf("%04x: ", (u16) addr); + + if (size == 4) + printf("%08x\n", inl(addr)); + else if (size == 2) + printf("%04x\n", inw(addr)); + else + printf("%02x\n", inb(addr)); + + return 0; +} + +int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + ulong addr, size, val; + + if (argc != 3) + return CMD_RET_USAGE; + + size = cmd_get_data_size(argv[0], 4); + if (size < 0) + return 1; + + addr = simple_strtoul(argv[1], NULL, 16); + val = simple_strtoul(argv[2], NULL, 16); + + if (size == 4) + outl((u32) val, addr); + else if (size == 2) + outw((u16) val, addr); + else + outb((u8) val, addr); + + return 0; +} + +/**************************************************/ +U_BOOT_CMD(iod, 2, 0, do_io_iod, + "IO space display", "[.b, .w, .l] address [# of objects]"); + +U_BOOT_CMD(iow, 3, 0, do_io_iow, + "IO space modify (auto-incrementing address)", + "[.b, .w, .l] address"); diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 006131f45c..7633f0c44a 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -47,12 +47,8 @@ #include <errno.h> #include <malloc.h> #include <watchdog.h> -#include <serial.h> #include <linux/stddef.h> #include <asm/byteorder.h> -#if defined(CONFIG_CMD_NET) -#include <net.h> -#endif DECLARE_GLOBAL_DATA_PTR; @@ -76,16 +72,6 @@ SPI_FLASH|NVRAM|MMC|FAT|REMOTE} or CONFIG_ENV_IS_NOWHERE */ #define MAX_ENV_SIZE (1 << 20) /* 1 MiB */ -ulong load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */ -ulong save_addr; /* Default Save Address */ -ulong save_size; /* Default Save Size (in bytes) */ - -/* - * Table with supported baudrates (defined in config_xyz.h) - */ -static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; -#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0])) - /* * This variable is incremented on each do_env_set(), so it can * be used via get_env_id() as an indication, if the environment @@ -106,7 +92,7 @@ int get_env_id(void) * * Returns 0 in case of error, or length of printed string */ -static int env_print(char *name) +static int env_print(char *name, int flag) { char *res = NULL; size_t len; @@ -116,7 +102,7 @@ static int env_print(char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, flag); if (ep == NULL) return 0; len = printf("%s=%s\n", ep->key, ep->data); @@ -124,7 +110,7 @@ static int env_print(char *name) } /* print whole list */ - len = hexport_r(&env_htab, '\n', &res, 0, 0, NULL); + len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL); if (len > 0) { puts(res); @@ -141,10 +127,17 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, { int i; int rcode = 0; + int env_flag = H_HIDE_DOT; + + if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') { + argc--; + argv++; + env_flag &= ~H_HIDE_DOT; + } if (argc == 1) { /* print all env vars */ - rcode = env_print(NULL); + rcode = env_print(NULL, env_flag); if (!rcode) return 1; printf("\nEnvironment size: %d/%ld bytes\n", @@ -153,8 +146,9 @@ static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, } /* print selected env vars */ + env_flag &= ~H_HIDE_DOT; for (i = 1; i < argc; ++i) { - int rc = env_print(argv[i]); + int rc = env_print(argv[i], env_flag); if (!rc) { printf("## Error: \"%s\" not defined\n", argv[i]); ++rcode; @@ -198,137 +192,32 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag, #endif /* CONFIG_SPL_BUILD */ /* - * Perform consistency checking before setting, replacing, or deleting an - * environment variable, then (if successful) apply the changes to internals so - * to make them effective. Code for this function was taken out of - * _do_env_set(), which now calls it instead. - * Also called as a callback function by himport_r(). - * Returns 0 in case of success, 1 in case of failure. - * When (flag & H_FORCE) is set, do not print out any error message and force - * overwriting of write-once variables. - */ - -int env_check_apply(const char *name, const char *oldval, - const char *newval, int flag) -{ - int console = -1; - - /* Default value for NULL to protect string-manipulating functions */ - newval = newval ? : ""; - - /* Check for console redirection */ - if (strcmp(name, "stdin") == 0) - console = stdin; - else if (strcmp(name, "stdout") == 0) - console = stdout; - else if (strcmp(name, "stderr") == 0) - console = stderr; - - if (console != -1) { - if ((newval == NULL) || (*newval == '\0')) { - /* We cannot delete stdin/stdout/stderr */ - if ((flag & H_FORCE) == 0) - printf("Can't delete \"%s\"\n", name); - return 1; - } - -#ifdef CONFIG_CONSOLE_MUX - if (iomux_doenv(console, newval)) - return 1; -#else - /* Try assigning specified device */ - if (console_assign(console, newval) < 0) - return 1; -#endif /* CONFIG_CONSOLE_MUX */ - } - - /* - * Some variables like "ethaddr" and "serial#" can be set only once and - * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined. - */ -#ifndef CONFIG_ENV_OVERWRITE - if (oldval != NULL && /* variable exists */ - (flag & H_FORCE) == 0) { /* and we are not forced */ - if (strcmp(name, "serial#") == 0 || - (strcmp(name, "ethaddr") == 0 -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) - && strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0 -#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ - )) { - printf("Can't overwrite \"%s\"\n", name); - return 1; - } - } -#endif - /* - * When we change baudrate, or we are doing an env default -a - * (which will erase all variables prior to calling this), - * we want the baudrate to actually change - for real. - */ - if (oldval != NULL || /* variable exists */ - (flag & H_NOCLEAR) == 0) { /* or env is clear */ - /* - * Switch to new baudrate if new baudrate is supported - */ - if (strcmp(name, "baudrate") == 0) { - int baudrate = simple_strtoul(newval, NULL, 10); - int i; - for (i = 0; i < N_BAUDRATES; ++i) { - if (baudrate == baudrate_table[i]) - break; - } - if (i == N_BAUDRATES) { - if ((flag & H_FORCE) == 0) - printf("## Baudrate %d bps not " - "supported\n", baudrate); - return 1; - } - if (gd->baudrate == baudrate) { - /* If unchanged, we just say it's OK */ - return 0; - } - printf("## Switch baudrate to %d bps and" - "press ENTER ...\n", baudrate); - udelay(50000); - gd->baudrate = baudrate; -#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) - gd->bd->bi_baudrate = baudrate; -#endif - - serial_setbrg(); - udelay(50000); - while (getc() != '\r') - ; - } - } - - /* - * Some variables should be updated when the corresponding - * entry in the environment is changed - */ - if (strcmp(name, "loadaddr") == 0) { - load_addr = simple_strtoul(newval, NULL, 16); - return 0; - } -#if defined(CONFIG_CMD_NET) - else if (strcmp(name, "bootfile") == 0) { - copy_filename(BootFile, newval, sizeof(BootFile)); - return 0; - } -#endif - return 0; -} - -/* * Set a new environment variable, * or replace or delete an existing one. -*/ + */ static int _do_env_set(int flag, int argc, char * const argv[]) { int i, len; char *name, *value, *s; ENTRY e, *ep; + int env_flag = H_INTERACTIVE; + + debug("Initial value for argc=%d\n", argc); + while (argc > 1 && **(argv + 1) == '-') { + char *arg = *++argv; + --argc; + while (*++arg) { + switch (*arg) { + case 'f': /* force */ + env_flag |= H_FORCE; + break; + default: + return CMD_RET_USAGE; + } + } + } + debug("Final value for argc=%d\n", argc); name = argv[1]; value = argv[2]; @@ -339,25 +228,10 @@ static int _do_env_set(int flag, int argc, char * const argv[]) } env_id++; - /* - * search if variable with this name already exists - */ - e.key = name; - e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); - - /* - * Perform requested checks. Notice how since we are overwriting - * a single variable, we need to set H_NOCLEAR - */ - if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) { - debug("check function did not approve, refusing\n"); - return 1; - } /* Delete only ? */ if (argc < 3 || argv[2] == NULL) { - int rc = hdelete_r(name, &env_htab, 0); + int rc = hdelete_r(name, &env_htab, env_flag); return !rc; } @@ -384,7 +258,7 @@ static int _do_env_set(int flag, int argc, char * const argv[]) e.key = name; e.data = value; - hsearch_r(e, ENTER, &ep, &env_htab); + hsearch_r(e, ENTER, &ep, &env_htab, env_flag); free(value); if (!ep) { printf("## Error inserting \"%s\" variable, errno=%d\n", @@ -511,6 +385,153 @@ int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) +static int print_static_binding(const char *var_name, const char *callback_name) +{ + printf("\t%-20s %-20s\n", var_name, callback_name); + + return 0; +} + +static int print_active_callback(ENTRY *entry) +{ + struct env_clbk_tbl *clbkp; + int i; + int num_callbacks; + + if (entry->callback == NULL) + return 0; + + /* look up the callback in the linker-list */ + num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); + i < num_callbacks; + i++, clbkp++) { +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + if (entry->callback == clbkp->callback + gd->reloc_off) +#else + if (entry->callback == clbkp->callback) +#endif + break; + } + + if (i == num_callbacks) + /* this should probably never happen, but just in case... */ + printf("\t%-20s %p\n", entry->key, entry->callback); + else + printf("\t%-20s %-20s\n", entry->key, clbkp->name); + + return 0; +} + +/* + * Print the callbacks available and what they are bound to + */ +int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct env_clbk_tbl *clbkp; + int i; + int num_callbacks; + + /* Print the available callbacks */ + puts("Available callbacks:\n"); + puts("\tCallback Name\n"); + puts("\t-------------\n"); + num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); + i < num_callbacks; + i++, clbkp++) + printf("\t%s\n", clbkp->name); + puts("\n"); + + /* Print the static bindings that may exist */ + puts("Static callback bindings:\n"); + printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); + printf("\t%-20s %-20s\n", "-------------", "-------------"); + env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding); + puts("\n"); + + /* walk through each variable and print the callback if it has one */ + puts("Active callback bindings:\n"); + printf("\t%-20s %-20s\n", "Variable Name", "Callback Name"); + printf("\t%-20s %-20s\n", "-------------", "-------------"); + hwalk_r(&env_htab, print_active_callback); + return 0; +} +#endif + +#if defined(CONFIG_CMD_ENV_FLAGS) +static int print_static_flags(const char *var_name, const char *flags) +{ + enum env_flags_vartype type = env_flags_parse_vartype(flags); + enum env_flags_varaccess access = env_flags_parse_varaccess(flags); + + printf("\t%-20s %-20s %-20s\n", var_name, + env_flags_get_vartype_name(type), + env_flags_get_varaccess_name(access)); + + return 0; +} + +static int print_active_flags(ENTRY *entry) +{ + enum env_flags_vartype type; + enum env_flags_varaccess access; + + if (entry->flags == 0) + return 0; + + type = (enum env_flags_vartype) + (entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK); + access = env_flags_parse_varaccess_from_binflags(entry->flags); + printf("\t%-20s %-20s %-20s\n", entry->key, + env_flags_get_vartype_name(type), + env_flags_get_varaccess_name(access)); + + return 0; +} + +/* + * Print the flags available and what variables have flags + */ +int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + /* Print the available variable types */ + printf("Available variable type flags (position %d):\n", + ENV_FLAGS_VARTYPE_LOC); + puts("\tFlag\tVariable Type Name\n"); + puts("\t----\t------------------\n"); + env_flags_print_vartypes(); + puts("\n"); + + /* Print the available variable access types */ + printf("Available variable access flags (position %d):\n", + ENV_FLAGS_VARACCESS_LOC); + puts("\tFlag\tVariable Access Name\n"); + puts("\t----\t--------------------\n"); + env_flags_print_varaccess(); + puts("\n"); + + /* Print the static flags that may exist */ + puts("Static flags:\n"); + printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", + "Variable Access"); + printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", + "---------------"); + env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags); + puts("\n"); + + /* walk through each variable and print the flags if non-default */ + puts("Active flags:\n"); + printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type", + "Variable Access"); + printf("\t%-20s %-20s %-20s\n", "-------------", "-------------", + "---------------"); + hwalk_r(&env_htab, print_active_flags); + return 0; +} +#endif + /* * Interactively edit an environment variable */ @@ -552,7 +573,7 @@ char *getenv(const char *name) e.key = name; e.data = NULL; - hsearch_r(e, FIND, &ep, &env_htab); + hsearch_r(e, FIND, &ep, &env_htab, 0); return ep ? ep->data : NULL; } @@ -704,8 +725,36 @@ static int do_env_default(cmd_tbl_t *cmdtp, int __flag, static int do_env_delete(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - printf("Not implemented yet\n"); - return 0; + int env_flag = H_INTERACTIVE; + int ret = 0; + + debug("Initial value for argc=%d\n", argc); + while (argc > 1 && **(argv + 1) == '-') { + char *arg = *++argv; + + --argc; + while (*++arg) { + switch (*arg) { + case 'f': /* force */ + env_flag |= H_FORCE; + break; + default: + return CMD_RET_USAGE; + } + } + } + debug("Final value for argc=%d\n", argc); + + env_id++; + + while (--argc > 0) { + char *name = *++argv; + + if (!hdelete_r(name, &env_htab, env_flag)) + ret = 1; + } + + return ret; } #ifdef CONFIG_CMD_EXPORTENV @@ -812,7 +861,7 @@ NXTARG: ; argv++; if (sep) { /* export as text file */ - len = hexport_r(&env_htab, sep, &addr, size, argc, argv); + len = hexport_r(&env_htab, sep, 0, &addr, size, argc, argv); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -830,7 +879,7 @@ NXTARG: ; else /* export as raw binary data */ res = addr; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, argc, argv); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, argc, argv); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -951,7 +1000,7 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag, } if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR, - 0, NULL, 0 /* do_apply */) == 0) { + 0, NULL) == 0) { error("Environment import failed: errno = %d\n", errno); return 1; } @@ -974,10 +1023,16 @@ static cmd_tbl_t cmd_env_sub[] = { U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""), #endif U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""), - U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""), + U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""), #if defined(CONFIG_CMD_EDITENV) U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""), #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) + U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""), +#endif +#if defined(CONFIG_CMD_ENV_FLAGS) + U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""), +#endif #if defined(CONFIG_CMD_EXPORTENV) U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""), #endif @@ -1028,21 +1083,28 @@ static char env_help_text[] = #if defined(CONFIG_CMD_ASKENV) "ask name [message] [size] - ask for environment variable\nenv " #endif +#if defined(CONFIG_CMD_ENV_CALLBACK) + "callbacks - print callbacks and their associated variables\nenv " +#endif "default [-f] -a - [forcibly] reset default environment\n" "env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n" + "env delete [-f] var [...] - [forcibly] delete variable(s)\n" #if defined(CONFIG_CMD_EDITENV) "env edit name - edit environment variable\n" #endif #if defined(CONFIG_CMD_EXPORTENV) "env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n" #endif +#if defined(CONFIG_CMD_ENV_FLAGS) + "env flags - print variables that have non-default flags\n" +#endif #if defined(CONFIG_CMD_GREPENV) "env grep string [...] - search environment\n" #endif #if defined(CONFIG_CMD_IMPORTENV) "env import [-d] [-t | -b | -c] addr [size] - import environment\n" #endif - "env print [name ...] - print environment\n" + "env print [-a | name ...] - print environment\n" #if defined(CONFIG_CMD_RUN) "env run var [...] - run commands in an environment variable\n" #endif @@ -1074,7 +1136,7 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( printenv, CONFIG_SYS_MAXARGS, 1, do_env_print, "print environment variables", - "\n - print values of all environment variables\n" + "[-a]\n - print [all] values of all environment variables\n" "printenv name ...\n" " - print value of environment variable 'name'", var_complete @@ -1093,10 +1155,10 @@ U_BOOT_CMD_COMPLETE( U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables", - "name value ...\n" - " - set environment variable 'name' to 'value ...'\n" - "setenv name\n" - " - delete environment variable 'name'", + "[-f] name value ...\n" + " - [forcibly] set environment variable 'name' to 'value ...'\n" + "setenv [-f] name\n" + " - [forcibly] delete environment variable 'name'", var_complete ); diff --git a/common/cmd_read.c b/common/cmd_read.c new file mode 100644 index 0000000000..f0fc9bfe17 --- /dev/null +++ b/common/cmd_read.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include <common.h> +#include <command.h> +#include <part.h> + +int do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *ep; + block_dev_desc_t *dev_desc = NULL; + int dev; + int part = 0; + disk_partition_t part_info; + ulong offset = 0u; + ulong limit = 0u; + void *addr; + uint blk; + uint cnt; + + if (argc != 6) { + cmd_usage(cmdtp); + return 1; + } + + dev = (int)simple_strtoul(argv[2], &ep, 16); + if (*ep) { + if (*ep != ':') { + printf("Invalid block device %s\n", argv[2]); + return 1; + } + part = (int)simple_strtoul(++ep, NULL, 16); + } + + dev_desc = get_dev(argv[1], dev); + if (dev_desc == NULL) { + printf("Block device %s %d not supported\n", argv[1], dev); + return 1; + } + + addr = (void *)simple_strtoul(argv[3], NULL, 16); + blk = simple_strtoul(argv[4], NULL, 16); + cnt = simple_strtoul(argv[5], NULL, 16); + + if (part != 0) { + if (get_partition_info(dev_desc, part, &part_info)) { + printf("Cannot find partition %d\n", part); + return 1; + } + offset = part_info.start; + limit = part_info.size; + } else { + /* Largest address not available in block_dev_desc_t. */ + limit = ~0; + } + + if (cnt + blk > limit) { + printf("Read out of range\n"); + return 1; + } + + if (dev_desc->block_read(dev, offset + blk, cnt, addr) < 0) { + printf("Error reading blocks\n"); + return 1; + } + + return 0; +} + +U_BOOT_CMD( + read, 6, 0, do_read, + "Load binary data from a partition", + "<interface> <dev[:part]> addr blk# cnt" +); diff --git a/common/cmd_sha1sum.c b/common/cmd_sha1sum.c index 8db5456c95..fe927ab248 100644 --- a/common/cmd_sha1sum.c +++ b/common/cmd_sha1sum.c @@ -26,73 +26,11 @@ #include <common.h> #include <command.h> +#include <hash.h> #include <sha1.h> -/* - * Store the resulting sum to an address or variable - */ -static void store_result(const u8 *sum, const char *dest) -{ - unsigned int i; - - if (*dest == '*') { - u8 *ptr; - - ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16); - for (i = 0; i < 20; i++) - *ptr++ = sum[i]; - } else { - char str_output[41]; - char *str_ptr = str_output; - - for (i = 0; i < 20; i++) { - sprintf(str_ptr, "%02x", sum[i]); - str_ptr += 2; - } - str_ptr = '\0'; - setenv(dest, str_output); - } -} - -#ifdef CONFIG_SHA1SUM_VERIFY -static int parse_verify_sum(char *verify_str, u8 *vsum) -{ - if (*verify_str == '*') { - u8 *ptr; - - ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16); - memcpy(vsum, ptr, 20); - } else { - unsigned int i; - char *vsum_str; - - if (strlen(verify_str) == 40) - vsum_str = verify_str; - else { - vsum_str = getenv(verify_str); - if (vsum_str == NULL || strlen(vsum_str) != 40) - return 1; - } - - for (i = 0; i < 20; i++) { - char *nullp = vsum_str + (i + 1) * 2; - char end = *nullp; - - *nullp = '\0'; - *(u8 *)(vsum + i) = - simple_strtoul(vsum_str + (i * 2), NULL, 16); - *nullp = end; - } - } - return 0; -} - int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - ulong addr, len; - unsigned int i; - u8 output[20]; - u8 vsum[20]; int verify = 0; int ac; char * const *av; @@ -102,75 +40,16 @@ int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) av = argv + 1; ac = argc - 1; +#ifdef CONFIG_SHA1SUM_VERIFY if (strcmp(*av, "-v") == 0) { verify = 1; av++; ac--; - if (ac < 3) - return CMD_RET_USAGE; } +#endif - addr = simple_strtoul(*av++, NULL, 16); - len = simple_strtoul(*av++, NULL, 16); - - sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1); - - if (!verify) { - printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1); - for (i = 0; i < 20; i++) - printf("%02x", output[i]); - printf("\n"); - - if (ac > 2) - store_result(output, *av); - } else { - char *verify_str = *av++; - - if (parse_verify_sum(verify_str, vsum)) { - printf("ERROR: %s does not contain a valid SHA1 sum\n", - verify_str); - return 1; - } - if (memcmp(output, vsum, 20) != 0) { - printf("SHA1 for %08lx ... %08lx ==> ", addr, - addr + len - 1); - for (i = 0; i < 20; i++) - printf("%02x", output[i]); - printf(" != "); - for (i = 0; i < 20; i++) - printf("%02x", vsum[i]); - printf(" ** ERROR **\n"); - return 1; - } - } - - return 0; -} -#else -static int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - unsigned long addr, len; - unsigned int i; - u8 output[20]; - - if (argc < 3) - return CMD_RET_USAGE; - - addr = simple_strtoul(argv[1], NULL, 16); - len = simple_strtoul(argv[2], NULL, 16); - - sha1_csum_wd((unsigned char *) addr, len, output, CHUNKSZ_SHA1); - printf("SHA1 for %08lx ... %08lx ==> ", addr, addr + len - 1); - for (i = 0; i < 20; i++) - printf("%02x", output[i]); - printf("\n"); - - if (argc > 3) - store_result(output, argv[3]); - - return 0; + return hash_command("sha1", verify, cmdtp, flag, ac, av); } -#endif #ifdef CONFIG_SHA1SUM_VERIFY U_BOOT_CMD( diff --git a/common/cmd_spl.c b/common/cmd_spl.c index 9ec054af3b..e3c543b46a 100644 --- a/common/cmd_spl.c +++ b/common/cmd_spl.c @@ -130,10 +130,12 @@ static int spl_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (call_bootm(argc, argv, subcmd_list[(int)c->cmd])) return -1; switch ((int)c->cmd) { +#ifdef CONFIG_OF_LIBFDT case SPL_EXPORT_FDT: printf("Argument image is now in RAM: 0x%p\n", (void *)images.ft_addr); break; +#endif case SPL_EXPORT_ATAGS: printf("Argument image is now in RAM at: 0x%p\n", (void *)gd->bd->bi_boot_params); diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c index 6f5cd4895d..0970a6fc19 100644 --- a/common/cmd_tpm.c +++ b/common/cmd_tpm.c @@ -63,19 +63,68 @@ static int tpm_process(int argc, char * const argv[], cmd_tbl_t *cmdtp) return rv; } -static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +#define CHECK(exp) do { \ + int _rv = exp; \ + if (_rv) { \ + printf("CHECK: %s %d %x\n", #exp, __LINE__, _rv);\ + } \ + } while (0) + +static int tpm_process_stress(int repeat_count) { + int i; int rv = 0; + u8 request[] = {0x0, 0xc1, + 0x0, 0x0, 0x0, 0x16, + 0x0, 0x0, 0x0, 0x65, + 0x0, 0x0, 0x0, 0x4, + 0x0, 0x0, 0x0, 0x4, + 0x0, 0x0, 0x1, 0x9}; + u8 response[MAX_TRANSACTION_SIZE]; + u32 rlength = MAX_TRANSACTION_SIZE; + + CHECK(tis_init()); + + for (i = 0; i < repeat_count; i++) { + CHECK(tis_open()); + rv = tis_sendrecv(request, sizeof(request), response, &rlength); + if (rv) { + printf("tpm test failed at step %d with 0x%x\n", i, rv); + CHECK(tis_close()); + break; + } + CHECK(tis_close()); + if ((response[6] || response[7] || response[8] || response[9]) + && response[9] != 0x26) { + /* Ignore postinit errors */ + printf("tpm command failed at step %d\n" + "tpm error code: %02x%02x%02x%02x\n", i, + response[6], response[7], + response[8], response[9]); + rv = -1; + break; + } + } + return rv; +} - /* - * Verify that in case it is present, the first argument, it is - * exactly one character in size. - */ - if (argc < 7) { + +static int do_tpm_many(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[], int repeat_count) + +{ + int rv = 0; + + if (argc < 7 && repeat_count == 0) { puts("command should be at least six bytes in size\n"); return -1; } + if (repeat_count > 0) { + rv = tpm_process_stress(repeat_count); + return rv; + } + if (tis_init()) { puts("tis_init() failed!\n"); return -1; @@ -96,8 +145,40 @@ static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return rv; } + +static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + return do_tpm_many(cmdtp, flag, argc, argv, 0); +} + + U_BOOT_CMD(tpm, MAX_TRANSACTION_SIZE, 1, do_tpm, "<byte> [<byte> ...] - write data and read response", "send arbitrary data (at least 6 bytes) to the TPM " "device and read the response" ); + +static int do_tpm_stress(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + long unsigned int n; + int rv; + + if (argc != 2) { + puts("usage: tpm_stress <count>\n"); + return -1; + } + + rv = strict_strtoul(argv[1], 10, &n); + if (rv) { + puts("tpm_stress: bad count"); + return -1; + } + + return do_tpm_many(cmdtp, flag, argc, argv, n); +} + +U_BOOT_CMD(tpm_stress, 2, 1, do_tpm_stress, + "<n> - stress-test communication with TPM", + "Repeat a TPM transaction (request-response) N times" +); diff --git a/common/console.c b/common/console.c index 1177f7d396..bf73178690 100644 --- a/common/console.c +++ b/common/console.c @@ -24,11 +24,78 @@ #include <common.h> #include <stdarg.h> #include <malloc.h> +#include <serial.h> #include <stdio_dev.h> #include <exports.h> +#include <environment.h> DECLARE_GLOBAL_DATA_PTR; +static int on_console(const char *name, const char *value, enum env_op op, + int flags) +{ + int console = -1; + + /* Check for console redirection */ + if (strcmp(name, "stdin") == 0) + console = stdin; + else if (strcmp(name, "stdout") == 0) + console = stdout; + else if (strcmp(name, "stderr") == 0) + console = stderr; + + /* if not actually setting a console variable, we don't care */ + if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0) + return 0; + + switch (op) { + case env_op_create: + case env_op_overwrite: + +#ifdef CONFIG_CONSOLE_MUX + if (iomux_doenv(console, value)) + return 1; +#else + /* Try assigning specified device */ + if (console_assign(console, value) < 0) + return 1; +#endif /* CONFIG_CONSOLE_MUX */ + return 0; + + case env_op_delete: + if ((flags & H_FORCE) == 0) + printf("Can't delete \"%s\"\n", name); + return 1; + + default: + return 0; + } +} +U_BOOT_ENV_CALLBACK(console, on_console); + +#ifdef CONFIG_SILENT_CONSOLE +static int on_silent(const char *name, const char *value, enum env_op op, + int flags) +{ +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET + if (flags & H_INTERACTIVE) + return 0; +#endif +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC + if ((flags & H_INTERACTIVE) == 0) + return 0; +#endif + + if (value != NULL) + gd->flags |= GD_FLG_SILENT; + else + gd->flags &= ~GD_FLG_SILENT; + + return 0; +} +U_BOOT_ENV_CALLBACK(silent, on_silent); +#endif + #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV /* * if overwrite_console returns 1, the stdin, stderr and stdout @@ -591,7 +658,6 @@ int console_init_f(void) void stdio_print_current_devices(void) { -#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET /* Print information */ puts("In: "); if (stdio_devices[stdin] == NULL) { @@ -613,7 +679,6 @@ void stdio_print_current_devices(void) } else { printf ("%s\n", stdio_devices[stderr]->name); } -#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ } #ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV @@ -683,9 +748,9 @@ int console_init_r(void) done: #endif - gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ - +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE /* set the environment variables (will overwrite previous env settings) */ @@ -694,6 +759,8 @@ done: } #endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ + gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ + #if 0 /* If nothing usable installed, use only the initial console */ if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) @@ -758,15 +825,17 @@ int console_init_r(void) #endif } - gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ - +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ /* Setting environment variables */ for (i = 0; i < 3; i++) { setenv(stdio_names[i], stdio_devices[i]->name); } + gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ + #if 0 /* If nothing usable installed, use only the initial console */ if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL)) diff --git a/common/edid.c b/common/edid.c new file mode 100644 index 0000000000..c82c298097 --- /dev/null +++ b/common/edid.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2010 + * Petr Stetiar <ynezz@true.cz> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Contains stolen code from ddcprobe project which is: + * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com> + * + */ + +#include <common.h> +#include <edid.h> +#include <linux/ctype.h> +#include <linux/string.h> + +int edid_check_info(struct edid1_info *edid_info) +{ + if ((edid_info == NULL) || (edid_info->version == 0)) + return -1; + + if (memcmp(edid_info->header, "\x0\xff\xff\xff\xff\xff\xff\x0", 8)) + return -1; + + if (edid_info->version == 0xff && edid_info->revision == 0xff) + return -1; + + return 0; +} + +int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, + unsigned int *hmax, unsigned int *vmin, + unsigned int *vmax) +{ + int i; + struct edid_monitor_descriptor *monitor; + + *hmin = *hmax = *vmin = *vmax = 0; + if (edid_check_info(edid)) + return -1; + + for (i = 0; i < ARRAY_SIZE(edid->monitor_details.descriptor); i++) { + monitor = &edid->monitor_details.descriptor[i]; + if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) { + *hmin = monitor->data.range_data.horizontal_min; + *hmax = monitor->data.range_data.horizontal_max; + *vmin = monitor->data.range_data.vertical_min; + *vmax = monitor->data.range_data.vertical_max; + return 0; + } + } + return -1; +} + +/** + * Snip the tailing whitespace/return of a string. + * + * @param string The string to be snipped + * @return the snipped string + */ +static char *snip(char *string) +{ + char *s; + + /* + * This is always a 13 character buffer + * and it's not always terminated. + */ + string[12] = '\0'; + s = &string[strlen(string) - 1]; + + while (s >= string && (isspace(*s) || *s == '\n' || *s == '\r' || + *s == '\0')) + *(s--) = '\0'; + + return string; +} + +/** + * Print an EDID monitor descriptor block + * + * @param monitor The EDID monitor descriptor block + * @have_timing Modifies to 1 if the desciptor contains timing info + */ +static void edid_print_dtd(struct edid_monitor_descriptor *monitor, + unsigned int *have_timing) +{ + unsigned char *bytes = (unsigned char *)monitor; + struct edid_detailed_timing *timing = + (struct edid_detailed_timing *)monitor; + + if (bytes[0] == 0 && bytes[1] == 0) { + if (monitor->type == EDID_MONITOR_DESCRIPTOR_SERIAL) + printf("Monitor serial number: %s\n", + snip(monitor->data.string)); + else if (monitor->type == EDID_MONITOR_DESCRIPTOR_ASCII) + printf("Monitor ID: %s\n", + snip(monitor->data.string)); + else if (monitor->type == EDID_MONITOR_DESCRIPTOR_NAME) + printf("Monitor name: %s\n", + snip(monitor->data.string)); + else if (monitor->type == EDID_MONITOR_DESCRIPTOR_RANGE) + printf("Monitor range limits, horizontal sync: " + "%d-%d kHz, vertical refresh: " + "%d-%d Hz, max pixel clock: " + "%d MHz\n", + monitor->data.range_data.horizontal_min, + monitor->data.range_data.horizontal_max, + monitor->data.range_data.vertical_min, + monitor->data.range_data.vertical_max, + monitor->data.range_data.pixel_clock_max * 10); + } else { + uint32_t pixclock, h_active, h_blanking, v_active, v_blanking; + uint32_t h_total, v_total, vfreq; + + pixclock = EDID_DETAILED_TIMING_PIXEL_CLOCK(*timing); + h_active = EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(*timing); + h_blanking = EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(*timing); + v_active = EDID_DETAILED_TIMING_VERTICAL_ACTIVE(*timing); + v_blanking = EDID_DETAILED_TIMING_VERTICAL_BLANKING(*timing); + + h_total = h_active + h_blanking; + v_total = v_active + v_blanking; + if (v_total * h_total) + vfreq = pixclock / (v_total * h_total); + else + vfreq = 1; /* Error case */ + printf("\t%dx%d\%c\t%d Hz (detailed)\n", h_active, + v_active, h_active > 1000 ? ' ' : '\t', vfreq); + *have_timing = 1; + } +} + +/** + * Get the manufacturer name from an EDID info. + * + * @param edid_info The EDID info to be printed + * @param name Returns the string of the manufacturer name + */ +static void edid_get_manufacturer_name(struct edid1_info *edid, char *name) +{ + name[0] = EDID1_INFO_MANUFACTURER_NAME_CHAR1(*edid) + 'A' - 1; + name[1] = EDID1_INFO_MANUFACTURER_NAME_CHAR2(*edid) + 'A' - 1; + name[2] = EDID1_INFO_MANUFACTURER_NAME_CHAR3(*edid) + 'A' - 1; + name[3] = '\0'; +} + +void edid_print_info(struct edid1_info *edid_info) +{ + int i; + char manufacturer[4]; + unsigned int have_timing = 0; + uint32_t serial_number; + + if (edid_check_info(edid_info)) { + printf("Not a valid EDID\n"); + return; + } + + printf("EDID version: %d.%d\n", + edid_info->version, edid_info->revision); + + printf("Product ID code: %04x\n", EDID1_INFO_PRODUCT_CODE(*edid_info)); + + edid_get_manufacturer_name(edid_info, manufacturer); + printf("Manufacturer: %s\n", manufacturer); + + serial_number = EDID1_INFO_SERIAL_NUMBER(*edid_info); + if (serial_number != 0xffffffff) { + if (strcmp(manufacturer, "MAG") == 0) + serial_number -= 0x7000000; + if (strcmp(manufacturer, "OQI") == 0) + serial_number -= 456150000; + if (strcmp(manufacturer, "VSC") == 0) + serial_number -= 640000000; + } + printf("Serial number: %08x\n", serial_number); + printf("Manufactured in week: %d year: %d\n", + edid_info->week, edid_info->year + 1990); + + printf("Video input definition: %svoltage level %d%s%s%s%s%s\n", + EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid_info) ? + "digital signal, " : "analog signal, ", + EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(*edid_info), + EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(*edid_info) ? + ", blank to black" : "", + EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(*edid_info) ? + ", separate sync" : "", + EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(*edid_info) ? + ", composite sync" : "", + EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(*edid_info) ? + ", sync on green" : "", + EDID1_INFO_VIDEO_INPUT_SERRATION_V(*edid_info) ? + ", serration v" : ""); + + printf("Monitor is %s\n", + EDID1_INFO_FEATURE_RGB(*edid_info) ? "RGB" : "non-RGB"); + + printf("Maximum visible display size: %d cm x %d cm\n", + edid_info->max_size_horizontal, + edid_info->max_size_vertical); + + printf("Power management features: %s%s, %s%s, %s%s\n", + EDID1_INFO_FEATURE_ACTIVE_OFF(*edid_info) ? + "" : "no ", "active off", + EDID1_INFO_FEATURE_SUSPEND(*edid_info) ? "" : "no ", "suspend", + EDID1_INFO_FEATURE_STANDBY(*edid_info) ? "" : "no ", "standby"); + + printf("Estabilished timings:\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_720X400_70(*edid_info)) + printf("\t720x400\t\t70 Hz (VGA 640x400, IBM)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_720X400_88(*edid_info)) + printf("\t720x400\t\t88 Hz (XGA2)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_640X480_60(*edid_info)) + printf("\t640x480\t\t60 Hz (VGA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_640X480_67(*edid_info)) + printf("\t640x480\t\t67 Hz (Mac II, Apple)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_640X480_72(*edid_info)) + printf("\t640x480\t\t72 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_640X480_75(*edid_info)) + printf("\t640x480\t\t75 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_800X600_56(*edid_info)) + printf("\t800x600\t\t56 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_800X600_60(*edid_info)) + printf("\t800x600\t\t60 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_800X600_72(*edid_info)) + printf("\t800x600\t\t72 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_800X600_75(*edid_info)) + printf("\t800x600\t\t75 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_832X624_75(*edid_info)) + printf("\t832x624\t\t75 Hz (Mac II)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(*edid_info)) + printf("\t1024x768\t87 Hz Interlaced (8514A)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(*edid_info)) + printf("\t1024x768\t60 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(*edid_info)) + printf("\t1024x768\t70 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(*edid_info)) + printf("\t1024x768\t75 Hz (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(*edid_info)) + printf("\t1280x1024\t75 (VESA)\n"); + if (EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(*edid_info)) + printf("\t1152x870\t75 (Mac II)\n"); + + /* Standard timings. */ + printf("Standard timings:\n"); + for (i = 0; i < ARRAY_SIZE(edid_info->standard_timings); i++) { + unsigned int aspect = 10000; + unsigned int x, y; + unsigned char xres, vfreq; + + xres = EDID1_INFO_STANDARD_TIMING_XRESOLUTION(*edid_info, i); + vfreq = EDID1_INFO_STANDARD_TIMING_VFREQ(*edid_info, i); + if ((xres != vfreq) || + ((xres != 0) && (xres != 1)) || + ((vfreq != 0) && (vfreq != 1))) { + switch (EDID1_INFO_STANDARD_TIMING_ASPECT(*edid_info, + i)) { + case ASPECT_625: + aspect = 6250; + break; + case ASPECT_75: + aspect = 7500; + break; + case ASPECT_8: + aspect = 8000; + break; + case ASPECT_5625: + aspect = 5625; + break; + } + x = (xres + 31) * 8; + y = x * aspect / 10000; + printf("\t%dx%d%c\t%d Hz\n", x, y, + x > 1000 ? ' ' : '\t', (vfreq & 0x3f) + 60); + have_timing = 1; + } + } + + /* Detailed timing information. */ + for (i = 0; i < ARRAY_SIZE(edid_info->monitor_details.descriptor); + i++) { + edid_print_dtd(&edid_info->monitor_details.descriptor[i], + &have_timing); + } + + if (!have_timing) + printf("\tNone\n"); +} diff --git a/common/env_attr.c b/common/env_attr.c new file mode 100644 index 0000000000..210c98dcfd --- /dev/null +++ b/common/env_attr.c @@ -0,0 +1,229 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ +#include <stdint.h> +#include <stdio.h> +#include <linux/linux_string.h> +#else +#include <common.h> +#endif + +#include <env_attr.h> +#include <errno.h> +#include <linux/string.h> +#include <malloc.h> + +/* + * Iterate through the whole list calling the callback for each found element. + * "attr_list" takes the form: + * attributes = [^,:\s]* + * entry = name[:attributes] + * list = entry[,list] + */ +int env_attr_walk(const char *attr_list, + int (*callback)(const char *name, const char *attributes)) +{ + const char *entry, *entry_end; + char *name, *attributes; + + if (!attr_list) + /* list not found */ + return 1; + + entry = attr_list; + do { + char *entry_cpy = NULL; + + entry_end = strchr(entry, ENV_ATTR_LIST_DELIM); + /* check if this is the last entry in the list */ + if (entry_end == NULL) { + int entry_len = strlen(entry); + + if (entry_len) { + /* + * allocate memory to copy the entry into since + * we will need to inject '\0' chars and squash + * white-space before calling the callback + */ + entry_cpy = malloc(entry_len + 1); + if (entry_cpy) + /* copy the rest of the list */ + strcpy(entry_cpy, entry); + else + return -ENOMEM; + } + } else { + int entry_len = entry_end - entry; + + if (entry_len) { + /* + * allocate memory to copy the entry into since + * we will need to inject '\0' chars and squash + * white-space before calling the callback + */ + entry_cpy = malloc(entry_len + 1); + if (entry_cpy) { + /* copy just this entry and null term */ + strncpy(entry_cpy, entry, entry_len); + entry_cpy[entry_len] = '\0'; + } else + return -ENOMEM; + } + } + + /* check if there is anything to process (e.g. not ",,,") */ + if (entry_cpy != NULL) { + attributes = strchr(entry_cpy, ENV_ATTR_SEP); + /* check if there is a ':' */ + if (attributes != NULL) { + /* replace the ':' with '\0' to term name */ + *attributes++ = '\0'; + /* remove white-space from attributes */ + attributes = strim(attributes); + } + /* remove white-space from name */ + name = strim(entry_cpy); + + /* only call the callback if there is a name */ + if (strlen(name) != 0) { + int retval = 0; + + retval = callback(name, attributes); + if (retval) { + free(entry_cpy); + return retval; + } + } + } + + free(entry_cpy); + entry = entry_end + 1; + } while (entry_end != NULL); + + return 0; +} + +/* + * Search for the last matching string in another string with the option to + * start looking at a certain point (i.e. ignore anything beyond that point). + */ +static char *reverse_strstr(const char *searched, const char *search_for, + const char *searched_start) +{ + char *result = NULL; + + if (*search_for == '\0') + return (char *)searched; + + for (;;) { + char *match = strstr(searched, search_for); + + /* + * Stop looking if no new match is found or looking past the + * searched_start pointer + */ + if (match == NULL || (searched_start != NULL && + match + strlen(search_for) > searched_start)) + break; + + result = match; + searched = match + 1; + } + + return result; +} + +/* + * Retrieve the attributes string associated with a single name in the list + * There is no protection on attributes being too small for the value + */ +int env_attr_lookup(const char *attr_list, const char *name, char *attributes) +{ + const char *entry = NULL; + + if (!attributes) + /* bad parameter */ + return -1; + if (!attr_list) + /* list not found */ + return 1; + + entry = reverse_strstr(attr_list, name, NULL); + while (entry != NULL) { + const char *prevch = entry - 1; + const char *nextch = entry + strlen(name); + + /* Skip spaces */ + while (*prevch == ' ') + prevch--; + while (*nextch == ' ') + nextch++; + + /* check for an exact match */ + if ((entry == attr_list || + *prevch == ENV_ATTR_LIST_DELIM) && + (*nextch == ENV_ATTR_SEP || + *nextch == ENV_ATTR_LIST_DELIM || + *nextch == '\0')) + break; + + entry = reverse_strstr(attr_list, name, entry); + } + if (entry != NULL) { + int len; + + /* skip the name */ + entry += strlen(name); + /* skip spaces */ + while (*entry == ' ') + entry++; + if (*entry != ENV_ATTR_SEP) + len = 0; + else { + const char *delim; + static const char delims[] = { + ENV_ATTR_LIST_DELIM, ' ', '\0'}; + + /* skip the attr sep */ + entry += 1; + /* skip spaces */ + while (*entry == ' ') + entry++; + + delim = strpbrk(entry, delims); + if (delim == NULL) + len = strlen(entry); + else + len = delim - entry; + memcpy(attributes, entry, len); + } + attributes[len] = '\0'; + + /* success */ + return 0; + } + + /* not found in list */ + return 2; +} diff --git a/common/env_callback.c b/common/env_callback.c new file mode 100644 index 0000000000..78ca3674f0 --- /dev/null +++ b/common/env_callback.c @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <environment.h> + +#if defined(CONFIG_NEEDS_MANUAL_RELOC) +DECLARE_GLOBAL_DATA_PTR; +#endif + +/* + * Look up a callback function pointer by name + */ +struct env_clbk_tbl *find_env_callback(const char *name) +{ + struct env_clbk_tbl *clbkp; + int i; + int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk); + + if (name == NULL) + return NULL; + + /* look up the callback in the linker-list */ + for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk); + i < num_callbacks; + i++, clbkp++) { + if (strcmp(name, clbkp->name) == 0) + return clbkp; + } + + return NULL; +} + +/* + * Look for a possible callback for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_callback_init(ENTRY *var_entry) +{ + const char *var_name = var_entry->key; + const char *callback_list = getenv(ENV_CALLBACK_VAR); + char callback_name[256] = ""; + struct env_clbk_tbl *clbkp; + int ret = 1; + + /* look in the ".callbacks" var for a reference to this variable */ + if (callback_list != NULL) + ret = env_attr_lookup(callback_list, var_name, callback_name); + + /* only if not found there, look in the static list */ + if (ret) + ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name, + callback_name); + + /* if an association was found, set the callback pointer */ + if (!ret && strlen(callback_name)) { + clbkp = find_env_callback(callback_name); + if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + var_entry->callback = clbkp->callback + gd->reloc_off; +#else + var_entry->callback = clbkp->callback; +#endif + } +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a callback association should remove its callback. + */ +static int clear_callback(ENTRY *entry) +{ + entry->callback = NULL; + + return 0; +} + +/* + * Call for each element in the list that associates variables to callbacks + */ +static int set_callback(const char *name, const char *value) +{ + ENTRY e, *ep; + struct env_clbk_tbl *clbkp; + + e.key = name; + e.data = NULL; + hsearch_r(e, FIND, &ep, &env_htab, 0); + + /* does the env variable actually exist? */ + if (ep != NULL) { + /* the assocaition delares no callback, so remove the pointer */ + if (value == NULL || strlen(value) == 0) + ep->callback = NULL; + else { + /* assign the requested callback */ + clbkp = find_env_callback(value); + if (clbkp != NULL) +#if defined(CONFIG_NEEDS_MANUAL_RELOC) + ep->callback = clbkp->callback + gd->reloc_off; +#else + ep->callback = clbkp->callback; +#endif + } + } + + return 0; +} + +static int on_callbacks(const char *name, const char *value, enum env_op op, + int flags) +{ + /* remove all callbacks */ + hwalk_r(&env_htab, clear_callback); + + /* configure any static callback bindings */ + env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback); + /* configure any dynamic callback bindings */ + env_attr_walk(value, set_callback); + + return 0; +} +U_BOOT_ENV_CALLBACK(callbacks, on_callbacks); diff --git a/common/env_common.c b/common/env_common.c index 3d3cb70a6d..906b41fcca 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR; #include <env_default.h> struct hsearch_data env_htab = { - .apply = env_check_apply, + .change_ok = env_flags_validate, }; static uchar __env_get_char_spec(int index) @@ -81,13 +81,42 @@ const uchar *env_get_addr(int index) return &default_environment[index]; } +/* + * Read an environment variable as a boolean + * Return -1 if variable does not exist (default to true) + */ +int getenv_yesno(const char *var) +{ + char *s = getenv(var); + + if (s == NULL) + return -1; + return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ? + 1 : 0; +} + +/* + * Look up the variable from the default environment + */ +char *getenv_default(const char *name) +{ + char *ret_val; + unsigned long really_valid = gd->env_valid; + unsigned long real_gd_flags = gd->flags; + + /* Pretend that the image is bad. */ + gd->flags &= ~GD_FLG_ENV_READY; + gd->env_valid = 0; + ret_val = getenv(name); + gd->env_valid = really_valid; + gd->flags = real_gd_flags; + return ret_val; +} + void set_default_env(const char *s) { - /* - * By default, do not apply changes as they will eventually - * be applied by someone else - */ - int do_apply = 0; + int flags = 0; + if (sizeof(default_environment) > ENV_SIZE) { puts("*** Error - default environment is too large\n\n"); return; @@ -99,14 +128,7 @@ void set_default_env(const char *s) "using default environment\n\n", s + 1); } else { - /* - * This set_to_default was explicitly asked for - * by the user, as opposed to being a recovery - * mechanism. Therefore we check every single - * variable and apply changes to the system - * right away (e.g. baudrate, console). - */ - do_apply = 1; + flags = H_INTERACTIVE; puts(s); } } else { @@ -114,8 +136,8 @@ void set_default_env(const char *s) } if (himport_r(&env_htab, (char *)default_environment, - sizeof(default_environment), '\0', 0, - 0, NULL, do_apply) == 0) + sizeof(default_environment), '\0', flags, + 0, NULL) == 0) error("Environment import failed: errno = %d\n", errno); gd->flags |= GD_FLG_ENV_READY; @@ -130,8 +152,8 @@ int set_default_vars(int nvars, char * const vars[]) * (and use \0 as a separator) */ return himport_r(&env_htab, (const char *)default_environment, - sizeof(default_environment), '\0', H_NOCLEAR, - nvars, vars, 1 /* do_apply */); + sizeof(default_environment), '\0', + H_NOCLEAR | H_INTERACTIVE, nvars, vars); } #ifndef CONFIG_SPL_BUILD @@ -155,7 +177,7 @@ int env_import(const char *buf, int check) } if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, - 0, NULL, 0 /* do_apply */)) { + 0, NULL)) { gd->flags |= GD_FLG_ENV_READY; return 1; } @@ -172,6 +194,7 @@ void env_relocate(void) { #if defined(CONFIG_NEEDS_MANUAL_RELOC) env_reloc(); + env_htab.change_ok += gd->reloc_off; #endif if (gd->env_valid == 0) { #if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD) diff --git a/common/env_dataflash.c b/common/env_dataflash.c index 3c5af37bf5..38c96157b9 100644 --- a/common/env_dataflash.c +++ b/common/env_dataflash.c @@ -60,7 +60,7 @@ int saveenv(void) char *res; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_eeprom.c b/common/env_eeprom.c index b66bba29f5..45c935b6df 100644 --- a/common/env_eeprom.c +++ b/common/env_eeprom.c @@ -139,7 +139,7 @@ int saveenv(void) BUG_ON(env_ptr != NULL); res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_fat.c b/common/env_fat.c index 6ef531821e..c0f18ab97d 100644 --- a/common/env_fat.c +++ b/common/env_fat.c @@ -61,7 +61,7 @@ int saveenv(void) int err; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_flags.c b/common/env_flags.c new file mode 100644 index 0000000000..336cae4e9f --- /dev/null +++ b/common/env_flags.c @@ -0,0 +1,560 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <linux/string.h> +#include <linux/ctype.h> + +#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */ +#include <stdint.h> +#include <stdio.h> +#include "fw_env.h" +#include <env_attr.h> +#include <env_flags.h> +#define getenv fw_getenv +#else +#include <common.h> +#include <environment.h> +#endif + +#ifdef CONFIG_CMD_NET +#define ENV_FLAGS_NET_VARTYPE_REPS "im" +#else +#define ENV_FLAGS_NET_VARTYPE_REPS "" +#endif + +static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS; +static const char env_flags_varaccess_rep[] = "aroc"; +static const int env_flags_varaccess_mask[] = { + 0, + ENV_FLAGS_VARACCESS_PREVENT_DELETE | + ENV_FLAGS_VARACCESS_PREVENT_CREATE | + ENV_FLAGS_VARACCESS_PREVENT_OVERWR, + ENV_FLAGS_VARACCESS_PREVENT_DELETE | + ENV_FLAGS_VARACCESS_PREVENT_OVERWR, + ENV_FLAGS_VARACCESS_PREVENT_DELETE | + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR}; + +#ifdef CONFIG_CMD_ENV_FLAGS +static const char * const env_flags_vartype_names[] = { + "string", + "decimal", + "hexadecimal", + "boolean", +#ifdef CONFIG_CMD_NET + "IP address", + "MAC address", +#endif +}; +static const char * const env_flags_varaccess_names[] = { + "any", + "read-only", + "write-once", + "change-default", +}; + +/* + * Print the whole list of available type flags. + */ +void env_flags_print_vartypes(void) +{ + enum env_flags_vartype curtype = (enum env_flags_vartype)0; + + while (curtype != env_flags_vartype_end) { + printf("\t%c -\t%s\n", env_flags_vartype_rep[curtype], + env_flags_vartype_names[curtype]); + curtype++; + } +} + +/* + * Print the whole list of available access flags. + */ +void env_flags_print_varaccess(void) +{ + enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0; + + while (curaccess != env_flags_varaccess_end) { + printf("\t%c -\t%s\n", env_flags_varaccess_rep[curaccess], + env_flags_varaccess_names[curaccess]); + curaccess++; + } +} + +/* + * Return the name of the type. + */ +const char *env_flags_get_vartype_name(enum env_flags_vartype type) +{ + return env_flags_vartype_names[type]; +} + +/* + * Return the name of the access. + */ +const char *env_flags_get_varaccess_name(enum env_flags_varaccess access) +{ + return env_flags_varaccess_names[access]; +} +#endif /* CONFIG_CMD_ENV_FLAGS */ + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags) +{ + char *type; + + if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) + return env_flags_vartype_string; + + type = strchr(env_flags_vartype_rep, + flags[ENV_FLAGS_VARTYPE_LOC]); + + if (type != NULL) + return (enum env_flags_vartype) + (type - &env_flags_vartype_rep[0]); + + printf("## Warning: Unknown environment variable type '%c'\n", + flags[ENV_FLAGS_VARTYPE_LOC]); + return env_flags_vartype_string; +} + +/* + * Parse the flags string from a .flags attribute list into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess(const char *flags) +{ + char *access; + + if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) + return env_flags_varaccess_any; + + access = strchr(env_flags_varaccess_rep, + flags[ENV_FLAGS_VARACCESS_LOC]); + + if (access != NULL) + return (enum env_flags_varaccess) + (access - &env_flags_varaccess_rep[0]); + + printf("## Warning: Unknown environment variable access method '%c'\n", + flags[ENV_FLAGS_VARACCESS_LOC]); + return env_flags_varaccess_any; +} + +/* + * Parse the binary flags from a hash table entry into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags) +{ + int i; + + for (i = 0; i < sizeof(env_flags_varaccess_mask); i++) + if (env_flags_varaccess_mask[i] == + (binflags & ENV_FLAGS_VARACCESS_BIN_MASK)) + return (enum env_flags_varaccess)i; + + printf("Warning: Non-standard access flags. (0x%x)\n", + binflags & ENV_FLAGS_VARACCESS_BIN_MASK); + + return env_flags_varaccess_any; +} + +static inline int is_hex_prefix(const char *value) +{ + return value[0] == '0' && (value[1] == 'x' || value[1] == 'X'); +} + +static void skip_num(int hex, const char *value, const char **end, + int max_digits) +{ + int i; + + if (hex && is_hex_prefix(value)) + value += 2; + + for (i = max_digits; i != 0; i--) { + if (hex && !isxdigit(*value)) + break; + if (!hex && !isdigit(*value)) + break; + value++; + } + if (end != NULL) + *end = value; +} + +/* + * Based on the declared type enum, validate that the value string complies + * with that format + */ +static int _env_flags_validate_type(const char *value, + enum env_flags_vartype type) +{ + const char *end; +#ifdef CONFIG_CMD_NET + const char *cur; + int i; +#endif + + switch (type) { + case env_flags_vartype_string: + break; + case env_flags_vartype_decimal: + skip_num(0, value, &end, -1); + if (*end != '\0') + return -1; + break; + case env_flags_vartype_hex: + skip_num(1, value, &end, -1); + if (*end != '\0') + return -1; + if (value + 2 == end && is_hex_prefix(value)) + return -1; + break; + case env_flags_vartype_bool: + if (value[0] != '1' && value[0] != 'y' && value[0] != 't' && + value[0] != 'Y' && value[0] != 'T' && + value[0] != '0' && value[0] != 'n' && value[0] != 'f' && + value[0] != 'N' && value[0] != 'F') + return -1; + if (value[1] != '\0') + return -1; + break; +#ifdef CONFIG_CMD_NET + case env_flags_vartype_ipaddr: + cur = value; + for (i = 0; i < 4; i++) { + skip_num(0, cur, &end, 3); + if (cur == end) + return -1; + if (i != 3 && *end != '.') + return -1; + if (i == 3 && *end != '\0') + return -1; + cur = end + 1; + } + break; + case env_flags_vartype_macaddr: + cur = value; + for (i = 0; i < 6; i++) { + skip_num(1, cur, &end, 2); + if (cur == end) + return -1; + if (cur + 2 == end && is_hex_prefix(cur)) + return -1; + if (i != 5 && *end != ':') + return -1; + if (i == 5 && *end != '\0') + return -1; + cur = end + 1; + } + break; +#endif + case env_flags_vartype_end: + return -1; + } + + /* OK */ + return 0; +} + +/* + * Look for flags in a provided list and failing that the static list + */ +static inline int env_flags_lookup(const char *flags_list, const char *name, + char *flags) +{ + int ret = 1; + + if (!flags) + /* bad parameter */ + return -1; + + /* try the env first */ + if (flags_list) + ret = env_attr_lookup(flags_list, name, flags); + + if (ret != 0) + /* if not found in the env, look in the static list */ + ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags); + + return ret; +} + +#ifdef USE_HOSTCC /* Functions only used from tools/env */ +/* + * Look up any flags directly from the .flags variable and the static list + * and convert them to the vartype enum. + */ +enum env_flags_vartype env_flags_get_type(const char *name) +{ + const char *flags_list = getenv(ENV_FLAGS_VAR); + char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + + if (env_flags_lookup(flags_list, name, flags)) + return env_flags_vartype_string; + + if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC) + return env_flags_vartype_string; + + return env_flags_parse_vartype(flags); +} + +/* + * Look up the access of a variable directly from the .flags var. + */ +enum env_flags_varaccess env_flags_get_varaccess(const char *name) +{ + const char *flags_list = getenv(ENV_FLAGS_VAR); + char flags[ENV_FLAGS_ATTR_MAX_LEN + 1]; + + if (env_flags_lookup(flags_list, name, flags)) + return env_flags_varaccess_any; + + if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC) + return env_flags_varaccess_any; + + return env_flags_parse_varaccess(flags); +} + +/* + * Validate that the proposed new value for "name" is valid according to the + * defined flags for that variable, if any. + */ +int env_flags_validate_type(const char *name, const char *value) +{ + enum env_flags_vartype type; + + if (value == NULL) + return 0; + type = env_flags_get_type(name); + if (_env_flags_validate_type(value, type) < 0) { + printf("## Error: flags type check failure for " + "\"%s\" <= \"%s\" (type: %c)\n", + name, value, env_flags_vartype_rep[type]); + return -1; + } + return 0; +} + +/* + * Validate that the proposed access to variable "name" is valid according to + * the defined flags for that variable, if any. + */ +int env_flags_validate_varaccess(const char *name, int check_mask) +{ + enum env_flags_varaccess access; + int access_mask; + + access = env_flags_get_varaccess(name); + access_mask = env_flags_varaccess_mask[access]; + + return (check_mask & access_mask) != 0; +} + +/* + * Validate the parameters to "env set" directly + */ +int env_flags_validate_env_set_params(int argc, char * const argv[]) +{ + if ((argc >= 3) && argv[2] != NULL) { + enum env_flags_vartype type = env_flags_get_type(argv[1]); + + /* + * we don't currently check types that need more than + * one argument + */ + if (type != env_flags_vartype_string && argc > 3) { + printf("## Error: too many parameters for setting " + "\"%s\"\n", argv[1]); + return -1; + } + return env_flags_validate_type(argv[1], argv[2]); + } + /* ok */ + return 0; +} + +#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */ + +/* + * Parse the flag charachters from the .flags attribute list into the binary + * form to be stored in the environment entry->flags field. + */ +static int env_parse_flags_to_bin(const char *flags) +{ + int binflags; + + binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK; + binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)]; + + return binflags; +} + +/* + * Look for possible flags for a newly added variable + * This is called specifically when the variable did not exist in the hash + * previously, so the blanket update did not find this variable. + */ +void env_flags_init(ENTRY *var_entry) +{ + const char *var_name = var_entry->key; + const char *flags_list = getenv(ENV_FLAGS_VAR); + char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = ""; + int ret = 1; + + /* look in the ".flags" and static for a reference to this variable */ + ret = env_flags_lookup(flags_list, var_name, flags); + + /* if any flags were found, set the binary form to the entry */ + if (!ret && strlen(flags)) + var_entry->flags = env_parse_flags_to_bin(flags); +} + +/* + * Called on each existing env var prior to the blanket update since removing + * a flag in the flag list should remove its flags. + */ +static int clear_flags(ENTRY *entry) +{ + entry->flags = 0; + + return 0; +} + +/* + * Call for each element in the list that defines flags for a variable + */ +static int set_flags(const char *name, const char *value) +{ + ENTRY e, *ep; + + e.key = name; + e.data = NULL; + hsearch_r(e, FIND, &ep, &env_htab, 0); + + /* does the env variable actually exist? */ + if (ep != NULL) { + /* the flag list is empty, so clear the flags */ + if (value == NULL || strlen(value) == 0) + ep->flags = 0; + else + /* assign the requested flags */ + ep->flags = env_parse_flags_to_bin(value); + } + + return 0; +} + +static int on_flags(const char *name, const char *value, enum env_op op, + int flags) +{ + /* remove all flags */ + hwalk_r(&env_htab, clear_flags); + + /* configure any static flags */ + env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags); + /* configure any dynamic flags */ + env_attr_walk(value, set_flags); + + return 0; +} +U_BOOT_ENV_CALLBACK(flags, on_flags); + +/* + * Perform consistency checking before creating, overwriting, or deleting an + * environment variable. Called as a callback function by hsearch_r() and + * hdelete_r(). Returns 0 in case of success, 1 in case of failure. + * When (flag & H_FORCE) is set, do not print out any error message and force + * overwriting of write-once variables. + */ + +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, + int flag) +{ + const char *name; + const char *oldval = NULL; + + if (op != env_op_create) + oldval = item->data; + + name = item->key; + + /* Default value for NULL to protect string-manipulating functions */ + newval = newval ? : ""; + + /* validate the value to match the variable type */ + if (op != env_op_delete) { + enum env_flags_vartype type = (enum env_flags_vartype) + (ENV_FLAGS_VARTYPE_BIN_MASK & item->flags); + + if (_env_flags_validate_type(newval, type) < 0) { + printf("## Error: flags type check failure for " + "\"%s\" <= \"%s\" (type: %c)\n", + name, newval, env_flags_vartype_rep[type]); + return -1; + } + } + + /* check for access permission */ +#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE + if (flag & H_FORCE) + return 0; +#endif + switch (op) { + case env_op_delete: + if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) { + printf("## Error: Can't delete \"%s\"\n", name); + return 1; + } + break; + case env_op_overwrite: + if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) { + printf("## Error: Can't overwrite \"%s\"\n", name); + return 1; + } else if (item->flags & + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) { + const char *defval = getenv_default(name); + + if (defval == NULL) + defval = ""; + printf("oldval: %s defval: %s\n", oldval, defval); + if (strcmp(oldval, defval) != 0) { + printf("## Error: Can't overwrite \"%s\"\n", + name); + return 1; + } + } + break; + case env_op_create: + if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) { + printf("## Error: Can't create \"%s\"\n", name); + return 1; + } + break; + } + + return 0; +} + +#endif diff --git a/common/env_flash.c b/common/env_flash.c index aa970d4400..e07d336a48 100644 --- a/common/env_flash.c +++ b/common/env_flash.c @@ -142,7 +142,7 @@ int saveenv(void) goto done; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; @@ -275,7 +275,7 @@ int saveenv(void) goto done; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; diff --git a/common/env_mmc.c b/common/env_mmc.c index a2ff90bf48..ce21671210 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -130,7 +130,7 @@ int saveenv(void) } res = (char *)&env_new->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); ret = 1; diff --git a/common/env_nand.c b/common/env_nand.c index 79e8033705..22e72a20b0 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -186,7 +186,7 @@ int saveenv(void) return 1; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -239,7 +239,7 @@ int saveenv(void) return 1; res = (char *)&env_new->data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_nvram.c b/common/env_nvram.c index 6483db39d3..eab0e7be0e 100644 --- a/common/env_nvram.c +++ b/common/env_nvram.c @@ -90,7 +90,7 @@ int saveenv(void) int rcode = 0; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_onenand.c b/common/env_onenand.c index da35071251..faa903d2f0 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -95,7 +95,7 @@ int saveenv(void) }; res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; diff --git a/common/env_sf.c b/common/env_sf.c index bbd472fcf2..d9e9085461 100644 --- a/common/env_sf.c +++ b/common/env_sf.c @@ -79,7 +79,7 @@ int saveenv(void) } res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); return 1; @@ -277,7 +277,7 @@ int saveenv(void) } res = (char *)&env_new.data; - len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL); + len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL); if (len < 0) { error("Cannot export environment: errno = %d\n", errno); goto done; diff --git a/common/fdt_support.c b/common/fdt_support.c index 963ea90234..6b9fa0550f 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -1315,7 +1315,7 @@ int fdt_set_status_by_alias(void *fdt, const char* alias, return fdt_set_node_status(fdt, offset, status, error_code); } -#if defined(CONFIG_VIDEO) +#if defined(CONFIG_VIDEO) || defined(CONFIG_LCD) int fdt_add_edid(void *blob, const char *compat, unsigned char *edid_buf) { int noff; diff --git a/common/hash.c b/common/hash.c new file mode 100644 index 0000000000..e3a6e438a3 --- /dev/null +++ b/common/hash.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2011 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <hash.h> +#include <sha1.h> +#include <sha256.h> + +/* + * These are the hash algorithms we support. Chips which support accelerated + * crypto could perhaps add named version of these algorithms here. + */ +static struct hash_algo hash_algo[] = { +#ifdef CONFIG_SHA1 + { + "SHA1", + SHA1_SUM_LEN, + sha1_csum_wd, + CHUNKSZ_SHA1, + }, +#endif +#ifdef CONFIG_SHA256 + { + "SHA256", + SHA256_SUM_LEN, + sha256_csum_wd, + CHUNKSZ_SHA256, + }, +#endif +}; + +/** + * store_result: Store the resulting sum to an address or variable + * + * @algo: Hash algorithm being used + * @sum: Hash digest (algo->digest_size bytes) + * @dest: Destination, interpreted as a hex address if it starts + * with * or otherwise as an environment variable. + */ +static void store_result(struct hash_algo *algo, const u8 *sum, + const char *dest) +{ + unsigned int i; + + if (*dest == '*') { + u8 *ptr; + + ptr = (u8 *)simple_strtoul(dest + 1, NULL, 16); + memcpy(ptr, sum, algo->digest_size); + } else { + char str_output[HASH_MAX_DIGEST_SIZE * 2 + 1]; + char *str_ptr = str_output; + + for (i = 0; i < algo->digest_size; i++) { + sprintf(str_ptr, "%02x", sum[i]); + str_ptr += 2; + } + str_ptr = '\0'; + setenv(dest, str_output); + } +} + +/** + * parse_verify_sum: Parse a hash verification parameter + * + * @algo: Hash algorithm being used + * @verify_str: Argument to parse. If it starts with * then it is + * interpreted as a hex address containing the hash. + * If the length is exactly the right number of hex digits + * for the digest size, then we assume it is a hex digest. + * Otherwise we assume it is an environment variable, and + * look up its value (it must contain a hex digest). + * @vsum: Returns binary digest value (algo->digest_size bytes) + * @return 0 if ok, non-zero on error + */ +static int parse_verify_sum(struct hash_algo *algo, char *verify_str, u8 *vsum) +{ + if (*verify_str == '*') { + u8 *ptr; + + ptr = (u8 *)simple_strtoul(verify_str + 1, NULL, 16); + memcpy(vsum, ptr, algo->digest_size); + } else { + unsigned int i; + char *vsum_str; + int digits = algo->digest_size * 2; + + /* + * As with the original code from sha1sum.c, we assume that a + * string which matches the digest size exactly is a hex + * string and not an environment variable. + */ + if (strlen(verify_str) == digits) + vsum_str = verify_str; + else { + vsum_str = getenv(verify_str); + if (vsum_str == NULL || strlen(vsum_str) != digits) { + printf("Expected %d hex digits in env var\n", + digits); + return 1; + } + } + + for (i = 0; i < algo->digest_size; i++) { + char *nullp = vsum_str + (i + 1) * 2; + char end = *nullp; + + *nullp = '\0'; + vsum[i] = simple_strtoul(vsum_str + (i * 2), NULL, 16); + *nullp = end; + } + } + return 0; +} + +static struct hash_algo *find_hash_algo(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hash_algo); i++) { + if (!strcasecmp(name, hash_algo[i].name)) + return &hash_algo[i]; + } + + return NULL; +} + +static void show_hash(struct hash_algo *algo, ulong addr, ulong len, + u8 *output) +{ + int i; + + printf("%s for %08lx ... %08lx ==> ", algo->name, addr, addr + len - 1); + for (i = 0; i < algo->digest_size; i++) + printf("%02x", output[i]); +} + +int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + struct hash_algo *algo; + ulong addr, len; + u8 output[HASH_MAX_DIGEST_SIZE]; + u8 vsum[HASH_MAX_DIGEST_SIZE]; + + if (argc < 2) + return CMD_RET_USAGE; + + algo = find_hash_algo(algo_name); + if (!algo) { + printf("Unknown hash algorithm '%s'\n", algo_name); + return CMD_RET_USAGE; + } + addr = simple_strtoul(*argv++, NULL, 16); + len = simple_strtoul(*argv++, NULL, 16); + argc -= 2; + + if (algo->digest_size > HASH_MAX_DIGEST_SIZE) { + puts("HASH_MAX_DIGEST_SIZE exceeded\n"); + return 1; + } + + algo->hash_func_ws((const unsigned char *)addr, len, output, + algo->chunk_size); + + /* Try to avoid code bloat when verify is not needed */ +#ifdef CONFIG_HASH_VERIFY + if (verify) { +#else + if (0) { +#endif + if (!argc) + return CMD_RET_USAGE; + if (parse_verify_sum(algo, *argv, vsum)) { + printf("ERROR: %s does not contain a valid %s sum\n", + *argv, algo->name); + return 1; + } + if (memcmp(output, vsum, algo->digest_size) != 0) { + int i; + + show_hash(algo, addr, len, output); + printf(" != "); + for (i = 0; i < algo->digest_size; i++) + printf("%02x", vsum[i]); + puts(" ** ERROR **\n"); + return 1; + } + } else { + show_hash(algo, addr, len, output); + printf("\n"); + + if (argc) + store_result(algo, output, *argv); + } + + return 0; +} diff --git a/common/image.c b/common/image.c index e93b6e89cf..95498e6186 100644 --- a/common/image.c +++ b/common/image.c @@ -43,6 +43,7 @@ #include <rtc.h> #endif +#include <environment.h> #include <image.h> #if defined(CONFIG_FIT) || defined(CONFIG_OF_LIBFDT) @@ -416,11 +417,25 @@ static const image_header_t *image_get_ramdisk(ulong rd_addr, uint8_t arch, /* Shared dual-format routines */ /*****************************************************************************/ #ifndef USE_HOSTCC -int getenv_yesno(char *var) +ulong load_addr = CONFIG_SYS_LOAD_ADDR; /* Default Load Address */ +ulong save_addr; /* Default Save Address */ +ulong save_size; /* Default Save Size (in bytes) */ + +static int on_loadaddr(const char *name, const char *value, enum env_op op, + int flags) { - char *s = getenv(var); - return (s && (*s == 'n')) ? 0 : 1; + switch (op) { + case env_op_create: + case env_op_overwrite: + load_addr = simple_strtoul(value, NULL, 16); + break; + default: + break; + } + + return 0; } +U_BOOT_ENV_CALLBACK(loadaddr, on_loadaddr); ulong getenv_bootm_low(void) { diff --git a/common/main.c b/common/main.c index 5362781f18..b145f85565 100644 --- a/common/main.c +++ b/common/main.c @@ -376,6 +376,8 @@ void main_loop (void) char bcs_set[16]; #endif /* CONFIG_BOOTCOUNT_LIMIT */ + bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop"); + #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); bootcount++; diff --git a/common/stdio.c b/common/stdio.c index 9f48e5f503..97ff9cf4a6 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -135,7 +135,6 @@ struct stdio_dev* stdio_clone(struct stdio_dev *dev) return NULL; memcpy(_dev, dev, sizeof(struct stdio_dev)); - strncpy(_dev->name, dev->name, 16); return _dev; } diff --git a/disk/part_efi.c b/disk/part_efi.c index a3873cebb3..7665017330 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -34,9 +34,11 @@ #include <command.h> #include <ide.h> #include <malloc.h> -#include "part_efi.h" +#include <part_efi.h> #include <linux/ctype.h> +DECLARE_GLOBAL_DATA_PTR; + #if defined(CONFIG_CMD_IDE) || \ defined(CONFIG_CMD_SATA) || \ defined(CONFIG_CMD_SCSI) || \ @@ -44,34 +46,6 @@ defined(CONFIG_MMC) || \ defined(CONFIG_SYSTEMACE) -/* Convert char[2] in little endian format to the host format integer - */ -static inline unsigned short le16_to_int(unsigned char *le16) -{ - return ((le16[1] << 8) + le16[0]); -} - -/* Convert char[4] in little endian format to the host format integer - */ -static inline unsigned long le32_to_int(unsigned char *le32) -{ - return ((le32[3] << 24) + (le32[2] << 16) + (le32[1] << 8) + le32[0]); -} - -/* Convert char[8] in little endian format to the host format integer - */ -static inline unsigned long long le64_to_int(unsigned char *le64) -{ - return (((unsigned long long)le64[7] << 56) + - ((unsigned long long)le64[6] << 48) + - ((unsigned long long)le64[5] << 40) + - ((unsigned long long)le64[4] << 32) + - ((unsigned long long)le64[3] << 24) + - ((unsigned long long)le64[2] << 16) + - ((unsigned long long)le64[1] << 8) + - (unsigned long long)le64[0]); -} - /** * efi_crc32() - EFI version of crc32 function * @buf: buffer to calculate crc32 of @@ -79,7 +53,7 @@ static inline unsigned long long le64_to_int(unsigned char *le64) * * Description: Returns EFI-style CRC32 value for @buf */ -static inline unsigned long efi_crc32(const void *buf, unsigned long len) +static inline u32 efi_crc32(const void *buf, u32 len) { return crc32(0, buf, len); } @@ -90,13 +64,10 @@ static inline unsigned long efi_crc32(const void *buf, unsigned long len) static int pmbr_part_valid(struct partition *part); static int is_pmbr_valid(legacy_mbr * mbr); - static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba, gpt_header * pgpt_head, gpt_entry ** pgpt_pte); - static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc, gpt_header * pgpt_head); - static int is_pte_valid(gpt_entry * pte); static char *print_efiname(gpt_entry *pte) @@ -142,6 +113,7 @@ static inline int is_bootable(gpt_entry *p) sizeof(efi_guid_t)); } +#ifdef CONFIG_EFI_PARTITION /* * Public Functions (include/part.h) */ @@ -171,14 +143,14 @@ void print_part_efi(block_dev_desc_t * dev_desc) printf("\tType UUID\n"); printf("\tPartition UUID\n"); - for (i = 0; i < le32_to_int(gpt_head->num_partition_entries); i++) { + for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) { /* Stop at the first non valid PTE */ if (!is_pte_valid(&gpt_pte[i])) break; printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1), - le64_to_int(gpt_pte[i].starting_lba), - le64_to_int(gpt_pte[i].ending_lba), + le64_to_cpu(gpt_pte[i].starting_lba), + le64_to_cpu(gpt_pte[i].ending_lba), print_efiname(&gpt_pte[i])); printf("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw); uuid_string(gpt_pte[i].partition_type_guid.b, uuid); @@ -211,7 +183,7 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part, return -1; } - if (part > le32_to_int(gpt_head->num_partition_entries) || + if (part > le32_to_cpu(gpt_head->num_partition_entries) || !is_pte_valid(&gpt_pte[part - 1])) { printf("%s: *** ERROR: Invalid partition number %d ***\n", __func__, part); @@ -219,9 +191,9 @@ int get_partition_info_efi(block_dev_desc_t * dev_desc, int part, } /* The ulong casting limits the maximum disk size to 2 TB */ - info->start = (ulong) le64_to_int(gpt_pte[part - 1].starting_lba); + info->start = (u64)le64_to_cpu(gpt_pte[part - 1].starting_lba); /* The ending LBA is inclusive, to calculate size, add 1 to it */ - info->size = ((ulong)le64_to_int(gpt_pte[part - 1].ending_lba) + 1) + info->size = ((u64)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1) - info->start; info->blksz = GPT_BLOCK_SIZE; @@ -253,6 +225,281 @@ int test_part_efi(block_dev_desc_t * dev_desc) return 0; } +/** + * set_protective_mbr(): Set the EFI protective MBR + * @param dev_desc - block device descriptor + * + * @return - zero on success, otherwise error + */ +static int set_protective_mbr(block_dev_desc_t *dev_desc) +{ + legacy_mbr *p_mbr; + + /* Setup the Protective MBR */ + p_mbr = calloc(1, sizeof(p_mbr)); + if (p_mbr == NULL) { + printf("%s: calloc failed!\n", __func__); + return -1; + } + /* Append signature */ + p_mbr->signature = MSDOS_MBR_SIGNATURE; + p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT; + p_mbr->partition_record[0].start_sect = 1; + p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba; + + /* Write MBR sector to the MMC device */ + if (dev_desc->block_write(dev_desc->dev, 0, 1, p_mbr) != 1) { + printf("** Can't write to device %d **\n", + dev_desc->dev); + free(p_mbr); + return -1; + } + + free(p_mbr); + return 0; +} + +/** + * string_uuid(); Convert UUID stored as string to bytes + * + * @param uuid - UUID represented as string + * @param dst - GUID buffer + * + * @return return 0 on successful conversion + */ +static int string_uuid(char *uuid, u8 *dst) +{ + efi_guid_t guid; + u16 b, c, d; + u64 e; + u32 a; + u8 *p; + u8 i; + + const u8 uuid_str_len = 36; + + /* The UUID is written in text: */ + /* 1 9 14 19 24 */ + /* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */ + + debug("%s: uuid: %s\n", __func__, uuid); + + if (strlen(uuid) != uuid_str_len) + return -1; + + for (i = 0; i < uuid_str_len; i++) { + if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { + if (uuid[i] != '-') + return -1; + } else { + if (!isxdigit(uuid[i])) + return -1; + } + } + + a = (u32)simple_strtoul(uuid, NULL, 16); + b = (u16)simple_strtoul(uuid + 9, NULL, 16); + c = (u16)simple_strtoul(uuid + 14, NULL, 16); + d = (u16)simple_strtoul(uuid + 19, NULL, 16); + e = (u64)simple_strtoull(uuid + 24, NULL, 16); + + p = (u8 *) &e; + guid = EFI_GUID(a, b, c, d >> 8, d & 0xFF, + *(p + 5), *(p + 4), *(p + 3), + *(p + 2), *(p + 1) , *p); + + memcpy(dst, guid.b, sizeof(efi_guid_t)); + + return 0; +} + +int write_gpt_table(block_dev_desc_t *dev_desc, + gpt_header *gpt_h, gpt_entry *gpt_e) +{ + const int pte_blk_num = (gpt_h->num_partition_entries + * sizeof(gpt_entry)) / dev_desc->blksz; + + u32 calc_crc32; + u64 val; + + debug("max lba: %x\n", (u32) dev_desc->lba); + /* Setup the Protective MBR */ + if (set_protective_mbr(dev_desc) < 0) + goto err; + + /* Generate CRC for the Primary GPT Header */ + calc_crc32 = efi_crc32((const unsigned char *)gpt_e, + le32_to_cpu(gpt_h->num_partition_entries) * + le32_to_cpu(gpt_h->sizeof_partition_entry)); + gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32); + + calc_crc32 = efi_crc32((const unsigned char *)gpt_h, + le32_to_cpu(gpt_h->header_size)); + gpt_h->header_crc32 = cpu_to_le32(calc_crc32); + + /* Write the First GPT to the block right after the Legacy MBR */ + if (dev_desc->block_write(dev_desc->dev, 1, 1, gpt_h) != 1) + goto err; + + if (dev_desc->block_write(dev_desc->dev, 2, pte_blk_num, gpt_e) + != pte_blk_num) + goto err; + + /* recalculate the values for the Second GPT Header */ + val = le64_to_cpu(gpt_h->my_lba); + gpt_h->my_lba = gpt_h->alternate_lba; + gpt_h->alternate_lba = cpu_to_le64(val); + gpt_h->header_crc32 = 0; + + calc_crc32 = efi_crc32((const unsigned char *)gpt_h, + le32_to_cpu(gpt_h->header_size)); + gpt_h->header_crc32 = cpu_to_le32(calc_crc32); + + if (dev_desc->block_write(dev_desc->dev, + le32_to_cpu(gpt_h->last_usable_lba + 1), + pte_blk_num, gpt_e) != pte_blk_num) + goto err; + + if (dev_desc->block_write(dev_desc->dev, + le32_to_cpu(gpt_h->my_lba), 1, gpt_h) != 1) + goto err; + + debug("GPT successfully written to block device!\n"); + return 0; + + err: + printf("** Can't write to device %d **\n", dev_desc->dev); + return -1; +} + +int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, + disk_partition_t *partitions, int parts) +{ + u32 offset = (u32)le32_to_cpu(gpt_h->first_usable_lba); + ulong start; + int i, k; + size_t name_len; +#ifdef CONFIG_PARTITION_UUIDS + char *str_uuid; +#endif + + for (i = 0; i < parts; i++) { + /* partition starting lba */ + start = partitions[i].start; + if (start && (start < offset)) { + printf("Partition overlap\n"); + return -1; + } + if (start) { + gpt_e[i].starting_lba = cpu_to_le64(start); + offset = start + partitions[i].size; + } else { + gpt_e[i].starting_lba = cpu_to_le64(offset); + offset += partitions[i].size; + } + if (offset >= gpt_h->last_usable_lba) { + printf("Partitions layout exceds disk size\n"); + return -1; + } + /* partition ending lba */ + if ((i == parts - 1) && (partitions[i].size == 0)) + /* extend the last partition to maximuim */ + gpt_e[i].ending_lba = gpt_h->last_usable_lba; + else + gpt_e[i].ending_lba = cpu_to_le64(offset - 1); + + /* partition type GUID */ + memcpy(gpt_e[i].partition_type_guid.b, + &PARTITION_BASIC_DATA_GUID, 16); + +#ifdef CONFIG_PARTITION_UUIDS + str_uuid = partitions[i].uuid; + if (string_uuid(str_uuid, gpt_e[i].unique_partition_guid.b)) { + printf("Partition no. %d: invalid guid: %s\n", + i, str_uuid); + return -1; + } +#endif + + /* partition attributes */ + memset(&gpt_e[i].attributes, 0, + sizeof(gpt_entry_attributes)); + + /* partition name */ + name_len = sizeof(gpt_e[i].partition_name) + / sizeof(efi_char16_t); + for (k = 0; k < name_len; k++) + gpt_e[i].partition_name[k] = + (efi_char16_t)(partitions[i].name[k]); + + debug("%s: name: %s offset[%d]: 0x%x size[%d]: 0x%lx\n", + __func__, partitions[i].name, i, + offset, i, partitions[i].size); + } + + return 0; +} + +int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h, + char *str_guid, int parts_count) +{ + gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE); + gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1); + gpt_h->header_size = cpu_to_le32(sizeof(gpt_header)); + gpt_h->my_lba = cpu_to_le64(1); + gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1); + gpt_h->first_usable_lba = cpu_to_le64(34); + gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34); + gpt_h->partition_entry_lba = cpu_to_le64(2); + gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS); + gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry)); + gpt_h->header_crc32 = 0; + gpt_h->partition_entry_array_crc32 = 0; + + if (string_uuid(str_guid, gpt_h->disk_guid.b)) + return -1; + + return 0; +} + +int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid, + disk_partition_t *partitions, int parts_count) +{ + int ret; + + gpt_header *gpt_h = calloc(1, sizeof(gpt_header)); + if (gpt_h == NULL) { + printf("%s: calloc failed!\n", __func__); + return -1; + } + + gpt_entry *gpt_e = calloc(GPT_ENTRY_NUMBERS, sizeof(gpt_entry)); + if (gpt_e == NULL) { + printf("%s: calloc failed!\n", __func__); + free(gpt_h); + return -1; + } + + /* Generate Primary GPT header (LBA1) */ + ret = gpt_fill_header(dev_desc, gpt_h, str_disk_guid, parts_count); + if (ret) + goto err; + + /* Generate partition entries */ + ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count); + if (ret) + goto err; + + /* Write GPT partition table */ + ret = write_gpt_table(dev_desc, gpt_h, gpt_e); + +err: + free(gpt_e); + free(gpt_h); + return ret; +} +#endif + /* * Private functions */ @@ -264,7 +511,7 @@ int test_part_efi(block_dev_desc_t * dev_desc) static int pmbr_part_valid(struct partition *part) { if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT && - le32_to_int(part->start_sect) == 1UL) { + le32_to_cpu(part->start_sect) == 1UL) { return 1; } @@ -283,9 +530,8 @@ static int is_pmbr_valid(legacy_mbr * mbr) { int i = 0; - if (!mbr || le16_to_int(mbr->signature) != MSDOS_MBR_SIGNATURE) { + if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) return 0; - } for (i = 0; i < 4; i++) { if (pmbr_part_valid(&mbr->partition_record[i])) { @@ -308,8 +554,8 @@ static int is_pmbr_valid(legacy_mbr * mbr) static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba, gpt_header * pgpt_head, gpt_entry ** pgpt_pte) { - unsigned char crc32_backup[4] = { 0 }; - unsigned long calc_crc32; + u32 crc32_backup = 0; + u32 calc_crc32; unsigned long long lastlba; if (!dev_desc || !pgpt_head) { @@ -324,54 +570,54 @@ static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba, } /* Check the GPT header signature */ - if (le64_to_int(pgpt_head->signature) != GPT_HEADER_SIGNATURE) { + if (le64_to_cpu(pgpt_head->signature) != GPT_HEADER_SIGNATURE) { printf("GUID Partition Table Header signature is wrong:" "0x%llX != 0x%llX\n", - (unsigned long long)le64_to_int(pgpt_head->signature), - (unsigned long long)GPT_HEADER_SIGNATURE); + le64_to_cpu(pgpt_head->signature), + GPT_HEADER_SIGNATURE); return 0; } /* Check the GUID Partition Table CRC */ - memcpy(crc32_backup, pgpt_head->header_crc32, sizeof(crc32_backup)); - memset(pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32)); + memcpy(&crc32_backup, &pgpt_head->header_crc32, sizeof(crc32_backup)); + memset(&pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32)); calc_crc32 = efi_crc32((const unsigned char *)pgpt_head, - le32_to_int(pgpt_head->header_size)); + le32_to_cpu(pgpt_head->header_size)); - memcpy(pgpt_head->header_crc32, crc32_backup, sizeof(crc32_backup)); + memcpy(&pgpt_head->header_crc32, &crc32_backup, sizeof(crc32_backup)); - if (calc_crc32 != le32_to_int(crc32_backup)) { + if (calc_crc32 != le32_to_cpu(crc32_backup)) { printf("GUID Partition Table Header CRC is wrong:" - "0x%08lX != 0x%08lX\n", - le32_to_int(crc32_backup), calc_crc32); + "0x%x != 0x%x\n", + le32_to_cpu(crc32_backup), calc_crc32); return 0; } /* Check that the my_lba entry points to the LBA that contains the GPT */ - if (le64_to_int(pgpt_head->my_lba) != lba) { + if (le64_to_cpu(pgpt_head->my_lba) != lba) { printf("GPT: my_lba incorrect: %llX != %llX\n", - (unsigned long long)le64_to_int(pgpt_head->my_lba), - (unsigned long long)lba); + le64_to_cpu(pgpt_head->my_lba), + lba); return 0; } /* Check the first_usable_lba and last_usable_lba are within the disk. */ lastlba = (unsigned long long)dev_desc->lba; - if (le64_to_int(pgpt_head->first_usable_lba) > lastlba) { + if (le64_to_cpu(pgpt_head->first_usable_lba) > lastlba) { printf("GPT: first_usable_lba incorrect: %llX > %llX\n", - le64_to_int(pgpt_head->first_usable_lba), lastlba); + le64_to_cpu(pgpt_head->first_usable_lba), lastlba); return 0; } - if (le64_to_int(pgpt_head->last_usable_lba) > lastlba) { + if (le64_to_cpu(pgpt_head->last_usable_lba) > lastlba) { printf("GPT: last_usable_lba incorrect: %llX > %llX\n", - le64_to_int(pgpt_head->last_usable_lba), lastlba); + (u64) le64_to_cpu(pgpt_head->last_usable_lba), lastlba); return 0; } debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n", - le64_to_int(pgpt_head->first_usable_lba), - le64_to_int(pgpt_head->last_usable_lba), lastlba); + le64_to_cpu(pgpt_head->first_usable_lba), + le64_to_cpu(pgpt_head->last_usable_lba), lastlba); /* Read and allocate Partition Table Entries */ *pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head); @@ -382,13 +628,13 @@ static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba, /* Check the GUID Partition Table Entry Array CRC */ calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte, - le32_to_int(pgpt_head->num_partition_entries) * - le32_to_int(pgpt_head->sizeof_partition_entry)); + le32_to_cpu(pgpt_head->num_partition_entries) * + le32_to_cpu(pgpt_head->sizeof_partition_entry)); - if (calc_crc32 != le32_to_int(pgpt_head->partition_entry_array_crc32)) { + if (calc_crc32 != le32_to_cpu(pgpt_head->partition_entry_array_crc32)) { printf("GUID Partition Table Entry Array CRC is wrong:" - "0x%08lX != 0x%08lX\n", - le32_to_int(pgpt_head->partition_entry_array_crc32), + "0x%x != 0x%x\n", + le32_to_cpu(pgpt_head->partition_entry_array_crc32), calc_crc32); free(*pgpt_pte); @@ -419,12 +665,12 @@ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc, return NULL; } - count = le32_to_int(pgpt_head->num_partition_entries) * - le32_to_int(pgpt_head->sizeof_partition_entry); + count = le32_to_cpu(pgpt_head->num_partition_entries) * + le32_to_cpu(pgpt_head->sizeof_partition_entry); - debug("%s: count = %lu * %lu = %zu\n", __func__, - le32_to_int(pgpt_head->num_partition_entries), - le32_to_int(pgpt_head->sizeof_partition_entry), count); + debug("%s: count = %u * %u = %zu\n", __func__, + (u32) le32_to_cpu(pgpt_head->num_partition_entries), + (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count); /* Allocate memory for PTE, remember to FREE */ if (count != 0) { @@ -440,7 +686,7 @@ static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc, /* Read GPT Entries from device */ if (dev_desc->block_read (dev_desc->dev, - (unsigned long)le64_to_int(pgpt_head->partition_entry_lba), + le64_to_cpu(pgpt_head->partition_entry_lba), (lbaint_t) (count / GPT_BLOCK_SIZE), pte) != (count / GPT_BLOCK_SIZE)) { diff --git a/doc/README.gpt b/doc/README.gpt new file mode 100644 index 0000000000..a9c58b4c96 --- /dev/null +++ b/doc/README.gpt @@ -0,0 +1,201 @@ +# +# Copyright (C) 2012 Samsung Electronics +# +# Lukasz Majewski <l.majewski@samsung.com> +# +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA + + +Glossary: +======== +- UUID -(Universally Unique Identifier) +- GUID - (Globally Unique ID) +- EFI - (Extensible Firmware Interface) +- UEFI - (Unified EFI) - EFI evolution +- GPT (GUID Partition Table) - it is the EFI standard part +- partitions - lists of available partitions (defined at u-boot): + ./include/configs/{target}.h + +Introduction: +============= +This document describes the GPT partition table format and usage of +the gpt command in u-boot. + + +UUID introduction: +==================== + +GPT for marking disks/partitions is using the UUID. It is supposed to be a +globally unique value. A UUID is a 16-byte (128-bit) number. The number of +theoretically possible UUIDs is therefore about 3 x 10^38. +More often UUID is displayed as 32 hexadecimal digits, in 5 groups, +separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters +(32 digits and 4 hyphens) + +For instance, GUID of Linux data partition: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 + +Historically there are 5 methods to generate this number. The oldest one is +combining machine's MAC address and timer (epoch) value. + +Successive versions are using MD5 hash, random numbers and SHA-1 hash. All major +OSes and programming languages are providing libraries to compute UUID (e.g. +uuid command line tool). + +GPT brief explanation: +====================== + + Layout: + ------- + + -------------------------------------------------- + LBA 0 |Protective MBR | + ---------------------------------------------------------- + LBA 1 |Primary GPT Header | Primary + -------------------------------------------------- GPT + LBA 2 |Entry 1|Entry 2| Entry 3| Entry 4| + -------------------------------------------------- + LBA 3 |Entries 5 - 128 | + | | + | | + ---------------------------------------------------------- + LBA 34 |Partition 1 | + | | + ----------------------------------- + |Partition 2 | + | | + ----------------------------------- + |Partition n | + | | + ---------------------------------------------------------- + LBA -34 |Entry 1|Entry 2| Entry 3| Entry 4| Secondary + -------------------------------------------------- (bkp) + LBA -33 |Entries 5 - 128 | GPT + | | + | | + LBA -2 | | + -------------------------------------------------- + LBA -1 |Secondary GPT Header | + ---------------------------------------------------------- + + +For a legacy reasons, GPT's LBA 0 sector has a MBR structure. It is called +"protective MBR". +Its first partition entry ID has 0xEE value, and disk software, which is not +handling the GPT sees it as a storage device without free space. + +It is possible to define 128 linearly placed partition entries. + +"LBA -1" means the last addressable block (in the mmc subsystem: +"dev_desc->lba - 1") + +Primary/Secondary GPT header: +---------------------------- +Offset Size Description + +0 8 B Signature ("EFI PART", 45 46 49 20 50 41 52 54) +8 4 B Revision (For version 1.0, the value is 00 00 01 00) +12 4 B Header size (in bytes, usually 5C 00 00 00 meaning 92 bytes) +16 4 B CRC32 of header (0 to header size), with this field zeroed + during calculation +20 4 B Reserved (ZERO); +24 8 B Current LBA (location of this header copy) +32 8 B Backup LBA (location of the other header copy) +40 8 B First usable LBA for partitions (primary partition table last + LBA + 1) +48 8 B Last usable LBA (secondary partition table first LBA - 1) +56 16 B Disk GUID (also referred as UUID on UNIXes) +72 8 B Partition entries starting LBA (always 2 in primary copy) +80 4 B Number of partition entries +84 4 B Size of a partition entry (usually 128) +88 4 B CRC32 of partition array +92 * Reserved; must be ZERO (420 bytes for a 512-byte LBA) + +TOTAL: 512 B + + + +IMPORTANT: + +GPT headers and partition entries are protected by CRC32 (the POSIX CRC32). + +Primary GPT header and Secondary GPT header have swapped values of "Current LBA" +and "Backup LBA" and therefore different CRC32 check-sum. + +CRC32 for GPT headers (field "CRC of header") are calculated up till +"Header size" (92), NOT 512 bytes. + +CRC32 for partition entries (field "CRC32 of partition array") is calculated for +the whole array entry ( Number_of_partition_entries * +sizeof(partition_entry_size (usually 128))) + +Observe, how Secondary GPT is placed in the memory. It is NOT a mirror reflect +of the Primary. + + + Partition Entry Format: + ---------------------- + Offset Size Description + + 0 16 B Partition type GUID + 16 16 B Unique partition GUID + 32 8 B First LBA (Little Endian) + 40 8 B Last LBA (inclusive) + 48 8 B Attribute flags [+] + 56 72 B Partition name (text) + + Attribute flags: + Bit 0 - System partition + Bit 60 - Read-only + Bit 62 - Hidden + Bit 63 - Not mount + + +Creating GPT partitions in U-Boot: +============== + +To restore GUID partition table one needs to: +1. Define partition layout in the environment. + Format of partitions layout: + "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...; + name=kernel,size=60MiB,uuid=...;" + or + "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name}, + size=${uboot_size},uuid=${uboot_uuid};" + + Fields 'name', 'size' and 'uuid' are mandatory for every partition. + The field 'start' is optional. + +2. Define 'CONFIG_EFI_PARTITION' and 'CONFIG_CMD_GPT' + +2. From u-boot prompt type: + gpt write mmc 0 $partitions + + +Useful info: +============ + +Two programs, namely: 'fdisk' and 'parted' are recommended to work with GPT +recovery. Parted is able to handle GUID partitions. Unfortunately the 'fdisk' +hasn't got such ability. +Please, pay attention at -l switch for parted. + +"uuid" program is recommended to generate UUID string. Moreover it can decode +(-d switch) passed in UUID string. It can be used to generate partitions UUID +passed to u-boot environment variables. diff --git a/doc/README.silent b/doc/README.silent index a26e3df0da..70202cece9 100644 --- a/doc/README.silent +++ b/doc/README.silent @@ -1,9 +1,15 @@ The config option CONFIG_SILENT_CONSOLE can be used to quiet messages on the console. If the option has been enabled, the output can be -silenced by setting the environment variable "silent". The variable -is latched into the global data at an early stage in the boot process -so deleting it with "setenv" will not take effect until the system is -restarted. +silenced by setting the environment variable "silent". + +- CONFIG_SILENT_CONSOLE_UPDATE_ON_SET + When the "silent" variable is changed with env set, the change + will take effect immediately. + +- CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC + Some environments are not available until relocation (e.g. NAND) + so this will make the value in the flash env take effect at + relocation. The following actions are taken if "silent" is set at boot time: diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index bf64a2a643..665387091a 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -26,7 +26,12 @@ #include <asm/arch/hardware.h> #include "designware_i2c.h" -static struct i2c_regs *const i2c_regs_p = +#ifdef CONFIG_I2C_MULTI_BUS +static unsigned int bus_initialized[CONFIG_SYS_I2C_BUS_MAX]; +static unsigned int current_bus = 0; +#endif + +static struct i2c_regs *i2c_regs_p = (struct i2c_regs *)CONFIG_SYS_I2C_BASE; /* @@ -39,7 +44,6 @@ static void set_speed(int i2c_spd) { unsigned int cntl; unsigned int hcnt, lcnt; - unsigned int high, low; unsigned int enbl; /* to set speed cltr must be disabled */ @@ -47,39 +51,38 @@ static void set_speed(int i2c_spd) enbl &= ~IC_ENABLE_0B; writel(enbl, &i2c_regs_p->ic_enable); - cntl = (readl(&i2c_regs_p->ic_con) & (~IC_CON_SPD_MSK)); switch (i2c_spd) { case IC_SPEED_MODE_MAX: cntl |= IC_CON_SPD_HS; - high = MIN_HS_SCL_HIGHTIME; - low = MIN_HS_SCL_LOWTIME; + hcnt = (IC_CLK * MIN_HS_SCL_HIGHTIME) / NANO_TO_MICRO; + writel(hcnt, &i2c_regs_p->ic_hs_scl_hcnt); + lcnt = (IC_CLK * MIN_HS_SCL_LOWTIME) / NANO_TO_MICRO; + writel(lcnt, &i2c_regs_p->ic_hs_scl_lcnt); break; case IC_SPEED_MODE_STANDARD: cntl |= IC_CON_SPD_SS; - high = MIN_SS_SCL_HIGHTIME; - low = MIN_SS_SCL_LOWTIME; + hcnt = (IC_CLK * MIN_SS_SCL_HIGHTIME) / NANO_TO_MICRO; + writel(hcnt, &i2c_regs_p->ic_ss_scl_hcnt); + lcnt = (IC_CLK * MIN_SS_SCL_LOWTIME) / NANO_TO_MICRO; + writel(lcnt, &i2c_regs_p->ic_ss_scl_lcnt); break; case IC_SPEED_MODE_FAST: default: cntl |= IC_CON_SPD_FS; - high = MIN_FS_SCL_HIGHTIME; - low = MIN_FS_SCL_LOWTIME; + hcnt = (IC_CLK * MIN_FS_SCL_HIGHTIME) / NANO_TO_MICRO; + writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); + lcnt = (IC_CLK * MIN_FS_SCL_LOWTIME) / NANO_TO_MICRO; + writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); break; } writel(cntl, &i2c_regs_p->ic_con); - hcnt = (IC_CLK * high) / NANO_TO_MICRO; - writel(hcnt, &i2c_regs_p->ic_fs_scl_hcnt); - - lcnt = (IC_CLK * low) / NANO_TO_MICRO; - writel(lcnt, &i2c_regs_p->ic_fs_scl_lcnt); - - /* re-enable i2c ctrl back now that speed is set */ + /* Enable back i2c now speed set */ enbl |= IC_ENABLE_0B; writel(enbl, &i2c_regs_p->ic_enable); } @@ -150,6 +153,10 @@ void i2c_init(int speed, int slaveadd) enbl = readl(&i2c_regs_p->ic_enable); enbl |= IC_ENABLE_0B; writel(enbl, &i2c_regs_p->ic_enable); + +#ifdef CONFIG_I2C_MULTI_BUS + bus_initialized[current_bus] = 1; +#endif } /* @@ -274,7 +281,10 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) start_time_rx = get_timer(0); while (len) { - writel(IC_CMD, &i2c_regs_p->ic_cmd_data); + if (len == 1) + writel(IC_CMD | IC_STOP, &i2c_regs_p->ic_cmd_data); + else + writel(IC_CMD, &i2c_regs_p->ic_cmd_data); if (readl(&i2c_regs_p->ic_status) & IC_STATUS_RFNE) { *buffer++ = (uchar)readl(&i2c_regs_p->ic_cmd_data); @@ -313,9 +323,11 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) start_time_tx = get_timer(0); while (len) { if (readl(&i2c_regs_p->ic_status) & IC_STATUS_TFNF) { - writel(*buffer, &i2c_regs_p->ic_cmd_data); + if (--len == 0) + writel(*buffer | IC_STOP, &i2c_regs_p->ic_cmd_data); + else + writel(*buffer, &i2c_regs_p->ic_cmd_data); buffer++; - len--; start_time_tx = get_timer(0); } else if (get_timer(start_time_tx) > (nb * I2C_BYTE_TO)) { @@ -344,3 +356,74 @@ int i2c_probe(uchar chip) return ret; } + +#ifdef CONFIG_I2C_MULTI_BUS +int i2c_set_bus_num(unsigned int bus) +{ + switch (bus) { + case 0: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE; + break; +#ifdef CONFIG_SYS_I2C_BASE1 + case 1: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE1; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE2 + case 2: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE2; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE3 + case 3: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE3; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE4 + case 4: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE4; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE5 + case 5: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE5; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE6 + case 6: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE6; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE7 + case 7: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE7; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE8 + case 8: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE8; + break; +#endif +#ifdef CONFIG_SYS_I2C_BASE9 + case 9: + i2c_regs_p = (void *)CONFIG_SYS_I2C_BASE9; + break; +#endif + default: + printf("Bad bus: %d\n", bus); + return -1; + } + + current_bus = bus; + + if (!bus_initialized[current_bus]) + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + return 0; +} + +int i2c_get_bus_num(void) +{ + return current_bus; +} +#endif diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h index 03b520ed43..2faf4a8717 100644 --- a/drivers/i2c/designware_i2c.h +++ b/drivers/i2c/designware_i2c.h @@ -60,14 +60,16 @@ struct i2c_regs { u32 ic_tx_abrt_source; }; +#if !defined(IC_CLK) #define IC_CLK 166 +#endif #define NANO_TO_MICRO 1000 /* High and low times in different speed modes (in ns) */ #define MIN_SS_SCL_HIGHTIME 4000 -#define MIN_SS_SCL_LOWTIME 5000 -#define MIN_FS_SCL_HIGHTIME 800 -#define MIN_FS_SCL_LOWTIME 1700 +#define MIN_SS_SCL_LOWTIME 4700 +#define MIN_FS_SCL_HIGHTIME 600 +#define MIN_FS_SCL_LOWTIME 1300 #define MIN_HS_SCL_HIGHTIME 60 #define MIN_HS_SCL_LOWTIME 160 @@ -95,6 +97,7 @@ struct i2c_regs { /* i2c data buffer and command register definitions */ #define IC_CMD 0x0100 +#define IC_STOP 0x0200 /* i2c interrupt status register definitions */ #define IC_GEN_CALL 0x0800 diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 18270b9de6..a73b10b9c4 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -115,7 +115,7 @@ static uint8_t i2c_imx_get_clk(unsigned int rate) /* * Set I2C Bus speed */ -int bus_i2c_set_bus_speed(void *base, int speed) +static int bus_i2c_set_bus_speed(void *base, int speed) { struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; u8 clk_idx = i2c_imx_get_clk(speed); @@ -133,7 +133,7 @@ int bus_i2c_set_bus_speed(void *base, int speed) /* * Get I2C Speed */ -unsigned int bus_i2c_get_bus_speed(void *base) +static unsigned int bus_i2c_get_bus_speed(void *base) { struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)base; u8 clk_idx = readb(&i2c_regs->ifdr); diff --git a/drivers/i2c/mxs_i2c.c b/drivers/i2c/mxs_i2c.c index 2a193c220d..b907f7b379 100644 --- a/drivers/i2c/mxs_i2c.c +++ b/drivers/i2c/mxs_i2c.c @@ -28,6 +28,7 @@ #include <common.h> #include <malloc.h> +#include <i2c.h> #include <asm/errno.h> #include <asm/io.h> #include <asm/arch/clock.h> @@ -40,6 +41,7 @@ void mxs_i2c_reset(void) { struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; int ret; + int speed = i2c_get_bus_speed(); ret = mxs_reset_block(&i2c_regs->hw_i2c_ctrl0_reg); if (ret) { @@ -53,6 +55,8 @@ void mxs_i2c_reset(void) &i2c_regs->hw_i2c_ctrl1_clr); writel(I2C_QUEUECTRL_PIO_QUEUE_MODE, &i2c_regs->hw_i2c_queuectrl_set); + + i2c_set_bus_speed(speed); } void mxs_i2c_setup_read(uint8_t chip, int len) @@ -210,37 +214,65 @@ int i2c_probe(uchar chip) return ret; } -void i2c_init(int speed, int slaveadd) +int i2c_set_bus_speed(unsigned int speed) { struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; + /* + * The timing derivation algorithm. There is no documentation for this + * algorithm available, it was derived by using the scope and fiddling + * with constants until the result observed on the scope was good enough + * for 20kHz, 50kHz, 100kHz, 200kHz, 300kHz and 400kHz. It should be + * possible to assume the algorithm works for other frequencies as well. + * + * Note it was necessary to cap the frequency on both ends as it's not + * possible to configure completely arbitrary frequency for the I2C bus + * clock. + */ + uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); + uint32_t base = ((clk / speed) - 38) / 2; + uint16_t high_count = base + 3; + uint16_t low_count = base - 3; + uint16_t rcv_count = (high_count * 3) / 4; + uint16_t xmit_count = low_count / 4; + + if (speed > 540000) { + printf("MXS I2C: Speed too high (%d Hz)\n", speed); + return -EINVAL; + } - mxs_i2c_reset(); - - switch (speed) { - case 100000: - writel((0x0078 << I2C_TIMING0_HIGH_COUNT_OFFSET) | - (0x0030 << I2C_TIMING0_RCV_COUNT_OFFSET), - &i2c_regs->hw_i2c_timing0); - writel((0x0080 << I2C_TIMING1_LOW_COUNT_OFFSET) | - (0x0030 << I2C_TIMING1_XMIT_COUNT_OFFSET), - &i2c_regs->hw_i2c_timing1); - break; - case 400000: - writel((0x000f << I2C_TIMING0_HIGH_COUNT_OFFSET) | - (0x0007 << I2C_TIMING0_RCV_COUNT_OFFSET), - &i2c_regs->hw_i2c_timing0); - writel((0x001f << I2C_TIMING1_LOW_COUNT_OFFSET) | - (0x000f << I2C_TIMING1_XMIT_COUNT_OFFSET), - &i2c_regs->hw_i2c_timing1); - break; - default: - printf("MXS I2C: Invalid speed selected (%d Hz)\n", speed); - return; + if (speed < 12000) { + printf("MXS I2C: Speed too low (%d Hz)\n", speed); + return -EINVAL; } - writel((0x0015 << I2C_TIMING2_BUS_FREE_OFFSET) | - (0x000d << I2C_TIMING2_LEADIN_COUNT_OFFSET), + writel((high_count << 16) | rcv_count, &i2c_regs->hw_i2c_timing0); + writel((low_count << 16) | xmit_count, &i2c_regs->hw_i2c_timing1); + + writel((0x0030 << I2C_TIMING2_BUS_FREE_OFFSET) | + (0x0030 << I2C_TIMING2_LEADIN_COUNT_OFFSET), &i2c_regs->hw_i2c_timing2); + return 0; +} + +unsigned int i2c_get_bus_speed(void) +{ + struct mxs_i2c_regs *i2c_regs = (struct mxs_i2c_regs *)MXS_I2C0_BASE; + uint32_t clk = mxc_get_clock(MXC_XTAL_CLK); + uint32_t timing0; + + timing0 = readl(&i2c_regs->hw_i2c_timing0); + /* + * This is a reverse version of the algorithm presented in + * i2c_set_bus_speed(). Please refer there for details. + */ + return clk / ((((timing0 >> 16) - 3) * 2) + 38); +} + +void i2c_init(int speed, int slaveadd) +{ + mxs_i2c_reset(); + i2c_set_bus_speed(speed); + return; } diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 094305fdf9..af454f901c 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -179,7 +179,8 @@ static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value) if (status & I2C_STAT_XRDY) { w = tmpbuf[i++]; #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX)) w |= tmpbuf[i++] << 8; #endif writew(w, &i2c_base->data); @@ -209,7 +210,8 @@ static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value) } if (status & I2C_STAT_RRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX) *value = readb(&i2c_base->data); #else *value = readw(&i2c_base->data); @@ -239,7 +241,8 @@ static void flush_fifo(void) stat = readw(&i2c_base->stat); if (stat == I2C_STAT_RRDY) { #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX) readb(&i2c_base->data); #else readw(&i2c_base->data); @@ -289,7 +292,8 @@ int i2c_probe(uchar chip) if (status & I2C_STAT_RRDY) { res = 0; #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX) readb(&i2c_base->data); #else readw(&i2c_base->data); @@ -376,7 +380,8 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) if (status & I2C_STAT_XRDY) { w = (i < 0) ? tmpbuf[2+i] : buffer[i]; #if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ - defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)) + defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \ + defined(CONFIG_OMAP54XX)) w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8; #endif writew(w, &i2c_base->data); diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 9bc4c7f1d1..90d297a284 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,7 +27,7 @@ */ #include <common.h> -#ifdef CONFIG_EXYNOS5 +#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) #include <asm/arch/clk.h> #include <asm/arch/cpu.h> #else @@ -62,7 +62,7 @@ static unsigned int g_current_bus; /* Stores Current I2C Bus */ -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) { struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); @@ -121,7 +121,12 @@ static void ReadWriteByte(struct s3c24x0_i2c *i2c) static struct s3c24x0_i2c *get_base_i2c(void) { -#ifdef CONFIG_EXYNOS5 +#ifdef CONFIG_EXYNOS4 + struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() + + (EXYNOS4_I2C_SPACING + * g_current_bus)); + return i2c; +#elif defined CONFIG_EXYNOS5 struct s3c24x0_i2c *i2c = (struct s3c24x0_i2c *)(samsung_get_base_i2c() + (EXYNOS5_I2C_SPACING * g_current_bus)); @@ -134,7 +139,7 @@ static struct s3c24x0_i2c *get_base_i2c(void) static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd) { ulong freq, pres = 16, div; -#ifdef CONFIG_EXYNOS5 +#if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) freq = get_i2c_clk(); #else freq = get_PCLK(); @@ -188,7 +193,7 @@ unsigned int i2c_get_bus_num(void) void i2c_init(int speed, int slaveadd) { struct s3c24x0_i2c *i2c; -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio(); #endif int i; @@ -204,7 +209,7 @@ void i2c_init(int speed, int slaveadd) i--; } -#ifndef CONFIG_EXYNOS5 +#if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) if ((readl(&i2c->iicstat) & I2CSTAT_BSY) || GetI2CSDA() == 0) { #ifdef CONFIG_S3C2410 ulong old_gpecon = readl(&gpio->gpecon); @@ -248,7 +253,7 @@ void i2c_init(int speed, int slaveadd) writel(old_gpecon, &gpio->pgcon); #endif } -#endif /* #ifndef CONFIG_EXYNOS5 */ +#endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */ i2c_ch_init(i2c, speed, slaveadd); } diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index 1595c0714a..ae3c57392b 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -30,6 +30,9 @@ #include <ioports.h> #include <asm/io.h> #endif +#if defined(CONFIG_AVR32) +#include <asm/arch/portmux.h> +#endif #if defined(CONFIG_AT91FAMILY) #include <asm/io.h> #include <asm/arch/hardware.h> diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index f5f43a6ddc..1f8955a0fd 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -22,6 +22,7 @@ */ #include <common.h> +#include <environment.h> #include <serial.h> #include <stdio_dev.h> #include <post.h> @@ -32,6 +33,11 @@ DECLARE_GLOBAL_DATA_PTR; static struct serial_device *serial_devices; static struct serial_device *serial_current; +/* + * Table with supported baudrates (defined in config_xyz.h) + */ +static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; +#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0])) /** * serial_null() - Void registration routine of a serial driver @@ -46,6 +52,70 @@ static void serial_null(void) } /** + * on_baudrate() - Update the actual baudrate when the env var changes + * + * This will check for a valid baudrate and only apply it if valid. + */ +static int on_baudrate(const char *name, const char *value, enum env_op op, + int flags) +{ + int i; + int baudrate; + + switch (op) { + case env_op_create: + case env_op_overwrite: + /* + * Switch to new baudrate if new baudrate is supported + */ + baudrate = simple_strtoul(value, NULL, 10); + + /* Not actually changing */ + if (gd->baudrate == baudrate) + return 0; + + for (i = 0; i < N_BAUDRATES; ++i) { + if (baudrate == baudrate_table[i]) + break; + } + if (i == N_BAUDRATES) { + if ((flags & H_FORCE) == 0) + printf("## Baudrate %d bps not supported\n", + baudrate); + return 1; + } + if ((flags & H_INTERACTIVE) != 0) { + printf("## Switch baudrate to %d" + " bps and press ENTER ...\n", baudrate); + udelay(50000); + } + + gd->baudrate = baudrate; +#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) + gd->bd->bi_baudrate = baudrate; +#endif + + serial_setbrg(); + + udelay(50000); + + if ((flags & H_INTERACTIVE) != 0) + while (1) { + if (getc() == '\r') + break; + } + + return 0; + case env_op_delete: + printf("## Baudrate may not be deleted\n"); + return 1; + default: + return 0; + } +} +U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); + +/** * serial_initfunc() - Forward declare of driver registration routine * @name: Name of the real driver registration routine. * diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 23c9649403..bfedbe4459 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -42,10 +42,11 @@ */ /** - * Request ownership of a GPIO. + * Request a gpio. This should be called before any of the other functions + * are used on this gpio. * - * @param gpio GPIO number - * @param label Name given to the GPIO + * @param gp GPIO number + * @param label User label for this GPIO * @return 0 if ok, -1 on error */ int gpio_request(unsigned gpio, const char *label); @@ -93,14 +94,4 @@ int gpio_get_value(unsigned gpio); * @return 0 if ok, -1 on error */ int gpio_set_value(unsigned gpio, int value); - -/** - * Request a gpio. This should be called before any of the other functions - * are used on this gpio. - * - * @param gp GPIO number - * @param label User label for this GPIO - * @return 0 if ok, -1 on error - */ -int gpio_request(unsigned gpio, const char *label); #endif /* _ASM_GENERIC_GPIO_H_ */ diff --git a/include/command.h b/include/command.h index 10bc2606c7..476e7cffc2 100644 --- a/include/command.h +++ b/include/command.h @@ -89,10 +89,10 @@ extern int cmd_auto_complete(const char *const prompt, char *buf, int *np, int * */ #if defined(CONFIG_CMD_MEMORY) \ - || defined(CONFIG_CMD_I2C) \ - || defined(CONFIG_CMD_ITEST) \ - || defined(CONFIG_CMD_PCI) \ - || defined(CONFIG_CMD_PORTIO) + || defined(CONFIG_CMD_I2C) \ + || defined(CONFIG_CMD_ITEST) \ + || defined(CONFIG_CMD_PCI) \ + || defined(CONFIG_CMD_PORTIO) #define CMD_DATA_SIZE extern int cmd_get_data_size(char* arg, int default_size); #endif diff --git a/include/common.h b/include/common.h index 5e3c5eeee1..d0bf1e8ab2 100644 --- a/include/common.h +++ b/include/common.h @@ -340,6 +340,11 @@ int envmatch (uchar *, int); char *getenv (const char *); int getenv_f (const char *name, char *buf, unsigned len); ulong getenv_ulong(const char *name, int base, ulong default_val); +/* + * Read an environment variable as a boolean + * Return -1 if variable does not exist (default to true) + */ +int getenv_yesno(const char *var); int saveenv (void); int setenv (const char *, const char *); int setenv_ulong(const char *varname, ulong value); diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h index f434cd0891..e82f6421c0 100644 --- a/include/config_cmd_all.h +++ b/include/config_cmd_all.h @@ -40,12 +40,15 @@ #define CONFIG_CMD_FDOS /* Floppy DOS support */ #define CONFIG_CMD_FLASH /* flinfo, erase, protect */ #define CONFIG_CMD_FPGA /* FPGA configuration Support */ +#define CONFIG_CMD_GETTIME /* Get time since boot */ +#define CONFIG_CMD_HASH /* calculate hash / digest */ #define CONFIG_CMD_HWFLOW /* RTS/CTS hw flow control */ #define CONFIG_CMD_I2C /* I2C serial bus support */ #define CONFIG_CMD_IDE /* IDE harddisk support */ #define CONFIG_CMD_IMI /* iminfo */ #define CONFIG_CMD_IMLS /* List all found images */ #define CONFIG_CMD_IMMAP /* IMMR dump support */ +#define CONFIG_CMD_IO /* Access to X86 IO space */ #define CONFIG_CMD_IRQ /* irqinfo */ #define CONFIG_CMD_ITEST /* Integer (and string) test */ #define CONFIG_CMD_JFFS2 /* JFFS2 Support */ @@ -70,6 +73,7 @@ #define CONFIG_CMD_REGINFO /* Register dump */ #define CONFIG_CMD_REISER /* Reiserfs support */ #define CONFIG_CMD_RARP /* rarpboot support */ +#define CONFIG_CMD_READ /* Read data from partition */ #define CONFIG_CMD_RUN /* run command in env variable */ #define CONFIG_CMD_SAVEENV /* saveenv */ #define CONFIG_CMD_SAVES /* save S record dump */ diff --git a/include/configs/omap3_evm.h b/include/configs/omap3_evm.h index b4d925ed90..fc6e78208c 100644 --- a/include/configs/omap3_evm.h +++ b/include/configs/omap3_evm.h @@ -95,10 +95,7 @@ #define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot.img" /* Partition tables */ -/* Only need DOS partition support for SPL, currently */ -#ifndef CONFIG_SPL_BUILD #define CONFIG_EFI_PARTITION -#endif #define CONFIG_DOS_PARTITION /* USB diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h index c0f86228b0..39a347af84 100644 --- a/include/configs/smdk5250.h +++ b/include/configs/smdk5250.h @@ -203,6 +203,7 @@ #define CONFIG_I2C_MULTI_BUS #define CONFIG_MAX_I2C_NUM 8 #define CONFIG_SYS_I2C_SLAVE 0x0 +#define CONFIG_I2C_EDID /* Ethernet Controllor Driver */ #ifdef CONFIG_CMD_NET @@ -215,4 +216,10 @@ /* Enable devicetree support */ #define CONFIG_OF_LIBFDT +/* SHA hashing */ +#define CONFIG_CMD_HASH +#define CONFIG_HASH_VERIFY +#define CONFIG_SHA1 +#define CONFIG_SHA256 + #endif /* __CONFIG_H */ diff --git a/include/configs/trats.h b/include/configs/trats.h index 355029e8d8..94ba55e277 100644 --- a/include/configs/trats.h +++ b/include/configs/trats.h @@ -98,6 +98,7 @@ #undef CONFIG_CMD_MTDPARTS #define CONFIG_CMD_MMC #define CONFIG_CMD_DFU +#define CONFIG_CMD_GPT /* FAT */ #define CONFIG_CMD_FAT @@ -122,6 +123,26 @@ #define CONFIG_BOOTBLOCK "10" #define CONFIG_ENV_COMMON_BOOT "${console} ${meminfo}" +/* Tizen - partitions definitions */ +#define PARTS_CSA "csa-mmc" +#define PARTS_BOOTLOADER "u-boot" +#define PARTS_BOOT "boot" +#define PARTS_ROOT "platform" +#define PARTS_DATA "data" +#define PARTS_CSC "csc" +#define PARTS_UMS "ums" + +#define PARTS_DEFAULT \ + "uuid_disk=${uuid_gpt_disk};" \ + "name="PARTS_CSA",size=8MiB,uuid=${uuid_gpt_"PARTS_CSA"};" \ + "name="PARTS_BOOTLOADER",size=60MiB," \ + "uuid=${uuid_gpt_"PARTS_BOOTLOADER"};" \ + "name="PARTS_BOOT",size=100MiB,uuid=${uuid_gpt_"PARTS_BOOT"};" \ + "name="PARTS_ROOT",size=1GiB,uuid=${uuid_gpt_"PARTS_ROOT"};" \ + "name="PARTS_DATA",size=3GiB,uuid=${uuid_gpt_"PARTS_DATA"};" \ + "name="PARTS_CSC",size=150MiB,uuid=${uuid_gpt_"PARTS_CSC"};" \ + "name="PARTS_UMS",size=-,uuid=${uuid_gpt_"PARTS_UMS"}\0" \ + #define CONFIG_DFU_ALT \ "dfu_alt_info=" \ "u-boot mmc 80 400;" \ @@ -171,7 +192,8 @@ "mmcbootpart=2\0" \ "mmcrootpart=3\0" \ "opts=always_resume=1\0" \ - CONFIG_DFU_ALT + "partitions=" PARTS_DEFAULT \ + CONFIG_DFU_ALT \ /* Miscellaneous configurable options */ #define CONFIG_SYS_LONGHELP /* undef to save memory */ @@ -208,6 +230,10 @@ #define CONFIG_DOS_PARTITION +/* GPT */ +#define CONFIG_EFI_PARTITION +#define CONFIG_PARTITION_UUIDS + #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_LOAD_ADDR - GENERATED_GBL_DATA_SIZE) #define CONFIG_SYS_CACHELINE_SIZE 32 diff --git a/include/edid.h b/include/edid.h new file mode 100644 index 0000000000..4788de9392 --- /dev/null +++ b/include/edid.h @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * (C) Copyright 2010 + * Petr Stetiar <ynezz@true.cz> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Contains stolen code from ddcprobe project which is: + * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com> + * + */ + +#ifndef __EDID_H_ +#define __EDID_H_ + +#include <linux/types.h> + +#define GET_BIT(_x, _pos) \ + (((_x) >> (_pos)) & 1) +#define GET_BITS(_x, _pos_msb, _pos_lsb) \ + (((_x) >> (_pos_lsb)) & ((1 << ((_pos_msb) - (_pos_lsb) + 1)) - 1)) + +/* Aspect ratios used in EDID info. */ +enum edid_aspect { + ASPECT_625 = 0, + ASPECT_75, + ASPECT_8, + ASPECT_5625, +}; + +/* Detailed timing information used in EDID v1.x */ +struct edid_detailed_timing { + unsigned char pixel_clock[2]; +#define EDID_DETAILED_TIMING_PIXEL_CLOCK(_x) \ + (((((uint32_t)(_x).pixel_clock[1]) << 8) + \ + (_x).pixel_clock[0]) * 10000) + unsigned char horizontal_active; + unsigned char horizontal_blanking; + unsigned char horizontal_active_blanking_hi; +#define EDID_DETAILED_TIMING_HORIZONTAL_ACTIVE(_x) \ + ((GET_BITS((_x).horizontal_active_blanking_hi, 7, 4) << 8) + \ + (_x).horizontal_active) +#define EDID_DETAILED_TIMING_HORIZONTAL_BLANKING(_x) \ + ((GET_BITS((_x).horizontal_active_blanking_hi, 3, 0) << 8) + \ + (_x).horizontal_blanking) + unsigned char vertical_active; + unsigned char vertical_blanking; + unsigned char vertical_active_blanking_hi; +#define EDID_DETAILED_TIMING_VERTICAL_ACTIVE(_x) \ + ((GET_BITS((_x).vertical_active_blanking_hi, 7, 4) << 8) + \ + (_x).vertical_active) +#define EDID_DETAILED_TIMING_VERTICAL_BLANKING(_x) \ + ((GET_BITS((_x).vertical_active_blanking_hi, 3, 0) << 8) + \ + (_x).vertical_blanking) + unsigned char hsync_offset; + unsigned char hsync_pulse_width; + unsigned char sync_offset_pulse_width; + unsigned char hsync_vsync_offset_pulse_width_hi; +#define EDID_DETAILED_TIMING_HSYNC_OFFSET(_x) \ + ((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 7, 6) << 8) + \ + (_x).hsync_offset) +#define EDID_DETAILED_TIMING_HSYNC_PULSE_WIDTH(_x) \ + ((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 5, 4) << 8) + \ + (_x).hsync_pulse_width) +#define EDID_DETAILED_TIMING_VSYNC_OFFSET(_x) \ + ((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 3, 2) << 4) + \ + GET_BITS((_x).vsync_offset_pulse_width, 7, 4)) +#define EDID_DETAILED_TIMING_VSYNC_PULSE_WIDTH(_x) \ + ((GET_BITS((_x).hsync_vsync_offset_pulse_width_hi, 1, 0) << 4) + \ + GET_BITS((_x).vsync_offset_pulse_width, 3, 0)) + unsigned char himage_size; + unsigned char vimage_size; + unsigned char himage_vimage_size_hi; +#define EDID_DETAILED_TIMING_HIMAGE_SIZE(_x) \ + ((GET_BITS((_x).himage_vimage_size_hi, 7, 4) << 8) + (_x).himage_size) +#define EDID_DETAILED_TIMING_VIMAGE_SIZE(_x) \ + ((GET_BITS((_x).himage_vimage_size_hi, 3, 0) << 8) + (_x).vimage_size) + unsigned char hborder; + unsigned char vborder; + unsigned char flags; +#define EDID_DETAILED_TIMING_FLAG_INTERLACED(_x) \ + GET_BIT((_x).flags, 7) +#define EDID_DETAILED_TIMING_FLAG_STEREO(_x) \ + GET_BITS((_x).flags, 6, 5) +#define EDID_DETAILED_TIMING_FLAG_DIGITAL_COMPOSITE(_x) \ + GET_BITS((_x).flags, 4, 3) +#define EDID_DETAILED_TIMING_FLAG_POLARITY(_x) \ + GET_BITS((_x).flags, 2, 1) +#define EDID_DETAILED_TIMING_FLAG_INTERLEAVED(_x) \ + GET_BIT((_x).flags, 0) +} __attribute__ ((__packed__)); + +enum edid_monitor_descriptor_types { + EDID_MONITOR_DESCRIPTOR_SERIAL = 0xff, + EDID_MONITOR_DESCRIPTOR_ASCII = 0xfe, + EDID_MONITOR_DESCRIPTOR_RANGE = 0xfd, + EDID_MONITOR_DESCRIPTOR_NAME = 0xfc, +}; + +struct edid_monitor_descriptor { + uint16_t zero_flag_1; + unsigned char zero_flag_2; + unsigned char type; + unsigned char zero_flag_3; + union { + char string[13]; + struct { + unsigned char vertical_min; + unsigned char vertical_max; + unsigned char horizontal_min; + unsigned char horizontal_max; + unsigned char pixel_clock_max; + unsigned char gtf_data[8]; + } range_data; + } data; +} __attribute__ ((__packed__)); + +struct edid1_info { + unsigned char header[8]; + unsigned char manufacturer_name[2]; +#define EDID1_INFO_MANUFACTURER_NAME_ZERO(_x) \ + GET_BIT(((_x).manufacturer_name[0]), 7) +#define EDID1_INFO_MANUFACTURER_NAME_CHAR1(_x) \ + GET_BITS(((_x).manufacturer_name[0]), 6, 2) +#define EDID1_INFO_MANUFACTURER_NAME_CHAR2(_x) \ + ((GET_BITS(((_x).manufacturer_name[0]), 1, 0) << 3) + \ + GET_BITS(((_x).manufacturer_name[1]), 7, 5)) +#define EDID1_INFO_MANUFACTURER_NAME_CHAR3(_x) \ + GET_BITS(((_x).manufacturer_name[1]), 4, 0) + unsigned char product_code[2]; +#define EDID1_INFO_PRODUCT_CODE(_x) \ + (((uint16_t)(_x).product_code[1] << 8) + (_x).product_code[0]) + unsigned char serial_number[4]; +#define EDID1_INFO_SERIAL_NUMBER(_x) \ + (((uint32_t)(_x).serial_number[3] << 24) + \ + ((_x).serial_number[2] << 16) + ((_x).serial_number[1] << 8) + \ + (_x).serial_number[0]) + unsigned char week; + unsigned char year; + unsigned char version; + unsigned char revision; + unsigned char video_input_definition; +#define EDID1_INFO_VIDEO_INPUT_DIGITAL(_x) \ + GET_BIT(((_x).video_input_definition), 7) +#define EDID1_INFO_VIDEO_INPUT_VOLTAGE_LEVEL(_x) \ + GET_BITS(((_x).video_input_definition), 6, 5) +#define EDID1_INFO_VIDEO_INPUT_BLANK_TO_BLACK(_x) \ + GET_BIT(((_x).video_input_definition), 4) +#define EDID1_INFO_VIDEO_INPUT_SEPARATE_SYNC(_x) \ + GET_BIT(((_x).video_input_definition), 3) +#define EDID1_INFO_VIDEO_INPUT_COMPOSITE_SYNC(_x) \ + GET_BIT(((_x).video_input_definition), 2) +#define EDID1_INFO_VIDEO_INPUT_SYNC_ON_GREEN(_x) \ + GET_BIT(((_x).video_input_definition), 1) +#define EDID1_INFO_VIDEO_INPUT_SERRATION_V(_x) \ + GET_BIT(((_x).video_input_definition), 0) + unsigned char max_size_horizontal; + unsigned char max_size_vertical; + unsigned char gamma; + unsigned char feature_support; +#define EDID1_INFO_FEATURE_STANDBY(_x) \ + GET_BIT(((_x).feature_support), 7) +#define EDID1_INFO_FEATURE_SUSPEND(_x) \ + GET_BIT(((_x).feature_support), 6) +#define EDID1_INFO_FEATURE_ACTIVE_OFF(_x) \ + GET_BIT(((_x).feature_support), 5) +#define EDID1_INFO_FEATURE_DISPLAY_TYPE(_x) \ + GET_BITS(((_x).feature_support), 4, 3) +#define EDID1_INFO_FEATURE_RGB(_x) \ + GET_BIT(((_x).feature_support), 2) +#define EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(_x) \ + GET_BIT(((_x).feature_support), 1) +#define EDID1_INFO_FEATURE_DEFAULT_GTF_SUPPORT(_x) \ + GET_BIT(((_x).feature_support), 0) + unsigned char color_characteristics[10]; + unsigned char established_timings[3]; +#define EDID1_INFO_ESTABLISHED_TIMING_720X400_70(_x) \ + GET_BIT(((_x).established_timings[0]), 7) +#define EDID1_INFO_ESTABLISHED_TIMING_720X400_88(_x) \ + GET_BIT(((_x).established_timings[0]), 6) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_60(_x) \ + GET_BIT(((_x).established_timings[0]), 5) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_67(_x) \ + GET_BIT(((_x).established_timings[0]), 4) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_72(_x) \ + GET_BIT(((_x).established_timings[0]), 3) +#define EDID1_INFO_ESTABLISHED_TIMING_640X480_75(_x) \ + GET_BIT(((_x).established_timings[0]), 2) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_56(_x) \ + GET_BIT(((_x).established_timings[0]), 1) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_60(_x) \ + GET_BIT(((_x).established_timings[0]), 0) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_72(_x) \ + GET_BIT(((_x).established_timings[1]), 7) +#define EDID1_INFO_ESTABLISHED_TIMING_800X600_75(_x) \ + GET_BIT(((_x).established_timings[1]), 6) +#define EDID1_INFO_ESTABLISHED_TIMING_832X624_75(_x) \ + GET_BIT(((_x).established_timings[1]), 5) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_87I(_x) \ + GET_BIT(((_x).established_timings[1]), 4) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_60(_x) \ + GET_BIT(((_x).established_timings[1]), 3) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_70(_x) \ + GET_BIT(((_x).established_timings[1]), 2) +#define EDID1_INFO_ESTABLISHED_TIMING_1024X768_75(_x) \ + GET_BIT(((_x).established_timings[1]), 1) +#define EDID1_INFO_ESTABLISHED_TIMING_1280X1024_75(_x) \ + GET_BIT(((_x).established_timings[1]), 0) +#define EDID1_INFO_ESTABLISHED_TIMING_1152X870_75(_x) \ + GET_BIT(((_x).established_timings[2]), 7) + struct { + unsigned char xresolution; + unsigned char aspect_vfreq; + } __attribute__((__packed__)) standard_timings[8]; +#define EDID1_INFO_STANDARD_TIMING_XRESOLUTION(_x, _i) \ + (((_x).standard_timings[_i]).xresolution) +#define EDID1_INFO_STANDARD_TIMING_ASPECT(_x, _i) \ + GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 7, 6) +#define EDID1_INFO_STANDARD_TIMING_VFREQ(_x, _i) \ + GET_BITS(((_x).standard_timings[_i].aspect_vfreq), 5, 0) + union { + unsigned char timing[72]; + struct edid_monitor_descriptor descriptor[4]; + } monitor_details; + unsigned char extension_flag; + unsigned char checksum; +} __attribute__ ((__packed__)); + +/** + * Print the EDID info. + * + * @param edid_info The EDID info to be printed + */ +void edid_print_info(struct edid1_info *edid_info); + +/** + * Check the EDID info. + * + * @param info The EDID info to be checked + * @return 0 on valid, or -1 on invalid + */ +int edid_check_info(struct edid1_info *info); + +/** + * Get the horizontal and vertical rate ranges of the monitor. + * + * @param edid The EDID info + * @param hmin Returns the minimum horizontal rate + * @param hmax Returns the maxium horizontal rate + * @param vmin Returns the minimum vertical rate + * @param vmax Returns the maxium vertical rate + * @return 0 on success, or -1 on error + */ +int edid_get_ranges(struct edid1_info *edid, unsigned int *hmin, + unsigned int *hmax, unsigned int *vmin, + unsigned int *vmax); + +#endif /* __EDID_H_ */ diff --git a/include/env_attr.h b/include/env_attr.h new file mode 100644 index 0000000000..6ef114f5da --- /dev/null +++ b/include/env_attr.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ENV_ATTR_H__ +#define __ENV_ATTR_H__ + +#define ENV_ATTR_LIST_DELIM ',' +#define ENV_ATTR_SEP ':' + +/* + * env_attr_walk takes as input an "attr_list" that takes the form: + * attributes = [^,:\s]* + * entry = name[:attributes] + * list = entry[,list] + * It will call the "callback" function with the "name" and attribute as "value" + * The callback may return a non-0 to abort the list walk. + * This return value will be passed through to the caller. + * 0 is returned on success. + */ +extern int env_attr_walk(const char *attr_list, + int (*callback)(const char *name, const char *value)); + +/* + * env_attr_lookup takes as input an "attr_list" with the same form as above. + * It also takes as input a "name" to look for. + * If the name is found in the list, it's value is copied into "attributes". + * There is no protection on attributes being too small for the value. + * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if + * "attr_list" is NULL. + * Returns 0 on success. + */ +extern int env_attr_lookup(const char *attr_list, const char *name, + char *attributes); + +#endif /* __ENV_ATTR_H__ */ diff --git a/include/env_callback.h b/include/env_callback.h new file mode 100644 index 0000000000..47fdc6fa91 --- /dev/null +++ b/include/env_callback.h @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ENV_CALLBACK_H__ +#define __ENV_CALLBACK_H__ + +#include <env_flags.h> +#include <linker_lists.h> +#include <search.h> + +#define ENV_CALLBACK_VAR ".callbacks" + +/* Board configs can define additional static callback bindings */ +#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC +#define CONFIG_ENV_CALLBACK_LIST_STATIC +#endif + +#ifdef CONFIG_SILENT_CONSOLE +#define SILENT_CALLBACK "silent:silent," +#else +#define SILENT_CALLBACK +#endif + +/* + * This list of callback bindings is static, but may be overridden by defining + * a new association in the ".callbacks" environment variable. + */ +#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \ + ENV_FLAGS_VAR ":flags," \ + "baudrate:baudrate," \ + "bootfile:bootfile," \ + "loadaddr:loadaddr," \ + SILENT_CALLBACK \ + "stdin:console,stdout:console,stderr:console," \ + CONFIG_ENV_CALLBACK_LIST_STATIC + +struct env_clbk_tbl { + const char *name; /* Callback name */ + int (*callback)(const char *name, const char *value, enum env_op op, + int flags); +}; + +struct env_clbk_tbl *find_env_callback(const char *); +void env_callback_init(ENTRY *var_entry); + +/* + * Define a callback that can be associated with variables. + * when associated through the ".callbacks" environment variable, the callback + * will be executed any time the variable is inserted, overwritten, or deleted. + */ +#define U_BOOT_ENV_CALLBACK(name, callback) \ + ll_entry_declare(struct env_clbk_tbl, name, env_clbk, env_clbk) = \ + {#name, callback} + +#endif /* __ENV_CALLBACK_H__ */ diff --git a/include/env_default.h b/include/env_default.h index a1db73a2c5..39c5b7c6aa 100644 --- a/include/env_default.h +++ b/include/env_default.h @@ -24,6 +24,8 @@ * MA 02111-1307 USA */ +#include <env_callback.h> + #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED env_t environment __PPCENV__ = { ENV_CRC, /* CRC Sum */ @@ -36,6 +38,12 @@ static char default_environment[] = { #else const uchar default_environment[] = { #endif +#ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT + ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0" +#endif +#ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT + ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0" +#endif #ifdef CONFIG_BOOTARGS "bootargs=" CONFIG_BOOTARGS "\0" #endif diff --git a/include/env_flags.h b/include/env_flags.h new file mode 100644 index 0000000000..d1aa1440f7 --- /dev/null +++ b/include/env_flags.h @@ -0,0 +1,172 @@ +/* + * (C) Copyright 2012 + * Joe Hershberger, National Instruments, joe.hershberger@ni.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ENV_FLAGS_H__ +#define __ENV_FLAGS_H__ + +enum env_flags_vartype { + env_flags_vartype_string, + env_flags_vartype_decimal, + env_flags_vartype_hex, + env_flags_vartype_bool, +#ifdef CONFIG_CMD_NET + env_flags_vartype_ipaddr, + env_flags_vartype_macaddr, +#endif + env_flags_vartype_end +}; + +enum env_flags_varaccess { + env_flags_varaccess_any, + env_flags_varaccess_readonly, + env_flags_varaccess_writeonce, + env_flags_varaccess_changedefault, + env_flags_varaccess_end +}; + +#define ENV_FLAGS_VAR ".flags" +#define ENV_FLAGS_ATTR_MAX_LEN 2 +#define ENV_FLAGS_VARTYPE_LOC 0 +#define ENV_FLAGS_VARACCESS_LOC 1 + +#ifndef CONFIG_ENV_FLAGS_LIST_STATIC +#define CONFIG_ENV_FLAGS_LIST_STATIC "" +#endif + +#ifdef CONFIG_CMD_NET +#ifdef CONFIG_ENV_OVERWRITE +#define ETHADDR_FLAGS "ethaddr:ma," +#else +#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE +#define ETHADDR_FLAGS "ethaddr:mc," +#else +#define ETHADDR_FLAGS "ethaddr:mo," +#endif +#endif +#else +#define ETHADDR_FLAGS "" +#endif + +#ifndef CONFIG_ENV_OVERWRITE +#define SERIAL_FLAGS "serial#:so," +#else +#define SERIAL_FLAGS "" +#endif + +#define ENV_FLAGS_LIST_STATIC \ + ETHADDR_FLAGS \ + SERIAL_FLAGS \ + CONFIG_ENV_FLAGS_LIST_STATIC + +#ifdef CONFIG_CMD_ENV_FLAGS +/* + * Print the whole list of available type flags. + */ +void env_flags_print_vartypes(void); +/* + * Print the whole list of available access flags. + */ +void env_flags_print_varaccess(void); +/* + * Return the name of the type. + */ +const char *env_flags_get_vartype_name(enum env_flags_vartype type); +/* + * Return the name of the access. + */ +const char *env_flags_get_varaccess_name(enum env_flags_varaccess access); +#endif + +/* + * Parse the flags string from a .flags attribute list into the vartype enum. + */ +enum env_flags_vartype env_flags_parse_vartype(const char *flags); +/* + * Parse the flags string from a .flags attribute list into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess(const char *flags); +/* + * Parse the binary flags from a hash table entry into the varaccess enum. + */ +enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags); + +#ifdef USE_HOSTCC +/* + * Look up the type of a variable directly from the .flags var. + */ +enum env_flags_vartype env_flags_get_type(const char *name); +/* + * Look up the access of a variable directly from the .flags var. + */ +enum env_flags_varaccess env_flags_get_access(const char *name); +/* + * Validate the newval for its type to conform with the requirements defined by + * its flags (directly looked at the .flags var). + */ +int env_flags_validate_type(const char *name, const char *newval); +/* + * Validate the newval for its access to conform with the requirements defined + * by its flags (directly looked at the .flags var). + */ +int env_flags_validate_access(const char *name, int check_mask); +/* + * Validate that the proposed access to variable "name" is valid according to + * the defined flags for that variable, if any. + */ +int env_flags_validate_varaccess(const char *name, int check_mask); +/* + * Validate the parameters passed to "env set" for type compliance + */ +int env_flags_validate_env_set_params(int argc, char * const argv[]); + +#else /* !USE_HOSTCC */ + +#include <search.h> + +/* + * When adding a variable to the environment, initialize the flags for that + * variable. + */ +void env_flags_init(ENTRY *var_entry); + +/* + * Validate the newval for to conform with the requirements defined by its flags + */ +int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op, + int flag); + +#endif /* USE_HOSTCC */ + +/* + * These are the binary flags used in the environment entry->flags variable to + * decribe properties of veriables in the table + */ +#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007 +/* The actual variable type values use the enum value (within the mask) */ +#define ENV_FLAGS_VARACCESS_PREVENT_DELETE 0x00000008 +#define ENV_FLAGS_VARACCESS_PREVENT_CREATE 0x00000010 +#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR 0x00000020 +#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR 0x00000040 +#define ENV_FLAGS_VARACCESS_BIN_MASK 0x00000078 + +#endif /* __ENV_FLAGS_H__ */ diff --git a/include/environment.h b/include/environment.h index e8ab7033bf..e64b43d2d9 100644 --- a/include/environment.h +++ b/include/environment.h @@ -164,6 +164,9 @@ extern void env_reloc(void); #ifndef DO_DEPS_ONLY +#include <env_attr.h> +#include <env_callback.h> +#include <env_flags.h> #include <search.h> extern struct hsearch_data env_htab; @@ -178,6 +181,9 @@ unsigned char env_get_char_memory(int index); /* Function that updates CRC of the enironment */ void env_crc_update(void); +/* Look up the variable from the default environment */ +char *getenv_default(const char *name); + /* [re]set to the default environment */ void set_default_env(const char *s); @@ -187,15 +193,6 @@ int set_default_vars(int nvars, char * const vars[]); /* Import from binary representation into hash table */ int env_import(const char *buf, int check); -/* - * Check if variable "name" can be changed from oldval to newval, - * and if so, apply the changes (e.g. baudrate). - * When (flag & H_FORCE) is set, it does not print out any error - * message and forces overwriting of write-once variables. - */ -int env_check_apply(const char *name, const char *oldval, - const char *newval, int flag); - #endif /* DO_DEPS_ONLY */ #endif /* _ENVIRONMENT_H_ */ diff --git a/include/exports.h b/include/exports.h index 63aa4b264a..6cf31aa5e7 100644 --- a/include/exports.h +++ b/include/exports.h @@ -23,7 +23,7 @@ char *getenv (const char *name); int setenv (const char *varname, const char *varvalue); long simple_strtol(const char *cp,char **endp,unsigned int base); int strcmp(const char * cs,const char * ct); -int ustrtoul(const char *cp, char **endp, unsigned int base); +unsigned long ustrtoul(const char *cp, char **endp, unsigned int base); #if defined(CONFIG_CMD_I2C) int i2c_write (uchar, uint, int , uchar* , int); int i2c_read (uchar, uint, int , uchar* , int); diff --git a/include/hash.h b/include/hash.h new file mode 100644 index 0000000000..34ba558bd0 --- /dev/null +++ b/include/hash.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _HASH_H +#define _HASH_H + +#ifdef CONFIG_SHA1SUM_VERIFY +#define CONFIG_HASH_VERIFY +#endif + +struct hash_algo { + const char *name; /* Name of algorithm */ + int digest_size; /* Length of digest */ + /** + * hash_func_ws: Generic hashing function + * + * This is the generic prototype for a hashing function. We only + * have the watchdog version at present. + * + * @input: Input buffer + * @ilen: Input buffer length + * @output: Checksum result (length depends on algorithm) + * @chunk_sz: Trigger watchdog after processing this many bytes + */ + void (*hash_func_ws)(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz); + int chunk_size; /* Watchdog chunk size */ +}; + +/* + * Maximum digest size for all algorithms we support. Having this value + * avoids a malloc() or C99 local declaration in common/cmd_hash.c. + */ +#define HASH_MAX_DIGEST_SIZE 32 + +/** + * hash_command: Process a hash command for a particular algorithm + * + * This common function is used to implement specific hash commands. + * + * @algo_name: Hash algorithm being used + * @verify: Non-zero to enable verify mode + * @cmdtp: Pointer to command table entry + * @flag: Some flags normally 0 (see CMD_FLAG_.. above) + * @argc: Number of arguments (arg 0 must be the command text) + * @argv: Arguments + */ +int hash_command(const char *algo_name, int verify, cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]); + +#endif diff --git a/include/image.h b/include/image.h index f54d983306..b958b18a4d 100644 --- a/include/image.h +++ b/include/image.h @@ -460,7 +460,6 @@ static inline void image_set_name(image_header_t *hdr, const char *name) int image_check_hcrc(const image_header_t *hdr); int image_check_dcrc(const image_header_t *hdr); #ifndef USE_HOSTCC -int getenv_yesno(char *var); ulong getenv_bootm_low(void); phys_size_t getenv_bootm_size(void); phys_size_t getenv_bootm_mapsize(void); diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h new file mode 100644 index 0000000000..192b4c9bea --- /dev/null +++ b/include/linux/linux_string.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_LINUX_STRING_H_ +#define _LINUX_LINUX_STRING_H_ + +extern char * skip_spaces(const char *); + +extern char *strim(char *); + +#endif diff --git a/include/linux/string.h b/include/linux/string.h index 9a8cbc24cd..e9b134d142 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -38,8 +38,11 @@ extern int strcmp(const char *,const char *); #ifndef __HAVE_ARCH_STRNCMP extern int strncmp(const char *,const char *,__kernel_size_t); #endif -#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ -extern int strnicmp(const char *, const char *, __kernel_size_t); +#ifndef __HAVE_ARCH_STRCASECMP +int strcasecmp(const char *s1, const char *s2); +#endif +#ifndef __HAVE_ARCH_STRNCASECMP +extern int strncasecmp(const char *s1, const char *s2, __kernel_size_t len); #endif #ifndef __HAVE_ARCH_STRCHR extern char * strchr(const char *,int); @@ -47,10 +50,7 @@ extern char * strchr(const char *,int); #ifndef __HAVE_ARCH_STRRCHR extern char * strrchr(const char *,int); #endif -extern char * skip_spaces(const char *); - -extern char *strim(char *); - +#include <linux/linux_string.h> #ifndef __HAVE_ARCH_STRSTR extern char * strstr(const char *,const char *); #endif diff --git a/include/part.h b/include/part.h index 27ea283f1e..c58a734ada 100644 --- a/include/part.h +++ b/include/part.h @@ -176,10 +176,62 @@ int test_part_amiga (block_dev_desc_t *dev_desc); #endif #ifdef CONFIG_EFI_PARTITION +#include <part_efi.h> /* disk/part_efi.c */ int get_partition_info_efi (block_dev_desc_t * dev_desc, int part, disk_partition_t *info); void print_part_efi (block_dev_desc_t *dev_desc); int test_part_efi (block_dev_desc_t *dev_desc); + +/** + * write_gpt_table() - Write the GUID Partition Table to disk + * + * @param dev_desc - block device descriptor + * @param gpt_h - pointer to GPT header representation + * @param gpt_e - pointer to GPT partition table entries + * + * @return - zero on success, otherwise error + */ +int write_gpt_table(block_dev_desc_t *dev_desc, + gpt_header *gpt_h, gpt_entry *gpt_e); + +/** + * gpt_fill_pte(): Fill the GPT partition table entry + * + * @param gpt_h - GPT header representation + * @param gpt_e - GPT partition table entries + * @param partitions - list of partitions + * @param parts - number of partitions + * + * @return zero on success + */ +int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, + disk_partition_t *partitions, int parts); + +/** + * gpt_fill_header(): Fill the GPT header + * + * @param dev_desc - block device descriptor + * @param gpt_h - GPT header representation + * @param str_guid - disk guid string representation + * @param parts_count - number of partitions + * + * @return - error on str_guid conversion error + */ +int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h, + char *str_guid, int parts_count); + +/** + * gpt_restore(): Restore GPT partition table + * + * @param dev_desc - block device descriptor + * @param str_disk_guid - disk GUID + * @param partitions - list of partitions + * @param parts - number of partitions + * + * @return zero on success + */ +int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid, + disk_partition_t *partitions, const int parts_count); #endif #endif /* _PART_H */ diff --git a/disk/part_efi.h b/include/part_efi.h index 4e28d1dcb6..6de0a3258a 100644 --- a/disk/part_efi.h +++ b/include/part_efi.h @@ -29,6 +29,8 @@ * http://developer.intel.com/technology/efi/efi.htm */ +#include <linux/compiler.h> + #ifndef _DISK_PART_EFI_H #define _DISK_PART_EFI_H @@ -41,6 +43,8 @@ #define GPT_HEADER_REVISION_V1 0x00010000 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1ULL #define GPT_ENTRY_NAME "gpt" +#define GPT_ENTRY_NUMBERS 128 +#define GPT_ENTRY_SIZE 128 #define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ ((efi_guid_t) \ @@ -72,73 +76,72 @@ 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) /* linux/include/efi.h */ -typedef unsigned short efi_char16_t; +typedef u16 efi_char16_t; typedef struct { - unsigned char b[16]; + u8 b[16]; } efi_guid_t; /* based on linux/include/genhd.h */ struct partition { - unsigned char boot_ind; /* 0x80 - active */ - unsigned char head; /* starting head */ - unsigned char sector; /* starting sector */ - unsigned char cyl; /* starting cylinder */ - unsigned char sys_ind; /* What partition type */ - unsigned char end_head; /* end head */ - unsigned char end_sector; /* end sector */ - unsigned char end_cyl; /* end cylinder */ - unsigned char start_sect[4]; /* starting sector counting from 0 */ - unsigned char nr_sects[4]; /* nr of sectors in partition */ -} __attribute__ ((packed)); + u8 boot_ind; /* 0x80 - active */ + u8 head; /* starting head */ + u8 sector; /* starting sector */ + u8 cyl; /* starting cylinder */ + u8 sys_ind; /* What partition type */ + u8 end_head; /* end head */ + u8 end_sector; /* end sector */ + u8 end_cyl; /* end cylinder */ + __le32 start_sect; /* starting sector counting from 0 */ + __le32 nr_sects; /* nr of sectors in partition */ +} __packed; /* based on linux/fs/partitions/efi.h */ typedef struct _gpt_header { - unsigned char signature[8]; - unsigned char revision[4]; - unsigned char header_size[4]; - unsigned char header_crc32[4]; - unsigned char reserved1[4]; - unsigned char my_lba[8]; - unsigned char alternate_lba[8]; - unsigned char first_usable_lba[8]; - unsigned char last_usable_lba[8]; + __le64 signature; + __le32 revision; + __le32 header_size; + __le32 header_crc32; + __le32 reserved1; + __le64 my_lba; + __le64 alternate_lba; + __le64 first_usable_lba; + __le64 last_usable_lba; efi_guid_t disk_guid; - unsigned char partition_entry_lba[8]; - unsigned char num_partition_entries[4]; - unsigned char sizeof_partition_entry[4]; - unsigned char partition_entry_array_crc32[4]; - unsigned char reserved2[GPT_BLOCK_SIZE - 92]; -} __attribute__ ((packed)) gpt_header; + __le64 partition_entry_lba; + __le32 num_partition_entries; + __le32 sizeof_partition_entry; + __le32 partition_entry_array_crc32; + u8 reserved2[GPT_BLOCK_SIZE - 92]; +} __packed gpt_header; typedef union _gpt_entry_attributes { struct { - unsigned long long required_to_function:1; - unsigned long long no_block_io_protocol:1; - unsigned long long legacy_bios_bootable:1; - unsigned long long reserved:45; - unsigned long long type_guid_specific:16; + u64 required_to_function:1; + u64 no_block_io_protocol:1; + u64 legacy_bios_bootable:1; + u64 reserved:45; + u64 type_guid_specific:16; } fields; unsigned long long raw; -} __attribute__ ((packed)) gpt_entry_attributes; +} __packed gpt_entry_attributes; #define PARTNAME_SZ (72 / sizeof(efi_char16_t)) typedef struct _gpt_entry { efi_guid_t partition_type_guid; efi_guid_t unique_partition_guid; - unsigned char starting_lba[8]; - unsigned char ending_lba[8]; + __le64 starting_lba; + __le64 ending_lba; gpt_entry_attributes attributes; efi_char16_t partition_name[PARTNAME_SZ]; -} -__attribute__ ((packed)) gpt_entry; +} __packed gpt_entry; typedef struct _legacy_mbr { - unsigned char boot_code[440]; - unsigned char unique_mbr_signature[4]; - unsigned char unknown[2]; + u8 boot_code[440]; + __le32 unique_mbr_signature; + __le16 unknown; struct partition partition_record[4]; - unsigned char signature[2]; -} __attribute__ ((packed)) legacy_mbr; + __le16 signature; +} __packed legacy_mbr; #endif /* _DISK_PART_EFI_H */ diff --git a/include/search.h b/include/search.h index 93e1cbc6d0..13d3be6291 100644 --- a/include/search.h +++ b/include/search.h @@ -32,6 +32,12 @@ #define __set_errno(val) do { errno = val; } while (0) +enum env_op { + env_op_create, + env_op_delete, + env_op_overwrite, +}; + /* Action which shall be performed in the call the hsearch. */ typedef enum { FIND, @@ -41,6 +47,9 @@ typedef enum { typedef struct entry { const char *key; char *data; + int (*callback)(const char *name, const char *value, enum env_op op, + int flags); + int flags; } ENTRY; /* Opaque type for internal use. */ @@ -59,21 +68,20 @@ struct hsearch_data { unsigned int filled; /* * Callback function which will check whether the given change for variable - * "name" from "oldval" to "newval" may be applied or not, and possibly apply - * such change. + * "item" to "newval" may be applied or not, and possibly apply such change. * When (flag & H_FORCE) is set, it shall not print out any error message and * shall force overwriting of write-once variables. .* Must return 0 for approval, 1 for denial. */ - int (*apply)(const char *name, const char *oldval, - const char *newval, int flag); + int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op, + int flag); }; /* Create a new hashing table which will at most contain NEL elements. */ extern int hcreate_r(size_t __nel, struct hsearch_data *__htab); /* Destroy current internal hashing table. */ -extern void hdestroy_r(struct hsearch_data *__htab, int do_apply); +extern void hdestroy_r(struct hsearch_data *__htab); /* * Search for entry matching ITEM.key in internal hash table. If @@ -82,7 +90,7 @@ extern void hdestroy_r(struct hsearch_data *__htab, int do_apply); * ITEM.data. * */ extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval, - struct hsearch_data *__htab); + struct hsearch_data *__htab, int __flag); /* * Search for an entry matching `MATCH'. Otherwise, Same semantics @@ -99,10 +107,10 @@ extern int hstrstr_r(const char *__match, int __last_idx, ENTRY ** __retval, /* Search and delete entry matching ITEM.key in internal hash table. */ extern int hdelete_r(const char *__key, struct hsearch_data *__htab, - int do_apply); + int __flag); extern ssize_t hexport_r(struct hsearch_data *__htab, - const char __sep, char **__resp, size_t __size, + const char __sep, int __flag, char **__resp, size_t __size, int argc, char * const argv[]); /* @@ -113,10 +121,15 @@ extern ssize_t hexport_r(struct hsearch_data *__htab, */ extern int himport_r(struct hsearch_data *__htab, const char *__env, size_t __size, const char __sep, - int __flag, int nvars, char * const vars[], int do_apply); + int __flag, int nvars, char * const vars[]); + +/* Walk the whole table calling the callback on each element */ +extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *)); -/* Flags for himport_r() */ -#define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */ -#define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */ +/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */ +#define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */ +#define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */ +#define H_INTERACTIVE (1 << 2) /* indicate that an import is user directed */ +#define H_HIDE_DOT (1 << 3) /* don't print env vars that begin with '.' */ #endif /* search.h */ diff --git a/include/sha1.h b/include/sha1.h index 734d1fb153..da09dab976 100644 --- a/include/sha1.h +++ b/include/sha1.h @@ -59,7 +59,8 @@ void sha1_starts( sha1_context *ctx ); * \param input buffer holding the data * \param ilen length of the input data */ -void sha1_update( sha1_context *ctx, unsigned char *input, int ilen ); +void sha1_update(sha1_context *ctx, const unsigned char *input, + unsigned int ilen); /** * \brief SHA-1 final digest @@ -76,8 +77,8 @@ void sha1_finish( sha1_context *ctx, unsigned char output[20] ); * \param ilen length of the input data * \param output SHA-1 checksum result */ -void sha1_csum( unsigned char *input, int ilen, - unsigned char output[20] ); +void sha1_csum(const unsigned char *input, unsigned int ilen, + unsigned char *output); /** * \brief Output = SHA-1( input buffer ), with watchdog triggering @@ -87,17 +88,8 @@ void sha1_csum( unsigned char *input, int ilen, * \param output SHA-1 checksum result * \param chunk_sz watchdog triggering period (in bytes of input processed) */ -void sha1_csum_wd (unsigned char *input, int ilen, - unsigned char output[20], unsigned int chunk_sz); - -/** - * \brief Output = SHA-1( file contents ) - * - * \param path input file name - * \param output SHA-1 checksum result - * \return 0 if successful, or 1 if fopen failed - */ -int sha1_file( char *path, unsigned char output[20] ); +void sha1_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz); /** * \brief Output = HMAC-SHA-1( input buffer, hmac key ) @@ -108,9 +100,9 @@ int sha1_file( char *path, unsigned char output[20] ); * \param ilen length of the input data * \param output HMAC-SHA-1 result */ -void sha1_hmac( unsigned char *key, int keylen, - unsigned char *input, int ilen, - unsigned char output[20] ); +void sha1_hmac(const unsigned char *key, int keylen, + const unsigned char *input, unsigned int ilen, + unsigned char *output); /** * \brief Checkup routine diff --git a/include/sha256.h b/include/sha256.h index e38ea898c3..beadab35ff 100644 --- a/include/sha256.h +++ b/include/sha256.h @@ -3,6 +3,9 @@ #define SHA256_SUM_LEN 32 +/* Reset watchdog each time we process this many bytes */ +#define CHUNKSZ_SHA256 (64 * 1024) + typedef struct { uint32_t total[2]; uint32_t state[8]; @@ -10,7 +13,10 @@ typedef struct { } sha256_context; void sha256_starts(sha256_context * ctx); -void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length); +void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length); void sha256_finish(sha256_context * ctx, uint8_t digest[SHA256_SUM_LEN]); +void sha256_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz); + #endif /* _SHA256_H */ diff --git a/lib/Makefile b/lib/Makefile index f83f6e8d8c..86ca1a6ec1 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -69,6 +69,7 @@ endif COBJS-y += crc32.o COBJS-y += ctype.o COBJS-y += div64.o +COBJS-y += linux_string.o COBJS-y += string.o COBJS-y += time.o COBJS-$(CONFIG_BOOTP_PXE) += uuid.o diff --git a/lib/hashtable.c b/lib/hashtable.c index 94a7b61717..07ebfb218f 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -54,7 +54,9 @@ #define CONFIG_ENV_MAX_ENTRIES 512 #endif -#include "search.h" +#include <env_callback.h> +#include <env_flags.h> +#include <search.h> /* * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 @@ -66,12 +68,16 @@ * Instead the interface of all functions is extended to take an argument * which describes the current status. */ + typedef struct _ENTRY { int used; ENTRY entry; } _ENTRY; +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx); + /* * hcreate() */ @@ -142,7 +148,7 @@ int hcreate_r(size_t nel, struct hsearch_data *htab) * be freed and the local static variable can be marked as not used. */ -void hdestroy_r(struct hsearch_data *htab, int do_apply) +void hdestroy_r(struct hsearch_data *htab) { int i; @@ -156,10 +162,7 @@ void hdestroy_r(struct hsearch_data *htab, int do_apply) for (i = 1; i <= htab->size; ++i) { if (htab->table[i].used > 0) { ENTRY *ep = &htab->table[i].entry; - if (do_apply && htab->apply != NULL) { - /* deletion is always forced */ - htab->apply(ep->key, ep->data, NULL, H_FORCE); - } + free((void *)ep->key); free(ep->data); } @@ -250,14 +253,65 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval, return 0; } +/* + * Compare an existing entry with the desired key, and overwrite if the action + * is ENTER. This is simply a helper function for hsearch_r(). + */ +static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, + ENTRY **retval, struct hsearch_data *htab, int flag, + unsigned int hval, unsigned int idx) +{ + if (htab->table[idx].used == hval + && strcmp(item.key, htab->table[idx].entry.key) == 0) { + /* Overwrite existing value? */ + if ((action == ENTER) && (item.data != NULL)) { + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, + env_op_overwrite, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(item.key, + item.data, env_op_overwrite, flag)) { + debug("callback() rejected setting variable " + "%s, skipping it!\n", item.key); + __set_errno(EINVAL); + *retval = NULL; + return 0; + } + + free(htab->table[idx].entry.data); + htab->table[idx].entry.data = strdup(item.data); + if (!htab->table[idx].entry.data) { + __set_errno(ENOMEM); + *retval = NULL; + return 0; + } + } + /* return found entry */ + *retval = &htab->table[idx].entry; + return idx; + } + /* keep searching */ + return -1; +} + int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, - struct hsearch_data *htab) + struct hsearch_data *htab, int flag) { unsigned int hval; unsigned int count; unsigned int len = strlen(item.key); unsigned int idx; unsigned int first_deleted = 0; + int ret; /* Compute an value for the given string. Perhaps use a better method. */ hval = len; @@ -289,23 +343,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, && !first_deleted) first_deleted = idx; - if (htab->table[idx].used == hval - && strcmp(item.key, htab->table[idx].entry.key) == 0) { - /* Overwrite existing value? */ - if ((action == ENTER) && (item.data != NULL)) { - free(htab->table[idx].entry.data); - htab->table[idx].entry.data = - strdup(item.data); - if (!htab->table[idx].entry.data) { - __set_errno(ENOMEM); - *retval = NULL; - return 0; - } - } - /* return found entry */ - *retval = &htab->table[idx].entry; - return idx; - } + ret = _compare_and_overwrite_entry(item, action, retval, htab, + flag, hval, idx); + if (ret != -1) + return ret; /* * Second hash function: @@ -331,23 +372,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, break; /* If entry is found use it. */ - if ((htab->table[idx].used == hval) - && strcmp(item.key, htab->table[idx].entry.key) == 0) { - /* Overwrite existing value? */ - if ((action == ENTER) && (item.data != NULL)) { - free(htab->table[idx].entry.data); - htab->table[idx].entry.data = - strdup(item.data); - if (!htab->table[idx].entry.data) { - __set_errno(ENOMEM); - *retval = NULL; - return 0; - } - } - /* return found entry */ - *retval = &htab->table[idx].entry; - return idx; - } + ret = _compare_and_overwrite_entry(item, action, retval, + htab, flag, hval, idx); + if (ret != -1) + return ret; } while (htab->table[idx].used); } @@ -383,6 +411,34 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, ++htab->filled; + /* This is a new entry, so look up a possible callback */ + env_callback_init(&htab->table[idx].entry); + /* Also look for flags */ + env_flags_init(&htab->table[idx].entry); + + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, env_op_create, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + _hdelete(item.key, htab, &htab->table[idx].entry, idx); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(item.key, item.data, + env_op_create, flag)) { + debug("callback() rejected setting variable " + "%s, skipping it!\n", item.key); + _hdelete(item.key, htab, &htab->table[idx].entry, idx); + __set_errno(EINVAL); + *retval = NULL; + return 0; + } + /* return new entry */ *retval = &htab->table[idx].entry; return 1; @@ -404,7 +460,21 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, * do that. */ -int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply) +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx) +{ + /* free used ENTRY */ + debug("hdelete: DELETING key \"%s\"\n", key); + free((void *)ep->key); + free(ep->data); + ep->callback = NULL; + ep->flags = 0; + htab->table[idx].used = -1; + + --htab->filled; +} + +int hdelete_r(const char *key, struct hsearch_data *htab, int flag) { ENTRY e, *ep; int idx; @@ -413,20 +483,31 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply) e.key = (char *)key; - if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) { + idx = hsearch_r(e, FIND, &ep, htab, 0); + if (idx == 0) { __set_errno(ESRCH); return 0; /* not found */ } - /* free used ENTRY */ - debug("hdelete: DELETING key \"%s\"\n", key); - if (do_apply && htab->apply != NULL) - htab->apply(ep->key, ep->data, NULL, H_FORCE); - free((void *)ep->key); - free(ep->data); - htab->table[idx].used = -1; + /* Check for permission */ + if (htab->change_ok != NULL && + htab->change_ok(ep, NULL, env_op_delete, flag)) { + debug("change_ok() rejected deleting variable " + "%s, skipping it!\n", key); + __set_errno(EPERM); + return 0; + } - --htab->filled; + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) { + debug("callback() rejected deleting variable " + "%s, skipping it!\n", key); + __set_errno(EINVAL); + return 0; + } + + _hdelete(key, htab, ep, idx); return 1; } @@ -482,7 +563,7 @@ static int cmpkey(const void *p1, const void *p2) return (strcmp(e1->key, e2->key)); } -ssize_t hexport_r(struct hsearch_data *htab, const char sep, +ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, char **resp, size_t size, int argc, char * const argv[]) { @@ -519,6 +600,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, if ((argc > 0) && (found == 0)) continue; + if ((flag & H_HIDE_DOT) && ep->key[0] == '.') + continue; + list[n++] = ep; totlen += strlen(ep->key) + 2; @@ -674,7 +758,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[]) int himport_r(struct hsearch_data *htab, const char *env, size_t size, const char sep, int flag, - int nvars, char * const vars[], int do_apply) + int nvars, char * const vars[]) { char *data, *sp, *dp, *name, *value; char *localvars[nvars]; @@ -704,7 +788,7 @@ int himport_r(struct hsearch_data *htab, debug("Destroy Hash Table: %p table = %p\n", htab, htab->table); if (htab->table) - hdestroy_r(htab, do_apply); + hdestroy_r(htab); } /* @@ -770,7 +854,7 @@ int himport_r(struct hsearch_data *htab, if (!drop_var_from_set(name, nvars, localvars)) continue; - if (hdelete_r(name, htab, do_apply) == 0) + if (hdelete_r(name, htab, flag) == 0) debug("DELETE ERROR ##############################\n"); continue; @@ -794,30 +878,10 @@ int himport_r(struct hsearch_data *htab, e.key = name; e.data = value; - /* if there is an apply function, check what it has to say */ - if (do_apply && htab->apply != NULL) { - debug("searching before calling cb function" - " for %s\n", name); - /* - * Search for variable in existing env, so to pass - * its previous value to the apply callback - */ - hsearch_r(e, FIND, &rv, htab); - debug("previous value was %s\n", rv ? rv->data : ""); - if (htab->apply(name, rv ? rv->data : NULL, - value, flag)) { - debug("callback function refused to set" - " variable %s, skipping it!\n", name); - continue; - } - } - - hsearch_r(e, ENTER, &rv, htab); - if (rv == NULL) { + hsearch_r(e, ENTER, &rv, htab, flag); + if (rv == NULL) printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); - return 0; - } debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n", htab, htab->filled, htab->size, @@ -839,7 +903,7 @@ int himport_r(struct hsearch_data *htab, * b) if the variable was not present in current env, we notify * it might be a typo */ - if (hdelete_r(localvars[i], htab, do_apply) == 0) + if (hdelete_r(localvars[i], htab, flag) == 0) printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]); else printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]); @@ -848,3 +912,27 @@ int himport_r(struct hsearch_data *htab, debug("INSERT: done\n"); return 1; /* everything OK */ } + +/* + * hwalk_r() + */ + +/* + * Walk all of the entries in the hash, calling the callback for each one. + * this allows some generic operation to be performed on each element. + */ +int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *)) +{ + int i; + int retval; + + for (i = 1; i <= htab->size; ++i) { + if (htab->table[i].used > 0) { + retval = callback(&htab->table[i].entry); + if (retval) + return retval; + } + } + + return 0; +} diff --git a/lib/linux_string.c b/lib/linux_string.c new file mode 100644 index 0000000000..d5a5e08d98 --- /dev/null +++ b/lib/linux_string.c @@ -0,0 +1,51 @@ +/* + * linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifdef USE_HOSTCC +#include <stdio.h> +#endif + +#include <linux/ctype.h> +#include <linux/string.h> + +/** + * skip_spaces - Removes leading whitespace from @str. + * @str: The string to be stripped. + * + * Returns a pointer to the first non-whitespace character in @str. + */ +char *skip_spaces(const char *str) +{ + while (isspace(*str)) + ++str; + return (char *)str; +} + +/** + * strim - Removes leading and trailing whitespace from @s. + * @s: The string to be stripped. + * + * Note that the first trailing whitespace is replaced with a %NUL-terminator + * in the given string @s. Returns a pointer to the first non-whitespace + * character in @s. + */ +char *strim(char *s) +{ + size_t size; + char *end; + + s = skip_spaces(s); + size = strlen(s); + if (!size) + return s; + + end = s + size - 1; + while (end >= s && isspace(*end)) + end--; + *(end + 1) = '\0'; + + return s; +} diff --git a/lib/sha1.c b/lib/sha1.c index da5bc16f3c..a121224855 100644 --- a/lib/sha1.c +++ b/lib/sha1.c @@ -73,7 +73,7 @@ void sha1_starts (sha1_context * ctx) ctx->state[4] = 0xC3D2E1F0; } -static void sha1_process (sha1_context * ctx, unsigned char data[64]) +static void sha1_process(sha1_context *ctx, const unsigned char data[64]) { unsigned long temp, W[16], A, B, C, D, E; @@ -230,7 +230,8 @@ static void sha1_process (sha1_context * ctx, unsigned char data[64]) /* * SHA-1 process buffer */ -void sha1_update (sha1_context * ctx, unsigned char *input, int ilen) +void sha1_update(sha1_context *ctx, const unsigned char *input, + unsigned int ilen) { int fill; unsigned long left; @@ -305,7 +306,8 @@ void sha1_finish (sha1_context * ctx, unsigned char output[20]) /* * Output = SHA-1( input buffer ) */ -void sha1_csum (unsigned char *input, int ilen, unsigned char output[20]) +void sha1_csum(const unsigned char *input, unsigned int ilen, + unsigned char *output) { sha1_context ctx; @@ -318,12 +320,12 @@ void sha1_csum (unsigned char *input, int ilen, unsigned char output[20]) * Output = SHA-1( input buffer ). Trigger the watchdog every 'chunk_sz' * bytes of input processed. */ -void sha1_csum_wd (unsigned char *input, int ilen, unsigned char output[20], - unsigned int chunk_sz) +void sha1_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz) { sha1_context ctx; #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) - unsigned char *end, *curr; + const unsigned char *end, *curr; int chunk; #endif @@ -350,8 +352,9 @@ void sha1_csum_wd (unsigned char *input, int ilen, unsigned char output[20], /* * Output = HMAC-SHA-1( input buffer, hmac key ) */ -void sha1_hmac (unsigned char *key, int keylen, - unsigned char *input, int ilen, unsigned char output[20]) +void sha1_hmac(const unsigned char *key, int keylen, + const unsigned char *input, unsigned int ilen, + unsigned char *output) { int i; sha1_context ctx; diff --git a/lib/sha256.c b/lib/sha256.c index deb63a40b6..ab2db4890a 100644 --- a/lib/sha256.c +++ b/lib/sha256.c @@ -60,7 +60,7 @@ void sha256_starts(sha256_context * ctx) ctx->state[7] = 0x5BE0CD19; } -void sha256_process(sha256_context * ctx, uint8_t data[64]) +static void sha256_process(sha256_context *ctx, const uint8_t data[64]) { uint32_t temp1, temp2; uint32_t W[64]; @@ -191,7 +191,7 @@ void sha256_process(sha256_context * ctx, uint8_t data[64]) ctx->state[7] += H; } -void sha256_update(sha256_context * ctx, uint8_t * input, uint32_t length) +void sha256_update(sha256_context *ctx, const uint8_t *input, uint32_t length) { uint32_t left, fill; @@ -260,3 +260,36 @@ void sha256_finish(sha256_context * ctx, uint8_t digest[32]) PUT_UINT32_BE(ctx->state[6], digest, 24); PUT_UINT32_BE(ctx->state[7], digest, 28); } + +/* + * Output = SHA-256( input buffer ). Trigger the watchdog every 'chunk_sz' + * bytes of input processed. + */ +void sha256_csum_wd(const unsigned char *input, unsigned int ilen, + unsigned char *output, unsigned int chunk_sz) +{ + sha256_context ctx; +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + unsigned char *end, *curr; + int chunk; +#endif + + sha256_starts(&ctx); + +#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) + curr = input; + end = input + ilen; + while (curr < end) { + chunk = end - curr; + if (chunk > chunk_sz) + chunk = chunk_sz; + sha256_update(&ctx, curr, chunk); + curr += chunk; + WATCHDOG_RESET(); + } +#else + sha256_update(&ctx, input, ilen); +#endif + + sha256_finish(&ctx, output); +} diff --git a/lib/string.c b/lib/string.c index c3ad055e2c..09dfae03c2 100644 --- a/lib/string.c +++ b/lib/string.c @@ -21,14 +21,13 @@ #include <malloc.h> -#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ /** - * strnicmp - Case insensitive, length-limited string comparison + * strncasecmp - Case insensitive, length-limited string comparison * @s1: One string * @s2: The other string * @len: the maximum number of characters to compare */ -int strnicmp(const char *s1, const char *s2, size_t len) +int strncasecmp(const char *s1, const char *s2, size_t len) { /* Yes, Virginia, it had better be unsigned */ unsigned char c1, c2; @@ -52,7 +51,16 @@ int strnicmp(const char *s1, const char *s2, size_t len) } return (int)c1 - (int)c2; } -#endif + +/** + * strcasecmp - Case insensitive string comparison + * @s1: One string + * @s2: The other string + */ +int strcasecmp(const char *s1, const char *s2) +{ + return strncasecmp(s1, s2, -1U); +} char * ___strtok; @@ -214,45 +222,6 @@ char * strrchr(const char * s, int c) } #endif - -/** - * skip_spaces - Removes leading whitespace from @str. - * @str: The string to be stripped. - * - * Returns a pointer to the first non-whitespace character in @str. - */ -char *skip_spaces(const char *str) -{ - while (isspace(*str)) - ++str; - return (char *)str; -} - -/** - * strim - Removes leading and trailing whitespace from @s. - * @s: The string to be stripped. - * - * Note that the first trailing whitespace is replaced with a %NUL-terminator - * in the given string @s. Returns a pointer to the first non-whitespace - * character in @s. - */ -char *strim(char *s) -{ - size_t size; - char *end; - - s = skip_spaces(s); - size = strlen(s); - if (!size) - return s; - - end = s + size - 1; - while (end >= s && isspace(*end)) - end--; - *(end + 1) = '\0'; - - return s; -} #ifndef __HAVE_ARCH_STRLEN /** * strlen - Find the length of a string diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b7a79c0e0c..3c432f8764 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -103,7 +103,7 @@ long simple_strtol(const char *cp, char **endp, unsigned int base) return simple_strtoul(cp, endp, base); } -int ustrtoul(const char *cp, char **endp, unsigned int base) +unsigned long ustrtoul(const char *cp, char **endp, unsigned int base) { unsigned long result = simple_strtoul(cp, endp, base); switch (**endp) { @@ -82,6 +82,7 @@ #include <common.h> #include <command.h> +#include <environment.h> #include <net.h> #if defined(CONFIG_STATUS_LED) #include <miiphy.h> @@ -208,32 +209,46 @@ static int NetTryCount; /**********************************************************************/ +static int on_bootfile(const char *name, const char *value, enum env_op op, + int flags) +{ + switch (op) { + case env_op_create: + case env_op_overwrite: + copy_filename(BootFile, value, sizeof(BootFile)); + break; + default: + break; + } + + return 0; +} +U_BOOT_ENV_CALLBACK(bootfile, on_bootfile); + /* * Check if autoload is enabled. If so, use either NFS or TFTP to download * the boot file. */ void net_auto_load(void) { +#if defined(CONFIG_CMD_NFS) const char *s = getenv("autoload"); - if (s != NULL) { - if (*s == 'n') { - /* - * Just use BOOTP/RARP to configure system; - * Do not use TFTP to load the bootfile. - */ - net_set_state(NETLOOP_SUCCESS); - return; - } -#if defined(CONFIG_CMD_NFS) - if (strcmp(s, "NFS") == 0) { - /* - * Use NFS to load the bootfile. - */ - NfsStart(); - return; - } + if (s != NULL && strcmp(s, "NFS") == 0) { + /* + * Use NFS to load the bootfile. + */ + NfsStart(); + return; + } #endif + if (getenv_yesno("autoload") == 0) { + /* + * Just use BOOTP/RARP to configure system; + * Do not use TFTP to load the bootfile. + */ + net_set_state(NETLOOP_SUCCESS); + return; } TftpStart(TFTPGET); } diff --git a/tools/env/Makefile b/tools/env/Makefile index ab73c8c744..0e798e0940 100644 --- a/tools/env/Makefile +++ b/tools/env/Makefile @@ -24,12 +24,15 @@ include $(TOPDIR)/config.mk HOSTSRCS := $(SRCTREE)/lib/crc32.c fw_env.c fw_env_main.c +HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c +HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c HEADERS := fw_env.h $(OBJTREE)/include/config.h # Compile for a hosted environment on the target HOSTCPPFLAGS = -idirafter $(SRCTREE)/include \ -idirafter $(OBJTREE)/include2 \ -idirafter $(OBJTREE)/include \ + -idirafter $(SRCTREE)/tools/env \ -DUSE_HOSTCC \ -DTEXT_BASE=$(TEXT_BASE) diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index 9b023e807b..90c7a5d3f3 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -25,6 +25,7 @@ */ #include <errno.h> +#include <env_flags.h> #include <fcntl.h> #include <linux/stringify.h> #include <stdio.h> @@ -181,6 +182,32 @@ char *fw_getenv (char *name) } /* + * Search the default environment for a variable. + * Return the value, if found, or NULL, if not found. + */ +char *fw_getdefenv(char *name) +{ + char *env, *nxt; + + for (env = default_environment; *env; env = nxt + 1) { + char *val; + + for (nxt = env; *nxt; ++nxt) { + if (nxt >= &default_environment[ENV_SIZE]) { + fprintf(stderr, "## Error: " + "default environment not terminated\n"); + return NULL; + } + } + val = envmatch(name, env); + if (!val) + continue; + return val; + } + return NULL; +} + +/* * Print the current definition of one, or more, or all * environment variables */ @@ -281,6 +308,7 @@ int fw_env_write(char *name, char *value) int len; char *env, *nxt; char *oldval = NULL; + int deleting, creating, overwriting; /* * search if variable with this name already exists @@ -298,27 +326,49 @@ int fw_env_write(char *name, char *value) break; } - /* - * Delete any existing definition - */ - if (oldval) { -#ifndef CONFIG_ENV_OVERWRITE - /* - * Ethernet Address and serial# can be set only once - */ - if ( - (strcmp(name, "serial#") == 0) || - ((strcmp(name, "ethaddr") == 0) -#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) - && (strcmp(oldval, __stringify(CONFIG_ETHADDR)) != 0) -#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ - ) ) { - fprintf (stderr, "Can't overwrite \"%s\"\n", name); + deleting = (oldval && !(value && strlen(value))); + creating = (!oldval && (value && strlen(value))); + overwriting = (oldval && (value && strlen(value))); + + /* check for permission */ + if (deleting) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_DELETE)) { + printf("Can't delete \"%s\"\n", name); + errno = EROFS; + return -1; + } + } else if (overwriting) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) { + printf("Can't overwrite \"%s\"\n", name); + errno = EROFS; + return -1; + } else if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) { + const char *defval = fw_getdefenv(name); + + if (defval == NULL) + defval = ""; + if (strcmp(oldval, defval) + != 0) { + printf("Can't overwrite \"%s\"\n", name); + errno = EROFS; + return -1; + } + } + } else if (creating) { + if (env_flags_validate_varaccess(name, + ENV_FLAGS_VARACCESS_PREVENT_CREATE)) { + printf("Can't create \"%s\"\n", name); errno = EROFS; return -1; } -#endif /* CONFIG_ENV_OVERWRITE */ + } else + /* Nothing to do */ + return 0; + if (deleting || overwriting) { if (*++nxt == '\0') { *env = '\0'; } else { @@ -395,6 +445,9 @@ int fw_setenv(int argc, char *argv[]) name = argv[1]; + if (env_flags_validate_env_set_params(argc, argv) < 0) + return 1; + len = 0; for (i = 2; i < argc; ++i) { char *val = argv[i]; @@ -516,6 +569,11 @@ int fw_parse_script(char *fname) name, val ? val : " removed"); #endif + if (env_flags_validate_type(name, val) < 0) { + ret = -1; + break; + } + /* * If there is an error setting a variable, * try to save the environment and returns an error diff --git a/tools/fit_image.c b/tools/fit_image.c index ef9ffeeec5..76bbba125a 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -80,7 +80,7 @@ static int fit_handle_file (struct mkimage_params *params) } sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX); - /* dtc -I dts -O -p 200 datafile > tmpfile */ + /* dtc -I dts -O dtb -p 500 datafile > tmpfile */ sprintf (cmd, "%s %s %s > %s", MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); debug ("Trying to execute \"%s\"\n", cmd); |