diff options
Diffstat (limited to 'plat/arm/css/common/css_scp_bootloader.c')
-rw-r--r-- | plat/arm/css/common/css_scp_bootloader.c | 165 |
1 files changed, 97 insertions, 68 deletions
diff --git a/plat/arm/css/common/css_scp_bootloader.c b/plat/arm/css/common/css_scp_bootloader.c index b0bd4175..c6d63f29 100644 --- a/plat/arm/css/common/css_scp_bootloader.c +++ b/plat/arm/css/common/css_scp_bootloader.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -29,125 +29,154 @@ */ #include <arch_helpers.h> +#include <assert.h> #include <css_def.h> +#include <debug.h> #include <platform.h> +#include <stdint.h> #include "css_mhu.h" #include "css_scp_bootloader.h" #include "css_scpi.h" -/* Boot commands sent from AP -> SCP */ -#define BOOT_CMD_START 0x01 -#define BOOT_CMD_DATA 0x02 +/* ID of the MHU slot used for the BOM protocol */ +#define BOM_MHU_SLOT_ID 0 -typedef struct { - uint32_t image_size; -} cmd_start_payload; +/* Boot commands sent from AP -> SCP */ +#define BOOT_CMD_INFO 0x00 +#define BOOT_CMD_DATA 0x01 +/* BOM command header */ typedef struct { - uint32_t sequence_num; - uint32_t offset; - uint32_t size; -} cmd_data_payload; - -#define BOOT_DATA_MAX_SIZE 0x1000 - -/* Boot commands sent from SCP -> AP */ -#define BOOT_CMD_ACK 0x03 -#define BOOT_CMD_NACK 0x04 + uint32_t id : 8; + uint32_t reserved : 24; +} bom_cmd_t; typedef struct { - uint32_t sequence_num; -} cmd_ack_payload; + uint32_t image_size; + uint32_t checksum; +} cmd_info_payload_t; /* - * Unlike the runtime protocol, the boot protocol uses the same memory region + * Unlike the SCPI protocol, the boot protocol uses the same memory region * for both AP -> SCP and SCP -> AP transfers; define the address of this... */ -static void * const cmd_payload = (void *)(MHU_SECURE_BASE + 0x0080); +#define BOM_SHARED_MEM (MHU_SECURE_BASE + 0x0080) +#define BOM_CMD_HEADER ((bom_cmd_t *) BOM_SHARED_MEM) +#define BOM_CMD_PAYLOAD ((void *) (BOM_SHARED_MEM + sizeof(bom_cmd_t))) -static void *scp_boot_message_start(void) -{ - mhu_secure_message_start(); +typedef struct { + /* Offset from the base address of the Trusted RAM */ + uint32_t offset; + uint32_t block_size; +} cmd_data_payload_t; - return cmd_payload; +static void scp_boot_message_start(void) +{ + mhu_secure_message_start(BOM_MHU_SLOT_ID); } -static void scp_boot_message_send(unsigned command, size_t size) +static void scp_boot_message_send(size_t payload_size) { /* Make sure payload can be seen by SCP */ if (MHU_PAYLOAD_CACHED) - flush_dcache_range((unsigned long)cmd_payload, size); + flush_dcache_range(BOM_SHARED_MEM, + sizeof(bom_cmd_t) + payload_size); /* Send command to SCP */ - mhu_secure_message_send(command | (size << 8)); + mhu_secure_message_send(BOM_MHU_SLOT_ID); } static uint32_t scp_boot_message_wait(size_t size) { - uint32_t response = mhu_secure_message_wait(); + uint32_t mhu_status; + + mhu_status = mhu_secure_message_wait(); + + /* Expect an SCP Boot Protocol message, reject any other protocol */ + if (mhu_status != (1 << BOM_MHU_SLOT_ID)) { + ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", + mhu_status); + panic(); + } /* Make sure we see the reply from the SCP and not any stale data */ if (MHU_PAYLOAD_CACHED) - inv_dcache_range((unsigned long)cmd_payload, size); + inv_dcache_range(BOM_SHARED_MEM, size); - return response & 0xff; + return *(uint32_t *) BOM_SHARED_MEM; } static void scp_boot_message_end(void) { - mhu_secure_message_end(); + mhu_secure_message_end(BOM_MHU_SLOT_ID); } -static int transfer_block(uint32_t sequence_num, uint32_t offset, uint32_t size) +int scp_bootloader_transfer(void *image, unsigned int image_size) { - cmd_data_payload *cmd_data = scp_boot_message_start(); - cmd_data->sequence_num = sequence_num; - cmd_data->offset = offset; - cmd_data->size = size; + uint32_t response; + uint32_t checksum; + cmd_info_payload_t *cmd_info_payload; + cmd_data_payload_t *cmd_data_payload; - scp_boot_message_send(BOOT_CMD_DATA, sizeof(*cmd_data)); + assert((uintptr_t) image == BL30_BASE); - cmd_ack_payload *cmd_ack = cmd_payload; - int ok = scp_boot_message_wait(sizeof(*cmd_ack)) == BOOT_CMD_ACK - && cmd_ack->sequence_num == sequence_num; + if ((image_size == 0) || (image_size % 4 != 0)) { + ERROR("Invalid size for the BL3-0 image. Must be a multiple of " + "4 bytes and not zero (current size = 0x%x)\n", + image_size); + return -1; + } - scp_boot_message_end(); + /* Extract the checksum from the image */ + checksum = *(uint32_t *) image; + image = (char *) image + sizeof(checksum); + image_size -= sizeof(checksum); - return ok; -} + mhu_secure_init(); -int scp_bootloader_transfer(void *image, unsigned int image_size) -{ - uintptr_t offset = (uintptr_t)image - MHU_SECURE_BASE; - uintptr_t end = offset + image_size; - uint32_t response; + VERBOSE("Send info about the BL3-0 image to be transferred to SCP\n"); - mhu_secure_init(); + /* + * Send information about the SCP firmware image about to be transferred + * to SCP + */ + scp_boot_message_start(); + + BOM_CMD_HEADER->id = BOOT_CMD_INFO; + cmd_info_payload = BOM_CMD_PAYLOAD; + cmd_info_payload->image_size = image_size; + cmd_info_payload->checksum = checksum; + + scp_boot_message_send(sizeof(*cmd_info_payload)); + response = scp_boot_message_wait(sizeof(response)); + scp_boot_message_end(); - /* Initiate communications with SCP */ - do { - cmd_start_payload *cmd_start = scp_boot_message_start(); - cmd_start->image_size = image_size; + if (response != 0) { + ERROR("SCP BOOT_CMD_INFO returned error %u\n", response); + return -1; + } + + VERBOSE("Transferring BL3-0 image to SCP\n"); - scp_boot_message_send(BOOT_CMD_START, sizeof(*cmd_start)); + /* Transfer BL3-0 image to SCP */ + scp_boot_message_start(); - response = scp_boot_message_wait(0); + BOM_CMD_HEADER->id = BOOT_CMD_DATA; + cmd_data_payload = BOM_CMD_PAYLOAD; + cmd_data_payload->offset = (uintptr_t) image - MHU_SECURE_BASE; + cmd_data_payload->block_size = image_size; - scp_boot_message_end(); - } while (response != BOOT_CMD_ACK); + scp_boot_message_send(sizeof(*cmd_data_payload)); + response = scp_boot_message_wait(sizeof(response)); + scp_boot_message_end(); - /* Transfer image to SCP a block at a time */ - uint32_t sequence_num = 1; - size_t size; - while ((size = end - offset) != 0) { - if (size > BOOT_DATA_MAX_SIZE) - size = BOOT_DATA_MAX_SIZE; - while (!transfer_block(sequence_num, offset, size)) - ; /* Retry forever */ - offset += size; - sequence_num++; + if (response != 0) { + ERROR("SCP BOOT_CMD_DATA returned error %u\n", response); + return -1; } + VERBOSE("Waiting for SCP to signal it is ready to go on\n"); + /* Wait for SCP to signal it's ready */ return scpi_wait_ready(); } |