diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 9ce16b9..5ccdb83 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -222,7 +222,7 @@ endif barebox.imximg: $(KBUILD_BINARY) FORCE - $(call if_changed,imx_image) + $(call if_changed,imx_image,$(CFG_$(@F)),) boarddir = $(srctree)/arch/arm/boards imxcfg-$(CONFIG_MACH_FREESCALE_MX53_SMD) += $(boarddir)/freescale-mx53-smd/flash-header.imxcfg diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 3f6dd77..c631c33 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -66,6 +66,12 @@ help if enabled the imx-image tool is compiled +config ARCH_IMX_IMXIMAGE_SSL_SUPPORT + bool + help + This enables SSL support for the imx-image tool. This is required + for created images for HABv3. This adds openssl to the build dependencies + config ARCH_IMX_XLOAD bool depends on ARCH_IMX51 @@ -695,8 +701,12 @@ mw -l -d /dev/imx-ocotp 0x8C 0x00001234 mw -l -d /dev/imx-ocotp 0x88 0x56789ABC +config HAB + bool + config HABV4 tristate "HABv4 support" + select HAB depends on ARCH_IMX6 help High Assurance Boot, as found on i.MX28/i.MX6. @@ -735,6 +745,30 @@ endif +config HABV3 + tristate "HABv3 support" + select HAB + select ARCH_IMX_IMXIMAGE_SSL_SUPPORT + depends on ARCH_IMX25 + help + High Assurance Boot, as found on i.MX25. + +if HABV3 + +config HABV3_SRK_PEM + string "Path to SRK Certificate (PEM)" + default "../crts/SRK1_sha256_2048_65537_v3_ca_x509_crt.pem" + +config HABV3_CSF_CRT_DER + string "Path to CSF certificate" + default "../crts/CSF1_1_sha256_2048_65537_v3_ca_crt.der" + +config HABV3_IMG_CRT_DER + string "Path to IMG certificate" + default "../crts/IMG1_1_sha256_2048_65537_v3_usr_crt.der" + +endif + endmenu endif diff --git a/arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h b/arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h new file mode 100644 index 0000000..4b81d49 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/habv3-imx25-gencsf.h @@ -0,0 +1,43 @@ +/* + * This snippet can be included from a i.MX flash header configuration + * file for generating signed images. The necessary keys/certificates + * are expected in these config variables: + * + * CONFIG_HABV3_SRK_PEM + * CONFIG_HABV3_SRK_PEM + * CONFIG_HABV3_IMG_CRT_PEM + */ +super_root_key CONFIG_HABV3_SRK_PEM + +hab [Header] +hab Version = 3.0 +hab Security Configuration = Engineering +hab Hash Algorithm = SHA256 +hab Engine = RTIC +hab Certificate Format = WTLS +hab Signature Format = PKCS1 +hab UID = Generic +hab Code = 0x00 + +hab [Install SRK] +hab File = "not-used" + +hab [Install CSFK] +hab File = CONFIG_HABV3_CSF_CRT_DER + +hab [Authenticate CSF] +/* below is the command that unlock the access to the DryIce registers */ + +hab [Write Data] +hab Width = 4 +hab Address Data = 0x53FFC03C 0xCA693569 + +hab [Install Key] +hab Verification index = 1 +hab Target index = 2 +hab File = CONFIG_HABV3_IMG_CRT_DER + +hab [Authenticate Data] +hab Verification index = 2 + +hab_blocks diff --git a/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h b/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h new file mode 100644 index 0000000..1a143a8 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/habv4-imx6-gencsf.h @@ -0,0 +1,44 @@ +/* + * This snippet can be included from a i.MX flash header configuration + * file for generating signed images. The necessary keys/certificates + * are expected in these config variables: + * + * CONFIG_HABV4_TABLE_BIN + * CONFIG_HABV4_CSF_CRT_PEM + * CONFIG_HABV4_IMG_CRT_PEM + */ + +hab [Header] +hab Version = 4.1 +hab Hash Algorithm = sha256 +hab Engine Configuration = 0 +hab Certificate Format = X509 +hab Signature Format = CMS +hab Engine = CAAM + +hab [Install SRK] +hab File = CONFIG_HABV4_TABLE_BIN +hab # SRK index within SRK-Table 0..3 +hab Source index = 0 + +hab [Install CSFK] +hab File = CONFIG_HABV4_CSF_CRT_PEM + +hab [Authenticate CSF] + +hab [Unlock] +hab Engine = CAAM +hab Features = RNG + +hab [Install Key] +/* verification key index in key store (0, 2...5) */ +hab Verification index = 0 +/* target key index in key store (2...5) */ +hab Target index = 2 +hab File = CONFIG_HABV4_IMG_CRT_PEM + +hab [Authenticate Data] +/* verification key index in key store (2...5) */ +hab Verification index = 2 + +hab_blocks \ No newline at end of file diff --git a/drivers/Makefile b/drivers/Makefile index 3afbb61..8a8c8c4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -30,4 +30,4 @@ obj-y += rtc/ obj-$(CONFIG_FIRMWARE) += firmware/ obj-$(CONFIG_GENERIC_PHY) += phy/ -obj-$(CONFIG_HABV4) += habv4/ +obj-$(CONFIG_HAB) += hab/ diff --git a/drivers/hab/Makefile b/drivers/hab/Makefile new file mode 100644 index 0000000..8528ef9 --- /dev/null +++ b/drivers/hab/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_HABV4) += habv4.o +obj-$(CONFIG_HABV3) += habv3.o diff --git a/drivers/hab/habv3.c b/drivers/hab/habv3.c new file mode 100644 index 0000000..70f31a3 --- /dev/null +++ b/drivers/hab/habv3.c @@ -0,0 +1,78 @@ +/* + * 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; version 2. + * + * 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. + */ +#define pr_fmt(fmt) "HABv3: " fmt + +#include +#include +#include + +struct hab_status { + u8 value; + const char *str; +}; + +static struct hab_status hab_status[] = { + { 0x8d, "data specified is out of bounds" }, + { 0x55, "error during assert verification" }, + { 0x36, "hash verification failed" }, + { 0x33, "certificate parsing failed or the certificate contained an unsupported key" }, + { 0x35, "signature verification failed" }, + { 0x4B, "CSF command sequence contains unsupported command identifier" }, + { 0x4e, "absence of expected CSF header" }, + { 0x4d, "CSF length is unsupported" }, + { 0x2e, "CSF TYPE does not match processor TYPE" }, + { 0x2d, "CSF UID does not match either processor UID or generic UID" }, + { 0x3a, "CSF customer/product code does not match processor customer/product code" }, + { 0x87, "key indexis either unsupported, or an attempt is made to overwrite the SRK from a CSF command" }, + { 0x17, "SCC unexpectedly not in secure state" }, + { 0x1e, "secureRAM secret key invalid" }, + { 0x1d, "secureRAM initialization failure" }, + { 0x1b, "secureRAM self test failure" }, + { 0x2b, "secureRAM internal failure" }, + { 0x27, "secureRAM secrect key unexpectedly in use" }, + { 0x8b, "an attempt is made to read a key from the list of subordinate public keys at a location " + "where no key is installed" }, + { 0x8e, "algorithm type is either invalid or ortherwise unsupported" }, + { 0x66, "write operation to register failed" }, + { 0x63, "DCD invalid" }, + { 0x6f, "RAM application pointer is NULL or ERASED_FLASH" }, + { 0x69, "CSF missing when HAB TYPE is not HAB-disabled" }, + { 0x6a, "NANDFC boot buffer load failed" }, + { 0x6c, "Exception has occured" }, + { 0x67, "INT_BOOT fuse is blown but BOOT pins are set for external boot" }, + { 0x88, "Successful download completion" }, +}; + +int imx_habv3_get_status(uint32_t status) +{ + int i; + + if (status == 0xf0) { + pr_info("status OK\n"); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(hab_status); i++) { + if (hab_status[i].value == status) { + pr_err("status: 0x%02x: %s\n", status, hab_status[i].str); + return -EPERM; + } + } + + pr_err("unknown status code 0x%02x\n", status); + + return -EPERM; +} + +int imx25_hab_get_status(void) +{ + return imx_habv3_get_status(readl(IOMEM(0x780018d4))); +} \ No newline at end of file diff --git a/drivers/hab/habv4.c b/drivers/hab/habv4.c new file mode 100644 index 0000000..91dbb7a --- /dev/null +++ b/drivers/hab/habv4.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2014, 2015 Marc Kleine-Budde + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * 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. + */ + +#define pr_fmt(fmt) "HABv4: " fmt + +#include +#include +#include + +#include + +#define HABV4_RVT_IMX28 0xffff8af8 +#define HABV4_RVT_IMX6_OLD 0x00000094 +#define HABV4_RVT_IMX6_NEW 0x00000098 + +enum hab_tag { + HAB_TAG_IVT = 0xd1, /* Image Vector Table */ + HAB_TAG_DCD = 0xd2, /* Device Configuration Data */ + HAB_TAG_CSF = 0xd4, /* Command Sequence File */ + HAB_TAG_CRT = 0xd7, /* Certificate */ + HAB_TAG_SIG = 0xd8, /* Signature */ + HAB_TAG_EVT = 0xdb, /* Event */ + HAB_TAG_RVT = 0xdd, /* ROM Vector Table */ + HAB_TAG_WRP = 0x81, /* Wrapped Key */ + HAB_TAG_MAC = 0xac, /* Message Authentication Code */ +}; + +/* Status definitions */ +enum hab_status { + HAB_STATUS_ANY = 0x00, /* Match any status in report_event */ + HAB_STATUS_FAILURE = 0x33, /* Operation failed */ + HAB_STATUS_WARNING = 0x69, /* Operation completed with warning */ + HAB_STATUS_SUCCESS = 0xf0, /* Operation completed successfully */ +}; + +/* Security Configuration definitions */ +enum hab_config { + HAB_CONFIG_FAB = 0x00, /* Un-programmed IC */ + HAB_CONFIG_RETURN = 0x33, /* Field Return IC */ + HAB_CONFIG_OPEN = 0xf0, /* Non-secure IC */ + HAB_CONFIG_CLOSED = 0xcc, /* Secure IC */ +}; + +/* State definitions */ +enum hab_state { + HAB_STATE_INITIAL = 0x33, /* Initialising state (transitory) */ + HAB_STATE_CHECK = 0x55, /* Check state (non-secure) */ + HAB_STATE_NONSECURE = 0x66, /* Non-secure state */ + HAB_STATE_TRUSTED = 0x99, /* Trusted state */ + HAB_STATE_SECURE = 0xaa, /* Secure state */ + HAB_STATE_FAIL_SOFT = 0xcc, /* Soft fail state */ + HAB_STATE_FAIL_HARD = 0xff, /* Hard fail state (terminal) */ + HAB_STATE_NONE = 0xf0, /* No security state machine */ +}; + +enum hab_target { + HAB_TARGET_MEMORY = 0x0f, /* Check memory white list */ + HAB_TARGET_PERIPHERAL = 0xf0, /* Check peripheral white list*/ + HAB_TARGET_ANY = 0x55, /* Check memory & peripheral white list */ +}; + +enum hab_assertion { + HAB_ASSERTION_BLOCK = 0x0, /* Check if memory is authenticated after CSF */ +}; + +struct hab_header { + uint8_t tag; + uint16_t len; /* len including the header */ + uint8_t par; +} __packed; + +typedef enum hab_status hab_loader_callback_fn(void **start, uint32_t *bytes, const void *boot_data); + +struct habv4_rvt { + struct hab_header header; + enum hab_status (*entry)(void); + enum hab_status (*exit)(void); + enum hab_status (*check_target)(enum hab_target target, const void *start, uint32_t bytes); + void *(*authenticate_image)(uint8_t cid, uint32_t ivt_offset, void **start, uint32_t *bytes, hab_loader_callback_fn *loader); + enum hab_status (*run_dcd)(const void *dcd); + enum hab_status (*run_csf)(const void *csf, uint8_t cid); + enum hab_status (*assert)(enum hab_assertion assertion, const void *data, uint32_t count); + enum hab_status (*report_event)(enum hab_status status, uint32_t index, void *event, uint32_t *bytes); + enum hab_status (*report_status)(enum hab_config *config, enum hab_state *state); + void (*failsafe)(void); +} __packed; + +static const char *habv4_get_status_str(enum hab_status status) +{ + switch (status) { + case HAB_STATUS_ANY: + return "Match any status in report_event"; break; + case HAB_STATUS_FAILURE: + return "Operation failed"; break; + case HAB_STATUS_WARNING: + return "Operation completed with warning"; break; + case HAB_STATUS_SUCCESS: + return "Operation completed successfully"; break; + } + + return ""; +} + +static const char *habv4_get_config_str(enum hab_config config) +{ + switch (config) { + case HAB_CONFIG_FAB: + return "Un-programmed IC"; break; + case HAB_CONFIG_RETURN: + return "Field Return IC"; break; + case HAB_CONFIG_OPEN: + return "Non-secure IC"; break; + case HAB_CONFIG_CLOSED: + return "Secure IC"; break; + } + + return ""; +} + +static const char *habv4_get_state_str(enum hab_state state) +{ + switch (state) { + case HAB_STATE_INITIAL: + return "Initialising state (transitory)"; break; + case HAB_STATE_CHECK: + return "Check state (non-secure)"; break; + case HAB_STATE_NONSECURE: + return "Non-secure state"; break; + case HAB_STATE_TRUSTED: + return "Trusted state"; break; + case HAB_STATE_SECURE: + return "Secure state"; break; + case HAB_STATE_FAIL_SOFT: + return "Soft fail state"; break; + case HAB_STATE_FAIL_HARD: + return "Hard fail state (terminal)"; break; + case HAB_STATE_NONE: + return "No security state machine"; break; + } + + return ""; +} + +static void habv4_display_event(uint8_t *data, uint32_t len) +{ + unsigned int i; + + if (data && len) { + for (i = 0; i < len; i++) { + if (i == 0) + printf(" %02x", data[i]); + else if ((i % 8) == 0) + printf("\n %02x", data[i]); + else if ((i % 4) == 0) + printf(" %02x", data[i]); + else + printf(" %02x", data[i]); + } + } + printf("\n\n"); +} + +static int habv4_get_status(const struct habv4_rvt *rvt) +{ + uint8_t data[256]; + uint32_t len = sizeof(data); + uint32_t index = 0; + enum hab_status status; + enum hab_config config = 0x0; + enum hab_state state = 0x0; + + if (rvt->header.tag != HAB_TAG_RVT) { + pr_err("ERROR - RVT not found!\n"); + return -EINVAL; + } + + status = rvt->report_status(&config, &state); + pr_info("Status: %s (0x%02x)\n", habv4_get_status_str(status), status); + pr_info("Config: %s (0x%02x)\n", habv4_get_config_str(config), config); + pr_info("State: %s (0x%02x)\n", habv4_get_state_str(state), state); + + if (status == HAB_STATUS_SUCCESS) { + pr_info("No HAB Failure Events Found!\n\n"); + return 0; + } + + while (rvt->report_event(HAB_STATUS_FAILURE, index, data, &len) == HAB_STATUS_SUCCESS) { + printf("-------- HAB Event %d --------\n" + "event data:\n", index); + + habv4_display_event(data, len); + len = sizeof(data); + index++; + } + + /* Check reason for stopping */ + if (rvt->report_event(HAB_STATUS_ANY, index, NULL, &len) == HAB_STATUS_SUCCESS) + pr_err("ERROR: Recompile with larger event data buffer (at least %d bytes)\n\n", len); + + return -EPERM; +} + +int imx6_hab_get_status(void) +{ + const struct habv4_rvt *rvt; + + rvt = (void *)HABV4_RVT_IMX6_OLD; + if (rvt->header.tag == HAB_TAG_RVT) + return habv4_get_status(rvt); + + rvt = (void *)HABV4_RVT_IMX6_NEW; + if (rvt->header.tag == HAB_TAG_RVT) + return habv4_get_status(rvt); + + pr_err("ERROR - RVT not found!\n"); + + return -EINVAL; +} + +int imx28_hab_get_status(void) +{ + const struct habv4_rvt *rvt = (void *)HABV4_RVT_IMX28; + + return habv4_get_status(rvt); +} \ No newline at end of file diff --git a/drivers/habv4/Makefile b/drivers/habv4/Makefile deleted file mode 100644 index 40b3253..0000000 --- a/drivers/habv4/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += habv4.o diff --git a/drivers/habv4/habv4.c b/drivers/habv4/habv4.c deleted file mode 100644 index 5ace0de..0000000 --- a/drivers/habv4/habv4.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2014, 2015 Marc Kleine-Budde - * Copyright (C) 2010 Freescale Semiconductor, Inc. - * - * 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. - */ - -#define pr_fmt(fmt) "HABv4: " fmt - -#include -#include -#include - -#include - -#define HABV4_RVT_IMX28 0xffff8af8 -#define HABV4_RVT_IMX6 0x00000094 - -enum hab_tag { - HAB_TAG_IVT = 0xd1, /* Image Vector Table */ - HAB_TAG_DCD = 0xd2, /* Device Configuration Data */ - HAB_TAG_CSF = 0xd4, /* Command Sequence File */ - HAB_TAG_CRT = 0xd7, /* Certificate */ - HAB_TAG_SIG = 0xd8, /* Signature */ - HAB_TAG_EVT = 0xdb, /* Event */ - HAB_TAG_RVT = 0xdd, /* ROM Vector Table */ - HAB_TAG_WRP = 0x81, /* Wrapped Key */ - HAB_TAG_MAC = 0xac, /* Message Authentication Code */ -}; - -/* Status definitions */ -enum hab_status { - HAB_STATUS_ANY = 0x00, /* Match any status in report_event */ - HAB_STATUS_FAILURE = 0x33, /* Operation failed */ - HAB_STATUS_WARNING = 0x69, /* Operation completed with warning */ - HAB_STATUS_SUCCESS = 0xf0, /* Operation completed successfully */ -}; - -/* Security Configuration definitions */ -enum hab_config { - HAB_CONFIG_FAB = 0x00, /* Un-programmed IC */ - HAB_CONFIG_RETURN = 0x33, /* Field Return IC */ - HAB_CONFIG_OPEN = 0xf0, /* Non-secure IC */ - HAB_CONFIG_CLOSED = 0xcc, /* Secure IC */ -}; - -/* State definitions */ -enum hab_state { - HAB_STATE_INITIAL = 0x33, /* Initialising state (transitory) */ - HAB_STATE_CHECK = 0x55, /* Check state (non-secure) */ - HAB_STATE_NONSECURE = 0x66, /* Non-secure state */ - HAB_STATE_TRUSTED = 0x99, /* Trusted state */ - HAB_STATE_SECURE = 0xaa, /* Secure state */ - HAB_STATE_FAIL_SOFT = 0xcc, /* Soft fail state */ - HAB_STATE_FAIL_HARD = 0xff, /* Hard fail state (terminal) */ - HAB_STATE_NONE = 0xf0, /* No security state machine */ -}; - -enum hab_target { - HAB_TARGET_MEMORY = 0x0f, /* Check memory white list */ - HAB_TARGET_PERIPHERAL = 0xf0, /* Check peripheral white list*/ - HAB_TARGET_ANY = 0x55, /* Check memory & peripheral white list */ -}; - -enum hab_assertion { - HAB_ASSERTION_BLOCK = 0x0, /* Check if memory is authenticated after CSF */ -}; - -struct hab_header { - uint8_t tag; - uint16_t len; /* len including the header */ - uint8_t par; -} __packed; - -typedef enum hab_status hab_loader_callback_fn(void **start, uint32_t *bytes, const void *boot_data); - -struct habv4_rvt { - struct hab_header header; - enum hab_status (*entry)(void); - enum hab_status (*exit)(void); - enum hab_status (*check_target)(enum hab_target target, const void *start, uint32_t bytes); - void *(*authenticate_image)(uint8_t cid, uint32_t ivt_offset, void **start, uint32_t *bytes, hab_loader_callback_fn *loader); - enum hab_status (*run_dcd)(const void *dcd); - enum hab_status (*run_csf)(const void *csf, uint8_t cid); - enum hab_status (*assert)(enum hab_assertion assertion, const void *data, uint32_t count); - enum hab_status (*report_event)(enum hab_status status, uint32_t index, void *event, uint32_t *bytes); - enum hab_status (*report_status)(enum hab_config *config, enum hab_state *state); - void (*failsafe)(void); -} __packed; - -static const struct habv4_rvt *__rvt; - -static inline const struct habv4_rvt *habv4_get_rvt(void) -{ - if (__rvt) - return __rvt; - - if (cpu_is_mx28()) - __rvt = (void *)HABV4_RVT_IMX28; - else if (cpu_is_mx6()) - __rvt = (void *)HABV4_RVT_IMX6; - - if (__rvt->header.tag != HAB_TAG_RVT) { - pr_err("ERROR - RVT not found!\n"); - return NULL; - } - - pr_info("Found RVT v%d.%d\n", __rvt->header.par >> 4, - __rvt->header.par & 0xf); - - return __rvt; -} - -static const char *habv4_get_status_str(enum hab_status status) -{ - switch (status) { - case HAB_STATUS_ANY: - return "Match any status in report_event"; break; - case HAB_STATUS_FAILURE: - return "Operation failed"; break; - case HAB_STATUS_WARNING: - return "Operation completed with warning"; break; - case HAB_STATUS_SUCCESS: - return "Operation completed successfully"; break; - } - - return ""; -} - -static const char *habv4_get_config_str(enum hab_config config) -{ - switch (config) { - case HAB_CONFIG_FAB: - return "Un-programmed IC"; break; - case HAB_CONFIG_RETURN: - return "Field Return IC"; break; - case HAB_CONFIG_OPEN: - return "Non-secure IC"; break; - case HAB_CONFIG_CLOSED: - return "Secure IC"; break; - } - - return ""; -} - -static const char *habv4_get_state_str(enum hab_state state) -{ - switch (state) { - case HAB_STATE_INITIAL: - return "Initialising state (transitory)"; break; - case HAB_STATE_CHECK: - return "Check state (non-secure)"; break; - case HAB_STATE_NONSECURE: - return "Non-secure state"; break; - case HAB_STATE_TRUSTED: - return "Trusted state"; break; - case HAB_STATE_SECURE: - return "Secure state"; break; - case HAB_STATE_FAIL_SOFT: - return "Soft fail state"; break; - case HAB_STATE_FAIL_HARD: - return "Hard fail state (terminal)"; break; - case HAB_STATE_NONE: - return "No security state machine"; break; - } - - return ""; -} - -static void habv4_display_event(uint8_t *data, uint32_t len) -{ - unsigned int i; - - if (data && len) { - for (i = 0; i < len; i++) { - if (i == 0) - printf(" %02x", data[i]); - else if ((i % 8) == 0) - printf("\n %02x", data[i]); - else if ((i % 4) == 0) - printf(" %02x", data[i]); - else - printf(" %02x", data[i]); - } - } - printf("\n\n"); -} - -int habv4_get_status(void) -{ - const struct habv4_rvt *rvt = habv4_get_rvt(); - uint8_t data[256]; - uint32_t len = sizeof(data); - uint32_t index = 0; - enum hab_status status; - enum hab_config config = 0x0; - enum hab_state state = 0x0; - - if (!rvt) - return -ENODEV; - - status = rvt->report_status(&config, &state); - pr_info("Status: %s (0x%02x)\n", habv4_get_status_str(status), status); - pr_info("Config: %s (0x%02x)\n", habv4_get_config_str(config), config); - pr_info("State: %s (0x%02x)\n", habv4_get_state_str(state), state); - - if (status == HAB_STATUS_SUCCESS) { - pr_info("No HAB Failure Events Found!\n\n"); - return 0; - } - - while (rvt->report_event(HAB_STATUS_FAILURE, index, data, &len) == HAB_STATUS_SUCCESS) { - printf("-------- HAB Event %d --------\n" - "event data:\n", index); - - habv4_display_event(data, len); - len = sizeof(data); - index++; - } - - /* Check reason for stopping */ - if (rvt->report_event(HAB_STATUS_ANY, index, NULL, &len) == HAB_STATUS_SUCCESS) - pr_err("ERROR: Recompile with larger event data buffer (at least %d bytes)\n\n", len); - - return -EPERM; -} diff --git a/images/Makefile b/images/Makefile index 6a44511..da9cc8d 100644 --- a/images/Makefile +++ b/images/Makefile @@ -104,7 +104,6 @@ include $(srctree)/images/Makefile.am33xx include $(srctree)/images/Makefile.imx -include $(srctree)/images/Makefile.imxhabv4 include $(srctree)/images/Makefile.mvebu include $(srctree)/images/Makefile.mxs include $(srctree)/images/Makefile.omap3 @@ -143,5 +142,6 @@ clean-files := *.pbl *.pblb *.pblx *.map start_*.imximg *.img barebox.z start_*.kwbimg \ start_*.kwbuartimg *.socfpgaimg *.mlo *.t20img *.t20img.cfg *.t30img \ - *.t30img.cfg *.t124img *.t124img.cfg *.mlospi *.mlo *.mxsbs *.mxssd + *.t30img.cfg *.t124img *.t124img.cfg *.mlospi *.mlo *.mxsbs *.mxssd \ + start_*.simximg start_*.usimximg clean-files += pbl.lds diff --git a/images/Makefile.imx b/images/Makefile.imx index ea9346a..4ab2dcb 100644 --- a/images/Makefile.imx +++ b/images/Makefile.imx @@ -8,12 +8,18 @@ ifdef CONFIG_ARCH_IMX_XLOAD $(obj)/%.imximg: $(obj)/% FORCE $(call cmd,check_file_size,$<,$(CONFIG_ARCH_IMX_UNUSED_IRAM_SIZE)) - $(call if_changed,imx_image) + $(call if_changed,imx_image,$(CFG_$(@F)),) else $(obj)/%.imximg: $(obj)/% FORCE - $(call if_changed,imx_image) + $(call if_changed,imx_image,$(CFG_$(@F)),) endif +$(obj)/%.simximg: $(obj)/% FORCE + $(call if_changed,imx_image,$(CFG_$(patsubst %.simximg,%.imximg,$(@F))),-s) + +$(obj)/%.usimximg: $(obj)/% FORCE + $(call if_changed,imx_image,$(CFG_$(patsubst %.usimximg,%.imximg,$(@F))),-s -u) + quiet_cmd_imx_sram_img ?= IMX-SRAM-IMG $@ cmd_imx_sram_img ?= cat $(obj)/$(patsubst %.imx-sram-img,%.pblb,$(2)) > $@; \ $(call size_append, $(obj)/barebox.z) >> $@; \ diff --git a/images/Makefile.imxhabv4 b/images/Makefile.imxhabv4 deleted file mode 100644 index 9eb9538..0000000 --- a/images/Makefile.imxhabv4 +++ /dev/null @@ -1,48 +0,0 @@ -# -*-makefile-*- -# -# barebox image generation Makefile for HABv4 images -# - -# default csf templates -havb4_imx6csf = $(srctree)/scripts/habv4/habv4-imx6.csf.in -habv4_imx2csf = $(srctree)/scripts/habv4/habv4-imx28.csf.in - -# %.imximg.prep - Convert in i.MX image, with preparation for signature -# ---------------------------------------------------------------- -quiet_cmd_imx_prep_image = IMX-PREP-IMG $@ - cmd_imx_prep_image = $(CPP) $(imxcfg_cpp_flags) -o $(imximg-tmp) $(word 2,$^) ; \ - $< -o $@ -b -c $(imximg-tmp) -p -f $(word 3,$^) - -.SECONDEXPANSION: -$(obj)/%.imximg.prep: $(objtree)/scripts/imx/imx-image $$(CFG_%.imximg) $(obj)/% - $(call if_changed,imx_prep_image) - -# %.habv4.csf - create Command Sequence File from template -# ---------------------------------------------------------------- -quiet_cmd_csf = CSF $@ - cmd_csf = TABLE_BIN=$(CONFIG_HABV4_TABLE_BIN) \ - CSF_CRT_PEM=$(CONFIG_HABV4_CSF_CRT_PEM) \ - IMG_CRT_PEM=$(CONFIG_HABV4_IMG_CRT_PEM) \ - $< -f $(word 2,$^) -c $(word 3,$^) -i $(word 4,$^) -o $@ - -.SECONDEXPANSION: -$(obj)/%.habv4.csf: $(srctree)/scripts/habv4/gencsf.sh $(obj)/%.prep $$(CFG_%) $$(CSF_%) - $(call if_changed,csf) - -# %.habv4.sig - create signature and pad to 0x2000 -# ---------------------------------------------------------------- -CST = cst -quiet_cmd_habv4_sig = HAB4SIG $@ - cmd_habv4_sig = $(CST) -o $(imximg-tmp) < $(word 2,$^) > /dev/null; \ - $(OBJCOPY) -I binary -O binary --pad-to 0x2000 --gap-fill=0x5a $(imximg-tmp) $@ - -$(obj)/%.habv4.sig: $(obj)/%.prep $(obj)/%.habv4.csf - $(call if_changed,habv4_sig) - -# %.imximg.signed - concatenate bootloader and signature -# ---------------------------------------------------------------- -quiet_cmd_cat = CAT $@ - cmd_cat = cat $^ > $@ - -$(obj)/%.imximg.signed: $(obj)/%.imximg.prep $(obj)/%.imximg.habv4.sig - $(call if_changed,cat) diff --git a/include/hab.h b/include/hab.h new file mode 100644 index 0000000..818d7ca --- /dev/null +++ b/include/hab.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2014, 2015 Marc Kleine-Budde + * + * 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. + */ + +#ifndef __HABV4_H +#define __HABV4_H + +#ifdef CONFIG_HABV4 +int imx28_hab_get_status(void); +int imx6_hab_get_status(void); +#else +static inline int imx28_hab_get_status(void) +{ + return -EPERM; +} +static inline int imx6_hab_get_status(void) +{ + return -EPERM; +} +#endif + +#ifdef CONFIG_HABV3 +int imx25_hab_get_status(void); +#else +static inline int imx25_hab_get_status(void) +{ + return -EPERM; +} +#endif + +#endif /* __HABV4_H */ diff --git a/include/habv4.h b/include/habv4.h deleted file mode 100644 index f9bf74f..0000000 --- a/include/habv4.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2014, 2015 Marc Kleine-Budde - * - * 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. - */ - -#ifndef __HABV4_H -#define __HABV4_H - -#ifdef CONFIG_HABV4 -int habv4_get_status(void); -#else -static inline int habv4_get_status(void) -{ - return -EPERM; -} -#endif - -#endif /* __HABV4_H */ diff --git a/scripts/Makefile b/scripts/Makefile index a3f6222..aeedcac 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -20,6 +20,7 @@ hostprogs-$(CONFIG_ARCH_ZYNQ) += zynq_mkimage hostprogs-$(CONFIG_ARCH_SOCFPGA) += socfpga_mkimage hostprogs-$(CONFIG_ARCH_MXS) += mxsimage mxsboot +HOSTCFLAGS += -I$(srctree)/scripts/include/ HOSTLOADLIBES_mxsimage = `pkg-config --libs openssl` HOSTCFLAGS_mxs-usb-loader.o = `pkg-config --cflags libusb-1.0` HOSTLOADLIBES_mxs-usb-loader = `pkg-config --libs libusb-1.0` diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index e991f33..27365d8 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -430,8 +430,8 @@ imximg-tmp = $(subst $(comma),_,$(dot-target).imxcfg.tmp) quiet_cmd_imx_image = IMX-IMG $@ - cmd_imx_image = $(CPP) $(imxcfg_cpp_flags) -o $(imximg-tmp) $(CFG_$(@F)) ; \ - $(objtree)/scripts/imx/imx-image -o $@ -b -c $(imximg-tmp) -f $< + cmd_imx_image = $(CPP) $(imxcfg_cpp_flags) -o $(imximg-tmp) $(2) ; \ + $(objtree)/scripts/imx/imx-image -o $@ -b -c $(imximg-tmp) $(3) -f $< quiet_cmd_kwb_image = KWB $@ cmd_kwb_image = scripts/kwbimage -p $< $(OPTS_$(@F)) -o $@ diff --git a/scripts/habv4/gencsf.sh b/scripts/habv4/gencsf.sh deleted file mode 100755 index 2c1c34a..0000000 --- a/scripts/habv4/gencsf.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh - -set -e - -while getopts "f:c:i:o:" opt; do - case $opt in - f) - file=$OPTARG - ;; - c) - cfg=$OPTARG - ;; - i) - in=$OPTARG - ;; - o) - out=$OPTARG - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - exit 1 - ;; - esac -done - -if [ ! -e $file -o ! -e $cfg -o ! -e $in ]; then - echo "file not found!" - exit 1 -fi - -# -# extract and set as shell vars: -# loadaddr= -# dcdofs= -# -eval $(sed -n -e "s/^[[:space:]]*\(loadaddr\|dcdofs\)[[:space:]]*\(0x[0-9]*\)/\1=\2/p" $cfg) - -length=$(stat -c '%s' $file) - -sed -e "s:@TABLE_BIN@:$TABLE_BIN:" \ - -e "s:@CSF_CRT_PEM@:$CSF_CRT_PEM:" \ - -e "s:@IMG_CRT_PEM@:$IMG_CRT_PEM:" \ - -e "s:@LOADADDR@:$loadaddr:" \ - -e "s:@OFFSET@:0:" \ - -e "s:@LENGTH@:$length:" \ - -e "s:@FILE@:$file:" \ - $in > $out diff --git a/scripts/habv4/habv4-imx28.csf.in b/scripts/habv4/habv4-imx28.csf.in deleted file mode 100644 index 5efd25b..0000000 --- a/scripts/habv4/habv4-imx28.csf.in +++ /dev/null @@ -1,33 +0,0 @@ -[Header] -Version = 4.0 -Hash Algorithm = sha256 -Engine Configuration = 0 -Certificate Format = X509 -Signature Format = CMS -Engine = DCP - -[Install SRK] -File = "@TABLE_BIN@" -# SRK index within SRK-Table 0..3 -Source index = 0 - -[Install CSFK] -File = "@CSF_CRT_PEM@" - -[Authenticate CSF] - -[Install Key] -# verification key index in key store (0, 2...5) -Verification index = 0 -# target key index in key store (2...5) -Target index = 2 -File = "@IMG_CRT_PEM@" - -[Authenticate Data] -# verification key index in key store (2...5) -Verification index = 2 -# "starting load address in memory" -# "starting offset within the source file" -# "length (in bytes)" -# "file (binary)" -Blocks = @LOADADDR@ @OFFSET@ @LENGTH@ "@FILE@" diff --git a/scripts/habv4/habv4-imx6.csf.in b/scripts/habv4/habv4-imx6.csf.in deleted file mode 100644 index 11a5db9..0000000 --- a/scripts/habv4/habv4-imx6.csf.in +++ /dev/null @@ -1,37 +0,0 @@ -[Header] -Version = 4.1 -Hash Algorithm = sha256 -Engine Configuration = 0 -Certificate Format = X509 -Signature Format = CMS -Engine = CAAM - -[Install SRK] -File = "@TABLE_BIN@" -# SRK index within SRK-Table 0..3 -Source index = 0 - -[Install CSFK] -File = "@CSF_CRT_PEM@" - -[Authenticate CSF] - -[Unlock] -Engine = CAAM -Features = RNG - -[Install Key] -# verification key index in key store (0, 2...5) -Verification index = 0 -# target key index in key store (2...5) -Target index = 2 -File = "@IMG_CRT_PEM@" - -[Authenticate Data] -# verification key index in key store (2...5) -Verification index = 2 -# "starting load address in memory" -# "starting offset within the source file" -# "length (in bytes)" -# "file (binary)" -Blocks = @LOADADDR@ @OFFSET@ @LENGTH@ "@FILE@" diff --git a/scripts/imx/Makefile b/scripts/imx/Makefile index ee0acc1..d9f0c51 100644 --- a/scripts/imx/Makefile +++ b/scripts/imx/Makefile @@ -7,6 +7,10 @@ HOSTLOADLIBES_imx-usb-loader = `pkg-config --libs libusb-1.0` HOSTCFLAGS_imx-image.o = -I$(srctree) +ifdef CONFIG_ARCH_IMX_IMXIMAGE_SSL_SUPPORT +HOSTCFLAGS_imx-image.o += -DIMXIMAGE_SSL_SUPPORT +HOSTLOADLIBES_imx-image = `pkg-config --libs openssl` +endif -imx-usb-loader-objs := imx-usb-loader.o -imx-image-objs := imx-image.o +imx-usb-loader-objs := imx-usb-loader.o imx.o +imx-image-objs := imx-image.o imx.o diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index e8d9dbf..20815bf 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. * */ +#define _GNU_SOURCE #include #include #include @@ -26,45 +27,29 @@ #include #include #include +#include +#include + +#include "imx.h" #include -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) -#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) - #define MAX_DCD 1024 -#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ #define CSF_LEN 0x2000 /* length of the CSF (needed for HAB) */ -static uint32_t image_load_addr; -static uint32_t image_dcd_offset; static uint32_t dcdtable[MAX_DCD]; static int curdcd; -static int header_version; -static int cpu_type; static int add_barebox_header; -static int prepare_sign; +static int create_usb_image; +static char *prgname; /* * ============================================================================ * i.MX flash header v1 handling. Found on i.MX35 and i.MX51 * ============================================================================ */ -struct imx_flash_header { - uint32_t app_code_jump_vector; - uint32_t app_code_barker; - uint32_t app_code_csf; - uint32_t dcd_ptr_ptr; - uint32_t super_root_key; - uint32_t dcd; - uint32_t app_dest; - uint32_t dcd_barker; - uint32_t dcd_block_len; -} __attribute__((packed)); #define FLASH_HEADER_OFFSET 0x400 -#define DCD_BARKER 0xb17219e9 static uint32_t bb_header[] = { 0xea0003fe, /* b 0x1000 */ @@ -89,11 +74,141 @@ 0x55555555, }; -static int add_header_v1(void *buf, int offset, uint32_t loadaddr, uint32_t imagesize) +struct hab_rsa_public_key { + uint8_t rsa_exponent[4]; /* RSA public exponent */ + uint32_t rsa_modulus; /* RSA modulus pointer */ + uint16_t exponent_size; /* Exponent size in bytes */ + uint16_t modulus_size; /* Modulus size in bytes*/ + uint8_t init_flag; /* Indicates if key initialized */ +}; + +#ifdef IMXIMAGE_SSL_SUPPORT +#define PUBKEY_ALGO_LEN 2048 + +#include +#include +#include +#include +#include +#include +#include + +static int extract_key(const char *certfile, uint8_t **modulus, int *modulus_len, + uint8_t **exponent, int *exponent_len) +{ + char buf[PUBKEY_ALGO_LEN]; + int pubkey_algonid; + const char *sslbuf; + EVP_PKEY *pkey; + FILE *fp; + X509 *cert; + RSA *rsa_key; + + fp = fopen(certfile, "r"); + if (!fp) { + fprintf(stderr, "unable to open certfile: %s\n", certfile); + return -errno; + } + + cert = PEM_read_X509(fp, NULL, NULL, NULL); + if (!cert) { + fprintf(stderr, "unable to parse certificate in: %s\n", certfile); + fclose(fp); + return -errno; + } + + fclose(fp); + + pubkey_algonid = OBJ_obj2nid(cert->cert_info->key->algor->algorithm); + if (pubkey_algonid == NID_undef) { + fprintf(stderr, "unable to find specified public key algorithm name.\n"); + return -EINVAL; + } + + if (pubkey_algonid != NID_rsaEncryption) + return -EINVAL; + + sslbuf = OBJ_nid2ln(pubkey_algonid); + strncpy(buf, sslbuf, PUBKEY_ALGO_LEN); + + pkey = X509_get_pubkey(cert); + if (!pkey) { + fprintf(stderr, "unable to extract public key from certificate"); + return -EINVAL; + } + + rsa_key = pkey->pkey.rsa; + if (!rsa_key) { + fprintf(stderr, "unable to extract RSA public key"); + return -EINVAL; + } + + *modulus_len = BN_num_bytes(rsa_key->n); + *modulus = malloc(*modulus_len); + BN_bn2bin(rsa_key->n, *modulus); + + *exponent_len = BN_num_bytes(rsa_key->e); + *exponent = malloc(*exponent_len); + BN_bn2bin(rsa_key->e, *exponent); + + EVP_PKEY_free(pkey); + X509_free(cert); + + return 0; +} + +static int add_srk(void *buf, int offset, uint32_t loadaddr, const char *srkfile) +{ + struct imx_flash_header *hdr = buf + offset; + struct hab_rsa_public_key *key = buf + 0xc00; + uint8_t *exponent = NULL, *modulus = NULL, *modulus_dest; + int exponent_len = 0, modulus_len = 0; + int ret; + + hdr->super_root_key = loadaddr + 0xc00; + + key->init_flag = 1; + key->exponent_size = htole16(3); + + ret = extract_key(srkfile, &modulus, &modulus_len, &exponent, &exponent_len); + if (ret) + return ret; + + modulus_dest = (void *)(key + 1); + + memcpy(modulus_dest, modulus, modulus_len); + + key->modulus_size = htole16(modulus_len); + key->rsa_modulus = htole32(hdr->super_root_key + sizeof(*key)); + + if (exponent_len > 4) + return -EINVAL; + + key->exponent_size = exponent_len; + memcpy(&key->rsa_exponent, exponent, key->exponent_size); + + return 0; +} +#else +static int add_srk(void *buf, int offset, uint32_t loadaddr, const char *srkfile) +{ + fprintf(stderr, "This version of imx-image is compiled without SSL support\n"); + + return -EINVAL; +} +#endif /* IMXIMAGE_SSL_SUPPORT */ + +static int dcd_ptr_offset; +static uint32_t dcd_ptr_content; + +static int add_header_v1(struct config_data *data, void *buf) { struct imx_flash_header *hdr; int dcdsize = curdcd * sizeof(uint32_t); uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET; + int offset = data->image_dcd_offset; + uint32_t loadaddr = data->image_load_addr; + uint32_t imagesize = data->load_size; if (add_barebox_header) { memcpy(buf, bb_header, sizeof(bb_header)); @@ -108,10 +223,17 @@ hdr->app_code_csf = 0x0; hdr->dcd_ptr_ptr = loadaddr + offset + offsetof(struct imx_flash_header, dcd); hdr->super_root_key = 0x0; - hdr->dcd = loadaddr + offset + offsetof(struct imx_flash_header, dcd_barker); + hdr->dcd = loadaddr + offset + offsetof(struct imx_flash_header, dcd_barker); + hdr->app_dest = loadaddr; hdr->dcd_barker = DCD_BARKER; - hdr->dcd_block_len = dcdsize; + if (create_usb_image) { + dcd_ptr_offset = offsetof(struct imx_flash_header, dcd_block_len) + offset; + hdr->dcd_block_len = 0; + dcd_ptr_content = dcdsize; + } else { + hdr->dcd_block_len = dcdsize; + } buf += sizeof(struct imx_flash_header); @@ -119,6 +241,11 @@ buf += dcdsize; + if (data->csf) { + hdr->app_code_csf = loadaddr + imagesize; + imagesize += CSF_LEN; + } + *(uint32_t *)buf = imagesize; return 0; @@ -144,45 +271,14 @@ * ============================================================================ */ -struct imx_boot_data { - uint32_t start; - uint32_t size; - uint32_t plugin; -} __attribute__((packed)); - -#define TAG_IVT_HEADER 0xd1 -#define IVT_VERSION 0x40 -#define TAG_DCD_HEADER 0xd2 -#define DCD_VERSION 0x40 -#define TAG_WRITE 0xcc -#define TAG_CHECK 0xcf - -struct imx_ivt_header { - uint8_t tag; - uint16_t length; - uint8_t version; -} __attribute__((packed)); - -struct imx_flash_header_v2 { - struct imx_ivt_header header; - - uint32_t entry; - uint32_t reserved1; - uint32_t dcd_ptr; - uint32_t boot_data_ptr; - uint32_t self; - uint32_t csf; - uint32_t reserved2; - - struct imx_boot_data boot_data; - struct imx_ivt_header dcd_header; -} __attribute__((packed)); - -static int add_header_v2(void *buf, int offset, uint32_t loadaddr, uint32_t imagesize) +static int add_header_v2(struct config_data *data, void *buf) { struct imx_flash_header_v2 *hdr; int dcdsize = curdcd * sizeof(uint32_t); uint32_t *psize = buf + ARM_HEAD_SIZE_OFFSET; + int offset = data->image_dcd_offset; + uint32_t loadaddr = data->image_load_addr; + uint32_t imagesize = data->load_size; if (add_barebox_header) memcpy(buf, bb_header, sizeof(bb_header)); @@ -196,13 +292,18 @@ hdr->entry = loadaddr + HEADER_LEN; hdr->dcd_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, dcd_header); + if (create_usb_image) { + dcd_ptr_content = hdr->dcd_ptr; + dcd_ptr_offset = offsetof(struct imx_flash_header_v2, dcd_ptr) + offset; + hdr->dcd_ptr = 0; + } hdr->boot_data_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, boot_data); hdr->self = loadaddr + offset; hdr->boot_data.start = loadaddr; hdr->boot_data.size = imagesize; - if (prepare_sign) { + if (data->csf) { hdr->csf = loadaddr + imagesize; hdr->boot_data.size += CSF_LEN; } @@ -230,55 +331,10 @@ "-b add barebox header to image. If used, barebox recognizes\n" " the image as regular barebox image which can be used as\n" " second stage image\n" - "-p prepare image for signing\n" "-h this help\n", prgname); exit(1); } -#define MAXARGS 5 - -static int parse_line(char *line, char *argv[]) -{ - int nargs = 0; - - while (nargs < MAXARGS) { - - /* skip any white space */ - while ((*line == ' ') || (*line == '\t')) - ++line; - - if (*line == '\0') /* end of line, no more args */ - argv[nargs] = NULL; - - if (*line == '\0') { /* end of line, no more args */ - argv[nargs] = NULL; - return nargs; - } - - argv[nargs++] = line; /* begin of argument string */ - - /* find end of string */ - while (*line && (*line != ' ') && (*line != '\t')) - ++line; - - if (*line == '\0') { /* end of line, no more args */ - argv[nargs] = NULL; - return nargs; - } - - *line++ = '\0'; /* terminate current arg */ - } - - printf("** Too many args (max. %d) **\n", MAXARGS); - - return nargs; -} - -struct command { - const char *name; - int (*parse)(int argc, char *argv[]); -}; - static uint32_t last_write_cmd; static int last_cmd_len; static uint32_t *last_dcd; @@ -324,289 +380,6 @@ return 0; } -static const char *check_cmds[] = { - "while_all_bits_clear", /* while ((*address & mask) == 0); */ - "while_all_bits_set" , /* while ((*address & mask) == mask); */ - "while_any_bit_clear", /* while ((*address & mask) != mask); */ - "while_any_bit_set", /* while ((*address & mask) != 0); */ -}; - -static void do_cmd_check_usage(void) -{ - fprintf(stderr, - "usage: check \n" - " access width in bytes [1|2|4]\n" - "with one of:\n" - "while_all_bits_clear: while ((*addr & mask) == 0)\n" - "while_all_bits_set: while ((*addr & mask) == mask)\n" - "while_any_bit_clear: while ((*addr & mask) != mask)\n" - "while_any_bit_set: while ((*addr & mask) != 0)\n"); -} - -static int do_cmd_check(int argc, char *argv[]) -{ - uint32_t addr, mask, cmd; - int i, width; - const char *scmd; - - if (argc < 5) { - do_cmd_check_usage(); - return -EINVAL; - } - - width = strtoul(argv[1], NULL, 0) >> 3; - scmd = argv[2]; - addr = strtoul(argv[3], NULL, 0); - mask = strtoul(argv[4], NULL, 0); - - switch (width) { - case 1: - case 2: - case 4: - break; - default: - fprintf(stderr, "illegal width %d\n", width); - return -EINVAL; - }; - - if (curdcd > MAX_DCD - 3) { - fprintf(stderr, "At maximum %d dcd entried are allowed\n", MAX_DCD); - return -ENOMEM; - } - - for (i = 0; i < ARRAY_SIZE(check_cmds); i++) { - if (!strcmp(scmd, check_cmds[i])) - break; - } - - if (i == ARRAY_SIZE(check_cmds)) { - do_cmd_check_usage(); - return -EINVAL; - } - - cmd = (TAG_CHECK << 24) | (i << 3) | width | ((sizeof(uint32_t) * 3) << 8); - - check_last_dcd(cmd); - - dcdtable[curdcd++] = htobe32(cmd); - dcdtable[curdcd++] = htobe32(addr); - dcdtable[curdcd++] = htobe32(mask); - - return 0; -} - -static int do_cmd_write_mem(int argc, char *argv[]) -{ - uint32_t addr, val, width; - char *end; - - if (argc != 4) { - fprintf(stderr, "usage: wm [8|16|32] \n"); - return -EINVAL; - } - - width = strtoul(argv[1], &end, 0); - if (*end != '\0') { - fprintf(stderr, "illegal width token \"%s\"\n", argv[1]); - return -EINVAL; - } - - addr = strtoul(argv[2], &end, 0); - if (*end != '\0') { - fprintf(stderr, "illegal address token \"%s\"\n", argv[2]); - return -EINVAL; - } - - val = strtoul(argv[3], &end, 0); - if (*end != '\0') { - fprintf(stderr, "illegal value token \"%s\"\n", argv[3]); - return -EINVAL; - } - - width >>= 3; - - switch (width) { - case 1: - case 2: - case 4: - break; - default: - fprintf(stderr, "illegal width %d\n", width); - return -EINVAL; - }; - - switch (header_version) { - case 1: - return write_mem_v1(addr, val, width); - case 2: - return write_mem_v2(addr, val, width); - default: - return -EINVAL; - } -} - -static int do_loadaddr(int argc, char *argv[]) -{ - if (argc < 2) - return -EINVAL; - - image_load_addr = strtoul(argv[1], NULL, 0); - - return 0; -} - -static int do_dcd_offset(int argc, char *argv[]) -{ - if (argc < 2) - return -EINVAL; - - image_dcd_offset = strtoul(argv[1], NULL, 0); - - return 0; -} - -struct soc_type { - char *name; - int header_version; - int cpu_type; -}; - -static struct soc_type socs[] = { - { .name = "imx25", .header_version = 1, .cpu_type = 25}, - { .name = "imx35", .header_version = 1, .cpu_type = 35 }, - { .name = "imx51", .header_version = 1, .cpu_type = 51 }, - { .name = "imx53", .header_version = 2, .cpu_type = 53 }, - { .name = "imx6", .header_version = 2, .cpu_type = 6 }, -}; - -static int do_soc(int argc, char *argv[]) -{ - char *soc; - int i; - - if (argc < 2) - return -EINVAL; - - soc = argv[1]; - - for (i = 0; i < ARRAY_SIZE(socs); i++) { - if (!strcmp(socs[i].name, soc)) { - header_version = socs[i].header_version; - cpu_type = socs[i].cpu_type; - return 0; - } - } - - fprintf(stderr, "unkown SoC type \"%s\". Known SoCs are:\n", soc); - for (i = 0; i < ARRAY_SIZE(socs); i++) - fprintf(stderr, "%s ", socs[i].name); - fprintf(stderr, "\n"); - - return -EINVAL; -} - -struct command cmds[] = { - { - .name = "wm", - .parse = do_cmd_write_mem, - }, { - .name = "check", - .parse = do_cmd_check, - }, { - .name = "loadaddr", - .parse = do_loadaddr, - }, { - .name = "dcdofs", - .parse = do_dcd_offset, - }, { - .name = "soc", - .parse = do_soc, - }, -}; - -static char *readcmd(FILE *f) -{ - static char *buf; - char *str; - ssize_t ret; - - if (!buf) { - buf = malloc(4096); - if (!buf) - return NULL; - } - - str = buf; - *str = 0; - - while (1) { - ret = fread(str, 1, 1, f); - if (!ret) - return strlen(buf) ? buf : NULL; - - if (*str == '\n' || *str == ';') { - *str = 0; - return buf; - } - - str++; - } -} - -static int parse_config(const char *filename) -{ - FILE *f; - int lineno = 0; - char *line = NULL, *tmp; - char *argv[MAXARGS]; - int nargs, i, ret = 0; - - f = fopen(filename, "r"); - if (!f) { - fprintf(stderr, "Error: %s - Can't open DCD file\n", filename); - exit(1); - } - - while (1) { - line = readcmd(f); - if (!line) - break; - - lineno++; - - tmp = strchr(line, '#'); - if (tmp) - *tmp = 0; - - nargs = parse_line(line, argv); - if (!nargs) - continue; - - ret = -ENOENT; - - for (i = 0; i < ARRAY_SIZE(cmds); i++) { - if (!strcmp(cmds[i].name, argv[0])) { - ret = cmds[i].parse(nargs, argv); - if (ret) { - fprintf(stderr, "error in line %d: %s\n", - lineno, strerror(-ret)); - goto cleanup; - } - break; - } - } - - if (ret == -ENOENT) { - fprintf(stderr, "no such command: %s\n", argv[0]); - goto cleanup; - } - } - -cleanup: - fclose(f); - return ret; -} - static int xread(int fd, void *buf, int len) { int ret; @@ -659,21 +432,210 @@ return 0; } +static int check(struct config_data *data, uint32_t cmd, uint32_t addr, uint32_t mask) +{ + if (curdcd > MAX_DCD - 3) { + fprintf(stderr, "At maximum %d dcd entried are allowed\n", MAX_DCD); + return -ENOMEM; + } + + check_last_dcd(cmd); + + dcdtable[curdcd++] = htobe32(cmd); + dcdtable[curdcd++] = htobe32(addr); + dcdtable[curdcd++] = htobe32(mask); + + return 0; +} + +static int write_mem(struct config_data *data, uint32_t addr, uint32_t val, int width) +{ + switch (data->header_version) { + case 1: + return write_mem_v1(addr, val, width); + case 2: + return write_mem_v2(addr, val, width); + default: + return -EINVAL; + } +} + +/* + * This uses the Freescale Code Signing Tool (CST) to sign the image. + * The cst is expected to be executable as 'cst' or if exists, the content + * of the environment variable 'CST' is used. + */ +static int hab_sign(struct config_data *data) +{ + int fd, outfd, ret, lockfd; + char *csffile, *command; + struct stat s; + char *cst; + void *buf; + + cst = getenv("CST"); + if (!cst) + cst = "cst"; + + ret = asprintf(&csffile, "%s.csfbin", data->outfile); + if (ret < 0) + exit(1); + + ret = stat(csffile, &s); + if (!ret) { + if (S_ISREG(s.st_mode)) { + ret = unlink(csffile); + if (ret) { + fprintf(stderr, "Cannot remove %s: %s\n", + csffile, strerror(errno)); + return -errno; + } + } else { + fprintf(stderr, "%s exists and is no regular file\n", + csffile); + return -EINVAL; + } + } + + ret = asprintf(&command, "%s -o %s", cst, csffile); + if (ret < 0) + return -ENOMEM; + + /* + * The cst uses "csfsig.bin" as temporary file. This of course breaks when it's + * called multiple times as often happens with parallel builds. Until cst learns + * how to properly create temporary files without races lock accesses to this + * file. + */ + lockfd = open(prgname, O_RDONLY); + if (lockfd < 0) { + fprintf(stderr, "Cannot open csfsig.bin: %s\n", strerror(errno)); + return -errno; + } + + ret = flock(lockfd, LOCK_EX); + if (ret) { + fprintf(stderr, "Cannot lock csfsig.bin: %s\n", strerror(errno)); + return -errno; + } + + FILE *f = popen(command, "w"); + if (!f) { + perror("popen"); + return -errno; + } + + fwrite(data->csf, 1, strlen(data->csf) + 1, f); + + pclose(f); + + flock(lockfd, LOCK_UN); + close(lockfd); + + /* + * the Freescale code signing tool doesn't fail if there + * are errors in the command sequence file, it just doesn't + * produce any output, so we have to check for existence of + * the output file rather than checking the return value of + * the cst call. + */ + fd = open(csffile, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Failed to open %s: %s\n", csffile, strerror(errno)); + fprintf(stderr, "%s failed\n", cst); + return -errno; + } + + ret = fstat(fd, &s); + if (ret < 0) { + fprintf(stderr, "stat failed: %s\n", strerror(errno)); + return -errno; + } + + buf = malloc(CSF_LEN); + if (!buf) + return -ENOMEM; + + memset(buf, 0x5a, CSF_LEN); + + if (s.st_size > CSF_LEN) { + fprintf(stderr, "CSF file size exceeds maximum CSF len of %d bytes\n", + CSF_LEN); + } + + ret = xread(fd, buf, s.st_size); + if (ret < 0) { + fprintf(stderr, "read failed: %s\n", strerror(errno)); + return -errno; + } + + outfd = open(data->outfile, O_WRONLY | O_APPEND); + + ret = xwrite(outfd, buf, CSF_LEN); + if (ret < 0) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + return -errno; + } + + ret = close(outfd); + if (ret) { + perror("close"); + exit(1); + } + + return 0; +} + +static void *read_file(const char *filename, size_t *size) +{ + int fd, ret; + void *buf; + struct stat s; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + perror("open"); + exit(1); + } + + ret = fstat(fd, &s); + if (ret) + return NULL; + + *size = s.st_size; + buf = malloc(*size); + if (!buf) + exit(1); + + xread(fd, buf, *size); + + close(fd); + + return buf; +} + int main(int argc, char *argv[]) { int opt, ret; char *configfile = NULL; char *imagename = NULL; - char *outfile = NULL; void *buf; - size_t image_size = 0, load_size, insize; + size_t insize; void *infile; struct stat s; - int infd, outfd; + int outfd; int dcd_only = 0; int now = 0; + int sign_image = 0; + struct config_data data = { + .image_dcd_offset = 0xffffffff, + .write_mem = write_mem, + .check = check, + }; - while ((opt = getopt(argc, argv, "c:hf:o:bdp")) != -1) { + prgname = argv[0]; + + while ((opt = getopt(argc, argv, "c:hf:o:bdus")) != -1) { switch (opt) { case 'c': configfile = optarg; @@ -682,7 +644,7 @@ imagename = optarg; break; case 'o': - outfile = optarg; + data.outfile = optarg; break; case 'b': add_barebox_header = 1; @@ -690,8 +652,11 @@ case 'd': dcd_only = 1; break; - case 'p': - prepare_sign = 1; + case 's': + sign_image = 1; + break; + case 'u': + create_usb_image = 1; break; case 'h': usage(argv[0]); @@ -710,7 +675,7 @@ exit(1); } - if (!outfile) { + if (!data.outfile) { fprintf(stderr, "output file not given\n"); exit(1); } @@ -722,36 +687,7 @@ exit(1); } - image_size = s.st_size; - } - - ret = parse_config(configfile); - if (ret) - exit(1); - - buf = calloc(1, HEADER_LEN); - if (!buf) - exit(1); - - if (!image_dcd_offset) { - fprintf(stderr, "no dcd offset given ('dcdofs'). Defaulting to 0x%08x\n", - FLASH_HEADER_OFFSET); - image_dcd_offset = FLASH_HEADER_OFFSET; - } - - if (!header_version) { - fprintf(stderr, "no SoC given. (missing 'soc' in config)\n"); - exit(1); - } - - if (header_version == 2) - check_last_dcd(0); - - if (dcd_only) { - ret = write_dcd(outfile); - if (ret) - exit(1); - exit (0); + data.image_size = s.st_size; } /* @@ -762,43 +698,70 @@ * - i.MX6 SPI NOR boot corrupts the last few bytes of an image loaded * in ver funy ways when the image size is not 4 byte aligned */ - load_size = roundup(image_size + HEADER_LEN, 0x1000); + data.load_size = roundup(data.image_size + HEADER_LEN, 0x1000); - if (cpu_type == 35) - load_size += HEADER_LEN; + ret = parse_config(&data, configfile); + if (ret) + exit(1); - switch (header_version) { + if (!sign_image) + data.csf = NULL; + + if (create_usb_image && !data.csf) { + fprintf(stderr, "Warning: the -u option only has effect with signed images\n"); + create_usb_image = 0; + } + + buf = calloc(1, HEADER_LEN); + if (!buf) + exit(1); + + if (data.image_dcd_offset == 0xffffffff) { + if (create_usb_image) + data.image_dcd_offset = 0x0; + else + data.image_dcd_offset = FLASH_HEADER_OFFSET; + } + + if (!data.header_version) { + fprintf(stderr, "no SoC given. (missing 'soc' in config)\n"); + exit(1); + } + + if (data.header_version == 2) + check_last_dcd(0); + + if (dcd_only) { + ret = write_dcd(data.outfile); + if (ret) + exit(1); + exit (0); + } + + switch (data.header_version) { case 1: - add_header_v1(buf, image_dcd_offset, image_load_addr, load_size); + add_header_v1(&data, buf); + if (data.srkfile) { + ret = add_srk(buf, data.image_dcd_offset, data.image_load_addr, + data.srkfile); + if (ret) + exit(1); + } break; case 2: - add_header_v2(buf, image_dcd_offset, image_load_addr, load_size); + add_header_v2(&data, buf); break; default: fprintf(stderr, "Congratulations! You're welcome to implement header version %d\n", - header_version); + data.header_version); exit(1); } - infd = open(imagename, O_RDONLY); - if (infd < 0) { - perror("open"); - exit(1); - } - - ret = fstat(infd, &s); - if (ret) - return ret; - - insize = s.st_size; - infile = malloc(insize); + infile = read_file(imagename, &insize); if (!infile) exit(1); - xread(infd, infile, insize); - close(infd); - - outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + outfd = open(data.outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (outfd < 0) { perror("open"); exit(1); @@ -810,7 +773,7 @@ exit(1); } - if (cpu_type == 35) { + if (data.cpu_type == 35) { ret = xwrite(outfd, buf, HEADER_LEN); if (ret < 0) { perror("write"); @@ -826,7 +789,7 @@ /* pad until next 4k boundary */ now = 4096 - (insize % 4096); - if (prepare_sign && now) { + if (data.csf && now) { memset(buf, 0x5a, now); ret = xwrite(outfd, buf, now); @@ -842,5 +805,34 @@ exit(1); } + if (data.csf) { + ret = hab_sign(&data); + if (ret) + exit(1); + } + + if (create_usb_image) { + uint32_t *dcd; + + infile = read_file(data.outfile, &insize); + + dcd = infile + dcd_ptr_offset; + *dcd = dcd_ptr_content; + + outfd = open(data.outfile, O_WRONLY | O_TRUNC); + if (outfd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", data.outfile, strerror(errno)); + exit(1); + } + + ret = xwrite(outfd, infile, insize); + if (ret < 0) { + perror("write"); + exit (1); + } + + close(outfd); + } + exit(0); } diff --git a/scripts/imx/imx-usb-loader.c b/scripts/imx/imx-usb-loader.c index 195b27b..ed27831 100644 --- a/scripts/imx/imx-usb-loader.c +++ b/scripts/imx/imx-usb-loader.c @@ -32,10 +32,21 @@ #include #include #include +#include + +#include "imx.h" #define get_min(a, b) (((a) < (b)) ? (a) : (b)) +#define FT_APP 0xaa +#define FT_CSF 0xcc +#define FT_DCD 0xee +#define FT_LOAD_ONLY 0x00 + int verbose; +static int skip_image_dcd; +static struct libusb_device_handle *usb_dev_handle; +static struct usb_id *usb_id; struct mach_id { struct mach_id * next; @@ -53,11 +64,6 @@ unsigned short max_transfer; }; -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#ifndef offsetof -#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) -#endif - struct usb_work { char filename[256]; unsigned char dcd; @@ -194,9 +200,10 @@ return NULL; } -static void dump_long(unsigned char *src, unsigned cnt, unsigned addr) +static void dump_long(const void *src, unsigned cnt, unsigned addr) { - unsigned *p = (unsigned *)src; + const unsigned *p = (unsigned *)src; + while (cnt >= 32) { printf("%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", addr, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); @@ -215,9 +222,9 @@ } } -static void dump_bytes(unsigned char *src, unsigned cnt, unsigned addr) +static void dump_bytes(const void *src, unsigned cnt, unsigned addr) { - unsigned char *p = src; + const unsigned char *p = src; int i; while (cnt >= 16) { @@ -297,12 +304,11 @@ * EP2IN - bulk in * (max packet size of 512 bytes) */ -static int transfer(struct libusb_device_handle *h, int report, unsigned char *p, unsigned cnt, - int* last_trans, struct usb_id *p_id) +static int transfer(int report, unsigned char *p, unsigned cnt, int *last_trans) { int err; - if (cnt > p_id->mach_id->max_transfer) - cnt = p_id->mach_id->max_transfer; + if (cnt > usb_id->mach_id->max_transfer) + cnt = usb_id->mach_id->max_transfer; if (verbose > 4) { printf("report=%i\n", report); @@ -310,9 +316,10 @@ dump_bytes(p, cnt, 0); } - if (p_id->mach_id->mode == MODE_BULK) { + if (usb_id->mach_id->mode == MODE_BULK) { *last_trans = 0; - err = libusb_bulk_transfer(h, (report < 3) ? 1 : 2 + EP_IN, p, cnt, last_trans, 1000); + err = libusb_bulk_transfer(usb_dev_handle, + (report < 3) ? 1 : 2 + EP_IN, p, cnt, last_trans, 1000); } else { unsigned char tmp[1028]; @@ -320,7 +327,7 @@ if (report < 3) { memcpy(&tmp[1], p, cnt); - err = libusb_control_transfer(h, + err = libusb_control_transfer(usb_dev_handle, CTRL_OUT, HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT << 8) | report, @@ -332,7 +339,8 @@ } else { *last_trans = 0; memset(&tmp[1], 0, cnt); - err = libusb_interrupt_transfer(h, 1 + EP_IN, tmp, cnt + 1, last_trans, 1000); + err = libusb_interrupt_transfer(usb_dev_handle, + 1 + EP_IN, tmp, cnt + 1, last_trans, 1000); if (err >= 0) { if (tmp[0] == (unsigned char)report) { if (*last_trans > 1) { @@ -354,7 +362,7 @@ return err; } -int do_status(libusb_device_handle *h, struct usb_id *p_id) +int do_status(void) { int last_trans; unsigned char tmp[64]; @@ -369,14 +377,14 @@ }; for (;;) { - err = transfer(h, 1, (unsigned char*)status_command, 16, &last_trans, p_id); + err = transfer(1, (unsigned char*)status_command, 16, &last_trans); if (verbose > 2) printf("report 1, wrote %i bytes, err=%i\n", last_trans, err); memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 3, tmp, 64, &last_trans, p_id); + err = transfer(3, tmp, 64, &last_trans); if (verbose > 2) { printf("report 3, read %i bytes, err=%i\n", last_trans, err); @@ -392,8 +400,8 @@ break; } - if (p_id->mach_id->mode == MODE_HID) { - err = transfer(h, 4, tmp, sizeof(tmp), &last_trans, p_id); + if (usb_id->mach_id->mode == MODE_HID) { + err = transfer(4, tmp, sizeof(tmp), &last_trans); if (err) printf("4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); @@ -402,43 +410,9 @@ return err; } -struct boot_data { - uint32_t dest; - uint32_t image_len; - uint32_t plugin; -}; - -struct imx_flash_header_v2 { -#define IVT_BARKER 0x402000d1 - uint32_t barker; - uint32_t start_addr; - uint32_t reserv1; - uint32_t dcd_ptr; - uint32_t boot_data_ptr; /* struct boot_data * */ - uint32_t self_ptr; /* struct imx_flash_header_v2 *, this - boot_data.start = offset linked at */ - uint32_t app_code_csf; - uint32_t reserv2; -}; - -/* - * MX51 header type - */ -struct imx_flash_header_v1 { - uint32_t app_start_addr; -#define APP_BARKER 0xb1 -#define DCD_BARKER 0xb17219e9 - uint32_t app_barker; - uint32_t csf_ptr; - uint32_t dcd_ptr_ptr; - uint32_t srk_ptr; - uint32_t dcd_ptr; - uint32_t app_dest_ptr; -}; - #define V(a) (((a) >> 24) & 0xff), (((a) >> 16) & 0xff), (((a) >> 8) & 0xff), ((a) & 0xff) -static int read_memory(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned addr, unsigned char *dest, unsigned cnt) +static int read_memory(unsigned addr, unsigned char *dest, unsigned cnt) { static unsigned char read_reg_command[] = { 1, @@ -466,7 +440,7 @@ read_reg_command[10] = (unsigned char)(cnt); for (;;) { - err = transfer(h, 1, read_reg_command, 16, &last_trans, p_id); + err = transfer(1, read_reg_command, 16, &last_trans); if (!err) break; printf("read_reg_command err=%i, last_trans=%i\n", err, last_trans); @@ -476,7 +450,7 @@ retry++; } - err = transfer(h, 3, tmp, 4, &last_trans, p_id); + err = transfer(3, tmp, 4, &last_trans); if (err) { printf("r3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); @@ -487,7 +461,7 @@ while (rem) { tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; - err = transfer(h, 4, tmp, 64, &last_trans, p_id); + err = transfer(4, tmp, 64, &last_trans); if (err) { printf("r4 in err=%i, last_trans=%i %02x %02x %02x %02x cnt=%u rem=%d\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem); @@ -511,8 +485,7 @@ return err; } -static int write_memory(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned addr, unsigned val, int width) +static int write_memory(unsigned addr, unsigned val, int width) { int retry = 0; int last_trans; @@ -555,7 +528,7 @@ write_reg_command[14] = (unsigned char)(val); for (;;) { - err = transfer(h, 1, write_reg_command, 16, &last_trans, p_id); + err = transfer(1, write_reg_command, 16, &last_trans); if (!err) break; printf("write_reg_command err=%i, last_trans=%i\n", err, last_trans); @@ -567,7 +540,7 @@ memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); + err = transfer(3, tmp, sizeof(tmp), &last_trans); if (err) { printf("w3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); @@ -576,25 +549,109 @@ memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 4, tmp, sizeof(tmp), &last_trans, p_id); + err = transfer(4, tmp, sizeof(tmp), &last_trans); if (err) printf("w4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); return err; } -static int write_dcd_table_ivt(struct libusb_device_handle *h, struct usb_id *p_id, - struct imx_flash_header_v2 *hdr, unsigned char *file_start, unsigned cnt) +static int load_file(void *buf, unsigned len, unsigned dladdr, unsigned char type) +{ + static unsigned char dl_command[] = { + 0x04, + 0x04, + V(0), /* address */ + 0x00, /* format */ + V(0x00000020), /* data count */ + V(0), /* data */ + 0xaa, /* type */ + }; + int last_trans, err; + int retry = 0; + unsigned transfer_size = 0; + unsigned char tmp[64]; + void *p; + int cnt; + + dl_command[2] = (unsigned char)(dladdr >> 24); + dl_command[3] = (unsigned char)(dladdr >> 16); + dl_command[4] = (unsigned char)(dladdr >> 8); + dl_command[5] = (unsigned char)(dladdr); + + dl_command[7] = (unsigned char)(len >> 24); + dl_command[8] = (unsigned char)(len >> 16); + dl_command[9] = (unsigned char)(len >> 8); + dl_command[10] = (unsigned char)(len); + dl_command[15] = type; + + for (;;) { + err = transfer(1, dl_command, 16, &last_trans); + if (!err) + break; + + printf("dl_command err=%i, last_trans=%i\n", err, last_trans); + + if (retry > 5) + return -4; + retry++; + } + + retry = 0; + + if (usb_id->mach_id->mode == MODE_BULK) { + err = transfer(3, tmp, sizeof(tmp), &last_trans); + if (err) + printf("in err=%i, last_trans=%i %02x %02x %02x %02x\n", + err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); + } + + p = buf; + cnt = len; + + while (1) { + int now = get_min(cnt, usb_id->mach_id->max_transfer); + + if (!now) + break; + + err = transfer(2, p, now, &now); + if (err) { + printf("dl_command err=%i, last_trans=%i\n", err, last_trans); + return err; + } + + p += now; + cnt -= now; + } + + if (usb_id->mach_id->mode == MODE_HID) { + err = transfer(3, tmp, sizeof(tmp), &last_trans); + if (err) + printf("3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", + err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); + err = transfer(4, tmp, sizeof(tmp), &last_trans); + if (err) + printf("4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", + err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); + } else { + do_status(); + } + + return transfer_size; +} + +static int write_dcd_table_ivt(struct imx_flash_header_v2 *hdr, unsigned char *file_start, unsigned cnt) { unsigned char *dcd_end; unsigned m_length; -#define cvt_dest_to_src (((unsigned char *)hdr) - hdr->self_ptr) +#define cvt_dest_to_src (((unsigned char *)hdr) - hdr->self) unsigned char* dcd; unsigned char* file_end = file_start + cnt; int err = 0; if (!hdr->dcd_ptr) { - printf("No dcd table, barker=%x\n", hdr->barker); + printf("No dcd table in this ivt\n"); return 0; /* nothing to do */ } @@ -646,7 +703,7 @@ unsigned val = (dcd[4] << 24) | (dcd[5] << 16) | (dcd[6] << 8) | dcd[7]; dcd += 8; - err = write_memory(h, p_id, addr, val, 4); + err = write_memory(addr, val, 4); if (err < 0) return err; } @@ -654,27 +711,27 @@ return err; } -static int get_dcd_range_old(struct imx_flash_header_v1 *hdr, +static int get_dcd_range_old(struct imx_flash_header *hdr, unsigned char *file_start, unsigned cnt, unsigned char **pstart, unsigned char **pend) { unsigned char *dcd_end; unsigned m_length; -#define cvt_dest_to_src_old (((unsigned char *)&hdr->dcd_ptr) - hdr->dcd_ptr_ptr) +#define cvt_dest_to_src_old (((unsigned char *)&hdr->dcd) - hdr->dcd_ptr_ptr) unsigned char* dcd; unsigned val; unsigned char* file_end = file_start + cnt; - if (!hdr->dcd_ptr) { - printf("No dcd table, barker=%x\n", hdr->app_barker); - *pstart = *pend = ((unsigned char *)hdr) + sizeof(struct imx_flash_header_v1); + if (!hdr->dcd) { + printf("No dcd table, barker=%x\n", hdr->app_code_barker); + *pstart = *pend = ((unsigned char *)hdr) + sizeof(struct imx_flash_header); return 0; /* nothing to do */ } - dcd = hdr->dcd_ptr + cvt_dest_to_src_old; + dcd = hdr->dcd + cvt_dest_to_src_old; if ((dcd < file_start) || ((dcd + 8) > file_end)) { - printf("bad dcd_ptr %08x\n", hdr->dcd_ptr); + printf("bad dcd_ptr %08x\n", hdr->dcd); return -1; } @@ -701,8 +758,7 @@ return 0; } -static int write_dcd_table_old(struct libusb_device_handle *h, struct usb_id *p_id, - struct imx_flash_header_v1 *hdr, unsigned char *file_start, unsigned cnt) +static int write_dcd_table_old(struct imx_flash_header *hdr, unsigned char *file_start, unsigned cnt) { unsigned val; unsigned char *dcd_end; @@ -723,14 +779,14 @@ case 1: if (verbose > 1) printf("type=%08x *0x%08x = 0x%08x\n", type, addr, val); - err = write_memory(h, p_id, addr, val, 1); + err = write_memory(addr, val, 1); if (err < 0) return err; break; case 4: if (verbose > 1) printf("type=%08x *0x%08x = 0x%08x\n", type, addr, val); - err = write_memory(h, p_id, addr, val, 4); + err = write_memory(addr, val, 4); if (err < 0) return err; break; @@ -747,117 +803,79 @@ return err; } -static int verify_memory(struct libusb_device_handle *h, struct usb_id *p_id, - FILE *xfile, unsigned offset, unsigned addr, unsigned size, - unsigned char *verify_buffer, unsigned verify_cnt) +static int verify_memory(const void *buf, unsigned len, unsigned addr) { - int mismatch = 0; - unsigned char file_buf[1024]; - fseek(xfile, offset + verify_cnt, SEEK_SET); + int ret, mismatch = 0; + void *readbuf; + unsigned offset = 0, now; - while (size) { - unsigned char mem_buf[64]; - unsigned char *p = file_buf; - int cnt = addr & 0x3f; - int request = get_min(size, sizeof(file_buf)); + readbuf = malloc(len); + if (!readbuf) + return -ENOMEM; - if (cnt) { - cnt = 64 - cnt; - if (request > cnt) - request = cnt; + ret = read_memory(addr, readbuf, len); + if (ret < 0) + goto err; + + while (len) { + now = get_min(len, 32); + + if (memcmp(buf + offset, readbuf + offset, now)) { + printf("mismatch at offset 0x%08x. expected:\n", offset); + dump_long(buf + offset, now, addr + offset); + printf("read:\n"); + dump_long(readbuf + offset, now, addr + offset); + ret = -EINVAL; + mismatch++; + if (mismatch > 4) + goto err; } - if (verify_cnt) { - p = verify_buffer; - cnt = get_min(request, verify_cnt); - verify_buffer += cnt; - verify_cnt -= cnt; - } else { - cnt = fread(p, 1, request, xfile); - if (cnt <= 0) { - printf("Unexpected end of file, request=0x%0x, size=0x%x, cnt=%i\n", - request, size, cnt); - return -1; - } - } - - size -= cnt; - - while (cnt) { - int ret; - - request = get_min(cnt, sizeof(mem_buf)); - - ret = read_memory(h, p_id, addr, mem_buf, request); - if (ret < 0) - return ret; - - if (memcmp(p, mem_buf, request)) { - unsigned char * m = mem_buf; - if (!mismatch) - printf("!!!!mismatch\n"); - mismatch++; - - while (request) { - unsigned req = get_min(request, 32); - if (memcmp(p, m, req)) { - dump_long(p, req, offset); - dump_long(m, req, addr); - printf("\n"); - } - p += req; - m+= req; - offset += req; - addr += req; - cnt -= req; - request -= req; - } - if (mismatch >= 5) - return -1; - } - p += request; - offset += request; - addr += request; - cnt -= request; - } + len -= now; + offset += now; } - return mismatch ? -1 : 0; +err: + free(readbuf); + + return ret; } -static int is_header(struct usb_id *p_id, unsigned char *p) +static int is_header(unsigned char *p) { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; - switch (p_id->mach_id->header_type) { + switch (usb_id->mach_id->header_type) { case HDR_MX51: - if (ohdr->app_barker == 0xb1) + if (ohdr->app_code_barker == 0xb1) return 1; break; case HDR_MX53: - if (hdr->barker == IVT_BARKER) + if (hdr->header.tag == TAG_IVT_HEADER && hdr->header.version == IVT_VERSION) return 1; } return 0; } -static int perform_dcd(struct libusb_device_handle *h, struct usb_id *p_id, unsigned char *p, - unsigned char *file_start, unsigned cnt) +static int perform_dcd(unsigned char *p, unsigned char *file_start, unsigned cnt) { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; int ret = 0; - switch (p_id->mach_id->header_type) { + if (skip_image_dcd) + return 0; + + switch (usb_id->mach_id->header_type) { case HDR_MX51: - ret = write_dcd_table_old(h, p_id, ohdr, file_start, cnt); - ohdr->dcd_ptr = 0; + ret = write_dcd_table_old(ohdr, file_start, cnt); + ohdr->dcd_block_len = 0; break; case HDR_MX53: - ret = write_dcd_table_ivt(h, p_id, hdr, file_start, cnt); + ret = write_dcd_table_ivt(hdr, file_start, cnt); hdr->dcd_ptr = 0; break; @@ -866,16 +884,15 @@ return ret; } -static int clear_dcd_ptr(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned char *p, unsigned char *file_start, unsigned cnt) +static int clear_dcd_ptr(unsigned char *p, unsigned char *file_start, unsigned cnt) { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; - switch (p_id->mach_id->header_type) { + switch (usb_id->mach_id->header_type) { case HDR_MX51: - printf("clear dcd_ptr=0x%08x\n", ohdr->dcd_ptr); - ohdr->dcd_ptr = 0; + printf("clear dcd_ptr=0x%08x\n", ohdr->dcd); + ohdr->dcd = 0; break; case HDR_MX53: printf("clear dcd_ptr=0x%08x\n", hdr->dcd_ptr); @@ -885,21 +902,21 @@ return 0; } -static int get_dl_start(struct usb_id *p_id, unsigned char *p, unsigned char *file_start, +static int get_dl_start(unsigned char *p, unsigned char *file_start, unsigned cnt, unsigned *dladdr, unsigned *max_length, unsigned *plugin, unsigned *header_addr) { unsigned char* file_end = file_start + cnt; - switch (p_id->mach_id->header_type) { + switch (usb_id->mach_id->header_type) { case HDR_MX51: { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; unsigned char *dcd_end; unsigned char* dcd; int err = get_dcd_range_old(ohdr, file_start, cnt, &dcd, &dcd_end); - *dladdr = ohdr->app_dest_ptr; - *header_addr = ohdr->dcd_ptr_ptr - offsetof(struct imx_flash_header_v1, dcd_ptr); + *dladdr = ohdr->app_dest; + *header_addr = ohdr->dcd_ptr_ptr - offsetof(struct imx_flash_header, dcd); *plugin = 0; if (err >= 0) *max_length = dcd_end[0] | (dcd_end[1] << 8) | (dcd_end[2] << 16) | (dcd_end[3] << 24); @@ -911,20 +928,18 @@ unsigned char *bd; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; - *dladdr = hdr->self_ptr; - *header_addr = hdr->self_ptr; + *dladdr = hdr->self; + *header_addr = hdr->self; bd = hdr->boot_data_ptr + cvt_dest_to_src; if ((bd < file_start) || ((bd + 4) > file_end)) { printf("bad boot_data_ptr %08x\n", hdr->boot_data_ptr); return -1; } - *dladdr = ((struct boot_data *)bd)->dest; - *max_length = ((struct boot_data *)bd)->image_len; - *plugin = ((struct boot_data *)bd)->plugin; - ((struct boot_data *)bd)->plugin = 0; - - hdr->boot_data_ptr = 0; + *dladdr = ((struct imx_boot_data *)bd)->start; + *max_length = ((struct imx_boot_data *)bd)->size; + *plugin = ((struct imx_boot_data *)bd)->plugin; + ((struct imx_boot_data *)bd)->plugin = 0; break; } @@ -932,8 +947,7 @@ return 0; } -static int process_header(struct libusb_device_handle *h, struct usb_id *p_id, - struct usb_work *curr, unsigned char *buf, int cnt, +static int process_header(struct usb_work *curr, unsigned char *buf, int cnt, unsigned *p_dladdr, unsigned *p_max_length, unsigned *p_plugin, unsigned *p_header_addr) { @@ -946,17 +960,17 @@ for (header_offset = 0; header_offset < header_max; header_offset += header_inc, p += header_inc) { - if (!is_header(p_id, p)) + if (!is_header(p)) continue; - ret = get_dl_start(p_id, p, buf, cnt, p_dladdr, p_max_length, p_plugin, p_header_addr); + ret = get_dl_start(p, buf, cnt, p_dladdr, p_max_length, p_plugin, p_header_addr); if (ret < 0) { printf("!!get_dl_start returned %i\n", ret); return ret; } if (curr->dcd) { - ret = perform_dcd(h, p_id, p, buf, cnt); + ret = perform_dcd(p, buf, cnt); if (ret < 0) { printf("!!perform_dcd returned %i\n", ret); return ret; @@ -969,7 +983,7 @@ } if (curr->clear_dcd) { - ret = clear_dcd_ptr(h, p_id, p, buf, cnt); + ret = clear_dcd_ptr(p, buf, cnt); if (ret < 0) { printf("!!clear_dcd returned %i\n", ret); return ret; @@ -995,137 +1009,7 @@ return -ENODEV; } -static int load_file(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned char *p, int cnt, unsigned char *buf, unsigned buf_cnt, - unsigned dladdr, unsigned fsize, unsigned char type, FILE* xfile) -{ - static unsigned char dl_command[] = { - 0x04, - 0x04, - V(0), /* address */ - 0x00, /* format */ - V(0x00000020), /* data count */ - V(0), /* data */ - 0xaa, /* type */ - }; - int last_trans, err; - int retry = 0; - unsigned transfer_size = 0; - int max = p_id->mach_id->max_transfer; - unsigned char tmp[64]; - - dl_command[2] = (unsigned char)(dladdr >> 24); - dl_command[3] = (unsigned char)(dladdr >> 16); - dl_command[4] = (unsigned char)(dladdr >> 8); - dl_command[5] = (unsigned char)(dladdr); - - dl_command[7] = (unsigned char)(fsize >> 24); - dl_command[8] = (unsigned char)(fsize >> 16); - dl_command[9] = (unsigned char)(fsize >> 8); - dl_command[10] = (unsigned char)(fsize); - dl_command[15] = type; - - for (;;) { - err = transfer(h, 1, dl_command, 16, &last_trans, p_id); - if (!err) - break; - - printf("dl_command err=%i, last_trans=%i\n", err, last_trans); - - if (retry > 5) - return -4; - retry++; - } - - retry = 0; - - if (p_id->mach_id->mode == MODE_BULK) { - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); - if (err) - printf("in err=%i, last_trans=%i %02x %02x %02x %02x\n", - err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); - } - - while (1) { - int retry; - - if (cnt > (int)(fsize - transfer_size)) - cnt = (fsize - transfer_size); - - if (cnt <= 0) - break; - - retry = 0; - - while (cnt) { - err = transfer(h, 2, p, get_min(cnt, max), &last_trans, p_id); - if (err) { - printf("out err=%i, last_trans=%i cnt=0x%x max=0x%x transfer_size=0x%X retry=%i\n", - err, last_trans, cnt, max, transfer_size, retry); - if (retry >= 10) { - printf("Giving up\n"); - return err; - } - if (max >= 16) - max >>= 1; - else - max <<= 1; - usleep(10000); - retry++; - continue; - } - max = p_id->mach_id->max_transfer; - retry = 0; - if (cnt < last_trans) { - printf("error: last_trans=0x%x, attempted only=0%x\n", last_trans, cnt); - cnt = last_trans; - } - if (!last_trans) { - printf("Nothing last_trans, err=%i\n", err); - break; - } - p += last_trans; - cnt -= last_trans; - transfer_size += last_trans; - } - - if (!last_trans) - break; - - if (feof(xfile)) - break; - - cnt = fsize - transfer_size; - if (cnt <= 0) - break; - - cnt = fread(buf, 1 , get_min(cnt, buf_cnt), xfile); - p = buf; - } - - if (p_id->mach_id->mode == MODE_HID) { - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); - if (err) - printf("3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", - err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); - err = transfer(h, 4, tmp, sizeof(tmp), &last_trans, p_id); - if (err) - printf("4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", - err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); - } else { - do_status(h, p_id); - } - - return transfer_size; -} - -#define FT_APP 0xaa -#define FT_CSF 0xcc -#define FT_DCD 0xee -#define FT_LOAD_ONLY 0x00 - -static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, - struct usb_work *curr, int verify) +static int do_irom_download(struct usb_work *curr, int verify) { static unsigned char jump_command[] = {0x0b,0x0b, V(0), 0x00, V(0x00000000), V(0), 0x00}; @@ -1137,10 +1021,9 @@ int cnt; unsigned file_base; int last_trans, err; -#define BUF_SIZE (1024*16) unsigned char *buf = NULL; + unsigned char *image; unsigned char *verify_buffer = NULL; - unsigned verify_cnt; unsigned char *p; unsigned char tmp[64]; unsigned dladdr = 0; @@ -1149,7 +1032,6 @@ unsigned header_addr = 0; unsigned skip = 0; - unsigned transfer_size=0; int retry = 0; xfile = fopen(curr->filename, "rb" ); @@ -1158,26 +1040,29 @@ return -5; } - buf = malloc(BUF_SIZE); + fsize = get_file_size(xfile); + if (fsize < 0x20) { + printf("error, file: %s is too small\n", curr->filename); + ret = -2; + goto cleanup; + } + + buf = malloc(fsize); if (!buf) { printf("error, out of memory\n"); ret = -2; goto cleanup; } - fsize = get_file_size(xfile); - - cnt = fread(buf, 1 , BUF_SIZE, xfile); - - if (cnt < 0x20) { - printf("error, file: %s is too small\n", curr->filename); - ret = -2; - goto cleanup; + cnt = fread(buf, 1 , fsize, xfile); + if (cnt < fsize) { + printf("error, cannot read %s\n", curr->filename); + return -1; } max_length = fsize; - ret = process_header(h, p_id, curr, buf, cnt, + ret = process_header(curr, buf, cnt, &dladdr, &max_length, &plugin, &header_addr); if (ret < 0) goto cleanup; @@ -1206,7 +1091,7 @@ type = (curr->plug || curr->jump_mode) ? FT_APP : FT_LOAD_ONLY; - if (p_id->mach_id->mode == MODE_BULK && type == FT_APP) { + if (usb_id->mach_id->mode == MODE_BULK && type == FT_APP) { /* No jump command, dladdr should point to header */ dladdr = header_addr; } @@ -1218,22 +1103,9 @@ skip = dladdr - file_base; - if (skip > cnt) { - if (skip > fsize) { - printf("skip(0x%08x) > fsize(0x%08x) file_base=0x%08x, header_offset=0x%x\n", - skip, fsize, file_base, header_offset); - ret = -4; - goto cleanup; - } + image = buf + skip; - fseek(xfile, skip, SEEK_SET); - cnt -= skip; - fsize -= skip; - skip = 0; - cnt = fread(buf, 1 , BUF_SIZE, xfile); - } - - p = &buf[skip]; + p = image; cnt -= skip; fsize -= skip; @@ -1241,13 +1113,7 @@ fsize = max_length; if (verify) { - /* - * we need to save header for verification - * because some of the file is changed - * before download - */ - verify_buffer = malloc(cnt); - verify_cnt = cnt; + verify_buffer = malloc(64); if (!verify_buffer) { printf("error, out of memory\n"); @@ -1255,9 +1121,9 @@ goto cleanup; } - memcpy(verify_buffer, p, cnt); + memcpy(verify_buffer, p, 64); - if ((type == FT_APP) && (p_id->mach_id->mode != MODE_HID)) { + if ((type == FT_APP) && (usb_id->mach_id->mode != MODE_HID)) { type = FT_LOAD_ONLY; verify = 2; } @@ -1266,19 +1132,16 @@ printf("loading binary file(%s) to %08x, skip=0x%x, fsize=%u type=%d...\n", curr->filename, dladdr, skip, fsize, type); - ret = load_file(h, p_id, p, cnt, buf, BUF_SIZE, - dladdr, fsize, type, xfile); + ret = load_file(image, fsize, dladdr, type); if (ret < 0) goto cleanup; printf("binary file successfully loaded\n"); - transfer_size = ret; - if (verify) { printf("verifying file...\n"); - ret = verify_memory(h, p_id, xfile, skip, dladdr, fsize, verify_buffer, verify_cnt); + ret = verify_memory(image, fsize, dladdr); if (ret < 0) { printf("verifying failed\n"); goto cleanup; @@ -1287,18 +1150,19 @@ printf("file successfully verified\n"); if (verify == 2) { - if (verify_cnt > 64) - verify_cnt = 64; - ret = load_file(h, p_id, verify_buffer, verify_cnt, - buf, BUF_SIZE, dladdr, verify_cnt, - FT_APP, xfile); + /* + * In bulk mode we do not have an explicit jump command, + * so we load part of the image again with type FT_APP + * this time. + */ + ret = load_file(verify_buffer, 64, dladdr, FT_APP); if (ret < 0) goto cleanup; } } - if (p_id->mach_id->mode == MODE_HID && type == FT_APP) { + if (usb_id->mach_id->mode == MODE_HID && type == FT_APP) { printf("jumping to 0x%08x\n", header_addr); jump_command[2] = (unsigned char)(header_addr >> 24); @@ -1310,7 +1174,7 @@ retry = 0; for (;;) { - err = transfer(h, 1, jump_command, 16, &last_trans, p_id); + err = transfer(1, jump_command, 16, &last_trans); if (!err) break; @@ -1323,14 +1187,14 @@ } memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); + err = transfer(3, tmp, sizeof(tmp), &last_trans); if (err) printf("j3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); } - ret = (fsize == transfer_size) ? 0 : -16; + ret = 0; cleanup: fclose(xfile); free(verify_buffer); @@ -1339,10 +1203,28 @@ return ret; } +static int write_mem(struct config_data *data, uint32_t addr, uint32_t val, int width) +{ + printf("wr 0x%08x 0x%08x\n", addr, val); + + return write_memory(addr, val, width); +} + +static int parse_initfile(const char *filename) +{ + struct config_data data = { + .write_mem = write_mem, + }; + + return parse_config(&data, filename); +} + static void usage(const char *prgname) { fprintf(stderr, "usage: %s [OPTIONS] [FILENAME]\n\n" "-c check correctness of flashed image\n" + "-i Specify custom SoC initialization file\n" + "-s skip DCD included in image\n" "-v verbose (give multiple times to increase)\n" "-h this help\n", prgname); exit(1); @@ -1350,7 +1232,6 @@ int main(int argc, char *argv[]) { - struct usb_id *p_id = NULL; struct mach_id *mach; libusb_device **devs; libusb_device *dev; @@ -1358,13 +1239,13 @@ int err; int ret = 1; ssize_t cnt; - libusb_device_handle *h = NULL; int config = 0; int verify = 0; struct usb_work w = {}; int opt; + char *initfile = NULL; - while ((opt = getopt(argc, argv, "cvh")) != -1) { + while ((opt = getopt(argc, argv, "cvhi:s")) != -1) { switch (opt) { case 'c': verify = 1; @@ -1374,6 +1255,12 @@ break; case 'h': usage(argv[0]); + case 'i': + initfile = optarg; + break; + case 's': + skip_image_dcd = 1; + break; default: exit(1); } @@ -1406,7 +1293,7 @@ goto out; } - err = libusb_open(dev, &h); + err = libusb_open(dev, &usb_dev_handle); if (err) { fprintf(stderr, "Could not open device vid=0x%x pid=0x%x err=%d\n", mach->vid, mach->pid, err); @@ -1415,44 +1302,50 @@ libusb_free_device_list(devs, 1); - libusb_get_configuration(h, &config); + libusb_get_configuration(usb_dev_handle, &config); - if (libusb_kernel_driver_active(h, 0)) - libusb_detach_kernel_driver(h, 0); + if (libusb_kernel_driver_active(usb_dev_handle, 0)) + libusb_detach_kernel_driver(usb_dev_handle, 0); - err = libusb_claim_interface(h, 0); + err = libusb_claim_interface(usb_dev_handle, 0); if (err) { printf("Claim failed\n"); goto out; } - p_id = malloc(sizeof(*p_id)); - if (!p_id) { + usb_id = malloc(sizeof(*usb_id)); + if (!usb_id) { perror("malloc"); exit(1); } - p_id->mach_id = mach; + usb_id->mach_id = mach; - err = do_status(h, p_id); + err = do_status(); if (err) { printf("status failed\n"); goto out; } - err = do_irom_download(h, p_id, &w, verify); + if (initfile) { + err = parse_initfile(initfile); + if (err) + goto out; + } + + err = do_irom_download(&w, verify); if (err) { - err = do_status(h, p_id); + err = do_status(); goto out; } ret = 0; out: - if (p_id) - free(p_id); + if (usb_id) + free(usb_id); - if (h) - libusb_close(h); + if (usb_dev_handle) + libusb_close(usb_dev_handle); libusb_exit(NULL); diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c new file mode 100644 index 0000000..82ef97f --- /dev/null +++ b/scripts/imx/imx.c @@ -0,0 +1,444 @@ +/* + * (C) Copyright 2016 Sascha Hauer, Pengutronix + * + * 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. + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "imx.h" + +#define MAXARGS 32 + +static int parse_line(char *line, char *argv[]) +{ + int nargs = 0; + + while (nargs < MAXARGS) { + + /* skip any white space */ + while ((*line == ' ') || (*line == '\t')) + ++line; + + if (*line == '\0') { /* end of line, no more args */ + argv[nargs] = NULL; + return nargs; + } + + argv[nargs++] = line; /* begin of argument string */ + + /* find end of string */ + while (*line && (*line != ' ') && (*line != '\t')) + ++line; + + if (*line == '\0') { /* end of line, no more args */ + argv[nargs] = NULL; + return nargs; + } + + *line++ = '\0'; /* terminate current arg */ + } + + printf("** Too many args (max. %d) **\n", MAXARGS); + + return nargs; +} + +struct command { + const char *name; + int (*parse)(struct config_data *data, int argc, char *argv[]); +}; + +static const char *check_cmds[] = { + "while_all_bits_clear", /* while ((*address & mask) == 0); */ + "while_all_bits_set" , /* while ((*address & mask) == mask); */ + "while_any_bit_clear", /* while ((*address & mask) != mask); */ + "while_any_bit_set", /* while ((*address & mask) != 0); */ +}; + +static void do_cmd_check_usage(void) +{ + fprintf(stderr, + "usage: check \n" + " access width in bytes [1|2|4]\n" + "with one of:\n" + "while_all_bits_clear: while ((*addr & mask) == 0)\n" + "while_all_bits_set: while ((*addr & mask) == mask)\n" + "while_any_bit_clear: while ((*addr & mask) != mask)\n" + "while_any_bit_set: while ((*addr & mask) != 0)\n"); +} + +static int do_cmd_check(struct config_data *data, int argc, char *argv[]) +{ + uint32_t addr, mask, cmd; + int i, width; + const char *scmd; + + if (argc < 5) { + do_cmd_check_usage(); + return -EINVAL; + } + + if (!data->check) + return -ENOSYS; + + width = strtoul(argv[1], NULL, 0) >> 3; + scmd = argv[2]; + addr = strtoul(argv[3], NULL, 0); + mask = strtoul(argv[4], NULL, 0); + + switch (width) { + case 1: + case 2: + case 4: + break; + default: + fprintf(stderr, "illegal width %d\n", width); + return -EINVAL; + }; + + for (i = 0; i < ARRAY_SIZE(check_cmds); i++) { + if (!strcmp(scmd, check_cmds[i])) + break; + } + + if (i == ARRAY_SIZE(check_cmds)) { + do_cmd_check_usage(); + return -EINVAL; + } + + cmd = (TAG_CHECK << 24) | (i << 3) | width | ((sizeof(uint32_t) * 3) << 8); + + return data->check(data, cmd, addr, mask); +} + +static int do_cmd_write_mem(struct config_data *data, int argc, char *argv[]) +{ + uint32_t addr, val, width; + char *end; + + if (argc != 4) { + fprintf(stderr, "usage: wm [8|16|32] \n"); + return -EINVAL; + } + + width = strtoul(argv[1], &end, 0); + if (*end != '\0') { + fprintf(stderr, "illegal width token \"%s\"\n", argv[1]); + return -EINVAL; + } + + addr = strtoul(argv[2], &end, 0); + if (*end != '\0') { + fprintf(stderr, "illegal address token \"%s\"\n", argv[2]); + return -EINVAL; + } + + val = strtoul(argv[3], &end, 0); + if (*end != '\0') { + fprintf(stderr, "illegal value token \"%s\"\n", argv[3]); + return -EINVAL; + } + + width >>= 3; + + switch (width) { + case 1: + case 2: + case 4: + break; + default: + fprintf(stderr, "illegal width %d\n", width); + return -EINVAL; + }; + + return data->write_mem(data, addr, val, width); +} + +static int do_loadaddr(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + data->image_load_addr = strtoul(argv[1], NULL, 0); + + return 0; +} + +static int do_dcd_offset(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + data->image_dcd_offset = strtoul(argv[1], NULL, 0); + + return 0; +} + +struct soc_type { + char *name; + int header_version; + int cpu_type; +}; + +static struct soc_type socs[] = { + { .name = "imx25", .header_version = 1, .cpu_type = 25}, + { .name = "imx35", .header_version = 1, .cpu_type = 35 }, + { .name = "imx51", .header_version = 1, .cpu_type = 51 }, + { .name = "imx53", .header_version = 2, .cpu_type = 53 }, + { .name = "imx6", .header_version = 2, .cpu_type = 6 }, +}; + +static int do_soc(struct config_data *data, int argc, char *argv[]) +{ + char *soc; + int i; + + if (argc < 2) + return -EINVAL; + + soc = argv[1]; + + for (i = 0; i < ARRAY_SIZE(socs); i++) { + if (!strcmp(socs[i].name, soc)) { + data->header_version = socs[i].header_version; + data->cpu_type = socs[i].cpu_type; + return 0; + } + } + + fprintf(stderr, "unkown SoC type \"%s\". Known SoCs are:\n", soc); + for (i = 0; i < ARRAY_SIZE(socs); i++) + fprintf(stderr, "%s ", socs[i].name); + fprintf(stderr, "\n"); + + if (data->cpu_type == 35) + data->load_size += HEADER_LEN; + + return -EINVAL; +} + +static int hab_add_str(struct config_data *data, const char *str) +{ + int len = strlen(str); + + if (data->csf_space < len) + return -ENOMEM; + + strcat(data->csf, str); + + data->csf_space -= len; + + return 0; +} + +static int do_hab(struct config_data *data, int argc, char *argv[]) +{ + int i, ret; + + if (!data->csf) { + data->csf_space = 0x10000; + + data->csf = malloc(data->csf_space + 1); + if (!data->csf) + return -ENOMEM; + } + + for (i = 1; i < argc; i++) { + ret = hab_add_str(data, argv[i]); + if (ret) + return ret; + + ret = hab_add_str(data, " "); + if (ret) + return ret; + } + + ret = hab_add_str(data, "\n"); + if (ret) + return ret; + + return 0; +} + +static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) +{ + char *str; + int ret; + + if (!data->csf) + return -EINVAL; + + ret = asprintf(&str, "Blocks = 0x%08x 0 %d \"%s\"\n", + data->image_load_addr, + data->load_size, data->outfile); + if (ret < 0) + return -ENOMEM; + + ret = hab_add_str(data, str); + if (ret) + return ret; + + return 0; +} + +static int do_super_root_key(struct config_data *data, int argc, char *argv[]) +{ + int len; + char *srkfile; + + if (argc != 2) { + fprintf(stderr, "usage: super_root_key \n"); + return -EINVAL; + } + + if (data->cpu_type != 35 && data->cpu_type != 25) { + fprintf(stderr, "Warning: The super_root_key command is meaningless " + "on non HABv3 based SoCs\n"); + return 0; + } + + srkfile = argv[1]; + + if (*srkfile == '"') + srkfile++; + + data->srkfile = strdup(srkfile); + if (!data->srkfile) + return -ENOMEM; + + len = strlen(data->srkfile); + if (data->srkfile[len - 1] == '"') + data->srkfile[len - 1] = 0; + + return 0; +} + +struct command cmds[] = { + { + .name = "wm", + .parse = do_cmd_write_mem, + }, { + .name = "check", + .parse = do_cmd_check, + }, { + .name = "loadaddr", + .parse = do_loadaddr, + }, { + .name = "dcdofs", + .parse = do_dcd_offset, + }, { + .name = "soc", + .parse = do_soc, + }, { + .name = "hab", + .parse = do_hab, + }, { + .name = "hab_blocks", + .parse = do_hab_blocks, + }, { + .name = "super_root_key", + .parse = do_super_root_key, + }, +}; + +static char *readcmd(struct config_data *data, FILE *f) +{ + static char *buf; + char *str; + ssize_t ret; + + if (!buf) { + buf = malloc(4096); + if (!buf) + return NULL; + } + + str = buf; + *str = 0; + + while (1) { + ret = fread(str, 1, 1, f); + if (!ret) + return strlen(buf) ? buf : NULL; + + if (*str == '\n' || *str == ';') { + *str = 0; + return buf; + } + + str++; + } +} + +int parse_config(struct config_data *data, const char *filename) +{ + FILE *f; + int lineno = 0; + char *line = NULL, *tmp; + char *argv[MAXARGS]; + int nargs, i, ret = 0; + + f = fopen(filename, "r"); + if (!f) { + fprintf(stderr, "Error: %s - Can't open DCD file\n", filename); + exit(1); + } + + while (1) { + line = readcmd(data, f); + if (!line) + break; + + lineno++; + + tmp = strchr(line, '#'); + if (tmp) + *tmp = 0; + + nargs = parse_line(line, argv); + if (!nargs) + continue; + + ret = -ENOENT; + + for (i = 0; i < ARRAY_SIZE(cmds); i++) { + if (!strcmp(cmds[i].name, argv[0])) { + ret = cmds[i].parse(data, nargs, argv); + if (ret) { + fprintf(stderr, "error in line %d: %s\n", + lineno, strerror(-ret)); + goto cleanup; + } + break; + } + } + + if (ret == -ENOENT) { + fprintf(stderr, "no such command: %s\n", argv[0]); + goto cleanup; + } + } + +cleanup: + fclose(f); + return ret; +} diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h new file mode 100644 index 0000000..85071b4 --- /dev/null +++ b/scripts/imx/imx.h @@ -0,0 +1,72 @@ + +#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ + +/* + * ============================================================================ + * i.MX flash header v1 handling. Found on i.MX35 and i.MX51 + * ============================================================================ + */ +#define DCD_BARKER 0xb17219e9 + +struct imx_flash_header { + uint32_t app_code_jump_vector; + uint32_t app_code_barker; + uint32_t app_code_csf; + uint32_t dcd_ptr_ptr; + uint32_t super_root_key; + uint32_t dcd; + uint32_t app_dest; + uint32_t dcd_barker; + uint32_t dcd_block_len; +} __attribute__((packed)); + +struct imx_boot_data { + uint32_t start; + uint32_t size; + uint32_t plugin; +} __attribute__((packed)); + +#define TAG_IVT_HEADER 0xd1 +#define IVT_VERSION 0x40 +#define TAG_DCD_HEADER 0xd2 +#define DCD_VERSION 0x40 +#define TAG_WRITE 0xcc +#define TAG_CHECK 0xcf + +struct imx_ivt_header { + uint8_t tag; + uint16_t length; + uint8_t version; +} __attribute__((packed)); + +struct imx_flash_header_v2 { + struct imx_ivt_header header; + + uint32_t entry; + uint32_t reserved1; + uint32_t dcd_ptr; + uint32_t boot_data_ptr; + uint32_t self; + uint32_t csf; + uint32_t reserved2; + + struct imx_boot_data boot_data; + struct imx_ivt_header dcd_header; +} __attribute__((packed)); + +struct config_data { + uint32_t image_load_addr; + uint32_t image_dcd_offset; + uint32_t image_size; + uint32_t load_size; + char *outfile; + char *srkfile; + int header_version; + int cpu_type; + int (*check)(struct config_data *data, uint32_t cmd, uint32_t addr, uint32_t mask); + int (*write_mem)(struct config_data *data, uint32_t addr, uint32_t val, int width); + int csf_space; + char *csf; +}; + +int parse_config(struct config_data *data, const char *filename); diff --git a/scripts/include/asm-generic/atomic-gcc.h b/scripts/include/asm-generic/atomic-gcc.h new file mode 100644 index 0000000..2ba78c9 --- /dev/null +++ b/scripts/include/asm-generic/atomic-gcc.h @@ -0,0 +1,63 @@ +#ifndef __TOOLS_ASM_GENERIC_ATOMIC_H +#define __TOOLS_ASM_GENERIC_ATOMIC_H + +#include +#include + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + * + * Excerpts obtained from the Linux kernel sources. + */ + +#define ATOMIC_INIT(i) { (i) } + +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +static inline int atomic_read(const atomic_t *v) +{ + return ACCESS_ONCE((v)->counter); +} + +/** + * atomic_set - set atomic variable + * @v: pointer of type atomic_t + * @i: required value + * + * Atomically sets the value of @v to @i. + */ +static inline void atomic_set(atomic_t *v, int i) +{ + v->counter = i; +} + +/** + * atomic_inc - increment atomic variable + * @v: pointer of type atomic_t + * + * Atomically increments @v by 1. + */ +static inline void atomic_inc(atomic_t *v) +{ + __sync_add_and_fetch(&v->counter, 1); +} + +/** + * atomic_dec_and_test - decrement and test + * @v: pointer of type atomic_t + * + * Atomically decrements @v by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +static inline int atomic_dec_and_test(atomic_t *v) +{ + return __sync_sub_and_fetch(&v->counter, 1) == 0; +} + +#endif /* __TOOLS_ASM_GENERIC_ATOMIC_H */ diff --git a/scripts/include/asm-generic/barrier.h b/scripts/include/asm-generic/barrier.h new file mode 100644 index 0000000..47b9339 --- /dev/null +++ b/scripts/include/asm-generic/barrier.h @@ -0,0 +1,44 @@ +/* + * Copied from the kernel sources to tools/perf/: + * + * Generic barrier definitions, originally based on MN10300 definitions. + * + * It should be possible to use these on really simple architectures, + * but it serves more as a starting point for new ports. + * + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#ifndef __TOOLS_LINUX_ASM_GENERIC_BARRIER_H +#define __TOOLS_LINUX_ASM_GENERIC_BARRIER_H + +#ifndef __ASSEMBLY__ + +#include + +/* + * Force strict CPU ordering. And yes, this is required on UP too when we're + * talking to devices. + * + * Fall back to compiler barriers if nothing better is provided. + */ + +#ifndef mb +#define mb() barrier() +#endif + +#ifndef rmb +#define rmb() mb() +#endif + +#ifndef wmb +#define wmb() mb() +#endif + +#endif /* !__ASSEMBLY__ */ +#endif /* __TOOLS_LINUX_ASM_GENERIC_BARRIER_H */ diff --git a/scripts/include/asm-generic/bitops.h b/scripts/include/asm-generic/bitops.h new file mode 100644 index 0000000..653d1ba --- /dev/null +++ b/scripts/include/asm-generic/bitops.h @@ -0,0 +1,29 @@ +#ifndef __TOOLS_ASM_GENERIC_BITOPS_H +#define __TOOLS_ASM_GENERIC_BITOPS_H + +/* + * tools/ copied this from include/asm-generic/bitops.h, bit by bit as it needed + * some functions. + * + * For the benefit of those who are trying to port Linux to another + * architecture, here are some C-language equivalents. You should + * recode these in the native assembly language, if at all possible. + * + * C language equivalents written by Theodore Ts'o, 9/26/92 + */ + +#include +#include +#include +#include +#include + +#ifndef _TOOLS_LINUX_BITOPS_H_ +#error only can be included directly +#endif + +#include + +#include + +#endif /* __TOOLS_ASM_GENERIC_BITOPS_H */ diff --git a/scripts/include/asm-generic/bitops/__ffs.h b/scripts/include/asm-generic/bitops/__ffs.h new file mode 100644 index 0000000..c941750 --- /dev/null +++ b/scripts/include/asm-generic/bitops/__ffs.h @@ -0,0 +1,43 @@ +#ifndef _TOOLS_LINUX_ASM_GENERIC_BITOPS___FFS_H_ +#define _TOOLS_LINUX_ASM_GENERIC_BITOPS___FFS_H_ + +#include + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static __always_inline unsigned long __ffs(unsigned long word) +{ + int num = 0; + +#if __BITS_PER_LONG == 64 + if ((word & 0xffffffff) == 0) { + num += 32; + word >>= 32; + } +#endif + if ((word & 0xffff) == 0) { + num += 16; + word >>= 16; + } + if ((word & 0xff) == 0) { + num += 8; + word >>= 8; + } + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +#endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS___FFS_H_ */ diff --git a/scripts/include/asm-generic/bitops/__fls.h b/scripts/include/asm-generic/bitops/__fls.h new file mode 100644 index 0000000..2218b9a --- /dev/null +++ b/scripts/include/asm-generic/bitops/__fls.h @@ -0,0 +1 @@ +#include <../../../../include/asm-generic/bitops/__fls.h> diff --git a/scripts/include/asm-generic/bitops/arch_hweight.h b/scripts/include/asm-generic/bitops/arch_hweight.h new file mode 100644 index 0000000..318bb2b --- /dev/null +++ b/scripts/include/asm-generic/bitops/arch_hweight.h @@ -0,0 +1 @@ +#include "../../../../include/asm-generic/bitops/arch_hweight.h" diff --git a/scripts/include/asm-generic/bitops/atomic.h b/scripts/include/asm-generic/bitops/atomic.h new file mode 100644 index 0000000..4bccd7c --- /dev/null +++ b/scripts/include/asm-generic/bitops/atomic.h @@ -0,0 +1,22 @@ +#ifndef _TOOLS_LINUX_ASM_GENERIC_BITOPS_ATOMIC_H_ +#define _TOOLS_LINUX_ASM_GENERIC_BITOPS_ATOMIC_H_ + +#include + +static inline void set_bit(int nr, unsigned long *addr) +{ + addr[nr / __BITS_PER_LONG] |= 1UL << (nr % __BITS_PER_LONG); +} + +static inline void clear_bit(int nr, unsigned long *addr) +{ + addr[nr / __BITS_PER_LONG] &= ~(1UL << (nr % __BITS_PER_LONG)); +} + +static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) +{ + return ((1UL << (nr % __BITS_PER_LONG)) & + (((unsigned long *)addr)[nr / __BITS_PER_LONG])) != 0; +} + +#endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS_ATOMIC_H_ */ diff --git a/scripts/include/asm-generic/bitops/const_hweight.h b/scripts/include/asm-generic/bitops/const_hweight.h new file mode 100644 index 0000000..0afd644 --- /dev/null +++ b/scripts/include/asm-generic/bitops/const_hweight.h @@ -0,0 +1 @@ +#include "../../../../include/asm-generic/bitops/const_hweight.h" diff --git a/scripts/include/asm-generic/bitops/find.h b/scripts/include/asm-generic/bitops/find.h new file mode 100644 index 0000000..31f5154 --- /dev/null +++ b/scripts/include/asm-generic/bitops/find.h @@ -0,0 +1,33 @@ +#ifndef _TOOLS_LINUX_ASM_GENERIC_BITOPS_FIND_H_ +#define _TOOLS_LINUX_ASM_GENERIC_BITOPS_FIND_H_ + +#ifndef find_next_bit +/** + * find_next_bit - find the next set bit in a memory region + * @addr: The address to base the search on + * @offset: The bitnumber to start searching at + * @size: The bitmap size in bits + * + * Returns the bit number for the next set bit + * If no bits are set, returns @size. + */ +extern unsigned long find_next_bit(const unsigned long *addr, unsigned long + size, unsigned long offset); +#endif + +#ifndef find_first_bit + +/** + * find_first_bit - find the first set bit in a memory region + * @addr: The address to start the search at + * @size: The maximum number of bits to search + * + * Returns the bit number of the first set bit. + * If no bits are set, returns @size. + */ +extern unsigned long find_first_bit(const unsigned long *addr, + unsigned long size); + +#endif /* find_first_bit */ + +#endif /*_TOOLS_LINUX_ASM_GENERIC_BITOPS_FIND_H_ */ diff --git a/scripts/include/asm-generic/bitops/fls.h b/scripts/include/asm-generic/bitops/fls.h new file mode 100644 index 0000000..dbf711a --- /dev/null +++ b/scripts/include/asm-generic/bitops/fls.h @@ -0,0 +1 @@ +#include <../../../../include/asm-generic/bitops/fls.h> diff --git a/scripts/include/asm-generic/bitops/fls64.h b/scripts/include/asm-generic/bitops/fls64.h new file mode 100644 index 0000000..980b1f6 --- /dev/null +++ b/scripts/include/asm-generic/bitops/fls64.h @@ -0,0 +1 @@ +#include <../../../../include/asm-generic/bitops/fls64.h> diff --git a/scripts/include/asm-generic/bitops/hweight.h b/scripts/include/asm-generic/bitops/hweight.h new file mode 100644 index 0000000..290120c --- /dev/null +++ b/scripts/include/asm-generic/bitops/hweight.h @@ -0,0 +1,7 @@ +#ifndef _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ +#define _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ + +#include +#include + +#endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ */ diff --git a/scripts/include/asm/atomic.h b/scripts/include/asm/atomic.h new file mode 100644 index 0000000..70794f5 --- /dev/null +++ b/scripts/include/asm/atomic.h @@ -0,0 +1,10 @@ +#ifndef __TOOLS_LINUX_ASM_ATOMIC_H +#define __TOOLS_LINUX_ASM_ATOMIC_H + +#if defined(__i386__) || defined(__x86_64__) +#include "../../arch/x86/include/asm/atomic.h" +#else +#include +#endif + +#endif /* __TOOLS_LINUX_ASM_ATOMIC_H */ diff --git a/scripts/include/asm/barrier.h b/scripts/include/asm/barrier.h new file mode 100644 index 0000000..ac66ac5 --- /dev/null +++ b/scripts/include/asm/barrier.h @@ -0,0 +1,27 @@ +#if defined(__i386__) || defined(__x86_64__) +#include "../../arch/x86/include/asm/barrier.h" +#elif defined(__arm__) +#include "../../arch/arm/include/asm/barrier.h" +#elif defined(__aarch64__) +#include "../../arch/arm64/include/asm/barrier.h" +#elif defined(__powerpc__) +#include "../../arch/powerpc/include/asm/barrier.h" +#elif defined(__s390__) +#include "../../arch/s390/include/asm/barrier.h" +#elif defined(__sh__) +#include "../../arch/sh/include/asm/barrier.h" +#elif defined(__sparc__) +#include "../../arch/sparc/include/asm/barrier.h" +#elif defined(__tile__) +#include "../../arch/tile/include/asm/barrier.h" +#elif defined(__alpha__) +#include "../../arch/alpha/include/asm/barrier.h" +#elif defined(__mips__) +#include "../../arch/mips/include/asm/barrier.h" +#elif defined(__ia64__) +#include "../../arch/ia64/include/asm/barrier.h" +#elif defined(__xtensa__) +#include "../../arch/xtensa/include/asm/barrier.h" +#else +#include +#endif diff --git a/scripts/include/asm/bug.h b/scripts/include/asm/bug.h new file mode 100644 index 0000000..9e5f484 --- /dev/null +++ b/scripts/include/asm/bug.h @@ -0,0 +1,25 @@ +#ifndef _TOOLS_ASM_BUG_H +#define _TOOLS_ASM_BUG_H + +#include + +#define __WARN_printf(arg...) do { fprintf(stderr, arg); } while (0) + +#define WARN(condition, format...) ({ \ + int __ret_warn_on = !!(condition); \ + if (unlikely(__ret_warn_on)) \ + __WARN_printf(format); \ + unlikely(__ret_warn_on); \ +}) + +#define WARN_ONCE(condition, format...) ({ \ + static int __warned; \ + int __ret_warn_once = !!(condition); \ + \ + if (unlikely(__ret_warn_once)) \ + if (WARN(!__warned, format)) \ + __warned = 1; \ + unlikely(__ret_warn_once); \ +}) + +#endif /* _TOOLS_ASM_BUG_H */ diff --git a/scripts/include/linux/atomic.h b/scripts/include/linux/atomic.h new file mode 100644 index 0000000..4e3d3d1 --- /dev/null +++ b/scripts/include/linux/atomic.h @@ -0,0 +1,6 @@ +#ifndef __TOOLS_LINUX_ATOMIC_H +#define __TOOLS_LINUX_ATOMIC_H + +#include + +#endif /* __TOOLS_LINUX_ATOMIC_H */ diff --git a/scripts/include/linux/bitmap.h b/scripts/include/linux/bitmap.h new file mode 100644 index 0000000..28f5493 --- /dev/null +++ b/scripts/include/linux/bitmap.h @@ -0,0 +1,68 @@ +#ifndef _PERF_BITOPS_H +#define _PERF_BITOPS_H + +#include +#include + +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + +int __bitmap_weight(const unsigned long *bitmap, int bits); +void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); + +#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) + +#define BITMAP_LAST_WORD_MASK(nbits) \ +( \ + ((nbits) % BITS_PER_LONG) ? \ + (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \ +) + +#define small_const_nbits(nbits) \ + (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG) + +static inline void bitmap_zero(unsigned long *dst, int nbits) +{ + if (small_const_nbits(nbits)) + *dst = 0UL; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memset(dst, 0, len); + } +} + +static inline int bitmap_weight(const unsigned long *src, int nbits) +{ + if (small_const_nbits(nbits)) + return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits)); + return __bitmap_weight(src, nbits); +} + +static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (small_const_nbits(nbits)) + *dst = *src1 | *src2; + else + __bitmap_or(dst, src1, src2, nbits); +} + +/** + * test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + */ +static inline int test_and_set_bit(int nr, unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old; + + old = *p; + *p = old | mask; + + return (old & mask) != 0; +} + +#endif /* _PERF_BITOPS_H */ diff --git a/scripts/include/linux/bitops.h b/scripts/include/linux/bitops.h new file mode 100644 index 0000000..5ad9ee1 --- /dev/null +++ b/scripts/include/linux/bitops.h @@ -0,0 +1,58 @@ +#ifndef _TOOLS_LINUX_BITOPS_H_ +#define _TOOLS_LINUX_BITOPS_H_ + +#include +#include +#include + +#ifndef __WORDSIZE +#define __WORDSIZE (__SIZEOF_LONG__ * 8) +#endif + +#define BITS_PER_LONG __WORDSIZE + +#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) +#define BITS_PER_BYTE 8 +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64)) +#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) +#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) + +extern unsigned int __sw_hweight8(unsigned int w); +extern unsigned int __sw_hweight16(unsigned int w); +extern unsigned int __sw_hweight32(unsigned int w); +extern unsigned long __sw_hweight64(__u64 w); + +/* + * Include this here because some architectures need generic_ffs/fls in + * scope + * + * XXX: this needs to be asm/bitops.h, when we get to per arch optimizations + */ +#include + +#define for_each_set_bit(bit, addr, size) \ + for ((bit) = find_first_bit((addr), (size)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +/* same as for_each_set_bit() but use bit as value to start with */ +#define for_each_set_bit_from(bit, addr, size) \ + for ((bit) = find_next_bit((addr), (size), (bit)); \ + (bit) < (size); \ + (bit) = find_next_bit((addr), (size), (bit) + 1)) + +static inline unsigned long hweight_long(unsigned long w) +{ + return sizeof(w) == 4 ? hweight32(w) : hweight64(w); +} + +static inline unsigned fls_long(unsigned long l) +{ + if (sizeof(l) == 4) + return fls(l); + return fls64(l); +} + +#endif diff --git a/scripts/include/linux/compiler.h b/scripts/include/linux/compiler.h new file mode 100644 index 0000000..fa7208a --- /dev/null +++ b/scripts/include/linux/compiler.h @@ -0,0 +1,118 @@ +#ifndef _TOOLS_LINUX_COMPILER_H_ +#define _TOOLS_LINUX_COMPILER_H_ + +/* Optimization barrier */ +/* The "volatile" is due to gcc bugs */ +#define barrier() __asm__ __volatile__("": : :"memory") + +#ifndef __always_inline +# define __always_inline inline __attribute__((always_inline)) +#endif + +#define __user + +#ifndef __attribute_const__ +# define __attribute_const__ +#endif + +#ifndef __maybe_unused +# define __maybe_unused __attribute__((unused)) +#endif + +#ifndef __packed +# define __packed __attribute__((__packed__)) +#endif + +#ifndef __force +# define __force +#endif + +#ifndef __weak +# define __weak __attribute__((weak)) +#endif + +#ifndef likely +# define likely(x) __builtin_expect(!!(x), 1) +#endif + +#ifndef unlikely +# define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) + +#include + +/* + * Following functions are taken from kernel sources and + * break aliasing rules in their original form. + * + * While kernel is compiled with -fno-strict-aliasing, + * perf uses -Wstrict-aliasing=3 which makes build fail + * under gcc 4.4. + * + * Using extra __may_alias__ type to allow aliasing + * in this case. + */ +typedef __u8 __attribute__((__may_alias__)) __u8_alias_t; +typedef __u16 __attribute__((__may_alias__)) __u16_alias_t; +typedef __u32 __attribute__((__may_alias__)) __u32_alias_t; +typedef __u64 __attribute__((__may_alias__)) __u64_alias_t; + +static __always_inline void __read_once_size(const volatile void *p, void *res, int size) +{ + switch (size) { + case 1: *(__u8_alias_t *) res = *(volatile __u8_alias_t *) p; break; + case 2: *(__u16_alias_t *) res = *(volatile __u16_alias_t *) p; break; + case 4: *(__u32_alias_t *) res = *(volatile __u32_alias_t *) p; break; + case 8: *(__u64_alias_t *) res = *(volatile __u64_alias_t *) p; break; + default: + barrier(); + __builtin_memcpy((void *)res, (const void *)p, size); + barrier(); + } +} + +static __always_inline void __write_once_size(volatile void *p, void *res, int size) +{ + switch (size) { + case 1: *(volatile __u8_alias_t *) p = *(__u8_alias_t *) res; break; + case 2: *(volatile __u16_alias_t *) p = *(__u16_alias_t *) res; break; + case 4: *(volatile __u32_alias_t *) p = *(__u32_alias_t *) res; break; + case 8: *(volatile __u64_alias_t *) p = *(__u64_alias_t *) res; break; + default: + barrier(); + __builtin_memcpy((void *)p, (const void *)res, size); + barrier(); + } +} + +/* + * Prevent the compiler from merging or refetching reads or writes. The + * compiler is also forbidden from reordering successive instances of + * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the + * compiler is aware of some particular ordering. One way to make the + * compiler aware of ordering is to put the two invocations of READ_ONCE, + * WRITE_ONCE or ACCESS_ONCE() in different C statements. + * + * In contrast to ACCESS_ONCE these two macros will also work on aggregate + * data types like structs or unions. If the size of the accessed data + * type exceeds the word size of the machine (e.g., 32 bits or 64 bits) + * READ_ONCE() and WRITE_ONCE() will fall back to memcpy and print a + * compile-time warning. + * + * Their two major use cases are: (1) Mediating communication between + * process-level code and irq/NMI handlers, all running on the same CPU, + * and (2) Ensuring that the compiler does not fold, spindle, or otherwise + * mutilate accesses that either do not require ordering or that interact + * with an explicit memory barrier or atomic instruction that provides the + * required ordering. + */ + +#define READ_ONCE(x) \ + ({ union { typeof(x) __val; char __c[1]; } __u; __read_once_size(&(x), __u.__c, sizeof(x)); __u.__val; }) + +#define WRITE_ONCE(x, val) \ + ({ union { typeof(x) __val; char __c[1]; } __u = { .__val = (val) }; __write_once_size(&(x), __u.__c, sizeof(x)); __u.__val; }) + +#endif /* _TOOLS_LINUX_COMPILER_H */ diff --git a/scripts/include/linux/err.h b/scripts/include/linux/err.h new file mode 100644 index 0000000..bdc3dd8 --- /dev/null +++ b/scripts/include/linux/err.h @@ -0,0 +1,49 @@ +#ifndef __TOOLS_LINUX_ERR_H +#define __TOOLS_LINUX_ERR_H + +#include +#include + +#include + +/* + * Original kernel header comment: + * + * Kernel pointers have redundant information, so we can use a + * scheme where we can return either an error code or a normal + * pointer with the same return value. + * + * This should be a per-architecture thing, to allow different + * error and pointer decisions. + * + * Userspace note: + * The same principle works for userspace, because 'error' pointers + * fall down to the unused hole far from user space, as described + * in Documentation/x86/x86_64/mm.txt for x86_64 arch: + * + * 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm hole caused by [48:63] sign extension + * ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole + * + * It should be the same case for other architectures, because + * this code is used in generic kernel code. + */ +#define MAX_ERRNO 4095 + +#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) + +static inline void * __must_check ERR_PTR(long error_) +{ + return (void *) error_; +} + +static inline long __must_check PTR_ERR(__force const void *ptr) +{ + return (long) ptr; +} + +static inline bool __must_check IS_ERR(__force const void *ptr) +{ + return IS_ERR_VALUE((unsigned long)ptr); +} + +#endif /* _LINUX_ERR_H */ diff --git a/scripts/include/linux/export.h b/scripts/include/linux/export.h new file mode 100644 index 0000000..d07e586 --- /dev/null +++ b/scripts/include/linux/export.h @@ -0,0 +1,10 @@ +#ifndef _TOOLS_LINUX_EXPORT_H_ +#define _TOOLS_LINUX_EXPORT_H_ + +#define EXPORT_SYMBOL(sym) +#define EXPORT_SYMBOL_GPL(sym) +#define EXPORT_SYMBOL_GPL_FUTURE(sym) +#define EXPORT_UNUSED_SYMBOL(sym) +#define EXPORT_UNUSED_SYMBOL_GPL(sym) + +#endif diff --git a/scripts/include/linux/kernel.h b/scripts/include/linux/kernel.h new file mode 100644 index 0000000..5d94e98 --- /dev/null +++ b/scripts/include/linux/kernel.h @@ -0,0 +1,109 @@ +#ifndef __TOOLS_LINUX_KERNEL_H +#define __TOOLS_LINUX_KERNEL_H + +#include +#include +#include +#include + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + +#define PERF_ALIGN(x, a) __PERF_ALIGN_MASK(x, (typeof(x))(a)-1) +#define __PERF_ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#ifndef container_of +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member) * __mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) +#endif + +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) + +#ifndef max +#define max(x, y) ({ \ + typeof(x) _max1 = (x); \ + typeof(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) +#endif + +#ifndef min +#define min(x, y) ({ \ + typeof(x) _min1 = (x); \ + typeof(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) +#endif + +#ifndef roundup +#define roundup(x, y) ( \ +{ \ + const typeof(y) __y = y; \ + (((x) + (__y - 1)) / __y) * __y; \ +} \ +) +#endif + +#ifndef BUG_ON +#ifdef NDEBUG +#define BUG_ON(cond) do { if (cond) {} } while (0) +#else +#define BUG_ON(cond) assert(!(cond)) +#endif +#endif + +/* + * Both need more care to handle endianness + * (Don't use bitmap_copy_le() for now) + */ +#define cpu_to_le64(x) (x) +#define cpu_to_le32(x) (x) + +static inline int +vscnprintf(char *buf, size_t size, const char *fmt, va_list args) +{ + int i; + ssize_t ssize = size; + + i = vsnprintf(buf, size, fmt, args); + + return (i >= ssize) ? (ssize - 1) : i; +} + +static inline int scnprintf(char * buf, size_t size, const char * fmt, ...) +{ + va_list args; + ssize_t ssize = size; + int i; + + va_start(args, fmt); + i = vsnprintf(buf, size, fmt, args); + va_end(args); + + return (i >= ssize) ? (ssize - 1) : i; +} + +/* + * This looks more complex than it should be. But we need to + * get the type for the ~ right in round_down (it needs to be + * as wide as the result!), and we want to evaluate the macro + * arguments just once each. + */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define round_down(x, y) ((x) & ~__round_mask(x, y)) + +#endif diff --git a/scripts/include/linux/list.h b/scripts/include/linux/list.h new file mode 100644 index 0000000..1da4238 --- /dev/null +++ b/scripts/include/linux/list.h @@ -0,0 +1,771 @@ +#ifndef __TOOLS_LINUX_LIST_H +#define __TOOLS_LINUX_LIST_H + +#include +#include +#include +#include + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} +#else +extern void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next); +#endif + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + WRITE_ONCE(prev->next, next); +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +#ifndef CONFIG_DEBUG_LIST +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} +#else +extern void __list_del_entry(struct list_head *entry); +extern void list_del(struct list_head *entry); +#endif + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void list_replace(struct list_head *old, + struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void list_replace_init(struct list_head *old, + struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del_entry(entry); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del_entry(list); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del_entry(list); + list_add_tail(list, head); +} + +/** + * list_is_last - tests whether @list is the last entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_last(const struct list_head *list, + const struct list_head *head) +{ + return list->next == head; +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ + return head->next == head; +} + +/** + * list_empty_careful - tests whether a list is empty and not being modified + * @head: the list to test + * + * Description: + * tests whether a list is empty _and_ checks that no other CPU might be + * in the process of modifying either member (next or prev) + * + * NOTE: using list_empty_careful() without synchronization + * can only be safe if the only activity that can happen + * to the list entry is list_del_init(). Eg. it cannot be used + * if another CPU could re-list_add() it. + */ +static inline int list_empty_careful(const struct list_head *head) +{ + struct list_head *next = head->next; + return (next == head) && (next == head->prev); +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +/** + * list_is_singular - tests whether a list has just one entry. + * @head: the list to test. + */ +static inline int list_is_singular(const struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +static inline void __list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + struct list_head *new_first = entry->next; + list->next = head->next; + list->next->prev = list; + list->prev = entry; + entry->next = list; + head->next = new_first; + new_first->prev = head; +} + +/** + * list_cut_position - cut a list into two + * @list: a new list to add all removed entries + * @head: a list with entries + * @entry: an entry within head, could be the head itself + * and if so we won't cut the list + * + * This helper moves the initial part of @head, up to and + * including @entry, from @head to @list. You should + * pass on @entry an element you know is on @head. @list + * should be an empty list or a list you do not care about + * losing its data. + * + */ +static inline void list_cut_position(struct list_head *list, + struct list_head *head, struct list_head *entry) +{ + if (list_empty(head)) + return; + if (list_is_singular(head) && + (head->next != entry && head != entry)) + return; + if (entry == head) + INIT_LIST_HEAD(list); + else + __list_cut_position(list, head, entry); +} + +static inline void __list_splice(const struct list_head *list, + struct list_head *prev, + struct list_head *next) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + + first->prev = prev; + prev->next = first; + + last->next = next; + next->prev = last; +} + +/** + * list_splice - join two lists, this is designed for stacks + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(const struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head, head->next); +} + +/** + * list_splice_tail - join two lists, each list being a queue + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice_tail(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head->prev, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head, head->next); + INIT_LIST_HEAD(list); + } +} + +/** + * list_splice_tail_init - join two lists and reinitialise the emptied list + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * Each of the lists is a queue. + * The list at @list is reinitialised + */ +static inline void list_splice_tail_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head->prev, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +/** + * list_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note, that list is expected to be not empty. + */ +#define list_last_entry(ptr, type, member) \ + list_entry((ptr)->prev, type, member) + +/** + * list_first_entry_or_null - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note that if the list is empty, it returns NULL. + */ +#define list_first_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) + +/** + * list_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * list_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, typeof(*(pos)), member) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev; pos != (head); pos = pos->prev) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_prev_safe(pos, n, head) \ + for (pos = (head)->prev, n = pos->prev; \ + pos != (head); \ + pos = n, n = pos->prev) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_reverse - iterate backwards over list of given type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +/** + * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() + * @pos: the type * to use as a start point + * @head: the head of the list + * @member: the name of the list_head within the struct. + * + * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). + */ +#define list_prepare_entry(pos, head, member) \ + ((pos) ? : list_entry(head, typeof(*pos), member)) + +/** + * list_for_each_entry_continue - continue iteration over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_for_each_entry_continue(pos, head, member) \ + for (pos = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_continue_reverse - iterate backwards from the given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_for_each_entry_continue_reverse(pos, head, member) \ + for (pos = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = list_prev_entry(pos, member)) + +/** + * list_for_each_entry_from - iterate over list of given type from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_for_each_entry_from(pos, head, member) \ + for (; &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_continue - continue list iteration safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos = list_next_entry(pos, member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_from - iterate over list from current point safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_safe_from(pos, n, head, member) \ + for (n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/** + * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_last_entry(head, typeof(*pos), member), \ + n = list_prev_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_prev_entry(n, member)) + +/** + * list_safe_reset_next - reset a stale list_for_each_entry_safe loop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_head within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_safe_reset_next(pos, n, member) \ + n = list_next_entry(pos, member) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +static inline void INIT_HLIST_NODE(struct hlist_node *h) +{ + h->next = NULL; + h->pprev = NULL; +} + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + + WRITE_ONCE(*pprev, next); + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (!hlist_unhashed(n)) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_behind(struct hlist_node *n, + struct hlist_node *prev) +{ + n->next = prev->next; + prev->next = n; + n->pprev = &prev->next; + + if (n->next) + n->next->pprev = &n->next; +} + +/* after that we'll appear to be on some hlist and hlist_del will work */ +static inline void hlist_add_fake(struct hlist_node *n) +{ + n->pprev = &n->next; +} + +static inline bool hlist_fake(struct hlist_node *h) +{ + return h->pprev == &h->next; +} + +/* + * Move a list from one list head to another. Fixup the pprev + * reference of the first entry if it exists. + */ +static inline void hlist_move_list(struct hlist_head *old, + struct hlist_head *new) +{ + new->first = old->first; + if (new->first) + new->first->pprev = &new->first; + old->first = NULL; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos ; pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +#define hlist_entry_safe(ptr, type, member) \ + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + }) + +/** + * hlist_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(pos, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after current point + * @pos: the type * to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(pos, member) \ + for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\ + pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from current point + * @pos: the type * to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(pos, member) \ + for (; pos; \ + pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(pos, n, head, member) \ + for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\ + pos && ({ n = pos->member.next; 1; }); \ + pos = hlist_entry_safe(n, typeof(*pos), member)) + +/** + * list_del_range - deletes range of entries from list. + * @begin: first element in the range to delete from the list. + * @end: last element in the range to delete from the list. + * Note: list_empty on the range of entries does not return true after this, + * the entries is in an undefined state. + */ +static inline void list_del_range(struct list_head *begin, + struct list_head *end) +{ + begin->prev->next = end->next; + end->next->prev = begin->prev; +} + +/** + * list_for_each_from - iterate over a list from one of its nodes + * @pos: the &struct list_head to use as a loop cursor, from where to start + * @head: the head for your list. + */ +#define list_for_each_from(pos, head) \ + for (; pos != (head); pos = pos->next) + +#endif /* __TOOLS_LINUX_LIST_H */ diff --git a/scripts/include/linux/log2.h b/scripts/include/linux/log2.h new file mode 100644 index 0000000..4144666 --- /dev/null +++ b/scripts/include/linux/log2.h @@ -0,0 +1,185 @@ +/* Integer base 2 logarithm calculation + * + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.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. + */ + +#ifndef _TOOLS_LINUX_LOG2_H +#define _TOOLS_LINUX_LOG2_H + +/* + * deal with unrepresentable constant logarithms + */ +extern __attribute__((const, noreturn)) +int ____ilog2_NaN(void); + +/* + * non-constant log of base 2 calculators + * - the arch may override these in asm/bitops.h if they can be implemented + * more efficiently than using fls() and fls64() + * - the arch is not required to handle n==0 if implementing the fallback + */ +static inline __attribute__((const)) +int __ilog2_u32(u32 n) +{ + return fls(n) - 1; +} + +static inline __attribute__((const)) +int __ilog2_u64(u64 n) +{ + return fls64(n) - 1; +} + +/* + * Determine whether some value is a power of two, where zero is + * *not* considered a power of two. + */ + +static inline __attribute__((const)) +bool is_power_of_2(unsigned long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} + +/* + * round up to nearest power of two + */ +static inline __attribute__((const)) +unsigned long __roundup_pow_of_two(unsigned long n) +{ + return 1UL << fls_long(n - 1); +} + +/* + * round down to nearest power of two + */ +static inline __attribute__((const)) +unsigned long __rounddown_pow_of_two(unsigned long n) +{ + return 1UL << (fls_long(n) - 1); +} + +/** + * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value + * @n - parameter + * + * constant-capable log of base 2 calculation + * - this can be used to initialise global variables from constant data, hence + * the massive ternary operator construction + * + * selects the appropriately-sized optimised version depending on sizeof(n) + */ +#define ilog2(n) \ +( \ + __builtin_constant_p(n) ? ( \ + (n) < 1 ? ____ilog2_NaN() : \ + (n) & (1ULL << 63) ? 63 : \ + (n) & (1ULL << 62) ? 62 : \ + (n) & (1ULL << 61) ? 61 : \ + (n) & (1ULL << 60) ? 60 : \ + (n) & (1ULL << 59) ? 59 : \ + (n) & (1ULL << 58) ? 58 : \ + (n) & (1ULL << 57) ? 57 : \ + (n) & (1ULL << 56) ? 56 : \ + (n) & (1ULL << 55) ? 55 : \ + (n) & (1ULL << 54) ? 54 : \ + (n) & (1ULL << 53) ? 53 : \ + (n) & (1ULL << 52) ? 52 : \ + (n) & (1ULL << 51) ? 51 : \ + (n) & (1ULL << 50) ? 50 : \ + (n) & (1ULL << 49) ? 49 : \ + (n) & (1ULL << 48) ? 48 : \ + (n) & (1ULL << 47) ? 47 : \ + (n) & (1ULL << 46) ? 46 : \ + (n) & (1ULL << 45) ? 45 : \ + (n) & (1ULL << 44) ? 44 : \ + (n) & (1ULL << 43) ? 43 : \ + (n) & (1ULL << 42) ? 42 : \ + (n) & (1ULL << 41) ? 41 : \ + (n) & (1ULL << 40) ? 40 : \ + (n) & (1ULL << 39) ? 39 : \ + (n) & (1ULL << 38) ? 38 : \ + (n) & (1ULL << 37) ? 37 : \ + (n) & (1ULL << 36) ? 36 : \ + (n) & (1ULL << 35) ? 35 : \ + (n) & (1ULL << 34) ? 34 : \ + (n) & (1ULL << 33) ? 33 : \ + (n) & (1ULL << 32) ? 32 : \ + (n) & (1ULL << 31) ? 31 : \ + (n) & (1ULL << 30) ? 30 : \ + (n) & (1ULL << 29) ? 29 : \ + (n) & (1ULL << 28) ? 28 : \ + (n) & (1ULL << 27) ? 27 : \ + (n) & (1ULL << 26) ? 26 : \ + (n) & (1ULL << 25) ? 25 : \ + (n) & (1ULL << 24) ? 24 : \ + (n) & (1ULL << 23) ? 23 : \ + (n) & (1ULL << 22) ? 22 : \ + (n) & (1ULL << 21) ? 21 : \ + (n) & (1ULL << 20) ? 20 : \ + (n) & (1ULL << 19) ? 19 : \ + (n) & (1ULL << 18) ? 18 : \ + (n) & (1ULL << 17) ? 17 : \ + (n) & (1ULL << 16) ? 16 : \ + (n) & (1ULL << 15) ? 15 : \ + (n) & (1ULL << 14) ? 14 : \ + (n) & (1ULL << 13) ? 13 : \ + (n) & (1ULL << 12) ? 12 : \ + (n) & (1ULL << 11) ? 11 : \ + (n) & (1ULL << 10) ? 10 : \ + (n) & (1ULL << 9) ? 9 : \ + (n) & (1ULL << 8) ? 8 : \ + (n) & (1ULL << 7) ? 7 : \ + (n) & (1ULL << 6) ? 6 : \ + (n) & (1ULL << 5) ? 5 : \ + (n) & (1ULL << 4) ? 4 : \ + (n) & (1ULL << 3) ? 3 : \ + (n) & (1ULL << 2) ? 2 : \ + (n) & (1ULL << 1) ? 1 : \ + (n) & (1ULL << 0) ? 0 : \ + ____ilog2_NaN() \ + ) : \ + (sizeof(n) <= 4) ? \ + __ilog2_u32(n) : \ + __ilog2_u64(n) \ + ) + +/** + * roundup_pow_of_two - round the given value up to nearest power of two + * @n - parameter + * + * round the given value up to the nearest power of two + * - the result is undefined when n == 0 + * - this can be used to initialise global variables from constant data + */ +#define roundup_pow_of_two(n) \ +( \ + __builtin_constant_p(n) ? ( \ + (n == 1) ? 1 : \ + (1UL << (ilog2((n) - 1) + 1)) \ + ) : \ + __roundup_pow_of_two(n) \ + ) + +/** + * rounddown_pow_of_two - round the given value down to nearest power of two + * @n - parameter + * + * round the given value down to the nearest power of two + * - the result is undefined when n == 0 + * - this can be used to initialise global variables from constant data + */ +#define rounddown_pow_of_two(n) \ +( \ + __builtin_constant_p(n) ? ( \ + (1UL << ilog2(n))) : \ + __rounddown_pow_of_two(n) \ + ) + +#endif /* _TOOLS_LINUX_LOG2_H */ diff --git a/scripts/include/linux/poison.h b/scripts/include/linux/poison.h new file mode 100644 index 0000000..0c27bdf --- /dev/null +++ b/scripts/include/linux/poison.h @@ -0,0 +1 @@ +#include "../../../include/linux/poison.h" diff --git a/scripts/include/linux/string.h b/scripts/include/linux/string.h new file mode 100644 index 0000000..e26223f --- /dev/null +++ b/scripts/include/linux/string.h @@ -0,0 +1,15 @@ +#ifndef _TOOLS_LINUX_STRING_H_ +#define _TOOLS_LINUX_STRING_H_ + + +#include /* for size_t */ + +void *memdup(const void *src, size_t len); + +int strtobool(const char *s, bool *res); + +#ifndef __UCLIBC__ +extern size_t strlcpy(char *dest, const char *src, size_t size); +#endif + +#endif /* _LINUX_STRING_H_ */ diff --git a/scripts/include/linux/types.h b/scripts/include/linux/types.h new file mode 100644 index 0000000..8ebf627 --- /dev/null +++ b/scripts/include/linux/types.h @@ -0,0 +1,83 @@ +#ifndef _TOOLS_LINUX_TYPES_H_ +#define _TOOLS_LINUX_TYPES_H_ + +#include +#include +#include + +#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ +#include + +struct page; +struct kmem_cache; + +typedef enum { + GFP_KERNEL, + GFP_ATOMIC, + __GFP_HIGHMEM, + __GFP_HIGH +} gfp_t; + +/* + * We define u64 as uint64_t for every architecture + * so that we can print it with "%"PRIx64 without getting warnings. + * + * typedef __u64 u64; + * typedef __s64 s64; + */ +typedef uint64_t u64; +typedef int64_t s64; + +typedef __u32 u32; +typedef __s32 s32; + +typedef __u16 u16; +typedef __s16 s16; + +typedef __u8 u8; +typedef __s8 s8; + +#ifdef __CHECKER__ +#define __bitwise__ __attribute__((bitwise)) +#else +#define __bitwise__ +#endif +#ifdef __CHECK_ENDIAN__ +#define __bitwise __bitwise__ +#else +#define __bitwise +#endif + +#define __force +#define __user +#define __must_check +#define __cold + +typedef __u16 __bitwise __le16; +typedef __u16 __bitwise __be16; +typedef __u32 __bitwise __le32; +typedef __u32 __bitwise __be32; +typedef __u64 __bitwise __le64; +typedef __u64 __bitwise __be64; + +typedef struct { + int counter; +} atomic_t; + +#ifndef __aligned_u64 +# define __aligned_u64 __u64 __attribute__((aligned(8))) +#endif + +struct list_head { + struct list_head *next, *prev; +}; + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#endif /* _TOOLS_LINUX_TYPES_H_ */ diff --git a/scripts/include/tools/be_byteshift.h b/scripts/include/tools/be_byteshift.h new file mode 100644 index 0000000..84c17d8 --- /dev/null +++ b/scripts/include/tools/be_byteshift.h @@ -0,0 +1,70 @@ +#ifndef _TOOLS_BE_BYTESHIFT_H +#define _TOOLS_BE_BYTESHIFT_H + +#include + +static inline uint16_t __get_unaligned_be16(const uint8_t *p) +{ + return p[0] << 8 | p[1]; +} + +static inline uint32_t __get_unaligned_be32(const uint8_t *p) +{ + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +static inline uint64_t __get_unaligned_be64(const uint8_t *p) +{ + return (uint64_t)__get_unaligned_be32(p) << 32 | + __get_unaligned_be32(p + 4); +} + +static inline void __put_unaligned_be16(uint16_t val, uint8_t *p) +{ + *p++ = val >> 8; + *p++ = val; +} + +static inline void __put_unaligned_be32(uint32_t val, uint8_t *p) +{ + __put_unaligned_be16(val >> 16, p); + __put_unaligned_be16(val, p + 2); +} + +static inline void __put_unaligned_be64(uint64_t val, uint8_t *p) +{ + __put_unaligned_be32(val >> 32, p); + __put_unaligned_be32(val, p + 4); +} + +static inline uint16_t get_unaligned_be16(const void *p) +{ + return __get_unaligned_be16((const uint8_t *)p); +} + +static inline uint32_t get_unaligned_be32(const void *p) +{ + return __get_unaligned_be32((const uint8_t *)p); +} + +static inline uint64_t get_unaligned_be64(const void *p) +{ + return __get_unaligned_be64((const uint8_t *)p); +} + +static inline void put_unaligned_be16(uint16_t val, void *p) +{ + __put_unaligned_be16(val, p); +} + +static inline void put_unaligned_be32(uint32_t val, void *p) +{ + __put_unaligned_be32(val, p); +} + +static inline void put_unaligned_be64(uint64_t val, void *p) +{ + __put_unaligned_be64(val, p); +} + +#endif /* _TOOLS_BE_BYTESHIFT_H */ diff --git a/scripts/include/tools/endian.h b/scripts/include/tools/endian.h new file mode 100644 index 0000000..8001194 --- /dev/null +++ b/scripts/include/tools/endian.h @@ -0,0 +1,56 @@ +#ifndef _TOOLS_ENDIAN_H +#define _TOOLS_ENDIAN_H + +#include + +#if __BYTE_ORDER == __LITTLE_ENDIAN + +#ifndef htole16 +#define htole16(x) (x) +#endif +#ifndef htole32 +#define htole32(x) (x) +#endif +#ifndef htole64 +#define htole64(x) (x) +#endif + +#ifndef le16toh +#define le16toh(x) (x) +#endif + +#ifndef le32toh +#define le32toh(x) (x) +#endif + +#ifndef le64toh +#define le64toh(x) (x) +#endif + +#else /* __BYTE_ORDER */ + +#ifndef htole16 +#define htole16(x) __bswap_16(x) +#endif +#ifndef htole32 +#define htole32(x) __bswap_32(x) +#endif +#ifndef htole64 +#define htole64(x) __bswap_64(x) +#endif + +#ifndef le16toh +#define le16toh(x) __bswap_16(x) +#endif + +#ifndef le32toh +#define le32toh(x) __bswap_32(x) +#endif + +#ifndef le64toh +#define le64toh(x) __bswap_64(x) +#endif + +#endif + +#endif /* _TOOLS_ENDIAN_H */ diff --git a/scripts/include/tools/le_byteshift.h b/scripts/include/tools/le_byteshift.h new file mode 100644 index 0000000..8fe9f24 --- /dev/null +++ b/scripts/include/tools/le_byteshift.h @@ -0,0 +1,70 @@ +#ifndef _TOOLS_LE_BYTESHIFT_H +#define _TOOLS_LE_BYTESHIFT_H + +#include + +static inline uint16_t __get_unaligned_le16(const uint8_t *p) +{ + return p[0] | p[1] << 8; +} + +static inline uint32_t __get_unaligned_le32(const uint8_t *p) +{ + return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; +} + +static inline uint64_t __get_unaligned_le64(const uint8_t *p) +{ + return (uint64_t)__get_unaligned_le32(p + 4) << 32 | + __get_unaligned_le32(p); +} + +static inline void __put_unaligned_le16(uint16_t val, uint8_t *p) +{ + *p++ = val; + *p++ = val >> 8; +} + +static inline void __put_unaligned_le32(uint32_t val, uint8_t *p) +{ + __put_unaligned_le16(val >> 16, p + 2); + __put_unaligned_le16(val, p); +} + +static inline void __put_unaligned_le64(uint64_t val, uint8_t *p) +{ + __put_unaligned_le32(val >> 32, p + 4); + __put_unaligned_le32(val, p); +} + +static inline uint16_t get_unaligned_le16(const void *p) +{ + return __get_unaligned_le16((const uint8_t *)p); +} + +static inline uint32_t get_unaligned_le32(const void *p) +{ + return __get_unaligned_le32((const uint8_t *)p); +} + +static inline uint64_t get_unaligned_le64(const void *p) +{ + return __get_unaligned_le64((const uint8_t *)p); +} + +static inline void put_unaligned_le16(uint16_t val, void *p) +{ + __put_unaligned_le16(val, p); +} + +static inline void put_unaligned_le32(uint32_t val, void *p) +{ + __put_unaligned_le32(val, p); +} + +static inline void put_unaligned_le64(uint64_t val, void *p) +{ + __put_unaligned_le64(val, p); +} + +#endif /* _TOOLS_LE_BYTESHIFT_H */ diff --git a/scripts/mxsimage.c b/scripts/mxsimage.c index 0a5f6a0..2b1a5f3 100644 --- a/scripts/mxsimage.c +++ b/scripts/mxsimage.c @@ -16,12 +16,10 @@ #include #include #include +#include #define SB_BLOCK_SIZE 16 -#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static char *prepfile; static char *bootloaderfile;