first and last commit

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

No files matched your search

@@ -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_ */
+147
View File
@@ -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_ */
+35
View File
@@ -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__
+329
View File
@@ -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_ */
+127
View File
@@ -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__
+182
View File
@@ -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_ */
+254
View File
@@ -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);
}
+237
View File
@@ -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_ */
+42
View File
@@ -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_ */
+22
View File
@@ -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
+781
View File
@@ -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__ //------------------
+208
View File
@@ -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;
}
+29
View File
@@ -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
+40
View File
@@ -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_
+17
View File
@@ -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
+563
View File
@@ -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);
// =============================================================================
+343
View File
@@ -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]);
}
+43
View File
@@ -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 */
+425
View File
@@ -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
+368
View File
@@ -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 */
+369
View File
@@ -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 */
/* ========================================================================== */
+19
View File
@@ -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
+30
View File
@@ -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 */
+17
View File
@@ -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
+61
View File
@@ -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;
}
+22
View File
@@ -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
+723
View File
@@ -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*)&currentNandInfo.geometry->chipId, &currentCECount, &currentCEBitmap);
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;
}
+311
View File
@@ -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_
+21
View File
@@ -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
+12
View File
@@ -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
+77
View File
@@ -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
+93
View File
@@ -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;
}
+77
View File
@@ -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 */
+37
View File
@@ -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