first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1 @@
|
||||
// Empty file
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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.
|
||||
*/
|
||||
|
||||
/////
|
||||
//
|
||||
// Whimory Feature Definitions
|
||||
//
|
||||
/////
|
||||
|
||||
#include "WMRTypes.h"
|
||||
|
||||
#ifndef _WMR_FEATURES_H_
|
||||
#define _WMR_FEATURES_H_
|
||||
|
||||
// Define the platform we're on
|
||||
#define WMR_BUILDING_IBOOT (1)
|
||||
|
||||
// Don't bother collect stats in read-only mode
|
||||
//#define AND_COLLECT_STATISTICS (1)
|
||||
|
||||
// Defined by platform, but they're all OK with 30 for now
|
||||
#define FIL_MAX_ECC_CORRECTION (30)
|
||||
|
||||
// =============================================================================
|
||||
// configurable preprocessor compilation control
|
||||
// =============================================================================
|
||||
|
||||
// Set H2FMI_DEBUG below to 1 if you want to build for debugging (default
|
||||
// to 0).
|
||||
#define H2FMI_DEBUG 1
|
||||
|
||||
// Set H2FMI_TEST_HOOK below to 1 if you want to insert tests at the end
|
||||
// of FIL_Init in iBoot (default to 0).
|
||||
#define H2FMI_TEST_HOOK 0
|
||||
|
||||
// Set H2FMI_WAIT_USING_ISR to true if you want operations to wait for
|
||||
// dma and bus events by hooking an interrupt service routine to the
|
||||
// FMI interrupt vector; set to false for waiting using register
|
||||
// polling with yield (default to true).
|
||||
#define H2FMI_WAIT_USING_ISR 1
|
||||
|
||||
#define H2FMI_INSTRUMENT_BUS_1 0
|
||||
|
||||
// Change the constant below to 1 if you want to see all FMI
|
||||
// subsystem register writes; note that doing so is likely to change
|
||||
// timing and therefore behavior, so it should be a rare case that you
|
||||
// would ever want to do this. In cases where you want to see just
|
||||
// one or two writes, consider calling the 'h2fmi_dbg_wr' or
|
||||
// 'h2fmi_dbg_wr8' function directly (default to 0).
|
||||
#define H2FMI_TRACE_REG_WRITES 0
|
||||
|
||||
// Change the constant below to 1 if you want to see all FMI
|
||||
// subsystem register reads; note that doing so is likely to change
|
||||
// timing and therefore behavior, so it should be a rare case that you
|
||||
// would ever want to do this. In cases where you want to see just
|
||||
// one or two reads, consider calling the 'h2fmi_dbg_rd' or
|
||||
// 'h2fmi_dbg_rd8' function directly (default to 0).
|
||||
#define H2FMI_TRACE_REG_READS 0
|
||||
|
||||
// =============================================================================
|
||||
// fixed preprocessor compilation control
|
||||
// =============================================================================
|
||||
|
||||
#define H2FMI_BOOTROM 0
|
||||
#define H2FMI_IOP 1
|
||||
#define H2FMI_IBOOT 0
|
||||
#define H2FMI_EFI 0
|
||||
|
||||
#define H2FMI_READONLY 0
|
||||
#endif /* _WMR_FEATURES_H_ */
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
#include "WMRConfig.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <lib/heap.h>
|
||||
#include <sys.h>
|
||||
#include <sys/task.h>
|
||||
#include <platform.h>
|
||||
#include <platform/soc/hwclocks.h>
|
||||
#include <platform/timer.h>
|
||||
|
||||
void *
|
||||
WMR_MALLOC(UInt32 nSize)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = memalign(nSize, CPU_CACHELINE_SIZE);
|
||||
WMR_MEMSET(p, 0, nSize);
|
||||
return p;
|
||||
}
|
||||
|
||||
BOOL32
|
||||
OAM_Init(void)
|
||||
{
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
void OAM_Beep(UInt32 dwMs)
|
||||
{
|
||||
}
|
||||
|
||||
void WMR_FREE(void * ptr, UInt32 size)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
BOOL32 WMR_CHECK_BUFFER(const void * buffer, UInt32 length)
|
||||
{
|
||||
return (((UInt32) buffer % CPU_CACHELINE_SIZE) == 0) ? TRUE32 : FALSE32;
|
||||
}
|
||||
|
||||
BOOL32
|
||||
WMR_FILL_STRUCT(void *pDstBuff, UInt32 *pdwDstBuffSize, const void *pSrcBuff, UInt32 dwSrcBuffSize)
|
||||
{
|
||||
BOOL32 boolRes = TRUE32;
|
||||
|
||||
if (!pDstBuff && pdwDstBuffSize)
|
||||
{
|
||||
// Just return the buffer size
|
||||
*pdwDstBuffSize = dwSrcBuffSize;
|
||||
}
|
||||
else if (!pdwDstBuffSize || (*pdwDstBuffSize < dwSrcBuffSize))
|
||||
{
|
||||
// Supplied buffer is too small
|
||||
UInt32 dwPrintedSize = pdwDstBuffSize ? *pdwDstBuffSize : (UInt32) ~0;
|
||||
WMR_PRINT(ERROR,"IOCtl on buffer of size %d with %d bytes of src data!\n",
|
||||
dwPrintedSize, dwSrcBuffSize);
|
||||
boolRes = FALSE32;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a valid buffer pointer and buffer size
|
||||
WMR_MEMCPY(pDstBuff, pSrcBuff, dwSrcBuffSize);
|
||||
*pdwDstBuffSize = dwSrcBuffSize;
|
||||
}
|
||||
|
||||
return boolRes;
|
||||
}
|
||||
|
||||
void _WMR_PRINT(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
// retrieve the variable arguments
|
||||
va_start(args, format);
|
||||
|
||||
vprintf(format, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
WMR_BEEP(UInt32 milliseconds)
|
||||
{
|
||||
printf("WMR_BEEP\n");
|
||||
}
|
||||
|
||||
const char * WMR_GETVERSION(void)
|
||||
{
|
||||
static char version[] = "version string";
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
BOOL32
|
||||
WMR_I_CAN_HAZ_DEBUGGER(void)
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
void WMR_WAIT_US(UInt64 microseconds)
|
||||
{
|
||||
spin(microseconds);
|
||||
}
|
||||
|
||||
void WMR_SLEEP_US(UInt32 microseconds)
|
||||
{
|
||||
task_sleep(microseconds);
|
||||
}
|
||||
|
||||
void WMR_YIELD(void)
|
||||
{
|
||||
// Task yield is not available to libraries, so can't build it into Whimory
|
||||
task_yield();
|
||||
}
|
||||
|
||||
void
|
||||
WMR_DEADLOOP(void)
|
||||
{
|
||||
volatile int i = 1;
|
||||
while (i)
|
||||
{
|
||||
(void) 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WMR_CLOCK_RESET_DEVICE(UInt32 device)
|
||||
{
|
||||
int clock;
|
||||
|
||||
if( device == 0 )
|
||||
{
|
||||
clock = CLK_FMI0;
|
||||
}
|
||||
else if( device == 1 )
|
||||
{
|
||||
clock = CLK_FMI1;
|
||||
}
|
||||
else
|
||||
{
|
||||
panic("invalid WMR_CLOCK_RESET_DEVICE");
|
||||
}
|
||||
|
||||
clock_reset_device(clock);
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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 "ANDTypes.h"
|
||||
#include "WMRFeatures.h"
|
||||
|
||||
#include <string.h> // memcmp
|
||||
#include <sys.h> // panic
|
||||
#include <platform.h> // cache
|
||||
#include <platform/timer.h> // ticks
|
||||
|
||||
#ifndef _WMR_PLATFORM_H_
|
||||
#define _WMR_PLATFORM_H_
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_LOG2
|
||||
//
|
||||
// Returns the floor(log2) of the given number
|
||||
//
|
||||
#define WMR_LOG2(x) (31UL - __builtin_clz((UInt32)(x)))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_MEMSET
|
||||
// WMR_MEMCPY
|
||||
// WMR_MEMCMP
|
||||
//
|
||||
// Standard memory operations (libraries where available)
|
||||
//
|
||||
|
||||
#define WMR_MEMSET(dest, pattern, length) memset((dest), (pattern), (length))
|
||||
#define WMR_MEMCPY(dest, src, length) memcpy((dest), (src), (length))
|
||||
#define WMR_MEMCMP(buf1, buf2, length) memcmp((buf1), (buf2), (length))
|
||||
#define WMR_STRLEN(str) strlen((str))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_ASSERT
|
||||
//
|
||||
// Print an error and panic if the given condition is not true
|
||||
//
|
||||
|
||||
# define WMR_ASSERT(_expr) \
|
||||
do { \
|
||||
if (__builtin_expect(!(_expr), 0)) \
|
||||
panic("WMR_ASSERT failed:(%s) %s:%u", \
|
||||
#_expr, __FILE__, __LINE__); \
|
||||
} while(0);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_PANIC
|
||||
//
|
||||
// Reset the system
|
||||
//
|
||||
# define WMR_PANIC(fmt, ...) \
|
||||
panic("WMR_PANIC: " #fmt " %s:%u", \
|
||||
## __VA_ARGS__, __FILE__, __LINE__)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_PREPARE_WRITE_BUFFER
|
||||
//
|
||||
// Call before an outgoing I/O operation to ensure cache coherency
|
||||
//
|
||||
|
||||
#define WRITE_PREP_CACHE_CMD (CACHE_CLEAN)
|
||||
|
||||
#if (defined(WMR_USE_FULL_CACHE_FLUSH) && WMR_USE_FULL_CACHE_FLUSH)
|
||||
#define WMR_PREPARE_WRITE_BUFFER(buf, length) \
|
||||
platform_cache_operation(WRITE_PREP_CACHE_CMD, 0, 0)
|
||||
#else //WMR_USE_FULL_CACHE_FLUSH
|
||||
#if WMR_DEBUG
|
||||
#define WMR_PREPARE_WRITE_BUFFER(buf, length) \
|
||||
do{ \
|
||||
WMR_ASSERT(0 == ((UInt32)(buf) % CPU_CACHELINE_SIZE)); \
|
||||
platform_cache_operation(WRITE_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE));\
|
||||
}while(0)
|
||||
#else
|
||||
#define WMR_PREPARE_WRITE_BUFFER(buf, length) \
|
||||
platform_cache_operation(WRITE_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE))
|
||||
#endif// !WMR_DEBUG
|
||||
#endif // !WMR_USE_FULL_CACHE_FLUSH
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_PREPARE_READ_BUFFER
|
||||
//
|
||||
// Call before an incoming I/O operation to ensure cache coherency
|
||||
//
|
||||
// Note: On the IOP, we only prepare aligned read buffers from the host, so we
|
||||
// shouldn't have to actually clean any dirty lines
|
||||
#define READ_PREP_CACHE_CMD (CACHE_CLEAN | CACHE_INVALIDATE)
|
||||
|
||||
#if (defined(WMR_USE_FULL_CACHE_FLUSH) && WMR_USE_FULL_CACHE_FLUSH)
|
||||
#define WMR_PREPARE_READ_BUFFER(buf, length) \
|
||||
platform_cache_operation(READ_PREP_CACHE_CMD, 0, 0)
|
||||
#else //WMR_USE_FULL_CACHE_FLUSH
|
||||
#if WMR_DEBUG
|
||||
#define WMR_PREPARE_READ_BUFFER(buf, length) \
|
||||
do{ \
|
||||
WMR_ASSERT(0 == ((UInt32)(buf) % CPU_CACHELINE_SIZE)); \
|
||||
platform_cache_operation(READ_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE));\
|
||||
}while(0)
|
||||
#else
|
||||
#define WMR_PREPARE_READ_BUFFER(buf, length) \
|
||||
platform_cache_operation(READ_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE))
|
||||
#endif// !WMR_DEBUG
|
||||
#endif // !WMR_USE_FULL_CACHE_FLUSH
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_COMPLETE_READ_BUFFER
|
||||
//
|
||||
// Call after an incoming I/O operation to ensure cache coherency
|
||||
//
|
||||
// Note: On the IOP, we only prepare aligned read buffers from the host, so we
|
||||
// shouldn't have to actually clean any dirty lines
|
||||
#define WMR_COMPLETE_READ_BUFFER(buf, length) \
|
||||
WMR_PREPARE_READ_BUFFER(buf, length)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_GET_TICKS_PER_US
|
||||
//
|
||||
// Return the number of native ticks (as returned from WMR_CLOCK_NATIVE) per
|
||||
// microsecond.
|
||||
//
|
||||
|
||||
// UInt32
|
||||
#define WMR_GET_TICKS_PER_US() (timer_get_tick_rate() / 1000000UL)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CLOCK_NATIVE
|
||||
//
|
||||
// Get the current system time in microseconds to be passed to
|
||||
// WMR_HAS_TIME_ELAPSED_US and WMR_HAS_TIME_ELAPSED_MS, but NOT
|
||||
// WMR_HAS_TIME_ELAPSED_TICKS
|
||||
//
|
||||
|
||||
// UInt64
|
||||
#define WMR_CLOCK_NATIVE() system_time()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CLOCK_TICKS
|
||||
//
|
||||
// Get the current system time in ticks (suitable for WMR_HAS_TIME_ELAPSED_TICKS)
|
||||
//
|
||||
|
||||
//UInt64
|
||||
#define WMR_CLOCK_TICKS() timer_get_ticks()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_HAS_TIME_ELAPSED_US
|
||||
//
|
||||
// Supply a start timestamp from WMR_CLOCK_NATIVE to determine if the given
|
||||
// time has elapsed
|
||||
//
|
||||
|
||||
//UInt64 startTicks, UInt64 elapsedUS
|
||||
#define WMR_HAS_TIME_ELAPSED_US(startTicks, elapsedUS) \
|
||||
(time_has_elapsed((startTicks), (elapsedUS)) ? TRUE32 : FALSE32)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_HAS_TIME_ELAPSED_TICKS
|
||||
//
|
||||
// Supply a start timestamp from WMR_CLOCK_NATIVE to determine if the given
|
||||
// time has elapsed.
|
||||
|
||||
//UInt64 startTicks, UInt64 elapsedTicks
|
||||
#define WMR_HAS_TIME_ELAPSED_TICKS(startTicks, elapsedTicks) \
|
||||
((timer_get_ticks() - (startTicks)) > (elapsedTicks) ? TRUE32 : FALSE32)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_ENTER_CRITICAL_SECTION
|
||||
//
|
||||
// Disable pre-emption, reference counted (safe to call in interrupt)
|
||||
|
||||
#define WMR_ENTER_CRITICAL_SECTION() enter_critical_section()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_EXIT_CRITICAL_SECTION
|
||||
//
|
||||
// Enable pre-emption, reference counted (safe to call in interrupt)
|
||||
|
||||
#define WMR_EXIT_CRITICAL_SECTION() exit_critical_section()
|
||||
|
||||
#endif /* _WMR_PLATFORM_H_ */
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef _WMR_TYPES_H_
|
||||
#define _WMR_TYPES_H_
|
||||
|
||||
# include <sys/types.h>
|
||||
# include "spTypes.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Basic Types */
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef UInt32 BOOL32;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Basic Constants */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define FALSE32 ((BOOL32)0)
|
||||
#define TRUE32 ((BOOL32)1)
|
||||
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# define __align(_x)
|
||||
/*****************************************************************************/
|
||||
/* Basic Compiler Flags */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define INLINE __inline
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
#define WMR_DEBUG (1)
|
||||
#else
|
||||
#define WMR_RELEASE (1)
|
||||
#endif
|
||||
|
||||
#endif /* _WMR_TYPES_H_ */
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef __WMR_BUF_H__
|
||||
#define __WMR_BUF_H__
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#include "WMRTypes.h"
|
||||
#include "WMRBufTypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
// Variables
|
||||
extern WMR_BufZoneList_t WMR_BufZoneList;
|
||||
|
||||
|
||||
// Functions
|
||||
extern void WMR_Buf_Init(void); // module-level initialization
|
||||
|
||||
extern void *WMR_Buf_Alloc(WMR_BufZone_t *zone, UInt32 size);
|
||||
extern void *WMR_Buf_Alloc_ForDMA(WMR_BufZone_t *zone, UInt32 size);
|
||||
|
||||
extern void WMR_BufZone_Init(WMR_BufZone_t *zone);
|
||||
extern BOOL32 WMR_BufZone_FinishedAllocs(WMR_BufZone_t *zone);
|
||||
extern void WMR_BufZone_Rebase(WMR_BufZone_t *zone, void** buf);
|
||||
extern void WMR_BufZone_FinishedRebases(WMR_BufZone_t *zone);
|
||||
extern void WMR_BufZone_Free(WMR_BufZone_t *zone);
|
||||
extern UInt32 WMR_BufZone_FindDescriptor(UInt8* buf, void **des); // returns offset
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // __WMR_BUF_H__
|
||||
@@ -0,0 +1,329 @@
|
||||
/////
|
||||
//
|
||||
// OS Adaptation Module API
|
||||
//
|
||||
/////
|
||||
#include "ANDTypes.h"
|
||||
#include "WMRFeatures.h"
|
||||
#include "WMRPlatform.h"
|
||||
|
||||
#ifndef _WMR_OAM_H_
|
||||
#define _WMR_OAM_H_
|
||||
|
||||
#define NUMELEMENTS(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define ROUNDDOWNTO(num, gran) ((num) - ((num) % (gran)))
|
||||
#define ROUNDUPTO(num, gran) ((((num) + (gran) - 1) / (gran)) * (gran))
|
||||
#define IS_ALIGNED_TO(addr, align) (((UInt32)(addr)) % (align) == 0)
|
||||
#define IS_ADDRESS_IN_RANGE(addr, start, end) \
|
||||
(((addr) >= (start) && (addr) < (end)) ? TRUE32 : FALSE32)
|
||||
|
||||
#define WMR_MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#define WMR_MAX(x, y) (((x) < (y)) ? (y) : (x))
|
||||
|
||||
#define WMR_CASSERT(x, name) typedef char __WMR_CASSERT_##name[(x) ? 1 : -1]
|
||||
#define WMR_OFFSETOF(type, field) ((size_t)(&((type *)0)->field))
|
||||
|
||||
// Print levels
|
||||
// Use only the last word in a WMR_PRINT call (e.g. ALWAYS for WMR_PRINT_ALWAYS)
|
||||
#define WMR_PRINT_ALWAYS (1UL << 0)
|
||||
|
||||
#define WMR_PRINT_INIT (1UL << 1)
|
||||
#define WMR_PRINT_IRQ (1UL << 2)
|
||||
#define WMR_PRINT_CLOCK (1UL << 3)
|
||||
#define WMR_PRINT_POWER (1UL << 4)
|
||||
#define WMR_PRINT_ALIGN (1UL << 5)
|
||||
#define WMR_PRINT_BUFFER (1UL << 6)
|
||||
#define WMR_PRINT_FACTORY (1UL << 7)
|
||||
#define WMR_PRINT_QUAL (1UL << 8)
|
||||
// WMR_PRINT_QUAL_FATAL allows simulator panics
|
||||
#define WMR_PRINT_QUAL_FATAL (WMR_PRINT_QUAL | WMR_PRINT_ERROR)
|
||||
|
||||
#define WMR_PRINT_READ (1UL << 10)
|
||||
#define WMR_PRINT_WRITE (1UL << 11)
|
||||
#define WMR_PRINT_ERASE (1UL << 12)
|
||||
#define WMR_PRINT_UECC_PANIC (1UL << 13)
|
||||
|
||||
#define WMR_PRINT_FTL (1UL << 20)
|
||||
#define WMR_PRINT_VFL (1UL << 21)
|
||||
#define WMR_PRINT_FIL (1UL << 22)
|
||||
#define WMR_PRINT_FTLWARN (1UL << 23)
|
||||
#define WMR_PRINT_VFLWARN (1UL << 24)
|
||||
#define WMR_PRINT_EXAM (1UL << 25)
|
||||
|
||||
#define WMR_PRINT_CRYPTO (1UL << 27)
|
||||
|
||||
#define WMR_PRINT_INF (1UL << 28)
|
||||
#define WMR_PRINT_LOG (1UL << 29)
|
||||
#define WMR_PRINT_MISC (1UL << 30)
|
||||
#define WMR_PRINT_ERROR (1UL << 31)
|
||||
|
||||
#define WMR_PRINT_LEVEL (WMR_PRINT_ALWAYS | WMR_PRINT_INIT | WMR_PRINT_ERROR | WMR_PRINT_FACTORY | WMR_PRINT_QUAL | WMR_PRINT_VFLWARN)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// OAM_Init
|
||||
//
|
||||
// Call *once* before any use of WMR or OAM functions
|
||||
//
|
||||
BOOL32 OAM_Init(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// gWhimoryInitParameters
|
||||
//
|
||||
// Bitmask of initialization parameters to WMR_Init()
|
||||
//
|
||||
extern UInt32 gWhimoryInitParameters;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_SCM_VERSION
|
||||
//
|
||||
// Get the SCM changelist of this build
|
||||
//
|
||||
UInt32 WMR_SCM_VERSION(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_BUILD_NUMBER
|
||||
//
|
||||
// Get the build number of this build
|
||||
//
|
||||
UInt32 WMR_BUILD_NUMBER(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_PRINT
|
||||
//
|
||||
// Use WMR_PRINT_XXX defines to describe your print type
|
||||
//
|
||||
#define TEXT(x) x
|
||||
|
||||
#if (defined (WMR_DEBUG) && WMR_DEBUG)
|
||||
#define WMR_DBG_PRINT(x) { _WMR_PRINT x; }
|
||||
#define WMR_RTL_PRINT(x) { _WMR_PRINT x; }
|
||||
#else
|
||||
#define WMR_DBG_PRINT(x)
|
||||
#define WMR_RTL_PRINT(x) { _WMR_PRINT x; }
|
||||
#endif
|
||||
|
||||
#if (defined(CC_NO_VA_ARGS) && !CC_NO_VA_ARGS)
|
||||
#define WMR_PRINT(type, format, ...) \
|
||||
do { \
|
||||
if (WMR_PRINT_ ## type & WMR_PRINT_LEVEL) { \
|
||||
_WMR_PRINT("[NAND] %s:%d " format "", __FUNCTION__, __LINE__, __VA_ARGS__); } \
|
||||
} while (0)
|
||||
#else //CC_NO_VA_ARGS
|
||||
#define WMR_PRINT(type, format, args ...) \
|
||||
do { \
|
||||
if (WMR_PRINT_ ## type & WMR_PRINT_LEVEL) { \
|
||||
_WMR_PRINT("[NAND] %s:%d " format "", __FUNCTION__, __LINE__, ## args); } \
|
||||
} while (0)
|
||||
#endif //CC_NO_VA_ARGS
|
||||
|
||||
void _WMR_PRINT(const char * format, ...);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_MALLOC
|
||||
//
|
||||
// Allocate a WMR internal buffer (cache aligned & padded)
|
||||
//
|
||||
void *WMR_MALLOC(UInt32 size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_FREE
|
||||
//
|
||||
// Release internal buffer
|
||||
//
|
||||
void WMR_FREE(void * ptr, UInt32 size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_BOOT_MALLOC
|
||||
//
|
||||
// Allocate up to one boot-time-only buffer that will be freed with
|
||||
// WMR_BOOT_FREE() before the NAND driver finishes opening
|
||||
//
|
||||
// The size argument is required. The incoming integer value is the minimum
|
||||
// required size. The outgoing value is the actual size of the buffer.
|
||||
//
|
||||
void *WMR_BOOT_MALLOC(UInt32 *size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_BOOT_FREE
|
||||
//
|
||||
// Free the buffer allocated by WMR_BOOT_MALLOC()
|
||||
//
|
||||
void WMR_BOOT_FREE(void * ptr);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CHECK_BUFFER
|
||||
//
|
||||
// Check if a given buffer is same for I/O DMA
|
||||
//
|
||||
BOOL32 WMR_CHECK_BUFFER(const void * buffer, UInt32 length);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_FILL_STRUCT
|
||||
//
|
||||
// Safely fill an ioctl buffer. Returns false if dest buffer size is too small
|
||||
// or unspecified
|
||||
//
|
||||
BOOL32 WMR_FILL_STRUCT(void *pDstBuff, UInt32 *pdwDstBuffSize, const void *pSrcBuff, UInt32 dwSrcBuffSize);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_GETVERSION
|
||||
//
|
||||
// gets version string (will be used for signature
|
||||
//
|
||||
const char * WMR_GETVERSION(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_I_CAN_HAZ_DEBUGGER
|
||||
//
|
||||
// indictes whether a unit is capable of being debugged
|
||||
//
|
||||
BOOL32 WMR_I_CAN_HAZ_DEBUGGER(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_BEEP
|
||||
//
|
||||
// Use a piezo sound (if available) to alert the user to an error
|
||||
//
|
||||
void WMR_BEEP(UInt32 milliseconds);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_DEADLOOP
|
||||
//
|
||||
// Alert the user that the system has stopped and deadloop
|
||||
//
|
||||
//
|
||||
void WMR_DEADLOOP(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CHKSUM
|
||||
//
|
||||
// Calculate a checksum on the given buffer
|
||||
//
|
||||
UInt32 WMR_CHKSUM(const void * buf, UInt32 length);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_WAIT_US
|
||||
//
|
||||
// Wait the given number of microseconds (may spin or deschedule)
|
||||
//
|
||||
void WMR_WAIT_US(UInt64 microseconds);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_SLEEP_US
|
||||
//
|
||||
// Sleep the given number of microseconds. On threading/tasking systems, this
|
||||
// relinquishes cpu control to the scheduler. On simpler systems, this simply
|
||||
// waits the specified amount of time.
|
||||
//
|
||||
void WMR_SLEEP_US(UInt32 microseconds);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_YIELD
|
||||
//
|
||||
// Yield cpu control to the scheduler on threading/tasking systems. On simpler
|
||||
// systems, this simply returns immediately.
|
||||
//
|
||||
void WMR_YIELD(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_BUS_FREQ_MHZ
|
||||
//
|
||||
// Return the minimum and maximum speeds that the system bus connected to the
|
||||
// the FMC may operate during NAND accesses
|
||||
//
|
||||
void WMR_BUS_FREQ_MHZ(UInt32 * minClockMHz, UInt32 * maxClockMHz);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_BUS_FREQ_HZ
|
||||
//
|
||||
// Return a precise version of the fastest operating frequency of the FMC
|
||||
//
|
||||
UInt32 WMR_BUS_FREQ_HZ(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_GET_SIGNATURE_MAJOR_VER
|
||||
//
|
||||
// Return signature byte indicating the major version
|
||||
//
|
||||
UInt8 WMR_GET_SIGNATURE_MAJOR_VER(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_GET_SIGNATURE_LAYOUT
|
||||
//
|
||||
// Return signature byte indicating the minor version
|
||||
//
|
||||
UInt8 WMR_GET_SIGNATURE_MINOR_VER(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_ACQUIRE_LOCK
|
||||
//
|
||||
// Acquire a lock allocated to the NAND driver
|
||||
//
|
||||
void WMR_ACQUIRE_LOCK(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_RELEASE_LOCK
|
||||
//
|
||||
// Releas a lock acquired through WMR_ACQUIRE_LOCK
|
||||
//
|
||||
void WMR_RELEASE_LOCK(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CLOCK_GATE
|
||||
//
|
||||
// Gates/Ungates the clock for device
|
||||
//
|
||||
void WMR_CLOCK_GATE(UInt32 device, BOOL32 enable);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_DLL_CLOCK_GATE
|
||||
//
|
||||
// Gates/Ungates the clock for NAND DLL
|
||||
//
|
||||
void WMR_DLL_CLOCK_GATE(BOOL32 enable);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CLOCK_RESET_DEVICE
|
||||
//
|
||||
// Clock reset device
|
||||
//
|
||||
void WMR_CLOCK_RESET_DEVICE(UInt32 device);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _WMR_OAM_H_ */
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
#include <WMRFeatures.h>
|
||||
#include <WMROAM.h>
|
||||
#include <WMRBuf.h>
|
||||
#include <platform.h>
|
||||
|
||||
|
||||
// Variable instantiations
|
||||
|
||||
WMR_BufZoneList_t WMR_BufZoneList;
|
||||
|
||||
|
||||
// Functions
|
||||
|
||||
static void ZoneList_Link(WMR_BufZone_t *zone)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
|
||||
static void ZoneList_Unlink(WMR_BufZone_t *zone)
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
|
||||
extern void WMR_Buf_Init()
|
||||
{
|
||||
// NOP
|
||||
}
|
||||
|
||||
|
||||
void *WMR_Buf_Alloc(WMR_BufZone_t *zone, UInt32 size)
|
||||
{
|
||||
// Only need cache-line alignment, so pass it through to the other allocator
|
||||
return WMR_Buf_Alloc_ForDMA(zone, size);
|
||||
}
|
||||
|
||||
|
||||
void *WMR_Buf_Alloc_ForDMA(WMR_BufZone_t *zone, UInt32 size)
|
||||
{
|
||||
void *ret;
|
||||
UInt32 oldTotal;
|
||||
|
||||
WMR_ASSERT(BZS_ALLOC == zone->state);
|
||||
|
||||
// Align alloc offset
|
||||
oldTotal = zone->totalAlloc;
|
||||
zone->totalAlloc = ROUNDUPTO(zone->totalAlloc, CPU_CACHELINE_SIZE);
|
||||
zone->waste += (zone->totalAlloc - oldTotal);
|
||||
|
||||
// Set up offset pointer
|
||||
ret = (void*)zone->totalAlloc;
|
||||
|
||||
// Move allocator along
|
||||
zone->totalAlloc += size;
|
||||
zone->numAllocs++;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void WMR_BufZone_Init(WMR_BufZone_t *zone)
|
||||
{
|
||||
zone->baseAddr = NULL;
|
||||
zone->maxAddr = NULL;
|
||||
zone->totalAlloc = 0;
|
||||
zone->numAllocs = 0;
|
||||
zone->numRebases = 0;
|
||||
zone->waste = 0;
|
||||
zone->state = BZS_ALLOC;
|
||||
|
||||
ZoneList_Link(zone);
|
||||
}
|
||||
|
||||
|
||||
BOOL32 WMR_BufZone_FinishedAllocs(WMR_BufZone_t *zone)
|
||||
{
|
||||
UInt8 *buf;
|
||||
|
||||
WMR_ASSERT(BZS_ALLOC == zone->state);
|
||||
|
||||
// Allocate buffer
|
||||
zone->totalAlloc = ROUNDUPTO(zone->totalAlloc, CPU_CACHELINE_SIZE);
|
||||
buf = WMR_MALLOC(zone->totalAlloc);
|
||||
if (NULL == buf)
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
// Update zone
|
||||
zone->baseAddr = buf;
|
||||
zone->maxAddr = zone->baseAddr + zone->totalAlloc;
|
||||
zone->state = BZS_FINISHED;
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
|
||||
void WMR_BufZone_Rebase(WMR_BufZone_t *zone, void** buf)
|
||||
{
|
||||
*buf = (void*)(zone->baseAddr + (UInt32)*buf);
|
||||
zone->numRebases++;
|
||||
}
|
||||
|
||||
|
||||
void WMR_BufZone_FinishedRebases(WMR_BufZone_t *zone)
|
||||
{
|
||||
WMR_ASSERT(zone->numAllocs == zone->numRebases);
|
||||
}
|
||||
|
||||
|
||||
void WMR_BufZone_Free(WMR_BufZone_t *zone)
|
||||
{
|
||||
if (zone->baseAddr) {
|
||||
WMR_FREE(zone->baseAddr, zone->totalAlloc);
|
||||
}
|
||||
|
||||
zone->baseAddr = NULL;
|
||||
zone->maxAddr = NULL;
|
||||
zone->totalAlloc = 0;
|
||||
zone->state = BZS_INIT;
|
||||
|
||||
ZoneList_Unlink(zone);
|
||||
}
|
||||
|
||||
// This function is meaningless on non-Darwin targets
|
||||
//UInt32 WMR_BufZone_FindDescriptor(UInt8* buf, void **des) // returns offset
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef __WMR_BUFTYPES_H__
|
||||
#define __WMR_BUFTYPES_H__
|
||||
|
||||
#include <WMRTypes.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// Types
|
||||
typedef enum {
|
||||
BZS_INIT,
|
||||
BZS_ALLOC,
|
||||
BZS_FINISHED,
|
||||
BZS_FREE,
|
||||
} WMR_BZS_State_e;
|
||||
|
||||
typedef struct {
|
||||
UInt8* baseAddr;
|
||||
UInt8* maxAddr;
|
||||
|
||||
UInt32 totalAlloc;
|
||||
UInt32 numAllocs;
|
||||
UInt32 numRebases;
|
||||
UInt32 waste;
|
||||
|
||||
WMR_BZS_State_e state;
|
||||
} WMR_BufZone_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
} WMR_BufZoneList_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // __WMR_BUFTYPES_H__
|
||||
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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.
|
||||
*/
|
||||
|
||||
/////
|
||||
//
|
||||
// Whimory Feature Definitions
|
||||
//
|
||||
/////
|
||||
|
||||
|
||||
#include "WMRTypes.h"
|
||||
|
||||
#ifndef _WMR_FEATURES_H_
|
||||
#define _WMR_FEATURES_H_
|
||||
|
||||
// Define the platform we're on
|
||||
#define WMR_BUILDING_IBOOT (1)
|
||||
// Allow yaFTL to open
|
||||
#define AND_SUPPORT_YAFTL (1)
|
||||
// Allow FTL to open
|
||||
#define AND_SUPPORT_LEGACY_FTL (0)
|
||||
#define AND_SUPPORT_LEGACY_VFL (0)
|
||||
#define PPN_ENABLE_RMA_MODE (1)
|
||||
|
||||
#define AND_MAX_SPECIAL_BLOCKS (120)
|
||||
|
||||
//#define WMR_FIL_TEST_ENABLED (1)
|
||||
|
||||
#if (defined(WMR_DEBUG) && WMR_DEBUG) && \
|
||||
(defined(PRODUCT_IBOOT) && PRODUCT_IBOOT) && \
|
||||
(defined(WMR_FIL_TEST_ENABLED) && WMR_FIL_TEST_ENABLED)
|
||||
// Allow writes on H2 and H3 DEBUG-ONLY iBoot builds to enable the FIL interface test
|
||||
#define AND_COLLECT_STATISTICS (1)
|
||||
#else
|
||||
// Disallow write and erase operations to block device as a bootloader
|
||||
#define AND_READONLY (1)
|
||||
#endif
|
||||
#ifndef ENABLE_L2V_TREE
|
||||
#define ENABLE_L2V_TREE (0)
|
||||
#endif
|
||||
|
||||
// Don't bother collect stats in read-only mode
|
||||
//#define AND_COLLECT_STATISTICS (1)
|
||||
// Use polling (instead of interrupts)
|
||||
#define BUILDING_SINGLETASKING (1)
|
||||
|
||||
//Should we use line-wise or full-cache operations
|
||||
#if (defined(PLATFORM_S5L8720X) && PLATFORM_S5L8720X)
|
||||
// M2 products shipped with full-cache flushing
|
||||
#define WMR_USE_FULL_CACHE_FLUSH (1)
|
||||
#endif
|
||||
|
||||
#if (defined(WITH_NAND_BOOT) && WITH_NAND_BOOT)
|
||||
// Boot-from-nand products use boot block
|
||||
#define AND_SUPPORT_FIL_BOOT_PAGES (1)
|
||||
#else
|
||||
// Don't write a boot block, because this platform won't use it
|
||||
#define AND_SUPPORT_FIL_BOOT_PAGES (0)
|
||||
#endif
|
||||
|
||||
// Create feature code for NVRAM support.
|
||||
#if ((defined(WITH_NAND_NVRAM) && WITH_NAND_NVRAM) || (defined(WITH_EFFACEABLE_NAND) && WITH_EFFACEABLE_NAND))
|
||||
#define AND_SUPPORT_NVRAM (1)
|
||||
#else
|
||||
#define AND_SUPPORT_NVRAM (0)
|
||||
#endif
|
||||
|
||||
// Create feature code for firmware area support.
|
||||
#if (defined(WITH_NAND_FIRMWARE) && WITH_NAND_FIRMWARE)
|
||||
#define AND_SUPPORT_FW_AREA (1)
|
||||
#else
|
||||
#define AND_SUPPORT_FW_AREA (0)
|
||||
#endif
|
||||
|
||||
|
||||
// Allow FIL layer to be built without support for block device.
|
||||
#if (defined(WITH_NAND_FILESYSTEM) && WITH_NAND_FILESYSTEM)
|
||||
#define AND_SUPPORT_BLOCK_STORAGE (1)
|
||||
#else
|
||||
#define AND_SUPPORT_BLOCK_STORAGE (0)
|
||||
#endif
|
||||
|
||||
// Build just enough to support boot-from-nand but not full block storage support.
|
||||
#if (!AND_SUPPORT_BLOCK_STORAGE && WITH_NAND_BOOT)
|
||||
#define AND_FPART_ONLY (1)
|
||||
#else
|
||||
#define AND_FPART_ONLY (0)
|
||||
#endif
|
||||
|
||||
// Sanity check
|
||||
#if (defined (AND_SUPPORT_2ND_BOOTLOADER) && AND_SUPPORT_2ND_BOOTLOADER && defined (AND_SIGNATURE_IN_BLOCK_ZERO) && AND_SIGNATURE_IN_BLOCK_ZERO)
|
||||
#error "AND_SUPPORT_2ND_BOOTLOADER & AND_SIGNATURE_IN_BLOCK_ZERO can't both be defined"
|
||||
#endif
|
||||
|
||||
// Defined by platform, but they're all OK with 30 for now
|
||||
#define FIL_MAX_ECC_CORRECTION (30)
|
||||
|
||||
#if (!defined(AND_READONLY) && WMR_BUILDING_IBOOT)
|
||||
//#error iBoot nand driver does not support writes
|
||||
#endif
|
||||
|
||||
// =============================================================================
|
||||
// configurable preprocessor compilation control
|
||||
// =============================================================================
|
||||
|
||||
// Set H2FMI_DEBUG below to 1 if you want to build for debugging (default
|
||||
// to 0).
|
||||
#define WMR_IBOOT_WRITE_ENABLE 0
|
||||
#define H2FMI_DEBUG 0
|
||||
|
||||
// Set H2FMI_TEST_HOOK below to 1 if you want to insert tests at the end
|
||||
// of FIL_Init in iBoot (default to 0).
|
||||
#define H2FMI_TEST_HOOK 0
|
||||
|
||||
// Set H2FMI_WAIT_USING_ISR to true if you want operations to wait for
|
||||
// dma and bus events by hooking an interrupt service routine to the
|
||||
// FMI interrupt vector; set to false for waiting using register
|
||||
// polling with yield (default to true).
|
||||
#if !(defined(AND_READONLY)) || WITH_NAND_NVRAM || WITH_NAND_FIRMWARE || WITH_EFFACEABLE_NAND
|
||||
// Disable ISR for more efficient deadstripping
|
||||
#define H2FMI_WAIT_USING_ISR 1
|
||||
#endif
|
||||
|
||||
// Change the constant below to 1 if you want to see all FMI
|
||||
// subsystem register writes; note that doing so is likely to change
|
||||
// timing and therefore behavior, so it should be a rare case that you
|
||||
// would ever want to do this. In cases where you want to see just
|
||||
// one or two writes, consider calling the 'h2fmi_dbg_wr' or
|
||||
// 'h2fmi_dbg_wr8' function directly (default to 0).
|
||||
#define H2FMI_TRACE_REG_WRITES 0
|
||||
|
||||
// Change the constant below to 1 if you want to see all FMI
|
||||
// subsystem register reads; note that doing so is likely to change
|
||||
// timing and therefore behavior, so it should be a rare case that you
|
||||
// would ever want to do this. In cases where you want to see just
|
||||
// one or two reads, consider calling the 'h2fmi_dbg_rd' or
|
||||
// 'h2fmi_dbg_rd8' function directly (default to 0).
|
||||
#define H2FMI_TRACE_REG_READS 0
|
||||
|
||||
// =============================================================================
|
||||
// fixed preprocessor compilation control
|
||||
// =============================================================================
|
||||
|
||||
#if (defined (WITH_HW_BOOTROM_NAND) && WITH_HW_BOOTROM_NAND)
|
||||
#define H2FMI_BOOTROM 1
|
||||
#else
|
||||
#define H2FMI_BOOTROM 0
|
||||
#endif
|
||||
|
||||
#define H2FMI_IOP 0
|
||||
#define H2FMI_IBOOT 1
|
||||
#define H2FMI_EFI 0
|
||||
|
||||
// Always build SecureROM read-only.
|
||||
#if (H2FMI_BOOTROM)
|
||||
#define H2FMI_READONLY 1
|
||||
// Otherwise, ignore nand driver read-only configuration in iBoot
|
||||
// debug builds so that erase/write are available for use in testing
|
||||
// read operations.
|
||||
#elif (H2FMI_IBOOT && defined(AND_READONLY) && H2FMI_DEBUG)
|
||||
#define H2FMI_READONLY 0
|
||||
// Otherwise, mirror nand driver configuration in iBoot.
|
||||
#elif (defined(AND_READONLY))
|
||||
#define H2FMI_READONLY 1
|
||||
#else
|
||||
#define H2FMI_READONLY 0
|
||||
#endif
|
||||
|
||||
#define DEFAULT_OAM_BOOT_BUFFER_SIZE (0x800000) // 8MB
|
||||
|
||||
#define H2FMI_ALLOW_MULTIS (1)
|
||||
|
||||
#endif /* _WMR_FEATURES_H_ */
|
||||
|
||||
@@ -0,0 +1,254 @@
|
||||
#include "WMROAM.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <lib/heap.h>
|
||||
|
||||
#include <sys/task.h>
|
||||
#include <platform.h>
|
||||
#include <platform/soc/hwclocks.h>
|
||||
#include <platform/soc/hwregbase.h>
|
||||
#include <platform/timer.h>
|
||||
|
||||
UInt32 gWhimoryInitParameters =
|
||||
#if (defined(WITH_BLOCK_ZERO_SIGNATURE) && WITH_BLOCK_ZERO_SIGNATURE)
|
||||
WMR_INIT_SIGNATURE_IN_BLOCKZERO |
|
||||
#endif
|
||||
0;
|
||||
|
||||
static UInt32 boot_buffer_size = DEFAULT_OAM_BOOT_BUFFER_SIZE;
|
||||
static void * boot_buffer = NULL;
|
||||
|
||||
void *
|
||||
WMR_MALLOC(UInt32 nSize)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = memalign(nSize, CPU_CACHELINE_SIZE);
|
||||
WMR_MEMSET(p, 0, nSize);
|
||||
return p;
|
||||
}
|
||||
|
||||
void*
|
||||
WMR_BOOT_MALLOC(UInt32 *size)
|
||||
{
|
||||
WMR_ASSERT(NULL != size);
|
||||
WMR_ASSERT(NULL == boot_buffer); // only one allocation allowed
|
||||
|
||||
if (*size <= boot_buffer_size)
|
||||
{
|
||||
boot_buffer = malloc(boot_buffer_size);
|
||||
WMR_MEMSET(boot_buffer, 0, boot_buffer_size);
|
||||
}
|
||||
*size = boot_buffer_size;
|
||||
return boot_buffer;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WMR_BOOT_FREE(void * ptr)
|
||||
{
|
||||
WMR_ASSERT(ptr == boot_buffer);
|
||||
free(ptr);
|
||||
boot_buffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
BOOL32
|
||||
OAM_Init(void)
|
||||
{
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
void OAM_Beep(UInt32 dwMs)
|
||||
{
|
||||
}
|
||||
|
||||
void WMR_FREE(void * ptr, UInt32 size)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
BOOL32 WMR_CHECK_BUFFER(const void * buffer, UInt32 length)
|
||||
{
|
||||
#if (defined(WMR_DEBUG) && WMR_DEBUG)
|
||||
if (IS_ALIGNED_TO(buffer, CPU_CACHELINE_SIZE) &&
|
||||
IS_ALIGNED_TO(length, CPU_CACHELINE_SIZE))
|
||||
{
|
||||
return TRUE32;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
#else //WMR_DEBUG
|
||||
return TRUE32;
|
||||
#endif // !WMR_DEBUG
|
||||
}
|
||||
|
||||
BOOL32
|
||||
WMR_FILL_STRUCT(void *pDstBuff, UInt32 *pdwDstBuffSize, const void *pSrcBuff, UInt32 dwSrcBuffSize)
|
||||
{
|
||||
BOOL32 boolRes = TRUE32;
|
||||
|
||||
if (!pDstBuff && pdwDstBuffSize)
|
||||
{
|
||||
// Just return the buffer size
|
||||
*pdwDstBuffSize = dwSrcBuffSize;
|
||||
}
|
||||
else if (!pdwDstBuffSize || (*pdwDstBuffSize < dwSrcBuffSize))
|
||||
{
|
||||
// Supplied buffer is too small
|
||||
UInt32 dwPrintedSize = pdwDstBuffSize ? *pdwDstBuffSize : (UInt32) ~0;
|
||||
WMR_PRINT(ERROR,"IOCtl on buffer of size %d with %d bytes of src data!\n",
|
||||
dwPrintedSize, dwSrcBuffSize);
|
||||
boolRes = FALSE32;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a valid buffer pointer and buffer size
|
||||
WMR_MEMCPY(pDstBuff, pSrcBuff, dwSrcBuffSize);
|
||||
*pdwDstBuffSize = dwSrcBuffSize;
|
||||
}
|
||||
|
||||
return boolRes;
|
||||
}
|
||||
|
||||
void _WMR_PRINT(const char * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
// retrieve the variable arguments
|
||||
va_start(args, format);
|
||||
|
||||
vprintf(format, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
WMR_BEEP(UInt32 milliseconds)
|
||||
{
|
||||
printf("WMR_BEEP\n");
|
||||
}
|
||||
|
||||
const char * WMR_GETVERSION(void)
|
||||
{
|
||||
static char version[] = "version string";
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
BOOL32
|
||||
WMR_I_CAN_HAZ_DEBUGGER(void)
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
void WMR_WAIT_US(UInt64 microseconds)
|
||||
{
|
||||
spin(microseconds);
|
||||
}
|
||||
|
||||
void WMR_SLEEP_US(UInt32 microseconds)
|
||||
{
|
||||
task_sleep(microseconds);
|
||||
}
|
||||
|
||||
void WMR_YIELD(void)
|
||||
{
|
||||
// Task yield is not available to libraries, so can't build it into Whimory
|
||||
task_yield();
|
||||
}
|
||||
|
||||
UInt32 WMR_BUS_FREQ_HZ(void)
|
||||
{
|
||||
return clock_get_frequency(CLK_FMI);
|
||||
}
|
||||
|
||||
void WMR_BUS_FREQ_MHZ(UInt32 * minClockMHz, UInt32 * maxClockMHz)
|
||||
{
|
||||
const UInt32 clkSpeed = WMR_BUS_FREQ_HZ() / 1000000;
|
||||
|
||||
if (minClockMHz)
|
||||
{
|
||||
*minClockMHz = clkSpeed;
|
||||
}
|
||||
|
||||
if (maxClockMHz)
|
||||
{
|
||||
*maxClockMHz = clkSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
#if FMI_VERSION >= 5
|
||||
void WMR_DLL_CLOCK_GATE(BOOL32 enable)
|
||||
{
|
||||
clock_gate(CLK_FMI_DLL, enable);
|
||||
}
|
||||
#endif
|
||||
|
||||
void WMR_CLOCK_GATE(UInt32 device, BOOL32 enable)
|
||||
{
|
||||
int clock;
|
||||
|
||||
switch (device)
|
||||
{
|
||||
case 0:
|
||||
clock = CLK_FMI0;
|
||||
break;
|
||||
case 1:
|
||||
clock = CLK_FMI1;
|
||||
break;
|
||||
default:
|
||||
panic("invalid WMR_CLOCK_GATE");
|
||||
break;
|
||||
}
|
||||
clock_gate(clock, enable);
|
||||
|
||||
#if FMI_VERSION > 1
|
||||
switch (device)
|
||||
{
|
||||
case 0:
|
||||
clock = CLK_FMI0BCH;
|
||||
break;
|
||||
case 1:
|
||||
clock = CLK_FMI1BCH;
|
||||
break;
|
||||
default:
|
||||
panic("invalid WMR_CLOCK_GATE");
|
||||
break;
|
||||
}
|
||||
clock_gate(clock, enable);
|
||||
#endif //FMI_VERSION > 0
|
||||
}
|
||||
|
||||
void
|
||||
WMR_DEADLOOP(void)
|
||||
{
|
||||
volatile int i = 1;
|
||||
while (i)
|
||||
{
|
||||
(void) 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WMR_CLOCK_RESET_DEVICE(UInt32 device)
|
||||
{
|
||||
int clock;
|
||||
|
||||
if( device == 0 )
|
||||
{
|
||||
clock = CLK_FMI0;
|
||||
}
|
||||
else if( device == 1 )
|
||||
{
|
||||
clock = CLK_FMI1;
|
||||
}
|
||||
else
|
||||
{
|
||||
panic("invalid WMR_CLOCK_RESET_DEVICE");
|
||||
}
|
||||
|
||||
clock_reset_device(clock);
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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 "ANDTypes.h"
|
||||
#include "WMRFeatures.h"
|
||||
|
||||
#include <string.h> // memcmp
|
||||
#include <sys.h> // panic
|
||||
#include <platform.h> // cache
|
||||
#include <platform/timer.h> // ticks
|
||||
|
||||
#ifndef _WMR_PLATFORM_H_
|
||||
#define _WMR_PLATFORM_H_
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_LOG2
|
||||
//
|
||||
// Returns the floor(log2) of the given number
|
||||
//
|
||||
#define WMR_LOG2(x) (31UL - __builtin_clz((UInt32)(x)))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_LSB1
|
||||
//
|
||||
// Returns the least significant set bit's position for the given number
|
||||
//
|
||||
#define WMR_LSB1(x) (0 != x ? __builtin_ctz((UInt32)x) : ~0UL)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_MEMSET
|
||||
// WMR_MEMCPY
|
||||
// WMR_MEMCMP
|
||||
//
|
||||
// Standard memory operations (libraries where available)
|
||||
//
|
||||
|
||||
#define WMR_MEMSET(dest, pattern, length) memset((dest), (pattern), (length))
|
||||
#define WMR_MEMCPY(dest, src, length) memcpy((dest), (src), (length))
|
||||
#define WMR_MEMCMP(buf1, buf2, length) memcmp((buf1), (buf2), (length))
|
||||
#define WMR_STRLEN(str) strlen((str))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_ASSERT
|
||||
//
|
||||
// Print an error and panic if the given condition is not true
|
||||
//
|
||||
|
||||
# define WMR_ASSERT(_expr) \
|
||||
do { \
|
||||
if (__builtin_expect(!(_expr), 0)) \
|
||||
panic("WMR_ASSERT failed:(%s) %u", \
|
||||
__FILE__, __LINE__); \
|
||||
} while(0);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_PANIC
|
||||
//
|
||||
// Reset the system
|
||||
//
|
||||
# define WMR_PANIC(fmt, ...) \
|
||||
panic("WMR_PANIC: " #fmt " %s:%u", \
|
||||
## __VA_ARGS__, __FILE__, __LINE__)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_PREPARE_WRITE_BUFFER
|
||||
//
|
||||
// Call before an outgoing I/O operation to ensure cache coherency
|
||||
//
|
||||
|
||||
#define WRITE_PREP_CACHE_CMD (CACHE_CLEAN)
|
||||
|
||||
#if (defined(WMR_USE_FULL_CACHE_FLUSH) && WMR_USE_FULL_CACHE_FLUSH)
|
||||
#define WMR_PREPARE_WRITE_BUFFER(buf, length) \
|
||||
platform_cache_operation(WRITE_PREP_CACHE_CMD, 0, 0)
|
||||
#else //WMR_USE_FULL_CACHE_FLUSH
|
||||
#if WMR_DEBUG
|
||||
#define WMR_PREPARE_WRITE_BUFFER(buf, length) \
|
||||
do{ \
|
||||
WMR_ASSERT(0 == ((UInt32)(buf) % CPU_CACHELINE_SIZE)); \
|
||||
platform_cache_operation(WRITE_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE));\
|
||||
}while(0)
|
||||
#else
|
||||
#define WMR_PREPARE_WRITE_BUFFER(buf, length) \
|
||||
platform_cache_operation(WRITE_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE))
|
||||
#endif// !WMR_DEBUG
|
||||
#endif // !WMR_USE_FULL_CACHE_FLUSH
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_PREPARE_READ_BUFFER
|
||||
//
|
||||
// Call before an incoming I/O operation to ensure cache coherency
|
||||
//
|
||||
#define READ_PREP_CACHE_CMD (CACHE_CLEAN | CACHE_INVALIDATE)
|
||||
|
||||
#if (defined(WMR_USE_FULL_CACHE_FLUSH) && WMR_USE_FULL_CACHE_FLUSH)
|
||||
#define WMR_PREPARE_READ_BUFFER(buf, length) \
|
||||
platform_cache_operation(READ_PREP_CACHE_CMD, 0, 0)
|
||||
#else //WMR_USE_FULL_CACHE_FLUSH
|
||||
#if WMR_DEBUG
|
||||
#define WMR_PREPARE_READ_BUFFER(buf, length) \
|
||||
do{ \
|
||||
WMR_ASSERT(0 == ((UInt32)(buf) % CPU_CACHELINE_SIZE)); \
|
||||
platform_cache_operation(READ_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE));\
|
||||
}while(0)
|
||||
#else
|
||||
#define WMR_PREPARE_READ_BUFFER(buf, length) \
|
||||
platform_cache_operation(READ_PREP_CACHE_CMD, (buf), ROUNDUPTO((length), CPU_CACHELINE_SIZE))
|
||||
#endif// !WMR_DEBUG
|
||||
#endif // !WMR_USE_FULL_CACHE_FLUSH
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_COMPLETE_READ_BUFFER
|
||||
//
|
||||
// Call after an incoming I/O operation to ensure cache coherency
|
||||
//
|
||||
// Note: On the IOP, we only prepare aligned read buffers from the host, so we
|
||||
// shouldn't have to actually clean any dirty lines
|
||||
#define WMR_COMPLETE_READ_BUFFER(buf, length) \
|
||||
WMR_PREPARE_READ_BUFFER(buf, length)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_GET_TICKS_PER_US
|
||||
//
|
||||
// Return the number of native ticks (as returned from WMR_CLOCK_NATIVE) per
|
||||
// microsecond.
|
||||
//
|
||||
|
||||
// UInt32
|
||||
#define WMR_GET_TICKS_PER_US() (timer_get_tick_rate() / 1000000UL)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CLOCK_NATIVE
|
||||
//
|
||||
// Get the current system time in microseconds to be passed to
|
||||
// WMR_HAS_TIME_ELAPSED_US and WMR_HAS_TIME_ELAPSED_MS, but NOT
|
||||
// WMR_HAS_TIME_ELAPSED_TICKS
|
||||
//
|
||||
|
||||
// UInt64
|
||||
#define WMR_CLOCK_NATIVE() system_time()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_CLOCK_TICKS
|
||||
//
|
||||
// Get the current system time in ticks (suitable for WMR_HAS_TIME_ELAPSED_TICKS)
|
||||
//
|
||||
|
||||
//UInt64
|
||||
#define WMR_CLOCK_TICKS() timer_get_ticks()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_HAS_TIME_ELAPSED_US
|
||||
//
|
||||
// Supply a start timestamp from WMR_CLOCK_NATIVE to determine if the given
|
||||
// time has elapsed
|
||||
//
|
||||
|
||||
//UInt64 startTicks, UInt64 elapsedUS
|
||||
#define WMR_HAS_TIME_ELAPSED_US(startTicks, elapsedUS) \
|
||||
(time_has_elapsed((startTicks), (elapsedUS)) ? TRUE32 : FALSE32)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_HAS_TIME_ELAPSED_TICKS
|
||||
//
|
||||
// Supply a start timestamp from WMR_CLOCK_NATIVE to determine if the given
|
||||
// time has elapsed.
|
||||
|
||||
//UInt64 startTicks, UInt64 elapsedTicks
|
||||
#define WMR_HAS_TIME_ELAPSED_TICKS(startTicks, elapsedTicks) \
|
||||
((timer_get_ticks() - (startTicks)) > (elapsedTicks) ? TRUE32 : FALSE32)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_ENTER_CRITICAL_SECTION
|
||||
//
|
||||
// Disable pre-emption, reference counted (safe to call in interrupt)
|
||||
|
||||
#define WMR_ENTER_CRITICAL_SECTION() enter_critical_section()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_EXIT_CRITICAL_SECTION
|
||||
//
|
||||
// Enable pre-emption, reference counted (safe to call in interrupt)
|
||||
|
||||
#define WMR_EXIT_CRITICAL_SECTION() exit_critical_section()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_TRACE_*
|
||||
//
|
||||
// Compile-time tracepoints (not supported)
|
||||
//
|
||||
#define WMR_TRACE_0(...)
|
||||
#define WMR_TRACE_1(...)
|
||||
#define WMR_TRACE_2(...)
|
||||
#define WMR_TRACE_3(...)
|
||||
#define WMR_TRACE_4(...)
|
||||
#define WMR_TRACE_IST_0(...)
|
||||
#define WMR_TRACE_IST_1(...)
|
||||
#define WMR_TRACE_IST_2(...)
|
||||
#define WMR_TRACE_IST_3(...)
|
||||
#define WMR_TRACE_IST_4(...)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_RAND
|
||||
//
|
||||
// Get the next random number in the stream
|
||||
//
|
||||
#define WMR_RAND() rand()
|
||||
|
||||
#endif /* _WMR_PLATFORM_H_ */
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
#ifndef _WMR_TYPES_H_
|
||||
#define _WMR_TYPES_H_
|
||||
|
||||
# include <sys/types.h>
|
||||
# include "spTypes.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Basic Types */
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef UInt32 BOOL32;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Basic Constants */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define FALSE32 ((BOOL32)0)
|
||||
#define TRUE32 ((BOOL32)1)
|
||||
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
# define __align(_x)
|
||||
/*****************************************************************************/
|
||||
/* Basic Compiler Flags */
|
||||
/*****************************************************************************/
|
||||
|
||||
#define INLINE __inline
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
#define WMR_DEBUG (1)
|
||||
#else
|
||||
#define WMR_RELEASE (1)
|
||||
#endif
|
||||
|
||||
#endif /* _WMR_TYPES_H_ */
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
GLOBAL_INCLUDES += \
|
||||
$(LOCAL_DIR) \
|
||||
$(LOCAL_DIR)/$(APPLICATION)
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/$(APPLICATION)/WMROAM.o \
|
||||
$(LOCAL_DIR)/$(APPLICATION)/WMRBuf.o
|
||||
|
||||
MODULES += \
|
||||
lib/heap
|
||||
@@ -0,0 +1,781 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// (C) Copyright 2001 Apple Computer, All rights reserved
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// FILE NAME: spTypes.h
|
||||
//
|
||||
// DESCRIPTION:
|
||||
//
|
||||
// DOCUMENT REF:
|
||||
//
|
||||
// NOTES: None
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
#ifndef __SPTYPES_H__ //--------------------
|
||||
#define __SPTYPES_H__
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Standard include files:
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Types and defines:
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#define False 0
|
||||
#define True (!False)
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define Null 0
|
||||
#else
|
||||
#define Null ((Void *)0)
|
||||
#endif
|
||||
|
||||
#define MB 0x100000
|
||||
#define KB 0x400
|
||||
|
||||
/* Metrowerks for Windows doesn't support __packed for structures */
|
||||
#ifdef __INTEL__
|
||||
#define __packed
|
||||
#pragma options align=packed
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SP Standard Types Type Pointer
|
||||
// ------ -------
|
||||
typedef signed char xInt8, *pInt8; // 8 bit signed integer
|
||||
typedef signed short xInt16, *pInt16; // 16 bit signed integer
|
||||
typedef signed long xInt32, *pInt32; // 32 bit signed integer
|
||||
typedef signed long long xInt64, *pInt64; // 64 bit signed integer
|
||||
typedef unsigned char xUInt8, *pUInt8; // 8 bit unsigned integer
|
||||
typedef const unsigned char cUInt8, *pcUInt8; // 8 bit unsigned integer
|
||||
typedef unsigned short xUInt16, *pUInt16; // 16 bit unsigned integer
|
||||
typedef unsigned int xUInt32, *pUInt32; // 32 bit unsigned integer
|
||||
typedef unsigned long long xUInt64, *pUInt64; // 64 bit unsigned integer
|
||||
typedef void Void, *pVoid; // Void (typeless)
|
||||
typedef unsigned int Bool, *pBool; // Boolean (True/False)
|
||||
typedef char Char, *pChar; // character, character array ptr
|
||||
typedef char *String, **pString; // Null terminated 8 bit char str,
|
||||
typedef const char *ConstString,**pConstString; // Null term 8 bit char str ptr
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Pointer access macros
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define mmioReg8( pv ) *((volatile char *)(pv))
|
||||
#define mmioReg8u( pv ) *((volatile unsigned char *)(pv))
|
||||
#define mmioReg16( pv ) *((volatile short*)(pv))
|
||||
#define mmioReg16u( pv ) *((volatile unsigned short*)(pv))
|
||||
#define mmioReg32( pv ) *((volatile long *)(pv))
|
||||
#define mmioReg32u( pv ) *((volatile unsigned long *)(pv))
|
||||
|
||||
// use mmioReg for types that are already defined with volatile and a proper size and type
|
||||
#define mmioReg( pv ) *(pv)
|
||||
|
||||
//
|
||||
// For C++ we have to make sure the rValue is invoked
|
||||
// explicitly from the pointers lvalue when we only want the
|
||||
// side effects for reading and not the actual result.
|
||||
//
|
||||
#define mmioReg8_access( pv ) ((void)(0+mmioReg8( pv )))
|
||||
#define mmioReg8u_access( pv ) ((void)(0+mmioReg8u( pv )))
|
||||
#define mmioReg16_access( pv ) ((void)(0+mmioReg16( pv )))
|
||||
#define mmioReg16u_access( pv ) ((void)(0+mmioReg16u( pv )))
|
||||
#define mmioReg32_access( pv ) ((void)(0+mmioReg32( pv )))
|
||||
#define mmioReg32u_access( pv ) ((void)(0+mmioReg32u( pv )))
|
||||
|
||||
// use mmioReg for types that are already defined with volatile and a proper size and type
|
||||
#define mmioReg_access( pv ) ((void)(0+mmioReg(pv)))
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Pointer creation macros
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define makePtr( c, b, o ) ((c)(((long)b)+((long)o)))
|
||||
|
||||
#define memberOffset(t,m) ( &(((t)0)->m))
|
||||
|
||||
#define mmioValueAlterMask( pv, mask, setclear ) \
|
||||
pv = (setclear) ? \
|
||||
(pv | (mask)) : \
|
||||
(pv & ~(mask))
|
||||
#define mmioValueAlterBit( pv, bit, setclear ) mmioValueAlterMask(pv, 1 << (bit), setclear)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Error Codes
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// +------+------+------------+------+------------------+
|
||||
// |31 28|27 24|23 16|15 12|11 0| bit
|
||||
// +------+------+------------+------+------------------+
|
||||
// |Class | Type |ComponentTag|Layer | Error/Progress |
|
||||
// +------+------+------------+------+------------------+
|
||||
|
||||
typedef UInt32 spErrorCode_t;
|
||||
typedef void (*spFn_t)(void);
|
||||
typedef void (*HandlerFunction)(void);
|
||||
typedef void (*spFnProgress_t)( UInt32 pct, pVoid pContext);
|
||||
typedef spErrorCode_t (*spFnUiCmd_t)( pUInt8 argv[],UInt32 argc);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SP_OK is the 32 bit global status value used by all software components
|
||||
// to indicate successful function/operation status. If a non-zero value is
|
||||
// returned as status, it should use the component ID formats defined.
|
||||
//
|
||||
#define SP_OK 0 // Global success return status
|
||||
|
||||
//
|
||||
// NOTE: Component ID types are defined as unsigned 32 bit integers (UInt32).
|
||||
//
|
||||
#define CID_ERR_BITSHIFT 0 // Component error bit shift
|
||||
#define CID_TAG_BITSHIFT 16 // Component tag bit shift
|
||||
#define CID_LAYER_BITSHIFT 12 // Component layer bit shift
|
||||
#define CID_TYPE_BITSHIFT 24 // Component type bit shift
|
||||
#define CID_CLASS_BITSHIFT 28 // Component class bit shift
|
||||
|
||||
#define CID_LAYER_BITMASK ( 0x00F << CID_LAYER_BITSHIFT) // Layer AND bitmask
|
||||
#define CID_TAG_BITMASK ( 0x0FF << CID_TAG_BITSHIFT ) // Comp tag AND bitmask
|
||||
#define CID_CLASS_BITMASK ( 0x00F << CID_CLASS_BITSHIFT) // Class AND bitmsk
|
||||
#define CID_ERR_BITMASK ( 0xFFF << CID_ERR_BITSHIFT ) // Component error AND bitmask
|
||||
#define CID_TYPE_BITMASK ( 0x00F << CID_TYPE_BITSHIFT ) // Type AND bitmask
|
||||
|
||||
#define SP_ERR_GET_ERROR(err) ((err & CID_ERR_BITMASK ) >> CID_ERR_BITSHIFT )
|
||||
#define SP_ERR_GET_CLASS(err) ((err & CID_CLASS_BITMASK) >> CID_CLASS_BITSHIFT)
|
||||
#define SP_ERR_GET_TYPE(err) ((err & CID_TYPE_BITMASK ) >> CID_TYPE_BITSHIFT )
|
||||
#define SP_ERR_GET_LAYER(err) ((err & CID_LAYER_BITMASK) >> CID_LAYER_BITSHIFT)
|
||||
|
||||
// Component Class definitions (bits 31:28, 4 bits)
|
||||
#define CID_CLASS_NONE (0x1 << CID_CLASS_BITSHIFT) // No class information
|
||||
#define CID_CLASS_INFRASTR (0x2 << CID_CLASS_BITSHIFT)
|
||||
|
||||
// Component Type definitions (bits 27:24, 4 bits)
|
||||
#define CID_TYPE_NONE (0x0 << CID_TYPE_BITSHIFT) // No data connections
|
||||
|
||||
// Component Tag definitions (bits 23:16, 8 bits)
|
||||
// NOTE: Component tags are defined in groups, dependent on the class and type.
|
||||
#define CID_TAG_NONE (0x00 << CID_TAG_BITSHIFT) // No tag information
|
||||
|
||||
#define TAG(num) ((num)<< CID_TAG_BITSHIFT) // Create tag from num
|
||||
|
||||
// Component Layer definitions (bits 15:12, 4 bits)
|
||||
#define CID_LAYER_NONE (0x0 << CID_LAYER_BITSHIFT) // No layer info
|
||||
#define CID_LAYER_BOOT (0x1 << CID_LAYER_BITSHIFT) // Boot loader layer
|
||||
#define CID_LAYER_HWAPI (0x2 << CID_LAYER_BITSHIFT) // Hardware API layer
|
||||
#define CID_LAYER_IMA (0x3 << CID_LAYER_BITSHIFT) // iMA interface layer
|
||||
|
||||
// STANDARD ERRORS
|
||||
#define SP_ERR_COMPATIBILITY 0x001 // SW Interface compatibility
|
||||
#define SP_ERR_MAJOR_VERSION 0x002 // SW Major Version error
|
||||
#define SP_ERR_COMP_VERSION 0x003 // SW component version error
|
||||
#define SP_ERR_BAD_MODULE_ID 0x004 // SW - HW module ID error
|
||||
#define SP_ERR_BAD_UNIT_NUMBER 0x005 // Invalid device unit number
|
||||
#define SP_ERR_BAD_INSTANCE 0x006 // Bad input instance value
|
||||
#define SP_ERR_BAD_HANDLE 0x007 // Bad input handle
|
||||
#define SP_ERR_BAD_INDEX 0x008 // Bad input index
|
||||
#define SP_ERR_BAD_PARAMETER 0x009 // Invalid input parameter
|
||||
#define SP_ERR_NO_INSTANCES 0x00A // No instances available
|
||||
#define SP_ERR_NO_COMPONENT 0x00B // Component is not present
|
||||
#define SP_ERR_NO_RESOURCES 0x00C // Resource is not available
|
||||
#define SP_ERR_INSTANCE_IN_USE 0x00D // Instance is already in use
|
||||
#define SP_ERR_RESOURCE_OWNED 0x00E // Resource is already in use
|
||||
#define SP_ERR_RESOURCE_NOT_OWNED 0x00F // Caller does not own resource
|
||||
#define SP_ERR_INCONSISTENT_PARAMS 0x010 // Inconsistent input params
|
||||
#define SP_ERR_NOT_INITIALIZED 0x011 // Component is not initialized
|
||||
#define SP_ERR_NOT_ENABLED 0x012 // Component is not enabled
|
||||
#define SP_ERR_NOT_SUPPORTED 0x013 // Function is not supported
|
||||
#define SP_ERR_INIT_FAILED 0x014 // Initialization failed
|
||||
#define SP_ERR_BUSY 0x015 // Component is busy
|
||||
#define SP_ERR_NOT_BUSY 0x016 // Component is not busy
|
||||
#define SP_ERR_READ 0x017 // Read error
|
||||
#define SP_ERR_WRITE 0x018 // Write error
|
||||
#define SP_ERR_ERASE 0x019 // Erase error
|
||||
#define SP_ERR_LOCK 0x01A // Lock error
|
||||
#define SP_ERR_UNLOCK 0x01B // Unlock error
|
||||
#define SP_ERR_OUT_OF_MEMORY 0x01C // Memory allocation failed
|
||||
#define SP_ERR_BAD_VIRT_ADDRESS 0x01D // Bad virtual address
|
||||
#define SP_ERR_BAD_PHYS_ADDRESS 0x01E // Bad physical address
|
||||
#define SP_ERR_TIMEOUT 0x01F // Timeout error
|
||||
#define SP_ERR_OVERFLOW 0x020 // Data overflow/overrun error
|
||||
#define SP_ERR_FULL 0x021 // Queue (etc.) is full
|
||||
#define SP_ERR_EMPTY 0x022 // Queue (etc.) is empty
|
||||
#define SP_ERR_NOT_STARTED 0x023 // Component stream not started
|
||||
#define SP_ERR_ALREADY_STARTED 0x024 // Comp. stream already started
|
||||
#define SP_ERR_NOT_STOPPED 0x025 // Component stream not stopped
|
||||
#define SP_ERR_ALREADY_STOPPED 0x026 // Comp. stream already stopped
|
||||
#define SP_ERR_ALREADY_SETUP 0x027 // Component already setup
|
||||
#define SP_ERR_NULL_PARAMETER 0x028 // Null input parameter
|
||||
#define SP_ERR_NULL_DATAINFUNC 0x029 // Null data input function
|
||||
#define SP_ERR_NULL_DATAOUTFUNC 0x02A // Null data output function
|
||||
#define SP_ERR_NULL_CONTROLFUNC 0x02B // Null control function
|
||||
#define SP_ERR_NULL_COMPLETIONFUNC 0x02C // Null completion function
|
||||
#define SP_ERR_NULL_PROGRESSFUNC 0x02D // Null progress function
|
||||
#define SP_ERR_NULL_ERRORFUNC 0x02E // Null error handler function
|
||||
#define SP_ERR_NULL_MEMALLOCFUNC 0x02F // Null memory alloc function
|
||||
#define SP_ERR_NULL_MEMFREEFUNC 0x030 // Null memory free function
|
||||
#define SP_ERR_NULL_CONFIGFUNC 0x031 // Null configuration function
|
||||
#define SP_ERR_NULL_PARENT 0x032 // Null parent data
|
||||
#define SP_ERR_NULL_IODESC 0x033 // Null in/out descriptor
|
||||
#define SP_ERR_NULL_CTRLDESC 0x034 // Null control descriptor
|
||||
#define SP_ERR_UNSUPPORTED_DATACLASS 0x035 // Unsupported data class
|
||||
#define SP_ERR_UNSUPPORTED_DATATYPE 0x036 // Unsupported data type
|
||||
#define SP_ERR_UNSUPPORTED_DATASUBTYPE 0x037 // Unsupported data subtype
|
||||
#define SP_ERR_FORMAT 0x038 // Invalid/unsupported format
|
||||
#define SP_ERR_INPUT_DESC_FLAGS 0x039 // Bad input descriptor flags
|
||||
#define SP_ERR_OUTPUT_DESC_FLAGS 0x03A // Bad output descriptor flags
|
||||
#define SP_ERR_CAP_REQUIRED 0x03B // Capabilities required ???
|
||||
#define SP_ERR_BAD_TMALFUNC_TABLE 0x03C // Bad TMAL function table
|
||||
#define SP_ERR_INVALID_CHANNEL_ID 0x03D // Invalid channel identifier
|
||||
#define SP_ERR_INVALID_COMMAND 0x03E // Invalid command/request
|
||||
#define SP_ERR_STREAM_MODE_CONFUSION 0x03F // Stream mode config conflict
|
||||
#define SP_ERR_UNDERRUN 0x040 // Data underflow/underrun
|
||||
#define SP_ERR_EMPTY_PACKET_RECVD 0x041 // Empty data packet received
|
||||
#define SP_ERR_OTHER_DATAINOUT_ERR 0x042 // Other data input/output err
|
||||
#define SP_ERR_STOP_REQUESTED 0x043 // Stop in progress
|
||||
#define SP_ERR_PIN_NOT_STARTED 0x044 // Pin not started
|
||||
#define SP_ERR_PIN_ALREADY_STARTED 0x045 // Pin already started
|
||||
#define SP_ERR_PIN_NOT_STOPPED 0x046 // Pin not stopped
|
||||
#define SP_ERR_PIN_ALREADY_STOPPED 0x047 // Pin already stopped
|
||||
#define SP_ERR_STOP_PIN_REQUESTED 0x048 // Stop of a single pin is in progress
|
||||
#define SP_ERR_ASSERTION 0x049 // Assertion failure
|
||||
#define SP_ERR_HIGHWAY_BANDWIDTH 0x04A // Highway bandwidth bus error
|
||||
#define SP_ERR_HW_RESET_FAILED 0x04B // Hardware reset failed
|
||||
#define SP_ERR_MEDIA_MISSING 0x04C // Media Missing
|
||||
#define SP_ERR_DEVICE_ABORT 0x04D // Device Abort
|
||||
#define SP_ERR_MEDIA_CHANGE 0x04E // Media Change
|
||||
#define SP_ERR_MEDIA_WRITE_PROTECTED 0x04F // Media Write Protected
|
||||
#define SP_ERR_HW_ERR_PENDING 0x050 //
|
||||
#define SP_ERR_HW_ERR 0x051 // Generic Hw Error
|
||||
#define SP_ERR_NOT_FOUND 0x052 // item not found
|
||||
#define SP_ERR_DEVICE_NOT_FOUND 0x053 // device not found
|
||||
#define SP_ERR_ITEMLIST_FULL 0x054 // no room for item in catalog
|
||||
#define SP_ERR_FNF_ERR 0x055 // file not found
|
||||
#define SP_ERR_NOPARTITION 0x056 // partition not found
|
||||
#define SP_ERR_CHECKSUM_FAILED 0x057 // checksum do not match
|
||||
#define SP_ERR_ATA_SELECT_ERROR 0x058 // IDE error selecting device
|
||||
#define SP_ERR_ATA_COMMAND_ERROR 0x059 // IDE command failed
|
||||
#define SP_ERR_ATA_SEQUENCE_ERROR 0x05a // IDE command setup sequence failed
|
||||
#define SP_ERR_ATA_COMMUNICATIONS_ERROR 0x05b // IDE communications error
|
||||
#define SP_ERR_IIC_NOACK 0x060 // IIC no ack error
|
||||
|
||||
// Add new standard error/progress status codes here
|
||||
|
||||
#define SP_ERR_COMP_UNIQUE_START 0x800 // 0x800-0xDFF: Component unique
|
||||
|
||||
// SP Standard assert error code start offset
|
||||
// NOTE: This define should be added to the component's base error value and
|
||||
// standard error code(s) to define assert error codes.
|
||||
//
|
||||
#define SP_ERR_ASSERT_START 0xE00 // 0xE00-0xEFF: Assert failures
|
||||
#define SP_ERR_ASSERT_LAST 0xEFF // Last assert error range value
|
||||
#define SP_IS_ASSERT_ERROR(err) \
|
||||
((SP_GET_ERROR(err) >= SP_ERR_ASSERT_START) && \
|
||||
(SP_GET_ERROR(err) <= SP_ERR_ASSERT_LAST))
|
||||
|
||||
// SP Standard fatal error code start offset
|
||||
// NOTE: This define should be added to the component's base error value and
|
||||
// standard error code(s) to define fatal error codes. For example:
|
||||
#define SP_ERR_FATAL_START 0xF00 // 0xF00-0xFFF: Fatal failures
|
||||
#define SP_ERR_FATAL_LAST 0xFFF // Last fatal error range value
|
||||
#define SP_IS_FATAL_ERROR(err) \
|
||||
((SP_GET_ERROR(err) >= SP_ERR_FATAL_START) && \
|
||||
(SP_GET_ERROR(err) <= SP_ERR_FATAL_LAST))
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SMART Self Test error codes
|
||||
//
|
||||
|
||||
// return values from ATA disk SMART test
|
||||
#define SP_SMART_OK 0x00 // no error
|
||||
#define SP_SMART_ABORTED 0x01 // aborted by host
|
||||
#define SP_SMART_RESET 0x02 // reset by host
|
||||
#define SP_SMART_FATAL_ERROR 0x03 // fatal or unknown error
|
||||
#define SP_SMART_UNKNOWN_ERROR 0x04 // unknown error
|
||||
#define SP_SMART_ELECTRICAL_ERROR 0x05 // electrical error
|
||||
#define SP_SMART_SERVO_ERROR 0x06 // servo error
|
||||
#define SP_SMART_READ_ERROR 0x07 // read error
|
||||
#define SP_SMART_RESERVED_8 0x08 // reserved
|
||||
#define SP_SMART_RESERVED_E 0x0E // reserved
|
||||
// 8 - 14 reserved, assume they indicate error
|
||||
#define SP_SMART_IN_PROGRESS 0x0F // test in progress
|
||||
#define SP_SMART_CANCELLED_BY_USER 0x10 // user cancelled test
|
||||
|
||||
// return values from test routine, simplified version of above errors
|
||||
// if everything is ok, we return SP_SMART_OK
|
||||
#define SP_SMART_RESCAN 0x01 // incomplete scan, try again
|
||||
#define SP_SMART_DEADBEEF 0x02 // dead as a doornail
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Version Structure
|
||||
//
|
||||
typedef UInt32 spVersion_t, *pspVersion_t;
|
||||
|
||||
#define SP_VERSION_MAJOR_NUM_MASK 0xFF000000
|
||||
#define SP_VERSION_MAJOR_NUM_SHIFT 24
|
||||
|
||||
#define SP_VERSION_MINOR_NUM_MASK 0x00FF0000
|
||||
#define SP_VERSION_MINOR_NUM_SHIFT 16
|
||||
|
||||
#define SP_VERSION_COMPATIBILITY_MASK 0x0000FFFF
|
||||
#define SP_VERSION_COMPATIBILITY_SHIFT 0
|
||||
|
||||
#define SP_VERSION_GET_MAJOR_NUM(v) (((v) & SP_VERSION_MAJOR_NUM_MASK ) >> \
|
||||
SP_VERSION_MAJOR_NUM_SHIFT )
|
||||
#define SP_VERSION_GET_MINOR_NUM(v) (((v) & SP_VERSION_MINOR_NUM_MASK ) >> \
|
||||
SP_VERSION_MINOR_NUM_SHIFT )
|
||||
#define SP_VERSION_GET_COMPATIBILITY(v) (((v) & SP_VERSION_COMPATIBILITY_MASK ) >> \
|
||||
SP_VERSION_COMPATIBILITY_SHIFT)
|
||||
|
||||
#define SP_VERSION(mj, mn, c ) ( ( ( (mj ) << SP_VERSION_MAJOR_NUM_SHIFT ) & \
|
||||
SP_VERSION_MAJOR_NUM_MASK ) | \
|
||||
( ( (mn ) << SP_VERSION_MINOR_NUM_SHIFT ) & \
|
||||
SP_VERSION_MINOR_NUM_MASK ) | \
|
||||
( ( (c ) << SP_VERSION_COMPATIBILITY_SHIFT ) & \
|
||||
SP_VERSION_COMPATIBILITY_MASK ) )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Memory heap
|
||||
//
|
||||
|
||||
typedef struct tagspboardMemHeap_t
|
||||
{
|
||||
pVoid pvHeapBase;
|
||||
UInt32 cbHeapSize;
|
||||
|
||||
}spboardMemHeap_t,*pspboardMemHeap_t;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// HW Unit Selection
|
||||
//
|
||||
typedef enum tagspUnitSelect_t
|
||||
{
|
||||
spUnitNone = -1,
|
||||
spUnit0 = 0,
|
||||
spUnit1 = 1,
|
||||
spUnit2 = 2,
|
||||
spUnit3 = 3,
|
||||
spUnit4 = 4
|
||||
|
||||
} spUnitSelect_t, *pspUnitSelect_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Boot Modes
|
||||
//
|
||||
typedef enum
|
||||
{
|
||||
spBootModeRetail = 1,
|
||||
spBootModeDebug = 2,
|
||||
spBootModeUiShell = 3,
|
||||
spBootModeDiag = 4,
|
||||
spBootModeDisk = 5,
|
||||
spBootModeScan = 6,
|
||||
spBootModeSleepTest = 7,
|
||||
spBootModeReset = 8
|
||||
} spBootMode_t, *pspBootMode_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CPU_13_5MHz = 13500,
|
||||
CPU_24MHz = 24000,
|
||||
CPU_36MHz = 36000,
|
||||
CPU_48MHz = 48000,
|
||||
CPU_64MHz = 64000,
|
||||
CPU_80MHz = 80000,
|
||||
CPU_90MHz = 90000
|
||||
} spCpuMHz_t, *pspCpuMHz_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Instance and handle
|
||||
//
|
||||
typedef UInt32 spInstance_t, *pspInstance_t;
|
||||
typedef UInt32 spHandle_t, *pspHandle_t;
|
||||
|
||||
#define SP_INVALID_HANDLE ((spHandle_t)-1)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Device flags
|
||||
//
|
||||
#define SP_HW_DEVICE_RAM 0x00000001
|
||||
#define SP_HW_DEVICE_SDRAM 0x00000002
|
||||
#define SP_HW_DEVICE_FLASH 0x00000004
|
||||
#define SP_HW_DEVICE_IDE 0x00000008
|
||||
#define SP_HW_DEVICE_UART1 0x00000010
|
||||
#define SP_HW_DEVICE_UART2 0x00000020
|
||||
#define SP_HW_DEVICE_LCD 0x00000040
|
||||
#define SP_HW_DEVICE_FIREWIRE 0x00000080
|
||||
#define SP_HW_DEVICE_GPIO 0x00000100
|
||||
#define SP_HW_DEVICE_LEDS 0x00000200
|
||||
#define SP_HW_DEVICE_PIEZO 0x00000400
|
||||
#define SP_HW_DEVICE_CODEC 0x00000800
|
||||
#define SP_HW_DEVICE_A2D 0x00001000
|
||||
|
||||
#define SP_HW_DEVICE_ALL 0xFFFFFFFF
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// System config structure location.
|
||||
//
|
||||
|
||||
#define SP_SYSCONFIG_START_FLASH_ADDRESS_GRPA 0x2000
|
||||
#define SP_SYSCONFIG_END_FLASH_ADDRESS_GRPA 0x4000
|
||||
#define SP_SYSCONFIG_START_FLASH_ADDRESS_GRPB 0x4000
|
||||
#define SP_SYSCONFIG_END_FLASH_ADDRESS_GRPB 0x6000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// System Information Structure
|
||||
//
|
||||
|
||||
#define SP_FLASH_VERSION_OFFSET 0x4040
|
||||
#define SP_FLASH_VERSION_MAGIC 'srev'
|
||||
|
||||
#define SP_SYSINFO_MAGIC 'SysI'
|
||||
|
||||
typedef struct tagspSysInfoAddr_t
|
||||
{
|
||||
UInt32 magic;
|
||||
UInt32 addr;
|
||||
|
||||
}spSysInfoAddr_t,*pspSysInfoAddr_t;
|
||||
|
||||
#define SP_SYSINFO_BOARDHWNAME_SIZE 16 // SCSI INQ depends on this!
|
||||
#define SP_SYSINFO_SERIALNUM_SIZE 32
|
||||
#define SP_SYSINFO_FIREWIREGUID_SIZE 16
|
||||
#define SP_SYSINFO_UNITCHARACTER_SIZE 16
|
||||
#define SP_SYSINFO_MODELNUM_SIZE 16
|
||||
#define SP_SYSINFO_HWOPTIONS1_SIZE 16
|
||||
#define SP_SYSINFO_CONTRAST_SIZE 16
|
||||
#define SP_SYSINFO_BACKLIGHT_SIZE 16
|
||||
#define SP_SYSINFO_DRMCONFIG_SIZE 16
|
||||
|
||||
#define SP_SYSINFO_MAX_MEM_RANGES 8
|
||||
#define SP_SYSINFO_MAX_BATTERY_CAL 4
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kSysInfoAddrRangeNone = 0,
|
||||
kSysInfoAddrRangeFlash = 'Flsh',
|
||||
kSysInfoAddrRangeSdram = 'Sdrm',
|
||||
kSysInfoAddrRangeFirewire = 'Frwr',
|
||||
kSysInfoAddrRangeIram = 'Iram',
|
||||
kSysInfoAddrRangeHdd0 = 'hdd0',
|
||||
kSysInfoAddrRangeHdd1 = 'hdd1'
|
||||
|
||||
}spSysInfoAddrRangeType_t;
|
||||
|
||||
typedef struct tagspBattA2DCal_t
|
||||
{
|
||||
UInt32 voltage; // Fix point format 16bit.16bit
|
||||
UInt32 a2d;
|
||||
|
||||
}spBattA2DCal_t,*pspBattA2DCal_t;
|
||||
|
||||
#define SP_SYSCFG_BATTERY_CAL_VERSION 1
|
||||
|
||||
typedef struct tagrtcAdjustKeyValueFormat_t
|
||||
{
|
||||
UInt32 version;
|
||||
UInt32 secPerDay; // Signed fix point format 16bit.16bit
|
||||
|
||||
}rtcAdjustKeyValueFormat_t, *prtcAdjustKeyValueFormat_t;
|
||||
|
||||
#define SP_SYSCFG_RTC_ADJUST_VERSION 1
|
||||
|
||||
typedef struct tagbatteryA2DCalKeyValueFormat_t
|
||||
{
|
||||
UInt32 version;
|
||||
UInt32 voltage; // Signed fix point format 16bit.16bit
|
||||
UInt32 a2d;
|
||||
|
||||
}batteryA2DCalKeyValueFormat_t, *pbatteryA2DCalKeyValueFormat_t;
|
||||
|
||||
//
|
||||
// Region codes and policy flags
|
||||
//
|
||||
#define SP_SYSCFG_REGION_VERSION 1
|
||||
#define SP_SYSCFG_REGION_POLICY_BYTES 2
|
||||
#define SP_SYSCFG_REGION_VENDOR_MASK 0xC0
|
||||
|
||||
// NOTE: HP adds the high bit '0x80' to a given region code to avoid adding a string
|
||||
// to the model number, but still allowing for region differentiation
|
||||
enum
|
||||
{
|
||||
kSyscfgRegionVendor_Apple = 0x00,
|
||||
kSyscfgRegionVendor_HP = 0x80
|
||||
};
|
||||
|
||||
// Check Wiki for most up-to-date list (v1.5, 3/10/06)
|
||||
// http://spgserver.apple.com/Ipodwiki/wiki?Region_Codes
|
||||
enum // Needs to fit in 16bit!
|
||||
{
|
||||
// Regions (Apple - 0x00) // Regions (HP - 0x80)
|
||||
kSyscfgRegion_World = 0x00,// Unassigned // Unassigned
|
||||
|
||||
kSyscfgRegion_NorthAmerica = 0x01,// LL = US/Canada // ABA = US/Canada
|
||||
kSyscfgRegion_Japan = 0x02,// J = Japanese Only
|
||||
kSyscfgRegion_FrenchGerman = 0x03,// FD = French (F), German (D), Swiss, Austria
|
||||
kSyscfgRegion_ItalianDutch = 0x04,// TN = Italian (T), Dutch (N), Belgium
|
||||
kSyscfgRegion_SpanishBrazilian = 0x05,// Y = Spanish (Y), Brazilian Portuguese (BR)
|
||||
kSyscfgRegion_SwedishNorwegian = 0x06,// S = Swedish (S), Norwegian (H)
|
||||
kSyscfgRegion_DanishFinnish = 0x07,// DK = Danish (DK), Finnish (K)
|
||||
kSyscfgRegion_ChineseHongKong = 0x08,// CH = Chinese (CH), Hong Kong
|
||||
kSyscfgRegion_Korean = 0x09,// KH = Korean (KH)
|
||||
|
||||
kSyscfgRegion_Canada = 0x0A,// C = Canada // ABC = Canada
|
||||
kSyscfgRegion_LatinAmerica = 0x0B,// E = Latin America // ABM = Latin America
|
||||
kSyscfgRegion_UnitedKingdom = 0x0C,// B = United Kingdom // ABU = United Kingdom
|
||||
kSyscfgRegion_Europe = 0x0D,// Z = Rest of Europe
|
||||
kSyscfgRegion_Australia = 0x0E,// X = Australia, New Zealand
|
||||
kSyscfgRegion_HongKongSingapore = 0x0F,// FE = HongKong, Singapore
|
||||
kSyscfgRegion_Taiwan = 0x10,// TA = Taiwan
|
||||
kSyscfgRegion_ZV = 0x11,// ZV = Europe (British, Swedish, Spanish, Danish)
|
||||
kSyscfgRegion_ZR = 0x12,// ZR = Europe (French, German, Dutch, Italian) // B19 = Europe (French, German, Dutch, Italian)
|
||||
kSyscfgRegion_SouthAsia = 0x13,// ZP = Singapore, South Asia
|
||||
// kSyscfgRegion_Spanish_Q98 = 0x13,// Y = Spanish (Y) [Q98 ONLY]
|
||||
kSyscfgRegion_HongKong = 0x14,// HK = Hong Kong (HK)
|
||||
// kSyscfgRegion_KoreaTaiwan_Q98 = 0x14,// PA = Korean, Taiwanise [Q98 ONLY]
|
||||
kSyscfgRegion_Spanish = 0x15,// Y = Spanish (Y) // ABE = Spanish (Y)
|
||||
kSyscfgRegion_Chinese = 0x16,// CH = Chinese (CH)
|
||||
kSyscfgRegion_KoreanTaiwanese = 0x17,// PA = Korean, Taiwanese // AB2 = Korean, Taiwanese
|
||||
kSyscfgRegion_French = 0x18,// F = French // ABF = French
|
||||
kSyscfgRegion_German = 0x19,// D = German // ABD = German
|
||||
kSyscfgRegion_SouthAfrica = 0x1A,// FB = CEMEA, South Africa
|
||||
kSyscfgRegion_DutchBelgium = 0x1B,// NF = Dutch (N), Belgium
|
||||
kSyscfgRegion_SpanishItalian = 0x1C,// TY = Spanish, (Y) Italian (T)
|
||||
kSyscfgRegion_Brazil = 0x1D,// YP = Brazil
|
||||
kSyscfgRegion_Portugal = 0x1E,// PZ = Portugal
|
||||
|
||||
kSyscfgRegion_LimitValue
|
||||
};
|
||||
|
||||
enum // Needs to fit in 16bit!
|
||||
{
|
||||
kSyscfgRegionPolicyFlag_None = 0x0000,
|
||||
kSyscfgRegionPolicyFlag_EU = 0x0001, // "French" volume problem
|
||||
kSyscfgRegionPolicyFlag_TVOut = 0x0006 // Two bits, PAL = 00, NTSC = 01
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kSyscfgRegionPolicyFlag_TVOut_PAL = (0 << 1),
|
||||
kSyscfgRegionPolicyFlag_TVOut_NTSC = (1 << 1)
|
||||
};
|
||||
|
||||
typedef struct tagregionKeyValueFormat_t
|
||||
{
|
||||
UInt16 version; // SP_SYSCFG_REGION_VERSION
|
||||
UInt8 reserve;
|
||||
UInt8 PolicySizeBytes; // Currently 2
|
||||
|
||||
UInt16 regionCode;
|
||||
UInt16 policyFlags;
|
||||
|
||||
}regionKeyValueFormat_t,*pregionKeyValueFormat_t;
|
||||
|
||||
typedef struct tagunitCharacteristicsFormat_t
|
||||
{
|
||||
// this structure maps on to data provided in flash
|
||||
UInt8 revision;
|
||||
UInt8 bytesOfValidData;
|
||||
|
||||
UInt16 oemVendorId; // little endian
|
||||
UInt32 color; // little endian
|
||||
UInt8 reserved[8];
|
||||
|
||||
}unitCharacteristicsFormat_t,*punitCharacteristicsFormat_t;
|
||||
|
||||
// Add stuff at end to maximize compatibility with old bootloaders
|
||||
typedef struct tagspSysInfo_t
|
||||
{
|
||||
UInt32 magic;
|
||||
UInt32 size;
|
||||
|
||||
UInt8 pszBoardHwName [ SP_SYSINFO_BOARDHWNAME_SIZE ];
|
||||
UInt8 pszSerialNumber[ SP_SYSINFO_SERIALNUM_SIZE ];
|
||||
UInt8 pu8FirewireGuid64[ SP_SYSINFO_FIREWIREGUID_SIZE ];
|
||||
|
||||
// Board Version
|
||||
spVersion_t boardHwRev;
|
||||
|
||||
// SW Versions
|
||||
spVersion_t bootLoaderImageRev;
|
||||
spVersion_t diskModeImageRev;
|
||||
spVersion_t diagImageRev;
|
||||
spVersion_t osImageRev;
|
||||
|
||||
//
|
||||
// Number of Voltage / Analog-to-Digital calibration
|
||||
// points.
|
||||
//
|
||||
UInt32 ccBattA2DCal;
|
||||
spBattA2DCal_t battA2DCal[SP_SYSINFO_MAX_BATTERY_CAL];
|
||||
|
||||
//
|
||||
// Currection to RTC drift due to constant PLL error.
|
||||
// Seconds per day.
|
||||
//
|
||||
Int32 RtcAdjustSecondsPerDay; // Signed fix point
|
||||
// format 16bit.16bit
|
||||
|
||||
// Board Sw Interface Revision
|
||||
spVersion_t boardHwSwInterfaceRev;
|
||||
|
||||
// HDD Firmware version string
|
||||
UInt8 pszHddFirmwareVersion[ 9 ];
|
||||
|
||||
// Region and Policy flags
|
||||
UInt16 regionCode;
|
||||
UInt32 policyFlags;
|
||||
|
||||
UInt8 pszModelNumStr [ SP_SYSINFO_MODELNUM_SIZE ];
|
||||
|
||||
UInt8 hardwareOptions1[SP_SYSINFO_HWOPTIONS1_SIZE];
|
||||
|
||||
Int8 contrastAdjBLOff;
|
||||
Int8 contrastAdjBLOn;
|
||||
Int8 backlightAdjCenter;
|
||||
Int8 backlightAdjSwing;
|
||||
unitCharacteristicsFormat_t unitCharacteristics;
|
||||
// Drive Low Power Cut Off
|
||||
UInt16 hddVoltageCutoff;
|
||||
|
||||
UInt8 drmConfig[SP_SYSINFO_DRMCONFIG_SIZE];
|
||||
|
||||
// Info on memory sizes, properly determined
|
||||
UInt32 SDRAMSize;
|
||||
UInt32 SDRAMBase;
|
||||
UInt32 IRAMSize;
|
||||
UInt32 IRAMBase;
|
||||
UInt32 FlashSize;
|
||||
UInt32 FlashBase;
|
||||
UInt32 NANDSizeTag; // Tag to help Diagnostics to find NAND size info
|
||||
UInt32 NANDTotalLBA;
|
||||
Int32 NANDBlockSize; // negtive number to indicate error
|
||||
|
||||
}spSystemInformation_t,*pspSystemInformation_t;
|
||||
|
||||
#define SYSINFO_BOARDHWREV 1
|
||||
#define SYSINFO_BOOTLOADERIMAGEREV 2
|
||||
#define SYSINFO_DISKMODEIMAGEREF 3
|
||||
#define SYSINFO_DIAGIMAGEREV 4
|
||||
#define SYSINFO_OSIMAGEREV 5
|
||||
|
||||
|
||||
#define SP_SYSCFG_KEY_SERIALNUM 'SrNm'
|
||||
#define SP_SYSCFG_KEY_FIREWIREGUID 'FwId'
|
||||
#define SP_SYSCFG_KEY_HWID 'HwId'
|
||||
#define SP_SYSCFG_KEY_HWIFVERSION 'HwVr'
|
||||
#define SP_SYSCFG_KEY_HWNAME 'HwNm'
|
||||
#define SP_SYSCFG_KEY_BATTERY_CAL 'Btry'
|
||||
#define SP_SYSCFG_KEY_RTC_ADJUST 'RtcA'
|
||||
#define SP_SYSCFG_KEY_REGION 'Regn'
|
||||
#define SP_SYSCFG_KEY_MODELNUM 'Mod#'
|
||||
#define SP_SYSCFG_KEY_HWOPTS1 'HwO1'
|
||||
#define SP_SYSCFG_KEY_CONTRAST 'Cont'
|
||||
#define SP_SYSCFG_KEY_UNITCHARACTER 'UntC'
|
||||
#define SP_SYSCFG_KEY_BACKLIGHT 'BkLt'
|
||||
#define SP_SYSCFG_KEY_DRMCONFIG 'DrmV'
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Image Manager types
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#define BT_IMAGE_TYPE_DIAG 'diag'
|
||||
#define BT_IMAGE_TYPE_OS 'osos'
|
||||
#define BT_IMAGE_TYPE_DISKMODE 'disk'
|
||||
#define BT_IMAGE_TYPE_SCANMODE 'scan'
|
||||
#define BT_IMAGE_TYPE_UPDATE 'aupd'
|
||||
#define BT_IMAGE_TYPE_BOOTLOGO 'logo'
|
||||
#define BT_IMAGE_VIDEOCORE_BOOT 'vmcs'
|
||||
#define BT_IMAGE_TYPE_HIBERNATE 'hibe'
|
||||
#define BT_IMAGE_TYPE_RESOURCE 'rsrc'
|
||||
#define BT_IMAGE_TYPE_GRAPE 'grpe'
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Image Manager types
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
#define BT_IMAGE_LOGO_MAGIC 'LoGo'
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Cpu Profile Interval type
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#define SP_PROFILE_EVENT_CPU_0 0
|
||||
#define SP_PROFILE_EVENT_COP_0 1
|
||||
|
||||
typedef struct tagpspProfileContext_t
|
||||
{
|
||||
UInt32 id;
|
||||
UInt32 maskEnable;
|
||||
Bool bEnable;
|
||||
|
||||
UInt32 triggerPin;
|
||||
UInt32 signalPin;
|
||||
|
||||
UInt32 signalPinAddr;
|
||||
UInt32 signalPinMask;
|
||||
|
||||
UInt32 start;
|
||||
UInt32 end;
|
||||
|
||||
Bool bHigh;
|
||||
|
||||
UInt32 HiTime;
|
||||
UInt32 LoTime;
|
||||
|
||||
}spProfileContext_t, *pspProfileContext_t;
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// The target image is passed this 32bit flags word from the Bootloader
|
||||
//
|
||||
#define SP_IMAGE_FLAGS_ADDR_PTR_OFFSET 0x10 // - 0x17
|
||||
|
||||
#define SP_IMAGE_NONE_FLAG 0x00000000
|
||||
#define SP_IMAGE_REBOOT_INTO_DISKMODE_FLAG 0x00000001
|
||||
#define SP_IMAGE_REBOOT_INTO_RETAILMODE_FLAG 0x00000002
|
||||
#define SP_IMAGE_USER_KEY_PRESS_FLAG 0x00000004
|
||||
#define SP_IMAGE_HIBERNATE_FLAG 0x00000008
|
||||
#define SP_IMAGE_BANGFOLDER 0x00000010
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// System info structure pointer has been moved up into the special space now.
|
||||
//
|
||||
|
||||
#define SP_SYSINFO_ADDR_PTR_OFFSET 0x18 // - 0x1F
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Storage area for RTC reference time across boots.
|
||||
//
|
||||
|
||||
#define SP_RTC_REF_TIME_STRUCT_OFFSET 0x20 // - 0x2B
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// COP publishes its exception status in this area.
|
||||
// Reserved for see t_watchdog.h.
|
||||
// #define SP_COP_EXCEPTION_STATUS_OFFSET 0x2C // - 0x2F
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Storage area for Locale information to communicate to DiskMode.
|
||||
//
|
||||
|
||||
#define SP_LOCALE_TYPE_PTR_OFFSET 0x30 // - 0x33
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __SPTYPES_H__ //------------------
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V_Print.h"
|
||||
//#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
|
||||
L2V_t L2V;
|
||||
|
||||
|
||||
#define LAST_TREE_TEST 16
|
||||
#define SIMPLE_SIZE (L2V_TREE_SIZE*LAST_TREE_TEST)
|
||||
|
||||
|
||||
|
||||
// Prototypes
|
||||
static void RandomTest(void);
|
||||
static void SequentialTest(void);
|
||||
static void Simple_Init(void);
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vpn);
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vpn);
|
||||
|
||||
static void Seed_Local_Rand(UInt32 seed);
|
||||
static UInt32 Get_Local_Rand(void);
|
||||
static UInt32 _current_rand = 0;
|
||||
|
||||
|
||||
|
||||
void Usage(int argc, char** argv)
|
||||
{
|
||||
printf("Usage: %s s OR %s r (for sequential and random, respectively\n", argv[0], argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int test = 0;
|
||||
|
||||
#if 0
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
L2V_Init(SIMPLE_SIZE, (L2V_VPN_SPECIAL-1) / 8192, 8192);
|
||||
|
||||
if (argc == 2) {
|
||||
if ('r' == argv[1][0]) {
|
||||
test = 0;
|
||||
} else if ('s' == argv[1][0]) {
|
||||
test = 1;
|
||||
} else {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
}
|
||||
if (argc > 2) {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
|
||||
if (0 == test) {
|
||||
RandomTest();
|
||||
} else {
|
||||
SequentialTest();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAXLEN 512
|
||||
void L2VRandomTest() {
|
||||
UInt32 lba, size, vpn;
|
||||
UInt32 i;
|
||||
L2V_SearchCtx_t c;
|
||||
UInt32 iterations = 1000000;
|
||||
|
||||
L2V_Init(SIMPLE_SIZE, (L2V_VPN_SPECIAL-1) / 8192, 8192);
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Seed_Local_Rand(12345);
|
||||
|
||||
while (iterations--) {
|
||||
lba = Get_Local_Rand() % ((L2V_TREE_SIZE*LAST_TREE_TEST)-MAXLEN);
|
||||
size = (Get_Local_Rand() % (MAXLEN-1))+1;
|
||||
vpn = Get_Local_Rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
|
||||
// 1 write
|
||||
L2V_Update(lba, size, vpn);
|
||||
|
||||
// 5 reads
|
||||
for (i = 0; i < 5; ++i)
|
||||
{
|
||||
c.lba = Get_Local_Rand() % ((L2V_TREE_SIZE*LAST_TREE_TEST)-MAXLEN);
|
||||
L2V_Search(&c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SequentialTest() {
|
||||
UInt32 lba, size, vpn;
|
||||
UInt32 i, svpn;
|
||||
L2V_SearchCtx_t c;
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Simple_Init();
|
||||
|
||||
Seed_Local_Rand(12345);
|
||||
|
||||
lba = 0;
|
||||
size = 0;
|
||||
vpn = 1;
|
||||
|
||||
while (1) {
|
||||
lba += size;
|
||||
size = (Get_Local_Rand() % (MAXLEN-1))+1;
|
||||
if ((lba + size) >= L2V_TREE_SIZE) {
|
||||
lba = 0;
|
||||
}
|
||||
if ((Get_Local_Rand() & 3) == 0) {
|
||||
vpn = Get_Local_Rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
}
|
||||
while (((vpn + size) & ((1<<(L2V_BITS_VPN-1))-1)) < vpn) {
|
||||
vpn = Get_Local_Rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
}
|
||||
|
||||
printf("[UPD: lba:%d, size:%d, vpn:%d]\n", lba, size, vpn);
|
||||
L2V_Update(lba, size, vpn);
|
||||
Simple_Update(lba, size, vpn);
|
||||
L2V_PrintUsage(0);
|
||||
vpn += size;
|
||||
|
||||
|
||||
// Validate entire range
|
||||
unsigned int maxlevel=0;
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_Lookup(i, &svpn);
|
||||
c.lba = i;
|
||||
L2V_Search(&c);
|
||||
if (c.level > maxlevel) maxlevel = c.level;
|
||||
if (svpn != c.vpn) {
|
||||
printf("\n\n\n");
|
||||
printf("====================\n");
|
||||
printf("MISMATCH lba:%d\n", i);
|
||||
printf("--------------------\n");
|
||||
printf("Simple vpn:%d\n", svpn);
|
||||
printf("Lookup vpn:%d\n", c.vpn);
|
||||
}
|
||||
l2v_assert_eq(svpn, c.vpn);
|
||||
}
|
||||
printf("maxlevel: %d\n", maxlevel);
|
||||
l2v_assert_lt(maxlevel, L2V_MAX_TREE_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 Simple_vpn[SIMPLE_SIZE];
|
||||
|
||||
static void Simple_Init()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_vpn[i] = L2V_VPN_MISS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vpn)
|
||||
{
|
||||
while (size) {
|
||||
Simple_vpn[lba] = vpn;
|
||||
|
||||
// Iterate
|
||||
lba++;
|
||||
if (vpn < L2V_VPN_SPECIAL) {
|
||||
vpn++;
|
||||
}
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vpn)
|
||||
{
|
||||
*vpn = Simple_vpn[lba];
|
||||
}
|
||||
|
||||
|
||||
static void Seed_Local_Rand(UInt32 seed)
|
||||
{
|
||||
_current_rand = seed;
|
||||
}
|
||||
static UInt32 Get_Local_Rand(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 17; ++i)
|
||||
{
|
||||
_current_rand = (_current_rand >> 1) ^ (UInt32)((0 - (_current_rand & 1u)) & 0xd0000001u);
|
||||
}
|
||||
return _current_rand;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Apple, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Computer, 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 Computer, Inc.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys.h>
|
||||
#include <sys/menu.h>
|
||||
|
||||
#if defined(WITH_MENU) && WITH_MENU
|
||||
|
||||
extern void L2VRandomTest(void);
|
||||
|
||||
static int do_l2v(int argc, struct cmd_arg *args)
|
||||
{
|
||||
UInt64 start = system_time();
|
||||
L2VRandomTest();
|
||||
printf("test time: %lldus\n", system_time() - start);
|
||||
return(0);
|
||||
}
|
||||
MENU_COMMAND_DEBUG(l2v, do_l2v, "run l2v benchmark", NULL);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
# Copyright (C) 2010 Apple, Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Computer, 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 Computer, Inc.
|
||||
#
|
||||
|
||||
#
|
||||
# L2V Test Benchmark
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
NAND_DIR := $(dir $(GET_LOCAL_DIR))
|
||||
L2V_DIR := $(NAND_DIR)/raw/Whimory/Core/FTL/L2V
|
||||
|
||||
MODULES += drivers/flash_nand/OAM
|
||||
|
||||
GLOBAL_INCLUDES += $(L2V_DIR)
|
||||
|
||||
OPTIONS += ENABLE_L2V_TREE=1
|
||||
|
||||
ALL_OBJS +=\
|
||||
$(LOCAL_DIR)/benchmark.o \
|
||||
$(LOCAL_DIR)/L2V_Test.o \
|
||||
$(L2V_DIR)/L2V_Forget.o \
|
||||
$(L2V_DIR)/L2V_Free.o \
|
||||
$(L2V_DIR)/L2V_Funcs.o \
|
||||
$(L2V_DIR)/L2V_Init.o \
|
||||
$(L2V_DIR)/L2V_Mem.o \
|
||||
$(L2V_DIR)/L2V_Print.o \
|
||||
$(L2V_DIR)/L2V_Repack.o \
|
||||
$(L2V_DIR)/L2V_Search.o \
|
||||
$(L2V_DIR)/L2V_Types.o \
|
||||
$(L2V_DIR)/L2V_Update.o \
|
||||
$(L2V_DIR)/L2V_Valid.o
|
||||
|
||||
IOP_HEAP_REQUIRED := $(call ADD,$(IOP_HEAP_REQUIRED),1048576)
|
||||
|
||||
@@ -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
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2010 Apple Inc. All rights reserved.
|
||||
* Copyright (c) 2006 Apple Computer, 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 <debug.h>
|
||||
#include <drivers/flash_nand.h>
|
||||
|
||||
#include "FIL.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
extern int ppn_init(void);
|
||||
extern int raw_nand_init(void);
|
||||
|
||||
uint32_t nand_fsys_block_offset = WMR_BOOT_AREA_DEFAULT_SIZE;
|
||||
|
||||
int flash_nand_init(void)
|
||||
{
|
||||
int ret = -1;
|
||||
LowFuncTbl *fil;
|
||||
|
||||
dprintf(DEBUG_INFO, "flash_nand_init()\n");
|
||||
|
||||
/* FIL_Init was already executed when flash_nand_id() was called in platform_late_init() */
|
||||
fil = FIL_GetFuncTbl();
|
||||
if ((NULL == fil) || (NULL == fil->GetDeviceInfo))
|
||||
{
|
||||
dprintf(DEBUG_INFO, "GetDeviceInfo not populated\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if WITH_PPN
|
||||
if (fil->GetDeviceInfo(AND_DEVINFO_PPN_DEVICE) > 0)
|
||||
{
|
||||
ret = ppn_init();
|
||||
}
|
||||
#if WITH_RAW_NAND
|
||||
else
|
||||
#endif // HAS_RAW_NAND
|
||||
#endif
|
||||
#if WITH_RAW_NAND
|
||||
{
|
||||
ret = raw_nand_init();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (!WITH_RAW_NAND && !WITH_PPN)
|
||||
#error nand.c included without a raw or ppn stack
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# 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_FILESYSTEM=1
|
||||
|
||||
MODULES += \
|
||||
drivers/flash_nand
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/nand.o
|
||||
|
||||
WITH_NAND_FTL := true
|
||||
@@ -0,0 +1,723 @@
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if WMR_BUILDING_IBOOT
|
||||
#include "nandid.h"
|
||||
#include <drivers/nand_device_tree.h>
|
||||
#include <target/nand_spec_tables.h>
|
||||
#include <sys.h>
|
||||
#include <debug.h>
|
||||
#else
|
||||
#include "NandSpec.h"
|
||||
#include "NandSpecTables.h"
|
||||
#endif
|
||||
|
||||
#include "WMROAM.h"
|
||||
#include "FIL.h"
|
||||
|
||||
// =============================================================================
|
||||
// Preprocessor Definitions
|
||||
|
||||
#define WITH_NAND_DT_CONFIG (WITH_NAND_FILESYSTEM && WITH_DEVICETREE)
|
||||
|
||||
// =============================================================================
|
||||
// Extern global variables
|
||||
|
||||
// =============================================================================
|
||||
// Private Function Declarations
|
||||
|
||||
static BOOL32 isSameChipId(const NandChipId chipId1, const NandChipId chipId2);
|
||||
static BOOL32 isSameConfigId(const NandConfigId* configId1, const NandConfigId* configId2);
|
||||
|
||||
static const NandGeometry* lookupNandGeometry(const NandChipId chipId);
|
||||
static const NandTiming* lookupNandTiming(const NandConfigId* configId);
|
||||
static const NandBoardSupport* lookupBoardSupport(const NandConfigId* configId);
|
||||
static BOOL32 isValidChipId(const NandChipId chipId);
|
||||
static BOOL32 getChipIdAndTotalCECountAndCEMap(const NandChipId* chipIds, NandChipId* foundChipId, UInt32* totalCECount, UInt32* ceMap);
|
||||
static BOOL32 areChipIdsIdentical(const NandChipId* chipIds, NandChipId* chipId);
|
||||
static UInt32 setBitCount(UInt32 x);
|
||||
static BOOL32 checkCESymmetryAndGetPackageCnt(NandLandingMap *landingMap, UInt32 ceMap, UInt8* pkgCnt);
|
||||
|
||||
// =============================================================================
|
||||
// Private Global Variables
|
||||
#if WITH_NAND_DT_CONFIG
|
||||
static NandInfo currentNandInfo;
|
||||
static UInt32 currentCECount = 0;
|
||||
static UInt32 currentCEBitmap = 0;
|
||||
static UInt32 currentActiveDataBus = 0;
|
||||
#endif //WITH_NAND_DT_CONFIG
|
||||
static UInt32 currentCorrectableBits = 0;
|
||||
static UInt32 currentRefreshThreshold = 0;
|
||||
static BOOL32 ppnDevice = FALSE32;
|
||||
static BOOL32 toggleDevice = FALSE32;
|
||||
static BOOL32 _retire_on_invalid_refresh;
|
||||
static void *_ppn_feature_list = NULL;
|
||||
static UInt32 _ppn_feature_size = 0;
|
||||
static void *_dbg_chipids_list = NULL;
|
||||
static UInt32 _dbg_chipids_size = 0;
|
||||
|
||||
static UInt32 _dqsHalfCycleClocks;
|
||||
static UInt32 _ceSetupClocks;
|
||||
static UInt32 _ceHoldClocks;
|
||||
static UInt32 _ADLClocks;
|
||||
static UInt32 _WHRClocks;
|
||||
|
||||
static UInt32 _readPreClocks;
|
||||
static UInt32 _readPostClocks;
|
||||
static UInt32 _writePreClocks;
|
||||
static UInt32 _writePostClocks;
|
||||
|
||||
static UInt32 _readSetupClocks;
|
||||
static UInt32 _readHoldClocks;
|
||||
static UInt32 _readDccycleClocks;
|
||||
static UInt32 _writeSetupClocks;
|
||||
static UInt32 _writeHoldClocks;
|
||||
|
||||
static UInt32 _regDQSTimingCtrl;
|
||||
|
||||
// =============================================================================
|
||||
// Local constants
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// Private Function Definitions
|
||||
|
||||
// compare the contents of a buffer to the given value, repeated
|
||||
static BOOL32 comparePattern(const UInt8 *buffer, UInt8 value, UInt32 length)
|
||||
{
|
||||
UInt32 idx;
|
||||
|
||||
for (idx = 0; idx < length; ++idx)
|
||||
{
|
||||
if (buffer[idx] != value)
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
static BOOL32 isSameChipId(const NandChipId chipId1,
|
||||
const NandChipId chipId2)
|
||||
{
|
||||
UInt32 idx;
|
||||
// Treat 0x00 as dont-care
|
||||
for (idx = 0; idx < COMPARE_NAND_CHIP_ID_SIZE; ++idx)
|
||||
{
|
||||
if (chipId1[idx] && chipId2[idx] && (chipId1[idx] != chipId2[idx]))
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
static BOOL32 isSameConfigId(const NandConfigId* configId1,
|
||||
const NandConfigId* configId2)
|
||||
{
|
||||
if (0 == WMR_MEMCMP(configId1, configId2, sizeof(NandConfigId)))
|
||||
{
|
||||
return TRUE32;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
|
||||
static const NandGeometry* lookupNandGeometry(const NandChipId chipId)
|
||||
{
|
||||
UInt32 count = sizeof(_nandGeometryTable) / sizeof(_nandGeometryTable[0]);
|
||||
UInt32 idx;
|
||||
|
||||
for (idx = 0; idx < count; idx++)
|
||||
{
|
||||
const NandGeometry* geometry = &_nandGeometryTable[idx];
|
||||
if (isSameChipId(chipId, geometry->chipId))
|
||||
{
|
||||
return geometry;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if AND_ENABLE_NAND_DESCRIPTION_TEXT
|
||||
static const NandDescription* lookupNandDescription(const NandPackageId* packageId)
|
||||
{
|
||||
UInt32 idx;
|
||||
|
||||
for (idx = 0; idx < _nandDescriptionTableSize; idx++)
|
||||
{
|
||||
const NandDescription* description = &_nandDescriptionTable[idx];
|
||||
if (isSamePackageId(packageId, &(description->packageId)))
|
||||
{
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const NandTiming* lookupNandTiming(const NandConfigId* configId)
|
||||
{
|
||||
UInt32 count = sizeof(_nandTimingTable) / sizeof(_nandTimingTable[0]);
|
||||
UInt32 idx;
|
||||
|
||||
for (idx = 0; idx < count; idx++)
|
||||
{
|
||||
const NandTiming* timing = &_nandTimingTable[idx];
|
||||
if (isSameConfigId(configId, &(timing->configId)))
|
||||
{
|
||||
return timing;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const NandBoardSupport* lookupBoardSupport(const NandConfigId* configId)
|
||||
{
|
||||
UInt32 count = sizeof(_nandBoardSupportTable) / sizeof(_nandBoardSupportTable[0]);
|
||||
UInt32 idx;
|
||||
|
||||
for (idx = 0; idx < count; idx++)
|
||||
{
|
||||
const NandBoardSupport* support = &_nandBoardSupportTable[idx];
|
||||
if (isSameConfigId(configId, &(support->configId)))
|
||||
{
|
||||
return support;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL32 isValidChipId(NandChipId const chipId)
|
||||
{
|
||||
if (comparePattern(&chipId[0], 0x00, NAND_CHIP_ID_SIZE) ||
|
||||
comparePattern(&chipId[0], 0xFF, NAND_CHIP_ID_SIZE))
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TRUE32;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL32 getChipIdAndTotalCECountAndCEMap(const NandChipId* chipIds, NandChipId* foundChipId, UInt32* totalCECount, UInt32* ceMap)
|
||||
{
|
||||
BOOL32 found = FALSE32;
|
||||
UInt32 i;
|
||||
|
||||
*ceMap = 0;
|
||||
*totalCECount = 0;
|
||||
|
||||
for (i = 0; i < NAND_MAX_CE_COUNT_TOTAL; i++)
|
||||
{
|
||||
if (isValidChipId(chipIds[i]))
|
||||
{
|
||||
if (!found)
|
||||
{
|
||||
WMR_MEMSET(foundChipId, 0, sizeof(NandChipId));
|
||||
WMR_MEMCPY(foundChipId, chipIds[i], VALID_NAND_CHIP_ID_SIZE);
|
||||
found = TRUE32;
|
||||
}
|
||||
(*totalCECount)++;
|
||||
(*ceMap) |= (1 << i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static BOOL32 areChipIdsIdentical(const NandChipId* chipIds, NandChipId* chipId)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < NAND_MAX_CE_COUNT_TOTAL; i++)
|
||||
{
|
||||
if (isValidChipId(chipIds[i]) && (!isSameChipId(*chipId, chipIds[i])))
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
static UInt32 setBitCount(UInt32 x)
|
||||
{
|
||||
// Count the ones
|
||||
UInt32 cnt = 0;
|
||||
|
||||
while (x)
|
||||
{
|
||||
if (x & 1)
|
||||
{
|
||||
cnt++;
|
||||
}
|
||||
x = x >> 1;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
static BOOL32 checkCESymmetryAndGetPackageCnt(NandLandingMap *landingMap, UInt32 ceMap, UInt8* pkgCnt)
|
||||
{
|
||||
UInt32 mask;
|
||||
UInt32 i = 0;
|
||||
UInt32 cePerPkg = setBitCount((*landingMap)[0] & ceMap);
|
||||
|
||||
*pkgCnt = 0;
|
||||
|
||||
do
|
||||
{
|
||||
mask = (*landingMap)[i];
|
||||
|
||||
if (mask & ceMap)
|
||||
{
|
||||
if (cePerPkg != setBitCount(mask & ceMap))
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
(*pkgCnt)++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
while (mask != 0);
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Public Function Definitions
|
||||
BOOL32 findNandInfo(const NandChipId* chipIds,
|
||||
NandInfo* nandInfo,
|
||||
const UInt32 numActiveDataBus)
|
||||
{
|
||||
NandConfigId detectedConfigId;
|
||||
NandChipId chipId;
|
||||
UInt32 totalCECount;
|
||||
UInt32 ceMap;
|
||||
UInt32 i;
|
||||
|
||||
nandInfo->boardInfo = &_nandBoardInfo;
|
||||
nandInfo->boardSupport = NULL;
|
||||
nandInfo->configTiming = NULL;
|
||||
nandInfo->format = &_nandFormatRaw;
|
||||
|
||||
WMR_MEMSET(&detectedConfigId, 0, sizeof(NandConfigId));
|
||||
|
||||
if (!getChipIdAndTotalCECountAndCEMap(chipIds, &chipId, &totalCECount, &ceMap))
|
||||
{
|
||||
WMR_PRINT(INIT, "No NAND Detected\n");
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
if (!areChipIdsIdentical(chipIds, &chipId))
|
||||
{
|
||||
WMR_PRINT(INIT, "Chip IDs not identical!\n");
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
if (!checkCESymmetryAndGetPackageCnt(&_nandBoardInfo.landingMap, ceMap, &(detectedConfigId.packageCnt)))
|
||||
{
|
||||
WMR_PRINT(INIT, "Chip IDs not symmetrical!\n");
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
detectedConfigId.connectedBusCnt = numActiveDataBus;
|
||||
|
||||
nandInfo->geometry = lookupNandGeometry(chipId);
|
||||
|
||||
if (!nandInfo->geometry)
|
||||
{
|
||||
WMR_PRINT(INIT, "Unknown Chip ID!\n");
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
for (i = 0; i < detectedConfigId.packageCnt; i++)
|
||||
{
|
||||
WMR_MEMCPY(&(detectedConfigId.packageIds[i].chipId), nandInfo->geometry->chipId, sizeof(NandChipId));
|
||||
detectedConfigId.packageIds[i].ceCnt = totalCECount / detectedConfigId.packageCnt;
|
||||
}
|
||||
|
||||
nandInfo->boardSupport = lookupBoardSupport(&detectedConfigId);
|
||||
nandInfo->configTiming = lookupNandTiming(&detectedConfigId);
|
||||
|
||||
if (!nandInfo->boardSupport)
|
||||
{
|
||||
WMR_PRINT(INIT, "Board support not found!\n");
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
if (!nandInfo->configTiming)
|
||||
{
|
||||
WMR_PRINT(INIT, "Nand timing not found!\n");
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
#if WITH_NAND_DT_CONFIG
|
||||
currentNandInfo = *nandInfo;
|
||||
currentCECount = totalCECount;
|
||||
currentCEBitmap = ceMap;
|
||||
currentActiveDataBus = numActiveDataBus;
|
||||
#endif //WITH_NAND_DT_CONFIG
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
void setECCLevels(UInt32 numCorrectableBits, UInt32 refreshThresholdBits)
|
||||
{
|
||||
currentCorrectableBits = numCorrectableBits;
|
||||
currentRefreshThreshold = refreshThresholdBits;
|
||||
}
|
||||
|
||||
#if WITH_NAND_DT_CONFIG
|
||||
void addNandProperty(DTNode *node, char *name, uint32_t value)
|
||||
{
|
||||
uint32_t propSize = 0;
|
||||
void *propData = NULL;
|
||||
|
||||
if (FindProperty(node, &name, &propData, &propSize) &&
|
||||
(propSize == sizeof(value)))
|
||||
{
|
||||
*(uint32_t*)propData = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
WMR_PRINT(ERROR, "Failed to find NAND property: %s\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
static void fillPpnFeatures(DTNode *node)
|
||||
{
|
||||
char *propName = "ppn-features";
|
||||
void *propData = NULL;
|
||||
UInt32 propSize = 0;
|
||||
UInt32 totalSize = sizeof(_ppn_feature_size) + _ppn_feature_size;
|
||||
UInt8 *cursor;
|
||||
|
||||
if (!FindProperty(node, &propName, &propData, &propSize) ||
|
||||
(totalSize > propSize))
|
||||
{
|
||||
WMR_PANIC("expected device tree property %s of at least %u bytes", propName, (unsigned)totalSize);
|
||||
}
|
||||
|
||||
cursor = propData;
|
||||
|
||||
WMR_MEMCPY(cursor, &_ppn_feature_size, sizeof(_ppn_feature_size));
|
||||
cursor += sizeof(_ppn_feature_size);
|
||||
|
||||
WMR_MEMCPY(cursor, _ppn_feature_list, _ppn_feature_size);
|
||||
cursor += _ppn_feature_size;
|
||||
}
|
||||
|
||||
static void fillNandPpnProperties(DTNode *node)
|
||||
{
|
||||
const NandPpn *ppn = currentNandInfo.ppn;
|
||||
|
||||
addNandProperty(node, "ppn-spec-version", ppn->specVersion);
|
||||
addNandProperty(node, "blocks-cau", ppn->blocksPerCau);
|
||||
addNandProperty(node, "caus-ce", ppn->causPerCe);
|
||||
addNandProperty(node, "slc-pages", ppn->slcPagesPerBlock);
|
||||
addNandProperty(node, "mlc-pages", ppn->mlcPagesPerBlock);
|
||||
addNandProperty(node, "match-oddeven-caus", ppn->matchOddEvenCaus);
|
||||
addNandProperty(node, "cau-bits", ppn->bitsPerCau);
|
||||
addNandProperty(node, "page-bits", ppn->bitsPerPage);
|
||||
addNandProperty(node, "block-bits", ppn->bitsPerBlock);
|
||||
addNandProperty(node, "max-transaction-size", ppn->maxTransactionSize);
|
||||
|
||||
fillPpnFeatures(node);
|
||||
}
|
||||
|
||||
static void fillDbgChipIds(DTNode *node)
|
||||
{
|
||||
char *propName = "dbg-chipids";
|
||||
void *propData = NULL;
|
||||
UInt32 propSize = 0;
|
||||
UInt32 totalSize = _dbg_chipids_size;
|
||||
UInt8 *cursor;
|
||||
|
||||
if (NULL == _dbg_chipids_list)
|
||||
{
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!FindProperty(node, &propName, &propData, &propSize) ||
|
||||
(totalSize > propSize))
|
||||
{
|
||||
WMR_PRINT(ERROR, "expected device tree property %s of at least %lu bytes", propName, totalSize);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cursor = propData;
|
||||
|
||||
WMR_MEMCPY(cursor, _dbg_chipids_list, _dbg_chipids_size);
|
||||
cursor += _dbg_chipids_size;
|
||||
|
||||
exit:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void fillNandConfigProperties(DTNode *node)
|
||||
{
|
||||
uint32_t propSize = 0;
|
||||
void *propData = NULL;
|
||||
char *propName = NULL;
|
||||
|
||||
if (0 == currentCECount) {
|
||||
fillDbgChipIds(node);
|
||||
return;
|
||||
}
|
||||
|
||||
// Configuration
|
||||
addNandProperty(node, "#ce", currentCECount);
|
||||
addNandProperty(node, "ce-bitmap", currentCEBitmap);
|
||||
|
||||
propName = "device-readid";
|
||||
if (FindProperty(node, &propName, &propData, &propSize) &&
|
||||
(propSize == NAND_CHIP_ID_SIZE))
|
||||
{
|
||||
WMR_MEMCPY(propData, currentNandInfo.geometry->chipId, NAND_CHIP_ID_SIZE);
|
||||
}
|
||||
|
||||
// Geometry
|
||||
addNandProperty(node, "#databus", currentActiveDataBus);
|
||||
addNandProperty(node, "#ce-blocks", currentNandInfo.geometry->blocksPerCS);
|
||||
addNandProperty(node, "#block-pages", currentNandInfo.geometry->pagesPerBlock);
|
||||
addNandProperty(node, "#page-bytes", currentNandInfo.geometry->dataBytesPerPage);
|
||||
addNandProperty(node, "#spare-bytes", currentNandInfo.geometry->spareBytesPerPage);
|
||||
addNandProperty(node, "#die-ce", currentNandInfo.geometry->diesPerCS);
|
||||
|
||||
// Formatting
|
||||
addNandProperty(node, "bbt-format", currentNandInfo.geometry->initialBBType);
|
||||
addNandProperty(node, "vendor-type", currentNandInfo.boardSupport->vsType);
|
||||
addNandProperty(node, "ecc-threshold", currentRefreshThreshold);
|
||||
addNandProperty(node, "ecc-correctable", currentCorrectableBits);
|
||||
|
||||
// Bus Timing
|
||||
addNandProperty(node, "read-setup-clks", _readSetupClocks);
|
||||
addNandProperty(node, "read-hold-clks", _readHoldClocks);
|
||||
addNandProperty(node, "read-dccycle-clks", _readDccycleClocks);
|
||||
addNandProperty(node, "write-setup-clks", _writeSetupClocks);
|
||||
addNandProperty(node, "write-hold-clks", _writeHoldClocks);
|
||||
|
||||
// NAND Format parameters
|
||||
addNandProperty(node, "meta-per-logical-page", currentNandInfo.format->metaPerLogicalPage);
|
||||
addNandProperty(node, "valid-meta-per-logical-page", currentNandInfo.format->validMetaPerLogicalPage);
|
||||
if (currentNandInfo.format->logicalPageSize == 0)
|
||||
{
|
||||
// Use native page size
|
||||
UInt32 pageSize = currentNandInfo.geometry->dataBytesPerPage;
|
||||
addNandProperty(node, "logical-page-size", pageSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
addNandProperty(node, "logical-page-size", currentNandInfo.format->logicalPageSize);
|
||||
}
|
||||
|
||||
if (toggleDevice)
|
||||
{
|
||||
addNandProperty(node, "toggle-device", 1);
|
||||
addNandProperty(node, "enable-diff-dqs", _nandBoardInfo.useDiffDQSMode);
|
||||
addNandProperty(node, "enable-diff-re", _nandBoardInfo.useDiffREMode);
|
||||
addNandProperty(node, "enable-vref", _nandBoardInfo.useVref);
|
||||
|
||||
addNandProperty(node, "dqs-half-cycle-clks", _dqsHalfCycleClocks);
|
||||
|
||||
addNandProperty(node, "ce-setup-clks", _ceSetupClocks);
|
||||
addNandProperty(node, "ce-hold-clks", _ceHoldClocks);
|
||||
addNandProperty(node, "adl-clks", _ADLClocks);
|
||||
addNandProperty(node, "whr-clks", _WHRClocks);
|
||||
|
||||
addNandProperty(node, "read-pre-clks", _readPreClocks);
|
||||
addNandProperty(node, "read-post-clks", _readPostClocks);
|
||||
addNandProperty(node, "write-pre-clks", _writePreClocks);
|
||||
addNandProperty(node, "write-post-clks", _writePostClocks);
|
||||
|
||||
addNandProperty(node, "reg-dqs-delay", _regDQSTimingCtrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
addNandProperty(node, "toggle-device", 0);
|
||||
}
|
||||
|
||||
if (ppnDevice == TRUE32)
|
||||
{
|
||||
addNandProperty(node, "ppn-device", 1);
|
||||
fillNandPpnProperties(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
addNandProperty(node, "ppn-device", 0);
|
||||
}
|
||||
|
||||
addNandProperty(node, "retire-on-invalid-refresh", _retire_on_invalid_refresh);
|
||||
|
||||
}
|
||||
|
||||
#endif //WITH_NAND_CONFIG
|
||||
|
||||
void reportToggleModeFMCTimingValues(UInt32 dqsHalfCycleClocks,
|
||||
UInt32 ceSetupClocks,
|
||||
UInt32 ceHoldClocks,
|
||||
UInt32 adlClocks,
|
||||
UInt32 whrClocks,
|
||||
UInt32 readPreClocks,
|
||||
UInt32 readPostClocks,
|
||||
UInt32 writePreClocks,
|
||||
UInt32 writePostClocks,
|
||||
UInt32 regDQSTimingCtrl)
|
||||
{
|
||||
_dqsHalfCycleClocks = dqsHalfCycleClocks;
|
||||
_ceSetupClocks = ceSetupClocks;
|
||||
_ceHoldClocks = ceHoldClocks;
|
||||
_ADLClocks = adlClocks;
|
||||
_WHRClocks = whrClocks;
|
||||
_readPreClocks = readPreClocks;
|
||||
_readPostClocks = readPostClocks;
|
||||
_writePreClocks = writePreClocks;
|
||||
_writePostClocks = writePostClocks;
|
||||
_regDQSTimingCtrl = regDQSTimingCtrl;
|
||||
}
|
||||
|
||||
void setToggleMode()
|
||||
{
|
||||
toggleDevice = TRUE32;
|
||||
}
|
||||
|
||||
|
||||
void reportFMCTimingValues(UInt32 readSetupClocks,
|
||||
UInt32 readHoldClocks,
|
||||
UInt32 readDccycleClocks,
|
||||
UInt32 writeSetupClocks,
|
||||
UInt32 writeHoldClocks)
|
||||
{
|
||||
_readSetupClocks = readSetupClocks;
|
||||
_readHoldClocks = readHoldClocks;
|
||||
_readDccycleClocks = readDccycleClocks;
|
||||
_writeSetupClocks = writeSetupClocks;
|
||||
_writeHoldClocks = writeHoldClocks;
|
||||
}
|
||||
|
||||
void setNandIdPpnConfig(const NandChipId* chipIds,
|
||||
NandInfo* nandInfo,
|
||||
UInt32 busses,
|
||||
UInt32 ces)
|
||||
{
|
||||
#if WITH_NAND_DT_CONFIG
|
||||
currentActiveDataBus = busses;
|
||||
currentNandInfo = *nandInfo;
|
||||
|
||||
getChipIdAndTotalCECountAndCEMap(chipIds, (NandChipId*)¤tNandInfo.geometry->chipId, ¤tCECount, ¤tCEBitmap);
|
||||
WMR_ASSERT(ces == currentCECount);
|
||||
#endif //WITH_NAND_DT_CONFIG
|
||||
nandInfo->format = &_nandFormatPpn;
|
||||
ppnDevice = TRUE32;
|
||||
}
|
||||
|
||||
void setPPNOptions(BOOL32 retire_on_invalid_refresh)
|
||||
{
|
||||
_retire_on_invalid_refresh = retire_on_invalid_refresh;
|
||||
}
|
||||
|
||||
void reportPpnFeatures(void *list, UInt32 size)
|
||||
{
|
||||
_ppn_feature_list = list;
|
||||
_ppn_feature_size = size;
|
||||
}
|
||||
|
||||
void reportDbgChipIds(void *list, UInt32 size)
|
||||
{
|
||||
_dbg_chipids_list = list;
|
||||
_dbg_chipids_size = size;
|
||||
}
|
||||
|
||||
// Bitmap of valid CEs (all CEs are identical to CE0) gets cross-checked
|
||||
// against landing map from nand table
|
||||
// If a valid CE bit is set on an invalid landing bit, returns error
|
||||
BOOL32 checkPpnLandingMap(UInt32 validCEMap)
|
||||
{
|
||||
NandLandingMap *landingMap;
|
||||
UInt32 i = 0;
|
||||
UInt32 current;
|
||||
UInt32 intersect, remainder;
|
||||
|
||||
landingMap = &_nandBoardInfo.landingMap;
|
||||
remainder = validCEMap;
|
||||
|
||||
do {
|
||||
current = (*landingMap)[i];
|
||||
intersect = remainder & current;
|
||||
remainder &= ~intersect;
|
||||
i++;
|
||||
} while ((current != 0) && (remainder != 0));
|
||||
|
||||
if (remainder != 0)
|
||||
{
|
||||
WMR_PRINT(ERROR, "Valid CE bit detected on an invalid landing bit!\n");
|
||||
return FALSE32;
|
||||
}
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
const NandFormat * getPPNFormat(void)
|
||||
{
|
||||
return &_nandFormatPpn;
|
||||
}
|
||||
|
||||
BOOL32 targetSupportsToggle(void)
|
||||
{
|
||||
return _nandBoardInfo.useToggleMode ? TRUE32 : FALSE32;
|
||||
}
|
||||
|
||||
BOOL32 targetSupportsDiffDQS(void)
|
||||
{
|
||||
return _nandBoardInfo.useDiffDQSMode ? TRUE32 : FALSE32;
|
||||
}
|
||||
|
||||
BOOL32 targetSupportsDiffRE(void)
|
||||
{
|
||||
return _nandBoardInfo.useDiffREMode ? TRUE32 : FALSE32;
|
||||
}
|
||||
|
||||
BOOL32 targetSupportsVREF(void)
|
||||
{
|
||||
return _nandBoardInfo.useVref ? TRUE32 : FALSE32;
|
||||
}
|
||||
|
||||
BOOL32 targetSupportsSHC(void)
|
||||
{
|
||||
return _nandBoardInfo.useSingleHostChannel;
|
||||
}
|
||||
|
||||
BOOL32 targetSupportsSingleCE(void)
|
||||
{
|
||||
return _nandBoardInfo.allowSingleChipEnable;
|
||||
}
|
||||
|
||||
// Run only NAND chip identification
|
||||
int flash_nand_id(void)
|
||||
{
|
||||
OAM_Init();
|
||||
|
||||
if (FIL_SUCCESS != FIL_Init())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include "ANDTypes.h"
|
||||
#include "WMRTypes.h"
|
||||
#include "WMRFeatures.h"
|
||||
#if WMR_BUILDING_IBOOT
|
||||
#include <lib/devicetree.h>
|
||||
#endif
|
||||
|
||||
#ifndef _NANDID_H_
|
||||
#define _NANDID_H_
|
||||
|
||||
// =============================================================================
|
||||
// Preprocessor Constants
|
||||
|
||||
#define NAND_CHIP_ID_SIZE (8)
|
||||
#define VALID_NAND_CHIP_ID_SIZE (6)
|
||||
#define COMPARE_NAND_CHIP_ID_SIZE (4)
|
||||
#define LEGACY_NAND_CHIP_ID_SIZE (4)
|
||||
|
||||
#define NAND_MAX_CE_COUNT_PER_PACKAGE (8)
|
||||
#define NAND_MAX_PACKAGES_PER_CONFIG (2)
|
||||
#define NAND_MAX_CE_COUNT_TOTAL (NAND_MAX_PACKAGES_PER_CONFIG * NAND_MAX_CE_COUNT_PER_PACKAGE)
|
||||
|
||||
#define NAND_MAX_APPLE_NAME_SIZE (20)
|
||||
#define NAND_MAX_VENDOR_NAME_SIZE (20)
|
||||
#define NAND_MAX_PACKAGE_TYPE_SIZE (20)
|
||||
#define NAND_MAX_PACKAGE_SIZE_SIZE (20)
|
||||
|
||||
// =============================================================================
|
||||
// Drive Strength
|
||||
|
||||
typedef UInt8 NandDriveStrength;
|
||||
|
||||
#define NAND_DRIVE_STRENGTH_DEFAULT ((NandDriveStrength)0)
|
||||
|
||||
#define NAND_DRIVE_STRENGTH_X1 ((NandDriveStrength)1)
|
||||
#define NAND_DRIVE_STRENGTH_X2 ((NandDriveStrength)2)
|
||||
#define NAND_DRIVE_STRENGTH_X3 ((NandDriveStrength)3)
|
||||
#define NAND_DRIVE_STRENGTH_X4 ((NandDriveStrength)4)
|
||||
|
||||
// =============================================================================
|
||||
// Nand Chip Id
|
||||
|
||||
typedef UInt8 NandChipId[NAND_CHIP_ID_SIZE];
|
||||
|
||||
// =============================================================================
|
||||
// Nand Package Id
|
||||
|
||||
struct NandPackageIdStruct
|
||||
{
|
||||
// Unique identifier for this struct - start
|
||||
NandChipId chipId;
|
||||
UInt8 ceCnt;
|
||||
// Unique identifier for this struct - end
|
||||
};
|
||||
|
||||
typedef struct NandPackageIdStruct NandPackageId;
|
||||
|
||||
// =============================================================================
|
||||
// Nand Config Id
|
||||
|
||||
struct NandConfigIdStruct
|
||||
{
|
||||
// Unique identifier for this struct - start
|
||||
UInt8 connectedBusCnt;
|
||||
UInt8 packageCnt;
|
||||
NandPackageId packageIds[NAND_MAX_PACKAGES_PER_CONFIG];
|
||||
// Unique identifier for this struct - end
|
||||
};
|
||||
|
||||
typedef struct NandConfigIdStruct NandConfigId;
|
||||
|
||||
// =============================================================================
|
||||
// Nand Geometry
|
||||
|
||||
struct NandGeometryStruct
|
||||
{
|
||||
// Unique identifier for this struct - start
|
||||
NandChipId chipId;
|
||||
// Unique identifier for this struct - end
|
||||
|
||||
UInt16 blocksPerCS;
|
||||
UInt16 pagesPerBlock;
|
||||
UInt16 dataBytesPerPage;
|
||||
UInt16 spareBytesPerPage;
|
||||
|
||||
UInt8 eccPer512Bytes;
|
||||
CheckInitialBadType initialBBType;
|
||||
|
||||
UInt16 diesPerCS;
|
||||
};
|
||||
|
||||
typedef struct NandGeometryStruct NandGeometry;
|
||||
|
||||
#if (defined (AND_ENABLE_NAND_DESCRIPTION_TEXT) || AND_ENABLE_NAND_DESCRIPTION_TEXT)
|
||||
// =============================================================================
|
||||
// Nand Description
|
||||
|
||||
struct NandDescriptionStruct
|
||||
{
|
||||
// Unique identifier for this struct - start
|
||||
NandPackageId packageId;
|
||||
// Unique identifier for this struct - end
|
||||
|
||||
char appleName[NAND_MAX_APPLE_NAME_SIZE];
|
||||
char vendorPartNumber[NAND_MAX_VENDOR_NAME_SIZE];
|
||||
char packageType[NAND_MAX_PACKAGE_TYPE_SIZE];
|
||||
char packageSize[NAND_MAX_PACKAGE_SIZE_SIZE];
|
||||
};
|
||||
|
||||
typedef struct NandDescriptionStruct NandDescription;
|
||||
|
||||
// =============================================================================
|
||||
// ChipId Description
|
||||
|
||||
struct NandChipIdDescriptionStruct
|
||||
{
|
||||
// Unique identifier for this struct - start
|
||||
NandChipId chipId;
|
||||
// Unique identifier for this struct - end
|
||||
|
||||
char die[NAND_MAX_VENDOR_NAME_SIZE];
|
||||
char vendor[NAND_MAX_VENDOR_NAME_SIZE];
|
||||
};
|
||||
|
||||
typedef struct NandChipIdDescriptionStruct NandChipIdDescription;
|
||||
#endif // (defined(AND_ENABLE_NAND_DESCRIPTION_TEXT) || AND_ENABLE_NAND_DESCRIPTION_TEXT)
|
||||
|
||||
// =============================================================================
|
||||
// Nand Timing
|
||||
|
||||
struct NandTimingStruct
|
||||
{
|
||||
// Unique identifier for this struct - start
|
||||
NandConfigId configId;
|
||||
// Unique identifier for this struct - end
|
||||
|
||||
// write cycle
|
||||
UInt8 writeCycleNanosecs;
|
||||
UInt8 writeSetupNanosecs;
|
||||
UInt8 writeHoldNanosecs;
|
||||
|
||||
// read cycle
|
||||
UInt8 readCycleNanosecs;
|
||||
UInt8 readSetupNanosecs;
|
||||
UInt8 readHoldNanosecs;
|
||||
|
||||
// read window
|
||||
UInt8 readDelayNanosecs;
|
||||
UInt8 readValidNanosecs;
|
||||
};
|
||||
|
||||
typedef struct NandTimingStruct NandTiming;
|
||||
|
||||
// =============================================================================
|
||||
// Nand Support
|
||||
|
||||
struct NandBoardSupportStruct
|
||||
{
|
||||
// Unique identifier for this struct - start
|
||||
NandConfigId configId;
|
||||
// Unique identifier for this struct - end
|
||||
|
||||
VendorSpecificType vsType;
|
||||
};
|
||||
|
||||
typedef struct NandBoardSupportStruct NandBoardSupport;
|
||||
|
||||
// =============================================================================
|
||||
// Board Package/Landing Map
|
||||
|
||||
typedef UInt32 NandLandingMask;
|
||||
|
||||
typedef NandLandingMask NandLandingMap[NAND_MAX_PACKAGES_PER_CONFIG + 1];
|
||||
|
||||
// =============================================================================
|
||||
// Nand Board Timing
|
||||
|
||||
struct NandBoardInfoStruct
|
||||
{
|
||||
NandDriveStrength controlDstr;
|
||||
NandDriveStrength dataDstr;
|
||||
NandDriveStrength chipEnableDstr;
|
||||
|
||||
UInt8 socToNandRiseNanosecs;
|
||||
UInt8 socToNandFallNanosecs;
|
||||
UInt8 nandToSocRiseNanosecs;
|
||||
UInt8 nandToSocFallNanosecs;
|
||||
|
||||
NandLandingMap landingMap;
|
||||
BOOL32 useToggleMode;
|
||||
BOOL32 useDiffDQSMode;
|
||||
BOOL32 useDiffREMode;
|
||||
BOOL32 useVref;
|
||||
BOOL32 useSingleHostChannel;
|
||||
BOOL32 allowSingleChipEnable;
|
||||
};
|
||||
|
||||
typedef struct NandBoardInfoStruct NandBoardInfo;
|
||||
|
||||
struct NandPpnStruct
|
||||
{
|
||||
UInt32 specVersion;
|
||||
UInt32 blocksPerCau;
|
||||
UInt32 causPerCe;
|
||||
UInt32 slcPagesPerBlock;
|
||||
UInt32 mlcPagesPerBlock;
|
||||
UInt32 matchOddEvenCaus;
|
||||
UInt32 bitsPerCau;
|
||||
UInt32 bitsPerPage;
|
||||
UInt32 bitsPerBlock;
|
||||
UInt32 maxTransactionSize;
|
||||
};
|
||||
|
||||
typedef struct NandPpnStruct NandPpn;
|
||||
|
||||
struct NandFormatStruct
|
||||
{
|
||||
UInt32 metaPerLogicalPage;
|
||||
UInt32 validMetaPerLogicalPage;
|
||||
UInt32 logicalPageSize;
|
||||
};
|
||||
typedef struct NandFormatStruct NandFormat;
|
||||
|
||||
// =============================================================================
|
||||
// Nand Info
|
||||
|
||||
struct NandInfoStruct
|
||||
{
|
||||
const NandBoardSupport* boardSupport;
|
||||
const NandBoardInfo* boardInfo;
|
||||
const NandTiming* configTiming;
|
||||
const NandGeometry* geometry;
|
||||
const NandPpn* ppn;
|
||||
const NandFormat* format;
|
||||
};
|
||||
|
||||
typedef struct NandInfoStruct NandInfo;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
// =============================================================================
|
||||
// Public Function Declarations
|
||||
|
||||
BOOL32 findNandInfo(const NandChipId* chipIds,
|
||||
NandInfo* nandInfo,
|
||||
UInt32 numActiveDataBus);
|
||||
|
||||
void setNandIdPpnConfig(const NandChipId* chipIds,
|
||||
NandInfo* nandInfo,
|
||||
UInt32 busses,
|
||||
UInt32 ces);
|
||||
|
||||
void reportFMCTimingValues(UInt32 readSetupClocks,
|
||||
UInt32 readHoldClocks,
|
||||
UInt32 readDccycleClocks,
|
||||
UInt32 writeSetupClocks,
|
||||
UInt32 writeHoldClocks);
|
||||
|
||||
void reportToggleModeFMCTimingValues(UInt32 dqsHalfCycleClocks,
|
||||
UInt32 ceSetupClocks,
|
||||
UInt32 ceHoldClocks,
|
||||
UInt32 adlClocks,
|
||||
UInt32 whrClocks,
|
||||
UInt32 readPreClocks,
|
||||
UInt32 readPostClocks,
|
||||
UInt32 writePreClocks,
|
||||
UInt32 writePostClocks,
|
||||
UInt32 regDQSTimingCtrl);
|
||||
|
||||
void setToggleMode();
|
||||
|
||||
void setPPNOptions(BOOL32 retire_on_invalid_refresh);
|
||||
|
||||
void reportPpnFeatures(void *list, UInt32 size);
|
||||
|
||||
void reportDbgChipIds(void *list, UInt32 size);
|
||||
|
||||
void setECCLevels(UInt32 numCorrectableBits,
|
||||
UInt32 refreshThresholdBits);
|
||||
|
||||
BOOL32 checkPpnLandingMap(UInt32 validCEMap);
|
||||
|
||||
const NandFormat * getPPNFormat(void);
|
||||
|
||||
BOOL32 targetSupportsToggle(void);
|
||||
BOOL32 targetSupportsDiffDQS(void);
|
||||
BOOL32 targetSupportsDiffRE(void);
|
||||
BOOL32 targetSupportsVREF(void);
|
||||
BOOL32 targetSupportsSHC(void);
|
||||
BOOL32 targetSupportsSingleCE(void);
|
||||
|
||||
// =============================================================================
|
||||
// Public Variables
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif // _NANDID_H_
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright (c) 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.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
GLOBAL_INCLUDES += \
|
||||
$(LOCAL_DIR) \
|
||||
drivers/flash_nand/raw/Whimory/Inc
|
||||
|
||||
MODULES += \
|
||||
drivers/flash_nand/OAM
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/nandid.o
|
||||
@@ -0,0 +1,12 @@
|
||||
_WMR_Open
|
||||
_WMR_PPN_GetFTL
|
||||
_WMR_PPN_GetFPart
|
||||
_WMR_Start
|
||||
_WMR_PPN_CtrlIO
|
||||
_ppn_init
|
||||
_ppnMiscSingleOperation
|
||||
_ppnMiscFillDevStruct
|
||||
_ppnMiscGetCEFromBank
|
||||
_ppnMiscSingleLbaRead
|
||||
_ppnMiscConvertToPPNPageAddress
|
||||
_ppnMiscConvertPhysicalAddressToCauBlockPage
|
||||
@@ -0,0 +1,77 @@
|
||||
# Copyright (C) 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.
|
||||
#
|
||||
|
||||
SWISSPPN_DIR := $(GET_LOCAL_DIR)
|
||||
SWISSPPN_BUILD := $(call TOLIBDIR,$(SWISSPPN_DIR)/SWISSPPN.a)
|
||||
COMMONLIBS += SWISSPPN
|
||||
|
||||
# Only process the remainder of the makefile if we are building libraries
|
||||
#
|
||||
ifeq ($(MAKEPHASE),libraries)
|
||||
|
||||
NAND_DIR := $(patsubst %/,%,$(dir $(GET_LOCAL_DIR)))
|
||||
|
||||
MODULES += \
|
||||
drivers/flash_nand/OAM \
|
||||
lib/blockdev
|
||||
|
||||
GLOBAL_INCLUDES += \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SVFL \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/Misc \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/FPart \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Boot \
|
||||
$(NAND_DIR)/raw/Whimory/Inc \
|
||||
$(NAND_DIR)/OAM \
|
||||
$(NAND_DIR)/OAM/iBoot
|
||||
|
||||
# base library files
|
||||
SWISSPPN_SUBOBJS += \
|
||||
$(SWISSPPN_DIR)/ppn.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/FPart/PPNFPart.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/Misc/PPNMisc.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/Misc/VFLBuffer.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SVFL/s_vfl.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_boot.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_btoc.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_cxt.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_cxt_diff.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_cxt_load.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_external.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_gc.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_geom.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_init.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_internal.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_meta.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_read.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/s_sb.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/L2V/L2V_Free.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/L2V/L2V_Init.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/L2V/L2V_Mem.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/L2V/L2V_Repack.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/L2V/L2V_Search.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/L2V/L2V_Types.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/SFTL/L2V/L2V_Update.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Boot/WhimoryBoot.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Boot/RegSwiss.o
|
||||
|
||||
SWISSPPN_SUBOBJS := $(call TOLIBOBJDIR,$(SWISSPPN_SUBOBJS))
|
||||
ALL_DEPS += $(SWISSPPN_SUBOBJS:%o=%d)
|
||||
|
||||
SWISSPPN_OBJS := $(call TOLIBOBJDIR,$(SWISSPPN_DIR)/SWISSPPN.o)
|
||||
|
||||
|
||||
$(SWISSPPN_OBJS): $(SWISSPPN_SUBOBJS)
|
||||
@echo LIB_LD $@
|
||||
$(_v)$(_LD) $(LIBRARY_LDFLAGS) $(SWISSPPN_SUBOBJS) -o $@ -exported_symbols_list $(SWISSPPN_DIR)/export.txt
|
||||
|
||||
$(SWISSPPN_BUILD): $(SWISSPPN_OBJS)
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Apple Inc. All rights reserved.
|
||||
* Copyright (c) 2006 Apple Computer, 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 <debug.h>
|
||||
#include <lib/heap.h>
|
||||
#include <lib/blockdev.h>
|
||||
#include <lib/partition.h>
|
||||
#include <platform/clocks.h>
|
||||
#include <sys/menu.h>
|
||||
|
||||
#include "WMRConfig.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "FIL.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "VFL.h"
|
||||
#include "FTL.h"
|
||||
#include "WhimoryBoot.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
|
||||
|
||||
extern uint32_t nand_fsys_block_offset;
|
||||
|
||||
static int nand_filesys_init(uint32_t block_size, uint32_t block_count);
|
||||
static FTLFunctions *TLFuncPtr=NULL;
|
||||
static int nand_read_block_hook(struct blockdev *_dev, void *ptr, block_addr block, uint32_t count)
|
||||
{
|
||||
Int32 err;
|
||||
|
||||
if (count > 0) {
|
||||
err = TLFuncPtr->Read(block, count, ptr);
|
||||
//err = FTL_Read(block, count, ptr);
|
||||
|
||||
if (err != FIL_SUCCESS) {
|
||||
printf("nand_read_block_hook: failure %d reading block %u, count %zd\n", err, block, count);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int ppn_init(void)
|
||||
{
|
||||
uint32_t block_size, block_count;
|
||||
uint32_t index_cache = 0;
|
||||
WhimoryBootCode boot_code;
|
||||
|
||||
dprintf(DEBUG_INFO, "swiss_ppn_init()\n");
|
||||
|
||||
// Find a signature
|
||||
boot_code = WMR_Start(0, 0, gWhimoryInitParameters);
|
||||
if (kWhimoryOk == boot_code) {
|
||||
// Open the FTL
|
||||
boot_code = WMR_Open(&block_count, &block_size, &index_cache, gWhimoryInitParameters);
|
||||
if (kWhimoryOk == boot_code) {
|
||||
// Publish a block device
|
||||
if (0 != nand_filesys_init(block_size, block_count)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if (kWhimoryWarningUnformatted == boot_code) {
|
||||
printf("***NAND driver is not formatted. Run restore process.***\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int nand_filesys_init(uint32_t block_size, uint32_t block_count)
|
||||
{
|
||||
struct blockdev *nand;
|
||||
|
||||
TLFuncPtr = WMR_PPN_GetFTL();
|
||||
// build a block device around this NAND
|
||||
nand = malloc(sizeof(struct blockdev));
|
||||
|
||||
construct_blockdev(nand, "nand0", (off_t)block_count * block_size, block_size);
|
||||
|
||||
nand->read_block_hook = &nand_read_block_hook;
|
||||
|
||||
register_blockdev(nand);
|
||||
|
||||
/* scan ourselves for partitions and publish subdevices */
|
||||
partition_scan_and_publish_subdevices("nand0");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2007-2009 Apple Inc. All rights reserved.
|
||||
* Copyright (c) 2006 Apple Computer, 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
|
||||
|
||||
#include <debug.h>
|
||||
#include <lib/blockdev.h>
|
||||
#include <lib/syscfg.h>
|
||||
|
||||
#include "FPart.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "WhimoryBoot.h"
|
||||
|
||||
extern uint32_t nand_fsys_block_offset;
|
||||
|
||||
// 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)
|
||||
|
||||
|
||||
|
||||
static FPartFunctions *_fpart = NULL;
|
||||
|
||||
int ppn_syscfg_init(void)
|
||||
{
|
||||
WhimoryBootCode boot_code;
|
||||
|
||||
boot_code = WMR_Start(0, 0, 0);
|
||||
if (kWhimoryOk == boot_code) {
|
||||
_fpart = WMR_PPN_GetFPart();
|
||||
if (NULL != _fpart->ReadSpecialBlock) {
|
||||
return 0;
|
||||
} else {
|
||||
dprintf(DEBUG_CRITICAL, "ppn syscfg is not supported!\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ppn_read_syscfg_hook(struct blockdev *_dev, void *ptr, block_addr block, size_t count)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
// Only allow reading the "second" block
|
||||
if ((block != 1) || (count != 1)) {
|
||||
dprintf(DEBUG_CRITICAL, "attempted to read ppn syscfg at non-zero offset\n");
|
||||
ok = false;
|
||||
|
||||
} else if (count > 0) {
|
||||
if (!_fpart->ReadSpecialBlock(ptr, kFakeBdevBlockSize, AND_SB_TYPE_UNIQUE_INFO)) {
|
||||
dprintf(DEBUG_CRITICAL, "ppn_read_syscfg_hook: failure reading syscfg\n");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
return -1;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif /* WITH_SYSCFG */
|
||||
@@ -0,0 +1,37 @@
|
||||
# Copyright (c) 2007-2009 Apple Inc. All rights reserved.
|
||||
# Copyright (c) 2006 Apple Computer, 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)
|
||||
NAND_DIR := $(patsubst %/,%,$(dir $(GET_LOCAL_DIR)))
|
||||
|
||||
OPTIONS += \
|
||||
WITH_PPN=1 \
|
||||
WITH_PPN_SYSCFG=1
|
||||
|
||||
GLOBAL_INCLUDES += \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/FPart \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/Misc \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Boot
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/ppn_syscfg.o
|
||||
|
||||
#
|
||||
# If a NAND FTL has not been configured, we need some of the raw NAND bits.
|
||||
#
|
||||
ifeq ($(WITH_NAND_FTL),)
|
||||
ALL_OBJS += \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/FPart/PPNFPart.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Core/Misc/PPNMisc.o \
|
||||
$(NAND_DIR)/ppn/WhimoryPPN/Boot/WhimoryBoot.o
|
||||
else
|
||||
LIBRARY_MODULES += $(LOCAL_DIR)
|
||||
endif
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "FPart.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "WhimoryBoot.h"
|
||||
#include "ANDStats.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
static VFLFunctions *stVflFunctions;
|
||||
static FTLFunctions *stFtlFunctions;
|
||||
|
||||
typedef BOOL32 (*GetStructFunc)(UInt32 dwStructType, void * pvoidStructBuffer, UInt32 * pdwStructSize);
|
||||
|
||||
typedef struct {
|
||||
UInt32 dwStructLayer;
|
||||
UInt32 dwStructType;
|
||||
UInt32 dwStructVersion;
|
||||
} ExportStructParameters;
|
||||
|
||||
|
||||
static ExportStructParameters astrStructsToExport[] =
|
||||
{
|
||||
// header (must be first)
|
||||
{ 0, AND_STRUCT_WMR_EXPORT_ALL, AND_EXPORT_STRUCTURE_VERSION},
|
||||
|
||||
// WMR Version (FTL & VFL types)
|
||||
{AND_STRUCT_LAYER_WMR, AND_STRUCT_WMR_VERSION, 0},
|
||||
|
||||
// VFL_type
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_GET_TYPE, 0},
|
||||
|
||||
// FTL_type ( FTL/yaFTL)
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_GET_TYPE, 0},
|
||||
|
||||
// All VFL Meta
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 0, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 1, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 2, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 3, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 4, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 5, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 6, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 7, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 8, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 9, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 10, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 11, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 12, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 13, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 14, 0},
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_VFLMETA | 15, 0},
|
||||
|
||||
//FTL geometry
|
||||
{AND_STRUCT_LAYER_FTL,AND_STRUCT_FTL_GET_FTL_DEVICEINFO, 0},
|
||||
|
||||
// FTL
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_FTLCXT, 0},
|
||||
|
||||
// FTL counters
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_GET_FTL_EC_BINS, 1},
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_GET_FTL_RC_BINS, 1},
|
||||
|
||||
// FTL - Stat
|
||||
{AND_STRUCT_LAYER_FTL, AND_STRUCT_FTL_STATISTICS, 0},
|
||||
|
||||
// VFL - Stat
|
||||
{AND_STRUCT_LAYER_VFL, AND_STRUCT_VFL_STATISTICS, 0},
|
||||
|
||||
// FIL - Device Info
|
||||
{AND_STRUCT_LAYER_FIL, AND_STRUCT_FIL_DEVICE_INFO, 0},
|
||||
|
||||
// FIL - Stat
|
||||
{AND_STRUCT_LAYER_FIL, AND_STRUCT_FIL_STATISTICS, 0},
|
||||
|
||||
// footer (must be last)
|
||||
{0, AND_STRUCT_WMR_EXPORT_ALL_END, AND_EXPORT_STRUCTURE_VERSION},
|
||||
|
||||
};
|
||||
|
||||
#define AND_DUMP_DEBUG (0)
|
||||
|
||||
#if AND_DUMP_DEBUG
|
||||
#define DUMP_VAR(variable) WMR_PRINT(ALWAYS, "%s : %u\n", #variable, (UInt32)(variable))
|
||||
|
||||
|
||||
static void
|
||||
hexdump(UInt8 *bytes, int count)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < count; i += 16) {
|
||||
kprintf("%04x:", i);
|
||||
for (j = 0; (j < 16) && ((i + j) < count); j++)
|
||||
kprintf(" %02.2x", *bytes++);
|
||||
kprintf("\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define DUMP_VAR(variable)
|
||||
#endif //AND_DUMP_DEBUG
|
||||
|
||||
|
||||
|
||||
static GetStructFunc _translateStructLayer (UInt32 dwStructLayer)
|
||||
{
|
||||
switch (dwStructLayer)
|
||||
{
|
||||
case AND_STRUCT_LAYER_FTL:
|
||||
return stFtlFunctions->GetStruct;
|
||||
case AND_STRUCT_LAYER_VFL:
|
||||
return stVflFunctions->GetStruct;
|
||||
case AND_STRUCT_LAYER_FIL:
|
||||
return FIL_GetStruct;
|
||||
case AND_STRUCT_LAYER_WMR:
|
||||
return WMR_PPNGetStruct;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static BOOL32 _appendStructToBuffer(void *pvoidExportBuffer,
|
||||
UInt32 *pdwBufferSize,
|
||||
UInt32 dwStructLayer,
|
||||
UInt32 dwStructType,
|
||||
UInt32 dwStructVersion)
|
||||
{
|
||||
UInt32 dwDataSize;
|
||||
BOOL32 boolResult;
|
||||
GetStructFunc fGetStruct = _translateStructLayer(dwStructLayer);
|
||||
UInt8 *cursor = (UInt8*) pvoidExportBuffer;
|
||||
|
||||
|
||||
DUMP_VAR(pvoidExportBuffer);
|
||||
if (pdwBufferSize)
|
||||
{
|
||||
DUMP_VAR(*pdwBufferSize);
|
||||
}
|
||||
DUMP_VAR(dwStructLayer);
|
||||
DUMP_VAR(dwStructType);
|
||||
DUMP_VAR(dwStructVersion);
|
||||
|
||||
if (fGetStruct)
|
||||
{
|
||||
if (pvoidExportBuffer)
|
||||
{
|
||||
// leave room for the struct header
|
||||
cursor += sizeof(ANDExportStruct);
|
||||
}
|
||||
dwDataSize = pdwBufferSize ? (*pdwBufferSize - sizeof(ANDExportStruct)) : 0;
|
||||
boolResult = fGetStruct(dwStructType, cursor, &dwDataSize);
|
||||
DUMP_VAR(dwDataSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for header and footer
|
||||
boolResult = TRUE32;
|
||||
dwDataSize = 0;
|
||||
}
|
||||
|
||||
if (boolResult)
|
||||
{
|
||||
#if AND_DUMP_DEBUG
|
||||
if (pvoidExportBuffer)
|
||||
{
|
||||
hexdump(pvoidExportBuffer, dwDataSize);
|
||||
}
|
||||
#endif
|
||||
if (pdwBufferSize)
|
||||
{
|
||||
*pdwBufferSize = dwDataSize + sizeof(ANDExportStruct);
|
||||
}
|
||||
|
||||
if (pvoidExportBuffer)
|
||||
{
|
||||
ANDExportStruct strExport;
|
||||
|
||||
strExport.dwStructID = dwStructType;
|
||||
strExport.dwStructureVersion = dwStructVersion;
|
||||
strExport.dwDataSize = dwDataSize;
|
||||
strExport.dwIndex = 0; // What is this?
|
||||
|
||||
WMR_MEMCPY(pvoidExportBuffer, &strExport, sizeof(ANDExportStruct));
|
||||
}
|
||||
}
|
||||
else if (pdwBufferSize)
|
||||
{
|
||||
*pdwBufferSize = 0;
|
||||
}
|
||||
|
||||
DUMP_VAR(boolResult);
|
||||
return boolResult;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define SUB_MIN_ZERO(minuend, subtrahend) (((minuend) > (subtrahend)) ? ((minuend) - (subtrahend)) : 0)
|
||||
|
||||
BOOL32 ANDExportAllStructs(void * pvoidDataBuffer, UInt32 * pdwDataSize)
|
||||
{
|
||||
UInt32 idx;
|
||||
ExportStructParameters *nextStruct;
|
||||
const UInt32 dwNumStructures = sizeof(astrStructsToExport) / sizeof(astrStructsToExport[0]);
|
||||
const UInt32 dwBufferSize = pdwDataSize ? *pdwDataSize : 0;
|
||||
UInt8 *cursor = (UInt8*) pvoidDataBuffer;
|
||||
UInt32 dwBufferRead = 0;
|
||||
UInt32 dwTmpStructSize;
|
||||
|
||||
if (!pdwDataSize)
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
// Update globals
|
||||
stVflFunctions = WMR_PPN_GetVFL();
|
||||
stFtlFunctions = WMR_PPN_GetFTL();
|
||||
|
||||
nextStruct = &astrStructsToExport[0];
|
||||
for (idx = 0; idx < dwNumStructures; ++idx)
|
||||
{
|
||||
dwTmpStructSize = SUB_MIN_ZERO(dwBufferSize, dwBufferRead);
|
||||
_appendStructToBuffer(cursor,
|
||||
&dwTmpStructSize,
|
||||
nextStruct->dwStructLayer,
|
||||
nextStruct->dwStructType,
|
||||
nextStruct->dwStructVersion);
|
||||
nextStruct++;
|
||||
if (cursor)
|
||||
{
|
||||
cursor += dwTmpStructSize;
|
||||
}
|
||||
dwBufferRead += dwTmpStructSize;
|
||||
}
|
||||
|
||||
if (pdwDataSize)
|
||||
{
|
||||
*pdwDataSize = dwBufferRead;
|
||||
}
|
||||
|
||||
// pdwDataSize tells the whole story, always pass
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "WMRTypes.h"
|
||||
|
||||
#ifndef _ANDSTATS_H_
|
||||
#define _ANDSTATS_H_
|
||||
|
||||
BOOL32 ANDExportAllStructs(void * pvoidDataBuffer, UInt32 * pdwDataSize);
|
||||
|
||||
#endif //_ANDSTATS_H_
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2010 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 "WhimoryBoot.h"
|
||||
#include "WhimoryBootTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
Boot_FTL_Registry_t g_ftl_registry[] =
|
||||
{
|
||||
{ SFTL_PPN_MAJOR_VER, SFTL_PPN_Register },
|
||||
{ YAFTL_PPN_MAJOR_VER, YAFTL_PPN_Register },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
Boot_VFL_Registry_t g_vfl_registry[] =
|
||||
{
|
||||
{ PPN_SVFL_MAJOR_VER, PPN_SVFL_GetFunctions },
|
||||
{ PPN_VFL_MAJOR_VER, PPN_VFL_GetFunctions },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2010 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 "WhimoryBoot.h"
|
||||
#include "WhimoryBootTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
Boot_FTL_Registry_t g_ftl_registry[] =
|
||||
{
|
||||
{ SFTL_PPN_MAJOR_VER, SFTL_PPN_Register },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
Boot_VFL_Registry_t g_vfl_registry[] =
|
||||
{
|
||||
{ PPN_SVFL_MAJOR_VER, PPN_SVFL_GetFunctions },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2010 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 "WhimoryBoot.h"
|
||||
#include "WhimoryBootTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
|
||||
Boot_FTL_Registry_t g_ftl_registry[] =
|
||||
{
|
||||
{ YAFTL_PPN_MAJOR_VER, YAFTL_PPN_Register },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
Boot_VFL_Registry_t g_vfl_registry[] =
|
||||
{
|
||||
{ PPN_VFL_MAJOR_VER, PPN_VFL_GetFunctions },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,208 @@
|
||||
// Copyright (C) 2010 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 _WHIMORY_BOOT_H_
|
||||
#define _WHIMORY_BOOT_H_
|
||||
|
||||
#include "WMRTypes.h"
|
||||
#include "FTL.h"
|
||||
#include "VFL.h"
|
||||
#include "FPart.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif //__cplusplus
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public structure definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef enum _WhimoryBootCode
|
||||
{
|
||||
kWhimoryOk = 0,
|
||||
|
||||
kWhimoryWarning = (1 << 29),
|
||||
kWhimoryWarningUnformatted,
|
||||
kWhimoryEpochMismatch_Deprecated,
|
||||
kWhimoryMinorVersionMismatch,
|
||||
kWhimoryMajorVersionNotAvailable,
|
||||
kWhimoryBirthVersionTooNew,
|
||||
|
||||
kWhimoryError = (1 << 30),
|
||||
kWhimoryErrMissingHardware,
|
||||
kWhimoryErrOutOfMemory,
|
||||
kWhimoryErrUnsupportedVersion,
|
||||
kWhimoryErrSetup,
|
||||
kWhimoryErrUnitTestFailed,
|
||||
kWhimoryErrCorruptedFormat,
|
||||
} WhimoryBootCode;
|
||||
|
||||
#define kWhimoryBootOptionLowPower (1 << 0)
|
||||
#define kWhimoryBootOptionForceFtlRecovery (1 << 1)
|
||||
#define kWhimoryBootOptionFreshOffFTLFormat (1 << 2)
|
||||
#define kWhimoryBootOptionDisableGCInTrim (1 << 3)
|
||||
#define kWhimorySetIndexCacheSize (1 << 4)
|
||||
#define kWhimoryBootOptionReadOnly (1 << 16) // Must align with WMR_INIT_OPEN_READONLY @ bit 16.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Public function declarations
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Start
|
||||
//
|
||||
// WMR_Start will attempt to locate a signature. It will call OAM_Init()
|
||||
// and FIL_Init(), so those fuctions should be idempotent.
|
||||
// Possible non-fatal outcomes:
|
||||
// kWhimoryWarningUnformatted - Run WMR_Initial_Format()
|
||||
//
|
||||
// On kWhimoryOk or warnings, callers can request WMR_PPN_GetFPart()
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Start
|
||||
(UInt32 fpart_major_ver,
|
||||
UInt32 fpart_options,
|
||||
UInt32 boot_options);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Open
|
||||
//
|
||||
// WMR_Open will open a block device if the media is properly formatted
|
||||
// and return appropriate warnings if the device needs to be formatted or
|
||||
// repaired.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Open
|
||||
(UInt32 *total_sectors,
|
||||
UInt32 *sector_size,
|
||||
UInt32 *index_cache,
|
||||
UInt32 boot_options);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Format
|
||||
//
|
||||
// Format the media with a given set of preferred versions
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Initial_Format
|
||||
(UInt32 fpart_major_ver,
|
||||
UInt32 fpart_options,
|
||||
UInt32 fpart_format_options,
|
||||
UInt32 vfl_major_ver,
|
||||
UInt32 vfl_options,
|
||||
UInt32 ftl_major_ver,
|
||||
UInt32 ftl_options,
|
||||
UInt32 num_keepout_blocks,
|
||||
UInt32 megabytes_for_ftl);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Partition
|
||||
//
|
||||
// Re-size the portion of the VFL that is visible to FTL.
|
||||
// A value of 0 gives the entire media to FTL.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Partition
|
||||
(UInt32 megabytes_for_ftl);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Update
|
||||
//
|
||||
// Update the physical format if newer format is supported by this software.
|
||||
// Optionally require backward compatiblity and saving user data
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WhimoryBootCode
|
||||
WMR_Update
|
||||
(const BOOL32 keep_backward_compatibility,
|
||||
const BOOL32 save_data,
|
||||
UInt32 vfl_major_ver,
|
||||
UInt32 vfl_options,
|
||||
UInt32 ftl_major_ver,
|
||||
UInt32 ftl_options,
|
||||
UInt32 num_keepout_blocks);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_Close
|
||||
//
|
||||
// Gracefully shut down the block device, deallocate all buffers, and return
|
||||
// static variables to initial state such that WMR_Open can be called again.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
WMR_Close
|
||||
(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_PPN_CtrlIO
|
||||
//
|
||||
// Generic IOCtl interface to all layers of whimory. Caller must specifiy data
|
||||
// buffer size in incoming size pointer.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL32
|
||||
WMR_PPN_CtrlIO
|
||||
(UInt32 ctrlio_type,
|
||||
void *data,
|
||||
UInt32 *size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_PPNGetStruct
|
||||
//
|
||||
// Get a parameter from RAM
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL32
|
||||
WMR_PPNGetStruct
|
||||
(UInt32 ctrlio_type,
|
||||
void *data,
|
||||
UInt32 *size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WMR_PPNGetCurrentSignature
|
||||
//
|
||||
// Get the signature representing the current software state
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const struct WhimorySignature *
|
||||
WMR_PPNGetSignature
|
||||
(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
//
|
||||
// Get a parameter from RAM
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
FTLFunctions *WMR_PPN_GetFTL
|
||||
(void);
|
||||
VFLFunctions *WMR_PPN_GetVFL
|
||||
(void);
|
||||
FPartFunctions *WMR_PPN_GetFPart
|
||||
(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif //__cplusplus
|
||||
|
||||
#endif //_WHIMORY_BOOT_H_
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright (C) 2010 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 _WHIMORY_BOOT_TYPES_H_
|
||||
#define _WHIMORY_BOOT_TYPES_H_
|
||||
|
||||
#define WHIMORY_SIGNATURE_SIZE (3 * 512)
|
||||
struct WhimorySignature
|
||||
{
|
||||
UInt32 magic;
|
||||
#define WHIMORY_SIGNATURE_MAGIC (0x776D7278) // 'wmrx'
|
||||
UInt32 _deprecated_epoch; // 0 for new devices
|
||||
UInt32 whimory_ver_at_birth; // SW older than birth epoch may not open this drive
|
||||
#define WHIMORY_SIGNATURE_VER_PPN_CUR (6)
|
||||
UInt32 ftl_major_ver;
|
||||
UInt32 ftl_minor_ver;
|
||||
UInt32 ftl_options;
|
||||
UInt32 vfl_major_ver;
|
||||
UInt32 vfl_minor_ver;
|
||||
UInt32 vfl_options;
|
||||
UInt32 fpart_major_ver;
|
||||
UInt32 fpart_minor_ver;
|
||||
UInt32 fpart_options; // debug-only: need these to find signature
|
||||
UInt32 num_keepout_blocks;
|
||||
|
||||
UInt32 num_chip_enables;
|
||||
|
||||
// Informational
|
||||
#define WHIMORY_SW_VER_MAX_LENGTH (128)
|
||||
UInt8 sw_ver_str[WHIMORY_SW_VER_MAX_LENGTH];
|
||||
UInt32 fpart_format_options; // options used for initial format
|
||||
|
||||
#define WHIMORY_FTL_PARTITION_VALID_BIT (1UL << 31)
|
||||
#define WHIMORY_FTL_PARTITION_SIZE_MASK (0x7fffffffUL)
|
||||
UInt32 megabytes_for_ftl;
|
||||
|
||||
// Reserve to 1.5KB
|
||||
UInt8 reserved[WHIMORY_SIGNATURE_SIZE - (16 * sizeof(UInt32)) - 128];
|
||||
};
|
||||
|
||||
struct WhimoryDeviceInfo
|
||||
{
|
||||
UInt32 num_ce;
|
||||
UInt32 main_bytes_per_page;
|
||||
UInt32 total_meta_per_page;
|
||||
UInt32 lba_per_page;
|
||||
};
|
||||
|
||||
typedef FTLFunctions * (*FTL_Registrar)(void);
|
||||
typedef struct
|
||||
{
|
||||
UInt32 major_ver;
|
||||
FTL_Registrar registrar;
|
||||
} Boot_FTL_Registry_t;
|
||||
|
||||
typedef VFLFunctions * (*VFL_Registrar)(void);
|
||||
typedef struct
|
||||
{
|
||||
UInt32 major_ver;
|
||||
VFL_Registrar registrar;
|
||||
} Boot_VFL_Registry_t;
|
||||
|
||||
typedef FPartFunctions * (*FPart_Registrar)(void);
|
||||
typedef struct
|
||||
{
|
||||
UInt32 major_ver;
|
||||
FPart_Registrar registrar;
|
||||
} Boot_FPart_Registry_t;
|
||||
|
||||
#endif //_WHIMORY_BOOT_TYPES_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,69 @@
|
||||
#ifndef _PPNFPART_TYPES_H_
|
||||
#define _PPNFPART_TYPES_H_
|
||||
|
||||
#include "WMRConfig.h"
|
||||
#include "PPNMiscTypes.h"
|
||||
#include "WMRBufTypes.h"
|
||||
|
||||
/* defines */
|
||||
|
||||
#define PPNFPART_MAX_SPECIAL_BLOCKS_PER_TYPE (8)
|
||||
#define PPNFPART_MAX_SPECIAL_BLOCKS_TYPE (20)
|
||||
|
||||
#define PPNFPART_SPECIAL_BLOCK_SPARE_TYPE (AND_SPARE_TYPE_REGION_FPART + 0x00)
|
||||
|
||||
// On NAND structures - Start
|
||||
|
||||
#define PPNFPART_STRUCTURE_VERSION (0x00000001) // use the two MSB as major - not forward compatible
|
||||
|
||||
// SpecialBlockHeaderStruct - used as a header in special blocks that are managed
|
||||
// by PPNFPart
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
UInt16 bank;
|
||||
UInt16 block;
|
||||
} block_addresses[PPNFPART_MAX_SPECIAL_BLOCKS_PER_TYPE];
|
||||
UInt32 version;
|
||||
UInt32 data_size;
|
||||
UInt32 copy_number;
|
||||
UInt32 reserved[21]; // reserving bits and rounding the structure size to 128 bytes
|
||||
} SpecialBlockHeaderStruct;
|
||||
|
||||
// PPNFPart_Spare - used in the metadata of any speical blcok
|
||||
// managed by PPNFPart
|
||||
typedef struct
|
||||
{
|
||||
UInt8 spare_type; // spare type
|
||||
UInt8 index; // for spcial blocks holding information that cross page boundary
|
||||
UInt16 vfl_special_type; // shared type (between VFL and FPART) identifying this type of special block
|
||||
UInt8 reserved1[12];
|
||||
} PPNFPart_Spare;
|
||||
|
||||
// On NAND structures - End
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt16 bank;
|
||||
UInt16 block;
|
||||
UInt16 type;
|
||||
} SpecialBlockCacheEntryType;
|
||||
|
||||
/* PPNFPart internal structures */
|
||||
typedef struct
|
||||
{
|
||||
PPN_DeviceInfo dev;
|
||||
LowFuncTbl *fil;
|
||||
SpecialBlockCacheEntryType * special_blocks; // malloc to size AND_MAX_SPECIAL_BLOCKS in init
|
||||
UInt16 special_blocks_idx; // pointer to the next available entry in the special_blocks array
|
||||
BOOL32 done_mapping; // flag indicating the cache is up to date - no need to search in nand
|
||||
|
||||
// reserve a single command struct for fpart to
|
||||
// do physical operations
|
||||
WMR_BufZone_t zone;
|
||||
PPNCommandStruct * command;
|
||||
BOOL32 initialized;
|
||||
} PPNFPart_MainCxt; // hold all other pointers
|
||||
|
||||
#endif /* _PPNFPART_TYPES_H_ */
|
||||
@@ -0,0 +1,97 @@
|
||||
//Test file compiled only for simulator
|
||||
|
||||
static BOOL32
|
||||
ppnMiscTestConversionFunctions
|
||||
(PPN_DeviceInfo * dev);
|
||||
|
||||
static BOOL32
|
||||
_verifyAnAddress
|
||||
(PPN_DeviceInfo * dev,
|
||||
UInt16 bank,
|
||||
UInt16 block,
|
||||
UInt16 page_offset,
|
||||
BOOL32 slc)
|
||||
{
|
||||
UInt16 chip_enable_idx, channel, cau;
|
||||
UInt32 page_address = 0, line_failed = 0;
|
||||
UInt16 temp_bank, temp_block, temp_page_offset;
|
||||
BOOL32 temp_slc;
|
||||
|
||||
// convert to a physical address
|
||||
cau = ppnMiscGetCAUFromBank(dev, bank);
|
||||
if (!(cau < dev->caus_per_ce))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
page_address = ppnMiscConvertToPPNPageAddress(dev, cau, block, page_offset, slc);
|
||||
chip_enable_idx = ppnMiscGetCEIdxFromBank(dev, bank);
|
||||
if (!(chip_enable_idx < dev->ces_per_channel))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
channel = ppnMiscGetChannelFromBank(dev, bank);
|
||||
if (!(channel < dev->num_channels))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
// convert back
|
||||
ppnMiscConvertPhysicalAddressToBankBlockPage(dev, channel, chip_enable_idx, page_address,
|
||||
&temp_bank, &temp_block, &temp_page_offset, &temp_slc);
|
||||
if (!((temp_bank == bank) && (temp_block == block) && (temp_page_offset == page_offset) && (slc == temp_slc)))
|
||||
{
|
||||
line_failed = __LINE__;
|
||||
goto return_error;
|
||||
}
|
||||
|
||||
return TRUE32;
|
||||
|
||||
return_error:
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] fail address conversion: (l:%d)\n"), line_failed));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] bank:0x%X, block:0x%X, page_offset:0x%X, slc:0x%X\n"),
|
||||
bank, block, page_offset, slc));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] channel:0x%X, chip_enable_idx:0x%X, cau:0x%X\n"),
|
||||
channel, chip_enable_idx, cau));
|
||||
VFL_WRN_PRINT((TEXT("PPNMISC:ERR] temp_bank:0x%X, temp_block:0x%X, temp_page_offset:0x%X, temp_slc:0x%X\n"),
|
||||
temp_bank, temp_block, temp_page_offset, temp_slc));
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
static BOOL32
|
||||
ppnMiscTestConversionFunctions
|
||||
(PPN_DeviceInfo * dev)
|
||||
{
|
||||
UInt16 bank, block, page_offset;
|
||||
UInt32 counter = 0;
|
||||
|
||||
for (bank = 0; bank < dev->num_of_banks; bank++)
|
||||
{
|
||||
for (block = 0; block < dev->blocks_per_cau; block++)
|
||||
{
|
||||
for (page_offset = 0; page_offset < dev->pages_per_block_mlc; page_offset++)
|
||||
{
|
||||
counter++;
|
||||
if (!(_verifyAnAddress(dev, bank, block, page_offset, TRUE32)))
|
||||
{
|
||||
VFL_ERR_PRINT((TEXT("PPNMISC:ERR] fail address conversion test: (l:%d)\n"), __LINE__));
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
for (page_offset = 0; page_offset < dev->pages_per_block_slc; page_offset++)
|
||||
{
|
||||
if (!(_verifyAnAddress(dev, bank, block, page_offset, TRUE32)))
|
||||
{
|
||||
VFL_ERR_PRINT((TEXT("PPNMISC:ERR] fail address conversion test: (l:%d)\n"), __LINE__));
|
||||
return FALSE32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_H__
|
||||
#define __L2V_H__
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern L2V_t L2V;
|
||||
extern UInt8 *L2V_root_depth;
|
||||
|
||||
|
||||
#endif // __L2V_H__
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_CASSERT_H__
|
||||
#define __L2V_CASSERT_H__
|
||||
|
||||
#define l2v_assert(e) WMR_ASSERT(e)
|
||||
|
||||
#define CASSERT(x, name) typedef char __CASSERT_##name[(x) ? 1 : -1]
|
||||
|
||||
#define l2v_assert_le(x, y) l2v_assert((x) <= (y))
|
||||
#define l2v_assert_lt(x, y) l2v_assert((x) < (y))
|
||||
#define l2v_assert_ge(x, y) l2v_assert((x) >= (y))
|
||||
#define l2v_assert_gt(x, y) l2v_assert((x) > (y))
|
||||
#define l2v_assert_eq(x, y) l2v_assert((x) == (y))
|
||||
#define l2v_assert_ne(x, y) l2v_assert((x) != (y))
|
||||
|
||||
#endif // __L2V_CASSERT_H__
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_CONFIG_H__
|
||||
#define __L2V_CONFIG_H__
|
||||
|
||||
// Defines the minium page size--ONLY used for easier extent (logical range) configuration
|
||||
#define L2V_MINPAGESIZE_BITS (b_4 + KiB_bits)
|
||||
|
||||
// Defines the node size
|
||||
#define L2V_CACHELINE 64
|
||||
#define L2V_NODE_SIZE L2V_CACHELINE
|
||||
|
||||
// Defines the memory set aside for the node pool
|
||||
#define L2V_NODEPOOL_MEM (MiB>>2)
|
||||
|
||||
// Defines the size of a logical tree
|
||||
#define L2V_TREE_BITS 15
|
||||
|
||||
// Repack periodicity
|
||||
#define L2V_REPACK_PERIOD 200
|
||||
|
||||
|
||||
#endif // __L2V_CONFIG_H__
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_DEFINES_H__
|
||||
#define __L2V_DEFINES_H__
|
||||
|
||||
// Shortcuts for the config
|
||||
#define b_1 0
|
||||
#define b_2 1
|
||||
#define b_4 2
|
||||
#define b_8 3
|
||||
#define b_16 4
|
||||
#define b_32 5
|
||||
#define b_64 6
|
||||
#define b_128 7
|
||||
#define b_256 8
|
||||
#define b_512 9
|
||||
#define KiB_bits 10
|
||||
#define MiB_bits 20
|
||||
#define GiB_bits 30
|
||||
#define TiB_bits 40
|
||||
#define KiB (1 << KiB_bits)
|
||||
#define MiB (1 << MiB_bits)
|
||||
#define GiB (1 << GiB_bits)
|
||||
#define TiB (1 << TiB_bits)
|
||||
|
||||
#include "L2V_Config.h"
|
||||
|
||||
|
||||
// Pointers to NAND
|
||||
// VPN bits were originally defined seperately as superblock bits, page offset bits;
|
||||
// combining them results in more flexibility. 10+3 was supposed to represent 8192 max superblocks;
|
||||
// 12 represented 4096 max pages per superblock.
|
||||
#define L2V_BITS_VPN (10+3+12)
|
||||
#define L2V_MAX_SB (1 << L2V_BITS_SB)
|
||||
#define L2V_BITS_NAND_SPAN (32 - 2 - L2V_BITS_VPN)
|
||||
|
||||
|
||||
// Node size
|
||||
#define L2V_CONTIG_ELEM_SMALL 4
|
||||
#define L2V_CONTIG_ELEM_LARGE 6
|
||||
#define L2V_MIN_CONTIG_PER_NODE (L2V_NODE_SIZE / L2V_CONTIG_ELEM_LARGE)
|
||||
#define L2V_MAX_CONTIG_PER_NODE (L2V_NODE_SIZE / L2V_CONTIG_ELEM_SMALL)
|
||||
|
||||
|
||||
// Memory usage
|
||||
#define L2V_NODEPOOL_COUNT (L2V_NODEPOOL_MEM / L2V_NODE_SIZE)
|
||||
#define L2V_BITS_NODEIDX 16
|
||||
#define L2V_BITS_NODE_SPAN (32 - 2 - L2V_BITS_NODEIDX)
|
||||
|
||||
|
||||
// Parameters
|
||||
#define L2V_SUCKUP_CHILDREN_MAX 3
|
||||
#define L2V_TRACK_VALID 0
|
||||
|
||||
|
||||
// Tree size
|
||||
#define L2V_TREE_SIZE (1 << L2V_TREE_BITS)
|
||||
#define L2V_TREE_MASK (L2V_TREE_SIZE - 1)
|
||||
#define L2V_MAX_TREE_DEPTH 32
|
||||
#define L2V_MAX_TREE_DEPTH_UPD 36
|
||||
#define L2V_TREE_DEPTH_REPACK 26
|
||||
|
||||
|
||||
// Magic numbers
|
||||
#define L2V_CONTIG_FREE_SIG 0xFFFFFFFF
|
||||
// These represent token values; normally, when we move along a span, we add to vpn and
|
||||
// subtract from span. If it's a token--such as "missing" or "deallocated"--we should
|
||||
// subtract from span, but not add to vpn, because it would change the meaning.
|
||||
#define L2V_VPN_DEALLOC ((1<<L2V_BITS_VPN)-0xfffe)
|
||||
#define L2V_VPN_MISS ((1<<L2V_BITS_VPN)-0xfffd)
|
||||
#define L2V_VPN_SPECIAL L2V_VPN_DEALLOC
|
||||
|
||||
|
||||
// Transforms
|
||||
#define L2V_IDX_TO_NODE(idx) (&L2V.Pool.Node[idx])
|
||||
#define L2V_NODE_TO_IDX(ptr) ((lNode_t*)(ptr) - &L2V.Pool.Node[0])
|
||||
|
||||
// Memory state
|
||||
#define L2V_LowMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*4))
|
||||
|
||||
|
||||
#endif // __L2V_DEFINES_H__
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_EXTERN_H__
|
||||
#define __L2V_EXTERN_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
// Define the context structure for faster macro access
|
||||
extern L2V_t L2V;
|
||||
extern UInt8 *L2V_root_depth;
|
||||
|
||||
extern BOOL32 L2V_Init(UInt32 numLbas, UInt32 numSBs, UInt32 pagesPerSB);
|
||||
extern void L2V_Free(void);
|
||||
extern void L2V_Search_Init(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Search(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Update(UInt32 lba, UInt32 size, UInt32 vpn);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
extern void L2V_ForgetBiggestTree(void);
|
||||
|
||||
#define L2V_LowMem (L2V.Pool.FreeCount <= (L2V_MAX_TREE_DEPTH*4))
|
||||
|
||||
|
||||
#endif // __L2V_EXTERN_H__
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
#include "L2V_Forget.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
static UInt32 ChooseBiggest(void);
|
||||
static void Forget(lNode_t *node);
|
||||
static void ReplaceRoot(UInt32 tree);
|
||||
|
||||
void L2V_ForgetBiggestTree()
|
||||
{
|
||||
UInt32 tree;
|
||||
|
||||
tree = ChooseBiggest();
|
||||
|
||||
// Trying to repack a rootptr? Abort...
|
||||
if (((UInt32)~0 == tree) || (!LPTR_IS_NODEPTR(L2V.Tree[tree]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
Forget(L2V_IDX_TO_NODE(LPTR_GET_NODEIDX(L2V.Tree[tree])));
|
||||
|
||||
ReplaceRoot(tree);
|
||||
}
|
||||
|
||||
static UInt32 ChooseBiggest()
|
||||
{
|
||||
UInt32 i, biggest, biggestSize;
|
||||
|
||||
biggest = ~0;
|
||||
biggestSize = 0;
|
||||
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
if (L2V.TreeNodes[i] > biggestSize) {
|
||||
biggest = i;
|
||||
biggestSize = L2V.TreeNodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return biggest;
|
||||
}
|
||||
|
||||
static void Forget(lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node and size
|
||||
lPtr_t thisPtr;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
// Recurse
|
||||
Forget(L2V_IDX_TO_NODE(cu.u.nodeIdx));
|
||||
}
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
// Free the node
|
||||
_L2V_FreeNode(node);
|
||||
}
|
||||
|
||||
static void ReplaceRoot(UInt32 tree)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Set up contig
|
||||
cu.isNodePtr = 0;
|
||||
cu.hasSpanOF = 0;
|
||||
cu.u.n.vpn = L2V_VPN_MISS;
|
||||
cu.span = 0; // Just so it's consistent... value doesn't matter in root
|
||||
|
||||
// Update tree
|
||||
L2V.Tree[tree] = LPTR_PACK_NAND(cu);
|
||||
L2V.TreeNodes[tree] = 0;
|
||||
L2V_root_depth[tree] = 0;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_FORGET_H__
|
||||
#define __L2V_FORGET_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void L2V_ForgetBiggestTree(void);
|
||||
|
||||
|
||||
#endif // __L2V_FORGET_H__
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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 "WMRFeatures.h"
|
||||
#include "L2V_Extern.h"
|
||||
|
||||
#if ENABLE_L2V_TREE
|
||||
|
||||
void L2V_Free(void)
|
||||
{
|
||||
if (0 == L2V.numRoots)
|
||||
return;
|
||||
|
||||
// Free arrays:
|
||||
|
||||
if (NULL != L2V.Tree) {
|
||||
WMR_FREE(L2V.Tree, L2V.numRoots * sizeof(lPtr_t));
|
||||
L2V.Tree = NULL;
|
||||
}
|
||||
|
||||
if (NULL != L2V.TreeNodes) {
|
||||
WMR_FREE(L2V.TreeNodes, L2V.numRoots * sizeof(UInt32));
|
||||
L2V.TreeNodes = NULL;
|
||||
}
|
||||
|
||||
if (NULL != L2V.UpdatesSinceRepack) {
|
||||
WMR_FREE(L2V.UpdatesSinceRepack, L2V.numRoots * sizeof(UInt32));
|
||||
L2V.UpdatesSinceRepack = NULL;
|
||||
}
|
||||
|
||||
if (NULL != L2V.Pool.Node) {
|
||||
WMR_FREE(L2V.Pool.Node, L2V_NODEPOOL_MEM);
|
||||
L2V.Pool.Node = NULL;
|
||||
}
|
||||
|
||||
if(L2V_root_depth != NULL)
|
||||
{
|
||||
WMR_FREE(L2V_root_depth, L2V.numRoots);
|
||||
L2V_root_depth = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
// Empty
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_FUNCS_H__
|
||||
#define __L2V_FUNCS_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
BOOL32 L2V_Init(UInt32 numLbas, UInt32 numSBs, UInt32 pagesPerSB);
|
||||
extern void L2V_Search_Init(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Search(L2V_SearchCtx_t *c);
|
||||
extern void L2V_Update(UInt32 lba, UInt32 size, UInt32 vpn);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
extern void L2V_ForgetBiggestTree(void);
|
||||
|
||||
|
||||
// Macros
|
||||
|
||||
#define _L2V_NODE_ITERATE_RESUME(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr) \
|
||||
while ((_nodeByteOfs) <= ((_nodeSize)-sizeof(lPtr_t))) { \
|
||||
(_destPtr) = *(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]); \
|
||||
if (L2V_CONTIG_FREE_SIG == (_destPtr)) { \
|
||||
break; \
|
||||
} \
|
||||
if (LPTR_IS_NODEPTR(_destPtr)) { \
|
||||
LPTR_UNPACK_NODE(_destPtr, _cu); \
|
||||
} else { \
|
||||
LPTR_UNPACK_NAND(_destPtr, _cu); \
|
||||
} \
|
||||
if ((_cu).hasSpanOF) { \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
(_cu).span += *(UInt16*)&(_node)->bytes[_nodeSize] << (LPTR_IS_NODEPTR(_destPtr) ? L2V_BITS_NODE_SPAN : L2V_BITS_NAND_SPAN); \
|
||||
l2v_assert_le(_nodeByteOfs, ((_nodeSize)-sizeof(lPtr_t))); \
|
||||
} \
|
||||
l2v_assert_ne((_cu).span, 0);
|
||||
|
||||
#define _L2V_NODE_ITERATE(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr) \
|
||||
(_nodeByteOfs) = 0; \
|
||||
(_nodeSize) = L2V_NODE_SIZE; \
|
||||
_L2V_NODE_ITERATE_RESUME(_node, _nodeByteOfs, _nodeSize, _cu, _destPtr)
|
||||
|
||||
|
||||
#define _L2V_NODE_ITERATE_NEXT(_nodeByteOfs) \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t);
|
||||
|
||||
#define _L2V_NODE_ITERATE_END_NOP }
|
||||
|
||||
#define _L2V_NODE_ITERATE_END(_nodeByteOfs) \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
}
|
||||
|
||||
#define _L2V_NODE_PUSH_CONTIG_NODE(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
{ \
|
||||
l2v_assert_ne((_cu).span, 0); \
|
||||
(_cu).hasSpanOF = 1; \
|
||||
*(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]) = LPTR_PACK_NODE(_cu); \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
*(UInt16*)&(_node)->bytes[_nodeSize] = (_cu).span >> L2V_BITS_NODE_SPAN; \
|
||||
}
|
||||
#define _L2V_NODE_PUSH_CONTIG_NAND(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
{ \
|
||||
l2v_assert_ne((_cu).span, 0); \
|
||||
(_cu).hasSpanOF = 0; \
|
||||
if ((_cu).span >= (1 << L2V_BITS_NAND_SPAN)) { \
|
||||
(_cu).hasSpanOF = 1; \
|
||||
(_nodeSize) -= sizeof(UInt16); \
|
||||
*(UInt16*)&(_node)->bytes[_nodeSize] = (_cu).span >> L2V_BITS_NAND_SPAN; \
|
||||
} \
|
||||
*(lPtr_t*)(&(_node)->bytes[_nodeByteOfs]) = LPTR_PACK_NAND(_cu); \
|
||||
(_nodeByteOfs) += sizeof(lPtr_t); \
|
||||
}
|
||||
#define _L2V_NODE_PUSH_CONTIG(_node, _nodeByteOfs, _nodeSize, _cu) \
|
||||
do { \
|
||||
if ((_cu).isNodePtr) { \
|
||||
_L2V_NODE_PUSH_CONTIG_NODE(_node, _nodeByteOfs, _nodeSize, _cu); \
|
||||
} else { \
|
||||
_L2V_NODE_PUSH_CONTIG_NAND(_node, _nodeByteOfs, _nodeSize, _cu); \
|
||||
} \
|
||||
} while (0)
|
||||
#define _L2V_CONTIG_SIZE(_cu) (sizeof(lPtr_t) + (((_cu).isNodePtr || ((_cu).span >= (1 << L2V_BITS_NAND_SPAN))) ? sizeof(UInt16) : 0))
|
||||
|
||||
#define _L2V_NODE_FILL(_node, _nodeByteOfs, _nodeSize) \
|
||||
do { \
|
||||
WMR_MEMSET(&(_node)->bytes[_nodeByteOfs], 0xFF, (_nodeSize) - (_nodeByteOfs)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // __L2V_FUNCS_H__
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Mem.h"
|
||||
|
||||
|
||||
// Declare our L2V context structure here
|
||||
L2V_t L2V;
|
||||
UInt8 *L2V_root_depth;
|
||||
|
||||
// Functions
|
||||
BOOL32 L2V_Init(UInt32 numLbas, UInt32 numSBs, UInt32 pagesPerSB)
|
||||
{
|
||||
UInt32 i;
|
||||
Int32 j;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Set number of superblocks for valid accounting division
|
||||
L2V.numSBs = numSBs;
|
||||
L2V.pagesPerSB = pagesPerSB;
|
||||
if ((numSBs * pagesPerSB) >= L2V_VPN_SPECIAL) {
|
||||
WMR_PANIC("Tree bitspace not sufficient for geometry %dx%d: please re-adjust", numSBs, pagesPerSB);
|
||||
}
|
||||
|
||||
// Set tree version
|
||||
L2V.treeVersion = 0;
|
||||
|
||||
// Calculate roots
|
||||
L2V.numRoots = (numLbas >> L2V_TREE_BITS) + 1;
|
||||
|
||||
// Allocate arrays
|
||||
L2V.Tree = WMR_MALLOC(L2V.numRoots * sizeof(lPtr_t));
|
||||
l2v_assert_ne(L2V.Tree, NULL);
|
||||
L2V.TreeNodes = WMR_MALLOC(L2V.numRoots * sizeof(UInt32));
|
||||
l2v_assert_ne(L2V.TreeNodes, NULL);
|
||||
L2V.UpdatesSinceRepack = WMR_MALLOC(L2V.numRoots * sizeof(UInt32));
|
||||
l2v_assert_ne(L2V.UpdatesSinceRepack, NULL);
|
||||
L2V_root_depth = WMR_MALLOC(L2V.numRoots);
|
||||
l2v_assert_ne(L2V_root_depth , NULL);
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
L2V_root_depth[i] = 0;
|
||||
}
|
||||
|
||||
// Empty roots; default to miss
|
||||
cu.hasSpanOF = 0;
|
||||
cu.u.n.vpn = L2V_VPN_MISS;
|
||||
cu.span = 0;
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
L2V.Tree[i] = LPTR_PACK_NAND(cu);
|
||||
}
|
||||
|
||||
// Reset periodic repacker variables
|
||||
L2V.RepackCounter = 0;
|
||||
|
||||
// Allocate the node pool
|
||||
L2V.Pool.Node = (lNode_t*)WMR_MALLOC(L2V_NODEPOOL_MEM);
|
||||
if (NULL == L2V.Pool.Node) {
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
// Finally, put all nodes in the free pool
|
||||
L2V.Pool.FreePtr = NULL;
|
||||
L2V.Pool.FreeCount = 0;
|
||||
for (j = L2V_NODEPOOL_COUNT-1; j >= 0; j--) {
|
||||
_L2V_FreeNode(&L2V.Pool.Node[j]);
|
||||
}
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
|
||||
void _L2V_FreeNode(lNode_t *node)
|
||||
{
|
||||
static int freeCount = 0;
|
||||
|
||||
freeCount++;
|
||||
|
||||
l2v_assert_ge(node, &L2V.Pool.Node[0]);
|
||||
l2v_assert_le(node, &L2V.Pool.Node[L2V_NODEPOOL_COUNT]);
|
||||
|
||||
node->nextFreePtr = L2V.Pool.FreePtr;
|
||||
L2V.Pool.FreePtr = node;
|
||||
L2V.Pool.FreeCount++;
|
||||
}
|
||||
|
||||
|
||||
lNode_t *_L2V_AllocNode()
|
||||
{
|
||||
lNode_t *ret;
|
||||
static int allocCount = 0;
|
||||
|
||||
allocCount++;
|
||||
|
||||
ret = (lNode_t*)L2V.Pool.FreePtr;
|
||||
if (NULL != ret) {
|
||||
L2V.Pool.FreePtr = L2V.Pool.FreePtr->nextFreePtr;
|
||||
L2V.Pool.FreeCount--;
|
||||
}
|
||||
l2v_assert_ne(ret, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_MEM_H__
|
||||
#define __L2V_MEM_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void _L2V_FreeNode(lNode_t *node);
|
||||
extern lNode_t *_L2V_AllocNode(void); // Warning: may return NULL; up to caller to handle gracefully
|
||||
|
||||
|
||||
#endif // __L2V_MEM_H__
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Print.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V.h"
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
#define PRINT_MAXPATH 0
|
||||
|
||||
|
||||
// Prototypes
|
||||
|
||||
static int L2V_GetUsage(lNode_t *node, UInt32 *used, UInt32 *total, UInt32 *nodes, UInt32 totalSpan, BOOL32 isMax);
|
||||
|
||||
|
||||
// Functions
|
||||
|
||||
void L2V_PrintPtr(lPtr_t lptr)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
LPTR_UNPACK(lptr, cu);
|
||||
L2V_PrintCU(&cu);
|
||||
}
|
||||
|
||||
void L2V_PrintCU(ContigUnpacked_t *cu)
|
||||
{
|
||||
if (cu->isNodePtr)
|
||||
printf("[Node]");
|
||||
else
|
||||
printf("[NAND]");
|
||||
|
||||
if (cu->hasSpanOF)
|
||||
printf("o");
|
||||
else
|
||||
printf("-");
|
||||
|
||||
if (cu->isNodePtr) {
|
||||
printf("[idx:%d][span:%d]", cu->u.nodeIdx, cu->span);
|
||||
} else {
|
||||
printf("[vpn:%d][span:%d]", cu->u.n.vpn, cu->span);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
void L2V_PrintNode(lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize;
|
||||
lPtr_t thisPtr;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
L2V_PrintCU(&cu);
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
}
|
||||
|
||||
|
||||
void L2V_PrintUsage(UInt32 tree)
|
||||
{
|
||||
UInt32 used, total, nodes, maxdepth;
|
||||
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
used = total = nodes = maxdepth = 0;
|
||||
printf("Max depth path: ");
|
||||
printf("digraph G {\n");
|
||||
LPTR_UNPACK(L2V.Tree[tree], cu);
|
||||
if (cu.isNodePtr) {
|
||||
maxdepth = L2V_GetUsage(L2V_IDX_TO_NODE(cu.u.nodeIdx), &used, &total, &nodes, L2V_TREE_SIZE, 1);
|
||||
}
|
||||
printf("}\n");
|
||||
printf("\nUsage tree %d: %.2f, nodes: %d, maxdepth: %d\n", tree, (float)used/(float)total, nodes, maxdepth);
|
||||
printf("Nodes calc: %d tally: %d\n\n", nodes, L2V.TreeNodes[tree]);
|
||||
if (nodes != L2V.TreeNodes[tree]) while(1);//DP
|
||||
//l2v_assert_eq(nodes, L2V_NODEPOOL_COUNT - L2V.Pool.FreeCount); // Only valid when using 1 tree
|
||||
}
|
||||
|
||||
static int L2V_GetUsage(lNode_t *node, UInt32 *used, UInt32 *total, UInt32 *nodes, UInt32 totalSpan, BOOL32 isMax)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
UInt32 sumSpan;
|
||||
lPtr_t thisPtr, maxNode;
|
||||
UInt32 depth, maxDepth, maxSpan;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
// Walk through
|
||||
(*nodes)++;
|
||||
maxDepth = 0;
|
||||
sumSpan = 0;
|
||||
|
||||
// Iterate through the node,
|
||||
L2V_PrintNode(node);
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
printf("%d -> %d;\n", (int)L2V_NODE_TO_IDX(node), cu.u.nodeIdx); // DOT output
|
||||
l2v_assert_ne(cu.u.nodeIdx, 65535);
|
||||
l2v_assert_ne(L2V_IDX_TO_NODE(cu.u.nodeIdx), node);
|
||||
l2v_assert_ne(cu.span, 0);
|
||||
depth = L2V_GetUsage(L2V_IDX_TO_NODE(cu.u.nodeIdx), used, total, nodes, cu.span, 0);
|
||||
if (depth > maxDepth) {
|
||||
maxDepth = depth;
|
||||
maxNode = thisPtr;
|
||||
maxSpan = cu.span;
|
||||
}
|
||||
}
|
||||
sumSpan += cu.span;
|
||||
l2v_assert_le(cu.span, 32768);
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
*used += nOfs;
|
||||
*total += sizeof(lNode_t);
|
||||
printf("%d [label=\"us:%.2f\\nsp:%.2f\",shape=box,style=filled,color=\"1.0 %.2f 1.0\"];\n", (int)L2V_NODE_TO_IDX(node), (float)nOfs/sizeof(lNode_t), (float)totalSpan/L2V_TREE_SIZE, (float)nOfs/sizeof(lNode_t)); // DOT output
|
||||
|
||||
if (sumSpan != totalSpan) {
|
||||
printf("Sum: %d, total: %d\n", sumSpan, totalSpan);
|
||||
L2V_PrintNode(node);
|
||||
}
|
||||
l2v_assert_eq(sumSpan, totalSpan);
|
||||
l2v_assert_ne(nOfs, 0);
|
||||
|
||||
#if PRINT_MAXPATH
|
||||
if (maxDepth && isMax) {
|
||||
printf("<-%d", maxNode.node.nodeIdx);
|
||||
L2V_GetUsage(L2V_LPTR_TO_NODE(maxNode), &nOfs, &nOfs, &nOfs, maxSpan, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return maxDepth+1;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_PRINT_H__
|
||||
#define __L2V_PRINT_H__
|
||||
|
||||
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
extern void L2V_PrintPtr(lPtr_t lptr);
|
||||
extern void L2V_PrintCU(ContigUnpacked_t *cu);
|
||||
extern void L2V_PrintNode(lNode_t *node);
|
||||
extern void L2V_PrintUsage(UInt32 tree);
|
||||
|
||||
|
||||
#endif // __L2V_PRINT_H__
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#define AND_TRACE_LAYER FTL
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Repack.h"
|
||||
#include "L2V.h"
|
||||
#include "L2V_Types.h"
|
||||
#include "L2V_Mem.h"
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
|
||||
#define REPACK_MAX_NODES (L2V_TREE_SIZE/L2V_MIN_CONTIG_PER_NODE)
|
||||
#define REPACK_TREE_LOG_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
lNode_t *bottom[REPACK_MAX_NODES];
|
||||
UInt32 bottomSpan[REPACK_MAX_NODES];
|
||||
UInt32 bottomIdx;
|
||||
UInt32 bottom_nOfs;
|
||||
UInt32 bottom_nodeSize;
|
||||
UInt32 repackTreeLog[REPACK_TREE_LOG_SIZE];
|
||||
UInt32 repackTreeLogIdx;
|
||||
} RepackCtx_t;
|
||||
|
||||
|
||||
// Static definitions
|
||||
static void CopyAndDestroy(RepackCtx_t *r, lNode_t *node);
|
||||
static int Rebuild(RepackCtx_t *r);
|
||||
static void ReplaceRoot(RepackCtx_t *r, UInt32 tree);
|
||||
|
||||
|
||||
void L2V_PeriodicRepack()
|
||||
{
|
||||
Int32 best;
|
||||
UInt32 merit, bestMerit, i;
|
||||
|
||||
// Check if it's appropriate or not
|
||||
if (L2V.RepackCounter < L2V_REPACK_PERIOD) {
|
||||
return;
|
||||
}
|
||||
L2V.RepackCounter = 0;
|
||||
|
||||
// Find best candidate; merit==updates
|
||||
bestMerit = 0;
|
||||
best = -1;
|
||||
for (i = 0; i < L2V.numRoots; i++) {
|
||||
merit = L2V.UpdatesSinceRepack[i];
|
||||
if (merit >= bestMerit) {
|
||||
bestMerit = merit;
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
l2v_assert_ne(best, -1);
|
||||
|
||||
L2V_Repack(best);
|
||||
}
|
||||
|
||||
|
||||
// WARNING: NOT REENTRANT
|
||||
static RepackCtx_t r;
|
||||
void L2V_Repack(UInt32 tree)
|
||||
{
|
||||
lNode_t *root;
|
||||
ContigUnpacked_t cu;
|
||||
|
||||
LPTR_UNPACK(L2V.Tree[tree], cu);
|
||||
|
||||
// Trying to repack a rootptr? Abort...
|
||||
if (!cu.isNodePtr) {
|
||||
return;
|
||||
}
|
||||
|
||||
WMR_TRACE_1(Repack, START, tree);
|
||||
|
||||
// Up tree version for search-update coherency
|
||||
L2V.treeVersion++;
|
||||
|
||||
// Create list of new bottom layer
|
||||
r.bottomIdx = 0;
|
||||
r.bottom_nOfs = 0;
|
||||
r.bottom_nodeSize = L2V_NODE_SIZE;
|
||||
WMR_MEMSET(r.bottom, 0, REPACK_MAX_NODES * sizeof(r.bottom[0]));
|
||||
WMR_MEMSET(r.bottomSpan, 0, REPACK_MAX_NODES * sizeof(r.bottomSpan[0]));
|
||||
|
||||
// Recurse and destroy
|
||||
root = L2V_IDX_TO_NODE(cu.u.nodeIdx);
|
||||
CopyAndDestroy(&r, root);
|
||||
|
||||
l2v_assert_ne(r.bottom_nOfs, 0);
|
||||
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(r.bottom[r.bottomIdx], r.bottom_nOfs, r.bottom_nodeSize);
|
||||
|
||||
// Rebuild hierarchy
|
||||
L2V.TreeNodes[tree] = Rebuild(&r);
|
||||
|
||||
// Replace root
|
||||
ReplaceRoot(&r, tree);
|
||||
|
||||
// Clear repack counter
|
||||
L2V.UpdatesSinceRepack[tree] = 0;
|
||||
|
||||
|
||||
// Log which tree we repacked
|
||||
if (r.repackTreeLogIdx >= REPACK_TREE_LOG_SIZE) {
|
||||
r.repackTreeLogIdx = 0;
|
||||
}
|
||||
r.repackTreeLog[r.repackTreeLogIdx] = tree;
|
||||
r.repackTreeLogIdx++;
|
||||
|
||||
WMR_TRACE_0(Repack, END);
|
||||
}
|
||||
|
||||
|
||||
static void CopyAndDestroy(RepackCtx_t *r, lNode_t *node)
|
||||
{
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr) {
|
||||
// Recurse
|
||||
CopyAndDestroy(r, L2V_IDX_TO_NODE(cu.u.nodeIdx));
|
||||
} else {
|
||||
// Would be full? Move along...
|
||||
if ((r->bottom_nOfs + _L2V_CONTIG_SIZE(cu)) > r->bottom_nodeSize) {
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(r->bottom[r->bottomIdx], r->bottom_nOfs, r->bottom_nodeSize);
|
||||
|
||||
r->bottomIdx++;
|
||||
l2v_assert_lt(r->bottomIdx, REPACK_MAX_NODES);
|
||||
}
|
||||
|
||||
// Allocate node if necessary
|
||||
if (NULL == r->bottom[r->bottomIdx]) {
|
||||
// Allocate...
|
||||
r->bottom[r->bottomIdx] = _L2V_AllocNode();
|
||||
r->bottom_nOfs = 0;
|
||||
r->bottom_nodeSize = L2V_NODE_SIZE;
|
||||
}
|
||||
|
||||
// Copy out
|
||||
_L2V_NODE_PUSH_CONTIG(r->bottom[r->bottomIdx], r->bottom_nOfs, r->bottom_nodeSize, cu);
|
||||
r->bottomSpan[r->bottomIdx] += cu.span;
|
||||
l2v_assert_le(cu.span, L2V_TREE_SIZE);
|
||||
}
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
// Free the node
|
||||
_L2V_FreeNode(node);
|
||||
}
|
||||
|
||||
|
||||
static int Rebuild(RepackCtx_t *r)
|
||||
{
|
||||
lNode_t *thisBranch;
|
||||
UInt32 nOfs, nodeSize, thisSpan, i, branchIdx;
|
||||
ContigUnpacked_t cu;
|
||||
int nodeCount;
|
||||
|
||||
nodeCount = r->bottomIdx+1;
|
||||
while (r->bottomIdx > 0) {
|
||||
thisBranch = _L2V_AllocNode();
|
||||
nodeCount++;
|
||||
nOfs = 0;
|
||||
nodeSize = L2V_NODE_SIZE;
|
||||
thisSpan = 0;
|
||||
branchIdx = 0;
|
||||
|
||||
// Rebuild this layer
|
||||
for (i = 0; i <= r->bottomIdx; i++) {
|
||||
cu.isNodePtr = 1;
|
||||
cu.u.nodeIdx = L2V_NODE_TO_IDX(r->bottom[i]);
|
||||
cu.span = r->bottomSpan[i];
|
||||
|
||||
if ((nOfs + _L2V_CONTIG_SIZE(cu)) > nodeSize) {
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(thisBranch, nOfs, nodeSize);
|
||||
|
||||
// Place it down and get a new one
|
||||
r->bottom[branchIdx] = thisBranch;
|
||||
r->bottomSpan[branchIdx] = thisSpan;
|
||||
branchIdx++;
|
||||
thisBranch = _L2V_AllocNode();
|
||||
nodeCount++;
|
||||
nOfs = 0;
|
||||
nodeSize = L2V_NODE_SIZE;
|
||||
thisSpan = 0;
|
||||
}
|
||||
|
||||
_L2V_NODE_PUSH_CONTIG(thisBranch, nOfs, nodeSize, cu);
|
||||
thisSpan += cu.span;
|
||||
}
|
||||
|
||||
l2v_assert_ne(nOfs, 0);
|
||||
|
||||
r->bottom[branchIdx] = thisBranch;
|
||||
r->bottomSpan[branchIdx] = thisSpan;
|
||||
// Fill rest with "empty" markers
|
||||
_L2V_NODE_FILL(thisBranch, nOfs, nodeSize);
|
||||
|
||||
// Make sure the repack didn't munge the root node's spans
|
||||
if (0 == branchIdx) {
|
||||
l2v_assert_eq(thisSpan, L2V_TREE_SIZE);
|
||||
}
|
||||
|
||||
// Get ready for the next round
|
||||
r->bottomIdx = branchIdx;
|
||||
}
|
||||
|
||||
return nodeCount;
|
||||
}
|
||||
|
||||
|
||||
static void ReplaceRoot(RepackCtx_t *r, UInt32 tree)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
l2v_assert_eq(r->bottomIdx, 0);
|
||||
cu.u.nodeIdx = L2V_NODE_TO_IDX(r->bottom[0]);
|
||||
cu.hasSpanOF = 0;
|
||||
cu.span = 0;
|
||||
L2V.Tree[tree] = LPTR_PACK_NODE(cu);
|
||||
if (!LPTR_IS_NODEPTR(L2V.Tree[tree])) {
|
||||
L2V_root_depth[tree] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_REPACK_H__
|
||||
#define __L2V_REPACK_H__
|
||||
|
||||
|
||||
#include "WMROAM.h"
|
||||
|
||||
// Functions
|
||||
|
||||
extern void L2V_PeriodicRepack(void);
|
||||
extern void L2V_Repack(UInt32 tree);
|
||||
|
||||
|
||||
#endif // __L2V_REPACK_H__
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
|
||||
|
||||
void L2V_Search_Init(L2V_SearchCtx_t *c)
|
||||
{
|
||||
c->next_lba = 0xffffffff;
|
||||
c->last_node = NULL;
|
||||
c->span = 0;
|
||||
}
|
||||
|
||||
|
||||
static BOOL32 HitCache(L2V_SearchCtx_t *c)
|
||||
{
|
||||
ContigUnpacked_t cu;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
|
||||
if ((c->treeVersion == L2V.treeVersion) && (c->lba == c->next_lba) && (NULL != c->last_node)) {
|
||||
// Sequential HIT
|
||||
_L2V_NODE_ITERATE_RESUME(c->last_node, c->next_nOfs, c->nodeSize, cu, thisPtr) {
|
||||
if (cu.isNodePtr)
|
||||
break;
|
||||
|
||||
c->vpn = cu.u.n.vpn;
|
||||
c->fromStart = 0;
|
||||
c->span = cu.span;
|
||||
|
||||
_L2V_NODE_ITERATE_NEXT(c->next_nOfs); // This will move nOfs along
|
||||
c->next_lba = c->lba + c->span;
|
||||
return TRUE32;
|
||||
|
||||
} _L2V_NODE_ITERATE_END_NOP;
|
||||
}
|
||||
|
||||
// Clear search history
|
||||
c->next_lba = 0xffffffff;
|
||||
c->last_node = NULL;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
void L2V_Search(L2V_SearchCtx_t *c)
|
||||
{
|
||||
UInt32 targTree, targTofs;
|
||||
UInt32 thisStart, thisMax;
|
||||
UInt32 nOfs, nodeSize; // Byte offset within the node, and node effective size
|
||||
ContigUnpacked_t cu, thiscu;
|
||||
lNode_t *node = NULL;
|
||||
lPtr_t thisPtr;
|
||||
|
||||
if (HitCache(c)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine first root
|
||||
targTree = c->lba >> L2V_TREE_BITS;
|
||||
targTofs = c->lba & L2V_TREE_MASK;
|
||||
l2v_assert_lt(targTree, L2V.numRoots);
|
||||
|
||||
c->level = 0;
|
||||
thisStart = 0;
|
||||
c->vpn = L2V_VPN_MISS;
|
||||
LPTR_UNPACK(L2V.Tree[targTree], cu);
|
||||
thiscu.span = L2V_TREE_SIZE;
|
||||
c->next_nOfs = 0;
|
||||
|
||||
// Search from top down
|
||||
while (c->level < L2V_MAX_TREE_DEPTH) {
|
||||
// Down and next
|
||||
// Decode node pointer
|
||||
if (!cu.isNodePtr) {
|
||||
// Terminal case--pointer to physical location; calculate relative offset...
|
||||
c->vpn = cu.u.n.vpn;
|
||||
c->fromStart = targTofs - thisStart;
|
||||
if (cu.u.n.vpn < L2V_VPN_SPECIAL) {
|
||||
c->vpn += c->fromStart;
|
||||
}
|
||||
c->span = thiscu.span - c->fromStart;
|
||||
// Set up return case for sequential searching
|
||||
c->last_node = node;
|
||||
c->next_lba = c->lba + c->span;
|
||||
c->treeVersion = L2V.treeVersion;
|
||||
// c->next_nOfs is populated from code below, i.e. the previous iteration of this while loop
|
||||
|
||||
// Is it getting really big? Do some preventative maintenence...
|
||||
if (c->level >= L2V_TREE_DEPTH_REPACK) {
|
||||
L2V_Repack(targTree);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Walk through
|
||||
node = L2V_IDX_TO_NODE(cu.u.nodeIdx);
|
||||
|
||||
// Iterate through the node,
|
||||
_L2V_NODE_ITERATE(node, nOfs, nodeSize, thiscu, thisPtr) {
|
||||
// Calculate endpoint
|
||||
thisMax = thisStart + thiscu.span;
|
||||
|
||||
// Are we in range?
|
||||
if (targTofs < thisMax) {
|
||||
// HIT! (Left-hand side implied by order of search.)
|
||||
cu = thiscu;
|
||||
_L2V_NODE_ITERATE_NEXT(nOfs);
|
||||
c->next_nOfs = nOfs;
|
||||
c->nodeSize = nodeSize;
|
||||
goto decodePtr;
|
||||
}
|
||||
|
||||
// Move along in the node
|
||||
thisStart = thisMax;
|
||||
} _L2V_NODE_ITERATE_END(nOfs);
|
||||
|
||||
WMR_PANIC("NAND index: bad tree: targTofs %d, level %d\n", targTofs, c->level);
|
||||
|
||||
decodePtr:
|
||||
// Resume here so we can check the while() condition
|
||||
c->level++;
|
||||
}
|
||||
|
||||
l2v_assert(0); // Should never get here; otherwise, the tree is too deep (or recursive or pointing to randomness)
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "L2V.h"
|
||||
#include "L2V_Funcs.h"
|
||||
#include "L2V_Print.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
L2V_t L2V;
|
||||
|
||||
|
||||
#define LAST_TREE_TEST 16
|
||||
#define SIMPLE_SIZE (L2V_TREE_SIZE*LAST_TREE_TEST)
|
||||
|
||||
|
||||
// Prototypes
|
||||
static void RandomTest(void);
|
||||
static void SequentialTest(void);
|
||||
static void Simple_Init(void);
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vpn);
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vpn);
|
||||
|
||||
void Usage(int argc, char** argv)
|
||||
{
|
||||
printf("Usage: %s s OR %s r (for sequential and random, respectively\n", argv[0], argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int test = 0;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
L2V_Init(SIMPLE_SIZE, (L2V_VPN_SPECIAL-1) / 8192, 8192);
|
||||
|
||||
if (argc == 2) {
|
||||
if ('r' == argv[1][0]) {
|
||||
test = 0;
|
||||
} else if ('s' == argv[1][0]) {
|
||||
test = 1;
|
||||
} else {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
}
|
||||
if (argc > 2) {
|
||||
Usage(argc, argv);
|
||||
}
|
||||
|
||||
if (0 == test) {
|
||||
RandomTest();
|
||||
} else {
|
||||
SequentialTest();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define MAXLEN 512
|
||||
static void RandomTest() {
|
||||
UInt32 lba, size, vpn;
|
||||
UInt32 i, svpn;
|
||||
L2V_SearchCtx_t c;
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Simple_Init();
|
||||
|
||||
sranddev();
|
||||
|
||||
while (1) {
|
||||
lba = rand() % ((L2V_TREE_SIZE*LAST_TREE_TEST)-MAXLEN);
|
||||
size = (rand() % (MAXLEN-1))+1;
|
||||
vpn = rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
|
||||
printf("[UPD: lba:%d, size:%d, vpn:%d]\n", lba, size, vpn);
|
||||
L2V_Update(lba, size, vpn);
|
||||
Simple_Update(lba, size, vpn);
|
||||
//printf("\n");
|
||||
//L2V_PrintNode(L2V_LPTR_TO_NODE(L2V.Tree[0]));
|
||||
L2V_PrintUsage(0);
|
||||
|
||||
|
||||
// Validate entire range
|
||||
int maxlevel=0;
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_Lookup(i, &svpn);
|
||||
c.lba = i;
|
||||
L2V_Search(&c);
|
||||
if (c.level > maxlevel) maxlevel = c.level;
|
||||
if (svpn != c.vpn) {
|
||||
printf("\n\n\n");
|
||||
printf("====================\n");
|
||||
printf("MISMATCH lba:%d\n", i);
|
||||
printf("--------------------\n");
|
||||
printf("Simple vpn:%d\n", svpn);
|
||||
printf("Lookup vpn:%d\n", c.vpn);
|
||||
}
|
||||
l2v_assert_eq(svpn, c.vpn);
|
||||
}
|
||||
printf("maxlevel: %d\n", maxlevel);
|
||||
l2v_assert_lt(maxlevel, L2V_MAX_TREE_DEPTH);
|
||||
|
||||
#if 0
|
||||
if (repack++ > 10) {
|
||||
printf("Repacking tree %d...\n", nextRepack);
|
||||
L2V_Repack(nextRepack);
|
||||
L2V_PrintUsage(nextRepack);
|
||||
repack = 0;
|
||||
nextRepack = (nextRepack + 1) % LAST_TREE_TEST;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void SequentialTest() {
|
||||
UInt32 lba, size, vpn;
|
||||
UInt32 i, svpn;
|
||||
L2V_SearchCtx_t c;
|
||||
|
||||
L2V_Search_Init(&c);
|
||||
|
||||
Simple_Init();
|
||||
|
||||
sranddev();
|
||||
|
||||
lba = 0;
|
||||
size = 0;
|
||||
vpn = 1;
|
||||
|
||||
while (1) {
|
||||
lba += size;
|
||||
size = (rand() % (MAXLEN-1))+1;
|
||||
if ((lba + size) >= L2V_TREE_SIZE) {
|
||||
lba = 0;
|
||||
}
|
||||
if ((rand() & 3) == 0) {
|
||||
vpn = rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
}
|
||||
while (((vpn + size) & ((1<<(L2V_BITS_VPN-1))-1)) < vpn) {
|
||||
vpn = rand() % ((1<<(L2V_BITS_VPN-1))-size-1);
|
||||
}
|
||||
|
||||
printf("[UPD: lba:%d, size:%d, vpn:%d]\n", lba, size, vpn);
|
||||
L2V_Update(lba, size, vpn);
|
||||
Simple_Update(lba, size, vpn);
|
||||
L2V_PrintUsage(0);
|
||||
vpn += size;
|
||||
|
||||
|
||||
// Validate entire range
|
||||
int maxlevel=0;
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_Lookup(i, &svpn);
|
||||
c.lba = i;
|
||||
L2V_Search(&c);
|
||||
if (c.level > maxlevel) maxlevel = c.level;
|
||||
if (svpn != c.vpn) {
|
||||
printf("\n\n\n");
|
||||
printf("====================\n");
|
||||
printf("MISMATCH lba:%d\n", i);
|
||||
printf("--------------------\n");
|
||||
printf("Simple vpn:%d\n", svpn);
|
||||
printf("Lookup vpn:%d\n", c.vpn);
|
||||
}
|
||||
l2v_assert_eq(svpn, c.vpn);
|
||||
}
|
||||
printf("maxlevel: %d\n", maxlevel);
|
||||
l2v_assert_lt(maxlevel, L2V_MAX_TREE_DEPTH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 Simple_vpn[SIMPLE_SIZE];
|
||||
|
||||
static void Simple_Init()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < SIMPLE_SIZE; i++) {
|
||||
Simple_vpn[i] = L2V_VPN_MISS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Update(UInt32 lba, UInt32 size, UInt32 vpn)
|
||||
{
|
||||
while (size) {
|
||||
Simple_vpn[lba] = vpn;
|
||||
|
||||
// Iterate
|
||||
lba++;
|
||||
if (vpn < L2V_VPN_SPECIAL) {
|
||||
vpn++;
|
||||
}
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void Simple_Lookup(UInt32 lba, UInt32 *vpn)
|
||||
{
|
||||
*vpn = Simple_vpn[lba];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
OBJS=L2V_Test.o L2V_Funcs.o L2V_Init.o L2V_Mem.o L2V_Search.o L2V_Update.o L2V_Valid.o L2V_Types.o L2V_Print.o L2V_Repack.o L2V_Forget.o L2V_Free.o WMROAM.o
|
||||
LINK_TARGET=L2V_Test
|
||||
REBUILDABLES=$(OBJS) $(LINK_TARGET)
|
||||
|
||||
.PHONY: all
|
||||
all: copythem $(LINK_TARGET) cleanthem
|
||||
#
|
||||
|
||||
.PHONY: copythem
|
||||
copythem:
|
||||
cp WMROAM-test.h WMROAM.h
|
||||
cp WMROAM-test.c WMROAM.c
|
||||
cp WMRFeatures-test.h WMRFeatures.h
|
||||
|
||||
.PHONY: cleanthem
|
||||
cleanthem:
|
||||
rm WMROAM.c WMROAM.h WMRFeatures.h
|
||||
|
||||
$(LINK_TARGET): $(OBJS)
|
||||
gcc -g -o $@ $^ -Wall
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(REBUILDABLES)
|
||||
rm WMROAM.c WMROAM.h WMRFeatures.h
|
||||
|
||||
%.o: %.c
|
||||
gcc -g -o $@ -c $< -Wall -I.
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V_Defines.h"
|
||||
#include "L2V_Types.h"
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig(lNodeBig_t *big, ContigUnpacked_t *cu)
|
||||
{
|
||||
Int32 last = ((Int32)big->max)-1;
|
||||
l2v_assert_ne(cu->span, 0);
|
||||
|
||||
if (!cu->isNodePtr && (last >= 0) && !big->cu[last].isNodePtr && (
|
||||
((cu->u.n.vpn < L2V_VPN_SPECIAL) && ((big->cu[last].u.n.vpn+big->cu[last].span) == cu->u.n.vpn))
|
||||
|| ((cu->u.n.vpn >= L2V_VPN_SPECIAL) && (big->cu[last].u.n.vpn == cu->u.n.vpn))))
|
||||
{
|
||||
big->cu[last].span += cu->span;
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
big->cu[big->max] = *cu;
|
||||
big->max++;
|
||||
|
||||
if (cu->isNodePtr) {
|
||||
l2v_assert_lt(cu->u.nodeIdx, L2V_NODEPOOL_COUNT);
|
||||
}
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig_Node(lNodeBig_t *big, UInt32 nodeIdx, UInt32 span)
|
||||
{
|
||||
big->cu[big->max].isNodePtr = 1;
|
||||
big->cu[big->max].u.nodeIdx = nodeIdx;
|
||||
big->cu[big->max].span = span;
|
||||
big->max++;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
|
||||
BOOL32 _L2V_NodeBig_PushContig_Nand(lNodeBig_t *big, UInt32 vpn, UInt32 span)
|
||||
{
|
||||
Int32 last = ((Int32)big->max)-1;
|
||||
l2v_assert_ne(span, 0);
|
||||
|
||||
if ((last >= 0) && !big->cu[last].isNodePtr && (
|
||||
((vpn < L2V_VPN_SPECIAL) && ((big->cu[last].u.n.vpn+big->cu[last].span) == vpn))
|
||||
|| ((vpn >= L2V_VPN_SPECIAL) && (big->cu[last].u.n.vpn == vpn))))
|
||||
{
|
||||
big->cu[last].span += span;
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
big->cu[big->max].isNodePtr = 0;
|
||||
big->cu[big->max].u.n.vpn = vpn;
|
||||
big->cu[big->max].span = span;
|
||||
big->max++;
|
||||
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_TYPES_H__
|
||||
#define __L2V_TYPES_H__
|
||||
|
||||
|
||||
#include "WMROAM.h"
|
||||
#include "L2V_Defines.h"
|
||||
#include "L2V_Assert.h"
|
||||
|
||||
|
||||
// Pointer type: can point to NAND, or to a subtree
|
||||
// Bits: 0=isNodePtr, 1=hasSpanOF.
|
||||
// isNodePtr=0: vpn:L2V_BITS_VPN, span:L2V_BITS_NAND_SPAN
|
||||
// isNodePtr=1: nodeIdx:L2V_BITS_NODEIDX, span:L2V_BITS_NODE_SPAN
|
||||
// hasSpanOF: fetch 2 bytes from the right end of the node
|
||||
|
||||
typedef UInt32 lPtr_t;
|
||||
#define LPTR_IS_NODEPTR(_lptr) ((_lptr) & 1)
|
||||
#define LPTR_HASSPANOF(_lptr) (((_lptr) & 2) >> 1)
|
||||
#define LPTR_PACK_NAND(_cu) ( \
|
||||
(((_cu).hasSpanOF & 1) << 1) | \
|
||||
(((_cu).u.n.vpn & (((1 <<L2V_BITS_VPN)-1))) << 2) | \
|
||||
(((_cu).span & ((1<<L2V_BITS_NAND_SPAN)-1)) << (2+L2V_BITS_VPN)) \
|
||||
)
|
||||
#define LPTR_PACK_NODE(_cu) ( \
|
||||
1 | \
|
||||
(((_cu).hasSpanOF & 1) << 1) | \
|
||||
(((_cu).u.nodeIdx & ((1 << L2V_BITS_NODEIDX)-1)) << 2) | \
|
||||
(((_cu).span & (((1 <<L2V_BITS_NODE_SPAN)-1))) << (2+L2V_BITS_NODEIDX)) \
|
||||
)
|
||||
#define LPTR_UNPACK_NAND(_lptr, _cu) do { \
|
||||
(_cu).isNodePtr = 0; \
|
||||
(_cu).hasSpanOF = ((_lptr) >> 1) & 1; \
|
||||
(_cu).u.n.vpn = ((_lptr) >> 2) & ((1 << L2V_BITS_VPN)-1); \
|
||||
(_cu).span = ((_lptr) >> (2+L2V_BITS_VPN)) & ((1 << L2V_BITS_NAND_SPAN)-1); \
|
||||
} while (0)
|
||||
#define LPTR_UNPACK_NODE(_lptr, _cu) do { \
|
||||
(_cu).isNodePtr = 1; \
|
||||
(_cu).hasSpanOF = ((_lptr) >> 1) & 1; \
|
||||
(_cu).u.nodeIdx = ((_lptr) >> 2) & ((1 << L2V_BITS_NODEIDX)-1); \
|
||||
(_cu).span = ((_lptr) >> (2+L2V_BITS_NODEIDX)) & ((1 << L2V_BITS_NODE_SPAN)-1); \
|
||||
} while (0)
|
||||
#define LPTR_GET_NODEIDX(_lptr) (((_lptr) >> 2) & ((1 << L2V_BITS_NODEIDX)-1))
|
||||
#define LPTR_UNPACK(_lptr, _cu) do { \
|
||||
if LPTR_IS_NODEPTR(_lptr) { \
|
||||
LPTR_UNPACK_NODE(_lptr, _cu); \
|
||||
} else { \
|
||||
LPTR_UNPACK_NAND(_lptr, _cu); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
UInt32 isNodePtr; // Values: 0, 1 (true)... must not be any other value
|
||||
UInt32 hasSpanOF; // Values: 0, 1 (true)... ditto
|
||||
union {
|
||||
struct {
|
||||
UInt32 vpn;
|
||||
} n;
|
||||
UInt32 nodeIdx;
|
||||
} u;
|
||||
UInt32 span;
|
||||
} ContigUnpacked_t;
|
||||
|
||||
|
||||
// Node type: union for dynamic and fixed node types (and FreePool linkage)
|
||||
typedef union _lNode_t {
|
||||
union _lNode_t *nextFreePtr;
|
||||
|
||||
UInt8 bytes[L2V_NODE_SIZE];
|
||||
} lNode_t;
|
||||
CASSERT(L2V_NODE_SIZE == sizeof(lNode_t), lNode_t_size_matches);
|
||||
|
||||
#define L2V_LNODEBIG_MAX (L2V_MAX_CONTIG_PER_NODE+(L2V_SUCKUP_CHILDREN_MAX*2)+5)
|
||||
typedef struct {
|
||||
ContigUnpacked_t cu[L2V_LNODEBIG_MAX];
|
||||
UInt32 start;
|
||||
UInt32 max;
|
||||
} lNodeBig_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
lNode_t *Node; // Node pool allocated with malloc()
|
||||
lNode_t *FreePtr;
|
||||
UInt32 FreeCount;
|
||||
} FTLight_NodePool_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
// Logical space
|
||||
UInt32 numRoots;
|
||||
lPtr_t *Tree;
|
||||
UInt32 *TreeNodes;
|
||||
UInt32 *UpdatesSinceRepack;
|
||||
UInt32 RepackCounter;
|
||||
UInt32 treeVersion;
|
||||
|
||||
// Physical space
|
||||
UInt32 numSBs;
|
||||
UInt32 pagesPerSB;
|
||||
#if L2V_TRACK_VALID!=0
|
||||
UInt32 Valid[L2V_MAX_SB];
|
||||
#endif
|
||||
|
||||
// Memory
|
||||
FTLight_NodePool_t Pool;
|
||||
} L2V_t;
|
||||
|
||||
typedef struct {
|
||||
// Input:
|
||||
UInt32 lba;
|
||||
|
||||
// Output:
|
||||
UInt32 fromStart; // blocks from start of treeSpan
|
||||
UInt32 vpn;
|
||||
UInt32 span;
|
||||
|
||||
// Internal state:
|
||||
lNode_t *last_node;
|
||||
UInt32 next_lba;
|
||||
UInt32 next_nOfs;
|
||||
UInt32 nodeSize;
|
||||
UInt32 level;
|
||||
UInt32 treeVersion;
|
||||
} L2V_SearchCtx_t;
|
||||
|
||||
|
||||
// Helper functions
|
||||
|
||||
extern BOOL32 _L2V_NodeBig_PushContig(lNodeBig_t *big, ContigUnpacked_t *cu); // True: compressed with left
|
||||
extern BOOL32 _L2V_NodeBig_PushContig_Node(lNodeBig_t *big, UInt32 nodeIdx, UInt32 span); // True: compress with left (always false)
|
||||
extern BOOL32 _L2V_NodeBig_PushContig_Nand(lNodeBig_t *big, UInt32 vpn, UInt32 span); // True: compressed with left
|
||||
#define _L2V_NodeBig_WillCompress(_big, _vpn, _span) \
|
||||
((_big.max > 0) && (!_big.cu[_big.max-1].isNodePtr) && \
|
||||
(((_vpn < L2V_VPN_SPECIAL) && ((_big.cu[_big.max-1].u.n.vpn+_big.cu[_big.max-1].span) == _vpn)) \
|
||||
|| ((_vpn >= L2V_VPN_SPECIAL) && (_big.cu[_big.max-1].u.n.vpn == _vpn))))
|
||||
|
||||
|
||||
#endif // __L2V_TYPES_H__
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "WMRFeatures.h"
|
||||
#if ENABLE_L2V_TREE
|
||||
#include "L2V.h"
|
||||
|
||||
|
||||
#if L2V_TRACK_VALID!=0
|
||||
|
||||
void _L2V_ValidUp(UInt32 vpn, UInt32 count)
|
||||
{
|
||||
UInt32 sb = vpn / L2V.pagesPerSB;
|
||||
L2V.Valid[sb] += count;
|
||||
//l2v_assert_le(L2V.Valid[sb], sbsize);
|
||||
}
|
||||
|
||||
void _L2V_ValidDown(UInt32 vpn, UInt32 count)
|
||||
{
|
||||
UInt32 sb = vpn / L2V.pagesPerSB;
|
||||
//l2v_assert_ge(L2V.Valid[sb], count);
|
||||
L2V.Valid[sb] -= count;
|
||||
}
|
||||
|
||||
#endif // track valid
|
||||
|
||||
#endif // ENABLE_L2V_TREE
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 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 __L2V_VALID_H__
|
||||
#define __L2V_VALID_H__
|
||||
|
||||
|
||||
#include "L2V_Defines.h"
|
||||
|
||||
#if L2V_TRACK_VALID!=0
|
||||
extern void _L2V_ValidUp(UInt32 vpn, UInt32 count);
|
||||
extern void _L2V_ValidDown(UInt32 vpn, UInt32 count);
|
||||
#else
|
||||
#define _L2V_ValidUp(vpn, count)
|
||||
#define _L2V_ValidDown(vpn, count)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // __L2V_VALID_H__
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
#define ENABLE_L2V_TREE (1)
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2010 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.
|
||||
*/
|
||||
|
||||
// Author: Daniel J. Post (djp), dpost@apple.com
|
||||
|
||||
#include "WMROAM.h"
|
||||
|
||||
|
||||
void *WMR_MALLOC(UInt32 size)
|
||||
{
|
||||
void * ptr = malloc(size);
|
||||
if (ptr)
|
||||
{
|
||||
WMR_MEMSET(ptr, 0, size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 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 __WMROAM_H__
|
||||
#define __WMROAM_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define UInt32 uint32_t
|
||||
#define Int32 int32_t
|
||||
#define UInt16 uint16_t
|
||||
#define Int16 int16_t
|
||||
#define UInt8 uint8_t
|
||||
#define Int8 int8_t
|
||||
#define BOOL32 bool
|
||||
#define TRUE32 true
|
||||
#define FALSE32 false
|
||||
|
||||
#define _WMR_ASSERT(e, file, line) { printf("%s:%u: failed assertion '%s'\nWaiting for debugger...\n", file, line, e); abort(); }
|
||||
#define WMR_ASSERT(e) if (!(e)) _WMR_ASSERT(#e, __FILE__, __LINE__)
|
||||
#define WMR_PANIC(format, args...) { printf(format , ##args); abort(); }
|
||||
#define WMR_MEMSET(a, b, c) memset(a, b, c)
|
||||
#define WMR_FREE(x, y) free(x)
|
||||
|
||||
extern void *WMR_MALLOC(UInt32 size);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// WMR_TRACE_*
|
||||
//
|
||||
// Compile-time tracepoints (not supported)
|
||||
//
|
||||
#define WMR_TRACE_0(...)
|
||||
#define WMR_TRACE_1(...)
|
||||
#define WMR_TRACE_2(...)
|
||||
#define WMR_TRACE_3(...)
|
||||
#define WMR_TRACE_4(...)
|
||||
#define WMR_TRACE_IST_0(...)
|
||||
#define WMR_TRACE_IST_1(...)
|
||||
#define WMR_TRACE_IST_2(...)
|
||||
#define WMR_TRACE_IST_3(...)
|
||||
#define WMR_TRACE_IST_4(...)
|
||||
|
||||
#endif // __WMROAM_H__
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* 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 _YAFTLTYPES_H_
|
||||
#define _YAFTLTYPES_H_
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "yaFTL_Defines.h"
|
||||
#include "L2V/L2V_Extern.h"
|
||||
#include "WMRBuf.h"
|
||||
#include "yaFTL_meta.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Info generated by CalcGlobal
|
||||
UInt16 wPagesPerVb; /* the count of pages per virtual block */
|
||||
UInt16 wUserVbTotal; /* the total number of data virtual block */
|
||||
UInt32 dwUserPagesTotal; /* the total number of data sector */
|
||||
UInt16 wBytesPerPage; /* bytes per page (main) */
|
||||
UInt16 wNumOfBanks; /* the number of banks */
|
||||
UInt16 wBytesPerPageMeta; /* bytes per page (meta) */
|
||||
} FTLWMRDeviceInfo;
|
||||
|
||||
#define PAGES_PER_SUBLK (yaFTL_FTLDeviceInfo.wPagesPerVb)
|
||||
#define NUM_BANKS (yaFTL_FTLDeviceInfo.wNumOfBanks)
|
||||
#define FTL_AREA_SIZE (yaFTL_FTLDeviceInfo.wUserVbTotal)
|
||||
#define USER_PAGES_TOTAL (yaFTL_FTLDeviceInfo.dwUserPagesTotal)
|
||||
#define BYTES_PER_PAGE (yaFTL_FTLDeviceInfo.wBytesPerPage)
|
||||
#define BYTES_PER_PAGE_META (yaFTL_FTLDeviceInfo.wBytesPerPageMeta)
|
||||
#define NUM_BANKS (yaFTL_FTLDeviceInfo.wNumOfBanks)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// UInt32 serialCounter; // serial allocation counter that would be used for restore
|
||||
// UInt16 validPagesNo; // Number of valid pages in block
|
||||
UInt32 erasableCount;
|
||||
UInt16 validPagesDNo;
|
||||
UInt16 validPagesINo;
|
||||
UInt16 pagesRead;
|
||||
UInt8 status;
|
||||
UInt8 eraseBeforeUse;
|
||||
UInt8 pagesReadSubCounter;
|
||||
} BlockEntry;
|
||||
|
||||
// TOCEntry: pointer to cache index if the given index page is in the cache, or pointer to NAND if not.
|
||||
// P.S.: not related to BlockTOCs.
|
||||
typedef struct
|
||||
{
|
||||
UInt32 indexPage; // location on the flash
|
||||
UInt16 cacheIndex; // 0xff means not cached
|
||||
} TOCEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt32 *indexPage; // pointer to the page address array
|
||||
UInt32 tocEntry; // index of the TOCEntry
|
||||
UInt16 counter; // number of hits on this cache
|
||||
UInt16 status; // free/occupied/dirty
|
||||
} CacheIndexEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UInt64 ddwPagesWrittenCnt;
|
||||
UInt64 ddwPagesReadCnt;
|
||||
UInt64 ddwFTLWriteCnt;
|
||||
UInt64 ddwFTLReadCnt;
|
||||
UInt64 ddwDataGCCnt;
|
||||
UInt64 ddwIndexGCCnt;
|
||||
UInt64 ddwEmptyGCDataCnt; /* case there is data to copy */
|
||||
UInt64 ddwEmptyGCIndexCnt; /* case there is data to copy */
|
||||
UInt64 ddwValidDataPages;
|
||||
UInt64 ddwValidIndexPages;
|
||||
UInt64 ddwFreeBlks;
|
||||
UInt64 ddwFTLRestoreCnt;
|
||||
UInt64 ddwReadDisturbHandleCall;
|
||||
UInt64 ddwWearLevelCnt;
|
||||
UInt64 ddwFlushCnt;
|
||||
UInt64 ddwRefreshCnt;
|
||||
UInt64 ddwRead[8];
|
||||
UInt64 ddwReadOver8;
|
||||
UInt64 ddwWrite[8];
|
||||
UInt64 ddwWriteOver8;
|
||||
UInt64 ddwNodesFree;
|
||||
UInt64 ddwNodesTotal;
|
||||
} FTLStatistics;
|
||||
|
||||
#define FTL_STATISTICS_DESCREPTION { \
|
||||
"ddwPagesWrittenCnt", \
|
||||
"ddwPagesReadCnt", \
|
||||
"ddwFTLWriteCnt", \
|
||||
"ddwFTLReadCnt", \
|
||||
"ddwDataGCCnt", \
|
||||
"ddwIndexGCCnt", \
|
||||
"ddwEmptyGCDataCnt", \
|
||||
"ddwEmptyGCIndexCnt", \
|
||||
"ddwValidDataPages", \
|
||||
"ddwValidIndexPages", \
|
||||
"ddwFreeBlks", \
|
||||
"ddwFTLRestoreCnt", \
|
||||
"ddwReadDisturbHandleCall", \
|
||||
"ddwWearLevelCnt", \
|
||||
"ddwFlushCnt", \
|
||||
"ddwRefreshCnt", \
|
||||
"ddwRead1", \
|
||||
"ddwRead2", \
|
||||
"ddwRead3", \
|
||||
"ddwRead4", \
|
||||
"ddwRead5", \
|
||||
"ddwRead6", \
|
||||
"ddwRead7", \
|
||||
"ddwRead8", \
|
||||
"ddwReadOver8", \
|
||||
"ddwWrite1", \
|
||||
"ddwWrite2", \
|
||||
"ddwWrite3", \
|
||||
"ddwWrite4", \
|
||||
"ddwWrite5", \
|
||||
"ddwWrite6", \
|
||||
"ddwWrite7", \
|
||||
"ddwWrite8", \
|
||||
"ddwWriteOver8", \
|
||||
"ddwNodesFree", \
|
||||
"ddwNodesTotal", \
|
||||
}
|
||||
|
||||
#define GCFIFO_DEPTH 16
|
||||
typedef struct
|
||||
{
|
||||
UInt32 block[GCFIFO_DEPTH + 1];
|
||||
UInt32 head, tail; // head==tail means it is empty
|
||||
} GC_Fifo_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GCD_IDLE,
|
||||
GCD_EVICT,
|
||||
GCD_ERASE,
|
||||
GCD_FIXINDEX_RETRY,
|
||||
GCD_FIXDATA_RETRY,
|
||||
} GCDState;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// In:
|
||||
UInt32 in_block;
|
||||
|
||||
// Work FIFO for error handling
|
||||
GC_Fifo_t workFifo;
|
||||
|
||||
// Choose out:
|
||||
UInt32 chosenBlock;
|
||||
UInt32 chosenValid;
|
||||
UInt32 chosenErases;
|
||||
|
||||
// Buffers:
|
||||
UInt32 outstandingAllocs;
|
||||
Buffer *tmpB1, *tmpB2, *tmpB3;
|
||||
UInt32 *TOCbuff;
|
||||
UInt8 *pageBuffer;
|
||||
|
||||
// GC zone:
|
||||
UInt32 *vpns;
|
||||
UInt8 *zone;
|
||||
PageMeta_t *meta;
|
||||
UInt32 curZoneSize;
|
||||
UInt32 ueccCounter;
|
||||
|
||||
// State:
|
||||
GCDState state;
|
||||
UInt32 curPage;
|
||||
UInt32 pagesRange;
|
||||
UInt32 pagesCopied;
|
||||
Int32 gcDataAdjust; // only meaningful for data GC
|
||||
|
||||
L2V_SearchCtx_t read_c; // Search context for GC translation
|
||||
} GC_Ctx_t;
|
||||
|
||||
#define ERASE_NOW_LIST_SIZE 5
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WMR_BufZone_t BufZone; // Buffer zone allocators
|
||||
WMR_BufZone_t BufZone_IndexCache; // ...
|
||||
UInt16 controlPageNo, indexPageRatio; /* TOC of each block contains Lpa for each page written to block */
|
||||
UInt32 indexSize; /* index size in blocks */
|
||||
UInt32 dataSize;
|
||||
UInt32 logicalPartitionSize; /* partititon size in pages exposed to file system */
|
||||
UInt16 TOCtableEntriesNo; /* number of entries in index TOC table */
|
||||
|
||||
UInt16 freeCachePages;
|
||||
UInt16 erasedBlockCount;
|
||||
#ifndef AND_READONLY
|
||||
UInt16 nextFreeCachePage;
|
||||
UInt64 cxtAllocation;
|
||||
UInt32 currentCXTIndex, FTLRestoreCnt;
|
||||
UInt8 cxtEraseCounter;
|
||||
UInt32 currentDBlockAllocationNo;
|
||||
UInt8 cxtValid;
|
||||
UInt8 formatWasCalled;
|
||||
BOOL32 readLimit;
|
||||
UInt16 eraseNowList[ERASE_NOW_LIST_SIZE];
|
||||
#endif
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
UInt32 block;
|
||||
UInt32 *TOC;
|
||||
UInt16 nextPage;
|
||||
WeaveSeq_t minWeaveSeq;
|
||||
} data;
|
||||
struct
|
||||
{
|
||||
UInt32 block;
|
||||
UInt32 *TOC;
|
||||
UInt16 nextPage;
|
||||
WeaveSeq_t minWeaveSeq;
|
||||
} index;
|
||||
|
||||
WeaveSeq_t weaveSeq;
|
||||
UInt32 lastBlock;
|
||||
} wrState;
|
||||
|
||||
struct
|
||||
{
|
||||
UInt32 size;
|
||||
UInt32 curAge;
|
||||
UInt32 free;
|
||||
UInt32 isData;
|
||||
UInt32 **BTOC;
|
||||
UInt32 *sb;
|
||||
Int32 *age;
|
||||
WMR_BufZone_t BufZone; // Buffer zone allocator
|
||||
|
||||
// For srcVpn:
|
||||
UInt32 srcSize;
|
||||
UInt32 curSrc;
|
||||
UInt32 *srcSb;
|
||||
UInt32 **srcVpn;
|
||||
UInt32 isLocked;
|
||||
} BTOCcache;
|
||||
|
||||
struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
UInt32 allocdBlocks;
|
||||
Int32 freeBlocks;
|
||||
UInt32 validPages;
|
||||
} data;
|
||||
struct
|
||||
{
|
||||
UInt32 allocdBlocks;
|
||||
Int32 freeBlocks;
|
||||
UInt32 validPages;
|
||||
} index;
|
||||
UInt32 freeBlocks;
|
||||
BOOL32 distCheckable;
|
||||
} seaState;
|
||||
|
||||
struct
|
||||
{
|
||||
UInt32 blocksSince;
|
||||
BOOL32 pointOfNoReturn;
|
||||
} wearLevel;
|
||||
|
||||
struct
|
||||
{
|
||||
UInt32 pagesWritten;
|
||||
UInt32 erases;
|
||||
} periodicCxt;
|
||||
|
||||
TOCEntry *tocArray; /* [TOC_SIZE] Table of content that contains location of index pages in flash and index cache */
|
||||
CacheIndexEntry *indexCache; /* [INDEX_CACHE_SIZE] cached index pages */
|
||||
BlockEntry *blockArray; /* [YAFTL_NO_OF_BLOCKS] block information */
|
||||
UInt32 *restoreTOC; // blockTOC for restore
|
||||
|
||||
PageMeta_t *meta_restoreIdx;
|
||||
PageMeta_t *meta_restoreData;
|
||||
PageMeta_t *meta_readCxt;
|
||||
PageMeta_t *meta_quickRestore;
|
||||
PageMeta_t *meta_invalidateCxt;
|
||||
PageMeta_t *meta_writeCxt;
|
||||
PageMeta_t *meta_restoreMountErase;
|
||||
PageMeta_t *meta_restoreMount;
|
||||
PageMeta_t *meta_clearEntryInCache;
|
||||
PageMeta_t *meta_writeBTOC;
|
||||
PageMeta_t *meta_indexLoadDirty;
|
||||
PageMeta_t *meta_getStats;
|
||||
PageMeta_t *meta_GetBlockTOC;
|
||||
PageMeta_t *meta_IsDataPageCurrent;
|
||||
PageMeta_t *meta_WriteZoneData;
|
||||
|
||||
UInt8 *quickRestore_tBuff;
|
||||
UInt32 *tmpReadBuffer; // = NULL;
|
||||
UInt32 readBufferIndex; // = 0xffffffff;
|
||||
PageMeta_t *writeMdPtr; // = NULL;
|
||||
UInt32 *multiReadvpN; // = NULL;
|
||||
PageMeta_t *readMdPtr; // = NULL;
|
||||
PageMeta_t *singleMdPtr;
|
||||
UInt32 cxtSize, cxtSizeTOC, cxtSizeBlockStatus, cxtSizeBlockRead,
|
||||
cxtSizeBlockErase, cxtSizeValidPagesD, cxtSizeValidPagesI;
|
||||
UInt32 currentCxtVpn; // = 0xffffffff;
|
||||
UInt16 cxtTable[FTL_CXT_SECTION_SIZE];
|
||||
UInt32 maxEraseCount, minEraseCount; // = 0
|
||||
|
||||
UInt32 indexCacheSize; // = DEFAULT_INDEX_CACHE_SIZE;
|
||||
UInt8 exportedRatio; // = DEFAULT_EXPO_RATIO;
|
||||
|
||||
// Garbage collection structures
|
||||
struct
|
||||
{
|
||||
UInt32 zoneSize;
|
||||
GC_Ctx_t data;
|
||||
GC_Ctx_t index;
|
||||
WMR_BufZone_t BufZone; // Buffer zone allocator
|
||||
PageMeta_t *meta_buf;
|
||||
} gc;
|
||||
|
||||
// Read search context
|
||||
L2V_SearchCtx_t read_c;
|
||||
} yaFTL_t;
|
||||
|
||||
#endif /* _YAFTLTYPES_H_ */
|
||||
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (c) 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.
|
||||
*/
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "yaFTL_BTOC.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "VFLBuffer.h"
|
||||
#include "VFL.h"
|
||||
#include "FTL.h"
|
||||
#include "yaFTLTypes.h"
|
||||
#include "yaFTL_Defines.h"
|
||||
|
||||
// Extern context struct
|
||||
extern yaFTL_t yaFTL;
|
||||
extern FTLWMRDeviceInfo yaFTL_FTLDeviceInfo;
|
||||
extern Int32 _readPage(UInt32 vpn, UInt8 *pageData, PageMeta_t *mdPtr, BOOL32 bInternalOp, BOOL32 boolCleanCheck, BOOL32 scrubOnUECC);
|
||||
extern ANDStatus invalidateCXT(void);
|
||||
|
||||
BOOL32 BTOC_Init()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
yaFTL.BTOCcache.size = YAFTL_BTOCCACHE_SIZE_PER * 2;
|
||||
WMR_ASSERT(yaFTL.BTOCcache.size <= 32);
|
||||
yaFTL.BTOCcache.srcSize = YAFTL_BTOCCACHE_SRCSIZE;
|
||||
yaFTL.BTOCcache.curSrc = yaFTL.BTOCcache.srcSize-1;
|
||||
|
||||
yaFTL.BTOCcache.curAge = 0;
|
||||
yaFTL.BTOCcache.age = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.age) * yaFTL.BTOCcache.size);
|
||||
yaFTL.BTOCcache.sb = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.sb) * yaFTL.BTOCcache.size);
|
||||
yaFTL.BTOCcache.BTOC = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.BTOC) * yaFTL.BTOCcache.size);
|
||||
yaFTL.BTOCcache.srcVpn = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.srcVpn) * yaFTL.BTOCcache.srcSize);
|
||||
yaFTL.BTOCcache.srcSb = WMR_MALLOC(sizeof(*yaFTL.BTOCcache.srcSb) * yaFTL.BTOCcache.srcSize);
|
||||
yaFTL.BTOCcache.isLocked = 0;
|
||||
|
||||
// Check for allocation failure
|
||||
if ((NULL == yaFTL.BTOCcache.age) || (NULL == yaFTL.BTOCcache.sb) || (NULL == yaFTL.BTOCcache.BTOC)
|
||||
|| (NULL == yaFTL.BTOCcache.srcVpn) || (NULL == yaFTL.BTOCcache.srcSb))
|
||||
{
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
yaFTL.BTOCcache.sb[i] = 0xffffffff;
|
||||
}
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
yaFTL.BTOCcache.srcSb[i] = 0xffffffff;
|
||||
yaFTL.BTOCcache.srcVpn[i] = WMR_MALLOC(sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
WMR_MEMSET(yaFTL.BTOCcache.srcVpn[i], 0xff, sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
}
|
||||
|
||||
yaFTL.BTOCcache.free = (1 << yaFTL.BTOCcache.size) - 1;
|
||||
yaFTL.BTOCcache.isData = (1 << YAFTL_BTOCCACHE_SIZE_PER) - 1;
|
||||
|
||||
// Allocate buffers
|
||||
WMR_BufZone_Init(&yaFTL.BTOCcache.BufZone);
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
yaFTL.BTOCcache.BTOC[i] = (UInt32*)WMR_Buf_Alloc_ForDMA(&yaFTL.BTOCcache.BufZone, yaFTL.controlPageNo * BYTES_PER_PAGE);
|
||||
}
|
||||
|
||||
if (!WMR_BufZone_FinishedAllocs(&yaFTL.BTOCcache.BufZone)) {
|
||||
return FALSE32;
|
||||
}
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
WMR_BufZone_Rebase(&yaFTL.BTOCcache.BufZone, (void**)&yaFTL.BTOCcache.BTOC[i]);
|
||||
}
|
||||
|
||||
WMR_BufZone_FinishedRebases(&yaFTL.BTOCcache.BufZone);
|
||||
|
||||
return TRUE32;
|
||||
}
|
||||
|
||||
void BTOC_Close()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
WMR_BufZone_Free(&yaFTL.BTOCcache.BufZone);
|
||||
|
||||
if (NULL != yaFTL.BTOCcache.age)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.age, sizeof(*yaFTL.BTOCcache.age) * yaFTL.BTOCcache.size);
|
||||
}
|
||||
if (NULL != yaFTL.BTOCcache.sb)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.sb, sizeof(*yaFTL.BTOCcache.sb) * yaFTL.BTOCcache.size);
|
||||
}
|
||||
if (NULL != yaFTL.BTOCcache.BTOC)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.BTOC, sizeof(*yaFTL.BTOCcache.BTOC) * yaFTL.BTOCcache.size);
|
||||
}
|
||||
// Free srcVpn memory
|
||||
if (NULL != yaFTL.BTOCcache.srcSb)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.srcSb, sizeof(*yaFTL.BTOCcache.srcSb) * yaFTL.BTOCcache.srcSize);
|
||||
}
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.srcVpn[i], sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
}
|
||||
if (NULL != yaFTL.BTOCcache.srcVpn)
|
||||
{
|
||||
WMR_FREE(yaFTL.BTOCcache.srcVpn, sizeof(*yaFTL.BTOCcache.srcVpn) * yaFTL.BTOCcache.srcSize);
|
||||
}
|
||||
|
||||
yaFTL.BTOCcache.age = NULL;
|
||||
yaFTL.BTOCcache.sb = NULL;
|
||||
yaFTL.BTOCcache.BTOC = NULL;
|
||||
yaFTL.BTOCcache.srcSb = NULL;
|
||||
yaFTL.BTOCcache.srcVpn = NULL;
|
||||
|
||||
yaFTL.BTOCcache.size = 0;
|
||||
|
||||
yaFTL.BTOCcache.srcSize = 0;
|
||||
}
|
||||
|
||||
void BTOC_BootFixup()
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if (0xfffffffd == yaFTL.BTOCcache.sb[i])
|
||||
{
|
||||
yaFTL.BTOCcache.sb[i] = yaFTL.wrState.data.block;
|
||||
}
|
||||
if (0xfffffffe == yaFTL.BTOCcache.sb[i])
|
||||
{
|
||||
yaFTL.BTOCcache.sb[i] = yaFTL.wrState.index.block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 *BTOC_Alloc(UInt32 sb, BOOL32 isData)
|
||||
{
|
||||
UInt32 i, minIdx, isData32 = (isData ? 1 : 0);
|
||||
Int32 minAge;
|
||||
|
||||
// Get a srcVpn
|
||||
yaFTL.BTOCcache.curSrc = (yaFTL.BTOCcache.curSrc + 1) % yaFTL.BTOCcache.srcSize;
|
||||
yaFTL.BTOCcache.srcSb[yaFTL.BTOCcache.curSrc] = sb;
|
||||
WMR_MEMSET(yaFTL.BTOCcache.srcVpn[yaFTL.BTOCcache.curSrc], 0xff, sizeof(**yaFTL.BTOCcache.srcVpn) * PAGES_PER_SUBLK);
|
||||
|
||||
// Get a BTOC
|
||||
yaFTL.BTOCcache.curAge++;
|
||||
|
||||
minAge = 0x7fffffff;
|
||||
minIdx = 0xffffffff;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if (((yaFTL.BTOCcache.isData & (1 << i)) == (isData32 << i))
|
||||
&& (yaFTL.BTOCcache.free & (1 << i))
|
||||
&& (yaFTL.BTOCcache.age[i] < minAge)
|
||||
&& ((yaFTL.BTOCcache.isLocked & (1 << i)) == 0))
|
||||
{
|
||||
minAge = yaFTL.BTOCcache.age[i];
|
||||
minIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (0xffffffff != minIdx) {
|
||||
yaFTL.BTOCcache.free &= ~(1 << minIdx);
|
||||
yaFTL.BTOCcache.sb[minIdx] = sb;
|
||||
yaFTL.BTOCcache.age[minIdx] = yaFTL.BTOCcache.curAge;
|
||||
return yaFTL.BTOCcache.BTOC[minIdx];
|
||||
}
|
||||
#ifndef AND_READONLY
|
||||
// Invalidate context
|
||||
if (yaFTL.cxtValid == 1)
|
||||
{
|
||||
invalidateCXT();
|
||||
yaFTL.cxtValid = 0;
|
||||
}
|
||||
WMR_PANIC("Couldn't allocate a BTOC");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UInt32 BTOC_GetSrc(UInt32 destVpn)
|
||||
{
|
||||
UInt32 i, sb, idx;
|
||||
|
||||
sb = destVpn / PAGES_PER_SUBLK;
|
||||
idx = destVpn % PAGES_PER_SUBLK;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
if (sb == yaFTL.BTOCcache.srcSb[i]) {
|
||||
return yaFTL.BTOCcache.srcVpn[i][idx];
|
||||
}
|
||||
}
|
||||
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
void BTOC_SetSrc(UInt32 destVpn, UInt32 srcVpn)
|
||||
{
|
||||
UInt32 i, sb, idx;
|
||||
|
||||
sb = destVpn / PAGES_PER_SUBLK;
|
||||
idx = destVpn % PAGES_PER_SUBLK;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.srcSize; i++)
|
||||
{
|
||||
if (sb == yaFTL.BTOCcache.srcSb[i]) {
|
||||
yaFTL.BTOCcache.srcVpn[i][idx] = srcVpn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BTOC_Dealloc(UInt32 *BTOC)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if (BTOC == yaFTL.BTOCcache.BTOC[i])
|
||||
{
|
||||
yaFTL.BTOCcache.free |= (1 << i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifndef AND_READONLY
|
||||
// Invalidate context
|
||||
if (yaFTL.cxtValid == 1)
|
||||
{
|
||||
invalidateCXT();
|
||||
yaFTL.cxtValid = 0;
|
||||
}
|
||||
WMR_PANIC("Couldn't deallocate BTOC: 0x%x", BTOC);
|
||||
#endif
|
||||
}
|
||||
|
||||
UInt32 *BTOC_Search(UInt32 sb, BOOL32 isData)
|
||||
{
|
||||
UInt32 i, isData32 = (isData ? 1 : 0);
|
||||
Int32 maxAge = -1;
|
||||
UInt32 *best = NULL;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if ((yaFTL.BTOCcache.sb[i] == sb) && (yaFTL.BTOCcache.age[i] > maxAge) && ((yaFTL.BTOCcache.isData & (1 << i)) == (isData32 << i)))
|
||||
{
|
||||
maxAge = yaFTL.BTOCcache.age[i];
|
||||
best = yaFTL.BTOCcache.BTOC[i];
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
void BTOC_Lock(UInt32 sb)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if ((yaFTL.BTOCcache.sb[i] == sb) && ((yaFTL.BTOCcache.free & (1 << i)) == 0))
|
||||
{
|
||||
yaFTL.BTOCcache.isLocked |= (1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BTOC_Unlock(UInt32 sb)
|
||||
{
|
||||
UInt32 i;
|
||||
|
||||
for (i = 0; i < yaFTL.BTOCcache.size; i++)
|
||||
{
|
||||
if ((yaFTL.BTOCcache.sb[i] == sb) && (yaFTL.BTOCcache.isLocked & (1 << i)))
|
||||
{
|
||||
yaFTL.BTOCcache.isLocked &= ~(1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ANDStatus BTOC_Read(UInt32 vpn, UInt32 *bTOC, PageMeta_t *mdPtr, BOOL32 val, BOOL32 scrubOnUECC, UInt32 upperBound)
|
||||
{
|
||||
UInt16 i;
|
||||
ANDStatus status = FTL_CRITICAL_ERROR;
|
||||
|
||||
for (i = 0; i < yaFTL.controlPageNo; i++)
|
||||
{
|
||||
status = _readPage(vpn + i, ((UInt8 *)bTOC) + (i * BYTES_PER_PAGE), mdPtr, val, TRUE32, scrubOnUECC);
|
||||
if (status != FTL_SUCCESS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (status == FTL_SUCCESS)
|
||||
{
|
||||
UInt32 * tmpPtr = (UInt32 *)bTOC;
|
||||
for(i = 0; i < ((yaFTL.controlPageNo * BYTES_PER_PAGE) >> 2);i++)
|
||||
if(tmpPtr[i] >= upperBound)
|
||||
{
|
||||
tmpPtr[i] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
void BTOC_SetAll(UInt32 *bTOC, UInt8 value)
|
||||
{
|
||||
WMR_MEMSET(bTOC, value, yaFTL.controlPageNo * BYTES_PER_PAGE);
|
||||
}
|
||||
|
||||
|
||||
void BTOC_Copy(UInt32 *left, UInt32 *right, UInt32 upperBound)
|
||||
{
|
||||
UInt16 i;
|
||||
for(i = 0; i < ((yaFTL.controlPageNo * BYTES_PER_PAGE) >> 2);i++)
|
||||
if(right[i] >= upperBound)
|
||||
{
|
||||
left[i] = 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
left[i] = right[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 BTOC_Get(UInt32 *bTOC, UInt32 offset, UInt32 upperBound)
|
||||
{
|
||||
if(bTOC[offset] >= upperBound)
|
||||
{
|
||||
return 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
return bTOC[offset];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UInt32 BTOC_Set(UInt32 *bTOC, UInt32 offset, UInt32 val, UInt32 upperBound)
|
||||
{
|
||||
if(val >= upperBound)
|
||||
{
|
||||
bTOC[offset] = 0xffffffff;
|
||||
}
|
||||
else
|
||||
{
|
||||
bTOC[offset] = val;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 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 __YAFTL_BTOC_H__
|
||||
#define __YAFTL_BTOC_H__
|
||||
|
||||
// Includes
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "ANDTypes.h"
|
||||
#include "WMROAM.h"
|
||||
#include "yaFTLTypes.h"
|
||||
#include "yaFTL_meta.h"
|
||||
|
||||
// Defines and types declared elsewhere
|
||||
|
||||
// Prototypes:
|
||||
|
||||
// BTOC init/alloc/dealloc
|
||||
extern BOOL32 BTOC_Init(void);
|
||||
extern void BTOC_BootFixup(void);
|
||||
extern void BTOC_Close(void);
|
||||
extern UInt32 *BTOC_Alloc(UInt32 sb, BOOL32 isData);
|
||||
extern void BTOC_Dealloc(UInt32 *BTOC);
|
||||
extern UInt32 *BTOC_Search(UInt32 sb, BOOL32 isData);
|
||||
extern void BTOC_Lock(UInt32 sb);
|
||||
extern void BTOC_Unlock(UInt32 sb);
|
||||
|
||||
// Read
|
||||
extern ANDStatus BTOC_Read(UInt32 vpn, UInt32 *bTOC, PageMeta_t *mdPtr, BOOL32 val, BOOL32 scrubOnUECC, UInt32 upperBound);
|
||||
|
||||
// Src for GC
|
||||
extern void BTOC_SetSrc(UInt32 destVpn, UInt32 srcVpn);
|
||||
extern UInt32 BTOC_GetSrc(UInt32 destVpn);
|
||||
|
||||
// Getters/setters
|
||||
extern void BTOC_SetAll(UInt32 *bTOC, UInt8 value);
|
||||
extern UInt32 BTOC_Get(UInt32 *bTOC, UInt32 offset, UInt32 upperBound);
|
||||
extern UInt32 BTOC_Set(UInt32 *bTOC, UInt32 offset, UInt32 val, UInt32 upperBound);
|
||||
|
||||
// Copy
|
||||
extern void BTOC_Copy(UInt32 *left, UInt32 *right, UInt32 upperBound);
|
||||
|
||||
#endif // ----- #ifndef __YAFTL_BTOC_H__
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 __YAFTL_DEFINES_H__
|
||||
#define __YAFTL_DEFINES_H__
|
||||
|
||||
|
||||
#define YAFTLDBG_INIT (1 << 0)
|
||||
#define YAFTLDBG_FORMAT (1 << 1)
|
||||
#define YAFTLDBG_READ (1 << 2)
|
||||
#define YAFTLDBG_WRITE (1 << 3)
|
||||
#define YAFTLDBG_ERASE (1 << 4)
|
||||
#define YAFTLDBG_MISC (1 << 5)
|
||||
#define YAFTLDBG_ERROR (1 << 6)
|
||||
#define YAFTLDBG_OPEN (1 << 7)
|
||||
#define YAFTLDBG_INFO (1 << 8)
|
||||
|
||||
//#define YAFTL_DEBUG (YAFTLDBG_INIT | YAFTLDBG_ERROR | YAFTLDBG_INFO)
|
||||
#define YAFTL_DEBUG (YAFTLDBG_ERROR)
|
||||
#ifdef YAFTL_DEBUG
|
||||
#define YAFTL_ENABLE_DEBUG_PRINT (0xff)
|
||||
|
||||
# define debug(fac, fmt, args ...) \
|
||||
do { \
|
||||
if (YAFTLDBG_ ## fac & YAFTL_DEBUG & YAFTL_ENABLE_DEBUG_PRINT) { \
|
||||
_WMR_PRINT("yaFTL::%s(l:%d): " fmt "\n", __FUNCTION__, __LINE__, ## args); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define debug(fac, fmt, args ...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define FREE_BLK_TRH (5) /* number of units we require to be avaiable at any time */
|
||||
#define INDEX_AREA (1) /* block belongs to Index area */
|
||||
#define DATA_AREA (2) /* block belongs to data area */
|
||||
#define FREE_I_BLOCK_TRS (2) /* minimum free blocks within index area */
|
||||
#define DEFAULT_INDEX_CACHE_SIZE (10) /* index cached pages */
|
||||
#define INDEX_BLOCKS_RATIO (3) /* ratio of index area in flash to required index area by flash size */
|
||||
#define DEFAULT_EXPO_RATIO (99) /* percentage of data area exposed to file system */
|
||||
#define CXT_ERASE_LIMIT (30)
|
||||
|
||||
|
||||
#define IC_DIRTY_PAGE 1
|
||||
#define IC_BUSY_PAGE 2
|
||||
#define FREE_CACHE_PAGE 0xffff
|
||||
|
||||
#define BLOCK_FREE (0xFF) /* block marked as free */
|
||||
#define BLOCK_ALLOCATED (1) /* block marked as allocated for data area */
|
||||
#define BLOCK_CURRENT (4) /* block marked as current in data area */
|
||||
|
||||
#define BLOCK_GC (8) /* block in data area goes through GC process */
|
||||
|
||||
#define BLOCK_I_FREE (0xFF) /* block marked as free */
|
||||
#define BLOCK_I_CURRENT (32) /* block marked as current index block */
|
||||
#define BLOCK_I_ALLOCATED (64) /* block marked as idex block */
|
||||
#define BLOCK_I_GC (128) /* block in index area goes through GC process */
|
||||
#define BLOCK_TO_BE_ERASED (0x1) /* erase block before use . make sure the block is not erased before current block is closed */
|
||||
#define BLOCK_TO_BE_ERASED_ALIGNED_DATA (0x2) /* erase block before use . make sure the block is not erased before current block is closed */
|
||||
#define BLOCK_TO_BE_ERASED_ALIGNED_INDEX (0x4) /* erase block before use . make sure the block is not erased before current block is closed */
|
||||
#define BLOCK_READ_SCATTER (0x8) /* mark a block as being used in multi-read operation */
|
||||
#define BLOCK_TO_BE_MOVED (0x80) /* use it as an idication that block is to be refreshed after full mount is complete due to UECCs */
|
||||
|
||||
#define ERASE_IDLE_LIMIT (5) /* number of free blocks to be erased in idle time */
|
||||
|
||||
#define BLOCK_CTX_CNTR (2) /* block marked as CXT */
|
||||
#define BLOCK_CTX_CURRENT (16) /* block marked as current CXT */
|
||||
#define INDEX_PAGE_MARK (0x80000000) /* to be defined */
|
||||
|
||||
#define YAFTL_READ_DISTURB_LIMIT YAFTL_RC_THRESHOLD /* read disturb limit */
|
||||
|
||||
#define MIN_RESTORE_BUFFER (0x10000)
|
||||
#define MAX_RESTORE_BUFFER (0x200000)
|
||||
#define YAFTL_WEARLEVEL_PERIOD 30
|
||||
#define ERASE_COUNT_GAP_LIMIT 100
|
||||
#define ERASE_COUNT_GAP_UPPER_LIMIT 500
|
||||
#define STATIC_WEARLEVEL_TRIGGER 1000
|
||||
#define NAND_MOUNT_INDEX_SIZE 1000
|
||||
#define YAFTL_WRITE_MAX_STRIPES 32
|
||||
#define YAFTL_INDEX_CACHE_COUNTER_LIMIT 0xFFFF
|
||||
#define PAGES_READ_SUB_COUNTER_LIMIT YAFTL_RC_MULTIPLIER
|
||||
|
||||
// GCZONE_DOUBLEUPTO defines the point up to which we will multiply banks to.
|
||||
// It is similar to setting a minimum of 16, but works with non-pow-2 configs.
|
||||
#define GCZONE_DOUBLEUPTO 16
|
||||
#define YAFTL_GC_RATIO_SCALAR 4
|
||||
|
||||
// Maximum number of TOC pages/block to support
|
||||
#define MAX_TOC_PAGES 4
|
||||
#define YAFTL_BTOCCACHE_SIZE_PER 2
|
||||
#define YAFTL_BTOCCACHE_SRCSIZE 2
|
||||
|
||||
// make the function pointers in vfl struct look like the old vfl functions
|
||||
#ifndef AND_READONLY
|
||||
#define VFL_Format (yaFTL_VFLFunctions.Format)
|
||||
#define VFL_Write (yaFTL_VFLFunctions.WriteSinglePage)
|
||||
#define VFL_Erase (yaFTL_VFLFunctions.Erase)
|
||||
#define VFL_ChangeFTLCxtVbn (yaFTL_VFLFunctions.ChangeFTLCxtVbn)
|
||||
#define VFL_WriteMultiplePagesInVb (yaFTL_VFLFunctions.WriteMultiplePagesInVb)
|
||||
#endif // ! AND_READONLY
|
||||
#define VFL_Init (yaFTL_VFLFunctions.Init)
|
||||
#define VFL_Open (yaFTL_VFLFunctions.Open)
|
||||
#define VFL_Close (yaFTL_VFLFunctions.Close)
|
||||
#define VFL_ReadMultiplePagesInVb (yaFTL_VFLFunctions.ReadMultiplePagesInVb)
|
||||
#define VFL_ReadScatteredPagesInVb (yaFTL_VFLFunctions.ReadScatteredPagesInVb)
|
||||
#define VFL_Read (yaFTL_VFLFunctions.ReadSinglePage)
|
||||
#define VFL_GetFTLCxtVbn (yaFTL_VFLFunctions.GetFTLCxtVbn)
|
||||
//#define VFL_GetAddress (yaFTL_VFLFunctions.GetAddress)
|
||||
#define VFL_GetDeviceInfo (yaFTL_VFLFunctions.GetDeviceInfo)
|
||||
#define VFL_GetStruct (yaFTL_VFLFunctions.GetStruct)
|
||||
#define VFL_SetStruct (yaFTL_VFLFunctions.SetStruct)
|
||||
|
||||
#endif // ----- #ifndef _YAFTL_DEFINES_H__INC -----
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 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 __YAFTL_GC_H__
|
||||
#define __YAFTL_GC_H__
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "ANDTypes.h"
|
||||
|
||||
// General setup/close
|
||||
extern ANDStatus YAFTL_GC_Init(void);
|
||||
extern void YAFTL_GC_Close(void);
|
||||
|
||||
// Called by Write
|
||||
extern void YAFTL_GC_PreWrite(UInt32 writeSize);
|
||||
|
||||
// For error recovery
|
||||
extern void YAFTL_GC_Data_Enq(UInt32 block);
|
||||
extern UInt32 YAFTL_GC_Data_Deq_sb(UInt32 block);
|
||||
extern void YAFTL_GC_Index_Enq(UInt32 block);
|
||||
|
||||
// Direct access to the machines
|
||||
extern ANDStatus YAFTL_GC_Index(UInt32 block, BOOL32 scrubOnUECC);
|
||||
extern ANDStatus YAFTL_GC_Data(UInt32 block, BOOL32 scrubOnUECC);
|
||||
|
||||
#ifdef AND_READONLY
|
||||
#define CheckBlockDist(x)
|
||||
#else
|
||||
extern void CheckBlockDist(void);
|
||||
#endif
|
||||
|
||||
#endif // ----- #ifndef __YAFTL_GC_H__
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 __YAFTL_META_H__
|
||||
#define __YAFTL_META_H__
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
#if NAND_PPN
|
||||
#include "yaFTL_meta_ppn.h"
|
||||
#else
|
||||
// Default to raw to avoid compilation errors--meta isn't needed by some of the parsers that include yaFTLTypes.h
|
||||
#include "yaFTL_meta_raw.h"
|
||||
#endif
|
||||
|
||||
#endif // __YAFTL_META_H__
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "yaFTL_meta_ppn.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "yaFTLTypes.h"
|
||||
|
||||
extern yaFTL_t yaFTL;
|
||||
|
||||
|
||||
void SetupMeta_Data(PageMeta_t *__meta, UInt32 lba, UInt32 count)
|
||||
{
|
||||
PageMeta_Data_t *m = (PageMeta_Data_t*)__meta;
|
||||
|
||||
while (count--) {
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_DATA;
|
||||
m->c.FTLFlags = 0;
|
||||
m->lba = lba;
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
m->userSeq = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
|
||||
// Next
|
||||
lba++;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Data_UECC(PageMeta_t *__meta)
|
||||
{
|
||||
__meta->c.FTLFlags |= PFLAG_UECC;
|
||||
}
|
||||
|
||||
void SetupMeta_Index(PageMeta_t *__meta, UInt32 ipn)
|
||||
{
|
||||
PageMeta_Idx_t *m = (PageMeta_Idx_t*)__meta;
|
||||
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_IDX;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
m->baseLba = ipn * yaFTL.indexPageRatio;
|
||||
}
|
||||
|
||||
void SetupMeta_Data_BTOC(PageMeta_t *__meta)
|
||||
{
|
||||
PageMeta_BTOC_t *m = (PageMeta_BTOC_t*)__meta;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_BTOC_DATA;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.data.minWeaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.data.minWeaveSeq >> 16);
|
||||
m->maxWeaveSeqAdd = (UInt32)(yaFTL.wrState.weaveSeq - yaFTL.wrState.data.minWeaveSeq);
|
||||
m->__rfu__ = 0xffffffff;
|
||||
}
|
||||
|
||||
void SetupMeta_Index_BTOC(PageMeta_t *__meta)
|
||||
{
|
||||
PageMeta_BTOC_t *m = (PageMeta_BTOC_t*)__meta;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_BTOC_IDX;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.index.minWeaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.index.minWeaveSeq >> 16);
|
||||
m->maxWeaveSeqAdd = (UInt32)(yaFTL.wrState.weaveSeq - yaFTL.wrState.index.minWeaveSeq);
|
||||
m->__rfu__ = 0xffffffff;
|
||||
}
|
||||
|
||||
void SetupMeta_IndexGC(PageMeta_t *__meta, UInt32 count)
|
||||
{
|
||||
PageMeta_Idx_t *m = (PageMeta_Idx_t*)__meta;
|
||||
|
||||
while (count--) {
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_IDX;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
|
||||
// Next
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_DataGC(PageMeta_t *__meta, UInt32 count)
|
||||
{
|
||||
PageMeta_Data_t *m = (PageMeta_Data_t*)__meta;
|
||||
|
||||
while (count--) {
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_DATA;
|
||||
// Don't touch FTLFlags--might have uECC flag
|
||||
m->c.weaveLo = yaFTL.wrState.weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16);
|
||||
// Don't touch LBA or userSeq
|
||||
|
||||
// Next
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Cxt(PageMeta_t *__meta, UInt64 weaveSeq)
|
||||
{
|
||||
PageMeta_Cxt_t *m = (PageMeta_Cxt_t*)__meta;
|
||||
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
m->c.PageType = PAGETYPE_FTL_CXT;
|
||||
m->c.FTLFlags = 0;
|
||||
m->c.weaveLo = weaveSeq;
|
||||
m->c.weaveHi = (UInt32)(weaveSeq >> 16);
|
||||
m->__rfu1__ = 0;
|
||||
m->__rfu2__ = 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 __YAFTL_META_PPN_H__
|
||||
#define __YAFTL_META_PPN_H__
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "WMROAM.h"
|
||||
|
||||
|
||||
|
||||
// PageType defines--
|
||||
#define PAGETYPE_FTL_DATA (AND_SPARE_TYPE_REGION_FTL + 0x00)
|
||||
#define PAGETYPE_FTL_BTOC_DATA (AND_SPARE_TYPE_REGION_FTL + 0x1C)
|
||||
#define PAGETYPE_FTL_BTOC_IDX (AND_SPARE_TYPE_REGION_FTL + 0x1D)
|
||||
#define PAGETYPE_FTL_IDX (AND_SPARE_TYPE_REGION_FTL + 0x1E)
|
||||
#define PAGETYPE_FTL_CXT (AND_SPARE_TYPE_REGION_FTL + 0x1F)
|
||||
|
||||
|
||||
// FTLFlags defines--
|
||||
#define PFLAG_UECC 0x01 // uECC state for data pages (moved by GC and thus re-encoded)
|
||||
|
||||
|
||||
// Must be 16 bytes on PPN
|
||||
|
||||
typedef struct {
|
||||
UInt8 PageType;
|
||||
UInt8 FTLFlags;
|
||||
UInt16 weaveLo;
|
||||
UInt32 weaveHi;
|
||||
} PageMeta_Common_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 __f1;
|
||||
UInt32 __f2;
|
||||
} PageMeta_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 userSeq;
|
||||
UInt32 lba;
|
||||
} PageMeta_Data_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 maxWeaveSeqAdd;
|
||||
UInt32 __rfu__;
|
||||
} PageMeta_BTOC_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt16 __rfu__;
|
||||
UInt16 lbaAdd;
|
||||
UInt32 baseLba;
|
||||
} PageMeta_Idx_t;
|
||||
|
||||
typedef struct {
|
||||
PageMeta_Common_t c;
|
||||
UInt32 __rfu1__;
|
||||
UInt32 __rfu2__;
|
||||
} PageMeta_Cxt_t;
|
||||
|
||||
|
||||
typedef UInt64 WeaveSeq_t;
|
||||
|
||||
|
||||
// Setup
|
||||
extern void SetupMeta_Data(PageMeta_t *__meta, UInt32 lba, UInt32 count);
|
||||
extern void SetupMeta_Data_UECC(PageMeta_t *__meta);
|
||||
|
||||
extern void SetupMeta_Index(PageMeta_t *__meta, UInt32 ipn);
|
||||
|
||||
extern void SetupMeta_Data_BTOC(PageMeta_t *__meta);
|
||||
extern void SetupMeta_Index_BTOC(PageMeta_t *__meta);
|
||||
|
||||
extern void SetupMeta_IndexGC(PageMeta_t *__meta, UInt32 count);
|
||||
extern void SetupMeta_DataGC(PageMeta_t *__meta, UInt32 count);
|
||||
|
||||
extern void SetupMeta_Cxt(PageMeta_t *__meta, UInt64 weaveSeq);
|
||||
|
||||
#define META_SET_LBA(meta, foo) do { ((PageMeta_Data_t*)(meta))->lba = (foo); } while (0)
|
||||
#define META_SET_WEAVESEQ(meta) do { (meta)->c.weaveLo = (UInt16)yaFTL.wrState.weaveSeq; (meta)->c.weaveHi = (UInt32)(yaFTL.wrState.weaveSeq >> 16); } while (0)
|
||||
#define META_SET_BTOC_DATA(meta) do { (meta)->c.PageType = PAGETYPE_FTL_BTOC_DATA; } while (0)
|
||||
#define META_SET_IPN_FROM_BTOC(meta, bte) do { ((PageMeta_Idx_t*)(meta))->baseLba = (bte); } while (0)
|
||||
#define BTOC_SET_FROM_IPN(bte, meta) do { (bte) = ((PageMeta_Idx_t*)(meta))->baseLba; } while (0)
|
||||
|
||||
|
||||
// Query
|
||||
#define BTOC_GET_IPN(bte) ((bte) / yaFTL.indexPageRatio)
|
||||
#define META_ARE_FLAGS_FF(meta) ((0xff == (meta)->c.PageType) && (0xff == (meta)->c.FTLFlags))
|
||||
#define META_IS_IDX(meta) (PAGETYPE_FTL_IDX == (meta)->c.PageType)
|
||||
#define META_IS_DATA(meta) (PAGETYPE_FTL_DATA == (meta)->c.PageType)
|
||||
#define META_IS_CXT(meta) (PAGETYPE_FTL_CXT == (meta)->c.PageType)
|
||||
#define META_IS_BTOC_IDX(meta) (PAGETYPE_FTL_BTOC_IDX == (meta)->c.PageType)
|
||||
#define META_IS_BTOC_DATA(meta) (PAGETYPE_FTL_BTOC_DATA == (meta)->c.PageType)
|
||||
#define META_IS_BTOC(meta) ((PAGETYPE_FTL_BTOC_IDX == (meta)->c.PageType) || (PAGETYPE_FTL_BTOC_DATA == ((meta)->c.PageType)))
|
||||
#define META_IS_UECC(meta) ((meta)->c.FTLFlags & PFLAG_UECC)
|
||||
#define META_GET_WEAVESEQ(meta) ((UInt64)(meta)->c.weaveLo | ((UInt64)(meta)->c.weaveHi << 16))
|
||||
#define META_GET_LBA(meta) (((PageMeta_Data_t*)(meta))->lba)
|
||||
#define META_GET_IPN(meta) (((PageMeta_Idx_t*)(meta))->baseLba / yaFTL.indexPageRatio)
|
||||
#define META_GET_IPNRAW(meta) (((PageMeta_Idx_t*)(meta))->baseLba)
|
||||
#define META_GET_ALL_FLAGS(meta) (((UInt32)((meta)->c.FTLFlags) << 8) | (UInt32)((meta)->c.PageType))
|
||||
|
||||
|
||||
|
||||
#endif // __YAFTL_META_PPN_H__
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "yaFTL_whoami.h"
|
||||
#include "yaFTL_meta_raw.h"
|
||||
#include "WMRConfig.h"
|
||||
#include "yaFTLTypes.h"
|
||||
|
||||
extern yaFTL_t yaFTL;
|
||||
|
||||
|
||||
void SetupMeta_Data(PageMeta_t *meta, UInt32 lba, UInt32 count)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.data.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.data.block;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
meta->FTLFlags = PAGETYPE_FTL_DATA;
|
||||
meta->lba = lba;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
|
||||
// Next
|
||||
lba++;
|
||||
meta++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Data_UECC(PageMeta_t *meta)
|
||||
{
|
||||
meta->FTLFlags |= PFLAG_UECC;
|
||||
}
|
||||
|
||||
void SetupMeta_Index(PageMeta_t *meta, UInt32 ipn)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.index.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.index.block;
|
||||
}
|
||||
|
||||
meta->FTLFlags = PAGETYPE_FTL_IDX;
|
||||
meta->lba = ipn;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
}
|
||||
|
||||
void SetupMeta_Data_BTOC(PageMeta_t *meta)
|
||||
{
|
||||
meta->FTLFlags = PFLAG_BTOC;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.data.minWeaveSeq;
|
||||
}
|
||||
|
||||
void SetupMeta_Index_BTOC(PageMeta_t *meta)
|
||||
{
|
||||
meta->FTLFlags = PAGETYPE_FTL_IDX | PFLAG_BTOC;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.index.minWeaveSeq;
|
||||
}
|
||||
|
||||
void SetupMeta_IndexGC(PageMeta_t *meta, UInt32 count)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.index.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.index.block;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
meta->FTLFlags = PAGETYPE_FTL_IDX;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
|
||||
// Next
|
||||
meta++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_DataGC(PageMeta_t *meta, UInt32 count)
|
||||
{
|
||||
if (yaFTL.wrState.lastBlock != yaFTL.wrState.data.block)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
yaFTL.wrState.lastBlock = yaFTL.wrState.data.block;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
// Or in the page type and clear all but uECC flag
|
||||
meta->FTLFlags = (meta->FTLFlags & PFLAG_UECC) | PAGETYPE_FTL_DATA;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
|
||||
// Next
|
||||
meta++;
|
||||
}
|
||||
}
|
||||
|
||||
void SetupMeta_Cxt(PageMeta_t *meta, UInt64 weaveSeq)
|
||||
{
|
||||
yaFTL.wrState.weaveSeq++;
|
||||
|
||||
meta->FTLFlags = PAGETYPE_FTL_CXT;
|
||||
meta->weaveSeq = (UInt32)yaFTL.wrState.weaveSeq;
|
||||
}
|
||||
|
||||
Loaded 100 of 2612 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user