mirror of
https://github.com/fail0verflow/mini.git
synced 2024-11-24 20:26:55 +01:00
nand, nandfs and crypto code for miniios
i blame lack of sleep for ugly code.
This commit is contained in:
parent
a02074a8ae
commit
51fd48f066
2
Makefile
2
Makefile
@ -12,7 +12,7 @@ TARGET = miniios.bin
|
|||||||
ELF = miniios.elf
|
ELF = miniios.elf
|
||||||
OBJECTS = start.o ipcstruct.o main.o ipc.o vsprintf.o string.o gecko.o memory.o memory_asm.o \
|
OBJECTS = start.o ipcstruct.o main.o ipc.o vsprintf.o string.o gecko.o memory.o memory_asm.o \
|
||||||
utils_asm.o utils.o ff.o diskio.o sdhc.o powerpc_elf.o powerpc.o panic.o irq.o irq_asm.o \
|
utils_asm.o utils.o ff.o diskio.o sdhc.o powerpc_elf.o powerpc.o panic.o irq.o irq_asm.o \
|
||||||
exception.o exception_asm.o
|
exception.o exception_asm.o crypto.o nand.o nandfs.o
|
||||||
|
|
||||||
$(TARGET) : $(ELF) $(ELFLOADER)
|
$(TARGET) : $(ELF) $(ELFLOADER)
|
||||||
@echo "MAKEBIN $@"
|
@echo "MAKEBIN $@"
|
||||||
|
102
crypto.c
Normal file
102
crypto.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#include "crypto.h"
|
||||||
|
#include "hollywood.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "irq.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define AES_CMD_RESET 0
|
||||||
|
#define AES_CMD_DECRYPT 0x9800
|
||||||
|
|
||||||
|
otp_t otp __attribute__((aligned(4))); // FIXME/WTF: why does this crash without the align?!
|
||||||
|
|
||||||
|
void crypto_read_otp(void)
|
||||||
|
{
|
||||||
|
u32 *otpd = (u32*)&otp;
|
||||||
|
int i;
|
||||||
|
for (i=0; i< 0x20; i++) {
|
||||||
|
write32(HW_OTPCMD,0x80000000|i);
|
||||||
|
*otpd++ = read32(HW_OTPDATA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void crypto_initialize()
|
||||||
|
{
|
||||||
|
crypto_read_otp();
|
||||||
|
write32(AES_CMD, 0);
|
||||||
|
while (read32(AES_CMD) != 0);
|
||||||
|
irq_enable(IRQ_AES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int _aes_irq = 0;
|
||||||
|
|
||||||
|
void aes_irq()
|
||||||
|
{
|
||||||
|
_aes_irq = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void aes_command(u16 cmd, u8 iv_keep, u32 blocks)
|
||||||
|
{
|
||||||
|
if (blocks != 0)
|
||||||
|
blocks--;
|
||||||
|
_aes_irq = 0;
|
||||||
|
write32(AES_CMD, (cmd << 16) | (iv_keep ? 0x1000 : 0) | (blocks&0x7f));
|
||||||
|
while (read32(AES_CMD) & 0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void aes_reset(void)
|
||||||
|
{
|
||||||
|
write32(AES_CMD, 0);
|
||||||
|
while (read32(AES_CMD) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void aes_set_iv(u8 *iv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
write32(AES_IV, *(u32 *)iv);
|
||||||
|
iv += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aes_empty_iv()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 4; i++)
|
||||||
|
write32(AES_IV, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void aes_set_key(u8 *key)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 4; i++) {
|
||||||
|
write32(AES_KEY, *(u32 *)key);
|
||||||
|
key += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
|
||||||
|
{
|
||||||
|
int this_blocks = 0;
|
||||||
|
while(blocks > 0) {
|
||||||
|
this_blocks = blocks;
|
||||||
|
if (this_blocks > 0x80)
|
||||||
|
this_blocks = 0x80;
|
||||||
|
|
||||||
|
dc_flushrange(src, this_blocks<<4);
|
||||||
|
dc_invalidaterange(dst, this_blocks<<4);
|
||||||
|
write32(AES_SRC, (u32)src);
|
||||||
|
write32(AES_DEST, (u32)dst);
|
||||||
|
aes_command(AES_CMD_DECRYPT, keep_iv, this_blocks);
|
||||||
|
|
||||||
|
blocks -= this_blocks;
|
||||||
|
src += this_blocks<<4;
|
||||||
|
dst += this_blocks<<4;
|
||||||
|
keep_iv = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
54
crypto.h
Normal file
54
crypto.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef __CRYPTO_H__
|
||||||
|
#define __CRYPTO_H__ 1
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u8 boot1_hash[20];
|
||||||
|
u8 common_key[16];
|
||||||
|
u32 ng_id;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u8 ng_priv[30];
|
||||||
|
u8 _wtf1[18];
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
u8 _wtf2[28];
|
||||||
|
u8 nand_hmac[20];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
u8 nand_key[16];
|
||||||
|
u8 rng_key[16];
|
||||||
|
u32 unk1;
|
||||||
|
u32 unk2;
|
||||||
|
} __attribute__((packed)) otp_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u32 dunno0; // 0x2 = MS
|
||||||
|
u32 dunno1; // 0x1 = CA
|
||||||
|
u32 ng_key_id;
|
||||||
|
u8 ng_sig[60];
|
||||||
|
u8 fill[0x2c];
|
||||||
|
u8 korean_key[16];
|
||||||
|
};
|
||||||
|
u8 data[512];
|
||||||
|
};
|
||||||
|
} __attribute__((packed)) seeprom_t;
|
||||||
|
|
||||||
|
extern otp_t otp;
|
||||||
|
|
||||||
|
void crypto_read_otp();
|
||||||
|
|
||||||
|
void crypto_initialize();
|
||||||
|
|
||||||
|
void aes_reset(void);
|
||||||
|
void aes_set_iv(u8 *iv);
|
||||||
|
void aes_empty_iv();
|
||||||
|
void aes_set_key(u8 *key);
|
||||||
|
void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv);
|
||||||
|
|
||||||
|
#endif
|
6
irq.c
6
irq.c
@ -3,6 +3,7 @@
|
|||||||
#include "gecko.h"
|
#include "gecko.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
void irq_setup_stack(void);
|
void irq_setup_stack(void);
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ void irq_handler(void)
|
|||||||
gecko_printf("IRQ: NAND\n");
|
gecko_printf("IRQ: NAND\n");
|
||||||
write32(NAND_CMD, 0x7fffffff); // shut it up
|
write32(NAND_CMD, 0x7fffffff); // shut it up
|
||||||
write32(HW_IRQFLAG, IRQF_NAND);
|
write32(HW_IRQFLAG, IRQF_NAND);
|
||||||
|
nand_irq();
|
||||||
}
|
}
|
||||||
if(flags & IRQF_GPIO1B) {
|
if(flags & IRQF_GPIO1B) {
|
||||||
gecko_printf("IRQ: GPIO1B\n");
|
gecko_printf("IRQ: GPIO1B\n");
|
||||||
@ -65,6 +67,10 @@ void irq_handler(void)
|
|||||||
ipc_irq();
|
ipc_irq();
|
||||||
write32(HW_IRQFLAG, IRQF_IPC);
|
write32(HW_IRQFLAG, IRQF_IPC);
|
||||||
}
|
}
|
||||||
|
if(flags & IRQF_AES) {
|
||||||
|
gecko_printf("IRQ: AES\n");
|
||||||
|
write32(HW_IRQFLAG, IRQF_AES);
|
||||||
|
}
|
||||||
flags &= ~IRQF_ALL;
|
flags &= ~IRQF_ALL;
|
||||||
if(flags) {
|
if(flags) {
|
||||||
gecko_printf("IRQ: unknown 0x%08x\n", flags);
|
gecko_printf("IRQ: unknown 0x%08x\n", flags);
|
||||||
|
4
irq.h
4
irq.h
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#define IRQ_TIMER 0
|
#define IRQ_TIMER 0
|
||||||
#define IRQ_NAND 1
|
#define IRQ_NAND 1
|
||||||
|
#define IRQ_AES 2 // not sure on this one
|
||||||
#define IRQ_GPIO1B 10
|
#define IRQ_GPIO1B 10
|
||||||
#define IRQ_GPIO1 11
|
#define IRQ_GPIO1 11
|
||||||
#define IRQ_RESET 17
|
#define IRQ_RESET 17
|
||||||
@ -10,6 +11,7 @@
|
|||||||
|
|
||||||
#define IRQF_TIMER (1<<IRQ_TIMER)
|
#define IRQF_TIMER (1<<IRQ_TIMER)
|
||||||
#define IRQF_NAND (1<<IRQ_NAND)
|
#define IRQF_NAND (1<<IRQ_NAND)
|
||||||
|
#define IRQF_AES (1<<IRQ_AES)
|
||||||
#define IRQF_GPIO1B (1<<IRQ_GPIO1B)
|
#define IRQF_GPIO1B (1<<IRQ_GPIO1B)
|
||||||
#define IRQF_GPIO1 (1<<IRQ_GPIO1)
|
#define IRQF_GPIO1 (1<<IRQ_GPIO1)
|
||||||
#define IRQF_RESET (1<<IRQ_RESET)
|
#define IRQF_RESET (1<<IRQ_RESET)
|
||||||
@ -17,7 +19,7 @@
|
|||||||
|
|
||||||
#define IRQF_ALL ( \
|
#define IRQF_ALL ( \
|
||||||
IRQF_TIMER|IRQF_NAND|IRQF_GPIO1B|IRQF_GPIO1| \
|
IRQF_TIMER|IRQF_NAND|IRQF_GPIO1B|IRQF_GPIO1| \
|
||||||
IRQF_RESET|IRQF_IPC \
|
IRQF_RESET|IRQF_IPC|IRQF_AES \
|
||||||
)
|
)
|
||||||
|
|
||||||
#define CPSR_IRQDIS 0x80
|
#define CPSR_IRQDIS 0x80
|
||||||
|
16
main.c
16
main.c
@ -13,6 +13,11 @@
|
|||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
#include "ipc.h"
|
#include "ipc.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "nand.h"
|
||||||
|
|
||||||
|
// TODO: move to powerpc
|
||||||
|
#include "nandfs.h"
|
||||||
|
|
||||||
void *vector;
|
void *vector;
|
||||||
|
|
||||||
@ -158,12 +163,21 @@ void *_main(void *base)
|
|||||||
|
|
||||||
irq_initialize();
|
irq_initialize();
|
||||||
irq_enable(IRQ_TIMER);
|
irq_enable(IRQ_TIMER);
|
||||||
irq_enable(IRQ_NAND);
|
|
||||||
irq_enable(IRQ_GPIO1B);
|
irq_enable(IRQ_GPIO1B);
|
||||||
irq_enable(IRQ_GPIO1);
|
irq_enable(IRQ_GPIO1);
|
||||||
irq_enable(IRQ_RESET);
|
irq_enable(IRQ_RESET);
|
||||||
gecko_puts("Interrupts initialized\n");
|
gecko_puts("Interrupts initialized\n");
|
||||||
|
|
||||||
|
crypto_initialize();
|
||||||
|
gecko_puts("crypto support initialized\n");
|
||||||
|
|
||||||
|
nand_initialize();
|
||||||
|
gecko_puts("NAND initialized.\n");
|
||||||
|
|
||||||
|
// TODO: move to powerpc
|
||||||
|
nandfs_initialize();
|
||||||
|
gecko_puts("NAND FS initialized.\n");
|
||||||
|
|
||||||
gecko_puts("Initializing IPC...\n");
|
gecko_puts("Initializing IPC...\n");
|
||||||
ipc_initialize();
|
ipc_initialize();
|
||||||
|
|
||||||
|
206
nand.c
Normal file
206
nand.c
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
#include "hollywood.h"
|
||||||
|
#include "nand.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "start.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "irq.h"
|
||||||
|
|
||||||
|
//#define NAND_DEBUG 1
|
||||||
|
#undef NAND_SUPPORT_WRITE
|
||||||
|
#undef NAND_SUPPORT_ERASE
|
||||||
|
|
||||||
|
#ifdef NAND_DEBUG
|
||||||
|
# include "gecko.h"
|
||||||
|
# define NAND_debug(f, arg...) gecko_printf("NAND: " f "\n", ##arg);
|
||||||
|
#else
|
||||||
|
# define NAND_debug(f, arg...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STACK_ALIGN(type, name, cnt, alignment) \
|
||||||
|
u8 _al__##name[((sizeof(type)*(cnt)) + (alignment) + \
|
||||||
|
(((sizeof(type)*(cnt))%(alignment)) > 0 ? ((alignment) - \
|
||||||
|
((sizeof(type)*(cnt))%(alignment))) : 0))]; \
|
||||||
|
type *name = (type*)(((u32)(_al__##name)) + ((alignment) - (( \
|
||||||
|
(u32)(_al__##name))&((alignment)-1))))
|
||||||
|
|
||||||
|
|
||||||
|
#define NAND_RESET 0xff
|
||||||
|
#define NAND_CHIPID 0x90
|
||||||
|
#define NAND_GETSTATUS 0x70
|
||||||
|
#define NAND_ERASE_PRE 0x60
|
||||||
|
#define NAND_ERASE_POST 0xd0
|
||||||
|
#define NAND_READ_PRE 0x00
|
||||||
|
#define NAND_READ_POST 0x30
|
||||||
|
#define NAND_WRITE_PRE 0x80
|
||||||
|
#define NAND_WRITE_POST 0x10
|
||||||
|
|
||||||
|
#define NAND_BUSY_MASK 0x80000000
|
||||||
|
|
||||||
|
#define PAGE_SIZE 2048
|
||||||
|
#define PAGE_SPARE_SIZE 64
|
||||||
|
|
||||||
|
static int irq = 0;
|
||||||
|
|
||||||
|
void nand_irq(void)
|
||||||
|
{
|
||||||
|
irq = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline u32 __nand_read32(u32 addr)
|
||||||
|
{
|
||||||
|
return read32(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void __nand_write32(u32 addr, u32 data)
|
||||||
|
{
|
||||||
|
write32(addr, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void __nand_wait(void) {
|
||||||
|
while(__nand_read32(NAND_CMD) & NAND_BUSY_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nand_send_command(u32 command, u32 bitmask, u32 flags, u32 num_bytes) {
|
||||||
|
u32 cmd = NAND_BUSY_MASK | (bitmask << 24) | (command << 16) | flags | num_bytes;
|
||||||
|
|
||||||
|
NAND_debug("nand_send_command(%x, %x, %x, %x) -> %x\n",
|
||||||
|
command, bitmask, flags, num_bytes, cmd);
|
||||||
|
|
||||||
|
__nand_write32(NAND_CMD, 0x7fffffff);
|
||||||
|
__nand_write32(NAND_CMD, 0);
|
||||||
|
__nand_write32(NAND_CMD, cmd);
|
||||||
|
__nand_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nand_set_address(s32 page_off, s32 pageno) {
|
||||||
|
NAND_debug("nand_set_address: %d, %d\n", page_off, pageno);
|
||||||
|
if (page_off != -1) __nand_write32(NAND_ADDR0, page_off);
|
||||||
|
if (pageno != -1) __nand_write32(NAND_ADDR1, pageno);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __nand_setup_dma(u8 *data, u8 *spare) {
|
||||||
|
NAND_debug("nand_setup_dma: %p, %p\n", data, spare);
|
||||||
|
if (((s32)data) != -1) {
|
||||||
|
dc_invalidaterange(data, 0x800);
|
||||||
|
__nand_write32(NAND_DATA, (s32)data);
|
||||||
|
}
|
||||||
|
if (((s32)spare) != -1) {
|
||||||
|
dc_invalidaterange(spare, 0x50); // +0x10 for calculated syndrome?
|
||||||
|
__nand_write32(NAND_ECC, (s32)spare);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int nand_reset(void)
|
||||||
|
{
|
||||||
|
NAND_debug("nand_reset()\n");
|
||||||
|
nand_send_command(NAND_RESET, 0, 0x8000, 0);
|
||||||
|
// yay cargo cult
|
||||||
|
__nand_write32(NAND_CONF, 0x8000000);
|
||||||
|
__nand_write32(NAND_CONF, 0x4b3e0e7f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 nand_get_id(void) {
|
||||||
|
STACK_ALIGN(u8, idbuf, 0x40, 64);
|
||||||
|
|
||||||
|
__nand_wait();
|
||||||
|
|
||||||
|
NAND_debug("nand_get_id(%p) (pre)\n", idbuf);
|
||||||
|
memset(idbuf, 0x42, 4);
|
||||||
|
dc_flushrange(idbuf, 0x40);
|
||||||
|
__nand_set_address(0,0);
|
||||||
|
|
||||||
|
NAND_debug("id = %02hx%02hx%02hx%02hx\n", idbuf[0], idbuf[1], idbuf[2], idbuf[3]);
|
||||||
|
|
||||||
|
__nand_setup_dma(idbuf, (u8 *)-1);
|
||||||
|
nand_send_command(NAND_CHIPID, 1, 0x2000, 0x40);
|
||||||
|
NAND_debug("id = %02hx%02hx%02hx%02hx (post)\n", idbuf[0], idbuf[1], idbuf[2], idbuf[3]);
|
||||||
|
|
||||||
|
return idbuf[0] << 24 | idbuf[1] << 16 | idbuf[2] << 8 | idbuf[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 nand_get_status(void) {
|
||||||
|
STACK_ALIGN(u8, status_buf, 0x40, 64);
|
||||||
|
status_buf[0]=0;
|
||||||
|
dc_flushrange(status_buf, 0x40);
|
||||||
|
__nand_setup_dma(status_buf, (u8 *)-1);
|
||||||
|
nand_send_command(NAND_GETSTATUS, 0, 0x2000, 0x40);
|
||||||
|
dc_invalidaterange(status_buf, 0x40);
|
||||||
|
return status_buf[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void __nand_wait_irq(void) {
|
||||||
|
while(irq == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nand_read_page(u32 pageno, void *data, void *ecc) {
|
||||||
|
NAND_debug("nand_read_page(%u, %p, %p)\n", pageno, data, ecc);
|
||||||
|
#if 1
|
||||||
|
irq = 0;
|
||||||
|
__nand_set_address(0, pageno);
|
||||||
|
nand_send_command(NAND_READ_PRE, 0x1f, 0, 0);
|
||||||
|
|
||||||
|
dc_invalidaterange(data, 0x800);
|
||||||
|
dc_invalidaterange(ecc, 0x50);
|
||||||
|
|
||||||
|
__nand_setup_dma(data, ecc);
|
||||||
|
nand_send_command(NAND_READ_POST, 0, 0x4000b000, 0x840);
|
||||||
|
|
||||||
|
__nand_wait_irq();
|
||||||
|
#else
|
||||||
|
int i;
|
||||||
|
unsigned char *c_data = (unsigned char *)data;
|
||||||
|
unsigned char *c_ecc = (unsigned char *)ecc;
|
||||||
|
for(i=0; i<0x800; i++) c_data[i] = pageno % 256;
|
||||||
|
for(i=0; i<0x40; i++) c_ecc = pageno % 256;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: do we really need to read the ECC data?
|
||||||
|
static u8 ecc[64] __attribute__((aligned(32))) MEM2_BSS;
|
||||||
|
void nand_read_cluster(u32 clusterno, void *data) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
nand_read_page((clusterno*8) + i, data + (i * PAGE_SIZE), ecc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nand_read_decrypted_cluster(u32 clusterno, void *data) {
|
||||||
|
nand_read_cluster(clusterno, data);
|
||||||
|
aes_reset();
|
||||||
|
aes_set_key(otp.nand_key);
|
||||||
|
aes_empty_iv();
|
||||||
|
aes_decrypt(data, data, 0x400, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NAND_SUPPORT_WRITE
|
||||||
|
void nand_write_page(u32 pageno, void *data, void *ecc) {
|
||||||
|
NAND_debug("nand_write_page(%u, %p, %p)\n", pageno, data, ecc);
|
||||||
|
dc_flushrange(data, 0x800);
|
||||||
|
dc_flushrange(ecc, 0x40);
|
||||||
|
__nand_set_address(0, pageno);
|
||||||
|
__nand_setup_dma(data, ecc);
|
||||||
|
nand_send_command(NAND_WRITE_PRE, 0x1f, 0x40005000, 0x840);
|
||||||
|
|
||||||
|
nand_send_command(NAND_WRITE_POST, 0, 0x40008000, 0x0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NAND_SUPPORT_ERASE
|
||||||
|
void nand_erase_block(u32 pageno) {
|
||||||
|
NAND_debug("nand_erase_block(%d)\n", pageno);
|
||||||
|
__nand_set_address(0, pageno);
|
||||||
|
nand_send_command(NAND_ERASE_PRE, 0x1c, 0, 0);
|
||||||
|
nand_send_command(NAND_ERASE_POST, 0, 0x40008000, 0x0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void nand_initialize(void)
|
||||||
|
{
|
||||||
|
irq_enable(IRQ_NAND);
|
||||||
|
irq = 0;
|
||||||
|
nand_reset();
|
||||||
|
}
|
21
nand.h
Normal file
21
nand.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef __NAND_H__
|
||||||
|
#define __NAND_H__
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void nand_irq(void);
|
||||||
|
|
||||||
|
void nand_send_command(u32 command, u32 bitmask, u32 flags, u32 num_bytes);
|
||||||
|
int nand_reset(void);
|
||||||
|
u32 nand_get_id(void);
|
||||||
|
u32 nand_get_status(void);
|
||||||
|
void nand_read_page(u32 pageno, void *data, void *ecc);
|
||||||
|
void nand_write_page(u32 pageno, void *data, void *ecc);
|
||||||
|
void nand_erase_block(u32 pageno);
|
||||||
|
|
||||||
|
void nand_read_cluster(u32 clusterno, void *data);
|
||||||
|
void nand_read_decrypted_cluster(u32 clusterno, void *data);
|
||||||
|
|
||||||
|
void nand_initialize();
|
||||||
|
|
||||||
|
#endif
|
214
nandfs.c
Normal file
214
nandfs.c
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
#include "nandfs.h"
|
||||||
|
#include "nand.h"
|
||||||
|
#include "gecko.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#define PAGE_SIZE 2048
|
||||||
|
|
||||||
|
struct _nandfs_file_node {
|
||||||
|
u8 name[NANDFS_NAME_LEN];
|
||||||
|
u8 attr;
|
||||||
|
u8 wtf;
|
||||||
|
union {
|
||||||
|
u16 first_child;
|
||||||
|
u16 first_cluster;
|
||||||
|
};
|
||||||
|
u16 sibling;
|
||||||
|
u32 size;
|
||||||
|
u32 uid;
|
||||||
|
u16 gid;
|
||||||
|
u32 dummy;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct _nandfs_sffs {
|
||||||
|
u8 magic[4];
|
||||||
|
u32 version;
|
||||||
|
u32 dummy;
|
||||||
|
|
||||||
|
s16 cluster_table[32768];
|
||||||
|
struct _nandfs_file_node files[6143];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
static struct _nandfs_sffs sffs __attribute__((aligned(32))) MEM2_BSS;
|
||||||
|
static u8 buffer[8*2048] __attribute__((aligned(32))) MEM2_BSS;
|
||||||
|
static s32 initialized = 0;
|
||||||
|
|
||||||
|
s32 nandfs_initialize()
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
u32 supercluster = 0;
|
||||||
|
u32 supercluster_version = 0;
|
||||||
|
|
||||||
|
nand_reset();
|
||||||
|
|
||||||
|
for(i = 0x7F00; i < 0x7fff; i++) {
|
||||||
|
nand_read_page(i*8, (void *)&sffs, NULL);
|
||||||
|
if(memcmp(sffs.magic, "SFFS", 4) != 0)
|
||||||
|
continue;
|
||||||
|
if(supercluster == 0 || sffs.version > supercluster_version) {
|
||||||
|
supercluster = i;
|
||||||
|
supercluster_version = sffs.version;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(supercluster == 0) {
|
||||||
|
gecko_printf("no supercluster found. "
|
||||||
|
" your nand filesystem is seriously broken...\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gecko_printf("using supercluster starting at page %08x\n",
|
||||||
|
supercluster);
|
||||||
|
|
||||||
|
for(i = 0; i < sizeof(struct _nandfs_sffs)/(PAGE_SIZE*8);
|
||||||
|
i++) {
|
||||||
|
nand_read_cluster(supercluster + i,
|
||||||
|
((u8 *)&sffs) + (i * PAGE_SIZE * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 nandfs_open(struct nandfs_fp *fp, const char *path)
|
||||||
|
{
|
||||||
|
char *ptr, *ptr2;
|
||||||
|
u32 len;
|
||||||
|
struct _nandfs_file_node *cur = sffs.files;
|
||||||
|
|
||||||
|
if (initialized != 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(fp, 0, sizeof(*fp));
|
||||||
|
|
||||||
|
if(strcmp(cur->name, "/") != 0) {
|
||||||
|
gecko_printf("your nandfs is corrupted. fixit!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = &sffs.files[cur->first_child];
|
||||||
|
|
||||||
|
ptr = (char *)path;
|
||||||
|
do {
|
||||||
|
ptr++;
|
||||||
|
ptr2 = strchr(ptr, '/');
|
||||||
|
if (ptr2 == NULL)
|
||||||
|
len = strlen(ptr);
|
||||||
|
else {
|
||||||
|
ptr2++;
|
||||||
|
len = ptr2 - ptr - 1;
|
||||||
|
}
|
||||||
|
if (len > 12)
|
||||||
|
{
|
||||||
|
gecko_printf("invalid length: %s %s %s [%d]\n",
|
||||||
|
ptr, ptr2, path, len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gecko_printf("length: %d\n", len);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int res = strncmp(cur->name, ptr, len);
|
||||||
|
if(ptr2 != NULL && strncmp(cur->name, ptr, len) == 0
|
||||||
|
&& strnlen(cur->name, 12) == len
|
||||||
|
&& (cur->attr&3) == 2
|
||||||
|
&& (cur->first_child&0xffff) != (s16)0xffff) {
|
||||||
|
cur = &sffs.files[cur->first_child];
|
||||||
|
ptr = ptr2-1;
|
||||||
|
break;
|
||||||
|
} else if(ptr2 == NULL &&
|
||||||
|
strncmp(cur->name, ptr, len) == 0 &&
|
||||||
|
strnlen(cur->name, 12) == len &&
|
||||||
|
(cur->attr&3) == 1) {
|
||||||
|
break;
|
||||||
|
} else if((cur->sibling&0xffff) != 0xffff) {
|
||||||
|
cur = &sffs.files[cur->sibling];
|
||||||
|
} else {
|
||||||
|
gecko_printf("unable to find %s (%s)\n", ptr,
|
||||||
|
path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while(ptr2 != NULL);
|
||||||
|
|
||||||
|
fp->first_cluster = cur->first_cluster;
|
||||||
|
fp->cur_cluster = fp->first_cluster;
|
||||||
|
fp->offset = 0;
|
||||||
|
fp->size = cur->size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 nandfs_read(void *ptr, u32 size, u32 nmemb, struct nandfs_fp *fp)
|
||||||
|
{
|
||||||
|
u32 total = size*nmemb;
|
||||||
|
u32 copy_offset, copy_len;
|
||||||
|
|
||||||
|
if (initialized != 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (fp->offset + total > fp->size)
|
||||||
|
total = fp->size - fp->offset;
|
||||||
|
|
||||||
|
if (total == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
while(total > 0) {
|
||||||
|
nand_read_decrypted_cluster(fp->cur_cluster, buffer);
|
||||||
|
copy_offset = fp->offset % (PAGE_SIZE * 8);
|
||||||
|
copy_len = (PAGE_SIZE * 8) - copy_offset;
|
||||||
|
if(copy_len > total)
|
||||||
|
copy_len = total;
|
||||||
|
memcpy(ptr, buffer + copy_offset, copy_len);
|
||||||
|
total -= copy_len;
|
||||||
|
fp->offset += copy_len;
|
||||||
|
|
||||||
|
if ((copy_offset + copy_len) >= (PAGE_SIZE * 8))
|
||||||
|
fp->cur_cluster = sffs.cluster_table[fp->cur_cluster];
|
||||||
|
}
|
||||||
|
|
||||||
|
return size*nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 nandfs_seek(struct nandfs_fp *fp, s32 offset, u32 whence)
|
||||||
|
{
|
||||||
|
if (initialized != 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch (whence) {
|
||||||
|
case NANDFS_SEEK_SET:
|
||||||
|
if (offset > fp->size)
|
||||||
|
return -1;
|
||||||
|
if (offset > 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fp->offset = offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NANDFS_SEEK_CUR:
|
||||||
|
if ((fp->offset + offset) > fp->size ||
|
||||||
|
(fp->offset + offset) < 0)
|
||||||
|
return -1;
|
||||||
|
fp->offset += offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NANDFS_SEEK_END:
|
||||||
|
default:
|
||||||
|
if ((fp->size + offset) > fp->size ||
|
||||||
|
(fp->size + offset) < 0)
|
||||||
|
return -1;
|
||||||
|
fp->offset = fp->size + offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int skip = fp->offset;
|
||||||
|
fp->cur_cluster = fp->first_cluster;
|
||||||
|
while (skip > (2048*8)) {
|
||||||
|
fp->cur_cluster = sffs.cluster_table[fp->cur_cluster];
|
||||||
|
skip -= 2048*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
25
nandfs.h
Normal file
25
nandfs.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __NANDFS_H__
|
||||||
|
#define __NANDFS_H__
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#define NANDFS_NAME_LEN 12
|
||||||
|
|
||||||
|
#define NANDFS_SEEK_SET 0
|
||||||
|
#define NANDFS_SEEK_CUR 1
|
||||||
|
#define NANDFS_SEEK_END 2
|
||||||
|
|
||||||
|
struct nandfs_fp {
|
||||||
|
s16 first_cluster;
|
||||||
|
s32 cur_cluster;
|
||||||
|
u32 size;
|
||||||
|
u32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
s32 nandfs_initialize();
|
||||||
|
|
||||||
|
s32 nandfs_open(struct nandfs_fp *fp, const char *path);
|
||||||
|
s32 nandfs_read(void *ptr, u32 size, u32 nmemb, struct nandfs_fp *fp);
|
||||||
|
s32 nandfs_seek(struct nandfs_fp *fp, s32 offset, u32 whence);
|
||||||
|
|
||||||
|
#endif
|
20
string.c
20
string.c
@ -58,6 +58,18 @@ int strcmp(const char *p, const char *q)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int strncmp(const char *p, const char *q, size_t n)
|
||||||
|
{
|
||||||
|
while (n-- != 0) {
|
||||||
|
unsigned char a, b;
|
||||||
|
a = *p++;
|
||||||
|
b = *q++;
|
||||||
|
if (a == 0 || a != b)
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void *memset(void *dst, int x, size_t n)
|
void *memset(void *dst, int x, size_t n)
|
||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
@ -92,3 +104,11 @@ int memcmp(const void *s1, const void *s2, size_t n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *strchr(const char *s, int c)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
if(*s == c)
|
||||||
|
return (char *)s;
|
||||||
|
} while(*s++ != 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
2
string.h
2
string.h
@ -6,8 +6,10 @@
|
|||||||
char *strcpy(char *, const char *);
|
char *strcpy(char *, const char *);
|
||||||
char *strncpy(char *, const char *, size_t);
|
char *strncpy(char *, const char *, size_t);
|
||||||
int strcmp(const char *, const char *);
|
int strcmp(const char *, const char *);
|
||||||
|
int strncmp(const char *p, const char *q, size_t n);
|
||||||
size_t strlen(const char *);
|
size_t strlen(const char *);
|
||||||
size_t strnlen(const char *, size_t);
|
size_t strnlen(const char *, size_t);
|
||||||
|
char *strchr(const char *s, int c);
|
||||||
void *memset(void *, int, size_t);
|
void *memset(void *, int, size_t);
|
||||||
void *memcpy(void *, const void *, size_t);
|
void *memcpy(void *, const void *, size_t);
|
||||||
int memcmp(const void *s1, const void *s2, size_t n);
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
|
Loading…
Reference in New Issue
Block a user