first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

+114
View File
@@ -0,0 +1,114 @@
#include <lib/env.h>
#include <stdlib.h>
#include <lib/nvram.h>
#include <debug.h>
#include <platform.h>
#include <arch.h>
#define BREADCRUMB_BUFFER_SIZE 256 // This is arbitrarily sized, should be large enough for
// sensible options of key/value
#define BREADCRUMB_MIN_SIZE 3 // Smallest size of a breadcrumb
typedef struct {
char* buffer; // Storage for the breadcrumbs
int buffer_len; // Length of breadcrumb buffer
int wrpos; // Current write position
} breadcrumb_store_t;
static bool initialized = false;
breadcrumb_store_t breadcrumb_store;
static char* bc_cur_pos (void)
{
ASSERT(breadcrumb_store.wrpos <= breadcrumb_store.buffer_len);
return &breadcrumb_store.buffer[breadcrumb_store.wrpos];
}
static int bc_remaining (void)
{
ASSERT(breadcrumb_store.wrpos <= breadcrumb_store.buffer_len);
return breadcrumb_store.buffer_len - breadcrumb_store.wrpos;
}
void _platform_init_breadcrumbs_internal(void)
{
if (!initialized) {
breadcrumb_store.buffer = malloc(BREADCRUMB_BUFFER_SIZE);
breadcrumb_store.wrpos = 0;
breadcrumb_store.buffer_len = BREADCRUMB_BUFFER_SIZE;
initialized = (breadcrumb_store.buffer != NULL);
dprintf(DEBUG_INFO, "breadcrumb store initialized at %p\n", breadcrumb_store.buffer);
platform_record_breadcrumb_marker("BOOT");
}
}
void _platform_record_breadcrumb_internal(const char* key, const char* val)
{
if (initialized && bc_remaining() > BREADCRUMB_MIN_SIZE) {
int count = (int)snprintf(bc_cur_pos(), bc_remaining(), "%s=%s, ", key, val);
if (count > 0)
breadcrumb_store.wrpos += strlen(bc_cur_pos());
}
}
void _platform_record_breadcrumb_marker_internal(const char* val)
{
if (initialized && bc_remaining() > BREADCRUMB_MIN_SIZE) {
int count = (int)snprintf(bc_cur_pos(), bc_remaining(), "<%s> ", val);
if (count > 0)
breadcrumb_store.wrpos += strlen(bc_cur_pos());
}
}
void _platform_record_breadcrumb_int_internal(const char* key, int val)
{
if (initialized && bc_remaining() > BREADCRUMB_MIN_SIZE) {
int count = (int)snprintf(bc_cur_pos(), bc_remaining(), "%s=%d, ", key, val);
if (count > 0)
breadcrumb_store.wrpos += strlen(bc_cur_pos());
}
}
void _platform_commit_breadcrumbs_internal(const char* envvar)
{
if (initialized) {
platform_record_breadcrumb_marker("DONE");
// We expect this buffer to always be NULL terminated since it was built using
// snprintf(), but just to be sure, make sure the end of the buffer is terminated.
breadcrumb_store.buffer[breadcrumb_store.buffer_len - 1] = '\0';
const char* existing_breadcrumbs = env_get(envvar);
if (existing_breadcrumbs) {
dprintf(DEBUG_INFO, "Existing breadcrumbs found: '%s'\n", existing_breadcrumbs);
// If there's already iBoot breadcrumbs, we should preserve them chronologically
// (earliest first). Since we need to prepend, we might as well swap it with
// a new buffer.
if (bc_remaining() < (int)strlen(existing_breadcrumbs)) {
// Existing breadcrumbs would not fit. Drop the oldest breadcrumbs first
existing_breadcrumbs += ((int)strlen(existing_breadcrumbs) - bc_remaining());
}
char* tmp_buf = malloc(BREADCRUMB_BUFFER_SIZE);
if (tmp_buf) {
int count = snprintf(tmp_buf, BREADCRUMB_BUFFER_SIZE, "%s%s", existing_breadcrumbs, breadcrumb_store.buffer);
if (count >= 0 && count < BREADCRUMB_BUFFER_SIZE)
breadcrumb_store.wrpos = count;
else
breadcrumb_store.wrpos = 0;
free(breadcrumb_store.buffer);
breadcrumb_store.buffer = tmp_buf;
}
}
dprintf(DEBUG_INFO, "Committing breadcrumbs [used %d of %d bytes]: Setting '%s'='%s'\n", breadcrumb_store.wrpos, breadcrumb_store.buffer_len, envvar, breadcrumb_store.buffer);
env_set(envvar, breadcrumb_store.buffer, ENV_PERSISTENT);
nvram_save();
initialized=false; // Stop recording breadcrumbs and make redundant commits a no-op.
}
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2008,2014-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.
*/
#if !APPLICATION_SECUREROM
#include <lib/mib.h>
#include <platform.h>
// Default MIB Application/Product
MIB_CONSTANT_WEAK(kMIBTargetApplicationProduct, kOIDTypeUInt32, 0);
// Default MIB build configuration constants
MIB_CONSTANT_WEAK(kMIBTargetWithHwAsp, kOIDTypeBoolean, false);
MIB_CONSTANT_WEAK(kMIBTargetWithEffaceable, kOIDTypeBoolean, false);
MIB_CONSTANT_WEAK(kMIBTargetWithFileSystem, kOIDTypeBoolean, false);
MIB_CONSTANT_WEAK(kMIBTargetWithHwFlashNand, kOIDTypeBoolean, false);
MIB_CONSTANT_WEAK(kMIBTargetWithHwFlashNor, kOIDTypeBoolean, false);
MIB_CONSTANT_WEAK(kMIBTargetWithHwNvme, kOIDTypeBoolean, false);
MIB_CONSTANT_WEAK(kMIBTargetWithLegacyPanicLogs, kOIDTypeBoolean, false);
// Default MIB target paint constants
MIB_CONSTANT_WEAK(kMIBTargetDisplayGammaTableCount, kOIDTypeUInt32, 0);
MIB_CONSTANT_PTR_WEAK(kMIBTargetDisplayGammaTablePtr, kOIDTypeStruct, NULL);
MIB_CONSTANT_WEAK(kMIBTargetPanicOnUnknownDclrVersion, kOIDTypeBoolean, true);
MIB_CONSTANT_WEAK(kMIBTargetPictureScale, kOIDTypeUInt32, 1);
// Default MIB NOR configuration
MIB_CONSTANT_WEAK(kMIBTargetNvramNorBankCount, kOIDTypeUInt32, 2);
MIB_CONSTANT_WEAK(kMIBTargetNvramNorBankSize, kOIDTypeSize, 0x2000);
MIB_CONSTANT_WEAK(kMIBTargetNvramNorOffset, kOIDTypeInt32, -(2 * 0x2000));
// Default MIB Image3 constants
// Delete this and it's definition in mib.base when all Image3 targets are deprecated.
MIB_CONSTANT_WEAK(kMIBTargetAcceptGlobalTicket, kOIDTypeBoolean, false);
//Default Color Manager Data
MIB_CONSTANT_WEAK(kMIBTargetDisplayCMEngammaTablePtr, kOIDTypeStruct, NULL);
MIB_CONSTANT_WEAK(kMIBTargetDisplayCMEngammaTableCount, kOIDTypeUInt32, 0);
MIB_CONSTANT_WEAK(kMIBTargetDisplayCMDegammaTablePtr, kOIDTypeStruct, NULL);
MIB_CONSTANT_WEAK(kMIBTargetDisplayCMDegammaTableCount, kOIDTypeUInt32, 0);
MIB_CONSTANT_WEAK(kMIBTargetDisplayCMMatrixTablePtr, kOIDTypeStruct, NULL);
MIB_CONSTANT_WEAK(kMIBTargetDisplayCMMatrixTableCount, kOIDTypeUInt32, 0);
#endif // !APPLICATION_SECUREROM
+12
View File
@@ -0,0 +1,12 @@
/*
* Copyright (C) 2007-2008 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.
*/
/* XXX keep this here but blank for now */
+36
View File
@@ -0,0 +1,36 @@
# Copyright (C) 2007 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.
#
LIBPGINDEP_DIR := $(GET_LOCAL_DIR)
LIBPGINDEP_BUILD:= $(call TOLIBDIR,$(LIBPGINDEP_DIR)/LIBPGINDEP.a)
COMMONLIBS += LIBPGINDEP
# Force this library's symbols to be imported so that they can't be
# overridden. This library isn't designed with one function per object file
# to allow selective overriding
GLOBAL_LDFORCELIBS += $(LIBPGINDEP_BUILD)
# Only process the remainder of the makefile if we are building libraries
#
ifeq ($(MAKEPHASE),libraries)
LIBPGINDEP_OBJS := \
$(LIBPGINDEP_DIR)/platform_indep.o \
$(LIBPGINDEP_DIR)/target_indep.o \
$(LIBPGINDEP_DIR)/target_pass_boot_manifest.o \
$(LIBPGINDEP_DIR)/breadcrumbs.o
LIBPGINDEP_OBJS := $(call TOLIBOBJDIR,$(LIBPGINDEP_OBJS))
$(LIBPGINDEP_BUILD): $(LIBPGINDEP_OBJS)
ALL_DEPS += $(LIBPGINDEP_OBJS:%o=%d)
endif
+402
View File
@@ -0,0 +1,402 @@
/*
* 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);
}
+347
View File
@@ -0,0 +1,347 @@
/*
* Copyright (C) 2014-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/dram.h>
#include <lib/libc.h>
#include <platform.h>
#include <platform/tunables.h>
#include <stdint.h>
// platfom_indep holds generic functions that are just defined once for all
// platforms, and are not expected to be rebuilt for every target/product.
//
// These functions can vary per BUILD, and per architecture, but not per
// PLATFORM, TARGET, PRODUCT, or CONFIG
void platform_not_supported(void)
{
dprintf(DEBUG_CRITICAL, "\n");
dprintf(DEBUG_CRITICAL, "\n");
dprintf(DEBUG_CRITICAL, "\n");
dprintf(DEBUG_CRITICAL, "**************************************\n");
dprintf(DEBUG_CRITICAL, "* *\n");
dprintf(DEBUG_CRITICAL, "* This unit is not supported *\n");
dprintf(DEBUG_CRITICAL, "* *\n");
dprintf(DEBUG_CRITICAL, "**************************************\n");
while (1);
}
// Fuse Modes
// Bit 0 - Chip is Secure
// Bit 1 - Chip is Production
uint32_t platform_get_fuse_modes(void)
{
u_int32_t fuse_summary = 0;
if (platform_get_secure_mode()) fuse_summary |= (1 << 0);
if (platform_get_raw_production_mode()) fuse_summary |= (1 << 1);
return fuse_summary;
}
const char *platform_get_memory_manufacturer_string(void)
{
uint8_t index;
// This list is based of JEDEC Vendor list in dram.h
// index 0 and 15 are reserverd, we are using them to provide additional information related to the system.
static const char *memory_manufacturer_strings[JEDEC_NUM_MANUF_IDS] = {
"Unknown",
"Samsung",
"Qimonda",
"Elpida",
"Etron",
"Nanya",
"Hynix",
"Mosel",
"Winbond",
"ESMT",
"Reserved",
"Spansion",
"SST",
"ZMOS",
"Intel",
"Numonyx",
"Micron",
"FPGA",
};
index = platform_get_memory_manufacturer_id();
if(platform_is_pre_lpddr4()) {
if (index >= JEDEC_NUM_MANUF_IDS)
return NULL;
return memory_manufacturer_strings[index];
} else {
switch(index) {
case JEDEC_LPDDR4_MANUF_ID_SAMSUNG:
return "Samsung";
break;
case JEDEC_LPDDR4_MANUF_ID_HYNIX:
return "Hynix";
break;
case JEDEC_LPDDR4_MANUF_ID_MICRON:
return "Micron";
break;
default:
return NULL;
break;
}
}
}
uintptr_t platform_get_memory_region_base(memory_region_type_t region)
{
uintptr_t base = platform_get_memory_region_base_optional(region);
if (base == (uintptr_t)-1)
panic("unsupported region %d base requested\n", (int)region);
return base;
}
size_t platform_get_memory_region_size(memory_region_type_t region)
{
size_t size = platform_get_memory_region_size_optional(region);
if (size == (size_t)-1)
panic("unsupported region %d size requested\n", region);
return size;
}
void platform_apply_tunables(const struct tunable_chip_struct *tunable_chips, uint32_t num_tunable_chips, const char* type)
{
const struct tunable_struct *tunable;
uintptr_t base_address;
uint32_t chip_rev = platform_get_chip_revision();
uint32_t i;
uint32_t t;
bool match = false;
if (num_tunable_chips == 0)
return;
ASSERT(tunable_chips != NULL);
// For each bucket of tunable values...
for (i = 0; i < num_tunable_chips; i++) {
// Tunable for a newer chip revision?
if (tunable_chips[i].chip_rev > chip_rev) {
continue;
}
// Tunable for an older chip revision?
if (tunable_chips[i].chip_rev < chip_rev) {
if (match) {
// We've already found all the tunables matching
// this chip revision -- we're done.
break;
} else {
// We haven't found a match yet. Because the tunable
// chip table is supposed to be sorted from highest
// to lowest, finding an older chip revision means
// that there is no entry in the table for this
// chip revision and we'll use the first older one
// we find.
dprintf(DEBUG_SPEW, "%s tunables for chip rev %d not found -- using tunables for chip rev %d\n",
type, chip_rev, tunable_chips[i].chip_rev);
chip_rev = tunable_chips[i].chip_rev;
}
}
// We've found a matching tunable chip revision (either an exact
// match or the next older chip revision).
match = true;
// Get the base address and pointer to the tunables data.
tunable = tunable_chips[i].tunable;
ASSERT(tunable != NULL);
base_address = tunable_chips[i].base_address;
// For each tunable in registers at this base address...
for (t = 0; tunable[t].offset != -1; t++) {
// Elided tunables have a size of zero, just skip them.
if (tunable[t].size == 0) {
continue;
}
switch (tunable[t].size) {
case sizeof(uint32_t):
{
volatile uint32_t *addr;
uint32_t new_reg, old_reg, mask, value;
// Get the address of the register.
addr = (volatile uint32_t *)(base_address + tunable[t].offset);
// Get the current value of the register.
old_reg = *addr;
mask = (uint32_t)tunable[t].mask;
value = (uint32_t)tunable[t].value;
// If the tunable needs to be applied, do it.
if ((old_reg & mask) != (value & mask)) {
new_reg = old_reg;
new_reg &= ~mask;
new_reg |= value & mask;
*addr = new_reg;
dprintf(DEBUG_SPEW, "%s tunable addr/mask/value=%p/0x%08x/0x%08x: 0x%08x -> 0x%08x\n",
type, addr, mask, value, old_reg, new_reg);
} else {
dprintf(DEBUG_SPEW, "%s tunable addr/mask/value=%p/0x%08x/0x%08x: already correct 0x%08x\n",
type, addr, mask, value, old_reg);
}
break;
}
case sizeof(uint64_t):
{
volatile uint64_t *addr;
uint64_t new_reg, old_reg, mask, value;
// Get the address of the register.
addr = (volatile uint64_t *)(base_address + tunable[t].offset);
// Get the current value of the register.
old_reg = *addr;
mask = tunable[t].mask;
value = tunable[t].value;
// If the tunable needs to be applied, do it.
if ((old_reg & mask) != (value & mask)) {
new_reg = old_reg;
new_reg &= ~mask;
new_reg |= value & mask;
*addr = new_reg;
dprintf(DEBUG_SPEW, "%s tunable addr/mask/value=%p/0x%016llx/0x%016llx: 0x%016llx -> 0x%016llx\n",
type, addr, mask, value, old_reg, new_reg);
} else {
dprintf(DEBUG_SPEW, "%s tunable addr/mask/value=%p/0x%016llx/0x%016llx: already correct 0x%016llx\n",
type, addr, mask, value, old_reg);
}
break;
}
default:
panic("Unsupported tunable register size");
}
}
}
}
uint8_t *platform_apply_dt_tunables(const struct tunable_chip_struct *tunable_chips,
uint32_t num_tunable_chips, uint8_t *buffer,
uintptr_t dt_base, const char *type)
{
const struct tunable_struct *tunable;
struct tunable_struct_unpacked tunable_data;
uintptr_t addr;
uintptr_t base_address;
uint32_t chip_rev = platform_get_chip_revision();
uint32_t i;
uint32_t t;
bool match = false;
if (num_tunable_chips == 0)
return buffer;
ASSERT((tunable_chips != NULL) && (buffer != NULL));
// For each bucket of tunable values...
for (i = 0; i < num_tunable_chips; i++) {
// Tunable for a newer chip revision?
if (tunable_chips[i].chip_rev > chip_rev) {
continue;
}
// Tunable for an older chip revision?
if (tunable_chips[i].chip_rev < chip_rev) {
if (match) {
// We've already found all the tunables matching
// this chip revision -- we're done.
break;
} else {
// We haven't found a match yet. Because the tunable
// chip table is supposed to be sorted from highest
// to lowest, finding an older chip revision means
// that there is no entry in the table for this
// chip revision and we'll use the first older one
// we find.
dprintf(DEBUG_SPEW, "%s tunables for chip rev %d not found -- using tunables for chip rev %d\n",
type, chip_rev, tunable_chips[i].chip_rev);
chip_rev = tunable_chips[i].chip_rev;
}
}
// We've found a matching tunable chip revision (either an exact
// match or the next older chip revision).
match = true;
// Copy the tunable value and get the base address of the block it pertains to.
tunable = tunable_chips[i].tunable;
ASSERT(tunable != NULL);
base_address = tunable_chips[i].base_address;
// For each tunable register at this base address...
for (t = 0; tunable[t].offset != -1; t++) {
// Elided tunables have a size of zero, but pass them
// through in case the driver wants to un-elide them.
// Copy the tunable data so we can update it.
tunable_data.offset = tunable[t].offset;
tunable_data.size = tunable[t].size;
tunable_data.mask = tunable[t].mask;
tunable_data.value = tunable[t].value;
addr = base_address + tunable_data.offset;
// Get the address of the register.
if (dt_base != 0) {
// Adjust the offset to match the reg property in the
// device tree.
tunable_data.offset = (uint32_t)addr - dt_base;
ASSERT(tunable_data.offset != -1);
}
if (tunable_data.size == -1) {
dprintf(DEBUG_SPEW, "%s DT tunable @ 0x%lx: offset=0x%08x, size=%d, mask=0x%16llx, value=0x%16llx\n",
type, addr,
tunable_data.offset, tunable_data.size,
tunable_data.mask, tunable_data.value);
} else {
dprintf(DEBUG_SPEW, "%s DT tunable @ 0x%lx: offset=0x%08x, size=%d, mask=0x%08llx, value=0x%08llx\n",
type, addr,
tunable_data.offset, tunable_data.size,
tunable_data.mask, tunable_data.value);
}
memcpy(buffer, &tunable_data, sizeof(tunable_data));
buffer += sizeof(tunable_data);
}
}
return buffer;
}
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2011 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 <platform/memmap.h>
/*
* Utility file exporting symbols at absolute locations. These
* values are largely useful to the build system before the final
* object is linked, or for diagnosis purposes later.
*/
/*
* symbol <name> <value>
*/
.macro symbol
.global $0
.set $0 , $1
.endmacro
/* This is used at link time */
symbol _TEXT_BASE, TEXT_BASE
#if 0
/* debug/sanity checks */
symbol _INSECURE_MEMORY_BASE, INSECURE_MEMORY_BASE
symbol _INSECURE_MEMORY_SIZE, INSECURE_MEMORY_SIZE
symbol _DEFAULT_KERNEL_ADDRESS, DEFAULT_KERNEL_ADDRESS
symbol _DEFAULT_KERNEL_SIZE, DEFAULT_KERNEL_SIZE
symbol _DEFAULT_RAMDISK_ADDRESS, DEFAULT_RAMDISK_ADDRESS
symbol _DEFAULT_RAMDISK_SIZE, DEFAULT_RAMDISK_SIZE
symbol _DEFAULT_DEVICETREE_ADDRESS, DEFAULT_DEVICETREE_ADDRESS
symbol _DEFAULT_DEVICETREE_SIZE, DEFAULT_DEVICETREE_SIZE
symbol _IBOOT_SIZE, IBOOT_SIZE
symbol _MMU_TT_BASE, MMU_TT_BASE
symbol _MMU_TT_SIZE, MMU_TT_SIZE
symbol _STACK_BASE, STACK_BASE
symbol _STACK_SIZE, STACK_SIZE
#endif
+294
View File
@@ -0,0 +1,294 @@
/*
* Copyright (C) 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 <platform.h>
#include <platform/pmgr.h>
#include <debug.h>
static uint64_t pmgr_binning_read_register(uint64_t address, uint32_t low, uint32_t high, bool reg64)
{
uint64_t result = 0;
do {
uint64_t current_low;
uint64_t offset;
uint64_t register_value;
if (reg64) {
offset = high/64;
current_low = offset * 64;
register_value = ((uint64_t *)(address))[offset];
} else {
offset = high/32;
current_low = offset * 32;
register_value = ((uint32_t *)(address))[offset];
}
// Mask useful bit : [current_low:high]
register_value &= (1ULL << (high - current_low + 1)) - 1;
if (current_low <= low) {
result |= register_value >> (low - current_low);
break;
}
result |= register_value << (current_low - low);
high = current_low - 1;
} while (1);
return result;
}
static uint64_t pmgr_binning_read(const struct pmgr_binning_fuse_to_register *fuse_to_register, uint32_t binning_low, uint32_t binning_high)
{
uint32_t result = 0;
while (1) {
uint32_t i = 0;
while (fuse_to_register[i].register_address != 0) {
if ((fuse_to_register[i].binning_high >= binning_high) && (fuse_to_register[i].binning_low <= binning_high)) {
break;
}
i++;
}
if (fuse_to_register[i].register_address == 0) {
return PMGR_BINNING_NOTFOUND;
}
if ((fuse_to_register[i].binning_high >= binning_high) && (fuse_to_register[i].binning_low <= binning_low)) {
result |= pmgr_binning_read_register(fuse_to_register[i].register_address,
binning_low - fuse_to_register[i].binning_low + fuse_to_register[i].register_low,
binning_high - fuse_to_register[i].binning_low + fuse_to_register[i].register_low,
fuse_to_register[i].register_64bit);
break;
}
result |= pmgr_binning_read_register(fuse_to_register[i].register_address,
fuse_to_register[i].register_low,
binning_high - fuse_to_register[i].binning_low + fuse_to_register[i].register_low,
fuse_to_register[i].register_64bit) << (fuse_to_register[i].binning_low - binning_low);
binning_high = fuse_to_register[i].binning_low - 1;
}
return result;
}
static uint32_t pmgr_binning_from_const_data(enum pmgr_binning_type_t type, uint32_t mode, bool use_binning)
{
uint32_t i;
for (i = 0; i < pmgr_binning_mode_to_const_data_size; i++) {
if (pmgr_binning_mode_to_const_data[i].type != type) {
continue;
}
if (pmgr_binning_mode_to_const_data[i].mode != mode) {
continue;
}
if ((use_binning) && pmgr_binning_mode_to_const_data[i].bingroup != pmgr_binning_get_group() && pmgr_binning_mode_to_const_data[i].bingroup != PMGR_BINNING_GROUP_ALL) {
continue;
}
if ((use_binning) && (pmgr_binning_get_revision() < pmgr_binning_mode_to_const_data[i].fuse_revision_minimum)) {
continue;
}
if ((!use_binning) && (pmgr_binning_mode_to_const_data[i].fuse_revision_minimum != 0)) {
continue;
}
return pmgr_binning_mode_to_const_data[i].mv;
}
return PMGR_BINNING_NOTFOUND;
}
uint32_t pmgr_binning_from_config_data(uint32_t voltage_index, const struct pmgr_binning_voltage_index_to_config **config_data)
{
uint32_t i;
for (i = 0; i < pmgr_binning_voltage_index_to_config_data_size; i++) {
if (pmgr_binning_voltage_index_to_config_data[i].voltage_index != voltage_index) {
continue;
}
if (pmgr_binning_voltage_index_to_config_data[i].bingroup != pmgr_binning_get_group() && pmgr_binning_voltage_index_to_config_data[i].bingroup != PMGR_BINNING_GROUP_ALL) {
continue;
}
if (pmgr_binning_get_revision() < pmgr_binning_voltage_index_to_config_data[i].fuse_revision_minimum) {
continue;
}
*config_data = &pmgr_binning_voltage_index_to_config_data[i];
return pmgr_binning_voltage_index_to_config_data[i].safe_voltage;
}
return PMGR_BINNING_NOTFOUND;
}
int32_t pmgr_binning_get_voltage_offset(uint32_t voltage_index, enum pmgr_binning_type_t type)
{
uint32_t i;
uint32_t size = 0;
const struct pmgr_binning_voltage_index_to_offset *voltage_index_to_offset;
uint32_t board_id = platform_get_board_id();
for (i = 0; i < pmgr_binning_board_id_to_offsets_data_size; i++) {
if (pmgr_binning_board_id_to_offsets_data[i].board_id != board_id) {
continue;
}
if (pmgr_binning_board_id_to_offsets_data[i].type != type) {
continue;
}
if (platform_get_chip_revision() < pmgr_binning_board_id_to_offsets_data[i].chip_rev_min) {
continue;
}
if (pmgr_binning_board_id_to_offsets_data[i].bingroup != pmgr_binning_get_group() && pmgr_binning_board_id_to_offsets_data[i].bingroup != PMGR_BINNING_GROUP_ALL) {
continue;
}
voltage_index_to_offset = pmgr_binning_board_id_to_offsets_data[i].voltage_offsets;
size = pmgr_binning_board_id_to_offsets_data[i].size;
break;
}
for (i = 0; i < size; i++) {
if (voltage_index_to_offset[i].voltage_index != voltage_index) {
continue;
}
if (pmgr_binning_get_revision() < voltage_index_to_offset[i].fuse_revision_minimum) {
continue;
}
return voltage_index_to_offset[i].offset;
}
return 0;
}
uint32_t pmgr_binning_mode_get_value(enum pmgr_binning_type_t type, uint32_t mode)
{
uint32_t i = 0;
do {
if (pmgr_binning_mode_to_fuse_data[i].type == PMGR_BINNING_END_OF_LIST) {
return PMGR_BINNING_NOTFOUND;
}
if (pmgr_binning_mode_to_fuse_data[i].type != type) {
i++;
continue;
}
if (pmgr_binning_mode_to_fuse_data[i].mode != mode) {
i++;
continue;
}
if (type != PMGR_BINNING_GROUP && pmgr_binning_mode_to_fuse_data[i].bingroup != pmgr_binning_get_group() && pmgr_binning_mode_to_fuse_data[i].bingroup != PMGR_BINNING_GROUP_ALL) {
i++;
continue;
}
break;
} while (1);
if (pmgr_binning_mode_to_fuse_data[i].low > pmgr_binning_mode_to_fuse_data[i].high) {
panic("Invalid low (%u) and high (%u) mode_to_fuse_data for type %u mode %u\n", pmgr_binning_mode_to_fuse_data[i].low, pmgr_binning_mode_to_fuse_data[i].high, type, mode);
}
uint32_t result = pmgr_binning_read(pmgr_binning_mode_to_fuse_data[i].fuse_to_register, pmgr_binning_mode_to_fuse_data[i].low, pmgr_binning_mode_to_fuse_data[i].high);
return result;
}
uint32_t pmgr_binning_get_base(void)
{
static uint32_t base = 0;
if (base == 0) {
base = pmgr_binning_mode_get_value(PMGR_BINNING_BASE, 0);
}
return base;
}
uint32_t pmgr_binning_get_group(void)
{
static uint32_t group = 0;
if (group == 0) {
group =pmgr_binning_mode_get_value(PMGR_BINNING_GROUP, 0);
}
return group;
}
uint32_t pmgr_binning_get_revision(void)
{
static uint32_t revision = 0;
if (revision == 0) {
revision = pmgr_binning_mode_get_value(PMGR_BINNING_REV, 0);
}
return revision;
}
uint32_t pmgr_binning_mode_get_mv(enum pmgr_binning_type_t type, uint32_t mode)
{
uint32_t value = pmgr_binning_mode_get_value(type, mode);
if ((value == PMGR_BINNING_NOTFOUND) || (value == 0)) {
return PMGR_BINNING_NOTFOUND;
}
return 25 * (pmgr_binning_get_base() + 1) + value * 5;
}
uint32_t pmgr_binning_get_mv(uint32_t voltage_index, bool sram, bool use_binning)
{
uint32_t voltage;
int32_t voltage_offset;
uint32_t mode;
enum pmgr_binning_type_t type;
if (sram) {
if (voltage_index >= pmgr_binning_voltage_config_sram_data_size) {
return PMGR_BINNING_NOTFOUND;
}
const struct pmgr_binning_voltage_config *binning_voltage_config;
binning_voltage_config = &pmgr_binning_voltage_config_sram_data[voltage_index];
voltage = binning_voltage_config->safe_voltage;
type = binning_voltage_config->type;
mode = binning_voltage_config->mode;
if ((voltage == 0) && (type != PMGR_BINNING_NONE)){
return pmgr_binning_from_const_data(type, mode, use_binning);
}
} else {
const struct pmgr_binning_voltage_index_to_config *config_data;
if (pmgr_binning_from_config_data(voltage_index, &config_data) == PMGR_BINNING_NOTFOUND) {
return PMGR_BINNING_NOTFOUND;
}
voltage = config_data->safe_voltage;
type = config_data->type;
mode = config_data->mode;
if (use_binning) {
uint32_t voltage_binning = pmgr_binning_mode_get_mv(type, mode);
if (voltage_binning != PMGR_BINNING_NOTFOUND) {
voltage = voltage_binning;
}
}
}
voltage_offset = pmgr_binning_get_voltage_offset(voltage_index, type);
if ((int32_t)voltage + voltage_offset < 0) {
panic("Invalid voltage offset");
}
return voltage + voltage_offset;
}
const struct pmgr_binning_vol_adj *pmgr_binning_get_vol_adj(uint32_t chipdid, uint32_t chip_rev, uint32_t voltage_index)
{
uint32_t fuse_rev = pmgr_binning_get_revision();
for (size_t i = 0; i < pmgr_binning_voltadj_entry_data_size; i++) {
if (voltage_index != pmgr_binning_voltadj_entry_data[i].voltage_index) {
continue;
}
if ((chip_rev < pmgr_binning_voltadj_entry_data[i].chip_rev_min)) {
continue;
}
if ((fuse_rev < pmgr_binning_voltadj_entry_data[i].fuse_rev_min)) {
continue;
}
return &pmgr_binning_voltadj_entry_data[i].voltages;
}
return NULL;
}
+344
View File
@@ -0,0 +1,344 @@
/*
* Copyright (c) 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.
*/
#if !RELEASE_BUILD && WITH_MENU
#include <sys/menu.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <platform.h>
#include <stdio.h>
#include <sys.h>
#include <lib/env.h>
#include <platform/pmgr.h>
static bool pmgr_binning_menu_override_get_voltage_indexes(bool gpu, uint32_t *voltage_indexes, uint32_t voltage_index_size, uint32_t *voltage_index_found)
{
uint32_t freq = 0;
uint32_t i = 0;
const char *name = env_get(gpu?"pmgr_gpu_override":"pmgr_cpu_override");
const struct pmgr_binning_voltage_index_to_config *config_data;
*voltage_index_found = 0;
if (name == NULL) {
return false;
}
while (i < voltage_index_size) {
if (i > 0) {
name = strchr(name, ',');
if (name == NULL) {
break;
}
name++;
}
voltage_indexes[i] = atoi(name);
if (pmgr_binning_from_config_data(voltage_indexes[i], &config_data) == PMGR_BINNING_NOTFOUND) {
return false;
}
if ((gpu) && (config_data->type != PMGR_BINNING_GPU)) {
return false;
}
if ((!gpu) && (config_data->type != PMGR_BINNING_CPU)) {
return false;
}
freq = pmgr_platform_get_freq(gpu, voltage_indexes[i]);
if (freq == 0) {
return false;
}
i++;
}
*voltage_index_found = i;
return true;
}
static bool pmgr_binning_menu_find_safe_voltage(enum pmgr_binning_type_t type, uint32_t mode,
uint32_t *safe_voltage, uint32_t *freq)
{
uint32_t i;
*freq = 0;
for (i = 0; i < pmgr_binning_voltage_config_sram_data_size; i++) {
if (pmgr_binning_voltage_config_sram_data[i].mode != mode) {
continue;
}
if (pmgr_binning_voltage_config_sram_data[i].type != type) {
continue;
}
*safe_voltage = pmgr_binning_voltage_config_sram_data[i].safe_voltage;
return true;
}
for (i = 0; i < pmgr_binning_voltage_index_to_config_data_size; i++) {
if (pmgr_binning_voltage_index_to_config_data[i].mode != mode) {
continue;
}
if (pmgr_binning_voltage_index_to_config_data[i].type != type) {
continue;
}
if (type == PMGR_BINNING_CPU) {
*freq = pmgr_platform_get_freq(false, pmgr_binning_voltage_index_to_config_data[i].voltage_index);
} else if (type == PMGR_BINNING_GPU) {
*freq = pmgr_platform_get_freq(true, pmgr_binning_voltage_index_to_config_data[i].voltage_index);
}
*safe_voltage = pmgr_binning_voltage_index_to_config_data[i].safe_voltage;
return true;
}
return false;
}
static void pmgr_binning_menu_print_type(enum pmgr_binning_type_t type)
{
uint32_t mode;
for (mode = 1; mode < 63; mode++) {
uint32_t result = pmgr_binning_mode_get_value(type, mode);
uint32_t safe_voltage;
uint32_t freq;
if ((result == PMGR_BINNING_NOTFOUND) || (result == 0)) {
continue;
}
printf(" mode %u %u mV (0x%x)", mode, pmgr_binning_mode_get_mv(type, mode), pmgr_binning_mode_get_value(type, mode));
if (!pmgr_binning_menu_find_safe_voltage(type, mode, &safe_voltage, &freq)) {
printf(" no safe voltage");
} else {
printf(" safe voltage %u mV", safe_voltage);
}
if (freq > 0) {
printf(" %u MHz", freq);
}
printf("\n");
}
}
static void pmgr_binning_menu_voltage_config_print(const struct pmgr_binning_voltage_config *voltage_config, uint32_t voltage_index)
{
const char *name = "";
uint32_t freq = 0, safe_voltage = 0, mode = 0, type = 0;
bool sram = false;
if (voltage_config != NULL) {
safe_voltage = voltage_config->safe_voltage;
mode = voltage_config->mode;
type = voltage_config->type;
}
else {
const struct pmgr_binning_voltage_index_to_config *config_data;
if (pmgr_binning_from_config_data(voltage_index, &config_data) == PMGR_BINNING_NOTFOUND) {
return;
}
safe_voltage = config_data->safe_voltage;
mode = config_data->mode;
type = config_data->type;
}
if (type == PMGR_BINNING_NONE) {
return;
}
switch (type) {
case PMGR_BINNING_CPU:
name = "CPU";
freq = pmgr_platform_get_freq(false, voltage_index);
break;
case PMGR_BINNING_GPU:
name = "GPU";
freq = pmgr_platform_get_freq(true, voltage_index);
break;
case PMGR_BINNING_SOC:
name = "SOC";
break;
case PMGR_BINNING_CPU_SRAM:
name = "CPU SRAM";
sram = true;
break;
case PMGR_BINNING_GPU_SRAM:
name = "GPU SRAM";
sram = true;
break;
case PMGR_BINNING_SRAM:
name = "SRAM";
sram = true;
break;
default:
name = "Unknown";
break;
}
printf(" %s index %u safe voltage %u mV",
name,
voltage_index,
pmgr_binning_get_mv(voltage_index, sram, false));
if (pmgr_binning_mode_get_mv(type, mode) != PMGR_BINNING_NOTFOUND) {
printf(" binning %u mV", pmgr_binning_get_mv(voltage_index, sram, true));
} else {
printf(" no binning %u mV", pmgr_binning_get_mv(voltage_index, sram, true));
}
printf(" offset %d mV", pmgr_binning_get_voltage_offset(voltage_index, type));
if (mode != PMGR_BINNING_MODE_NONE && mode > 0) {
printf(" mode %u", mode);
}
if (freq > 0) {
printf(" %u MHz", freq);
}
if (sram && safe_voltage == 0) {
uint32_t i;
for (i = 0; i < pmgr_binning_mode_to_const_data_size; i++) {
if (pmgr_binning_mode_to_const_data[i].type != type) {
continue;
}
if (pmgr_binning_mode_to_const_data[i].mode != mode) {
continue;
}
if (pmgr_binning_mode_to_const_data[i].bingroup != pmgr_binning_get_group() && pmgr_binning_mode_to_const_data[i].bingroup != PMGR_BINNING_GROUP_ALL) {
continue;
}
printf(" fuse >= %d %d mV", pmgr_binning_mode_to_const_data[i].fuse_revision_minimum, pmgr_binning_mode_to_const_data[i].mv + pmgr_binning_get_voltage_offset(voltage_index, type));
}
}
else if (!sram && mode != PMGR_BINNING_MODE_NONE) {
uint32_t i;
for (i = 0; i < pmgr_binning_voltage_index_to_config_data_size; i++) {
if (pmgr_binning_voltage_index_to_config_data[i].voltage_index != voltage_index) {
continue;
}
if (pmgr_binning_voltage_index_to_config_data[i].type != type) {
continue;
}
if (pmgr_binning_voltage_index_to_config_data[i].bingroup != pmgr_binning_get_group() && pmgr_binning_voltage_index_to_config_data[i].bingroup != PMGR_BINNING_GROUP_ALL) {
continue;
}
printf(" fuse >= %d %d mV", pmgr_binning_voltage_index_to_config_data[i].fuse_revision_minimum, pmgr_binning_voltage_index_to_config_data[i].safe_voltage + pmgr_binning_get_voltage_offset(voltage_index, type));
}
}
printf("\n");
}
static void pmgr_binning_menu_current_values_type(enum pmgr_binning_type_t type)
{
uint32_t i = 0;
uint32_t freq;
uint32_t voltage;
while (pmgr_platform_get_perf_state(type, i, &voltage, &freq)) {
if (freq == 0) {
printf(" state %u: %u mV", i, voltage);
} else {
printf(" state %u: %u Mhz %u mV", i, freq / 1000000, voltage);
}
if ((type == PMGR_BINNING_CPU) && (pmgr_platform_get_perf_state(PMGR_BINNING_CPU_SRAM, i, &voltage, &freq))) {
printf(" SRAM %u mV", voltage);
}
if ((type == PMGR_BINNING_GPU) && (pmgr_platform_get_perf_state(PMGR_BINNING_GPU_SRAM, i, &voltage, &freq))) {
printf(" SRAM %u mV", voltage);
}
printf("\n");
i++;
}
}
static int do_pmgr(int argc, struct cmd_arg *args)
{
uint32_t voltage_indexes[32];
uint32_t max_voltage_index = 0;
uint32_t voltage_index_found;
if ((argc < 2) || ((strcmp(args[1].str, "binning") != 0) && (strcmp(args[1].str, "values") != 0))) {
printf("Usage\n");
printf(" pmgr [values | [binning [internal|values]]]\n");
printf(" pmgr binning: fused value\n");
printf(" pmgr binning internal: fused value and all known operating points\n");
printf(" pmgr values: values currently set in PMGR/ACC registers\n");
return 0;
}
if ((argc > 1) && (strcmp(args[1].str, "values") == 0)) {
printf("CPU:\n");
pmgr_binning_menu_current_values_type(PMGR_BINNING_CPU);
printf("GPU:\n");
pmgr_binning_menu_current_values_type(PMGR_BINNING_GPU);
printf("SOC:\n");
pmgr_binning_menu_current_values_type(PMGR_BINNING_SOC);
return 0;
}
printf("Fuse revision %u base %u bin group %u\n", pmgr_binning_get_revision(), pmgr_binning_get_base(), pmgr_binning_get_group());
printf(" CPU\n");
pmgr_binning_menu_print_type(PMGR_BINNING_CPU);
printf(" CPU SRAM\n");
pmgr_binning_menu_print_type(PMGR_BINNING_CPU_SRAM);
printf(" GPU\n");
pmgr_binning_menu_print_type(PMGR_BINNING_GPU);
printf(" GPU SRAM\n");
pmgr_binning_menu_print_type(PMGR_BINNING_GPU_SRAM);
printf(" SRAM\n");
pmgr_binning_menu_print_type(PMGR_BINNING_SRAM);
printf(" SOC\n");
pmgr_binning_menu_print_type(PMGR_BINNING_SOC);
if ((argc > 2) && (strcmp(args[2].str, "internal") == 0)) {
uint32_t i;
printf("\n");
for (i = 0; i < pmgr_binning_voltage_index_to_config_data_size; i++) {
if (pmgr_binning_voltage_index_to_config_data[i].voltage_index > max_voltage_index) {
max_voltage_index = pmgr_binning_voltage_index_to_config_data[i].voltage_index;
}
}
for (i = 0; i <= max_voltage_index; i++) {
pmgr_binning_menu_voltage_config_print(NULL, i);
}
for (i = 0; i < pmgr_binning_voltage_config_sram_data_size; i++) {
pmgr_binning_menu_voltage_config_print(&pmgr_binning_voltage_config_sram_data[i], i);
}
}
if (pmgr_binning_menu_override_get_voltage_indexes(false, voltage_indexes, sizeof(voltage_indexes)/sizeof(voltage_indexes[0]), &voltage_index_found)) {
uint32_t i;
for (i = 0; i < voltage_index_found; i++) {
if (i == 0) {
printf("\n\nOverridden CPU states:\n");
}
printf(" state %u ", i + 3); // state 0 (bypass), 1 (securerom) and 2 (current state) are not overridden
pmgr_binning_menu_voltage_config_print(NULL, voltage_indexes[i]);
}
}
if (pmgr_binning_menu_override_get_voltage_indexes(true, voltage_indexes, sizeof(voltage_indexes)/sizeof(voltage_indexes[0]), &voltage_index_found)) {
uint32_t i;
for (i = 0; i < voltage_index_found; i++) {
if (i == 0) {
printf("\n\nOverridden GPU states:\n");
}
printf(" state %u ", i + 1); // state 0 (off) are not overridden
pmgr_binning_menu_voltage_config_print(NULL, voltage_indexes[i]);
}
}
return 0;
}
void pmgr_binning_menu_update_states(void)
{
uint32_t voltage_indexes[32];
uint32_t voltage_index_found;
if (pmgr_binning_menu_override_get_voltage_indexes(false, voltage_indexes, sizeof(voltage_indexes)/sizeof(voltage_indexes[0]), &voltage_index_found)) {
pmgr_platform_set_perf_state(false, 3, voltage_indexes, voltage_index_found);
}
if (pmgr_binning_menu_override_get_voltage_indexes(true, voltage_indexes, sizeof(voltage_indexes)/sizeof(voltage_indexes[0]), &voltage_index_found)) {
pmgr_platform_set_perf_state(true, 1, voltage_indexes, voltage_index_found);
}
}
// _command, _function, _help, _meta
MENU_COMMAND_DEVELOPMENT(pmgr, do_pmgr, "Print pmgr data", NULL);
#endif // !RELEASE_BUILD && WITH_MENU
+42
View File
@@ -0,0 +1,42 @@
# Copyright (C) 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
# All H8+ chip must use pmgr_binning
PMGR_BINNING=0
ifeq ($(SUB_PLATFORM),s8000)
PMGR_BINNING=1
endif
ifeq ($(SUB_PLATFORM),s8001)
PMGR_BINNING=1
endif
ifeq ($(SUB_PLATFORM),s8003)
PMGR_BINNING=1
endif
ifeq ($(PMGR_BINNING),1)
ALL_OBJS += \
$(LOCAL_DIR)/pmgr_binning.o
ifneq ($(BUILD),RELEASE)
ifeq ($(PRODUCT),iBoot)
ALL_OBJS += \
$(LOCAL_DIR)/pmgr_binning_menu.o
endif
ifeq ($(PRODUCT),iBEC)
ALL_OBJS += \
$(LOCAL_DIR)/pmgr_binning_menu.o
endif
endif
endif
+48
View File
@@ -0,0 +1,48 @@
# Copyright (C) 2007-2013 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.
#
LOCAL_DIR := $(GET_LOCAL_DIR)
#
# Objects that must be built for every target.
#
# Adding files here is very expensive, as each file
# gets compiled for every target/product/build permutation.
#
#
ifneq ($(APPLICATION),SecureROM)
MODULES += \
$(LOCAL_DIR)/pmgr
endif
ALL_OBJS += \
$(LOCAL_DIR)/default_mib.o \
$(LOCAL_DIR)/platform_info.o \
$(LOCAL_DIR)/platform_dep.o \
$(LOCAL_DIR)/target_dep.o
# Include library with platform/target/product-independent functions
LIBRARY_MODULES += $(LOCAL_DIR)
#
# The platform_info file contains symbols with useful information
#
INFO_SYMBOL_FILE := $(call TOBUILDDIR,$(LOCAL_DIR)/platform_info.o)
# for platform_get_security_epoch()
ifeq ($(DEVMAP_EPOCH),)
OPTIONS += PLATFORM_SECURITY_EPOCH=00
else
OPTIONS += PLATFORM_SECURITY_EPOCH=$(DEVMAP_EPOCH)
endif
ifneq ($(DEVMAP_PRODUCT_ID),)
OPTIONS += PLATFORM_PRODUCT_ID=`echo $(DEVMAP_PRODUCT_ID) | sed 's/../0x&,/g' | sed 's/.*/{&}/g'`
endif
+29
View File
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2014 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 <lib/syscfg.h>
#include <lib/env.h>
#include <stdint.h>
// Target/product dependent functions that aren't expected to be overridden by targets
bool target_is_tethered(void)
{
#if WITH_SYSCFG
uint8_t tethcfg[16];
if ((syscfgCopyDataForTag('Teth', tethcfg, 16) != -1) && (tethcfg[0] != 0x0)) {
return true;
}
#endif
return 0 != env_get_uint("is-tethered", 0);
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2012-2014 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 <platform.h>
#include <stdbool.h>
#include <target.h>
bool target_config_ap(void)
{
static bool valid = false;
static bool result;
if (!valid) {
result = (platform_get_board_id() & 1) == 0;
valid = true;
}
return result;
}
bool target_config_dev(void)
{
static bool valid = false;
static bool result;
if (!valid) {
result = (platform_get_board_id() & 1) != 0;
valid = true;
}
return result;
}
@@ -0,0 +1,247 @@
/*
* Copyright (C) 2014 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 <target.h>
#include <stdlib.h>
#include <lib/devicetree.h>
#include <lib/image4_spi.h>
#include <debug.h>
/**
* Stash away properties in a simple data structure while the image is being validated.
*
* The image4 wrapper extracts out properties before declaring an overall image valid/invalid,
* and we also can load the kernelcache before the device tree.
*/
#define N_BOOL_PROPS 20
#define N_INT_PROPS 20
#define N_STRING_PROPS 10
#define MAX_IMG4_STRING_LEN 64
typedef struct {
uint32_t tag;
bool val;
} bool_prop_t;
typedef struct {
uint32_t tag;
uint64_t val;
} int_prop_t;
typedef struct {
uint32_t tag;
size_t length;
uint8_t data[MAX_IMG4_STRING_LEN];
} string_prop_t;
typedef struct {
bool_prop_t bool_props[N_BOOL_PROPS];
int_prop_t int_props[N_INT_PROPS];
string_prop_t string_props[N_STRING_PROPS];
} image4_property_collection_t;
struct {
bool is_valid;
bool cb_encountered_error;
image4_property_collection_t manifest_properties;
image4_property_collection_t manifest_object_properties;
} image4_properties;
static bool image4_start_cb(uint32_t type)
{
return (type == IMAGE_TYPE_KERNELCACHE || type == IMAGE_TYPE_KERNELCACHE_RESTORE);
}
static void image4_update_validity(bool is_valid)
{
if (!is_valid) {
bzero(&image4_properties, sizeof(image4_properties));
}
image4_properties.is_valid = is_valid;
}
static void image4_bool_cb(uint32_t tag, bool is_object_property, bool val)
{
bool_prop_t* properties = NULL;
if (is_object_property) {
properties = image4_properties.manifest_object_properties.bool_props;
} else {
properties = image4_properties.manifest_properties.bool_props;
}
for(int i = 0; i < N_BOOL_PROPS; i++)
{
if(properties[i].tag == 0)
{
properties[i].tag = tag;
properties[i].val = val;
return;
}
}
dprintf(DEBUG_CRITICAL, "Ran out of space storing boolean properties -- please tune N_BOOL_PROPS");
image4_properties.cb_encountered_error = true;
}
static void image4_int_cb(uint32_t tag, bool is_object_property, uint64_t val)
{
int_prop_t* properties = NULL;
if (is_object_property) {
properties = image4_properties.manifest_object_properties.int_props;
} else {
properties = image4_properties.manifest_properties.int_props;
}
for(int i = 0; i < N_INT_PROPS; i++)
{
if(properties[i].tag == 0)
{
properties[i].tag = tag;
properties[i].val = val;
return;
}
}
dprintf(DEBUG_CRITICAL, "Ran out of space storing integer properties -- please tune N_INT_PROPS");
image4_properties.cb_encountered_error = true;
}
static void image4_string_cb(uint32_t tag, bool is_object_property, uint8_t* data, size_t length)
{
string_prop_t* properties = NULL;
if (is_object_property) {
properties = image4_properties.manifest_object_properties.string_props;
} else {
properties = image4_properties.manifest_properties.string_props;
}
for(int i = 0; i < N_STRING_PROPS; i++)
{
if(properties[i].tag == 0)
{
if (length > MAX_IMG4_STRING_LEN) {
dprintf(DEBUG_CRITICAL, "image4_string_cb: Property length %lu exceeds max supported length, %u", length, MAX_IMG4_STRING_LEN);
image4_properties.cb_encountered_error = true;
return;
}
properties[i].tag = tag;
memcpy(properties[i].data, data, length);
properties[i].length = length;
return;
}
}
dprintf(DEBUG_CRITICAL, "Ran out of space storing string properties -- please tune N_STRING_PROPS");
image4_properties.cb_encountered_error = true;
}
#define IMG4UNTAG(x) (((x) >> 24) & 0xff),(((x) >> 16) & 0xff),(((x) >> 8) & 0xff),((x) & 0xff)
static int image4_copy_boolean_properties(DTNode* node, bool_prop_t* props)
{
char entryName[50];
char* propName;
void* propData;
uint32_t propSize;
for(int i = 0; (i < N_BOOL_PROPS) && (props[i].tag != 0); i++) {
snprintf(entryName, sizeof(entryName), "UnusedBooleanProperty%d", i);
propName = entryName;
if (!FindProperty(node, &propName, &propData, &propSize)) {
dprintf(DEBUG_CRITICAL, "Ran out of boolean entries %s", propName);
return -1;
}
snprintf(entryName, sizeof(entryName), "%c%c%c%c", IMG4UNTAG(props[i].tag));
strlcpy(propName, entryName, kPropNameLength);
memcpy(propData, &props[i].val, sizeof(bool));
}
return 0;
}
static int image4_copy_integer_properties(DTNode* node, int_prop_t* props)
{
char entryName[50];
char* propName;
void* propData;
uint32_t propSize;
for(int i = 0; (i < N_INT_PROPS) && (props[i].tag != 0); i++) {
snprintf(entryName, sizeof(entryName), "UnusedIntegerProperty%d", i);
propName = entryName;
if (!FindProperty(node, &propName, &propData, &propSize)) {
dprintf(DEBUG_CRITICAL, "Ran out of integer entries %s", propName);
return -1;
}
snprintf(entryName, sizeof(entryName), "%c%c%c%c", IMG4UNTAG(props[i].tag));
strlcpy(propName, entryName, kPropNameLength);
memcpy(propData, &props[i].val, sizeof(uint64_t));
}
return 0;
}
static int image4_copy_string_properties(DTNode* node, string_prop_t* props)
{
char entryName[50];
char* propName;
void* propData;
uint32_t propSize;
for(int i = 0; (i < N_STRING_PROPS) && (props[i].tag != 0); i++) {
snprintf(entryName, sizeof(entryName), "UnusedStringProperty%d", i);
propName = entryName;
if (!FindProperty(node, &propName, &propData, &propSize)) {
dprintf(DEBUG_CRITICAL, "Ran out of string entries %s", propName);
return -1;
}
if (propSize < props[i].length) {
dprintf(DEBUG_CRITICAL, "DT property size too small to fit string property");
return -2;
}
snprintf(entryName, sizeof(entryName), "%c%c%c%c", IMG4UNTAG(props[i].tag));
strlcpy(propName, entryName, kPropNameLength);
memcpy(propData, &props[i].data, props[i].length);
}
return 0;
}
static bool initialized;
int target_init_boot_manifest(void)
{
image4_register_property_capture_callbacks(image4_start_cb,
image4_bool_cb, image4_int_cb, image4_string_cb, image4_update_validity);
initialized=true;
return 0;
}
int target_pass_boot_manifest(void)
{
// You must call init before loading the image4 of interest.
if (!initialized)
panic("target_pass_boot_manifest() used without target_init_boot_manifest()");
if (!image4_properties.is_valid || image4_properties.cb_encountered_error) {
// Don't touch the DT unless the image is validated.
return -1;
}
const char* ManifestPropertiesPath = "chosen/manifest-properties";
const char* ManifestObjectPropertiesPath = "chosen/manifest-object-properties";
DTNode* dtnode;
if (FindNode(0, ManifestPropertiesPath, &dtnode)) {
if (image4_copy_boolean_properties(dtnode, image4_properties.manifest_properties.bool_props))
return -2;
if (image4_copy_integer_properties(dtnode, image4_properties.manifest_properties.int_props))
return -3;
if (image4_copy_string_properties(dtnode, image4_properties.manifest_properties.string_props))
return -4;
} else {
dprintf(DEBUG_CRITICAL, "Can't find manifest properties path %s -- Skipping DT patching\n", ManifestPropertiesPath);
return -5;
}
if (FindNode(0, ManifestObjectPropertiesPath, &dtnode)) {
if (image4_copy_boolean_properties(dtnode, image4_properties.manifest_object_properties.bool_props))
return -6;
if (image4_copy_integer_properties(dtnode, image4_properties.manifest_object_properties.int_props))
return -7;
if (image4_copy_string_properties(dtnode, image4_properties.manifest_object_properties.string_props))
return -8;
} else {
dprintf(DEBUG_CRITICAL, "Can't find manifest object properties path %s -- Skipping DT patching\n", ManifestObjectPropertiesPath);
return -9;
}
return 0;
}