first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2012 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 WITH_BLOCKDEV
|
||||
|
||||
#include <debug.h>
|
||||
#include <sys/types.h>
|
||||
#include <lib/blockdev.h>
|
||||
|
||||
#include "nand_part.h"
|
||||
#include "nand_part_interface.h"
|
||||
#include "nand_export.h"
|
||||
#include "nand_firmware.h"
|
||||
|
||||
//#undef DEBUG_LEVEL
|
||||
//#define DEBUG_LEVEL DEBUG_INFO
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#define kNandFirmwareBDevName "nand_firmware"
|
||||
#define kNandLLBBDevName "nand_llb"
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static NandPartInterface * _npi;
|
||||
static uint32_t _llb_index;
|
||||
static uint32_t _firmware_index;
|
||||
static bool _have_cache;
|
||||
static uint32_t _cached_part;
|
||||
static uint32_t _cached_block;
|
||||
static uint32_t _cached_page;
|
||||
static uint8_t * _page_cache;
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static bool nand_firmware_cache_page(uint32_t part, uint32_t block, uint32_t page);
|
||||
static int nand_firmware_read_block_handler(struct blockdev *bdev, void *ptr, block_addr block, uint32_t count);
|
||||
#if ALLOW_NAND_FIRMWARE_ERASE
|
||||
static int nand_firmware_erase_block_handler(struct blockdev *bdev, off_t offset, uint64_t len);
|
||||
#endif
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
bool
|
||||
nand_firmware_init(NandPartInterface *npi, uint32_t partIndex)
|
||||
{
|
||||
const uint32_t page_size = npi_get_bytes_per_page(npi, partIndex);
|
||||
struct blockdev * _bdev;
|
||||
bool ok = false;
|
||||
|
||||
_npi = npi;
|
||||
_have_cache = false;
|
||||
_cached_part = 0;
|
||||
_cached_block = 0;
|
||||
_cached_page = 0;
|
||||
_page_cache = NULL;
|
||||
_bdev = NULL;
|
||||
|
||||
_bdev = malloc(sizeof(struct blockdev));
|
||||
_page_cache = (uint8_t*)memalign(page_size, CPU_CACHELINE_SIZE);
|
||||
const uint32_t blockCount = npi_get_block_depth(_npi, partIndex);
|
||||
const uint32_t pagesPerBlock = npi_get_pages_per_block(_npi, partIndex);
|
||||
const off_t len = (blockCount * pagesPerBlock * page_size);
|
||||
const NandPartEntry * entry = npi_get_entry(_npi, partIndex);
|
||||
|
||||
switch (entry->content) {
|
||||
case kNandPartContentFirmware:
|
||||
_firmware_index = partIndex;
|
||||
construct_blockdev(_bdev, kNandFirmwareBDevName, len, kNandPartSectorSize);
|
||||
break;
|
||||
case kNandPartContentBootBlock:
|
||||
_llb_index = partIndex;
|
||||
construct_blockdev(_bdev, kNandLLBBDevName, len, kNandPartSectorSize);
|
||||
break;
|
||||
default:
|
||||
panic("Should never have been here\n");
|
||||
}
|
||||
|
||||
_bdev->read_block_hook = &nand_firmware_read_block_handler;
|
||||
#if ALLOW_NAND_FIRMWARE_ERASE
|
||||
_bdev->erase_hook = &nand_firmware_erase_block_handler;
|
||||
#endif
|
||||
register_blockdev(_bdev);
|
||||
|
||||
ok = true;
|
||||
return(ok);
|
||||
}
|
||||
|
||||
static bool
|
||||
nand_firmware_cache_page(uint32_t part, uint32_t block, uint32_t page)
|
||||
{
|
||||
bool is_clean;
|
||||
uint32_t bank;
|
||||
|
||||
if (!_have_cache || (_cached_part != part) || (_cached_block != block) || (_cached_page != page)) {
|
||||
_have_cache = false;
|
||||
for (bank = 0; bank < npi_get_bank_width(_npi, part); bank++) {
|
||||
if (npi_is_block_bad(_npi, part, bank, block)) {
|
||||
dprintf(DEBUG_SPEW,
|
||||
"WARNING: bad block (%d:%d:%d)\n",
|
||||
part, bank, block);
|
||||
continue;
|
||||
}
|
||||
if (npi_read_page(_npi, part, bank, block, page, _page_cache, &is_clean)) {
|
||||
_have_cache = true;
|
||||
_cached_part = part;
|
||||
_cached_block = block;
|
||||
_cached_page = page;
|
||||
break;
|
||||
} else {
|
||||
dprintf(DEBUG_SPEW,
|
||||
"WARNING: page read (%d:%d:%d:%d) failed\n",
|
||||
part, bank, block, page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(_have_cache);
|
||||
}
|
||||
|
||||
static int
|
||||
nand_firmware_read_block_handler(struct blockdev *bdev, void *ptr, block_addr sector_addr, uint32_t sector_count)
|
||||
{
|
||||
// this is a bit confusing, since a bdev "block" is not the same as a nand "block";
|
||||
// instead, the bdev "block" concept is mapped to a 512-byte virtual "sector"
|
||||
|
||||
const uint32_t sector_base = 0;
|
||||
uint32_t sector_limit = 0;
|
||||
|
||||
uint32_t block_count;
|
||||
uint32_t bytes_per_page;
|
||||
uint32_t pages_per_block;
|
||||
uint32_t bytes_per_block;
|
||||
uint32_t sectors_per_block;
|
||||
uint32_t sectors_per_page;
|
||||
|
||||
uint32_t first_sector = 0;
|
||||
uint32_t last_sector = 0;
|
||||
|
||||
uint32_t sector_idx;
|
||||
uint8_t * cursor = (uint8_t *)ptr;
|
||||
uint32_t sectors_read = 0;
|
||||
|
||||
uint32_t part;
|
||||
|
||||
if (strcmp(bdev->name, kNandFirmwareBDevName) == 0) {
|
||||
part = _firmware_index;
|
||||
} else if (strcmp(bdev->name, kNandLLBBDevName) == 0) {
|
||||
part = _llb_index;
|
||||
} else {
|
||||
/* Something wrong */
|
||||
dprintf(DEBUG_CRITICAL,
|
||||
"ERROR: bad bdev: %s\n",
|
||||
bdev->name);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
block_count = npi_get_block_depth(_npi, part);
|
||||
bytes_per_page = npi_get_bytes_per_page(_npi, part);
|
||||
pages_per_block = npi_get_pages_per_block(_npi, part);
|
||||
bytes_per_block = (bytes_per_page * pages_per_block);
|
||||
sectors_per_block = (bytes_per_block / kNandPartSectorSize);
|
||||
sectors_per_page = (bytes_per_page / kNandPartSectorSize);
|
||||
|
||||
sector_limit = (block_count * sectors_per_block);
|
||||
|
||||
first_sector = (sector_base + sector_addr);
|
||||
last_sector = (first_sector + sector_count - 1);
|
||||
|
||||
if (last_sector > sector_limit) {
|
||||
dprintf(DEBUG_CRITICAL,
|
||||
"ERROR: 0x%08X-0x%08X not within 0x%08X-0x%08X\n",
|
||||
first_sector, last_sector, sector_base, sector_limit);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
for (sector_idx = first_sector; sector_idx <= last_sector; sector_idx++) {
|
||||
const uint32_t block = sector_idx / sectors_per_block;
|
||||
const uint32_t sector_in_block = sector_idx % sectors_per_block;
|
||||
const uint32_t page = sector_in_block / sectors_per_page;
|
||||
const uint32_t offset = sector_in_block % sectors_per_page;
|
||||
if (!nand_firmware_cache_page(part, block, page)) {
|
||||
dprintf(DEBUG_SPEW,
|
||||
"WARNING: unable to read firmware page 0x%X\n",
|
||||
page);
|
||||
break;;
|
||||
}
|
||||
memcpy(cursor, &_page_cache[offset * kNandPartSectorSize], kNandPartSectorSize);
|
||||
sectors_read++;
|
||||
cursor += kNandPartSectorSize;
|
||||
}
|
||||
|
||||
return(sectors_read);
|
||||
}
|
||||
|
||||
#if ALLOW_NAND_FIRMWARE_ERASE
|
||||
static int
|
||||
nand_firmware_erase_block_handler(struct blockdev *bdev, off_t offset, uint64_t len)
|
||||
{
|
||||
uint32_t block_base = 0;
|
||||
uint32_t block_num = 0;
|
||||
bool llb_nuke = false;
|
||||
uint32_t pages_per_block;
|
||||
uint32_t bytes_per_page;
|
||||
uint32_t bytes_per_block;
|
||||
uint32_t part;
|
||||
|
||||
if (strcmp(bdev->name, kNandFirmwareBDevName) == 0) {
|
||||
part = _firmware_index;
|
||||
} else if (strcmp(bdev->name, kNandLLBBDevName) == 0) {
|
||||
part = _llb_index;
|
||||
llb_nuke = true;
|
||||
} else {
|
||||
/* Something wrong */
|
||||
dprintf(DEBUG_CRITICAL,
|
||||
"ERROR: bad bdev: %s\n",
|
||||
bdev->name);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
pages_per_block = npi_get_pages_per_block(_npi, part);
|
||||
bytes_per_page = npi_get_bytes_per_page(_npi, part);
|
||||
bytes_per_block = (pages_per_block * bytes_per_page);
|
||||
|
||||
/* Sanity check offset and len before erase, need to be page-size aligned */
|
||||
ASSERT(offset >= 0);
|
||||
if ((uint64_t)offset >= bdev->total_len)
|
||||
return 0;
|
||||
if ((offset + len) > bdev->total_len)
|
||||
len = bdev->total_len - offset;
|
||||
if ((offset % bytes_per_block) || (len % bytes_per_block))
|
||||
return 0;
|
||||
|
||||
block_num = (len / bytes_per_block);
|
||||
block_base = (offset / bytes_per_block);
|
||||
|
||||
for (UInt16 bank = 0; bank < npi_get_bank_width(_npi, part); bank++) {
|
||||
/* Read the partition table in the case if LLB erase */
|
||||
if (llb_nuke) {
|
||||
npi_erase_boot_partition(_npi);
|
||||
} else {
|
||||
for (UInt16 block = block_base; block < (block_base + block_num); block++) {
|
||||
if (!npi_erase_block(_npi, part, bank, block)) {
|
||||
dprintf(DEBUG_SPEW,
|
||||
"WARNING: Erase(%d:%d:%d) failed\n", part, bank, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(block_num * bytes_per_block);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WITH_BLOCKDEV */
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 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.
|
||||
*/
|
||||
|
||||
#ifndef _NAND_FIRMWARE_H_
|
||||
#define _NAND_FIRMWARE_H_
|
||||
|
||||
// The ability to erase firmware is only allowed for triage/development purposes.
|
||||
#define ALLOW_NAND_FIRMWARE_ERASE (!RELEASE_BUILD && WITH_MENU && WITH_NAND_FIRMWARE)
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
bool nand_firmware_init(NandPartInterface *npi, uint32_t partIndex);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif // _NAND_FIRMWARE_H_
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += \
|
||||
WITH_NAND_FIRMWARE=1
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/nand_firmware.o
|
||||
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2012 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 <AssertMacros.h>
|
||||
#include <debug.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys.h>
|
||||
#include <sys/menu.h>
|
||||
#include <drivers/nand_boot.h>
|
||||
|
||||
#include <platform/clocks.h>
|
||||
#include <platform/soc/hwclocks.h>
|
||||
|
||||
#include <lib/profile.h>
|
||||
#include <lib/random.h>
|
||||
|
||||
#include "nand_part.h"
|
||||
#include "nand_part_interface.h"
|
||||
#include "nand_export.h"
|
||||
|
||||
#if WITH_NAND_FIRMWARE
|
||||
# include "firmware/nand_firmware.h"
|
||||
#endif
|
||||
|
||||
#if WITH_NAND_NVRAM
|
||||
# include "nvram/nand_nvram_platform.h"
|
||||
# include "nvram/nand_nvram_impl.h"
|
||||
#endif
|
||||
|
||||
#if WITH_NAND_SYSCFG
|
||||
# include <drivers/nand_syscfg.h>
|
||||
#endif
|
||||
|
||||
#if WITH_EFFACEABLE_NAND
|
||||
# include <lib/effaceable_nand.h>
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#if WITH_NAND_NVRAM
|
||||
extern bool flash_nand_nvram_init(NandPartInterface *npi, uint32_t part, bool isNewborn);
|
||||
#endif
|
||||
|
||||
// =============================================================================
|
||||
|
||||
static const char * kLogOrigin = "nand_boot";
|
||||
|
||||
#define _logLine(fac, fmt, args...) _logf_impl(kNandPartLogLevel##fac, "[%s:%s@%4d] " fmt "\n", kLogOrigin, kNandPartLogTag##fac, __LINE__, ##args)
|
||||
|
||||
#define error(args...) _logLine(Error, ##args)
|
||||
#define info(args...) _logLine(Info, ##args)
|
||||
|
||||
#if NAND_PART_EXTENDED_LOGGING
|
||||
# define warn(args...) _logLine(Warn, ##args)
|
||||
#else
|
||||
# define warn(args...) /* do nothing */
|
||||
#endif
|
||||
|
||||
#if NAND_PART_EXTENDED_LOGGING
|
||||
# define debug(args...) _logLine(Debug, ##args)
|
||||
#else
|
||||
# define debug(args...) /* do nothing */
|
||||
#endif
|
||||
|
||||
#if NAND_PART_LOCAL_DEBUG_ONLY
|
||||
# define spew(args...) _logLine(Spew, ##args)
|
||||
#else
|
||||
# define spew(args...) /* do nothing */
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#if NAND_PART_LOCAL_DEBUG_ONLY
|
||||
static void
|
||||
_conditionally_force_enable_uarts(void)
|
||||
{
|
||||
static bool isEnabled = false;
|
||||
if (!isEnabled) {
|
||||
debug_enable_uarts(3);
|
||||
isEnabled = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define _conditionally_force_enable_uarts() /* do nothing */
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static nand_boot_context_t _context;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#if DEBUG_BUILD
|
||||
# define USING_STRONG_SEED false
|
||||
#else
|
||||
# define USING_STRONG_SEED true
|
||||
#endif
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#if DEBUG_BUILD
|
||||
# define USING_STRONG_SEED false
|
||||
#else
|
||||
# define USING_STRONG_SEED true
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
// XXX - eliminate these references
|
||||
|
||||
#if WITH_NAND_FILESYSTEM
|
||||
extern uint32_t nand_fsys_block_offset;
|
||||
#elif WITH_NAND_SYSCFG
|
||||
uint32_t nand_fsys_block_offset;
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static bool _create_partition_device(void * context, NandPartEntry * entry, uint32_t idx);
|
||||
static bool _publish_partition_device(void * context, uint32_t idx);
|
||||
|
||||
static void * _alloc_mem(void * context, unsigned size, bool align);
|
||||
static int _compare_mem(void * context, const void * left, const void * right, unsigned int size);
|
||||
static void * _move_mem(void * context, void * dest, const void * src, unsigned size);
|
||||
static void * _set_mem(void * context, void * mem, uint8_t val, unsigned size);
|
||||
static void _free_mem(void * context, void * mem, unsigned size);
|
||||
|
||||
static void _lock_interface(void * context);
|
||||
static void _unlock_interface(void * context);
|
||||
|
||||
static void _read_random(void * context, void * buf, unsigned size);
|
||||
|
||||
static bool _set_data_property(void * context, const char * key, void * buf, unsigned size);
|
||||
static bool _set_number_property(void * context, const char * key, uint64_t num, unsigned bits);
|
||||
static bool _set_string_property(void * context, const char * key, const char * cstring);
|
||||
static bool _set_boolean_property(void * context, const char * key, bool val);
|
||||
|
||||
static bool _wait_for_fbbt_service(void * context);
|
||||
|
||||
static void _vlogf_message(void * context, NandPartLogLevel lvl, const char * fmt, va_list ap);
|
||||
static void _vlogf_impl(NandPartLogLevel lvl, const char * fmt, va_list ap);
|
||||
static void _logf_impl(NandPartLogLevel lvl, const char * fmt, ...);
|
||||
|
||||
static void init_nand_part_callbacks(NandPartProvider *npp);
|
||||
static void init_nand_part_params(NandPartProvider *npp);
|
||||
static bool init_nand_boot_context(nand_boot_context_t * cxt);
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
int
|
||||
nand_boot_init(void)
|
||||
{
|
||||
bool ok = true;
|
||||
static nand_boot_context_t * cxt = NULL;
|
||||
|
||||
PROFILE_ENTER('NBI');
|
||||
|
||||
// If we've already been initialized for some reason, short
|
||||
// circuit and finish.
|
||||
require(NULL == cxt, finish);
|
||||
cxt = &_context;
|
||||
|
||||
info("nand_boot_init() starting");
|
||||
|
||||
ok = init_nand_boot_context(cxt);
|
||||
require(ok, finally);
|
||||
|
||||
spew("initializing nand_part subsystem");
|
||||
ok = nand_part_init(&cxt->npi, &cxt->npp);
|
||||
require(ok, finally);
|
||||
|
||||
spew("scanning for nand boot partition tables");
|
||||
ok = npi_load_ptab(cxt->npi);
|
||||
require(ok, finally);
|
||||
|
||||
#if WITH_NAND_SYSCFG
|
||||
// Defer syscfg init until after file system has finished initializing.
|
||||
//
|
||||
// XXX - <rdar://problem/9192124> Open FTL before first syscfg request
|
||||
if (cxt->syscfg_needs_init && cxt->found_fsys_offset) {
|
||||
if (0 != nand_syscfg_init(cxt->npi)) {
|
||||
spew("unable to init syscfg");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
finally:
|
||||
|
||||
#if WITH_NAND_NVRAM
|
||||
// If nvram feature is needed but unable to find valid nand
|
||||
// nvram partition entry for any reason, create a mock
|
||||
// ram-based nvram device so that the system won't hang when
|
||||
// attempting to read the environment settings
|
||||
// (<rdar://problem/6675471>).
|
||||
if (!cxt->have_nvram_part) {
|
||||
if (!flash_nand_nvram_init(cxt->npi, kNandPartEntryMaxCount, true)) {
|
||||
spew("unable to create temporary nvram device");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
info("nand_boot_init() %s", ok ? "succeeded" : "failed");
|
||||
|
||||
finish:
|
||||
PROFILE_EXIT('NBI');
|
||||
return(ok ? 0 : -1);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static bool
|
||||
_create_partition_device(void * context, NandPartEntry * entry, uint32_t idx)
|
||||
{
|
||||
bool ok = true;
|
||||
nand_boot_context_t * cxt = withContext(context);
|
||||
|
||||
if (kNandPartEntryMaxCount != idx) {
|
||||
switch (entry->content) {
|
||||
case kNandPartContentSyscfg:
|
||||
cxt->syscfg_needs_init = true;
|
||||
break;
|
||||
case kNandPartContentNVRAM:
|
||||
cxt->have_nvram_part = true;
|
||||
break;
|
||||
default:
|
||||
// nothing to do for most cases
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool
|
||||
_publish_partition_device(void * context, uint32_t idx)
|
||||
{
|
||||
bool ok = true;
|
||||
nand_boot_context_t * cxt = withContext(context);
|
||||
const NandPartEntry * entry = NULL;
|
||||
|
||||
if (kNandPartEntryMaxCount == idx) {
|
||||
debug("nand has not yet been formatted\n");
|
||||
return ok;
|
||||
}
|
||||
|
||||
entry = npi_get_entry(cxt->npi, idx);
|
||||
switch (entry->content) {
|
||||
case kNandPartContentBootBlock:
|
||||
#if ALLOW_NAND_FIRMWARE_ERASE
|
||||
// The only reason to publish boot block device is to allow
|
||||
// the erasure of LLB in triage/development use cases.
|
||||
if (!nand_firmware_init(cxt->npi, idx)) {
|
||||
spew("unable to create nand LLB device\n");
|
||||
ok = false;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case kNandPartContentNVRAM:
|
||||
#if WITH_NAND_NVRAM
|
||||
if (!flash_nand_nvram_init(cxt->npi, idx, false)) {
|
||||
spew("unable to create nand nvram device\n");
|
||||
ok = false;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case kNandPartContentFirmware:
|
||||
#if WITH_NAND_FIRMWARE
|
||||
if (!nand_firmware_init(cxt->npi, idx)) {
|
||||
spew("unable to create nand firmware device\n");
|
||||
ok = false;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case kNandPartContentFilesystem:
|
||||
cxt->found_fsys_offset = true;
|
||||
cxt->fsys_block_offset = entry->slice.offset;
|
||||
#if WITH_NAND_SYSCFG
|
||||
nand_fsys_block_offset = entry->slice.offset;
|
||||
#elif WITH_NAND_FILESYS
|
||||
// XXX never reachable
|
||||
nand_fsys_block_offset = entry->slice.offset;
|
||||
#endif
|
||||
break;
|
||||
case kNandPartContentEffaceable:
|
||||
#if WITH_EFFACEABLE_NAND
|
||||
effaceable_nand_init(cxt->npi, idx);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
// nothing to do...
|
||||
ok = true;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static void *
|
||||
_alloc_mem(void * context, unsigned size, bool align)
|
||||
{
|
||||
void * buf = NULL;
|
||||
|
||||
if (align) {
|
||||
buf = memalign(size, CPU_CACHELINE_SIZE);
|
||||
} else {
|
||||
buf = malloc(size);
|
||||
}
|
||||
|
||||
return(buf);
|
||||
}
|
||||
|
||||
static int
|
||||
_compare_mem(void * context, const void * left, const void * right, unsigned int size)
|
||||
{
|
||||
return(memcmp(left, right, size));
|
||||
}
|
||||
|
||||
static void *
|
||||
_move_mem(void * context, void * dest, const void * src, unsigned size)
|
||||
{
|
||||
return(memmove(dest, src, size));
|
||||
}
|
||||
|
||||
static void *
|
||||
_set_mem(void * context, void * mem, uint8_t val, unsigned size)
|
||||
{
|
||||
return(memset(mem, val, size));
|
||||
}
|
||||
|
||||
static void
|
||||
_free_mem(void * context, void * mem, unsigned size)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
||||
static void
|
||||
_lock_interface(void * context)
|
||||
{
|
||||
// XXX - Given its cooperative multitasking nature, does iBoot
|
||||
// even need to bother with locking the nand_part_core
|
||||
// interface?
|
||||
}
|
||||
|
||||
static void
|
||||
_unlock_interface(void * context)
|
||||
{
|
||||
// XXX - Given its cooperative multitasking nature, does iBoot
|
||||
// even need to bother with locking the nand_part_core
|
||||
// interface?
|
||||
}
|
||||
|
||||
static void
|
||||
_read_random(void * context, void * buf, unsigned size)
|
||||
{
|
||||
static bool is_seeded = false;
|
||||
const unsigned increment = sizeof(int);
|
||||
uint8_t * cursor = (uint8_t *)buf;
|
||||
unsigned idx;
|
||||
|
||||
// if we're using a strong seed, draw from the entropy pool to
|
||||
// re-seed psuedo-random generator the first time function is called
|
||||
if (!is_seeded && USING_STRONG_SEED) {
|
||||
unsigned int seed;
|
||||
random_get_bytes((u_int8_t*)&seed, sizeof(seed));
|
||||
srand(seed);
|
||||
is_seeded = true;
|
||||
}
|
||||
|
||||
// fill with psuedo-random values by 'int'-sized chunks as long as possible
|
||||
for (idx = 0; (idx + increment) <= size; idx += increment, cursor += increment) {
|
||||
*((int*)cursor) = rand();
|
||||
}
|
||||
|
||||
// if size doesn't divide evenly by increment, fill fringe bytewise
|
||||
for (; idx < size; idx++, cursor++) {
|
||||
*cursor = (uint8_t)rand();
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
_set_data_property(void * context, const char * key, void * buf, unsigned size)
|
||||
{
|
||||
spew("%s=[%02x %02x %02x %02x ...]",
|
||||
key, ((uint8_t*)buf)[0], ((uint8_t*)buf)[1], ((uint8_t*)buf)[2], ((uint8_t*)buf)[3]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_set_number_property(void * context, const char * key, uint64_t num, unsigned bits)
|
||||
{
|
||||
spew("%s=%llu", key, num);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_set_string_property(void * context, const char * key, const char * cstring)
|
||||
{
|
||||
spew("%s=%s", key, cstring);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_set_boolean_property(void * context, const char * key, bool val)
|
||||
{
|
||||
spew("%s=%s", key, val ? "true" : "false");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_wait_for_fbbt_service(void * context)
|
||||
{
|
||||
// This callback is not relevant in iBoot context.
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
_vlogf_message(void * context, NandPartLogLevel lvl, const char * fmt, va_list ap)
|
||||
{
|
||||
_vlogf_impl(lvl, fmt, ap);
|
||||
}
|
||||
|
||||
static void
|
||||
_vlogf_impl(NandPartLogLevel lvl, const char * fmt, va_list ap)
|
||||
{
|
||||
#if DEBUG_BUILD
|
||||
const NandPartLogLevel max_level = kNandPartLogLevelDebug;
|
||||
#elif DEVELOPMENT_BUILD
|
||||
const NandPartLogLevel max_level = kNandPartLogLevelInfo;
|
||||
#else
|
||||
const NandPartLogLevel max_level = kNandPartLogLevelError;
|
||||
#endif
|
||||
|
||||
// XXX - Implement circular log buffer to help triage failures
|
||||
// before debug uart is turned on in development and debug
|
||||
// builds.
|
||||
|
||||
if (max_level >= lvl) {
|
||||
if ((kNandPartLogLevelError == lvl) || (kNandPartLogLevelBug == lvl)) {
|
||||
_conditionally_force_enable_uarts();
|
||||
}
|
||||
vprintf(fmt, ap);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_logf_impl(NandPartLogLevel lvl, const char * fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_vlogf_impl(lvl, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static void
|
||||
init_nand_part_callbacks(NandPartProvider *npp)
|
||||
{
|
||||
npp->lock_interface = _lock_interface;
|
||||
npp->unlock_interface = _unlock_interface;
|
||||
npp->alloc_mem = _alloc_mem;
|
||||
npp->compare_mem = _compare_mem;
|
||||
npp->move_mem = _move_mem;
|
||||
npp->set_mem = _set_mem;
|
||||
npp->free_mem = _free_mem;
|
||||
npp->read_random = _read_random;
|
||||
npp->set_data_property = _set_data_property;
|
||||
npp->set_number_property = _set_number_property;
|
||||
npp->set_string_property = _set_string_property;
|
||||
npp->set_boolean_property = _set_boolean_property;
|
||||
npp->wait_for_fbbt_service = _wait_for_fbbt_service;
|
||||
npp->create_partition_device = _create_partition_device;
|
||||
npp->publish_partition_device = _publish_partition_device;
|
||||
npp->vlogf_message = _vlogf_message;
|
||||
|
||||
// The following callbacks are initialized by nand_export_init():
|
||||
//
|
||||
// npp->read_boot_page
|
||||
// npp->read_full_page
|
||||
// npp->write_boot_page
|
||||
// npp->write_full_page
|
||||
// npp->erase_block
|
||||
// npp->is_block_factory_bad
|
||||
// npp->validate_spare_list
|
||||
// npp->request_spare_blocks
|
||||
}
|
||||
|
||||
static void
|
||||
init_nand_part_params(NandPartProvider *npp)
|
||||
{
|
||||
// The only destructive operation allowed on boot block is
|
||||
// erase of boot partition (i.e. LLB portion but not partition
|
||||
// table copies), available only in debug builds.
|
||||
#if ALLOW_NAND_FIRMWARE_ERASE
|
||||
npp->params.isBootPartErasable = true;
|
||||
#else
|
||||
npp->params.isBootPartErasable = false;
|
||||
#endif
|
||||
npp->params.isBootPartWritable = false;
|
||||
npp->params.isFormatEnabled = false;
|
||||
|
||||
// Enable debug-only features only in debug builds of iBoot.
|
||||
#if DEBUG_BUILD
|
||||
npp->params.isDebugEnabled = true;
|
||||
#else
|
||||
npp->params.isDebugEnabled = false;
|
||||
#endif
|
||||
|
||||
// In iBoot, only enable tracing for local developer builds.
|
||||
npp->params.isHostTraceEnabled = false;
|
||||
npp->params.isClientTraceEnabled = false;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static bool
|
||||
init_nand_boot_context(nand_boot_context_t * cxt)
|
||||
{
|
||||
memset(cxt, 0, sizeof(nand_boot_context_t));
|
||||
cxt->npp.context = cxt;
|
||||
|
||||
init_nand_part_params(&cxt->npp);
|
||||
init_nand_part_callbacks(&cxt->npp);
|
||||
|
||||
return nand_export_init(cxt);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static int do_nand_failval_set(int argc, struct cmd_arg *args)
|
||||
{
|
||||
nand_failval_set(args[1].n, args[2].n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MENU_COMMAND_DEBUG(nand_failval_set, do_nand_failval_set, "Set the number of operations before failure is injected", NULL);
|
||||
|
||||
// =============================================================================
|
||||
|
||||
static int do_nand_part_dump(int argc, struct cmd_arg *args)
|
||||
{
|
||||
nand_part_dump(_context.npi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MENU_COMMAND_DEBUG(nand_part_dump, do_nand_part_dump, "dump nand partition table info", NULL);
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2012 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 <stdarg.h>
|
||||
|
||||
#include "nand_part.h"
|
||||
#include "nand_part_interface.h"
|
||||
#include "nand_export.h"
|
||||
|
||||
#include <FIL.h>
|
||||
#include <debug.h>
|
||||
#include <AssertMacros.h>
|
||||
|
||||
#include "ANDTypes.h"
|
||||
#include "WMRFeatures.h"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
#define _log(fac, line, fmt, args...) dprintf(DEBUG_CRITICAL, "[nand_export.c : %s @ %4d] " fmt "\n", kNandPartLogTag##fac, line, ##args)
|
||||
|
||||
#define error(args...) _log(Error, __LINE__, ##args)
|
||||
#define info(args...) _log(Info, __LINE__, ##args)
|
||||
|
||||
#if NAND_PART_EXTENDED_LOGGING
|
||||
# define warn(args...) _log(Warn, __LINE__, ##args)
|
||||
# define debug(args...) _log(Debug, __LINE__, ##args)
|
||||
#else
|
||||
# define warn(args...) /* do nothing */
|
||||
# define debug(args...) /* do nothing */
|
||||
#endif
|
||||
|
||||
#if NAND_PART_LOCAL_DEBUG_ONLY
|
||||
# define spew(args...) _log(Spew, __LINE__, ##args)
|
||||
#else
|
||||
# define spew(args...) /* do nothing */
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static bool _read_boot_page(void * context, uint32_t ce, uint32_t addr, void * buf, bool * is_clean);
|
||||
static bool _read_full_page(void * context, uint32_t ce, uint32_t addr, void * buf, void * meta, bool * is_clean);
|
||||
static bool _write_boot_page(void * context, uint32_t ce, uint32_t addr, void * buf);
|
||||
static bool _write_full_page(void * context, uint32_t ce, uint32_t addr, void * buf, void * meta);
|
||||
static bool _erase_block(void * context, uint32_t ce, uint32_t addr, uint32_t block);
|
||||
|
||||
static bool _is_block_factory_bad(void * context, uint32_t ce, uint32_t block);
|
||||
static bool _validate_spare_list(void * context, uint32_t * ce_list, uint32_t * block_list, unsigned count);
|
||||
static bool _request_spare_blocks(void * context, uint32_t * ce_list, uint32_t * block_list, unsigned count, unsigned * quantity);
|
||||
|
||||
static void _init_nand_export_geometry(NandPartProvider *npp);
|
||||
static void _init_nand_export_callbacks(NandPartProvider *npp);
|
||||
|
||||
static int failVal[] = {0, 0, 0};
|
||||
static int numOps[] = {0, 0, 0};
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static bool
|
||||
_read_boot_page(void * context, uint32_t ce, uint32_t addr, void * buf, bool * is_clean)
|
||||
{
|
||||
Int32 ret;
|
||||
nand_boot_context_t * cxt = withContext(context);
|
||||
|
||||
require(cxt->is_fil_available, no_fil);
|
||||
require(0 != FIL_GetFuncTbl()->ReadBLPage, no_op);
|
||||
ret = FIL_GetFuncTbl()->ReadBLPage(ce, addr, buf);
|
||||
if (NULL != is_clean) {
|
||||
*is_clean = (ANDErrorCodeCleanOk == ret);
|
||||
}
|
||||
|
||||
numOps[READ_OP]++;
|
||||
if (failVal[READ_OP] > 0 && numOps[READ_OP] >= failVal[READ_OP]) {
|
||||
debug("*** injecting error ***\n");
|
||||
numOps[READ_OP] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return((ANDErrorCodeOk == ret) ? true : false);
|
||||
|
||||
no_op:
|
||||
#if RELEASE_BUILD
|
||||
error("no FIL ReadBLPage");
|
||||
#else
|
||||
panic("no FIL ReadBLPage");
|
||||
#endif
|
||||
|
||||
no_fil:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
_read_full_page(void * context, uint32_t ce, uint32_t addr, void * buf, void * meta, bool * is_clean)
|
||||
{
|
||||
Int32 ret;
|
||||
nand_boot_context_t * cxt = withContext(context);
|
||||
|
||||
require(cxt->is_fil_available, no_fil);
|
||||
require(0 != FIL_GetFuncTbl()->ReadWithECC, no_op);
|
||||
ret = FIL_GetFuncTbl()->ReadWithECC(ce, addr, buf, meta, NULL, NULL, false);
|
||||
if (NULL != is_clean) {
|
||||
*is_clean = (ANDErrorCodeCleanOk == ret);
|
||||
}
|
||||
|
||||
numOps[READ_OP]++;
|
||||
if (failVal[READ_OP] > 0 && numOps[READ_OP] >= failVal[READ_OP]) {
|
||||
debug("*** injecting error ***\n");
|
||||
numOps[READ_OP] = 0;
|
||||
return false;
|
||||
}
|
||||
return((ANDErrorCodeOk == ret) ? true : false);
|
||||
|
||||
no_op:
|
||||
#if RELEASE_BUILD
|
||||
error("no FIL ReadWithECC");
|
||||
#else
|
||||
panic("no FIL ReadWithECC");
|
||||
#endif
|
||||
|
||||
no_fil:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
_write_boot_page(void * context, uint32_t ce, uint32_t addr, void * buf)
|
||||
{
|
||||
Int32 ret;
|
||||
nand_boot_context_t * cxt = withContext(context);
|
||||
|
||||
require(cxt->is_fil_available, no_fil);
|
||||
require(0 != FIL_GetFuncTbl()->WriteBLPage, no_op);
|
||||
ret = FIL_GetFuncTbl()->WriteBLPage(ce, addr, buf);
|
||||
|
||||
numOps[WRITE_OP]++;
|
||||
if (failVal[WRITE_OP] > 0 && numOps[WRITE_OP] >= failVal[WRITE_OP]) {
|
||||
debug("*** injecting error ***\n");
|
||||
numOps[WRITE_OP] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return((ANDErrorCodeOk == ret) ? true : false);
|
||||
|
||||
no_op:
|
||||
#if RELEASE_BUILD
|
||||
error("no FIL WriteBLPage");
|
||||
#else
|
||||
panic("no FIL WriteBLPage");
|
||||
#endif
|
||||
|
||||
no_fil:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
_write_full_page(void * context, uint32_t ce, uint32_t addr, void * buf, void * meta)
|
||||
{
|
||||
Int32 ret;
|
||||
nand_boot_context_t * cxt = withContext(context);
|
||||
|
||||
require(cxt->is_fil_available, no_fil);
|
||||
require(0 != FIL_GetFuncTbl()->Write, no_op);
|
||||
ret = FIL_GetFuncTbl()->Write(ce, addr, buf, meta, false);
|
||||
|
||||
numOps[WRITE_OP]++;
|
||||
if (failVal[WRITE_OP] > 0 && numOps[WRITE_OP] >= failVal[WRITE_OP]) {
|
||||
debug("*** injecting error ***\n");
|
||||
numOps[WRITE_OP] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return((ANDErrorCodeOk == ret) ? true : false);
|
||||
|
||||
no_op:
|
||||
#if RELEASE_BUILD
|
||||
error("no FIL Write");
|
||||
#else
|
||||
panic("no FIL Write");
|
||||
#endif
|
||||
|
||||
no_fil:
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
_erase_block(void * context, uint32_t ce, uint32_t addr, uint32_t block)
|
||||
{
|
||||
Int32 ret;
|
||||
nand_boot_context_t * cxt = withContext(context);
|
||||
|
||||
require(cxt->is_fil_available, no_fil);
|
||||
require(0 != FIL_GetFuncTbl()->Erase, no_op);
|
||||
|
||||
// In iBoot, the FIL erase command expects an block offset;
|
||||
// however, other environments may expect an address instead.
|
||||
ret = FIL_GetFuncTbl()->Erase(ce, block);
|
||||
|
||||
numOps[ERASE_OP]++;
|
||||
if (failVal[ERASE_OP] > 0 && numOps[ERASE_OP] >= failVal[ERASE_OP]) {
|
||||
debug("*** injecting error ***\n");
|
||||
numOps[ERASE_OP] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
return((ANDErrorCodeOk == ret) ? true : false);
|
||||
|
||||
no_op:
|
||||
#if RELEASE_BUILD
|
||||
error("no FIL Erase");
|
||||
#else
|
||||
panic("no FIL Erase");
|
||||
#endif
|
||||
|
||||
no_fil:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static bool
|
||||
_is_block_factory_bad(void * context, uint32_t ce, uint32_t block)
|
||||
{
|
||||
// XXX - Access to factory bad block table not yet supported
|
||||
// in iBoot context. This probably should be fixed from an
|
||||
// academic perspective; however, by the time we've finished
|
||||
// formatting during first restore in iOS, the problem of
|
||||
// factory bad blocks should be moot for nand_part_core.
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
_validate_spare_list(void * context, uint32_t * ce_list, uint32_t * block_list, unsigned count)
|
||||
{
|
||||
// XXX - Double-checking spare block list against what VFL
|
||||
// believes it should be is not yet supported in iBoot; therefore,
|
||||
// for the moment, simply lie when asked and say that all is well.
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_request_spare_blocks(void * context, uint32_t * ce_list, uint32_t * block_list, unsigned count, unsigned * quantity)
|
||||
{
|
||||
// Requesting spare blocks should only happen as a result of
|
||||
// initial format (in iOS); therefore, it's a bug if this
|
||||
// callback is ever in invoked in iBoot.
|
||||
#if RELEASE_BUILD
|
||||
error("unexpected callback requesting spare blocks\n");
|
||||
#else
|
||||
panic("unexpected callback requesting spare blocks\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static void
|
||||
_init_nand_export_geometry(NandPartProvider *npp)
|
||||
{
|
||||
npp->geometry.isPpn = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_PPN_DEVICE);
|
||||
|
||||
npp->geometry.ceCount = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_NUM_OF_CS);
|
||||
|
||||
/* The value of AND_DEVINFO_BLOCKS_PER_CS should NOT be used for PPN */
|
||||
npp->geometry.blocksPerCE = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_BLOCKS_PER_CS);
|
||||
npp->geometry.blockStride = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_BLOCK_STRIDE);
|
||||
|
||||
npp->geometry.pagesPerMLCBlock = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_MLC_PAGES_PER_BLOCK);
|
||||
npp->geometry.pagesPerSLCBlock = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_SLC_PAGES_PER_BLOCK);
|
||||
|
||||
npp->geometry.bytesPerBootPage = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_BYTES_PER_BL_PAGE);
|
||||
npp->geometry.bytesPerFullPage = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_BYTES_PER_PAGE);
|
||||
npp->geometry.bytesPerFullPageMeta = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_FIL_META_BUFFER_BYTES) * FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_FIL_LBAS_PER_PAGE);
|
||||
|
||||
npp->geometry.bitsPerCauAddr = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_BITS_PER_CAU_ADDRESS);
|
||||
npp->geometry.bitsPerPageAddr = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_BITS_PER_PAGE_ADDRESS);
|
||||
npp->geometry.bitsPerBlockAddr = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_BITS_PER_BLOCK_ADDRESS);
|
||||
}
|
||||
|
||||
static void
|
||||
_init_nand_export_callbacks(NandPartProvider *npp)
|
||||
{
|
||||
npp->read_boot_page = _read_boot_page;
|
||||
npp->read_full_page = _read_full_page;
|
||||
npp->write_boot_page = _write_boot_page;
|
||||
npp->write_full_page = _write_full_page;
|
||||
npp->erase_block = _erase_block;
|
||||
npp->is_block_factory_bad = _is_block_factory_bad;
|
||||
npp->validate_spare_list = _validate_spare_list;
|
||||
npp->request_spare_blocks = _request_spare_blocks;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
bool
|
||||
nand_export_init(nand_boot_context_t * cxt)
|
||||
{
|
||||
bool ok = false;
|
||||
Int32 ret = 0;
|
||||
NandPartProvider *npp = &(cxt->npp);
|
||||
|
||||
ret = FIL_Init();
|
||||
|
||||
// Always export callbacks. Even if FIL failed to init, they
|
||||
// will be protected internally by 'cxt->is_fil_available'.
|
||||
_init_nand_export_callbacks(npp);
|
||||
|
||||
if (ANDErrorCodeOk == ret) {
|
||||
_init_nand_export_geometry(npp);
|
||||
ok = true;
|
||||
} else {
|
||||
dprintf(DEBUG_SPEW, "unable to init nand FIL\n");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
cxt->is_fil_available = ok;
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
|
||||
extern void
|
||||
nand_failval_set(int op_num, int fail_val)
|
||||
{
|
||||
int i;
|
||||
failVal[op_num] = fail_val;
|
||||
|
||||
/* print out the failure values set for each operation
|
||||
* where i = 0 = READ, i = 1 = WRITE, and i = 2 = ERASE
|
||||
*/
|
||||
for (i = 0; i < 3; i++)
|
||||
debug("%d %d\n", i, failVal[i]);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2012 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.
|
||||
*/
|
||||
|
||||
#ifndef _NAND_EXPORT_H
|
||||
#define _NAND_EXPORT_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct _nand_boot_context
|
||||
{
|
||||
NandPartProvider npp;
|
||||
NandPartInterface * npi;
|
||||
|
||||
bool is_fil_available;
|
||||
bool syscfg_needs_init;
|
||||
bool have_nvram_part;
|
||||
bool found_fsys_offset;
|
||||
|
||||
uint32_t fsys_block_offset;
|
||||
};
|
||||
|
||||
typedef struct _nand_boot_context nand_boot_context_t;
|
||||
|
||||
#define withContext(_ctxt) ((nand_boot_context_t*)(_ctxt))
|
||||
|
||||
bool nand_export_init(nand_boot_context_t * cxt);
|
||||
void nand_failval_set(int op_num, int fail_val);
|
||||
|
||||
#define READ_OP 0
|
||||
#define WRITE_OP 1
|
||||
#define ERASE_OP 2
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ! _NAND_EXPORT_H */
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2012 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.
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@header nand_part
|
||||
|
||||
@abstract definition of device-resident persistent partition table
|
||||
|
||||
@copyright Apple Inc.
|
||||
|
||||
@updated 2012-02-21
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifndef _NAND_PART_H
|
||||
#define _NAND_PART_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// feature introduction version history
|
||||
|
||||
#define kNandPartFeatureInitialVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeatureFBBTCacheVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeatureEffaceableVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeatureIgnoreFBBTVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeatureTrimDeviceVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeatureFuneralDirgeVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeatureCleanEntryFlagsVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeaturePortableCoreVersionMajor ((uint32_t)0x00000000)
|
||||
#define kNandPartFeaturePoolPartitionVersionMajor ((uint32_t)0x00000001)
|
||||
|
||||
#define kNandPartFeatureInitialVersionMinor ((uint32_t)0x00000001)
|
||||
#define kNandPartFeatureFBBTCacheVersionMinor ((uint32_t)0x00000002)
|
||||
#define kNandPartFeatureEffaceableVersionMinor ((uint32_t)0x00000003)
|
||||
#define kNandPartFeatureIgnoreFBBTVersionMinor ((uint32_t)0x00000004)
|
||||
#define kNandPartFeatureTrimDeviceVersionMinor ((uint32_t)0x00000005)
|
||||
#define kNandPartFeatureFuneralDirgeVersionMinor ((uint32_t)0x00000006)
|
||||
#define kNandPartFeatureCleanEntryFlagsVersionMinor ((uint32_t)0x00000007)
|
||||
#define kNandPartFeaturePortableCoreVersionMinor ((uint32_t)0x00000008)
|
||||
#define kNandPartFeaturePoolPartitionVersionMinor ((uint32_t)0x00000009)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// release version history - for historical reference only
|
||||
|
||||
#define kNandPartReleaseNorthstarVersionMajor kNandPartFeatureFBBTCacheVersionMajor
|
||||
#define kNandPartReleaseNorthstarVersionMinor kNandPartFeatureFBBTCacheVersionMinor
|
||||
|
||||
#define kNandPartReleaseNorthstar2VersionMajor kNandPartFeatureFBBTCacheVersionMajor
|
||||
#define kNandPartReleaseNorthstar2VersionMinor kNandPartFeatureFBBTCacheVersionMinor
|
||||
|
||||
#define kNandPartReleaseApexVersionMajor kNandPartFeatureIgnoreFBBTVersionMajor
|
||||
#define kNandPartReleaseApexVersionMinor kNandPartFeatureIgnoreFBBTVersionMinor
|
||||
|
||||
#define kNandPartReleaseBakerVersionMajor kNandPartFeatureFuneralDirgeVersionMajor
|
||||
#define kNandPartReleaseBakerVersionMinor kNandPartFeatureFuneralDirgeVersionMinor
|
||||
|
||||
#define kNandPartReleaseDurangoVersionMajor kNandPartFeatureFuneralDirgeVersionMajor
|
||||
#define kNandPartReleaseDurangoVersionMinor kNandPartFeatureFuneralDirgeVersionMinor
|
||||
|
||||
#define kNandPartReleaseTellurideVersionMajor kNandPartFeatureFuneralDirgeVersionMajor
|
||||
#define kNandPartReleaseTellurideVersionMinor kNandPartFeatureFuneralDirgeVersionMinor
|
||||
|
||||
#define kNandPartReleaseHoodooVersionMajor kNandPartFeatureFuneralDirgeVersionMajor
|
||||
#define kNandPartReleaseHoodooVersionMinor kNandPartFeatureFuneralDirgeVersionMinor
|
||||
|
||||
#define kNandPartReleaseSundanceVersionMajor kNandPartFeaturePoolPartitionVersionMajor
|
||||
#define kNandPartReleaseSundanceVersionMinor kNandPartFeaturePoolPartitionVersionMinor
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// general constants
|
||||
|
||||
#define kNandPartSectorSize 512
|
||||
#define kNandPartSectorsPerPage 3
|
||||
#define kNandPartPageSize (kNandPartSectorSize * kNandPartSectorsPerPage)
|
||||
#define kNandPartBankMax 16
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition header
|
||||
|
||||
typedef struct _NandPartHeader {
|
||||
|
||||
uint32_t magic;
|
||||
uint32_t should_be_zero;
|
||||
uint32_t versionMajor;
|
||||
uint32_t versionMinor;
|
||||
uint32_t generation;
|
||||
uint8_t reserved[12];
|
||||
|
||||
} __attribute__((__packed__)) NandPartHeader;
|
||||
|
||||
#define kNandPartHeaderMagic 'Grdn'
|
||||
|
||||
#define kNandPartHeaderVersionMajor kNandPartReleaseSundanceVersionMajor
|
||||
#define kNandPartHeaderVersionMinor kNandPartReleaseSundanceVersionMinor
|
||||
|
||||
#define kNandPartHeaderMaxSize (kNandPartSectorSize / 16)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition factory BBT cache
|
||||
|
||||
typedef struct _NandPartFBBTCacheInfo {
|
||||
|
||||
uint32_t blockDepth;
|
||||
uint32_t entryCount;
|
||||
|
||||
} __attribute__((__packed__)) NandPartFBBTCacheInfo;
|
||||
|
||||
#define kNandPartFBBTCacheMaxSize (kNandPartSectorSize - kNandPartHeaderMaxSize)
|
||||
#define kNandPartFBBTCacheEntriesMaxSize (kNandPartFBBTCacheMaxSize - sizeof(NandPartFBBTCacheInfo))
|
||||
|
||||
typedef struct _NandPartFBBTCacheEntry {
|
||||
|
||||
uint32_t bankNum;
|
||||
uint32_t blockAddr;
|
||||
|
||||
} __attribute__((__packed__)) NandPartFBBTCacheEntry;
|
||||
|
||||
#define kNandPartFBBTCacheEntryCount (kNandPartFBBTCacheEntriesMaxSize / sizeof(NandPartFBBTCacheEntry))
|
||||
|
||||
typedef struct _NandPartFBBTCache {
|
||||
|
||||
NandPartFBBTCacheInfo info;
|
||||
NandPartFBBTCacheEntry entries[kNandPartFBBTCacheEntryCount];
|
||||
|
||||
} __attribute__((__packed__)) NandPartFBBTCache;
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition device info
|
||||
|
||||
typedef struct _NandPartDevice {
|
||||
|
||||
uint32_t should_be_zero[2];
|
||||
uint32_t should_be_one;
|
||||
|
||||
uint32_t numOfCS;
|
||||
uint32_t blocksPerCS;
|
||||
uint32_t pagesPerBlock;
|
||||
uint32_t sectorsPerPage;
|
||||
uint32_t spareBytesPerPage;
|
||||
|
||||
uint32_t flags;
|
||||
|
||||
} __attribute__((__packed__)) NandPartDevice;
|
||||
|
||||
#define kNandPartDeviceFlagNone ((uint32_t)0x00000000)
|
||||
#define kNandPartDeviceFlagNeedsCemetery (((uint32_t)0x1) << 0)
|
||||
#define kNandPartDeviceFlagExplicitEntries (((uint32_t)0x1) << 1)
|
||||
#define kNandPartDeviceFlagAllowPool (((uint32_t)0x1) << 2)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// cemetery
|
||||
//
|
||||
// Where bad blocks go to die.
|
||||
|
||||
#define kNandPartCemeteryGate ((uint32_t) 0xDeadCafe)
|
||||
#define kNandPartCemeteryCapacity 256
|
||||
#define nandPartCemeteryPlotsSize(capacity) (((capacity) / 8) + (((capacity) % 8) ? 1 : 0))
|
||||
#define kNandPartCemeteryPlotsSize nandPartCemeteryPlotsSize(kNandPartCemeteryCapacity)
|
||||
|
||||
typedef struct _NandPartCemetery {
|
||||
|
||||
uint32_t gate;
|
||||
uint16_t capacity;
|
||||
uint8_t flags;
|
||||
uint8_t reserved[3];
|
||||
uint8_t plots[kNandPartCemeteryPlotsSize];
|
||||
uint8_t locks[2];
|
||||
|
||||
} __attribute__((__packed__)) NandPartCemetery;
|
||||
|
||||
#define kNandPartCemeteryFlagIgnoreLocks ((uint8_t)0x01)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// spare blocks
|
||||
|
||||
#define kNandPartSpareMaxCount 64
|
||||
#define kNandPartSpareMagic 'spAr'
|
||||
|
||||
typedef struct _NandPartSpareLocation {
|
||||
|
||||
uint8_t block[3];
|
||||
uint8_t ce;
|
||||
|
||||
} __attribute__((__packed__)) NandPartSpareLocation;
|
||||
|
||||
typedef struct _NandPartSpare {
|
||||
|
||||
uint32_t magic;
|
||||
uint16_t count;
|
||||
uint8_t flags;
|
||||
uint8_t reserved[3];
|
||||
NandPartSpareLocation locations[kNandPartSpareMaxCount];
|
||||
uint8_t checks[2];
|
||||
|
||||
} __attribute__((__packed__)) NandPartSpare;
|
||||
|
||||
#define kNandPartSpareFlagIgnoreChecks ((uint8_t)0x01)
|
||||
#define kNandPartSpareMinExtraCount 4
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// block substitutions
|
||||
|
||||
#define kNandPartSubstMaxCount kNandPartSpareMaxCount
|
||||
#define kNandPartSubstMagic 'subs'
|
||||
|
||||
typedef struct _NandPartSubst {
|
||||
|
||||
uint32_t magic;
|
||||
uint16_t count;
|
||||
uint8_t flags;
|
||||
uint8_t reserved[3];
|
||||
uint8_t maps[kNandPartSubstMaxCount];
|
||||
uint8_t checks[2];
|
||||
|
||||
} __attribute__((__packed__)) NandPartSubst;
|
||||
|
||||
#define kNandPartSubstFlagIgnoreChecks ((uint8_t)0x01)
|
||||
#define kNandPartSubstFlagCorrectedChecks ((uint8_t)0x02)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// unused
|
||||
|
||||
#define kNandPartUnusedSize (kNandPartSectorSize \
|
||||
- sizeof(NandPartDevice) \
|
||||
- sizeof(NandPartCemetery) \
|
||||
- sizeof(NandPartSpare) \
|
||||
- sizeof(NandPartSubst))
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition content
|
||||
|
||||
#define kNandPartContentUndefined 0x00000000
|
||||
#define kNandPartContentNone 'none'
|
||||
#define kNandPartContentBootBlock 'boot'
|
||||
#define kNandPartContentDiagData 'diag'
|
||||
#define kNandPartContentSyscfg 'scfg'
|
||||
#define kNandPartContentFirmware 'firm'
|
||||
#define kNandPartContentNVRAM 'nvrm'
|
||||
#define kNandPartContentFilesystem 'fsys'
|
||||
#define kNandPartContentEffaceable 'plog'
|
||||
#define kNandPartContentBadBlockTable 'fbbt'
|
||||
#define kNandPartContentErased 0xFFFFFFFF
|
||||
|
||||
#define kNandPartContentNameUnformatted "Unformatted"
|
||||
#define kNandPartContentNameUnallocated "Unallocated"
|
||||
#define kNandPartContentNameUnrecognized "Unrecognized"
|
||||
#define kNandPartContentNameBootBlock "Boot Block"
|
||||
#define kNandPartContentNameDiagData "Diagnostic Data"
|
||||
#define kNandPartContentNameSyscfg "System Config"
|
||||
#define kNandPartContentNameNVRAM "NVRAM"
|
||||
#define kNandPartContentNameFirmware "Firmware"
|
||||
#define kNandPartContentNameFilesystem "Filesystem"
|
||||
#define kNandPartContentNameEffaceable "Effaceable"
|
||||
#define kNandPartContentNameBadBlockTable "Bad Block Table"
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition entry
|
||||
|
||||
typedef struct _NandPartEntryInfo {
|
||||
|
||||
uint32_t content;
|
||||
uint32_t reserved_0;
|
||||
uint32_t reserved_1;
|
||||
uint32_t flags;
|
||||
|
||||
} __attribute__((__packed__)) NandPartEntryInfo;
|
||||
|
||||
typedef struct _NandPartEntrySlice {
|
||||
|
||||
uint32_t content;
|
||||
uint32_t offset;
|
||||
uint32_t depth;
|
||||
uint32_t flags;
|
||||
|
||||
} __attribute__((__packed__)) NandPartEntrySlice;
|
||||
|
||||
typedef struct _NandPartEntryPool {
|
||||
|
||||
uint32_t content;
|
||||
uint32_t width;
|
||||
uint32_t depth;
|
||||
uint32_t flags;
|
||||
|
||||
} __attribute__((__packed__)) NandPartEntryPool;
|
||||
|
||||
typedef union _NandPartEntry {
|
||||
|
||||
struct {
|
||||
|
||||
uint32_t content;
|
||||
uint32_t reserved_0;
|
||||
uint32_t reserved_1;
|
||||
uint32_t flags;
|
||||
|
||||
} __attribute__((__packed__));
|
||||
|
||||
NandPartEntryInfo info;
|
||||
NandPartEntrySlice slice;
|
||||
NandPartEntryPool pool;
|
||||
|
||||
} NandPartEntry;
|
||||
|
||||
#define kNandPartEntryMaxCount (kNandPartSectorSize / sizeof(NandPartEntry))
|
||||
|
||||
#define kNandPartEntryFlagsNone 0x00000000
|
||||
|
||||
#define kNandPartEntryFlagsTypeInfo 0x00000001
|
||||
#define kNandPartEntryFlagsTypeSlice 0x00000002
|
||||
#define kNandPartEntryFlagsTypePool 0x00000008
|
||||
#define kNandPartEntryFlagsUnpartitioned 0x80000000
|
||||
|
||||
#define kNandPartEntryFlagsTypeMask (kNandPartEntryFlagsTypeInfo | \
|
||||
kNandPartEntryFlagsTypeSlice | \
|
||||
kNandPartEntryFlagsTypePool | \
|
||||
kNandPartEntryFlagsUnpartitioned)
|
||||
|
||||
#define kNandPartEntryFlagsIsBulk 0x00000004
|
||||
#define kNandPartEntryFlagsUsingSLCBlocks 0x00000100
|
||||
#define kNandPartEntryFlagsUsingFullPages 0x00000200
|
||||
#define kNandPartEntryFlagsIgnoreFBBT 0x40000000
|
||||
|
||||
#define kNandPartEntryFlagsMiscMask (kNandPartEntryFlagsIsBulk | \
|
||||
kNandPartEntryFlagsUsingSLCBlocks | \
|
||||
kNandPartEntryFlagsUsingFullPages | \
|
||||
kNandPartEntryFlagsIgnoreFBBT)
|
||||
|
||||
#define kNandPartEntryFlagsMask (kNandPartEntryFlagsTypeMask | \
|
||||
kNandPartEntryFlagsMiscMask)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition table
|
||||
|
||||
typedef struct _NandPartTable {
|
||||
|
||||
NandPartHeader header;
|
||||
NandPartFBBTCache fbbtCache;
|
||||
NandPartDevice device;
|
||||
NandPartCemetery cemetery;
|
||||
NandPartSpare spare;
|
||||
NandPartSubst subst;
|
||||
uint8_t unused[kNandPartUnusedSize];
|
||||
NandPartEntry entries[kNandPartEntryMaxCount];
|
||||
|
||||
} __attribute__((__packed__)) NandPartTable;
|
||||
|
||||
#define kNandPartTableLayoutIsValid (sizeof(NandPartTable) == kNandPartPageSize)
|
||||
#define kNandPartTableCopies 2
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition table incremental differences
|
||||
//
|
||||
// incremental difference information about the current partition
|
||||
// table state that is stored in metadata of other on-nand containers
|
||||
// (e.g. nvram, effaceable) rather than in partition table itself
|
||||
|
||||
typedef struct _NandPartDiffHeader {
|
||||
|
||||
uint32_t magic;
|
||||
uint16_t size;
|
||||
uint16_t sequence;
|
||||
uint32_t versionMajor;
|
||||
uint32_t versionMinor;
|
||||
uint32_t generation;
|
||||
uint16_t flags;
|
||||
uint8_t reserved[10];
|
||||
|
||||
} __attribute__((__packed__)) NandPartDiffHeader;
|
||||
|
||||
typedef struct _NandPartDiff {
|
||||
|
||||
NandPartDiffHeader header;
|
||||
NandPartCemetery cemetery;
|
||||
uint8_t checks[2];
|
||||
|
||||
} __attribute__((__packed__)) NandPartDiff;
|
||||
|
||||
#define kNandPartDiffMagic 'Diff'
|
||||
#define kNandPartDiffFlagIgnoreChecks ((uint16_t)0x0001)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// boot loader
|
||||
|
||||
#define kNandPartLoaderPageCount 128
|
||||
#define kNandPartLoaderMaxPages (kNandPartLoaderPageCount - kNandPartTableCopies - 1)
|
||||
#define kNandPartLoaderMaxSize (kNandPartLoaderMaxPages * kNandPartPageSize)
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// generally useful macros
|
||||
|
||||
#define isMaskSet(_msk, _val) ((_msk) == ((_msk) & (_val)))
|
||||
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ! _NAND_PART_H */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2012 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.
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@header nand_part_core
|
||||
|
||||
@abstract prototypes for internal implementation of nand_part_core.c
|
||||
|
||||
@copyright Apple Inc.
|
||||
|
||||
@updated 2012-02-21
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifndef _NAND_PART_CORE_H
|
||||
#define _NAND_PART_CORE_H
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// XXX - pass this in from provider rather than hard-code copy
|
||||
|
||||
#define AND_SPARE_TYPE_REGION_BFN (0x40) // allowing BFN to use 4 bits for types
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// partition mapping
|
||||
//
|
||||
// Note that this is a calculated dynamic data structure only.
|
||||
|
||||
#define kNandPartMappingMaxCount kNandPartEntryMaxCount
|
||||
|
||||
typedef struct _NandPartMapping {
|
||||
|
||||
uint32_t total;
|
||||
uint32_t counts[kNandPartEntryMaxCount];
|
||||
uint32_t offsets[kNandPartEntryMaxCount];
|
||||
|
||||
} NandPartMapping;
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// mapped block replacement
|
||||
//
|
||||
// Note that this is a dynamic data structure only. The array of
|
||||
// these structs is effectively an expanded version of the persistent
|
||||
// NandPartSubst information, forming a fully populated table indexing
|
||||
// from block map number to spare index rather the other way around
|
||||
// for ease and speed of use when remapping in the runtime context.
|
||||
|
||||
#define kNandPartReplacementMaxCount kNandPartCemeteryCapacity
|
||||
#define kNandPartReplacementInvalidIndex ((uint32_t)-1)
|
||||
|
||||
typedef struct _NandPartReplacement {
|
||||
|
||||
bool isValid;
|
||||
bool isReplaced;
|
||||
uint32_t spareIndex;
|
||||
|
||||
} NandPartReplacement;
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// state of portable core providing interface for nand partitioning logic
|
||||
|
||||
typedef struct _NandPartCore {
|
||||
|
||||
NandPartInterface interface;
|
||||
NandPartProvider * provider;
|
||||
|
||||
NandPartEntry rawMedia;
|
||||
|
||||
bool isPTabValid;
|
||||
bool isBootPartErased;
|
||||
bool isFBBTCached;
|
||||
uint32_t bootIdx;
|
||||
uint16_t diffSequence[kNandPartEntryMaxCount];
|
||||
|
||||
uint8_t * meta;
|
||||
NandPartTable * ptab;
|
||||
|
||||
NandPartMapping mapping;
|
||||
NandPartReplacement replacements[kNandPartReplacementMaxCount];
|
||||
|
||||
} NandPartCore;
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
struct partition_spec {
|
||||
uint32_t type;
|
||||
uint32_t content;
|
||||
uint32_t depth;
|
||||
uint32_t width; /* optional, depending on type */
|
||||
};
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#define kNandPartCountInvalid ((uint32_t)-1)
|
||||
#define kNandPartBlockInvalid ((uint32_t)-1)
|
||||
#define kNandPartCEInvalid ((uint32_t)-1)
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Provider Service Wrappers
|
||||
|
||||
static bool hostCreatePartitionDevice(NandPartCore * npc, NandPartEntry * entry, unsigned idx);
|
||||
static bool hostPublishPartitionDevice(NandPartCore * npc, unsigned idx);
|
||||
static bool hostReadBootPage(NandPartCore * npc, uint32_t ce, uint32_t addr, void * buf, bool * is_clean);
|
||||
static bool hostReadFullPage(NandPartCore * npc, uint32_t ce, uint32_t addr, void * buf, void * meta, bool * is_clean);
|
||||
static bool hostWriteBootPage(NandPartCore * npc, uint32_t ce, uint32_t addr, void * buf);
|
||||
static bool hostWriteFullPage(NandPartCore * npc, uint32_t ce, uint32_t addr, void * buf, void * meta);
|
||||
static bool hostEraseBlock(NandPartCore * npc, uint32_t ce, uint32_t addr, uint32_t block);
|
||||
static void hostLogMessage(NandPartCore * npc, NandPartLogLevel lvl, const char * fmt, ...);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Initialization
|
||||
|
||||
static NandPartCore * withNandPartCore(NandPartProvider * provider);
|
||||
static bool createUnformattedPartitionDevice(NandPartCore * npc);
|
||||
static bool createPartitionDevices(NandPartCore * npc, bool isNewborn);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Version-Dependent Fixups
|
||||
|
||||
static void makeEntryTypesExplicit(NandPartCore * npc);
|
||||
static void addIgnoreFBBTFlag(NandPartCore * npc);
|
||||
static void cleanEntryFlags(NandPartCore * npc, NandPartEntry * entry, bool isNewborn);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Mature Device Preparation
|
||||
|
||||
static bool prepareMatureState(NandPartCore * npc, bool *isReborn);
|
||||
static void setPartitionTableProperties(NandPartCore * npc, bool isNewborn, bool isReborn);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Reborn/Newborn Device Preparation
|
||||
|
||||
static bool prepareRebornState(NandPartCore * npc);
|
||||
static bool prepareNewbornState(NandPartCore * npc, bool isReborn);
|
||||
static uint32_t countSparesNeeded(NandPartCore * npc, bool useWorstCase);
|
||||
static uint32_t countSparesExtra(NandPartCore * npc);
|
||||
static uint32_t scrubMappedPartitionsForStillborn(NandPartCore * npc);
|
||||
static bool scrubBlockForStillborn(NandPartCore * npc, uint32_t part, uint32_t bank, uint32_t block, void * patternBuf);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Initial Format/Partitioning
|
||||
|
||||
static bool formatWithSpecs(NandPartCore * npc);
|
||||
static void initPartitionTable(NandPartCore * npc);
|
||||
static uint32_t majorVersion(NandPartCore * npc);
|
||||
static bool addPartition(NandPartCore *npc, NandPartSpec *spec, uint32_t index, bool * haveBulk);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Runtime Parameters
|
||||
|
||||
static bool isBootPartErasable(NandPartCore * npc);
|
||||
static bool isBootPartWritable(NandPartCore * npc);
|
||||
static bool isFormatEnabled(NandPartCore * npc);
|
||||
static bool isDebugEnabled(NandPartCore * npc);
|
||||
static bool isPoolAllowed(NandPartCore * npc);
|
||||
static uint32_t maxMajorVersion(NandPartCore * npc);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Miscellaneous Global Information
|
||||
|
||||
static bool isPpnDevice(NandPartCore * npc);
|
||||
static bool findBootPartIndex(NandPartCore * npc, uint32_t * partIndex);
|
||||
static bool isEntryIndexValid(NandPartCore * npc, uint32_t partIndex, bool allowRawIndex);
|
||||
static bool isRawEntryIndex(NandPartCore * npc, uint32_t partIndex);
|
||||
static bool allowPoolPartitions(NandPartCore * npc);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Partition Entry Information
|
||||
|
||||
static const char * entryContentName(NandPartCore * npc, uint32_t partIndex);
|
||||
static bool areFlagsSet(NandPartCore * npc, uint32_t partIndex, uint32_t flagMask);
|
||||
static bool usingSLCBlocks(NandPartCore * npc, uint32_t partIndex);
|
||||
static bool usingFullPages(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t getBlockOffset(NandPartCore * npc, uint32_t partIndex);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Virtual to Physical Address Calculation
|
||||
|
||||
static uint32_t mapNandBlock(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
static uint32_t mapNandCE(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
static uint32_t calcNandAddress(NandPartCore * npc, uint32_t nandBlock, uint32_t pageInBlock, bool useSLC);
|
||||
|
||||
#if NAND_PART_CORE_ORPHAN
|
||||
static uint32_t calcNandBlock(NandPartCore * npc, uint32_t nandAddress, bool useSLC);
|
||||
#endif
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Meta Buffer Proxy
|
||||
|
||||
static uint8_t * getMetaBuf(NandPartCore * npc);
|
||||
static uint8_t * resetMetaBuf(NandPartCore * npc);
|
||||
static uint8_t * endorseMetaBuf(NandPartCore * npc, uint32_t partIndex);
|
||||
static void verifyMetaBuf(NandPartCore * npc, uint32_t partIndex);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Block Replacement
|
||||
|
||||
static bool initReplacements(NandPartCore * npc);
|
||||
static bool refreshReplacements(NandPartCore * npc);
|
||||
static bool validateSpare(NandPartCore * npc, NandPartSpare * spare);
|
||||
static bool validateSubst(NandPartCore * npc, NandPartSubst * subst);
|
||||
static bool isBlockReplaced(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, uint32_t * spareIndex);
|
||||
static NandPartReplacement * getMappedReplacement(NandPartCore * npc, uint32_t map);
|
||||
static NandPartSpareLocation * getSpareLocation(NandPartCore * npc, uint32_t spareIndex);
|
||||
static uint32_t getSpareLocationBlock(NandPartCore * npc, NandPartSpareLocation * location);
|
||||
static void setSpareLocationBlock(NandPartCore * npc, NandPartSpareLocation * location, uint32_t block);
|
||||
static bool substituteSparesForBadBlocks(NandPartCore * npc);
|
||||
static void initMapping(NandPartCore * npc);
|
||||
static bool isPartitionMapped(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t calcPartitionMapCount(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t getPartitionMapOffset(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t getTotalMapCount(NandPartCore * npc);
|
||||
static uint32_t calcBlockMap(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
|
||||
#if NAND_PART_CORE_ORPHAN
|
||||
static uint32_t getPartitionMapCount(NandPartCore * npc, uint32_t partIndex);
|
||||
#endif
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Bad Block Management
|
||||
|
||||
static bool initCemetery(NandPartCore * npc, bool isNewborn);
|
||||
static void fletcher16(NandPartCore * npc, uint8_t *checkA, uint8_t *checkB, const void *buf, size_t len);
|
||||
static bool isCemeterySafe(NandPartCore * npc, const NandPartCemetery *cemetery);
|
||||
static void changeCemeteryLocks(NandPartCore * npc, NandPartCemetery * cemetery);
|
||||
static bool mergePartitionCemetery(NandPartCore * npc, uint32_t partIndex, const NandPartCemetery * partCemetery, NandPartCemetery * mainCemetery);
|
||||
static void markBlockDead(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
static bool isBlockDead(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
static NandPartFBBTCache * getFBBTCache(NandPartCore * npc);
|
||||
static bool isBlockFactoryBad(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
static void cacheFactoryBadBlockTable(NandPartCore * npc);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Partition Table I/O
|
||||
|
||||
static bool readPTab(NandPartCore * npc);
|
||||
static bool validatePTab(NandPartCore * npc, const NandPartTable * ptab);
|
||||
static bool writePTab(NandPartCore * npc);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Partition Table Diffs
|
||||
|
||||
static void initDiffSequence(NandPartCore * npc);
|
||||
static bool validatePTabDiff(NandPartCore * npc, NandPartDiff * diff, unsigned size);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Structure Dumping
|
||||
|
||||
static void dumpNandGeometry(NandPartCore * npc, NandPartGeometry * geometry);
|
||||
static void dumpPTabHeader(NandPartCore * npc, NandPartHeader * header);
|
||||
static void dumpCemetery(NandPartCore * npc, NandPartCemetery * cemetery);
|
||||
static void dumpSpare(NandPartCore * npc, NandPartSpare * spare);
|
||||
static void dumpSubst(NandPartCore * npc, NandPartSubst * subst);
|
||||
static void dumpEntries(NandPartCore * npc, NandPartEntry * entries);
|
||||
static void dumpPTab(NandPartCore * npc, NandPartTable * ptab);
|
||||
static void dumpMapping(NandPartCore * npc, NandPartMapping * mapping);
|
||||
static void dumpReplacements(NandPartCore * npc, NandPartReplacement * replacements);
|
||||
static void dumpTranslationTables(NandPartCore * npc);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Interface Implementation
|
||||
|
||||
static const NandPartEntry * getEntry(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t getBankWidth(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t getBlockDepth(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t getPagesPerBlock(NandPartCore * npc, uint32_t partIndex);
|
||||
static uint32_t getBytesPerPage(NandPartCore * npc, uint32_t partIndex);
|
||||
static bool isBlockBad(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
static bool readPage(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, uint32_t pageInBlock, void * buf, bool * isClean, bool allowSpare);
|
||||
static bool writePage(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, uint32_t pageInBlock, void * buf, bool allowSpare);
|
||||
static bool eraseBlock(NandPartCore * npc, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, bool allowSpare);
|
||||
static bool requestPTabDiff(NandPartCore * npc, uint32_t partIndex, void * buf, unsigned size);
|
||||
static bool providePTabDiff(NandPartCore * npc, uint32_t partIndex, const void * buf, unsigned size);
|
||||
static bool formatPTab(NandPartCore * npc);
|
||||
static unsigned getPTabBytes(NandPartCore * npc, void * buf, unsigned size);
|
||||
static bool loadPartitionTable(NandPartCore * npc);
|
||||
static bool eraseBootPartition(NandPartCore * npc);
|
||||
static bool writeBootPartition(NandPartCore * npc, uint8_t * llbBuf, unsigned llbSize);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Unlocked External Interface Wrappers
|
||||
|
||||
static const NandPartEntry * getEntryExternal(void * core, uint32_t partIndex);
|
||||
static uint32_t getBankWidthExternal(void * core, uint32_t partIndex);
|
||||
static uint32_t getBlockDepthExternal(void * core, uint32_t partIndex);
|
||||
static uint32_t getPagesPerBlockExternal(void * core, uint32_t partIndex);
|
||||
static uint32_t getBytesPerPageExternal(void * core, uint32_t partIndex);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#pragma mark - Locked External Interface Wrappers
|
||||
|
||||
static bool loadPartitionTableExternal(void * core);
|
||||
static bool eraseBootPartitionExternal(void * core);
|
||||
static bool writeBootPartitionExternal(void * core, void * llbBuf, unsigned llbSize);
|
||||
static bool isBlockBadExternal(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock);
|
||||
static bool readPageExternal(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, uint32_t pageInBlock, void * buf, bool * isClean);
|
||||
static bool writePageExternal(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, uint32_t pageInBlock, void * buf);
|
||||
static bool eraseBlockExternal(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock);
|
||||
static bool requestPTabDiffExternal(void * core, uint32_t partIndex, void * buf, unsigned size);
|
||||
static bool providePTabDiffExternal(void * core, uint32_t partIndex, const void * buf, unsigned size);
|
||||
static bool formatPTabExternal(void * core);
|
||||
static unsigned getPTabBytesExternal(void * core, void * buf, unsigned size);
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _NAND_PART_CORE_H */
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2012 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.
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@header nand_part_interface
|
||||
|
||||
@abstract portable core for (mostly boot-related) nand partitioning logic
|
||||
|
||||
@copyright Apple Inc.
|
||||
|
||||
@updated 2012-02-21
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifndef _NAND_PART_INTERFACE_H
|
||||
#define _NAND_PART_INTERFACE_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
// disable significant amounts of the logging for tiny build profile
|
||||
#if (defined(WITH_NAND_PART_BUILD_TINY) && WITH_NAND_PART_BUILD_TINY)
|
||||
# define NAND_PART_EXTENDED_LOGGING 0
|
||||
#else
|
||||
# define NAND_PART_EXTENDED_LOGGING 1
|
||||
#endif
|
||||
|
||||
// enable for local development only; DO NOT SUBMIT with this enabled to trunk
|
||||
#define NAND_PART_LOCAL_DEBUG_ONLY 0
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
/* property keys */
|
||||
|
||||
#define kNandPartCoreVersionMajorKey "VersionMajor"
|
||||
#define kNandPartCoreVersionMinorKey "VersionMinor"
|
||||
#define kNandPartCoreGenerationKey "Generation"
|
||||
|
||||
#define kNandPartCoreIsFormattedKey "isFormatted"
|
||||
#define kNandPartCoreIsNewbornKey "isNewborn"
|
||||
#define kNandPartCoreIsRebornKey "isReborn"
|
||||
|
||||
#define kNandPartCoreMaxSparesKey "maxSpares"
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
enum _NandPartLogLevel {
|
||||
|
||||
kNandPartLogLevelAlways = 0,
|
||||
|
||||
kNandPartLogLevelBug = 1,
|
||||
kNandPartLogLevelError = 2,
|
||||
kNandPartLogLevelInfo = 3,
|
||||
kNandPartLogLevelWarn = 4,
|
||||
kNandPartLogLevelDebug = 5,
|
||||
kNandPartLogLevelSpew = 6,
|
||||
|
||||
kNandPartLogLevelNever
|
||||
};
|
||||
|
||||
typedef enum _NandPartLogLevel NandPartLogLevel;
|
||||
|
||||
extern const char * kNandPartLogTagBug;
|
||||
extern const char * kNandPartLogTagError;
|
||||
extern const char * kNandPartLogTagInfo;
|
||||
extern const char * kNandPartLogTagWarn;
|
||||
extern const char * kNandPartLogTagDebug;
|
||||
extern const char * kNandPartLogTagSpew;
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
struct _NandPartGeometry {
|
||||
|
||||
bool isPpn;
|
||||
|
||||
uint32_t ceCount;
|
||||
|
||||
uint32_t blocksPerCE;
|
||||
uint32_t blockStride;
|
||||
|
||||
uint32_t pagesPerMLCBlock;
|
||||
uint32_t pagesPerSLCBlock;
|
||||
|
||||
uint32_t bytesPerBootPage;
|
||||
uint32_t bytesPerFullPage;
|
||||
uint32_t bytesPerFullPageMeta;
|
||||
|
||||
uint32_t bitsPerCauAddr;
|
||||
uint32_t bitsPerPageAddr;
|
||||
uint32_t bitsPerBlockAddr;
|
||||
};
|
||||
|
||||
typedef struct _NandPartGeometry NandPartGeometry;
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
struct _NandPartSpec {
|
||||
uint32_t type;
|
||||
uint32_t content;
|
||||
uint32_t depth;
|
||||
uint32_t width;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
typedef struct _NandPartSpec NandPartSpec;
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
struct _NandPartParams {
|
||||
|
||||
bool isBootPartErasable;
|
||||
bool isBootPartWritable;
|
||||
bool isFormatEnabled;
|
||||
bool isDebugEnabled;
|
||||
bool isHostTraceEnabled;
|
||||
bool isClientTraceEnabled;
|
||||
bool isPoolAllowed;
|
||||
uint32_t maxMajorVersion;
|
||||
NandPartSpec partitionSpecs[kNandPartEntryMaxCount];
|
||||
};
|
||||
|
||||
typedef struct _NandPartParams NandPartParams;
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
struct _NandPartProvider {
|
||||
|
||||
void * context;
|
||||
NandPartGeometry geometry;
|
||||
NandPartParams params;
|
||||
|
||||
void (*lock_interface)(void * context);
|
||||
void (*unlock_interface)(void * context);
|
||||
void * (*alloc_mem)(void * context, unsigned size, bool align);
|
||||
int (*compare_mem)(void * context, const void * left, const void * right, unsigned int size);
|
||||
void * (*move_mem)(void * context, void * dest, const void * src, unsigned size);
|
||||
void * (*set_mem)(void * context, void * mem, uint8_t val, unsigned size);
|
||||
void (*free_mem)(void * context, void * mem, unsigned size);
|
||||
void (*read_random)(void * context, void * buf, unsigned size);
|
||||
bool (*read_boot_page)(void * context, uint32_t ce, uint32_t addr, void * buf, bool * is_clean);
|
||||
bool (*read_full_page)(void * context, uint32_t ce, uint32_t addr, void * buf, void * meta, bool * is_clean);
|
||||
bool (*write_boot_page)(void * context, uint32_t ce, uint32_t addr, void * buf);
|
||||
bool (*write_full_page)(void * context, uint32_t ce, uint32_t addr, void * buf, void * meta);
|
||||
bool (*erase_block)(void * context, uint32_t ce, uint32_t addr, uint32_t block);
|
||||
bool (*is_block_factory_bad)(void * context, uint32_t ce, uint32_t block);
|
||||
bool (*validate_spare_list)(void * context, uint32_t * ce_list, uint32_t * block_list, unsigned count);
|
||||
bool (*request_spare_blocks)(void * context, uint32_t * ce_list, uint32_t * block_list, unsigned count, unsigned * quantity);
|
||||
bool (*set_data_property)(void * context, const char * key, void * buf, unsigned size);
|
||||
bool (*set_number_property)(void * context, const char * key, uint64_t num, unsigned bits);
|
||||
bool (*set_string_property)(void * context, const char * key, const char * cstring);
|
||||
bool (*set_boolean_property)(void * context, const char * key, bool val);
|
||||
bool (*wait_for_fbbt_service)(void * context);
|
||||
bool (*create_partition_device)(void * context, NandPartEntry * entry, uint32_t idx);
|
||||
bool (*publish_partition_device)(void * context, uint32_t idx);
|
||||
void (*vlogf_message)(void * context, NandPartLogLevel lvl, const char * fmt, va_list ap);
|
||||
};
|
||||
|
||||
typedef struct _NandPartProvider NandPartProvider;
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
struct _NandPartInterface {
|
||||
|
||||
void * core;
|
||||
|
||||
bool (*load_ptab)(void * core);
|
||||
bool (*erase_boot_partition)(void * core);
|
||||
bool (*write_boot_partition)(void * core, void * llbBuf, unsigned llbSize);
|
||||
bool (*is_block_bad)(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock);
|
||||
const NandPartEntry * (*get_entry)(void * core, uint32_t partIndex);
|
||||
uint32_t (*get_bank_width)(void * core, uint32_t partIndex);
|
||||
uint32_t (*get_block_depth)(void * core, uint32_t partIndex);
|
||||
uint32_t (*get_pages_per_block)(void * core, uint32_t partIndex);
|
||||
uint32_t (*get_bytes_per_page)(void * core, uint32_t partIndex);
|
||||
bool (*read_page)(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, uint32_t pageInBlock, void * buf, bool * isClean);
|
||||
bool (*write_page)(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock, uint32_t pageInBlock, void * buf);
|
||||
bool (*erase_block)(void * core, uint32_t partIndex, uint32_t partBank, uint32_t partBlock);
|
||||
bool (*request_ptab_diff)(void * core, uint32_t partIndex, void * buf, unsigned size);
|
||||
bool (*provide_ptab_diff)(void * core, uint32_t partIndex, const void * buf, unsigned size);
|
||||
bool (*format_ptab)(void * core);
|
||||
unsigned (*get_ptab_bytes)(void * core, void * buf, unsigned size);
|
||||
};
|
||||
|
||||
typedef struct _NandPartInterface NandPartInterface;
|
||||
|
||||
#define _npiExec(npi, fn, args...) npi->fn(npi->core, ##args)
|
||||
|
||||
#define npi_load_ptab(npi) _npiExec(npi, load_ptab)
|
||||
#define npi_erase_boot_partition(npi) _npiExec(npi, erase_boot_partition)
|
||||
#define npi_write_boot_partition(npi, buf, size) _npiExec(npi, write_boot_partition, buf, size)
|
||||
#define npi_is_block_bad(npi, part, bank, block) _npiExec(npi, is_block_bad, part, bank, block)
|
||||
#define npi_get_entry(npi, part) _npiExec(npi, get_entry, part)
|
||||
#define npi_get_bank_width(npi, part) _npiExec(npi, get_bank_width, part)
|
||||
#define npi_get_block_depth(npi, part) _npiExec(npi, get_block_depth, part)
|
||||
#define npi_get_pages_per_block(npi, part) _npiExec(npi, get_pages_per_block, part)
|
||||
#define npi_get_bytes_per_page(npi, part) _npiExec(npi, get_bytes_per_page, part)
|
||||
#define npi_read_page(npi, part, bank, block, page, buf, clean) _npiExec(npi, read_page, part, bank, block, page, buf, clean)
|
||||
#define npi_write_page(npi, part, bank, block, page, buf) _npiExec(npi, write_page, part, bank, block, page, buf)
|
||||
#define npi_erase_block(npi, part, bank, block) _npiExec(npi, erase_block, part, bank, block)
|
||||
#define npi_request_ptab_diff(npi, part, buf, size) _npiExec(npi, request_ptab_diff, part, buf, size)
|
||||
#define npi_provide_ptab_diff(npi, part, buf, size) _npiExec(npi, provide_ptab_diff, part, buf, size)
|
||||
#define npi_format_ptab(npi) _npiExec(npi, format_ptab)
|
||||
#define npi_get_ptab_bytes(npi, buf, size) _npiExec(npi, get_ptab_bytes, buf, size)
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
extern bool nand_part_init(NandPartInterface ** interface, NandPartProvider * provider);
|
||||
extern void nand_part_dump(NandPartInterface * interface);
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _NAND_PART_INTERFACE_H */
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 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 WITH_NVRAM
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#include <platform.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <lib/blockdev.h>
|
||||
#include <lib/nvram.h>
|
||||
#include <lib/env.h>
|
||||
#include <lib/libc.h>
|
||||
|
||||
#include <sys/menu.h>
|
||||
#include <sys/task.h>
|
||||
|
||||
#include <platform/soc/hwclocks.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "nand_part.h"
|
||||
#include "nand_part_interface.h"
|
||||
#include "nand_export.h"
|
||||
#include "nand_nvram_impl.h"
|
||||
#include "nand_nvram_core.h"
|
||||
#include "nand_nvram_dump.h"
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#define DEBUG_NONDESTRUCTIVE 0
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#define TRACE_ENABLE 0
|
||||
#if TRACE_ENABLE
|
||||
|
||||
// FWiW: tracing is relying on single-threaded behavior for correctness
|
||||
|
||||
static utime_t trace_time = 0;
|
||||
static unsigned int trace_line = 0;
|
||||
|
||||
#define TRACE_BEFORE() \
|
||||
do { \
|
||||
trace_line = __LINE__; \
|
||||
trace_time = system_time(); \
|
||||
} while (0)
|
||||
|
||||
#define TRACE_AFTER() \
|
||||
do { \
|
||||
utime_t elapsed = system_time() - trace_time; \
|
||||
dprintf(DEBUG_CRITICAL, \
|
||||
"\nTRACE - %s@%u-%u: %u.%03u ms\n", \
|
||||
__func__, \
|
||||
trace_line, \
|
||||
__LINE__, \
|
||||
elapsed / 1000, \
|
||||
elapsed % 1000); \
|
||||
} while (0)
|
||||
|
||||
#else /* !TRACE_ENABLE */
|
||||
|
||||
#define TRACE_BEFORE() /* do nothing */
|
||||
#define TRACE_AFTER() /* do nothing */
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
typedef struct {
|
||||
|
||||
NandPartInterface * npi;
|
||||
uint32_t part;
|
||||
bool is_initialized;
|
||||
nand_nvram_t * nvram;
|
||||
struct blockdev nvram_bdev;
|
||||
|
||||
} _context_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static _context_t _context = { .part = ~0 };
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static int flash_nand_nvram_read(struct blockdev *bdev, void *buffer, off_t offset, uint64_t length);
|
||||
static int flash_nand_nvram_read_block(struct blockdev *bdev, void *buffer, block_addr block, uint32_t count);
|
||||
static int flash_nand_nvram_write(struct blockdev *bdev, const void *buffer, off_t offset, uint64_t length);
|
||||
static int flash_nand_nvram_write_block(struct blockdev *bdev, const void *buffer, block_addr block, uint32_t count);
|
||||
|
||||
extern bool
|
||||
flash_nand_nvram_init(NandPartInterface *npi, uint32_t part, bool isNewborn)
|
||||
{
|
||||
nand_nvram_geometry_t geometry;
|
||||
uint32_t page_size = 0;
|
||||
|
||||
if (_context.is_initialized)
|
||||
goto done;
|
||||
|
||||
dprintf(DEBUG_SPEW, "initializing nand nvram...\n");
|
||||
|
||||
TRACE_BEFORE();
|
||||
if (isNewborn || (NULL == npi)) {
|
||||
|
||||
dprintf(DEBUG_SPEW, "nand partition table unavailable; returning failure\n");
|
||||
goto done;
|
||||
|
||||
} else {
|
||||
|
||||
_context.npi = npi;
|
||||
_context.part = part;
|
||||
|
||||
page_size = npi_get_bytes_per_page(npi, part);
|
||||
|
||||
/* specify nand geometry information */
|
||||
geometry.bytes_per_meta_buffer = kNAND_NVRAM_META_SIZE;
|
||||
geometry.bytes_per_meta_actual = kNAND_NVRAM_META_SIZE;
|
||||
geometry.number_of_banks = npi_get_bank_width(npi, part);
|
||||
geometry.blocks_per_bank = npi_get_block_depth(npi, part);
|
||||
geometry.pages_per_block = npi_get_pages_per_block(npi, part);
|
||||
geometry.data_pages_per_block = geometry.pages_per_block - kNAND_NVRAM_PAGE_RESERVED_IN_BLOCK;
|
||||
geometry.bytes_per_page = page_size - geometry.bytes_per_meta_buffer;
|
||||
|
||||
if (!nand_nvram_open(&_context.nvram, &_context, &geometry, kNAND_NVRAM_SIZE)) {
|
||||
dprintf(DEBUG_CRITICAL, "couldn't open nand nvram device\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
dprintf(DEBUG_SPEW, "nand nvram initialized\n");
|
||||
}
|
||||
|
||||
construct_blockdev(&_context.nvram_bdev, "nvram", kNAND_NVRAM_SIZE, 1);
|
||||
_context.nvram_bdev.read_hook = &flash_nand_nvram_read;
|
||||
_context.nvram_bdev.read_block_hook = &flash_nand_nvram_read_block;
|
||||
_context.nvram_bdev.write_hook = &flash_nand_nvram_write;
|
||||
_context.nvram_bdev.write_block_hook = &flash_nand_nvram_write_block;
|
||||
register_blockdev(&_context.nvram_bdev);
|
||||
|
||||
_context.is_initialized = true;
|
||||
|
||||
done:
|
||||
TRACE_AFTER();
|
||||
return (_context.is_initialized);
|
||||
}
|
||||
|
||||
static int
|
||||
flash_nand_nvram_read(struct blockdev *bdev, void *buffer, off_t offset, uint64_t length)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
TRACE_BEFORE();
|
||||
if (!_context.is_initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ok = nand_nvram_read(_context.nvram, offset, buffer, length);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok ? length : 0);
|
||||
}
|
||||
|
||||
static int
|
||||
flash_nand_nvram_read_block(struct blockdev *bdev, void *buffer, block_addr block, uint32_t count)
|
||||
{
|
||||
return flash_nand_nvram_read(bdev, buffer, block, count);
|
||||
}
|
||||
|
||||
static int
|
||||
flash_nand_nvram_write(struct blockdev *bdev, const void *buffer, off_t offset, uint64_t length)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
TRACE_BEFORE();
|
||||
if (!_context.is_initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ok = nand_nvram_write(_context.nvram, offset, buffer, length);
|
||||
if (ok)
|
||||
ok = nand_nvram_sync(_context.nvram);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok ? length : 0);
|
||||
}
|
||||
|
||||
static int
|
||||
flash_nand_nvram_write_block(struct blockdev *bdev, const void *buffer, block_addr block, uint32_t count)
|
||||
{
|
||||
return flash_nand_nvram_write(bdev, buffer, block, count);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
bool
|
||||
flash_nand_nvram_is_block_bad(void * context, uint32_t bank, uint32_t block)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
bool bad;
|
||||
|
||||
TRACE_BEFORE();
|
||||
bad = npi_is_block_bad(ctxt->npi, ctxt->part, bank, block);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (bad);
|
||||
}
|
||||
|
||||
bool
|
||||
flash_nand_nvram_read_page(void * context, uint32_t bank, uint32_t page, void * data, void * meta, bool * is_clean)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
const nand_nvram_geometry_t * geo = nand_nvram_get_geometry(ctxt->nvram);
|
||||
const uint32_t block = page / geo->pages_per_block;
|
||||
const uint32_t page_in_block = page % geo->pages_per_block;
|
||||
const uint32_t nand_page_size = npi_get_bytes_per_page(ctxt->npi, ctxt->part);
|
||||
UInt8 * buf = NULL;
|
||||
bool ok = false;
|
||||
|
||||
TRACE_BEFORE();
|
||||
buf = (UInt8*)memalign(nand_page_size, CPU_CACHELINE_SIZE);
|
||||
|
||||
if (npi_read_page(ctxt->npi, ctxt->part, bank, block, page_in_block, buf, is_clean)) {
|
||||
|
||||
memcpy(meta, buf, geo->bytes_per_meta_actual);
|
||||
memcpy(data, buf + geo->bytes_per_meta_buffer, geo->bytes_per_page);
|
||||
|
||||
ok = true;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
bool
|
||||
flash_nand_nvram_write_page(void * context, uint32_t bank, uint32_t page, void * data, void * meta)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
const nand_nvram_geometry_t * geo = nand_nvram_get_geometry(ctxt->nvram);
|
||||
const uint32_t block = page / geo->pages_per_block;
|
||||
const uint32_t page_in_block = page % geo->pages_per_block;
|
||||
const uint32_t nand_page_size = npi_get_bytes_per_page(ctxt->npi, ctxt->part);
|
||||
UInt8 * buf = NULL;
|
||||
bool ok = false;
|
||||
|
||||
TRACE_BEFORE();
|
||||
buf = (UInt8*)memalign(nand_page_size, CPU_CACHELINE_SIZE);
|
||||
|
||||
memcpy(buf, meta, geo->bytes_per_meta_actual);
|
||||
memcpy(buf + geo->bytes_per_meta_buffer, data, geo->bytes_per_page);
|
||||
|
||||
ok = npi_write_page(ctxt->npi, ctxt->part, bank, block, page_in_block, buf);
|
||||
|
||||
free(buf);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
bool
|
||||
flash_nand_nvram_request_ptab_diff(void * context, void * data, uint32_t size)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
bool ok;
|
||||
|
||||
TRACE_BEFORE();
|
||||
ok = npi_request_ptab_diff(ctxt->npi, ctxt->part, data, size);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
bool
|
||||
flash_nand_nvram_provide_ptab_diff(void * context, void * data, uint32_t size)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
bool ok;
|
||||
|
||||
TRACE_BEFORE();
|
||||
ok = npi_provide_ptab_diff(ctxt->npi, ctxt->part, data, size);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
bool
|
||||
flash_nand_nvram_erase_block(void * context, uint32_t bank, uint32_t block)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
bool ok;
|
||||
|
||||
TRACE_BEFORE();
|
||||
ok = npi_erase_block(ctxt->npi, ctxt->part, bank, block);
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
bool flash_nand_nvram_copy_ptab(void * context, void * buf)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
bool ok = false;
|
||||
|
||||
TRACE_BEFORE();
|
||||
if (NULL != buf) {
|
||||
ok = npi_get_ptab_bytes(ctxt->npi, buf, npi_get_bytes_per_page(ctxt->npi, ctxt->part));
|
||||
}
|
||||
TRACE_AFTER();
|
||||
|
||||
return(ok);
|
||||
}
|
||||
|
||||
bool flash_nand_nvram_read_ptab(void * context, uint32_t bank, uint32_t page, void * buf)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
const nand_nvram_geometry_t * geo = nand_nvram_get_geometry(ctxt->nvram);
|
||||
const uint32_t block = page / geo->pages_per_block;
|
||||
const uint32_t page_in_block = page % geo->pages_per_block;
|
||||
bool is_clean;
|
||||
bool ok = false;
|
||||
|
||||
TRACE_BEFORE();
|
||||
if (NULL != buf) {
|
||||
ok = npi_read_page(ctxt->npi, ctxt->part, bank, block, page_in_block, buf, &is_clean);
|
||||
}
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
bool flash_nand_nvram_write_ptab(void * context, uint32_t bank, uint32_t page, void * buf)
|
||||
{
|
||||
const _context_t * ctxt = (_context_t*)context;
|
||||
const nand_nvram_geometry_t * geo = nand_nvram_get_geometry(ctxt->nvram);
|
||||
const uint32_t block = page / geo->pages_per_block;
|
||||
const uint32_t page_in_block = page % geo->pages_per_block;
|
||||
bool ok = false;
|
||||
|
||||
TRACE_BEFORE();
|
||||
if (NULL != buf) {
|
||||
ok = npi_write_page(ctxt->npi, ctxt->part, bank, block, page_in_block, buf);
|
||||
}
|
||||
TRACE_AFTER();
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static int do_nvram_dump(int argc, struct cmd_arg *args)
|
||||
{
|
||||
return (nand_nvram_dump(_context.nvram) ? 0 : -1);
|
||||
}
|
||||
|
||||
MENU_COMMAND_DEVELOPMENT(nvramdump, do_nvram_dump, "dump nand-based nvram pages", NULL);
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#endif // WITH_NVRAM
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2008-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.
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@header nand_nvram_core
|
||||
|
||||
@abstract portable core of a nand-based NVRAM device implementation
|
||||
|
||||
@discussion In order to boot from nand, the NVRAM device must have an
|
||||
implementation with a backing store on the nand flash device since
|
||||
the traditional nor-based backing store will no longer be available.
|
||||
This class implements such a device over a slice of the nand array,
|
||||
using a journalled commit approach with multiple redundant copies.
|
||||
|
||||
@copyright Apple Inc.
|
||||
|
||||
@updated 2011-05-18
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifndef _NAND_NVRAM_CORE_H
|
||||
#define _NAND_NVRAM_CORE_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@group public platform-independent interface function declarations
|
||||
*/
|
||||
|
||||
/*!
|
||||
@function nand_nvram_open
|
||||
|
||||
@abstract Open platform-independent ram-shadowed nand nvram device.
|
||||
|
||||
@param _geometry Geometry of nand device array slice for backing store.
|
||||
|
||||
@result Returns bool indicating whether function succeeded.
|
||||
*/
|
||||
bool nand_nvram_open(nand_nvram_t ** _nvram, void * context, nand_nvram_geometry_t * _geometry, uint32_t _size);
|
||||
|
||||
/*!
|
||||
@function nand_nvram_read
|
||||
|
||||
@abstract Read data from the nvram device shadow.
|
||||
|
||||
@param _offset Byte offset into nvram data blob.
|
||||
|
||||
@param _buffer Pointer to memory buffer to read data from.
|
||||
|
||||
@param _length Amount of data in bytes to read from blob.
|
||||
|
||||
@result Returns bool indicating whether function succeeded.
|
||||
*/
|
||||
bool nand_nvram_read(nand_nvram_t * _nvram, uint32_t _offset, uint8_t * _buffer, uint32_t _length);
|
||||
|
||||
/*!
|
||||
@function nand_nvram_write
|
||||
|
||||
@abstract Write data to the nvram device shadow.
|
||||
|
||||
@param _offset Byte offset into nvram data blob.
|
||||
|
||||
@param _buffer Pointer to memory buffer to write data into.
|
||||
|
||||
@param _length Amount of data in bytes to write to blob.
|
||||
|
||||
@result Returns bool indicating whether function succeeded.
|
||||
*/
|
||||
bool nand_nvram_write(nand_nvram_t * _nvram, uint32_t _offset, const uint8_t * _buffer, uint32_t _length);
|
||||
|
||||
/*!
|
||||
@function nand_nvram_sync
|
||||
|
||||
@abstract Synchronize nvram device data to backing store.
|
||||
|
||||
@result Returns bool indicating whether function succeeded.
|
||||
*/
|
||||
bool nand_nvram_sync(nand_nvram_t * _nvram);
|
||||
|
||||
/*!
|
||||
@function nand_nvram_get_geometry
|
||||
|
||||
@abstract Provide access to nand nvram driver's geometry information.
|
||||
|
||||
@result Returns pointer to struct defining nand nvram geometry.
|
||||
*/
|
||||
const nand_nvram_geometry_t * nand_nvram_get_geometry(nand_nvram_t * _nvram);
|
||||
|
||||
/*!
|
||||
@function nand_nvram_close
|
||||
|
||||
@abstract Close platform-independent ram-shadowed nand nvram device.
|
||||
*/
|
||||
void nand_nvram_close(nand_nvram_t ** _nvram);
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ! _NAND_NVRAM_CORE_H */
|
||||
|
||||
/* ========================================================================== */
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012 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 <sys/types.h>
|
||||
|
||||
#include "nand_part.h"
|
||||
#include "nand_nvram_platform.h"
|
||||
#include "nand_nvram_impl.h"
|
||||
#include "nand_nvram_dump.h"
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
static void
|
||||
dumpData(nand_nvram_t * nv, uint8_t * data)
|
||||
{
|
||||
const uint32_t bytes_per_row = 16;
|
||||
char alpha[bytes_per_row + 1];
|
||||
uint32_t col = 0;
|
||||
uint32_t idx;
|
||||
|
||||
nand_nvram_printf(nv->context, " <data>");
|
||||
nand_nvram_set_mem(nv->context, alpha, 0x00, bytes_per_row + 1);
|
||||
for (idx = 0; idx < nv->geo.bytes_per_page; idx++) {
|
||||
uint8_t byte = data[idx];
|
||||
col = (idx % bytes_per_row);
|
||||
if (0 == col) {
|
||||
if (0 != alpha[0]) {
|
||||
nand_nvram_printf(nv->context, " <!-- %s -->", alpha);
|
||||
nand_nvram_set_mem(nv->context, alpha, 0x00, bytes_per_row + 1);
|
||||
}
|
||||
nand_nvram_printf(nv->context, "\n ");
|
||||
}
|
||||
alpha[col] = ((0x20 <= byte) && (byte <= 0x7e)) ? (char) byte : '.';
|
||||
nand_nvram_printf(nv->context, "%02X ", byte);
|
||||
}
|
||||
if (0 != alpha[0]) {
|
||||
for (idx = 0; idx < (bytes_per_row - (col + 1)); idx++) {
|
||||
nand_nvram_printf(nv->context, " ");
|
||||
}
|
||||
nand_nvram_printf(nv->context, " <!-- %s -->", alpha);
|
||||
nand_nvram_set_mem(nv->context, alpha, 0x00, bytes_per_row + 1);
|
||||
}
|
||||
nand_nvram_printf(nv->context, "\n </data>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dumpMeta(nand_nvram_t * nv, meta_t * meta)
|
||||
{
|
||||
nand_nvram_printf(nv->context, " <meta_t>\n");
|
||||
nand_nvram_printf(nv->context, " <generation>0x%08X</generation>\n", meta->generation);
|
||||
nand_nvram_printf(nv->context, " <page_max>0x%02X</page_max>\n", meta->page_max);
|
||||
nand_nvram_printf(nv->context, " <page_idx>0x%02X</page_idx>\n", meta->page_idx);
|
||||
nand_nvram_printf(nv->context, " <version_major>0x%02X</version_major>\n", meta->version_major);
|
||||
nand_nvram_printf(nv->context, " <version_minor>0x%02X</version_minor>\n", meta->version_minor);
|
||||
nand_nvram_printf(nv->context, " <signature>0x%04X</signature>\n", meta->signature);
|
||||
nand_nvram_printf(nv->context, " </meta_t>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dumpPage(nand_nvram_t * nv, uint32_t bank, uint32_t block, uint32_t page, meta_t * meta, uint8_t * data)
|
||||
{
|
||||
uint32_t abs_page = page + (block * nv->geo.pages_per_block);
|
||||
|
||||
nand_nvram_printf(nv->context, " <page>\n");
|
||||
nand_nvram_printf(nv->context, " <bank_num>%d</bank_num>\n", bank);
|
||||
nand_nvram_printf(nv->context, " <block_num>%d</block_num>\n", block);
|
||||
nand_nvram_printf(nv->context, " <page_num>%d</page_num>\n", page);
|
||||
if (nand_nvram_read_page(nv->context, bank, abs_page, data, meta, NULL)) {
|
||||
NandPartTable *closing = (NandPartTable*)meta;
|
||||
if (kNAND_NVRAM_SIGNATURE == meta->signature) {
|
||||
nand_nvram_printf(nv->context, " <type>content</type>\n");
|
||||
dumpMeta(nv, meta);
|
||||
} else if (kNandPartHeaderMagic == closing->header.magic) {
|
||||
nand_nvram_printf(nv->context, " <type>closing</type>\n");
|
||||
} else {
|
||||
nand_nvram_printf(nv->context, " <type>unrecognized</type>\n");
|
||||
}
|
||||
dumpData(nv, data);
|
||||
} else {
|
||||
nand_nvram_printf(nv->context, " <type>unreadable</type>\n");
|
||||
}
|
||||
nand_nvram_printf(nv->context, " </page>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dumpBlock(nand_nvram_t * nv, uint32_t bank, uint32_t block, meta_t * meta, uint8_t * data)
|
||||
{
|
||||
uint32_t page;
|
||||
|
||||
nand_nvram_printf(nv->context, " <block>\n");
|
||||
nand_nvram_printf(nv->context, " <bank_num>%d</bank_num>\n", bank);
|
||||
nand_nvram_printf(nv->context, " <block_num>%d</block_num>\n", block);
|
||||
if (nand_nvram_is_block_bad(nv->context, bank, block)) {
|
||||
nand_nvram_printf(nv->context, " <bad/>\n");
|
||||
} else {
|
||||
for (page = 0; page < nv->geo.pages_per_block; page++)
|
||||
{
|
||||
dumpPage(nv, bank, block, page, meta, data);
|
||||
}
|
||||
}
|
||||
nand_nvram_printf(nv->context, " </block>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dumpBank(nand_nvram_t * nv, uint32_t bank, meta_t * meta, uint8_t * data)
|
||||
{
|
||||
uint32_t block;
|
||||
|
||||
nand_nvram_printf(nv->context, " <bank>\n");
|
||||
nand_nvram_printf(nv->context, " <bank_num>%d</bank_num>\n", bank);
|
||||
for (block = 0; block < nv->geo.blocks_per_bank; block++)
|
||||
{
|
||||
dumpBlock(nv, bank, block, meta, data);
|
||||
}
|
||||
nand_nvram_printf(nv->context, " </bank>\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dumpGeometry(nand_nvram_t * nv)
|
||||
{
|
||||
nand_nvram_printf(nv->context, " <nand_nvram_geometry_t>\n");
|
||||
nand_nvram_printf(nv->context, " <number_of_banks>%d</number_of_banks>\n", nv->geo.number_of_banks);
|
||||
nand_nvram_printf(nv->context, " <blocks_per_bank>%d</blocks_per_bank>\n", nv->geo.blocks_per_bank);
|
||||
nand_nvram_printf(nv->context, " <pages_per_block>%d</pages_per_block>\n", nv->geo.pages_per_block);
|
||||
nand_nvram_printf(nv->context, " <data_pages_per_block>%d</data_pages_per_block>\n", nv->geo.data_pages_per_block);
|
||||
nand_nvram_printf(nv->context, " <bytes_per_page>%d</bytes_per_page>\n", nv->geo.bytes_per_page);
|
||||
nand_nvram_printf(nv->context, " <bytes_per_meta_buffer>%d</bytes_per_meta_buffer>\n", nv->geo.bytes_per_meta_buffer);
|
||||
nand_nvram_printf(nv->context, " <bytes_per_meta_actual>%d</bytes_per_meta_actual>\n", nv->geo.bytes_per_meta_actual);
|
||||
nand_nvram_printf(nv->context, " </nand_nvram_geometry_t>\n");
|
||||
}
|
||||
|
||||
bool
|
||||
nand_nvram_dump(nand_nvram_t * nv)
|
||||
{
|
||||
bool ok = false;
|
||||
uint32_t bank;
|
||||
meta_t * meta = NULL;
|
||||
uint8_t * data = NULL;
|
||||
|
||||
if ((NULL != nv) &&
|
||||
(NULL != nv->context) &&
|
||||
(NULL != (meta = nand_nvram_alloc_mem(nv->context, nv->geo.bytes_per_meta_buffer))) &&
|
||||
(NULL != (data = nand_nvram_alloc_mem(nv->context, nv->geo.bytes_per_page)))) {
|
||||
|
||||
nand_nvram_printf(nv->context, "<nvram>\n");
|
||||
dumpGeometry(nv);
|
||||
for (bank = 0; bank < nv->geo.number_of_banks; bank++)
|
||||
{
|
||||
dumpBank(nv, bank, meta, data);
|
||||
}
|
||||
nand_nvram_printf(nv->context, "</nvram>\n");
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (NULL != meta) {
|
||||
nand_nvram_free_mem(nv->context, meta, nv->geo.bytes_per_meta_buffer);
|
||||
}
|
||||
if (NULL != data) {
|
||||
nand_nvram_free_mem(nv->context, data, nv->geo.bytes_per_page);
|
||||
}
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2009-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.
|
||||
*/
|
||||
|
||||
#ifndef _NAND_NVRAM_DUMP_H_
|
||||
#define _NAND_NVRAM_DUMP_H_
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
bool nand_nvram_dump(nand_nvram_t * nv);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif // _NAND_NVRAM_DUMP_H_
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2012 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.
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@header nand_nvram_impl
|
||||
|
||||
@abstract portable header info for nand nvram implementation use only
|
||||
|
||||
@discussion These declarations have been pulled out into an
|
||||
independent file so that diagnostic utilities and white box unit
|
||||
tests might take advantage of knowing implementation-specific
|
||||
details. Nevertheless, no client of the nand nvram driver nor its
|
||||
system-specific wrapper should ever need to reference this header.
|
||||
Any declarations that need that level of visibility are intended to
|
||||
be placed in "nand_nvram_core.h".
|
||||
|
||||
@copyright Apple Inc.
|
||||
|
||||
@updated 2012-02-21
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifndef _NAND_NVRAM_IMPL_H
|
||||
#define _NAND_NVRAM_IMPL_H
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@group public platform-independent type declarations
|
||||
*/
|
||||
|
||||
/*!
|
||||
@typedef nand_nvram_t
|
||||
|
||||
@abstract Opaque reference to structure needed by nand nvram implementation.
|
||||
*/
|
||||
typedef struct nand_nvram nand_nvram_t;
|
||||
|
||||
/*!
|
||||
@typedef nand_nvram_geometry_t
|
||||
|
||||
@abstract
|
||||
*/
|
||||
typedef struct nand_nvram_geometry nand_nvram_geometry_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@group private platform-independent type declarations
|
||||
*/
|
||||
|
||||
typedef struct _meta meta_t;
|
||||
typedef struct _blob blob_t;
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@group public platform-independent constant definitions
|
||||
*/
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_SIZE
|
||||
|
||||
@abstract Standard size of nvram presented by the driver. Note
|
||||
that, if this ends up changing in the future, this value should
|
||||
start being defined on a platform/product specific basis.
|
||||
*/
|
||||
#define kNAND_NVRAM_SIZE 8192
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_META_SIZE
|
||||
|
||||
@abstract Amount of bytes required by meta data for each nvram
|
||||
backing store page.
|
||||
*/
|
||||
#define kNAND_NVRAM_META_SIZE 10
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_PAGE_RESERVED_IN_BLOCK
|
||||
|
||||
@abstract Number of pages reserved for partition table in each
|
||||
NAND block.
|
||||
*/
|
||||
#define kNAND_NVRAM_PAGE_RESERVED_IN_BLOCK 2
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@group private platform-independent constant definitions
|
||||
*/
|
||||
|
||||
/*!
|
||||
@const NULL
|
||||
|
||||
@abstract It really sucks that some of our systems don't define NULL.
|
||||
*/
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_MAX_SIZE
|
||||
|
||||
@abstract Maximum amount of storage; should fit into a standard 2K page.
|
||||
*/
|
||||
#define kNAND_NVRAM_MAX_SIZE (128 * 2048)
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_SIGNATURE
|
||||
|
||||
@abstract Constant value used to identify nand nvram meta data.
|
||||
*/
|
||||
#define kNAND_NVRAM_SIGNATURE ((uint16_t) 0xBEAD)
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_VERSION_MAJOR
|
||||
|
||||
@abstract Major version of the driver that wrote the nvram content.
|
||||
Major version differences are considered to be incompatible. Even
|
||||
major version numbers are reserved for development purposes; odd
|
||||
version numbers should be used for when development is frozen,
|
||||
stabilized, and therefore only accepting minor revision level changes.
|
||||
*/
|
||||
#define kNAND_NVRAM_FEATURE_EXTRA_AREA_VERSION_MAJOR ((uint8_t) 0x0)
|
||||
#define kNAND_NVRAM_VERSION_MAJOR kNAND_NVRAM_FEATURE_EXTRA_AREA_VERSION_MAJOR
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_VERSION_MINOR
|
||||
|
||||
@abstract Minor version of the driver that wrote the nvram content.
|
||||
Minor versions should be fully compatible within a major version and
|
||||
are intended to be incremented when the driver has changed between
|
||||
public releases.
|
||||
*/
|
||||
#define kNAND_NVRAM_FEATURE_EXTRA_AREA_VERSION_MINOR ((uint8_t) 0x3)
|
||||
#define kNAND_NVRAM_VERSION_MINOR kNAND_NVRAM_FEATURE_EXTRA_AREA_VERSION_MINOR
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_GENERATION_ERASED
|
||||
|
||||
@abstract A generation number of all ones is reserved since it also
|
||||
corresponds to the erased state of nand bits.
|
||||
*/
|
||||
#define kNAND_NVRAM_GENERATION_ERASED ((uint32_t) 0xFFFFFFFF)
|
||||
|
||||
/*!
|
||||
@const kNAND_NVRAM_GENERATION_UNKNOWN
|
||||
|
||||
@abstract A generation number of all zeros is reserved since it
|
||||
corresponds to the state of an uninitialized meta struct.
|
||||
*/
|
||||
#define kNAND_NVRAM_GENERATION_UNKNOWN ((uint32_t) 0x00000000)
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@group public platform-independent structure declarations
|
||||
*/
|
||||
|
||||
/*!
|
||||
@struct nand_nvram_geometry
|
||||
|
||||
@abstract Geometry of nand device array slice.
|
||||
|
||||
@field number_of_banks Number of logical banks.
|
||||
|
||||
@field blocks_per_bank Number of blocks in each bank.
|
||||
|
||||
@field pages_per_block Number of pages per block.
|
||||
|
||||
@field data_pages_per_block Number of pages per block available for data storage.
|
||||
|
||||
@field bytes_per_page Size in bytes of page.
|
||||
|
||||
@field bytes_per_meta_buffer Size in bytes of buffer for in-memory per-page meta info.
|
||||
|
||||
@field bytes_per_meta_actual Size in bytes of in-storage per-page meta info (i.e. actual size).
|
||||
*/
|
||||
struct nand_nvram_geometry {
|
||||
|
||||
uint32_t number_of_banks;
|
||||
uint32_t blocks_per_bank;
|
||||
uint32_t pages_per_block;
|
||||
uint32_t data_pages_per_block;
|
||||
uint32_t bytes_per_page;
|
||||
uint32_t bytes_per_meta_buffer;
|
||||
uint32_t bytes_per_meta_actual;
|
||||
};
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@group private platform-independent structure declarations
|
||||
*/
|
||||
|
||||
/*!
|
||||
@struct _meta
|
||||
|
||||
@abstract Structure defining per-page meta layout.
|
||||
|
||||
@field generation Monotonically increasing generation of blob;
|
||||
kNAND_NVRAM_GENERATION_UNKNOWN and kNAND_NVRAM_GENERATION_ERASED are
|
||||
reserved values that should never appear on a nand device.
|
||||
|
||||
@field page_max Maximum page index for blob (i.e. page count - 1).
|
||||
|
||||
@field page_idx Page index of this meta within blob.
|
||||
|
||||
@field version_major Major version number of nand nvram driver.
|
||||
|
||||
@field version_minor Minor version number of nand nvram driver.
|
||||
|
||||
@field signature Constant value of kNAND_NVRAM_SIGNATURE marks valid
|
||||
nvram meta.
|
||||
*/
|
||||
struct _meta {
|
||||
|
||||
uint32_t generation;
|
||||
uint8_t page_max;
|
||||
uint8_t page_idx;
|
||||
uint8_t version_major;
|
||||
uint8_t version_minor;
|
||||
uint16_t signature;
|
||||
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/*!
|
||||
@struct _blob
|
||||
|
||||
@abstract Container for N pages of data and meta information
|
||||
for convenience of writing to/from nand devices.
|
||||
|
||||
@field pageCount Number of pages currently allocated to
|
||||
shadow the blob.
|
||||
|
||||
@field metaBufs Buffer containing pages' meta structs.
|
||||
|
||||
@field dataBufs Buffer containing pages' data.
|
||||
*/
|
||||
struct _blob {
|
||||
|
||||
void * meta_bufs;
|
||||
void * data_bufs;
|
||||
};
|
||||
|
||||
/*!
|
||||
@struct nand_nvram
|
||||
|
||||
@abstract NAND-based nvram driver context information.
|
||||
|
||||
@field geometry Geometry of nand device array slice used for
|
||||
backing store.
|
||||
|
||||
@field is_dirty Flag indicating whether shadow has been
|
||||
modified since last restore or sync.
|
||||
|
||||
@field shadow Blob used as container for pages of data and meta
|
||||
information being shadowed from nand.
|
||||
|
||||
@field cursors Array of page numbers of next page in each
|
||||
bank available for commit.
|
||||
*/
|
||||
struct nand_nvram {
|
||||
|
||||
nand_nvram_geometry_t geo;
|
||||
void * context;
|
||||
uint32_t size;
|
||||
bool is_born;
|
||||
bool is_dirty;
|
||||
uint32_t * watermarks;
|
||||
uint32_t * cursors;
|
||||
bool * copies;
|
||||
blob_t * shadow;
|
||||
};
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* ! _NAND_NVRAM_IMPL_H */
|
||||
|
||||
/* ========================================================================== */
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2008-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.
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
/*!
|
||||
@header nand_nvram_platform
|
||||
|
||||
@abstract iBoot platform-specific macros needed by nand nvram
|
||||
|
||||
@copyright Apple Inc.
|
||||
|
||||
@updated 2011-05-18
|
||||
*/
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifndef _NAND_NVRAM_PLATFORM_H
|
||||
#define _NAND_NVRAM_PLATFORM_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <lib/heap.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#define nand_nvram_alloc_mem(context, size) memalign((size), CPU_CACHELINE_SIZE)
|
||||
|
||||
#define nand_nvram_compare_mem(context, left, right, size) memcmp((left), (right), (size))
|
||||
|
||||
#define nand_nvram_copy_mem(context, dest, src, size) memcpy((dest), (src), (size))
|
||||
|
||||
#define nand_nvram_set_mem(context, mem, value, size) memset((mem), (value), (size))
|
||||
|
||||
#define nand_nvram_free_mem(context, mem, size) free((mem))
|
||||
|
||||
#define nand_nvram_printf(context, ...) dprintf(DEBUG_CRITICAL, __VA_ARGS__)
|
||||
|
||||
#define nand_nvram_is_block_bad(context, bank, block) flash_nand_nvram_is_block_bad((context), (bank), (block))
|
||||
|
||||
#define nand_nvram_read_page(context, bank, page, data, meta, is_clean) flash_nand_nvram_read_page((context), (bank), (page), (data), (meta), (is_clean))
|
||||
|
||||
#define nand_nvram_write_page(context, bank, page, data, meta) flash_nand_nvram_write_page((context), (bank), (page), (data), (meta))
|
||||
|
||||
#define nand_nvram_erase_block(context, bank, block) flash_nand_nvram_erase_block((context), (bank), (block))
|
||||
|
||||
#define nand_nvram_request_ptab_diff(context, data, size) flash_nand_nvram_request_ptab_diff((context), (data), (size))
|
||||
|
||||
#define nand_nvram_provide_ptab_diff(context, data, size) flash_nand_nvram_provide_ptab_diff((context), (data), (size))
|
||||
|
||||
#define nand_nvram_copy_ptab(context, buf) flash_nand_nvram_copy_ptab((context), (buf))
|
||||
|
||||
#define nand_nvram_read_ptab(context, bank, page, buf) flash_nand_nvram_read_ptab((context), (bank), (page), (buf))
|
||||
|
||||
#define nand_nvram_write_ptab(context, bank, page, buf) flash_nand_nvram_write_ptab((context), (bank), (page), (buf))
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
bool flash_nand_nvram_is_block_bad(void * context, uint32_t bank, uint32_t block);
|
||||
bool flash_nand_nvram_read_page(void * context, uint32_t bank, uint32_t page, void * data, void * meta, bool * is_clean);
|
||||
bool flash_nand_nvram_write_page(void * context, uint32_t bank, uint32_t page, void * data, void * meta);
|
||||
bool flash_nand_nvram_erase_block(void * context, uint32_t bank, uint32_t block);
|
||||
bool flash_nand_nvram_request_ptab_diff(void * context, void * data, uint32_t size);
|
||||
bool flash_nand_nvram_provide_ptab_diff(void * context, void * data, uint32_t size);
|
||||
bool flash_nand_nvram_copy_ptab(void * context, void * buf);
|
||||
bool flash_nand_nvram_read_ptab(void * context, uint32_t bank, uint32_t page, void * buf);
|
||||
bool flash_nand_nvram_write_ptab(void * context, uint32_t bank, uint32_t page, void * buf);
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _NAND_NVRAM_PLATFORM_H */
|
||||
|
||||
/* ========================================================================== */
|
||||
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += \
|
||||
WITH_NAND_NVRAM=1
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/nand_nvram.o \
|
||||
$(LOCAL_DIR)/nand_nvram_core.o \
|
||||
$(LOCAL_DIR)/nand_nvram_dump.o
|
||||
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# Copyright (c) 2008-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.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += \
|
||||
WITH_NAND_BOOT=1
|
||||
|
||||
GLOBAL_INCLUDES += \
|
||||
$(LOCAL_DIR)
|
||||
|
||||
MODULES += \
|
||||
lib/effaceable/iboot/nand
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/nand_export.o \
|
||||
$(LOCAL_DIR)/nand_part_core.o \
|
||||
$(LOCAL_DIR)/nand_boot.o
|
||||
|
||||
ifeq ($(PRODUCT),LLB)
|
||||
OPTIONS += \
|
||||
WITH_NAND_PART_BUILD_TINY=1
|
||||
endif
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2012 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 WITH_SYSCFG
|
||||
|
||||
// XXX include list is bloated; trim it down
|
||||
|
||||
#include <arch/arm/arm.h>
|
||||
#include <debug.h>
|
||||
#include <lib/heap.h>
|
||||
#include <lib/blockdev.h>
|
||||
#include <lib/partition.h>
|
||||
#include <lib/syscfg.h>
|
||||
#include <AssertMacros.h>
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "ANDTypes.h"
|
||||
#if WITH_RAW_NAND
|
||||
#include "WMRExam.h"
|
||||
#endif // WITH_RAW_NAND
|
||||
#include "WMROAM.h"
|
||||
#include "FIL.h"
|
||||
|
||||
#include "nand_part.h"
|
||||
#include "nand_part_interface.h"
|
||||
#include "nand_export.h"
|
||||
|
||||
// Ugly, ugly, ugly!
|
||||
extern uint32_t nand_fsys_block_offset;
|
||||
|
||||
#if WITH_PPN_SYSCFG
|
||||
extern int ppn_syscfg_init(void);
|
||||
extern int ppn_read_syscfg_hook(struct blockdev *_dev, void *ptr, block_addr block, uint32_t count);
|
||||
#endif //WITH_PPN_SYSCFG
|
||||
|
||||
// The syscfg library assumes that syscfg will be 0x4000 bytes into
|
||||
// the device regardles of whether it's NAND or NOR. nand1 will ONLY
|
||||
// expose syscfg, so this doesn't make any sense, but we'll say we're
|
||||
// big enough to read that far in anyway.
|
||||
#define kSysCfgActualSize ( 0x4000 )
|
||||
#define kFakeBdevBlockSize (kSysCfgBdevOffset)
|
||||
#define kFakeBdevCapacity (kSysCfgBdevOffset + kSysCfgActualSize)
|
||||
|
||||
|
||||
#if WITH_RAW_NAND
|
||||
|
||||
static int nand_read_syscfg_hook(struct blockdev *_dev, void *ptr, block_addr block, uint32_t count)
|
||||
{
|
||||
bool ok = true;
|
||||
BOOL32 result;
|
||||
|
||||
// Only allow reading the "second" block
|
||||
if ((block != 1) || (count != 1)) {
|
||||
dprintf(DEBUG_CRITICAL, "attempted to read nand syscfg at non-zero offset\n");
|
||||
ok = false;
|
||||
|
||||
} else if (count > 0) {
|
||||
|
||||
result = WMR_GetFPart()->ReadDeviceUniqueInfo(ptr, kFakeBdevBlockSize);
|
||||
if (!result) {
|
||||
|
||||
dprintf(DEBUG_CRITICAL, "nand_read_block_hook: failure reading syscfg\n");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
return -1;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif // WITH_RAW_NAND
|
||||
|
||||
int nand_syscfg_init(NandPartInterface * npi)
|
||||
{
|
||||
int err = 0;
|
||||
struct blockdev *nand_syscfg;
|
||||
bool is_ppn;
|
||||
|
||||
dprintf(DEBUG_INFO, "nand_syscfg_init()\n");
|
||||
|
||||
is_ppn = FIL_GetFuncTbl()->GetDeviceInfo(AND_DEVINFO_PPN_DEVICE);
|
||||
|
||||
nand_syscfg = malloc(sizeof(struct blockdev));
|
||||
#if WITH_PPN_SYSCFG
|
||||
if (is_ppn) {
|
||||
if (0 == ppn_syscfg_init()) {
|
||||
construct_blockdev(nand_syscfg, "nand_syscfg", kFakeBdevCapacity, kFakeBdevBlockSize);
|
||||
nand_syscfg->read_block_hook = &ppn_read_syscfg_hook;
|
||||
register_blockdev(nand_syscfg);
|
||||
syscfgInitWithBdev("nand_syscfg");
|
||||
} else {
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
#else //WITH_PPN_SYSCFG
|
||||
check(!is_ppn);
|
||||
#endif //WITH_PPN_SYSCFG
|
||||
|
||||
#if WITH_RAW_NAND
|
||||
if (!is_ppn) {
|
||||
if (WMR_SUCCESS == WMR_PreInit(gWhimoryInitParameters, nand_fsys_block_offset)) {
|
||||
construct_blockdev(nand_syscfg, "nand_syscfg", kFakeBdevCapacity, kFakeBdevBlockSize);
|
||||
nand_syscfg->read_block_hook = &nand_read_syscfg_hook;
|
||||
register_blockdev(nand_syscfg);
|
||||
syscfgInitWithBdev("nand_syscfg");
|
||||
} else {
|
||||
err = -1;
|
||||
}
|
||||
}
|
||||
#else // WITH_RAW_NAND
|
||||
check(is_ppn);
|
||||
#endif // WITH_RAW_NAND
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif /* WITH_SYSCFG */
|
||||
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += \
|
||||
WITH_NAND_SYSCFG=1
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/nand_syscfg.o
|
||||
Reference in new issue
Block a user