Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From 8cc8dac612a432cdb973c69ab9d2af71341ab9fe Mon Sep 17 00:00:00 2001
- From: Alex Marshall <SquidMan72@gmail.com>
- Date: Mon, 25 May 2009 15:14:12 -0700
- Subject: [PATCH 3/3] Added AES encryption, NAND FS (implemented as a new device), and several new access methods to the raw NAND.
- ---
- Makefile | 2 +-
- crypto.c | 27 ++++-
- crypto.h | 1 +
- ipc.c | 4 +
- ipc.h | 143 +++++++++++++++----------
- nand.c | 161 ++++++++++++++++++++++++++++
- nand.h | 14 ++-
- nandfs.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- nandfs.h | 38 +++++++
- nandstructs.h | 133 +++++++++++++++++++++++
- string.c | 43 ++++++++
- string.h | 1 +
- 12 files changed, 830 insertions(+), 68 deletions(-)
- create mode 100644 nandfs.c
- create mode 100644 nandfs.h
- create mode 100644 nandstructs.h
- diff --git a/Makefile b/Makefile
- index d35474e..0cd7719 100644
- --- a/Makefile
- +++ b/Makefile
- @@ -13,7 +13,7 @@ TARGET_BIN = armboot.bin
- OBJS = start.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 exception.o exception_asm.o seeprom.o crypto.o nand.o \
- - boot2.o ldhack.o sdmmc.o
- + boot2.o ldhack.o sdmmc.o nandfs.o
- include common.mk
- diff --git a/crypto.c b/crypto.c
- index ffb517a..ac7cc10 100644
- --- a/crypto.c
- +++ b/crypto.c
- @@ -21,6 +21,7 @@ Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
- #define AES_CMD_RESET 0
- #define AES_CMD_DECRYPT 0x9800
- +#define AES_CMD_ENCRYPT 0x9000
- otp_t otp;
- seeprom_t seeprom;
- @@ -115,31 +116,41 @@ void aes_set_key(u8 *key)
- }
- }
- -void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
- +void aes_engine(u8 *src, u8 *dst, u32 blocks, u8 keep_iv, u16 cmd)
- {
- int this_blocks = 0;
- while(blocks > 0) {
- this_blocks = blocks;
- if (this_blocks > 0x80)
- this_blocks = 0x80;
- -
- +
- write32(AES_SRC, dma_addr(src));
- write32(AES_DEST, dma_addr(dst));
- -
- +
- dc_flushrange(src, blocks * 16);
- dc_invalidaterange(dst, blocks * 16);
- -
- +
- ahb_flush_to(AHB_AES);
- - aes_command(AES_CMD_DECRYPT, keep_iv, this_blocks);
- + aes_command(cmd, keep_iv, this_blocks);
- ahb_flush_from(AHB_AES);
- ahb_flush_to(AHB_STARLET);
- -
- +
- blocks -= this_blocks;
- src += this_blocks<<4;
- dst += this_blocks<<4;
- keep_iv = 1;
- }
- +
- +}
- +void aes_decrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
- +{
- + aes_engine(src, dst, blocks, keep_iv, AES_CMD_DECRYPT);
- +}
- +
- +void aes_encrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv)
- +{
- + aes_engine(src, dst, blocks, keep_iv, AES_CMD_ENCRYPT);
- }
- void aes_ipc(volatile ipc_request *req)
- @@ -158,6 +169,10 @@ void aes_ipc(volatile ipc_request *req)
- aes_decrypt((u8 *)req->args[0], (u8 *)req->args[1],
- req->args[2], req->args[3]);
- break;
- + case IPC_AES_ENCRYPT:
- + aes_encrypt((u8 *)req->args[0], (u8 *)req->args[1],
- + req->args[2], req->args[3]);
- + break;
- default:
- gecko_printf("IPC: unknown SLOW AES request %04x\n",
- req->req);
- diff --git a/crypto.h b/crypto.h
- index 66f0ede..34de424 100644
- --- a/crypto.h
- +++ b/crypto.h
- @@ -75,6 +75,7 @@ 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);
- +void aes_encrypt(u8 *src, u8 *dst, u32 blocks, u8 keep_iv);
- void aes_ipc(volatile ipc_request *req);
- #endif
- diff --git a/ipc.c b/ipc.c
- index 9daad2d..5b6e583 100644
- --- a/ipc.c
- +++ b/ipc.c
- @@ -22,6 +22,7 @@ Copyright (C) 2009 John Kelley <wiidev@kelley.ca>
- #include "gecko.h"
- #include "ipc.h"
- #include "nand.h"
- +#include "nandfs.h"
- #include "sdhcvar.h"
- #include "sdmmc.h"
- #include "crypto.h"
- @@ -156,6 +157,9 @@ static u32 process_slow(volatile ipc_request *req)
- case IPC_DEV_NAND:
- nand_ipc(req);
- break;
- + case IPC_DEV_NANDFS:
- + nandfs_ipc(req);
- + break;
- case IPC_DEV_SDHC:
- sdhc_ipc(req);
- break;
- diff --git a/ipc.h b/ipc.h
- index 1071f08..984e452 100644
- --- a/ipc.h
- +++ b/ipc.h
- @@ -31,72 +31,97 @@ Copyright (C) 2009 John Kelley <wiidev@kelley.ca>
- Even still, you are encouraged to add in sanity checks and version
- checking to prevent strange bugs or even data loss. --bushing */
- -#define IPC_FAST 0x01
- -#define IPC_SLOW 0x00
- -
- -#define IPC_DEV_SYS 0x00
- -#define IPC_DEV_NAND 0x01
- -#define IPC_DEV_SDHC 0x02
- -#define IPC_DEV_KEYS 0x03
- -#define IPC_DEV_AES 0x04
- -#define IPC_DEV_BOOT2 0x05
- -#define IPC_DEV_PPC 0x06
- -#define IPC_DEV_SDMMC 0x07
- -
- -//#define IPC_DEV_USER0 0x80
- -//#define IPC_DEV_USER1 0x81
- -
- -#define IPC_SYS_PING 0x0000
- -#define IPC_SYS_JUMP 0x0001
- -#define IPC_SYS_GETVERS 0x0002
- -#define IPC_SYS_GETGITS 0x0003
- -#define IPC_SYS_WRITE32 0x0100
- -#define IPC_SYS_WRITE16 0x0101
- -#define IPC_SYS_WRITE8 0x0102
- -#define IPC_SYS_READ32 0x0103
- -#define IPC_SYS_READ16 0x0104
- -#define IPC_SYS_READ8 0x0105
- -#define IPC_SYS_SET32 0x0106
- -#define IPC_SYS_SET16 0x0107
- -#define IPC_SYS_SET8 0x0108
- -#define IPC_SYS_CLEAR32 0x0109
- -#define IPC_SYS_CLEAR16 0x010a
- -#define IPC_SYS_CLEAR8 0x010b
- -#define IPC_SYS_MASK32 0x010c
- -#define IPC_SYS_MASK16 0x010d
- -#define IPC_SYS_MASK8 0x010e
- -
- -#define IPC_NAND_RESET 0x0000
- -#define IPC_NAND_GETID 0x0001
- -#define IPC_NAND_READ 0x0002
- -#define IPC_NAND_WRITE 0x0003
- -#define IPC_NAND_ERASE 0x0004
- -#define IPC_NAND_STATUS 0x0005
- -//#define IPC_NAND_USER0 0x8000
- -//#define IPC_NAND_USER1 0x8001
- +#define IPC_FAST 0x01
- +#define IPC_SLOW 0x00
- +
- +#define IPC_DEV_SYS 0x00
- +#define IPC_DEV_NAND 0x01
- +#define IPC_DEV_SDHC 0x02
- +#define IPC_DEV_KEYS 0x03
- +#define IPC_DEV_AES 0x04
- +#define IPC_DEV_BOOT2 0x05
- +#define IPC_DEV_PPC 0x06
- +#define IPC_DEV_SDMMC 0x07
- +#define IPC_DEV_NANDFS 0x80
- +
- +//#define IPC_DEV_USER0 0x80
- +//#define IPC_DEV_USER1 0x81
- +
- +#define IPC_SYS_PING 0x0000
- +#define IPC_SYS_JUMP 0x0001
- +#define IPC_SYS_GETVERS 0x0002
- +#define IPC_SYS_GETGITS 0x0003
- +#define IPC_SYS_WRITE32 0x0100
- +#define IPC_SYS_WRITE16 0x0101
- +#define IPC_SYS_WRITE8 0x0102
- +#define IPC_SYS_READ32 0x0103
- +#define IPC_SYS_READ16 0x0104
- +#define IPC_SYS_READ8 0x0105
- +#define IPC_SYS_SET32 0x0106
- +#define IPC_SYS_SET16 0x0107
- +#define IPC_SYS_SET8 0x0108
- +#define IPC_SYS_CLEAR32 0x0109
- +#define IPC_SYS_CLEAR16 0x010a
- +#define IPC_SYS_CLEAR8 0x010b
- +#define IPC_SYS_MASK32 0x010c
- +#define IPC_SYS_MASK16 0x010d
- +#define IPC_SYS_MASK8 0x010e
- +
- +#define IPC_NAND_RESET 0x0000
- +#define IPC_NAND_GETID 0x0001
- +#define IPC_NAND_READ 0x0002
- +#define IPC_NAND_WRITE 0x0003
- +#define IPC_NAND_ERASE 0x0004
- +#define IPC_NAND_STATUS 0x0005
- +// Read and decrypt a cluster
- +#define IPC_NAND_READ_DECRYPT_C 0x8000
- +// Read and decrypt a block
- +#define IPC_NAND_READ_DECRYPT_B 0x8001
- +// Read a cluster
- +#define IPC_NAND_READ_CLUSTER 0x8002
- +// Read a block
- +#define IPC_NAND_READ_BLOCK 0x8003
- +// Encrypt and write a cluster
- +#define IPC_NAND_WRITE_CRYPT_C 0x8004
- +// Encrypt and write a block
- +#define IPC_NAND_WRITE_CRYPT_B 0x8005
- +// Write a cluster
- +#define IPC_NAND_WRITE_CLUSTER 0x8006
- +// Write a block
- +#define IPC_NAND_WRITE_BLOCK 0x8007
- +
- +//#define IPC_NAND_USER0 0x8000
- +//#define IPC_NAND_USER1 0x8001
- // etc.
- -#define IPC_SDHC_DISCOVER 0x0000
- -#define IPC_SDHC_EXIT 0x0001
- +#define IPC_NANDFS_MOUNT 0x8000
- +#define IPC_NANDFS_OPEN 0x8001
- +#define IPC_NANDFS_CLOSE 0x8002
- +#define IPC_NANDFS_READ 0x8003
- +#define IPC_NANDFS_WRITE 0x8004
- -#define IPC_SDMMC_ACK 0x0000
- -#define IPC_SDMMC_READ 0x0001
- -#define IPC_SDMMC_WRITE 0x0002
- -#define IPC_SDMMC_STATE 0x0003
- -#define IPC_SDMMC_SIZE 0x0004
- +#define IPC_SDHC_DISCOVER 0x0000
- +#define IPC_SDHC_EXIT 0x0001
- -#define IPC_KEYS_GETOTP 0x0000
- -#define IPC_KEYS_GETEEP 0x0001
- +#define IPC_SDMMC_ACK 0x0000
- +#define IPC_SDMMC_READ 0x0001
- +#define IPC_SDMMC_WRITE 0x0002
- +#define IPC_SDMMC_STATE 0x0003
- +#define IPC_SDMMC_SIZE 0x0004
- -#define IPC_AES_RESET 0x0000
- -#define IPC_AES_SETIV 0x0001
- -#define IPC_AES_SETKEY 0x0002
- -#define IPC_AES_DECRYPT 0x0003
- +#define IPC_KEYS_GETOTP 0x0000
- +#define IPC_KEYS_GETEEP 0x0001
- -#define IPC_BOOT2_RUN 0x0000
- -#define IPC_BOOT2_TMD 0x0001
- +#define IPC_AES_RESET 0x0000
- +#define IPC_AES_SETIV 0x0001
- +#define IPC_AES_SETKEY 0x0002
- +#define IPC_AES_DECRYPT 0x0003
- +#define IPC_AES_ENCRYPT 0x8000
- -#define IPC_PPC_BOOT 0x0000
- +#define IPC_BOOT2_RUN 0x0000
- +#define IPC_BOOT2_TMD 0x0001
- +
- +#define IPC_PPC_BOOT 0x0000
- #define IPC_CODE (f,d,r) (((f)<<24)|((d)<<16)|(r))
- diff --git a/nand.c b/nand.c
- index a5f2e8e..5600b81 100644
- --- a/nand.c
- +++ b/nand.c
- @@ -96,9 +96,39 @@ void nand_irq(void)
- dc_flushrange((void*)current_request.args[2], PAGE_SPARE_SIZE);
- }
- break;
- + case IPC_NAND_READ_DECRYPT_C:
- + case IPC_NAND_READ_CLUSTER:
- + err = nand_correct(last_page_read, ipc_data, ipc_ecc);
- +
- + if (current_request.args[1] != 0xFFFFFFFF) {
- + memcpy32((void*)current_request.args[1], ipc_data, CLUSTER_SIZE);
- + dc_flushrange((void*)current_request.args[1], CLUSTER_SIZE);
- + }
- + if (current_request.args[2] != 0xFFFFFFFF) {
- + memcpy32((void*)current_request.args[2], ipc_ecc, PAGE_SPARE_SIZE * PAGES_PER_CLUSTER);
- + dc_flushrange((void*)current_request.args[2], PAGE_SPARE_SIZE * PAGES_PER_CLUSTER);
- + }
- + break;
- + case IPC_NAND_READ_DECRYPT_B:
- + case IPC_NAND_READ_BLOCK:
- + err = nand_correct(last_page_read, ipc_data, ipc_ecc);
- +
- + if (current_request.args[1] != 0xFFFFFFFF) {
- + memcpy32((void*)current_request.args[1], ipc_data, BLOCK_SIZE);
- + dc_flushrange((void*)current_request.args[1], BLOCK_SIZE);
- + }
- + if (current_request.args[2] != 0xFFFFFFFF) {
- + memcpy32((void*)current_request.args[2], ipc_ecc, PAGE_SPARE_SIZE * PAGES_PER_BLOCK);
- + dc_flushrange((void*)current_request.args[2], PAGE_SPARE_SIZE * PAGES_PER_BLOCK);
- + }
- + break;
- case IPC_NAND_ERASE:
- // no action needed upon erase completion
- break;
- + case IPC_NAND_WRITE_CLUSTER:
- + case IPC_NAND_WRITE_BLOCK:
- + case IPC_NAND_WRITE_CRYPT_B:
- + case IPC_NAND_WRITE_CRYPT_C:
- case IPC_NAND_WRITE:
- // no action needed upon write completion
- break;
- @@ -195,6 +225,16 @@ void nand_read_page(u32 pageno, void *data, void *ecc) {
- nand_send_command(NAND_READ_POST, 0, NAND_FLAGS_IRQ | NAND_FLAGS_WAIT | NAND_FLAGS_RD | NAND_FLAGS_ECC, 0x840);
- }
- +void nand_read_cluster(u32 clusterno, void *data, void *ecc)
- +{
- + int i;
- + for (i = 0; i < PAGES_PER_CLUSTER; i++) {
- + nand_read_page((clusterno * PAGES_PER_CLUSTER) + i, ((u8*)data) + (i * PAGE_SIZE), \
- + ((u8*)ecc) + (i * ECC_BUFFER_SIZE));
- + }
- +
- +}
- +
- void nand_wait(void) {
- // power-saving IRQ wait
- while(!irq_flag) {
- @@ -205,6 +245,29 @@ void nand_wait(void) {
- }
- }
- +void nand_decrypt_cluster(unsigned int cluster, void *data, void *ecc)
- +{
- + u8 crypted_buffer[CLUSTER_SIZE];
- + u8 iv[16];
- +
- + nand_read_cluster(cluster, crypted_buffer, ecc);
- +
- + memset(iv, 0, sizeof iv);
- + crypto_read_otp();
- + aes_set_key(otp.nand_key);
- + aes_set_iv(iv);
- + aes_decrypt(crypted_buffer, data, CLUSTER_SIZE / 16, 0);
- +}
- +
- +void nand_decrypt_block(unsigned int block, void *data, void *ecc)
- +{
- + int i;
- + for (i = 0; i < CLUSTERS_PER_BLOCK; i++) {
- + nand_decrypt_cluster((block * CLUSTERS_PER_BLOCK) + i, ((u8*)data) + (i * CLUSTER_SIZE), \
- + ((u8*)ecc) + (i * ECC_BUFFER_SIZE * CLUSTERS_PER_BLOCK));
- + }
- +}
- +
- #ifdef NAND_SUPPORT_WRITE
- void nand_write_page(u32 pageno, void *data, void *ecc) {
- irq_flag = 0;
- @@ -224,6 +287,51 @@ void nand_write_page(u32 pageno, void *data, void *ecc) {
- __nand_wait();
- nand_send_command(NAND_WRITE_POST, 0, NAND_FLAGS_IRQ | NAND_FLAGS_WAIT, 0);
- }
- +
- +void nand_write_cluster(unsigned int cluster, void *data, void *ecc)
- +{
- + int i;
- + for (i = 0; i < PAGES_PER_CLUSTER; i++) {
- + nand_write_page((cluster * PAGES_PER_CLUSTER) + i, \
- + ((u8*)data) + (i * PAGE_SIZE), ((u8*)ecc) + (i * PAGE_SPARE_SIZE));
- + }
- +}
- +
- +void nand_write_block(unsigned int block, void *data, void *ecc)
- +{
- + int i;
- + for (i = 0; i < CLUSTERS_PER_BLOCK; i++) {
- + nand_write_cluster((block * CLUSTERS_PER_BLOCK) + i, \
- + ((u8*)data) + (i * CLUSTER_SIZE), \
- + ((u8*)ecc) + (i * PAGE_SPARE_SIZE * CLUSTERS_PER_BLOCK));
- + }
- +}
- +
- +void nand_write_encrypted_cluster(unsigned int cluster, void *data, void *ecc)
- +{
- + u8 crypted_buffer[CLUSTER_SIZE];
- + u8 iv[16];
- +
- +
- + memset(iv, 0, sizeof iv);
- + crypto_read_otp();
- + aes_set_key(otp.nand_key);
- + aes_set_iv(iv);
- + aes_encrypt(data, crypted_buffer, CLUSTER_SIZE / 16, 0);
- +
- + nand_write_cluster(cluster, crypted_buffer, ecc);
- +}
- +
- +void nand_write_encrypted_block(unsigned int block, void *data, void *ecc)
- +{
- + int i;
- +
- + for (i = 0; i < CLUSTERS_PER_BLOCK; i++) {
- + nand_write_encrypted_cluster((block * CLUSTERS_PER_BLOCK) + i, \
- + ((u8*)data) + (i * CLUSTER_SIZE), \
- + ((u8*)ecc) + (i * PAGE_SPARE_SIZE * CLUSTERS_PER_BLOCK));
- + }
- +}
- #endif
- #ifdef NAND_SUPPORT_ERASE
- @@ -321,6 +429,7 @@ void nand_ipc(volatile ipc_request *req)
- current_request = *req;
- nand_read_page(req->args[0], ipc_data, ipc_ecc);
- break;
- +
- #ifdef NAND_SUPPORT_WRITE
- case IPC_NAND_WRITE:
- current_request = *req;
- @@ -330,6 +439,38 @@ void nand_ipc(volatile ipc_request *req)
- memcpy(ipc_ecc, (void*)req->args[2], PAGE_SPARE_SIZE);
- nand_write_page(req->args[0], ipc_data, ipc_ecc);
- break;
- + case IPC_NAND_WRITE_CLUSTER:
- + current_request = *req;
- + dc_invalidaterange((void*)req->args[1], CLUSTER_SIZE);
- + dc_invalidaterange((void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_CLUSTER);
- + memcpy(ipc_data, (void*)req->args[1], CLUSTER_SIZE);
- + memcpy(ipc_ecc, (void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_CLUSTER);
- + nand_write_cluster(req->args[0], ipc_data, ipc_ecc);
- + break;
- + case IPC_NAND_WRITE_BLOCK:
- + current_request = *req;
- + dc_invalidaterange((void*)req->args[1], BLOCK_SIZE);
- + dc_invalidaterange((void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_BLOCK);
- + memcpy(ipc_data, (void*)req->args[1], BLOCK_SIZE);
- + memcpy(ipc_ecc, (void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_BLOCK);
- + nand_write_block(req->args[0], ipc_data, ipc_ecc);
- + break;
- + case IPC_NAND_WRITE_CRYPT_C:
- + current_request = *req;
- + dc_invalidaterange((void*)req->args[1], CLUSTER_SIZE);
- + dc_invalidaterange((void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_CLUSTER);
- + memcpy(ipc_data, (void*)req->args[1], CLUSTER_SIZE);
- + memcpy(ipc_ecc, (void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_CLUSTER);
- + nand_write_encrypted_cluster(req->args[0], ipc_data, ipc_ecc);
- + break;
- + case IPC_NAND_WRITE_CRYPT_B:
- + current_request = *req;
- + dc_invalidaterange((void*)req->args[1], BLOCK_SIZE);
- + dc_invalidaterange((void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_BLOCK);
- + memcpy(ipc_data, (void*)req->args[1], BLOCK_SIZE);
- + memcpy(ipc_ecc, (void*)req->args[2], PAGE_SPARE_SIZE * PAGES_PER_BLOCK);
- + nand_write_encrypted_block(req->args[0], ipc_data, ipc_ecc);
- + break;
- #endif
- #ifdef NAND_SUPPORT_ERASE
- case IPC_NAND_ERASE:
- @@ -337,6 +478,26 @@ void nand_ipc(volatile ipc_request *req)
- nand_erase_block(req->args[0]);
- break;
- #endif
- + case IPC_NAND_READ_DECRYPT_C:
- + current_request = *req;
- + nand_decrypt_cluster(req->args[0], ipc_data, ipc_ecc);
- + break;
- +
- + case IPC_NAND_READ_DECRYPT_B:
- + current_request = *req;
- + nand_decrypt_block(req->args[0], ipc_data, ipc_ecc);
- + break;
- +
- + case IPC_NAND_READ_CLUSTER:
- + current_request = *req;
- + nand_decrypt_cluster(req->args[0], ipc_data, ipc_ecc);
- + break;
- +
- + case IPC_NAND_READ_BLOCK:
- + current_request = *req;
- + nand_decrypt_block(req->args[0], ipc_data, ipc_ecc);
- + break;
- +
- default:
- gecko_printf("IPC: unknown SLOW NAND request %04x\n",
- req->req);
- diff --git a/nand.h b/nand.h
- index 205e73a..1b72525 100644
- --- a/nand.h
- +++ b/nand.h
- @@ -15,11 +15,15 @@ Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
- #include "types.h"
- #include "ipc.h"
- +#define PAGES_PER_CLUSTER (8)
- +#define CLUSTERS_PER_BLOCK (8)
- +#define PAGES_PER_BLOCK (PAGES_PER_CLUSTER * CLUSTERS_PER_BLOCK)
- #define PAGE_SIZE 2048
- +#define CLUSTER_SIZE (PAGE_SIZE * PAGES_PER_CLUSTER)
- +#define BLOCK_SIZE (CLUSTER_SIZE * CLUSTERS_PER_BLOCK)
- #define PAGE_SPARE_SIZE 64
- #define ECC_BUFFER_SIZE (PAGE_SPARE_SIZE+16)
- #define ECC_BUFFER_ALLOC (PAGE_SPARE_SIZE+32)
- -#define BLOCK_SIZE 64
- #define NAND_MAX_PAGE 0x40000
- void nand_irq(void);
- @@ -33,7 +37,13 @@ void nand_write_page(u32 pageno, void *data, void *ecc);
- void nand_erase_block(u32 pageno);
- void nand_wait(void);
- -void nand_read_cluster(u32 clusterno, void *data);
- +void nand_read_cluster(u32 clusterno, void *data, void *ecc);
- +void nand_decrypt_cluster(unsigned int cluster, void *data, void *ecc);
- +void nand_decrypt_block(unsigned int block, void *data, void *ecc);
- +void nand_write_cluster(unsigned int cluster, void *data, void *ecc);
- +void nand_write_block(unsigned int block, void *data, void *ecc);
- +void nand_write_encrypted_cluster(unsigned int cluster, void *data, void *ecc);
- +void nand_write_encrypted_block(unsigned int block, void *data, void *ecc);
- #define NAND_ECC_OK 0
- #define NAND_ECC_CORRECTED 1
- diff --git a/nandfs.c b/nandfs.c
- new file mode 100644
- index 0000000..7594a52
- --- /dev/null
- +++ b/nandfs.c
- @@ -0,0 +1,331 @@
- +#include "crypto.h"
- +#include "utils.h"
- +#include "memory.h"
- +#include "gecko.h"
- +#include "string.h"
- +#include "types.h"
- +#include "nand.h"
- +#include "nandfs.h"
- +#include "nandstructs.h"
- +#include "crypto.h"
- +#include "ipc.h"
- +
- +#define SFFS_COUNT (16)
- +
- +#define SFFS_FIRST_BLOCK (4064)
- +#define SFFS_FIRST_CLUSTER (SFFS_FIRST_BLOCK * CLUSTERS_PER_BLOCK)
- +#define SFFS_FIRST_PAGE (SFFS_FIRST_CLUSTER * PAGES_PER_CLUSTER)
- +
- +//#define NANDFS_DEBUG 1
- +#ifdef NANDFS_DEBUG
- +# define dbgprintf(f, arg...) do { gecko_printf("nandfs: " f, ##arg); } while(0)
- +#else
- +# define dbgprintf(f, arg...)
- +#endif
- +
- +#define NANDFS_ERROR_NOMOUNT -1
- +#define NANDFS_ERROR_NOENT -2
- +#define NANDFS_ERROR_NOIMPLEMENT -3
- +#define NANDFS_ERROR_TOOBIG -4
- +
- +struct nandfs *_nandfs;
- +struct nandfs _nandfs_x;
- +u8* _nand_key;
- +
- +static ipc_request current_request;
- +
- +static u8 ipc_input1 [4096] MEM2_BSS ALIGNED(32);
- +static u8 ipc_output1[4096] MEM2_BSS ALIGNED(32);
- +
- +static u8 devnullbuf[ECC_BUFFER_SIZE * PAGES_PER_CLUSTER] MEM2_BSS ALIGNED(32);
- +
- +static s16 nandfs_find_super()
- +{
- + u32 newest = 0;
- + s16 superclstr = 0, cluster;
- + struct sffs_header *sffs_head;
- + static u8 buffer[BYTES_PER_CLUSTER] MEM2_BSS ALIGNED(32);
- +
- + for (cluster = SFFS_START_CLUSTER; cluster < SFFS_END_CLUSTER; cluster++){
- + nand_read_cluster(cluster, buffer, devnullbuf);
- +
- + sffs_head = (struct sffs_header *)buffer;
- + if(memcmp(&sffs_head->fourcc, SFFS_FOURCC, sizeof
- + SFFS_FOURCC) == 0) {
- + u32 version = sffs_head->generation;
- + if (superclstr == 0 || version > newest) {
- + superclstr = cluster;
- + newest = version;
- + }
- + }
- + }
- + return superclstr;
- +}
- +
- +int nandfs_read(void *buffer, size_t size, struct nandfile *fp)
- +{
- + static u8 tmpbuf[BYTES_PER_CLUSTER] MEM2_BSS ALIGNED(32);
- + u16 cluster = fp->entry.first_cluster;
- + u32 this_size, size_left = size;
- + u32 amount_read = 0;
- +
- + if(!fp->enabled) {
- + gecko_printf("file not opened!\n");
- + return NANDFS_ERROR_NOENT;
- + }
- +
- + if((size_t)fp->entry.size < size) {
- + gecko_printf("attempted to read too much from file.\n");
- + return NANDFS_ERROR_TOOBIG;
- + }
- +
- + while (size_left) {
- + this_size = size_left > BYTES_PER_CLUSTER ? BYTES_PER_CLUSTER : size_left;
- +
- + nand_decrypt_cluster(cluster, tmpbuf, devnullbuf);
- +
- + memcpy((u8*)(buffer+amount_read), tmpbuf, this_size);
- +
- + size_left -= this_size;
- + amount_read += this_size;
- + cluster = fp->fs->sffs->cluster_map[cluster];
- + }
- + return amount_read;
- +}
- +
- +int nandfs_write(void *buffer, size_t size, struct nandfile *fp)
- +{
- + static u8 tmpbuf[BYTES_PER_CLUSTER] MEM2_BSS ALIGNED(32);
- + u16 cluster = fp->entry.first_cluster;
- + u32 this_size, size_left=size;
- + u32 amount_wrote = 0;
- +
- + gecko_printf("this function is not currently at a state where it should be used. Sorry.\n");
- + return NANDFS_ERROR_NOIMPLEMENT;
- +
- + if(!fp->enabled) {
- + gecko_printf("file not opened!\n");
- + return NANDFS_ERROR_NOENT;
- + }
- +
- + if((size_t)fp->entry.size < size) {
- + gecko_printf("attempted to write too much to file.\nWriting more to a file than already exists currently is not supported.\n");
- + return NANDFS_ERROR_TOOBIG;
- + }
- +
- + while (size_left) {
- + this_size = size_left > BYTES_PER_CLUSTER ? BYTES_PER_CLUSTER : size_left;
- +
- + memcpy(tmpbuf, (u8*)buffer, this_size);
- + if (this_size != BYTES_PER_CLUSTER)
- + memset(tmpbuf+this_size, 0, BYTES_PER_CLUSTER-this_size);
- + // We need to get the ECC generation stuff in here.
- +// nand_write_encrypted_cluster(cluster, tmpbuf);
- +
- + size_left -= this_size;
- + amount_wrote += this_size;
- + cluster = fp->fs->sffs->cluster_map[cluster];
- + }
- + return amount_wrote;
- +}
- +
- +static int nandfs_get_fs_entry(struct nandfs *nandfs, size_t dir_levels, char *directories, struct fs_entry *entry)
- +{
- + if (!nandfs->enabled) {
- + gecko_printf("fs not mounted!\n");
- + return -1;
- + }
- +
- + struct fs_entry _current_dir, *current_dir = &_current_dir;
- + memcpy(current_dir, &nandfs->sffs->entries[0],
- + sizeof(struct fs_entry));
- +
- + while(dir_levels > 0) {
- + gecko_printf("looking for \"%s\"\n", directories);
- + for(;;) {
- + current_dir->first_child = current_dir->first_child;
- + current_dir->sibling = current_dir->sibling;
- + current_dir->size = current_dir->size;
- + current_dir->user_id = current_dir->user_id;
- + current_dir->group_id = current_dir->group_id;
- + current_dir->unknown = current_dir->unknown;
- +
- + gecko_printf("checking (sibling = %08x): %s\n", current_dir->sibling, current_dir->name);
- + if(dir_levels > 1 &&
- + strncmp((const char*)current_dir->name, directories,
- + MAX_FS_NAME_LEN) == 0 &&
- + current_dir->type == TYPE_DIRECTORY &&
- + current_dir->first_child != (s16)0xffff) {
- + gecko_printf("found dir; first_child = %08x\n",
- + current_dir->first_child);
- + memcpy(current_dir, &nandfs->sffs->entries[current_dir->first_child],
- + sizeof(struct fs_entry));
- + directories += MAX_FS_NAME_LEN;
- + dir_levels--;
- + break;
- + }
- + else if(dir_levels == 1 &&
- + strncmp((const char*)current_dir->name,
- + directories,
- + MAX_FS_NAME_LEN) == 0 &&
- + current_dir->type == TYPE_FILE) {
- + gecko_printf("FOUND\n");
- + memcpy(entry, current_dir, sizeof(struct fs_entry));
- + return 0;
- + }else if(current_dir->sibling != 0xffff) {
- + gecko_printf("going to next sibling %08x\n",
- + current_dir->sibling);
- + memcpy(current_dir, &nandfs->sffs->entries[current_dir->sibling],
- + sizeof(struct fs_entry));
- + }else{
- + gecko_printf("no more siblings :/\n");
- + return NANDFS_ERROR_NOENT;
- + }
- + }
- + }
- +
- + return NANDFS_ERROR_NOENT;
- +}
- +
- +s8 nandfs_open(const char *path, struct nandfile *fp)
- +{
- + int dir_depth = 0;
- + int ret;
- + char *pch;
- + static char path_new[256] MEM2_BSS ALIGNED(32);
- +
- + if (!_nandfs->enabled) {
- + gecko_printf("fs not mounted!\n");
- + return NANDFS_ERROR_NOMOUNT;
- + }
- +
- + fp->fs = _nandfs;
- + static char directories[16 * MAX_FS_NAME_LEN] MEM2_BSS ALIGNED(32);
- +
- + strlcpy(path_new, path, 256);
- + pch = strtok(path_new, "/");
- +
- + // HAXX
- + directories[0] = '/';
- + directories[1] = 0;
- + dir_depth++;
- + while (pch != NULL) {
- + strlcpy(&directories[dir_depth * MAX_FS_NAME_LEN], pch, MAX_FS_NAME_LEN);
- + dir_depth++;
- + pch = strtok(NULL, "/");
- + }
- +
- + ret = nandfs_get_fs_entry(_nandfs, dir_depth, directories, &fp->entry);
- + if(ret < 0) {
- + return ret;
- + }else
- + fp->enabled = 1;
- +
- +/*
- + for each cluster i in cluster chain:
- + fs_hmac_data(cluster_buf,user_id,name,entry_index,entry->unknown,i++,calc_hmac);
- +*/
- +
- + return 0;
- +}
- +
- +int nandfs_close(struct nandfile *fp)
- +{
- + if (!fp->enabled) {
- + gecko_printf("file not open!\n");
- + return NANDFS_ERROR_NOENT;
- + }
- + return 0;
- +}
- +
- +s8 nandfs_mount()
- +{
- + int i;
- + static u8 buffer[BYTES_PER_CLUSTER] MEM2_BSS ALIGNED(32);
- + static u8 sffs_buffer[16 * BYTES_PER_CLUSTER] MEM2_BSS ALIGNED(32);
- + _nandfs = &_nandfs_x;
- +
- + _nandfs->super = nandfs_find_super();
- +
- + for (i = 0; i < 16; i++) {
- + nand_read_cluster(_nandfs->super+i, buffer, devnullbuf);
- + memcpy(sffs_buffer + (BYTES_PER_CLUSTER * i), buffer, BYTES_PER_CLUSTER);
- + }
- + crypto_read_otp();
- + _nand_key = otp.nand_key;
- + _nandfs->sffs = (struct sffs *)sffs_buffer;
- + _nandfs->enabled = 1;
- +
- + return 0;
- +}
- +
- +void nandfs_initialize(void)
- +{
- + current_request.code = 0;
- +}
- +
- +void nandfs_ipc(volatile ipc_request *req)
- +{
- + if (current_request.code != 0) {
- + gecko_printf("NANDFS: previous IPC request is not done yet.");
- + ipc_post(req->code, req->tag, 1, -1);
- + return;
- + }
- + s8 retval;
- + switch (req->req) {
- + case IPC_NANDFS_MOUNT:
- + current_request = *req;
- + nandfs_mount();
- + break;
- +
- + // args[0] (in) == filename
- + // args[1] (out) == file pointer
- + case IPC_NANDFS_OPEN:
- + current_request = *req;
- + retval = nandfs_open((char *)req->args[0], (struct nandfile *)ipc_output1);
- + if(retval < 0)
- + gecko_printf("NANDFS: open error %d.\n", retval);
- + else {
- + memcpy((void *)req->args[1], ipc_output1, sizeof(struct nandfile));
- + dc_flushrange((void *)req->args[1], sizeof(struct nandfile));
- + }
- + break;
- +
- + // args[0] (in) == file pointer
- + case IPC_NANDFS_CLOSE:
- + current_request = *req;
- + retval = nandfs_close((struct nandfile *)(req->args[0]));
- + if(retval < 0)
- + gecko_printf("NANDFS: close error %d.\n", retval);
- + break;
- +
- + // args[0] (in) == filepointer
- + // args[1] (in) == size
- + // args[2] (out) == buffer
- + case IPC_NANDFS_READ:
- + current_request = *req;
- + retval = nandfs_read(ipc_output1, req->args[1], (struct nandfile *)req->args[0]);
- + if(retval < 0)
- + gecko_printf("NANDFS: read error %d.\n", retval);
- + else {
- + memcpy((void *)req->args[2], ipc_output1, req->args[1]);
- + dc_flushrange((void *)req->args[2], req->args[1]);
- + }
- + break;
- +
- + // args[0] (in) == filepointer
- + // args[1] (in) == size
- + // args[2] (in) == buffer
- + case IPC_NANDFS_WRITE:
- + current_request = *req;
- + dc_invalidaterange((void*)req->args[2], req->args[1]);
- + memcpy(ipc_input1, (void*)req->args[2], req->args[1]);
- + nandfs_write(ipc_input1, req->args[1], (struct nandfile *)(req->args[0]));
- + break;
- +
- + default:
- + gecko_printf("IPC: unknown SLOW NANDFS request %04x\n",
- + req->req);
- + }
- +}
- +
- diff --git a/nandfs.h b/nandfs.h
- new file mode 100644
- index 0000000..9c38504
- --- /dev/null
- +++ b/nandfs.h
- @@ -0,0 +1,38 @@
- +#ifndef _NANDFS_H_
- +#define _NANDFS_H_
- +
- +// Functions to access the NAND filesystem
- +
- +#include "ipc.h"
- +#include "types.h"
- +#include "nandstructs.h"
- +#include "nand.h"
- +
- +#define SFFS_START_CLUSTER 0x7F00
- +#define SFFS_END_CLUSTER 0x7FFF
- +
- +struct nandfile
- +{
- + struct nandfs *fs;
- + struct fs_entry entry;
- + s8 enabled;
- +};
- +
- +struct nandfs
- +{
- + struct sffs *sffs;
- + s16 super;
- + s8 enabled;
- +};
- +
- +s8 nandfs_mount();
- +s8 nandfs_open(const char *path, struct nandfile *fp);
- +int nandfs_read(void *buffer, size_t size, struct nandfile *fp);
- +int nandfs_write(void *buffer, size_t size, struct nandfile *fp);
- +// int nandfs_seek(struct nandfile *fp, u64 offset, u32 whence);
- +int nandfs_close(struct nandfile *fp);
- +void nandfs_initialize(void);
- +void nandfs_ipc(volatile ipc_request *req);
- +
- +#endif // _NANDFS_H_
- +
- diff --git a/nandstructs.h b/nandstructs.h
- new file mode 100644
- index 0000000..a07a3ef
- --- /dev/null
- +++ b/nandstructs.h
- @@ -0,0 +1,133 @@
- +#ifndef _NANDSTRUCTS_H_
- +#define _NANDSTRUCTS_H_
- +
- +
- +#include "types.h"
- +
- +#define SFFS_FOURCC ("SFFS")
- +
- +#define MAX_CLUSTERS (32768)
- +#define MAX_FS_ENTRIES (0x17ff)
- +
- +#define MAX_FS_NAME_LEN (12)
- +
- +#define FS_NO_SIBLING (-1)
- +
- +
- +#define BYTES_PER_PAGE (2048)
- +#define BYTES_PER_CLUSTER (BYTES_PER_PAGE * PAGES_PER_CLUSTER)
- +#define BYTES_PER_BLOCK (BYTES_PER_CLUSTER * CLUSTERS_PER_BLOCK)
- +
- +#define PAGES_PER_CLUSTER (8)
- +#define CLUSTERS_PER_BLOCK (8)
- +
- +#define PAGES_PER_BLOCK (PAGES_PER_CLUSTER * CLUSTERS_PER_BLOCK)
- +#define SPARE_DATA_SIZE (64)
- +#define ECC_DATA_SIZE (16)
- +#define HMAC_DATA_SIZE (48)
- +
- +#define BLOCK_COUNT (4096)
- +#define CLUSTER_COUNT (BLOCK_COUNT * CLUSTERS_PER_BLOCK)
- +#define PAGE_COUNT (CLUSTER_COUNT * PAGES_PER_CLUSTER)
- +
- +#define NAND_DATA_SIZE (PAGE_COUNT * BYTES_PER_PAGE)
- +#define NAND_SIZE (PAGE_COUNT * (BYTES_PER_PAGE + SPARE_DATA_SIZE))
- +
- +#define SFFS_COUNT (16)
- +
- +#define SFFS_FIRST_BLOCK (4064)
- +#define SFFS_FIRST_CLUSTER (SFFS_FIRST_BLOCK * CLUSTERS_PER_BLOCK)
- +#define SFFS_FIRST_PAGE (SFFS_FIRST_CLUSTER * PAGES_PER_CLUSTER)
- +#define SFFS_OFFSET (SFFS_FIRST_PAGE * BYTES_PER_PAGE)
- +
- +
- +//Goes from -1 to -5 or -6, so it needs more investigation
- +#define CLUSTER_FREE (-2)
- +#define CLUSTER_RESERVED (-4)
- +#define CLUSTER_CHAIN_LAST (-5)
- +
- +
- +#define TYPE_FREE (0)
- +#define TYPE_FILE (1)
- +#define TYPE_DIRECTORY (2)
- +
- +#ifdef _MSC_VER
- +#pragma pack(push, 1)
- +#endif //_MSC_VER
- +
- +/*
- +"attributes" apears to be unused
- +The sole purpose of "unknown" is possibly padding up to 32/20h size
- +
- +"first_child" is used in directiory entries
- +"first_cluster" is used in file entries
- +*/
- +
- +struct fs_entry {
- + s8 name[MAX_FS_NAME_LEN]; //00
- + union {
- + u8 permissions; //0C
- + struct {
- + u8 type : 2; //0C
- + u8 other_perm : 2; //0C
- + u8 group_perm : 2; //0C
- + u8 user_perm : 2; //0C
- + };
- + };
- + u8 attributes; //0D
- + union {
- + s16 first_child; //0E
- + s16 first_cluster; //0E
- + };
- + s16 sibling; //10
- + u32 size; //12
- + u32 user_id; //16
- + u16 group_id; //1A
- + u32 unknown; //1C
- +#ifdef _MSC_VER
- +};
- +#elif __GNUC__ //_MSC_VER
- +} __attribute__((packed));
- +#endif //__GNUC__
- +
- +
- +/*
- +The highest generation out of the 16 stored SFFS blocks is the newest.
- +Upon each filesystem modification, the generation number is incremented
- +and the SFFS block is copied to the next slot (round-robin), for purposes
- +of data integrity and wear-levelling. The generation number is then
- +stored in the Hollywood SEEPROM, but this may or may not actually get used.
- +*/
- +
- +struct sffs_header {
- + u32 fourcc;
- + u32 generation;
- + u32 whatever;
- +#ifdef _MSC_VER
- +};
- +#elif __GNUC__ //_MSC_VER
- +} __attribute__((packed));
- +#endif //__GNUC__
- +
- +struct sffs {
- + struct sffs_header header;
- +
- + // this either is s16 or MAX_CLUSTERS/2
- + s16 cluster_map[MAX_CLUSTERS];
- + union {
- + struct fs_entry entries[MAX_FS_ENTRIES];
- + u8 entries_size[0x2FFF4];
- + };
- +#ifdef _MSC_VER
- +};
- +#elif __GNUC__ //_MSC_VER
- +} __attribute__((packed));
- +#endif //__GNUC__
- +
- +
- +#ifdef _MSC_VER
- +#pragma pack(pop)
- +#endif //_MSC_VER
- +
- +#endif //_NANDSTRUCTS_H_
- +
- diff --git a/string.c b/string.c
- index 5b867b0..eed8de9 100644
- --- a/string.c
- +++ b/string.c
- @@ -155,3 +155,46 @@ size_t strcspn(const char *s1, const char *s2)
- return len;
- }
- +// Thanks ReactOS!
- +char* strtok(char *s, const char *delim)
- +{
- + const char *spanp;
- + int c, sc;
- + int brk = 0;
- + char *tok;
- + static char *last;
- +
- + if (s == NULL && (s = last) == NULL)
- + return (NULL);
- +
- + while(!brk) {
- + brk = 1;
- + c = *s++;
- + for (spanp = delim; (sc = *spanp++) != 0;) {
- + if (c == sc)
- + brk = 0;
- + }
- + }
- +
- + if (c == 0) {
- + last = NULL;
- + return (NULL);
- + }
- + tok = s - 1;
- +
- + for (;;) {
- + c = *s++;
- + spanp = delim;
- + do {
- + if ((sc = *spanp++) == c) {
- + if (c == 0)
- + s = NULL;
- + else
- + s[-1] = 0;
- + last = s;
- + return (tok);
- + }
- + } while (sc != 0);
- + }
- + /* NOTREACHED */
- +}
- diff --git a/string.h b/string.h
- index da87683..106034e 100644
- --- a/string.h
- +++ b/string.h
- @@ -24,6 +24,7 @@ size_t strlcat(char *, const char *, size_t);
- char *strchr(const char *, int);
- size_t strspn(const char *, const char *);
- size_t strcspn(const char *, const char *);
- +char* strtok(char *, const char *);
- #endif
- --
- 1.6.1
Add Comment
Please, Sign In to add comment