Merge "aboot: fwlock: Add support for recovery PIN"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 35373d8..c03d456 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -1724,7 +1724,7 @@
#ifdef MDTP_SUPPORT
/* Go through Firmware Lock verification before continue with boot process */
mdtp_fwlock_verify_lock();
- fbcon_clear();
+ display_image_on_screen();
#endif /* MDTP_SUPPORT */
#if VERIFIED_BOOT
@@ -2384,7 +2384,7 @@
#ifdef MDTP_SUPPORT
/* Go through Firmware Lock verification before continue with boot process */
mdtp_fwlock_verify_lock();
- fbcon_clear();
+ display_image_on_screen();
#endif /* MDTP_SUPPORT */
if (target_is_emmc_boot())
@@ -2868,7 +2868,7 @@
#ifdef MDTP_SUPPORT
/* Go through Firmware Lock verification before continue with boot process */
mdtp_fwlock_verify_lock();
- fbcon_clear();
+ display_image_on_screen();
#endif /* MDTP_SUPPORT */
boot_linux_from_mmc();
diff --git a/app/aboot/mdtp.c b/app/aboot/mdtp.c
index 60b97b0..9ae9890 100644
--- a/app/aboot/mdtp.c
+++ b/app/aboot/mdtp.c
@@ -76,7 +76,7 @@
return -1;
}
- dprintf(INFO, "mdtp: read_DIP: SUCCESS, read %d bytes\n", actual_partition_size);
+ dprintf(SPEW, "mdtp: read_DIP: SUCCESS, read %d bytes\n", actual_partition_size);
return 0;
}
@@ -85,7 +85,6 @@
static int write_DIP(DIP_t *dip)
{
unsigned long long ptn = 0;
- uint32_t partition_size;
uint32_t block_size = mmc_get_device_blocksize();
int index = INVALID_PTN;
@@ -94,30 +93,25 @@
index = partition_get_index("dip");
ptn = partition_get_offset(index);
+
if(ptn == 0)
{
return -1;
}
- partition_size = partition_get_size(index);
-
- if(partition_size < size)
- {
- dprintf(CRITICAL, "mdtp: write_DIP: ERROR, DIP partition too small\n");
- return -1;
- }
-
- if(mmc_write(ptn, ROUNDUP(size, block_size), (void *)dip))
+ if(mmc_write(ptn, ROUNDUP(sizeof(DIP_t), block_size), (void *)dip))
{
dprintf(CRITICAL, "mdtp: write_DIP: ERROR, cannot read DIP info\n");
return -1;
}
+ dprintf(SPEW, "mdtp: write_DIP: SUCCESS, write %d bytes\n", ROUNDUP(sizeof(DIP_t), block_size));
+
return 0;
}
-/* Provision the DIP by storing the default DIP into the EMMC */
-static void provision_DIP()
+/* Deactivate MDTP by storing the default DIP into the EMMC */
+static void write_deactivated_DIP()
{
DIP_t *enc_dip;
DIP_t *dec_dip;
@@ -126,14 +120,14 @@
enc_dip = malloc(sizeof(DIP_t));
if (enc_dip == NULL)
{
- dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+ dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot allocate DIP\n");
return;
}
dec_dip = malloc(sizeof(DIP_t));
if (dec_dip == NULL)
{
- dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+ dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot allocate DIP\n");
free(enc_dip);
return;
}
@@ -145,21 +139,14 @@
ret = mdtp_tzbsp_enc_hash_DIP(dec_dip, enc_dip);
if(ret < 0)
{
- dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot cipher DIP\n");
+ dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot cipher DIP\n");
goto out;
}
ret = write_DIP(enc_dip);
if(ret < 0)
{
- dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot write DIP\n");
- goto out;
- }
-
- ret = mdtp_tzbsp_set_provisioned_fuse();
- if(ret < 0)
- {
- dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot set DIP_PROVISIONED fuse\n\n");
+ dprintf(CRITICAL, "mdtp: write_deactivated_DIP: ERROR, cannot write DIP\n");
goto out;
}
@@ -178,7 +165,7 @@
uint32_t block_size = mmc_get_device_blocksize();
uint32_t actual_partition_size = ROUNDUP(size, block_size);
- dprintf(INFO, "mdtp: verify_partition_single_hash: %s, %u\n", name, size);
+ dprintf(SPEW, "mdtp: verify_partition_single_hash: %s, %u\n", name, size);
ASSERT(name != NULL);
ASSERT(hash_table != NULL);
@@ -208,7 +195,7 @@
return -1;
}
- dprintf(INFO, "verify_partition_single_hash: %s: VERIFIED!\n", name);
+ dprintf(SPEW, "verify_partition_single_hash: %s: VERIFIED!\n", name);
return 0;
}
@@ -228,7 +215,7 @@
uint32_t bytes_to_read;
uint32_t block_num = 0;
- dprintf(INFO, "mdtp: verify_partition_block_hash: %s, %u\n", name, size);
+ dprintf(SPEW, "mdtp: verify_partition_block_hash: %s, %u\n", name, size);
ASSERT(name != NULL);
ASSERT(hash_table != NULL);
@@ -287,7 +274,7 @@
force_verify_block += 1;
}
- dprintf(INFO, "verify_partition_block_hash: %s: VERIFIED!\n", name);
+ dprintf(SPEW, "verify_partition_block_hash: %s: VERIFIED!\n", name);
return 0;
}
@@ -321,6 +308,75 @@
return 0;
}
+/* Display the recovery UI to allow the user to enter the PIN and continue boot */
+static int display_recovery_ui(DIP_t *dip)
+{
+ uint32_t pin_length = 0;
+ char entered_pin[MDTP_MAX_PIN_LEN+1] = {0};
+ uint32_t i;
+ uint32_t equal_count = 0, different_count = 0;
+
+ if (dip->mdtp_cfg.enable_local_pin_authentication)
+ {
+ dprintf(SPEW, "mdtp: display_recovery_ui: Local deactivation enabled\n");
+
+ pin_length = strlen(dip->mdtp_cfg.mdtp_pin.mdtp_pin);
+
+ if (pin_length > MDTP_MAX_PIN_LEN || pin_length < MDTP_MIN_PIN_LEN)
+ {
+ dprintf(CRITICAL, "mdtp: display_recovery_ui: Error, invalid PIN length\n");
+ display_error_msg();
+ return -1;
+ }
+
+ // Set entered_pin to initial '0' string + null terminator
+ for (i=0; i<pin_length; i++)
+ {
+ entered_pin[i] = '0';
+ }
+
+ // Allow the user to enter the PIN as many times as he wishes
+ // (with INVALID_PIN_DELAY_MSECONDS after each failed attempt)
+ while (1)
+ {
+ get_pin_from_user(entered_pin, pin_length);
+
+ // Go over the entire PIN in any case, to prevent side-channel attacks
+ for (i=0; i<pin_length; i++)
+ {
+ if (dip->mdtp_cfg.mdtp_pin.mdtp_pin[i] == entered_pin[i])
+ equal_count++;
+ else
+ different_count++;
+ }
+
+ if (equal_count == pin_length)
+ {
+ // Valid PIN - deactivate and continue boot
+ dprintf(SPEW, "mdtp: display_recovery_ui: valid PIN, continue boot\n");
+ write_deactivated_DIP();
+ return 0;
+ }
+ else
+ {
+ // Invalid PIN - display an appropriate message (which also includes a wait
+ // for INVALID_PIN_DELAY_MSECONDS), and allow the user to try again
+ dprintf(CRITICAL, "mdtp: display_recovery_ui: ERROR, invalid PIN\n");
+ display_invalid_pin_msg();
+
+ equal_count = 0;
+ different_count = 0;
+ }
+ }
+ }
+ else
+ {
+ dprintf(CRITICAL, "mdtp: display_recovery_ui: Local deactivation disabled, unable to display recovery UI\n");
+ display_error_msg();
+ return -1;
+ }
+}
+
/* Verify all protected partitinons according to the DIP */
static int verify_all_partitions(DIP_t *dip, verify_result_t *verify_result)
{
@@ -340,8 +396,6 @@
}
else if (dip->status == DIP_STATUS_ACTIVATED)
{
- show_checking_msg();
-
for(i=0; i<MAX_PARTITIONS; i++)
{
if(dip->partition_cfg[i].lock_enabled && dip->partition_cfg[i].size)
@@ -361,14 +415,12 @@
if (verify_failure)
{
dprintf(CRITICAL, "mdtp: verify_all_partitions: Failed partition verification\n");
- show_invalid_msg();
- return -1;
+ return 0;
}
}
*verify_result = VERIFY_OK;
- show_OK_msg();
return 0;
}
@@ -385,14 +437,14 @@
enc_dip = malloc(ROUNDUP(sizeof(DIP_t), block_size));
if (enc_dip == NULL)
{
- dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+ dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot allocate DIP\n");
return;
}
dec_dip = malloc(ROUNDUP(sizeof(DIP_t), block_size));
if (dec_dip == NULL)
{
- dprintf(CRITICAL, "mdtp: provision_DIP: ERROR, cannot allocate DIP\n");
+ dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot allocate DIP\n");
free(enc_dip);
return;
}
@@ -410,7 +462,7 @@
if(ret < 0)
{
dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, cannot verify DIP\n");
- show_invalid_msg();
+ display_error_msg();
goto out;
}
@@ -418,7 +470,7 @@
if(!verified)
{
dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, corrupted DIP\n");
- show_invalid_msg();
+ display_error_msg();
goto out;
}
@@ -432,14 +484,15 @@
if (verify_result == VERIFY_OK)
{
- dprintf(INFO, "mdtp: validate_DIP_and_firmware: Verify OK\n");
+ dprintf(SPEW, "mdtp: validate_DIP_and_firmware: Verify OK\n");
}
else if (verify_result == VERIFY_FAILED)
{
dprintf(CRITICAL, "mdtp: validate_DIP_and_firmware: ERROR, corrupted firmware\n");
+ display_recovery_ui(dec_dip);
} else /* VERIFY_SKIPPED */
{
- dprintf(INFO, "mdtp: validate_DIP_and_firmware: Verify skipped\n");
+ dprintf(SPEW, "mdtp: validate_DIP_and_firmware: Verify skipped\n");
}
out:
diff --git a/app/aboot/mdtp.h b/app/aboot/mdtp.h
index 9975899..d40807a 100644
--- a/app/aboot/mdtp.h
+++ b/app/aboot/mdtp.h
@@ -34,9 +34,13 @@
#define MAX_PARTITIONS 3
#define MAX_PARTITION_NAME_LEN 100
#define HASH_LEN 32
+#define MDTP_MIN_PIN_LEN 5
#define MDTP_MAX_PIN_LEN 8
#define DIP_PADDING 11
+#define INITIAL_DELAY_MSECONDS 5000
+#define INVALID_PIN_DELAY_MSECONDS 5000
+
#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
#define MDTP_FWLOCK_BLOCK_SIZE (1024*1024*16)
#define MDTP_FWLOCK_MAX_FILES (100)
@@ -104,19 +108,59 @@
VERIFY_FAILED,
} verify_result_t;
-/* Start Firmware Lock verification process */
+
+/**
+ * mdtp_fwlock_verify_lock
+ *
+ * Start Firmware Lock verification process.
+ *
+ * @return - negative value for an error, 0 for success.
+ */
int mdtp_fwlock_verify_lock();
-/* Return whether the MDTP is currently enabled or disabled in HW */
+/**
+ * mdtp_fuse_get_enabled
+ *
+ * Return whether the MDTP is currently enabled or
+ * disabled in HW.
+ *
+ * @param[out] enabled: set to true if MDTP enabled,
+ * false otherwise.
+ *
+ * @return - negative value for an error, 0 for success.
+ */
int mdtp_fuse_get_enabled(bool *enabled);
-/* Display the "Firmware Valid" screen */
-void show_OK_msg();
+/**
+ * get_pin_from_user
+ *
+ * Display the recovery PIN screen and set received buffer
+ * with the PIN the user has entered.
+ *
+ * @param[out] entered_pin: buffer holding the received PIN.
+ * @param[in] pin_length: PIN length (and also entered_pin buffer length).
+ *
+ * @return - None.
+ */
+void get_pin_from_user(char *entered_pin, uint32_t pin_length);
-/* Display the "Firmware Invalid" screen */
-void show_invalid_msg();
+/**
+ * display_invalid_pin_msg
+ *
+ * User has entered invalid PIN, display error message and
+ * allow the user to try again.
+ *
+ * @return - None.
+ */
+void display_invalid_pin_msg();
-/* Display the "Verifying Firmware" screen */
-void show_checking_msg();
+/**
+ * display_error_msg
+ *
+ * Display error message and stop boot process.
+ *
+ * @return - None.
+ */
+void display_error_msg();
#endif
diff --git a/app/aboot/mdtp_ui.c b/app/aboot/mdtp_ui.c
index 30d70d6..48d899e 100644
--- a/app/aboot/mdtp_ui.c
+++ b/app/aboot/mdtp_ui.c
@@ -32,31 +32,88 @@
#include <mmc.h>
#include <partition_parser.h>
#include <stdlib.h>
+#include <string.h>
#include "mdtp.h"
-#define MDTP_IMAGE_WIDTH 500
-#define MDTP_IMAGE_HEIGHT 800
-#define MDTP_UX_DELAY 1000
-#define MDTP_OK_OFFSET 0x0
-#define MDTP_CHECKING_OFFSET 0x200000
-#define MDTP_INVALID_OFFSET 0x400000
-#define MDTP_RECOVERED_OFFSET 0x600000
+// Image dimensions
+#define MDTP_ERROR_MSG_WIDTH (1412)
+#define MDTP_ERROR_MSG_HEIGHT (212)
+#define MDTP_MAIN_TEXT_WIDTH (1364)
+#define MDTP_MAIN_TEXT_HEIGHT (288)
+#define MDTP_PIN_DIGIT_WIDTH (180)
+#define MDTP_PIN_DIGIT_HEIGHT (180)
+#define MDTP_OK_BUTTON_WIDTH (644)
+#define MDTP_OK_BUTTON_HEIGHT (158)
+#define MDTP_DIGITS_INSTRUCTIONS_WIDTH (1384)
+#define MDTP_DIGITS_INSTRUCTIONS_HEIGHT (166)
+#define MDTP_PIN_INSTRUCTIONS_WIDTH (920)
+#define MDTP_PIN_INSTRUCTIONS_HEIGHT (204)
-extern uint32_t target_volume_down(void);
-extern void fbcon_putImage(struct fbimage *fbimg, bool flag);
+// Image offsets
+#define MDTP_ERROR_MSG_OFFSET (0x1000)
+#define MDTP_INITIAL_DELAY_OFFSET (0xDD000)
+#define MDTP_ENTER_PIN_OFFSET (0x1FD000)
+#define MDTP_INVALID_PIN_OFFSET (0x31D000)
+#define MDTP_PIN_DIGIT_0_OFFSET (0x43D000)
+#define MDTP_PIN_DIGITS_OFFSET (0x18000)
+#define MDTP_PIN_SELECTED_DIGIT_0_OFFSET (MDTP_PIN_DIGIT_0_OFFSET + 10*MDTP_PIN_DIGITS_OFFSET) // (0x52D000)
+#define MDTP_OK_BUTTON_OFFSET (0x61D000)
+#define MDTP_SELECTED_OK_BUTTON_OFFSET (0x668000)
+#define MDTP_DIGITS_INSTRUCTIONS_OFFSET (0x6B3000)
+#define MDTP_PIN_INSTRUCTIONS_OFFSET (0x75C000)
+
+// Image releative locations
+#define ERROR_MESSAGE_RELATIVE_Y_LOCATION (0.18)
+#define MAIN_TEXT_RELATIVE_Y_LOCATION (0.33)
+#define PIN_RELATIVE_Y_LOCATION (0.47)
+#define PIN_TEXT_RELATIVE_Y_LOCATION (0.57)
+#define OK_BUTTON_RELATIVE_Y_LOCATION (0.75)
+#define OK_TEXT_RELATIVE_Y_LOCATION (0.82)
+
+#define DIGIT_SPACE (12)
+
+#define MDTP_PRESSING_DELAY_MSEC (400)
+#define MDTP_MAX_IMAGE_SIZE (1183000) //size in bytes, includes some extra bytes since we round up to block size in read
+#define RGB888_BLACK (0x000000)
+#define BITS_PER_BYTE (8)
+
+
+#define CENTER_IMAGE_ON_X_AXIS(image_width,screen_width) ((screen_width-image_width)/2)
+
extern void mdelay(unsigned msecs);
+extern uint32_t target_volume_up();
+extern uint32_t target_volume_down();
-static struct fbimage mdtp_header;/* = {0};*/
+struct mdtp_fbimage {
+ uint32_t width;
+ uint32_t height;
+ uint8_t image[MDTP_MAX_IMAGE_SIZE];
+};
-/********************************************************************************/
+/*----------------------------------------------------------------------------
+ * Global Variables
+ * -------------------------------------------------------------------------*/
-/* Load the "Firmware Valid" image from EMMC */
-static struct fbimage* mdtp_images_mmc_OK()
+static uint32_t g_pin_frames_x_location[MDTP_MAX_PIN_LEN] = {0};
+static uint32_t g_pin_frames_y_location = 0;
+
+static bool g_initial_screen_displayed = false;
+
+static struct mdtp_fbimage g_mdtp_header;
+static struct fbcon_config *fb_config = NULL;
+
+/*----------------------------------------------------------------------------
+ * Local Functions
+ * -------------------------------------------------------------------------*/
+
+/**
+ * Load images from EMMC
+ */
+static struct mdtp_fbimage* mdtp_read_mmc_image(uint32_t offset, uint32_t width, uint32_t height)
{
int index = INVALID_PTN;
unsigned long long ptn = 0;
- struct fbcon_config *fb_display = NULL;
- struct fbimage *logo = &mdtp_header;
+ struct mdtp_fbimage *logo = &g_mdtp_header;
uint32_t block_size = mmc_get_device_blocksize();
index = partition_get_index("mdtp");
@@ -71,231 +128,475 @@
return NULL;
}
- fb_display = fbcon_display();
- if (fb_display)
+ if (fb_config)
{
- uint8_t *base = (uint8_t *) fb_display->base;
- base += LOGO_IMG_OFFSET;
+ uint8_t *base = logo->image;
- if (mmc_read(ptn, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
+ if (mmc_read(ptn+offset, (void*)base, ROUNDUP(width*height*3, block_size))) {
fbcon_clear();
dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
return NULL;
}
- logo->image = base;
+ logo->width = width;
+ logo->height = height;
}
return logo;
}
-/* Load the "Firmware Invalid" image from EMMC */
-static struct fbimage* mdtp_images_mmc_INVALID()
+/**
+ * flush fbcon display
+ *
+ * The function is duplicated from fbcon.c
+ */
+static void fbcon_flush(void)
{
- int index = INVALID_PTN;
- unsigned long long ptn = 0;
- struct fbcon_config *fb_display = NULL;
- struct fbimage *logo = &mdtp_header;
- uint32_t block_size = mmc_get_device_blocksize();
+ if (fb_config->update_start)
+ fb_config->update_start();
+ if (fb_config->update_done)
+ while (!fb_config->update_done());
+}
- index = partition_get_index("mdtp");
- if (index == 0) {
- dprintf(CRITICAL, "ERROR: mdtp Partition table not found\n");
- return NULL;
- }
+/**
+ * Clear complete section on the screen.
+ * The section is of section_height, and is located from the y
+ * coordinate and down.
+ */
+static void fbcon_clear_section(uint32_t y, uint32_t section_height)
+{
+ unsigned image_base;
+ unsigned bytes_per_bpp;
- ptn = partition_get_offset(index);
- if (ptn == 0) {
- dprintf(CRITICAL, "ERROR: mdtp Partition invalid\n");
- return NULL;
- }
-
- fb_display = fbcon_display();
- if (fb_display)
+ if (fb_config)
{
- uint8_t *base = (uint8_t *) fb_display->base;
- base += LOGO_IMG_OFFSET;
+ image_base = (y *(fb_config->width));
+ bytes_per_bpp = ((fb_config->bpp) / BITS_PER_BYTE);
- if (mmc_read(ptn+MDTP_INVALID_OFFSET, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
- fbcon_clear();
- dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
- return NULL;
- }
- logo->image = base;
+ unsigned count = fb_config->width*section_height;
+ memset(fb_config->base + image_base*bytes_per_bpp, RGB888_BLACK, count*bytes_per_bpp);
+
+ fbcon_flush();
}
-
- return logo;
-}
-
-/* Load the "Verifying Firmware" image from EMMC */
-static struct fbimage* mdtp_images_mmc_CHECKING()
-{
- int index = INVALID_PTN;
- unsigned long long ptn = 0;
- struct fbcon_config *fb_display = NULL;
- struct fbimage *logo = &mdtp_header;
- uint32_t block_size = mmc_get_device_blocksize();
-
- index = partition_get_index("mdtp");
- if (index == 0) {
- dprintf(CRITICAL, "ERROR: mdtp Partition table not found\n");
- return NULL;
- }
-
- ptn = partition_get_offset(index);
- if (ptn == 0) {
- dprintf(CRITICAL, "ERROR: mdtp Partition invalid\n");
- return NULL;
- }
-
- fb_display = fbcon_display();
- if (fb_display)
+ else
{
- uint8_t *base = (uint8_t *) fb_display->base;
- base += LOGO_IMG_OFFSET;
-
- if (mmc_read(ptn+MDTP_CHECKING_OFFSET, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
- fbcon_clear();
- dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
- return NULL;
- }
- logo->image = base;
+ dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+ display_error_msg();
}
-
- return logo;
}
-/* Load the "Verifying Firmware" image from EMMC */
-static struct fbimage* mdtp_images_mmc_RECOVERED()
+/**
+ * Put image at a specific (x,y) location on the screen.
+ * Duplicated from fbcon.c, with modifications to allow (x,y) location (instead of a centered image),
+ * and display bmp images properly (order of copying the lines to the screen was reversed)
+ */
+static void fbcon_putImage_in_location(struct mdtp_fbimage *fbimg, uint32_t x, uint32_t y)
{
- int index = INVALID_PTN;
- unsigned long long ptn = 0;
- struct fbcon_config *fb_display = NULL;
- struct fbimage *logo = &mdtp_header;
- uint32_t block_size = mmc_get_device_blocksize();
+ unsigned i = 0;
+ unsigned bytes_per_bpp;
+ unsigned image_base;
+ unsigned width, pitch, height;
+ unsigned char *logo_base = NULL;
- index = partition_get_index("mdtp");
- if (index == 0) {
- dprintf(CRITICAL, "ERROR: mdtp Partition table not found\n");
- return NULL;
+ if (!fb_config) {
+ dprintf(CRITICAL,"ERROR: NULL configuration, image cannot be displayed\n");
+ return;
}
- ptn = partition_get_offset(index);
- if (ptn == 0) {
- dprintf(CRITICAL, "ERROR: mdtp Partition invalid\n");
- return NULL;
+ if(fbimg) {
+ width = pitch = fbimg->width;
+ height = fbimg->height;
+ logo_base = (unsigned char *)fbimg->image;
+ }
+ else {
+ dprintf(CRITICAL,"ERROR: invalid image struct\n");
+ return;
}
- fb_display = fbcon_display();
- if (fb_display)
+ bytes_per_bpp = ((fb_config->bpp) / BITS_PER_BYTE);
+
+#if DISPLAY_TYPE_MIPI
+ if (bytes_per_bpp == 3)
{
- uint8_t *base = (uint8_t *) fb_display->base;
- base += LOGO_IMG_OFFSET;
+ if (fbimg->width == fb_config->width && fbimg->height == fb_config->height)
+ return;
- if (mmc_read(ptn+MDTP_RECOVERED_OFFSET, (void*)base, ROUNDUP(MDTP_IMAGE_WIDTH*MDTP_IMAGE_HEIGHT*3, block_size))) {
- fbcon_clear();
- dprintf(CRITICAL, "ERROR: mdtp image read failed\n");
- return NULL;
+ if (fbimg->width > fb_config->width || fbimg->height > fb_config->height)
+ {
+ dprintf(CRITICAL,"ERROR: invalid image size, larger than the screen\n");
+ return;
}
- logo->image = base;
+
+ image_base = ( (y *(fb_config->width)) + x);
+ for (i = 0; i < height; i++) {
+ memcpy (fb_config->base + ((image_base + (i * (fb_config->width))) * bytes_per_bpp),
+ logo_base + ((height - 1 - i) * pitch * bytes_per_bpp), width * bytes_per_bpp);
+ }
}
- return logo;
+ fbcon_flush();
+
+#if DISPLAY_MIPI_PANEL_NOVATEK_BLUE
+ if(is_cmd_mode_enabled())
+ mipi_dsi_cmd_mode_trigger();
+#endif
+
+#else
+ if (bytes_per_bpp == 2)
+ {
+ for (i = 0; i < fbimg->width; i++)
+ {
+ memcpy (fb_config->base + ((image_base + (i * (fb_config->width))) * bytes_per_bpp),
+ fbimg->image + (i * fbimg->height * bytes_per_bpp),
+ fbimg->height * bytes_per_bpp);
+ }
+ }
+ fbcon_flush();
+#endif
}
-/* Show the "Firmware Valid" image */
-static void display_image_on_screen_OK()
+/**
+ * Display main error message
+ */
+static int display_error_message()
{
- struct fbimage *fbimg;
+ struct mdtp_fbimage *fbimg;
- fbcon_clear();
- fbimg = mdtp_images_mmc_OK();
- fbimg->header.width = MDTP_IMAGE_WIDTH;
- fbimg->header.height = MDTP_IMAGE_HEIGHT;
+ fb_config = fbcon_display();
- dprintf(CRITICAL, "display_image_on_screen_OK\n");
- fbcon_putImage(fbimg, true);
+ if (fb_config)
+ {
+ uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_ERROR_MSG_WIDTH,fb_config->width);
+ uint32_t y = ((fb_config->height)*ERROR_MESSAGE_RELATIVE_Y_LOCATION);
+
+ fbimg = mdtp_read_mmc_image(MDTP_ERROR_MSG_OFFSET, MDTP_ERROR_MSG_WIDTH, MDTP_ERROR_MSG_HEIGHT);
+ if (NULL == fbimg)
+ {
+ dprintf(CRITICAL,"ERROR: failed to read error image from mmc\n");
+ return -1;
+ }
+
+ fbcon_putImage_in_location(fbimg, x, y);
+
+ return 0;
+ }
+ else
+ {
+ dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+ return -1;
+ }
}
-/* Show the "Firmware Invalid" image */
-static void display_image_on_screen_INVALID()
+/**
+ * Read from mmc the image in the given offset, of the given width and height.
+ * Then, display the image on the screen in the given (x,y) location.
+ */
+static void display_image(uint32_t offset, uint32_t width, uint32_t height, uint32_t x, uint32_t y)
{
- struct fbimage *fbimg;
+ struct mdtp_fbimage *fbimg;
- fbcon_clear();
- fbimg = mdtp_images_mmc_INVALID();
- fbimg->header.width = MDTP_IMAGE_WIDTH;
- fbimg->header.height = MDTP_IMAGE_HEIGHT;
+ if (fb_config)
+ {
+ fbimg = mdtp_read_mmc_image(offset, width, height);
+ if (NULL == fbimg)
+ {
+ dprintf(CRITICAL,"ERROR: failed to read image from mmc\n");
+ display_error_msg();
+ }
- dprintf(CRITICAL, "display_image_on_screen_INVALID\n");
- fbcon_putImage(fbimg, true);
+ fbcon_putImage_in_location(fbimg, x, y);
+ }
+ else
+ {
+ dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+ display_error_msg();
+ }
}
-/* Show the "Verifying Firmware" image */
-static void display_image_on_screen_CHECKING()
+/**
+ * Display initial delay message
+ */
+static void display_initial_delay()
{
- struct fbimage *fbimg;
+ uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_MAIN_TEXT_WIDTH,fb_config->width);
+ uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
- fbcon_clear();
- fbimg = mdtp_images_mmc_CHECKING();
- fbimg->header.width = MDTP_IMAGE_WIDTH;
- fbimg->header.height = MDTP_IMAGE_HEIGHT;
-
- dprintf(CRITICAL, "display_image_on_screen_CHECKING\n");
- fbcon_putImage(fbimg, true);
+ display_image(MDTP_INITIAL_DELAY_OFFSET, MDTP_MAIN_TEXT_WIDTH, MDTP_MAIN_TEXT_HEIGHT, x, y);
}
-/* Show the "Verifying Firmware" image */
-static void display_image_on_screen_RECOVERED()
+/**
+ * Display "enter PIN" message
+ */
+static void display_enter_pin()
{
- struct fbimage *fbimg;
+ uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_MAIN_TEXT_WIDTH,fb_config->width);
+ uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
- fbcon_clear();
- fbimg = mdtp_images_mmc_RECOVERED();
- fbimg->header.width = MDTP_IMAGE_WIDTH;
- fbimg->header.height = MDTP_IMAGE_HEIGHT;
-
- dprintf(CRITICAL, "display_image_on_screen_RECOVERED\n");
- fbcon_putImage(fbimg, true);
+ display_image(MDTP_ENTER_PIN_OFFSET, MDTP_MAIN_TEXT_WIDTH, MDTP_MAIN_TEXT_HEIGHT, x, y);
}
-/* Display the "Firmware Valid" screen */
-void show_OK_msg()
+/**
+ * Display invalid PIN message
+ */
+static void display_invalid_pin()
{
- display_image_on_screen_OK();
- mdelay(MDTP_UX_DELAY);
+ uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_MAIN_TEXT_WIDTH,fb_config->width);
+ uint32_t y = (fb_config->height)*MAIN_TEXT_RELATIVE_Y_LOCATION;
- return;
+ display_image(MDTP_INVALID_PIN_OFFSET, MDTP_MAIN_TEXT_WIDTH, MDTP_MAIN_TEXT_HEIGHT, x, y);
}
-/* Display the "Firmware Invalid" screen */
-void show_invalid_msg()
+/**
+ * Clear digits instructions
+ */
+static void display_digits_instructions()
{
- display_image_on_screen_INVALID();
+ uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_DIGITS_INSTRUCTIONS_WIDTH,fb_config->width);
+ uint32_t y = (fb_config->height)*PIN_TEXT_RELATIVE_Y_LOCATION;
+
+ display_image(MDTP_DIGITS_INSTRUCTIONS_OFFSET, MDTP_DIGITS_INSTRUCTIONS_WIDTH, MDTP_DIGITS_INSTRUCTIONS_HEIGHT, x, y);
+}
+
+/**
+ * Clear digits instructions
+ */
+static void clear_digits_instructions()
+{
+ uint32_t y = (fb_config->height)*PIN_TEXT_RELATIVE_Y_LOCATION;
+
+ fbcon_clear_section(y, MDTP_DIGITS_INSTRUCTIONS_HEIGHT);
+}
+
+/**
+ * Display a digit as un-selected.
+ */
+static void display_digit(uint32_t x, uint32_t y, uint32_t digit)
+{
+ display_image(MDTP_PIN_DIGIT_0_OFFSET + digit*MDTP_PIN_DIGITS_OFFSET,
+ MDTP_PIN_DIGIT_WIDTH, MDTP_PIN_DIGIT_HEIGHT, x, y);
+}
+
+/**
+ * Display a digit as selected.
+ */
+static void display_selected_digit(uint32_t x, uint32_t y, uint32_t digit)
+{
+ display_image(MDTP_PIN_SELECTED_DIGIT_0_OFFSET + digit*MDTP_PIN_DIGITS_OFFSET,
+ MDTP_PIN_DIGIT_WIDTH, MDTP_PIN_DIGIT_HEIGHT, x, y);
+}
+
+/**
+ * Display OK button as un-selected.
+ */
+static void display_ok_button()
+{
+ uint32_t ok_x = CENTER_IMAGE_ON_X_AXIS(MDTP_OK_BUTTON_WIDTH,fb_config->width);
+ uint32_t ok_y = (fb_config->height)*OK_BUTTON_RELATIVE_Y_LOCATION;
+
+ display_image(MDTP_OK_BUTTON_OFFSET, MDTP_OK_BUTTON_WIDTH, MDTP_OK_BUTTON_HEIGHT, ok_x, ok_y);
+}
+
+/**
+ * Display OK button as selected.
+ */
+static void display_selected_ok_button()
+{
+ uint32_t ok_x = CENTER_IMAGE_ON_X_AXIS(MDTP_OK_BUTTON_WIDTH,fb_config->width);
+ uint32_t ok_y = (fb_config->height)*OK_BUTTON_RELATIVE_Y_LOCATION;
+
+ display_image(MDTP_SELECTED_OK_BUTTON_OFFSET, MDTP_OK_BUTTON_WIDTH, MDTP_OK_BUTTON_HEIGHT, ok_x, ok_y);
+}
+
+/**
+ * Display the instructions for the OK button.
+ */
+static void display_pin_instructions()
+{
+ uint32_t x = CENTER_IMAGE_ON_X_AXIS(MDTP_PIN_INSTRUCTIONS_WIDTH,fb_config->width);
+ uint32_t y = (fb_config->height)*OK_TEXT_RELATIVE_Y_LOCATION;
+
+ display_image(MDTP_PIN_INSTRUCTIONS_OFFSET, MDTP_PIN_INSTRUCTIONS_WIDTH, MDTP_PIN_INSTRUCTIONS_HEIGHT, x, y);
+}
+
+/**
+ * Clear the instructions for the OK button.
+ */
+static void clear_pin_message()
+{
+ uint32_t y = (fb_config->height)*OK_TEXT_RELATIVE_Y_LOCATION;
+
+ fbcon_clear_section(y, MDTP_PIN_INSTRUCTIONS_HEIGHT);
+}
+
+/**
+ * Display the basic layout of the screen (done only once).
+ */
+static void display_initial_screen(uint32_t pin_length)
+{
+ if (g_initial_screen_displayed == true)
+ return;
+
+ fb_config = fbcon_display();
+
+ if (fb_config)
+ {
+ fbcon_clear();
+
+ if (display_error_message())
+ display_error_msg();
+ display_initial_delay();
+
+ mdelay(INITIAL_DELAY_MSECONDS);
+
+ g_pin_frames_y_location = ((fb_config->height)*PIN_RELATIVE_Y_LOCATION);
+
+ uint32_t total_pin_length = pin_length*MDTP_PIN_DIGIT_WIDTH + DIGIT_SPACE*(pin_length - 1);
+ uint32_t complete_pin_centered = (fb_config->width - total_pin_length)/2;
+
+ for (int i=0; i<(int)pin_length; i++)
+ {
+ g_pin_frames_x_location[i] = complete_pin_centered + i*(DIGIT_SPACE+MDTP_PIN_DIGIT_WIDTH);
+ }
+
+ for (int i=0; i<(int)pin_length; i++)
+ {
+ display_digit(g_pin_frames_x_location[i], g_pin_frames_y_location, 0);
+ }
+
+ display_ok_button();
+
+ g_initial_screen_displayed = true;
+ }
+ else
+ {
+ dprintf(CRITICAL,"ERROR: fbcon_config struct is NULL\n");
+ display_error_msg();
+ return;
+ }
+}
+
+/**
+ * Display the recovery PIN screen and set received buffer
+ * with the PIN the user has entered.
+ * The entered PIN will be validated by the calling function.
+ */
+static void display_get_pin_interface(char *entered_pin, uint32_t pin_length)
+{
+ uint32_t previous_position = 0, current_position = 0;
+
+ display_initial_screen(pin_length);
+ display_enter_pin();
+
+ // Convert ascii to digits
+ for (uint32_t i=0; i<pin_length; i++)
+ {
+ entered_pin[i] -= '0';
+ }
+ display_selected_digit(g_pin_frames_x_location[0], g_pin_frames_y_location, entered_pin[0]);
+ display_digits_instructions();
while (1)
{
- if(target_volume_down())
+ if (target_volume_up())
{
- display_image_on_screen_RECOVERED();
- mdelay(MDTP_UX_DELAY);
- break;
+ // current position is the OK button
+ if (current_position == pin_length)
+ {
+ // Convert digits to ascii and
+ // validate entered PIN in the calling function
+ for (uint32_t i=0; i<pin_length; i++)
+ {
+ entered_pin[i] += '0';
+ }
+ return;
+ }
+
+ // current position is a PIN slot
+ entered_pin[current_position] = (entered_pin[current_position]+1) % 10;
+ display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
+ mdelay(MDTP_PRESSING_DELAY_MSEC);
+ }
+ if (target_volume_down())
+ {
+ previous_position = current_position;
+ current_position = (current_position+1) % (pin_length+1);
+
+ // previous position was the OK button
+ if (previous_position == pin_length)
+ {
+ clear_pin_message();
+ display_ok_button();
+
+ display_digits_instructions();
+ display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
+
+ }
+
+ // current position is the OK button
+ else if (current_position == pin_length)
+ {
+ display_digit(g_pin_frames_x_location[previous_position], g_pin_frames_y_location, entered_pin[previous_position]);
+ clear_digits_instructions();
+
+ display_selected_ok_button();
+ display_pin_instructions();
+ }
+
+ // both the previous and the current positions are PIN slots
+ else
+ {
+ display_digit(g_pin_frames_x_location[previous_position], g_pin_frames_y_location, entered_pin[previous_position]);
+
+ display_selected_digit(g_pin_frames_x_location[current_position], g_pin_frames_y_location, entered_pin[current_position]);
+ }
+
+ mdelay(MDTP_PRESSING_DELAY_MSEC);
}
}
+}
+
+/*----------------------------------------------------------------------------
+ * External Functions
+ * -------------------------------------------------------------------------*/
+
+/**
+ * Display the recovery PIN screen and set received buffer
+ * with the PIN the user has entered.
+ */
+void get_pin_from_user(char *entered_pin, uint32_t pin_length)
+{
+ display_get_pin_interface(entered_pin, pin_length);
return;
}
-/* Display the "Verifying Firmware" screen */
-void show_checking_msg()
+/**
+ * User has entered invalid PIN, display error message and
+ * allow the user to try again.
+ */
+void display_invalid_pin_msg()
{
- display_image_on_screen_CHECKING();
- return;
+ clear_pin_message();
+ display_ok_button();
+
+ display_invalid_pin();
+
+ mdelay(INVALID_PIN_DELAY_MSECONDS);
}
-/* Display the "Verifying Firmware" screen */
-void show_recovered_msg()
+/**
+ * Display error message and stop boot process.
+ */
+void display_error_msg()
{
- display_image_on_screen_RECOVERED();
- return;
+ fbcon_clear();
+ display_error_message(); // No point in checking the return value here
+
+ // Invalid state. Nothing to be done but contacting the OEM.
+ // Stop boot process.
+ dprintf(CRITICAL,"ERROR: blocking boot process\n");
+ while(1)
+ {
+
+ }
}
diff --git a/target/msm8994/init.c b/target/msm8994/init.c
index 6dc9ce9..824bdc1 100644
--- a/target/msm8994/init.c
+++ b/target/msm8994/init.c
@@ -105,7 +105,7 @@
}
/* Return 1 if vol_up pressed */
-static int target_volume_up()
+int target_volume_up()
{
uint8_t status = 0;
struct pm8x41_gpio gpio;