iBoot/platform/generic/platform_dep.c

403 lines
10 KiB
C

/*
* Copyright (C) 2007-2015 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <arch.h>
#include <debug.h>
#include <drivers/aes.h>
#include <drivers/power.h>
#if WITH_HW_SEP
#include <drivers/sep/sep_client.h>
#endif
#if WITH_EFFACEABLE
#include <lib/effaceable.h>
#endif
#include <lib/image.h>
#include <lib/libc.h>
#include <lib/nonce.h>
#include <lib/random.h>
#include <lib/syscfg.h>
#include <platform.h>
#include <platform/chipid.h>
#include <platform/memmap.h>
#include <target.h>
#include <sys.h>
#include <sys/boot.h>
#include <sys/hash.h>
#include <sys/security.h>
#include <drivers/display.h>
// platfom_dep holds generic functions that are just defined once for all
// platforms, and are expected to be rebuilt for every target/product
#if !PLATFORM_VARIANT_IOP && !PLATFORM_VARIANT_AUDIO
#if (defined(__arm__) || defined(__arm64__))
# include <arch/arm/arm.h>
/*
* Default implementation of platform_cache_operation(), assumes the ARM architecture
* supplied functions are available and appropriate.
*/
void platform_cache_operation(int operation, void *address, u_int32_t length)
{
uintptr_t start, end;
void (*func)(addr_t addr);
/* all we are willing to do in the panic case is clean the entire cache */
if (unlikely(operation & CACHE_PANIC)) {
if ((operation & CACHE_CLEAN) && (NULL == address) && (0 == length))
arm_clean_dcache();
return;
}
/* disable interrupts as we don't want to be re-entered */
enter_critical_section();
if ((0 == address) && (0 == length)) {
/* invalidating the entire cache guarantees a crash */
ASSERT((operation & (CACHE_CLEAN | CACHE_INVALIDATE)) != CACHE_INVALIDATE);
/* whole-cache operations */
switch(operation & (CACHE_CLEAN | CACHE_INVALIDATE)) {
case CACHE_CLEAN:
arm_clean_dcache();
break;
case CACHE_CLEAN | CACHE_INVALIDATE:
arm_clean_invalidate_dcache();
break;
}
} else {
/* ranged operations by line */
start = (uintptr_t)address;
end = start + length;
switch (operation & (CACHE_CLEAN | CACHE_INVALIDATE)) {
case CACHE_INVALIDATE:
/*
* Non-aligned range invalidate operations are illegal
* as we may shoot something else sharing the line.
*/
ASSERT(0 == (start % CPU_CACHELINE_SIZE));
ASSERT(0 == (length % CPU_CACHELINE_SIZE));
/* invalidate */
func = arm_invalidate_dcache_line;
break;
case CACHE_CLEAN:
/* adjust start to the base of the cacheline */
start &= ~(CPU_CACHELINE_SIZE - 1);
func = arm_clean_dcache_line;
break;
case CACHE_CLEAN | CACHE_INVALIDATE:
/* adjust start to the base of the cacheline */
start &= ~(CPU_CACHELINE_SIZE - 1);
func = arm_clean_invalidate_dcache_line;
break;
default:
func = NULL;
}
/* do it */
if (likely(NULL != func))
for (; start < end; start += CPU_CACHELINE_SIZE)
func(start);
}
/* write buffer is address-agnostic */
if (operation & CACHE_DRAIN_WRITE_BUFFER)
arm_drain_write_buffer();
#if defined(__arm64__)
arm_memory_barrier();
#endif
exit_critical_section();
}
void platform_memory_barrier(void)
{
arm_memory_barrier();
}
#else
# error no architecture support for platform_cache_operation
#endif /* ARCH_ARM */
#endif // PLATFORM_VARIANT_IOP
// iBoot Flags
// Bit 0 - Restore host should send image capable of restore boot (a.k.a. iBEC).
// Bit 1 - Restore host should send ticket to validate images
// Bit 2 - Restore host should send Image4 images.
// Bit 3 - Current status of Secure fuse bit
// Bit 4 - Current status of Production fuse bit
// Bit 5 - Restore host should send images with SHA2-384 hash
uint32_t platform_get_iboot_flags(void)
{
u_int32_t flag_summary = 0;
#if WITH_RESTORE_STRAP
flag_summary |= (1 << 0);
#endif
#if WITH_TICKET
flag_summary |= (1 << 1);
#endif
#if WITH_IMAGE4
flag_summary |= (1 << 2);
#endif
if (platform_get_secure_mode()) flag_summary |= (1 << 3);
if (platform_get_current_production_mode()) flag_summary |= (1 << 4);
#if WITH_SHA2_384
flag_summary |= (1 << 5);
#endif
return flag_summary;
}
#ifndef PLATFORM_PRODUCT_ID
#define PLATFORM_PRODUCT_ID {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
#endif
const char* platform_get_product_id(void)
{
static const char product_id[] = PLATFORM_PRODUCT_ID;
return product_id;
}
u_int32_t platform_get_security_epoch(void)
{
#if WITH_IMAGE4
return chipid_get_minimum_epoch();
#else
u_int32_t build_epoch = PLATFORM_SECURITY_EPOCH;
u_int32_t minimum_epoch = chipid_get_minimum_epoch();
if (minimum_epoch < build_epoch) minimum_epoch = build_epoch;
return minimum_epoch;
#endif
}
#ifndef DEFAULT_RECOVERY_MODE_PRODUCT_ID
#define DEFAULT_RECOVERY_MODE_PRODUCT_ID 0x1281
#endif
/*
* platform_get_usb_product_id() - returns the usb product
*
*
*/
uint16_t platform_get_usb_product_id(void)
{
#if WITH_RECOVERY_MODE
return DEFAULT_RECOVERY_MODE_PRODUCT_ID;
#else
return 0x1226 + (platform_get_security_domain() & 3);
#endif
}
const char *platform_get_usb_product_string(void)
{
#if WITH_RECOVERY_MODE
return "Apple Mobile Device (Recovery Mode)";
#else
return "Apple Mobile Device (DFU Mode)";
#endif
}
// gUSBSerialNumber Format: "CPID:xxxx CPRV:xx CPFM:xx SCEP:xx BDID:xx ECID:xxxxxxxxxxxxxxxx IBFL:xx"
// optionally includes " SRTG:[<str24>]"
// optionally includes " SRNM:[xxxxxxxxxxxxxxxx]"
static char gUSBSerialNumber[127];
// Size iBoot SecureROM
// CPID (5 + 4) 9 9 9
// CPRV + 1 + (5 + 2) 8 17 17
// CPFM + 1 + (5 + 2) 8 25 25
// SCEP + 1 + (5 + 2) 8 33 33
// BDID + 1 + (5 + 2) 8 41 41
// ECID + 1 + (5 + 16) 22 63 63
// IBFL + 1 + (5 + 2) 8 71 71
// SRTG + 1 + (5 + 2 + 24) 32 103
// SRNM + 1 + (5 + 2 + 16) 24 95
// nul + 1 1 96 104
static u_int32_t gUSBSerialNumberStatus;
const char *platform_get_usb_serial_number_string(bool full)
{
char srnm_buf[1 + (5 + 2 + 16) + 1];
char imei_buf[1 + (5 + 2 + 16) + 1];
char srtg_buf[1 + (5 + 2 + 24) + 1];
int srnm_size = 0, imei_size = 0;
// Return if the request string has already been generated
if (gUSBSerialNumberStatus > 1) return gUSBSerialNumber;
if (!full && (gUSBSerialNumberStatus > 0)) return gUSBSerialNumber;
// Set the status based on the requested string
gUSBSerialNumberStatus = full ? 2 : 1;
srtg_buf[0] = '\0';
srnm_buf[srnm_size] = '\0';
imei_buf[imei_size] = '\0';
snprintf(gUSBSerialNumber, sizeof(gUSBSerialNumber),
"CPID:%04X CPRV:%02X CPFM:%02X SCEP:%02X BDID:%02X ECID:%016llX IBFL:%02X",
platform_get_chip_id(), platform_get_chip_revision(), platform_get_fuse_modes(),
platform_get_security_epoch(), platform_get_board_id(), platform_get_ecid_id(),
platform_get_iboot_flags());
#if APPLICATION_SECUREROM
snprintf(srtg_buf, sizeof(srtg_buf), " SRTG:[%s]", build_tag_string);
strlcat(gUSBSerialNumber, srtg_buf, sizeof(gUSBSerialNumber));
#endif
#if WITH_SYSCFG
strlcpy(srnm_buf, " SRNM:[", sizeof(srnm_buf));
srnm_size = syscfgCopyDataForTag('SrNm', (u_int8_t *)(srnm_buf + 7), 16);
if (srnm_size > 0) {
srnm_buf[7 + srnm_size] = '\0';
strlcat(srnm_buf, "]", sizeof(srnm_buf));
strlcat(gUSBSerialNumber, srnm_buf, sizeof(gUSBSerialNumber));
}
#endif
return gUSBSerialNumber;
}
// gUSBMoreOther Format: ""
// optionally includes " NONC:xxxxxxxxxxxxxxxx"
// optionally includes " SNON:xxxxxxxxxxxxxxxx"
static char gUSBMoreOther[127];
// SHA1:
// Size
// NONC + 1 + (5 + (2*20)) 46
// SNON + 1 + (5 + (2*20)) 46
// Total 92
//
// SHA2-384:
// Size
// NONC + 1 + (5 + (2*32)) 70
// SNON + 1 + (5 + (2*20)) 46
// Total 116
static u_int32_t gUSBMoreOtherStatus;
const char *platform_get_usb_more_other_string(bool full)
{
u_int64_t nonc;
u_int8_t nonc_hash[HASH_OUTPUT_SIZE];
char nonc_buf[1 + (5 + (2 * NONCE_HASH_OUTPUT_SIZE)) + 1];
u_int8_t i;
// Return if the request string has already been generated
if (gUSBMoreOtherStatus > 1) return gUSBMoreOther;
if (!full && (gUSBMoreOtherStatus > 0)) return gUSBMoreOther;
// Set the status based on the requested string
gUSBMoreOtherStatus = full ? 2 : 1;
nonc_buf[0] = '\0';
gUSBMoreOther[0] = '\0';
if (full) {
nonc = platform_get_nonce();
hash_calculate((const void *)&nonc, sizeof(nonc), (void *)nonc_hash, sizeof(nonc_hash));
strlcpy(nonc_buf, " NONC:", sizeof(nonc_buf));
for(i = 0; (i < NONCE_HASH_OUTPUT_SIZE) && (i < HASH_OUTPUT_SIZE); i++)
snprintf((nonc_buf + 1 + 5 + (i * 2)), (sizeof(nonc_buf) - 1 - 5 - (i * 2)), "%02X", nonc_hash[i]);
strlcat(gUSBMoreOther, nonc_buf, sizeof(gUSBMoreOther));
#if WITH_HW_SEP
u_int8_t snon[SEP_NONCE_SIZE];
if (platform_get_sep_nonce(snon) == 0) {
bzero(nonc_buf, sizeof(nonc_buf));
strlcpy(nonc_buf, " SNON:", sizeof(nonc_buf));
for(i = 0; (i < SEP_NONCE_SIZE); i++)
snprintf((nonc_buf + 1 + 5 + (i * 2)), (sizeof(nonc_buf) - 1 - 5 - (i * 2)), "%02X", snon[i]);
strlcat(gUSBMoreOther, nonc_buf, sizeof(gUSBMoreOther));
}
#endif
}
// dprintf(DEBUG_INFO, "%s, len=%ld\n", gUSBMoreOther, strlen(gUSBMoreOther));
return gUSBMoreOther;
}
u_int64_t platform_consume_nonce(void)
{
uint64_t nonce = 0;
const char* how = NULL;
#if WITH_EFFACEABLE
if (effaceable_consume_nonce(&nonce)) {
how = "effaced";
}
#elif WITH_NVRAM && WITH_ENV
if (mobile_ap_nonce_consume_nonce(&nonce)) {
how = "consumed";
}
#endif
#if WITH_RANDOM
if (!how) {
uint8_t *nonce_bytes = (uint8_t *)&nonce;
int result = random_get_bytes(nonce_bytes, sizeof(nonce));
RELEASE_ASSERT(result == 0);
if (result == 0) {
how = "generated";
}
}
#endif
if (!how) {
nonce = 0;
how = "zeroed";
}
#if DEBUG_BUILD
dprintf(DEBUG_INFO, "boot-nonce (%s): 0x%016llX\n", how, nonce);
#endif
return nonce;
}
size_t platform_get_display_memory_size(void)
{
size_t size = 0;
struct display_info info;
memset(&info, 0, sizeof(info));
display_get_info(&info);
if ((addr_t)info.framebuffer != 0)
size = (uintptr_t)PANIC_BASE - (uintptr_t)info.framebuffer;
#ifdef PURPLE_GFX_MEMORY_LEN
if (size < PURPLE_GFX_MEMORY_LEN)
size = PURPLE_GFX_MEMORY_LEN;
#endif
return (size);
}